| Index: net/base/upload_data_stream.cc
|
| diff --git a/net/base/upload_data_stream.cc b/net/base/upload_data_stream.cc
|
| index 5b2e5d30b659cbf7410da85b41898ee604819fb4..19118b603b4185a0b748701f34bf9c2f631a1d2f 100644
|
| --- a/net/base/upload_data_stream.cc
|
| +++ b/net/base/upload_data_stream.cc
|
| @@ -7,55 +7,91 @@
|
| #include "base/file_util.h"
|
| #include "base/logging.h"
|
| #include "base/threading/thread_restrictions.h"
|
| +#include "base/threading/worker_pool.h"
|
| +#include "base/tracked_objects.h"
|
| #include "net/base/file_stream.h"
|
| #include "net/base/io_buffer.h"
|
| #include "net/base/net_errors.h"
|
|
|
| namespace net {
|
|
|
| -bool UploadDataStream::merge_chunks_ = true;
|
| -
|
| -UploadDataStream::UploadDataStream(UploadData* upload_data)
|
| - : upload_data_(upload_data),
|
| - element_index_(0),
|
| - element_offset_(0),
|
| - element_file_bytes_remaining_(0),
|
| - total_size_(0),
|
| - current_position_(0),
|
| - initialized_successfully_(false) {
|
| -}
|
| -
|
| -UploadDataStream::~UploadDataStream() {
|
| -}
|
| -
|
| -int UploadDataStream::Init() {
|
| - DCHECK(!initialized_successfully_);
|
| -
|
| - {
|
| - base::ThreadRestrictions::ScopedAllowIO allow_io;
|
| - total_size_ = upload_data_->GetContentLengthSync();
|
| - }
|
| +namespace {
|
|
|
| +// Checks if any file in |upload_file| is modified since we initially
|
| +// observed. Stores ERR_UPLOAD_FILE_CHANGED in |result| if such a
|
| +// modification is detected. Otherwise, stores OK in |result|.
|
| +void CheckModifiedFiles(scoped_refptr<UploadData> upload_data, int* result) {
|
| // If the underlying file has been changed and the expected file
|
| // modification time is set, treat it as error. Note that the expected
|
| // modification time from WebKit is based on time_t precision. So we
|
| // have to convert both to time_t to compare. This check is used for
|
| // sliced files.
|
| - const std::vector<UploadData::Element>& elements = *upload_data_->elements();
|
| + const std::vector<UploadData::Element>& elements = *upload_data->elements();
|
| for (size_t i = 0; i < elements.size(); ++i) {
|
| const UploadData::Element& element = elements[i];
|
| if (element.type() == UploadData::TYPE_FILE &&
|
| !element.expected_file_modification_time().is_null()) {
|
| - // Temporarily allow until fix: http://crbug.com/72001.
|
| - base::ThreadRestrictions::ScopedAllowIO allow_io;
|
| base::PlatformFileInfo info;
|
| if (file_util::GetFileInfo(element.file_path(), &info) &&
|
| element.expected_file_modification_time().ToTimeT() !=
|
| info.last_modified.ToTimeT()) {
|
| - return ERR_UPLOAD_FILE_CHANGED;
|
| + *result = ERR_UPLOAD_FILE_CHANGED;
|
| + return;
|
| }
|
| }
|
| }
|
| + *result = OK;
|
| + return;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +bool UploadDataStream::merge_chunks_ = true;
|
| +
|
| +UploadDataStream::UploadDataStream(UploadData* upload_data)
|
| + : upload_data_(upload_data),
|
| + element_index_(0),
|
| + element_offset_(0),
|
| + element_file_bytes_remaining_(0),
|
| + total_size_(0),
|
| + current_position_(0),
|
| + initialized_successfully_(false),
|
| + weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
|
| +}
|
| +
|
| +UploadDataStream::~UploadDataStream() {
|
| +}
|
| +
|
| +int UploadDataStream::Init(const CompletionCallback& on_completion) {
|
| + DCHECK(!initialized_successfully_);
|
| + DCHECK(user_callback_.is_null());
|
| +
|
| + // Fast path. Initialize synchronously if the data is in memory.
|
| + if (upload_data_->IsInMemory())
|
| + return InitSync();
|
| +
|
| + // The asynchronous initialization is performed in the following steps:
|
| + // 1. GetContentLength() computes the content length in the background.
|
| + // 2. OnGetContentLengthComplete() is called once it's done.
|
| + // 3. CheckModifiedFiles() checks the modified files in the background.
|
| + // 4. OnCheckModifiedFilesComplete() is called once it's done.
|
| + // 5. user_callback_ is run with the initialization result.
|
| + user_callback_ = on_completion;
|
| + upload_data_->GetContentLength(
|
| + base::Bind(&UploadDataStream::OnGetContentLengthComplete,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + return ERR_IO_PENDING;
|
| +}
|
| +
|
| +int UploadDataStream::InitSync() {
|
| + DCHECK(!initialized_successfully_);
|
| +
|
| + total_size_ = upload_data_->GetContentLengthSync();
|
| +
|
| + int result = OK;
|
| + CheckModifiedFiles(upload_data_, &result);
|
| + if (result != OK)
|
| + return result;
|
|
|
| initialized_successfully_ = true;
|
| return OK;
|
| @@ -164,6 +200,31 @@ void UploadDataStream::AdvanceToNextElement() {
|
| }
|
| }
|
|
|
| +void UploadDataStream::OnGetContentLengthComplete(uint64 content_length) {
|
| + total_size_ = content_length;
|
| + int* result = new int(OK);
|
| + const bool posted = base::WorkerPool::PostTaskAndReply(
|
| + FROM_HERE,
|
| + base::Bind(&CheckModifiedFiles, upload_data_, result),
|
| + base::Bind(&UploadDataStream::OnCheckModifiedFilesComplete,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + base::Owned(result)),
|
| + true /* task_is_slow */);
|
| + DCHECK(posted);
|
| +}
|
| +
|
| +void UploadDataStream::OnCheckModifiedFilesComplete(int* result) {
|
| + if (*result == OK)
|
| + initialized_successfully_ = true;
|
| +
|
| + // Tell the caller of Init() that the initialization is done. Run() may
|
| + // triger other asynchronous operations so user_callback_ is reset before
|
| + // running it.
|
| + CompletionCallback copied_user_callback = user_callback_;
|
| + user_callback_.Reset();
|
| + copied_user_callback.Run(*result);
|
| +}
|
| +
|
| bool UploadDataStream::IsEOF() const {
|
| const std::vector<UploadData::Element>& elements = *upload_data_->elements();
|
|
|
|
|