// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/base/upload_data_stream.h"
#include "base/logging.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
namespace net {
UploadDataStream::UploadDataStream(const UploadData* data)
: data_(data),
buf_(new IOBuffer(kBufSize)),
buf_len_(0),
next_element_(data->elements().begin()),
next_element_offset_(0),
next_element_remaining_(0),
total_size_(data->GetContentLength()),
current_position_(0) {
FillBuf();
}
UploadDataStream::~UploadDataStream() {
}
void UploadDataStream::DidConsume(size_t num_bytes) {
// TODO(vandebo): Change back to a DCHECK when issue 27870 is resolved.
CHECK(num_bytes <= buf_len_);
buf_len_ -= num_bytes;
if (buf_len_)
memmove(buf_->data(), buf_->data() + num_bytes, buf_len_);
FillBuf();
current_position_ += num_bytes;
}
void UploadDataStream::FillBuf() {
std::vector<UploadData::Element>::const_iterator end =
data_->elements().end();
while (buf_len_ < kBufSize && next_element_ != end) {
bool advance_to_next_element = false;
const UploadData::Element& element = *next_element_;
size_t size_remaining = kBufSize - buf_len_;
if (element.type() == UploadData::TYPE_BYTES) {
const std::vector<char>& d = element.bytes();
size_t count = d.size() - next_element_offset_;
size_t bytes_copied = std::min(count, size_remaining);
memcpy(buf_->data() + buf_len_, &d[next_element_offset_], bytes_copied);
buf_len_ += bytes_copied;
if (bytes_copied == count) {
advance_to_next_element = true;
} else {
next_element_offset_ += bytes_copied;
}
} else {
DCHECK(element.type() == UploadData::TYPE_FILE);
if (!next_element_stream_.IsOpen()) {
int flags = base::PLATFORM_FILE_OPEN |
base::PLATFORM_FILE_READ;
int rv = next_element_stream_.Open(element.file_path(), flags);
// If the file does not exist, that's technically okay.. we'll just
// upload an empty file. This is for consistency with Mozilla.
DLOG_IF(WARNING, rv != OK) << "Failed to open \""
<< element.file_path().value()
<< "\" for reading: " << rv;
next_element_remaining_ = 0; // Default to reading nothing.
if (rv == OK) {
uint64 offset = element.file_range_offset();
if (offset && next_element_stream_.Seek(FROM_BEGIN, offset) < 0) {
DLOG(WARNING) << "Failed to seek \"" << element.file_path().value()
<< "\" to offset: " << offset;
} else {
next_element_remaining_ = element.file_range_length();
}
}
}
int rv = 0;
int count = static_cast<int>(std::min(
static_cast<uint64>(size_remaining), next_element_remaining_));
if (count > 0 &&
(rv = next_element_stream_.Read(buf_->data() + buf_len_,
count, NULL)) > 0) {
buf_len_ += rv;
next_element_remaining_ -= rv;
} else {
advance_to_next_element = true;
}
}
if (advance_to_next_element) {
++next_element_;
next_element_offset_ = 0;
next_element_stream_.Close();
}
}
}
} // namespace net