upload_data_stream.cc revision c7f5f8508d98d5952d42ed7648c2a8f30a4da156
1// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/base/upload_data_stream.h"
6
7#include "base/logging.h"
8#include "net/base/io_buffer.h"
9#include "net/base/net_errors.h"
10
11namespace net {
12
13UploadDataStream::UploadDataStream(const UploadData* data)
14    : data_(data),
15      buf_(new IOBuffer(kBufSize)),
16      buf_len_(0),
17      next_element_(data->elements().begin()),
18      next_element_offset_(0),
19      next_element_remaining_(0),
20      total_size_(data->GetContentLength()),
21      current_position_(0) {
22  FillBuf();
23}
24
25UploadDataStream::~UploadDataStream() {
26}
27
28void UploadDataStream::DidConsume(size_t num_bytes) {
29  // TODO(vandebo): Change back to a DCHECK when issue 27870 is resolved.
30  CHECK(num_bytes <= buf_len_);
31
32  buf_len_ -= num_bytes;
33  if (buf_len_)
34    memmove(buf_->data(), buf_->data() + num_bytes, buf_len_);
35
36  FillBuf();
37
38  current_position_ += num_bytes;
39}
40
41void UploadDataStream::FillBuf() {
42  std::vector<UploadData::Element>::const_iterator end =
43      data_->elements().end();
44
45  while (buf_len_ < kBufSize && next_element_ != end) {
46    bool advance_to_next_element = false;
47
48    const UploadData::Element& element = *next_element_;
49
50    size_t size_remaining = kBufSize - buf_len_;
51    if (element.type() == UploadData::TYPE_BYTES) {
52      const std::vector<char>& d = element.bytes();
53      size_t count = d.size() - next_element_offset_;
54
55      size_t bytes_copied = std::min(count, size_remaining);
56
57      memcpy(buf_->data() + buf_len_, &d[next_element_offset_], bytes_copied);
58      buf_len_ += bytes_copied;
59
60      if (bytes_copied == count) {
61        advance_to_next_element = true;
62      } else {
63        next_element_offset_ += bytes_copied;
64      }
65    } else {
66      DCHECK(element.type() == UploadData::TYPE_FILE);
67
68      if (!next_element_stream_.IsOpen()) {
69        int flags = base::PLATFORM_FILE_OPEN |
70                    base::PLATFORM_FILE_READ;
71        int rv = next_element_stream_.Open(element.file_path(), flags);
72        // If the file does not exist, that's technically okay.. we'll just
73        // upload an empty file.  This is for consistency with Mozilla.
74        DLOG_IF(WARNING, rv != OK) << "Failed to open \""
75                                   << element.file_path().value()
76                                   << "\" for reading: " << rv;
77
78        next_element_remaining_ = 0;  // Default to reading nothing.
79        if (rv == OK) {
80          uint64 offset = element.file_range_offset();
81          if (offset && next_element_stream_.Seek(FROM_BEGIN, offset) < 0) {
82            DLOG(WARNING) << "Failed to seek \"" << element.file_path().value()
83                          << "\" to offset: " << offset;
84          } else {
85            next_element_remaining_ = element.file_range_length();
86          }
87        }
88      }
89
90      int rv = 0;
91      int count = static_cast<int>(std::min(
92          static_cast<uint64>(size_remaining), next_element_remaining_));
93      if (count > 0 &&
94          (rv = next_element_stream_.Read(buf_->data() + buf_len_,
95                                          count, NULL)) > 0) {
96        buf_len_ += rv;
97        next_element_remaining_ -= rv;
98      } else {
99        advance_to_next_element = true;
100      }
101    }
102
103    if (advance_to_next_element) {
104      ++next_element_;
105      next_element_offset_ = 0;
106      next_element_stream_.Close();
107    }
108  }
109}
110
111}  // namespace net
112