Home | History | Annotate | Download | only in base
      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 
     11 namespace net {
     12 
     13 UploadDataStream::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 
     25 UploadDataStream::~UploadDataStream() {
     26 }
     27 
     28 void 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 
     41 void 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