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