upload_data_stream.cc revision a01ff25d304217e7ef77ad2d83f48aca73be2c9d
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::JavaISWrapper(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