upload_data_stream.cc revision 69dbe9fcda26341f31379053f8123d7f611c0be1
1// Copyright (c) 2010 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/file_util.h"
8#include "base/logging.h"
9#include "net/base/file_stream.h"
10#include "net/base/io_buffer.h"
11#include "net/base/net_errors.h"
12
13namespace net {
14
15UploadDataStream* UploadDataStream::Create(UploadData* data, int* error_code) {
16  scoped_ptr<UploadDataStream> stream(new UploadDataStream(data));
17  int rv = stream->FillBuf();
18  if (error_code)
19    *error_code = rv;
20  if (rv != OK)
21    return NULL;
22
23  return stream.release();
24}
25
26UploadDataStream::UploadDataStream(UploadData* data)
27    : data_(data),
28      buf_(new IOBuffer(kBufSize)),
29      buf_len_(0),
30      next_element_(data->elements()->begin()),
31      next_element_offset_(0),
32      next_element_remaining_(0),
33      total_size_(data->GetContentLength()),
34      current_position_(0),
35      eof_(false) {
36}
37
38UploadDataStream::~UploadDataStream() {
39}
40
41void UploadDataStream::DidConsume(size_t num_bytes) {
42  DCHECK_LE(num_bytes, buf_len_);
43  DCHECK(!eof_);
44
45  buf_len_ -= num_bytes;
46  if (buf_len_)
47    memmove(buf_->data(), buf_->data() + num_bytes, buf_len_);
48
49  FillBuf();
50
51  current_position_ += num_bytes;
52}
53
54int UploadDataStream::FillBuf() {
55  std::vector<UploadData::Element>::iterator end =
56      data_->elements()->end();
57
58  while (buf_len_ < kBufSize && next_element_ != end) {
59    bool advance_to_next_element = false;
60
61    UploadData::Element& element = *next_element_;
62
63    size_t size_remaining = kBufSize - buf_len_;
64    if (element.type() == UploadData::TYPE_BYTES) {
65      const std::vector<char>& d = element.bytes();
66      size_t count = d.size() - next_element_offset_;
67
68      size_t bytes_copied = std::min(count, size_remaining);
69
70      memcpy(buf_->data() + buf_len_, &d[next_element_offset_], bytes_copied);
71      buf_len_ += bytes_copied;
72
73      if (bytes_copied == count) {
74        advance_to_next_element = true;
75      } else {
76        next_element_offset_ += bytes_copied;
77      }
78    } else {
79      DCHECK(element.type() == UploadData::TYPE_FILE);
80
81      if (!next_element_remaining_) {
82        // If the underlying file has been changed, treat it as error.
83        // Note that the expected modification time from WebKit is based on
84        // time_t precision. So we have to convert both to time_t to compare.
85        if (!element.expected_file_modification_time().is_null()) {
86          base::PlatformFileInfo info;
87          if (file_util::GetFileInfo(element.file_path(), &info) &&
88              element.expected_file_modification_time().ToTimeT() !=
89                  info.last_modified.ToTimeT()) {
90            return ERR_UPLOAD_FILE_CHANGED;
91          }
92        }
93        next_element_remaining_ = element.GetContentLength();
94#ifdef ANDROID
95        if (element.file_path().value().find("content://") == 0) {
96            next_element_java_stream_.reset(
97                new android::JavaInputStreamWrapper(element.file_path()));
98        } else
99#endif
100        next_element_stream_.reset(element.NewFileStreamForReading());
101      }
102
103      int rv = 0;
104      int count =
105          static_cast<int>(std::min(next_element_remaining_,
106                                    static_cast<uint64>(size_remaining)));
107      if (count > 0) {
108#ifdef ANDROID
109        if (next_element_java_stream_.get())
110            rv = next_element_java_stream_->Read(buf_->data() + buf_len_, count);
111        else {
112#endif
113        if (next_element_stream_.get())
114          rv = next_element_stream_->Read(buf_->data() + buf_len_, count, NULL);
115#ifdef ANDROID
116        }
117#endif
118        if (rv <= 0) {
119          // If there's less data to read than we initially observed, then
120          // pad with zero.  Otherwise the server will hang waiting for the
121          // rest of the data.
122          memset(buf_->data() + buf_len_, 0, count);
123          rv = count;
124        }
125        buf_len_ += rv;
126      }
127
128      if (static_cast<int>(next_element_remaining_) == rv) {
129        advance_to_next_element = true;
130      } else {
131        next_element_remaining_ -= rv;
132      }
133    }
134
135    if (advance_to_next_element) {
136      ++next_element_;
137      next_element_offset_ = 0;
138      next_element_remaining_ = 0;
139      next_element_stream_.reset();
140    }
141  }
142
143  if (next_element_ == end && !buf_len_)
144    eof_ = true;
145
146  return OK;
147}
148
149}  // namespace net
150