summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-18 14:01:53 +0000
committerhashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-18 14:01:53 +0000
commitdf7adc6e3a6c82831052ebe799912e66ee01304d (patch)
tree3d05c14a37ab3b598a2b76e1c251b9b867a721a5
parent014bc6fdc57911f95f9de6119b70bcbda774b1e8 (diff)
downloadchromium_src-df7adc6e3a6c82831052ebe799912e66ee01304d.zip
chromium_src-df7adc6e3a6c82831052ebe799912e66ee01304d.tar.gz
chromium_src-df7adc6e3a6c82831052ebe799912e66ee01304d.tar.bz2
net: Make UploadDataStream::Init() asynchronous.
Rename the existing synchronous version to InitSync() and add a new asynchronous version, Init(). However, the new asynchronous version is not used yet. The existing code is changed to use the synchronous version. BUG=72001 TEST=net_unittests Review URL: https://chromiumcodereview.appspot.com/10913179 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@157344 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome_frame/urlmon_upload_data_stream.cc4
-rw-r--r--net/base/upload_bytes_element_reader.cc4
-rw-r--r--net/base/upload_bytes_element_reader.h1
-rw-r--r--net/base/upload_data_stream.cc77
-rw-r--r--net/base/upload_data_stream.h30
-rw-r--r--net/base/upload_data_stream_unittest.cc154
-rw-r--r--net/base/upload_element_reader.cc6
-rw-r--r--net/base/upload_element_reader.h10
-rw-r--r--net/base/upload_file_element_reader.cc148
-rw-r--r--net/base/upload_file_element_reader.h9
-rw-r--r--net/http/http_network_transaction.cc2
-rw-r--r--net/http/http_stream_parser_unittest.cc12
-rw-r--r--net/spdy/spdy_http_stream_spdy2_unittest.cc4
-rw-r--r--net/spdy/spdy_http_stream_spdy3_unittest.cc6
-rw-r--r--net/spdy/spdy_network_transaction_spdy2_unittest.cc4
-rw-r--r--net/spdy/spdy_network_transaction_spdy3_unittest.cc4
16 files changed, 390 insertions, 85 deletions
diff --git a/chrome_frame/urlmon_upload_data_stream.cc b/chrome_frame/urlmon_upload_data_stream.cc
index 2437554..8aae0df7 100644
--- a/chrome_frame/urlmon_upload_data_stream.cc
+++ b/chrome_frame/urlmon_upload_data_stream.cc
@@ -11,7 +11,7 @@ void UrlmonUploadDataStream::Initialize(net::UploadData* upload_data) {
upload_data_ = upload_data;
request_body_stream_.reset(
new net::UploadDataStream(upload_data));
- const int result = request_body_stream_->Init();
+ const int result = request_body_stream_->InitSync();
DCHECK_EQ(net::OK, result);
}
@@ -70,7 +70,7 @@ STDMETHODIMP UrlmonUploadDataStream::Seek(LARGE_INTEGER move, DWORD origin,
if (origin == STREAM_SEEK_SET && move.QuadPart == 0) {
if (request_body_stream_->position() != 0) {
request_body_stream_.reset(new net::UploadDataStream(upload_data_));
- const int result = request_body_stream_->Init();
+ const int result = request_body_stream_->InitSync();
DCHECK_EQ(net::OK, result);
}
if (new_pos) {
diff --git a/net/base/upload_bytes_element_reader.cc b/net/base/upload_bytes_element_reader.cc
index c99ce74..9beb1f4 100644
--- a/net/base/upload_bytes_element_reader.cc
+++ b/net/base/upload_bytes_element_reader.cc
@@ -19,6 +19,10 @@ UploadBytesElementReader::UploadBytesElementReader(const char* bytes,
UploadBytesElementReader::~UploadBytesElementReader() {
}
+int UploadBytesElementReader::Init(const CompletionCallback& callback) {
+ return OK;
+}
+
int UploadBytesElementReader::InitSync() {
return OK;
}
diff --git a/net/base/upload_bytes_element_reader.h b/net/base/upload_bytes_element_reader.h
index cb9d3e8..1467ed7 100644
--- a/net/base/upload_bytes_element_reader.h
+++ b/net/base/upload_bytes_element_reader.h
@@ -17,6 +17,7 @@ class NET_EXPORT_PRIVATE UploadBytesElementReader : public UploadElementReader {
virtual ~UploadBytesElementReader();
// UploadElementReader overrides:
+ virtual int Init(const CompletionCallback& callback) OVERRIDE;
virtual int InitSync() OVERRIDE;
virtual uint64 GetContentLength() const OVERRIDE;
virtual uint64 BytesRemaining() const OVERRIDE;
diff --git a/net/base/upload_data_stream.cc b/net/base/upload_data_stream.cc
index e46f2e6..a62528d 100644
--- a/net/base/upload_data_stream.cc
+++ b/net/base/upload_data_stream.cc
@@ -24,7 +24,8 @@ UploadDataStream::UploadDataStream(UploadData* upload_data)
element_index_(0),
total_size_(0),
current_position_(0),
- initialized_successfully_(false) {
+ initialized_successfully_(false),
+ weak_ptr_factory_(this) {
const std::vector<UploadElement>& elements = *upload_data_->elements();
for (size_t i = 0; i < elements.size(); ++i)
element_readers_.push_back(UploadElementReader::Create(elements[i]));
@@ -33,21 +34,31 @@ UploadDataStream::UploadDataStream(UploadData* upload_data)
UploadDataStream::~UploadDataStream() {
}
-int UploadDataStream::Init() {
+int UploadDataStream::Init(const CompletionCallback& callback) {
DCHECK(!initialized_successfully_);
- uint64 total_size = 0;
+ // Use fast path when initialization can be done synchronously.
+ if (IsInMemory())
+ return InitSync();
+
+ InitInternal(0, callback, OK);
+ return ERR_IO_PENDING;
+}
+
+int UploadDataStream::InitSync() {
+ DCHECK(!initialized_successfully_);
+
+ // Initialize all readers synchronously.
for (size_t i = 0; i < element_readers_.size(); ++i) {
UploadElementReader* reader = element_readers_[i];
const int result = reader->InitSync();
- if (result != OK)
+ if (result != OK) {
+ element_readers_.clear();
return result;
- if (!is_chunked())
- total_size += reader->GetContentLength();
+ }
}
- total_size_ = total_size;
- initialized_successfully_ = true;
+ FinalizeInitialization();
return OK;
}
@@ -118,4 +129,54 @@ bool UploadDataStream::IsInMemory() const {
return true;
}
+void UploadDataStream::InitInternal(int start_index,
+ const CompletionCallback& callback,
+ int previous_result) {
+ DCHECK(!initialized_successfully_);
+ DCHECK_NE(ERR_IO_PENDING, previous_result);
+
+ // Check the last result.
+ if (previous_result != OK) {
+ element_readers_.clear();
+ callback.Run(previous_result);
+ return;
+ }
+
+ // Call Init() for all elements.
+ for (size_t i = start_index; i < element_readers_.size(); ++i) {
+ UploadElementReader* reader = element_readers_[i];
+ // When new_result is ERR_IO_PENDING, InitInternal() will be called
+ // with start_index == i + 1 when reader->Init() finishes.
+ const int new_result = reader->Init(
+ base::Bind(&UploadDataStream::InitInternal,
+ weak_ptr_factory_.GetWeakPtr(),
+ i + 1,
+ callback));
+ if (new_result != OK) {
+ if (new_result != ERR_IO_PENDING) {
+ element_readers_.clear();
+ callback.Run(new_result);
+ }
+ return;
+ }
+ }
+
+ // Finalize initialization.
+ FinalizeInitialization();
+ callback.Run(OK);
+}
+
+void UploadDataStream::FinalizeInitialization() {
+ DCHECK(!initialized_successfully_);
+ if (!is_chunked()) {
+ uint64 total_size = 0;
+ for (size_t i = 0; i < element_readers_.size(); ++i) {
+ UploadElementReader* reader = element_readers_[i];
+ total_size += reader->GetContentLength();
+ }
+ total_size_ = total_size;
+ }
+ initialized_successfully_ = true;
+}
+
} // namespace net
diff --git a/net/base/upload_data_stream.h b/net/base/upload_data_stream.h
index 73c9359..8679b2c 100644
--- a/net/base/upload_data_stream.h
+++ b/net/base/upload_data_stream.h
@@ -5,8 +5,11 @@
#ifndef NET_BASE_UPLOAD_DATA_STREAM_H_
#define NET_BASE_UPLOAD_DATA_STREAM_H_
+#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
#include "net/base/upload_data.h"
@@ -24,10 +27,17 @@ class NET_EXPORT UploadDataStream {
// before calling any other method. It is not valid to call any method
// (other than the destructor) if Init() returns a failure.
//
+ // Does the initialization synchronously and returns the result if possible,
+ // otherwise returns ERR_IO_PENDING and runs the callback with the result.
+ //
// Returns OK on success. Returns ERR_UPLOAD_FILE_CHANGED if the expected
// file modification time is set (usually not set, but set for sliced
// files) and the target file is changed.
- int Init();
+ int Init(const CompletionCallback& callback);
+
+ // Initializes the stream synchronously.
+ // Use this method only in tests and Chrome Frame.
+ int InitSync();
// Reads up to |buf_len| bytes from the upload data stream to |buf|. The
// number of bytes read is returned. Partial reads are allowed. Zero is
@@ -71,6 +81,22 @@ class NET_EXPORT UploadDataStream {
friend class SpdyNetworkTransactionSpdy2Test;
friend class SpdyNetworkTransactionSpdy3Test;
+ // TODO(hashimoto): Stop directly accsssing element_readers_ from tests and
+ // remove these friend declarations.
+ FRIEND_TEST_ALL_PREFIXES(UploadDataStreamTest, InitAsync);
+ FRIEND_TEST_ALL_PREFIXES(UploadDataStreamTest, InitAsyncFailureAsync);
+ FRIEND_TEST_ALL_PREFIXES(UploadDataStreamTest, InitAsyncFailureSync);
+
+ // Runs Init() for all element readers.
+ // This method is used to implement Init().
+ void InitInternal(int start_index,
+ const CompletionCallback& callback,
+ int previous_result);
+
+ // Finalizes the initialization process.
+ // This method is used to implement Init().
+ void FinalizeInitialization();
+
// These methods are provided only to be used by unit tests.
static void ResetMergeChunks();
static void set_merge_chunks(bool merge) { merge_chunks_ = merge; }
@@ -90,6 +116,8 @@ class NET_EXPORT UploadDataStream {
// True if the initialization was successful.
bool initialized_successfully_;
+ base::WeakPtrFactory<UploadDataStream> weak_ptr_factory_;
+
// TODO(satish): Remove this once we have a better way to unit test POST
// requests with chunked uploads.
static bool merge_chunks_;
diff --git a/net/base/upload_data_stream_unittest.cc b/net/base/upload_data_stream_unittest.cc
index 8a8ec39..33d035e4 100644
--- a/net/base/upload_data_stream_unittest.cc
+++ b/net/base/upload_data_stream_unittest.cc
@@ -17,9 +17,15 @@
#include "net/base/net_errors.h"
#include "net/base/upload_data.h"
#include "net/base/upload_file_element_reader.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+using ::testing::DoAll;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::_;
+
namespace net {
namespace {
@@ -39,6 +45,46 @@ std::string ReadFromUploadDataStream(UploadDataStream* stream) {
return data_read;
}
+// A mock class of UploadElementReader.
+class MockUploadElementReader : public UploadElementReader {
+ public:
+ MockUploadElementReader() : init_result_(OK) {}
+ virtual ~MockUploadElementReader() {}
+
+ MOCK_METHOD1(Init, int(const CompletionCallback& callback));
+ MOCK_CONST_METHOD0(GetContentLength, uint64());
+ MOCK_CONST_METHOD0(BytesRemaining, uint64());
+ MOCK_CONST_METHOD0(IsInMemory, bool());
+ MOCK_METHOD2(ReadSync, int(char* buf, int buf_length));
+
+ // Sets expectation to return the specified result from Init() asynchronously.
+ void SetAsyncInitExpectation(int result) {
+ init_result_ = result;
+ EXPECT_CALL(*this, Init(_))
+ .WillOnce(DoAll(Invoke(this, &MockUploadElementReader::OnInit),
+ Return(ERR_IO_PENDING)));
+ }
+
+ private:
+ void OnInit(const CompletionCallback& callback) {
+ MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(callback, init_result_));
+ }
+
+ // Result value returned from Init().
+ int init_result_;
+};
+
+// A mock CompletionCallback.
+class MockCompletionCallback {
+ public:
+ MOCK_METHOD1(Run, void(int result));
+
+ CompletionCallback CreateCallback() {
+ return base::Bind(&MockCompletionCallback::Run, base::Unretained(this));
+ }
+};
+
} // namespace
class UploadDataStreamTest : public PlatformTest {
@@ -55,7 +101,7 @@ class UploadDataStreamTest : public PlatformTest {
TEST_F(UploadDataStreamTest, EmptyUploadData) {
upload_data_->AppendBytes("", 0);
scoped_ptr<UploadDataStream> stream(new UploadDataStream(upload_data_));
- ASSERT_EQ(OK, stream->Init());
+ ASSERT_EQ(OK, stream->InitSync());
EXPECT_TRUE(stream->IsInMemory());
ASSERT_TRUE(stream.get());
EXPECT_EQ(0U, stream->size());
@@ -66,7 +112,7 @@ TEST_F(UploadDataStreamTest, EmptyUploadData) {
TEST_F(UploadDataStreamTest, ConsumeAllBytes) {
upload_data_->AppendBytes(kTestData, kTestDataSize);
scoped_ptr<UploadDataStream> stream(new UploadDataStream(upload_data_));
- ASSERT_EQ(OK, stream->Init());
+ ASSERT_EQ(OK, stream->InitSync());
EXPECT_TRUE(stream->IsInMemory());
ASSERT_TRUE(stream.get());
EXPECT_EQ(kTestDataSize, stream->size());
@@ -94,7 +140,7 @@ TEST_F(UploadDataStreamTest, File) {
upload_data_->SetElements(elements);
scoped_ptr<UploadDataStream> stream(new UploadDataStream(upload_data_));
- ASSERT_EQ(OK, stream->Init());
+ ASSERT_EQ(OK, stream->InitSync());
EXPECT_FALSE(stream->IsInMemory());
ASSERT_TRUE(stream.get());
EXPECT_EQ(kTestDataSize, stream->size());
@@ -127,7 +173,7 @@ TEST_F(UploadDataStreamTest, FileSmallerThanLength) {
upload_data_->SetElements(elements);
scoped_ptr<UploadDataStream> stream(new UploadDataStream(upload_data_));
- ASSERT_EQ(OK, stream->Init());
+ ASSERT_EQ(OK, stream->InitSync());
EXPECT_FALSE(stream->IsInMemory());
ASSERT_TRUE(stream.get());
EXPECT_EQ(kFakeSize, stream->size());
@@ -164,7 +210,7 @@ TEST_F(UploadDataStreamTest, FileAndBytes) {
const uint64 kStreamSize = kTestDataSize + kFileRangeLength;
scoped_ptr<UploadDataStream> stream(new UploadDataStream(upload_data_));
- ASSERT_EQ(OK, stream->Init());
+ ASSERT_EQ(OK, stream->InitSync());
EXPECT_FALSE(stream->IsInMemory());
ASSERT_TRUE(stream.get());
EXPECT_EQ(kStreamSize, stream->size());
@@ -188,7 +234,7 @@ TEST_F(UploadDataStreamTest, Chunk) {
const uint64 kStreamSize = kTestDataSize*2;
scoped_ptr<UploadDataStream> stream(new UploadDataStream(upload_data_));
- ASSERT_EQ(OK, stream->Init());
+ ASSERT_EQ(OK, stream->InitSync());
EXPECT_FALSE(stream->IsInMemory());
ASSERT_TRUE(stream.get());
EXPECT_EQ(0U, stream->size()); // Content-Length is 0 for chunked data.
@@ -203,6 +249,96 @@ TEST_F(UploadDataStreamTest, Chunk) {
ASSERT_TRUE(stream->IsEOF());
}
+// Init() with on-memory and not-on-memory readers.
+TEST_F(UploadDataStreamTest, InitAsync) {
+ // Create stream without element readers.
+ UploadDataStream stream(upload_data_);
+
+ // Set mock readers to the stream.
+ MockUploadElementReader* reader = NULL;
+
+ reader = new MockUploadElementReader;
+ EXPECT_CALL(*reader, Init(_)).WillOnce(Return(OK));
+ EXPECT_CALL(*reader, GetContentLength()).WillRepeatedly(Return(0));
+ EXPECT_CALL(*reader, IsInMemory()).WillRepeatedly(Return(true));
+ stream.element_readers_.push_back(reader);
+
+ reader = new MockUploadElementReader;
+ EXPECT_CALL(*reader, Init(_)).WillOnce(Return(OK));
+ EXPECT_CALL(*reader, GetContentLength()).WillRepeatedly(Return(0));
+ EXPECT_CALL(*reader, IsInMemory()).WillRepeatedly(Return(true));
+ stream.element_readers_.push_back(reader);
+
+ reader = new MockUploadElementReader;
+ reader->SetAsyncInitExpectation(OK);
+ EXPECT_CALL(*reader, GetContentLength()).WillRepeatedly(Return(0));
+ EXPECT_CALL(*reader, IsInMemory()).WillRepeatedly(Return(false));
+ stream.element_readers_.push_back(reader);
+
+ reader = new MockUploadElementReader;
+ reader->SetAsyncInitExpectation(OK);
+ EXPECT_CALL(*reader, GetContentLength()).WillRepeatedly(Return(0));
+ EXPECT_CALL(*reader, IsInMemory()).WillRepeatedly(Return(false));
+ stream.element_readers_.push_back(reader);
+
+ reader = new MockUploadElementReader;
+ EXPECT_CALL(*reader, Init(_)).WillOnce(Return(OK));
+ EXPECT_CALL(*reader, GetContentLength()).WillRepeatedly(Return(0));
+ EXPECT_CALL(*reader, IsInMemory()).WillRepeatedly(Return(true));
+ stream.element_readers_.push_back(reader);
+
+ // Run Init().
+ MockCompletionCallback mock_callback;
+ EXPECT_CALL(mock_callback, Run(OK)).Times(1);
+ EXPECT_EQ(stream.Init(mock_callback.CreateCallback()), ERR_IO_PENDING);
+ MessageLoop::current()->RunAllPending();
+}
+
+// Init() of a reader fails asynchronously.
+TEST_F(UploadDataStreamTest, InitAsyncFailureAsync) {
+ // Create stream without element readers.
+ UploadDataStream stream(upload_data_);
+
+ // Set a mock reader to the stream.
+ MockUploadElementReader* reader = NULL;
+
+ reader = new MockUploadElementReader;
+ reader->SetAsyncInitExpectation(ERR_FAILED);
+ EXPECT_CALL(*reader, IsInMemory()).WillRepeatedly(Return(false));
+ stream.element_readers_.push_back(reader);
+
+ // Run Init().
+ MockCompletionCallback mock_callback;
+ EXPECT_CALL(mock_callback, Run(ERR_FAILED)).Times(1);
+ EXPECT_EQ(stream.Init(mock_callback.CreateCallback()), ERR_IO_PENDING);
+ MessageLoop::current()->RunAllPending();
+}
+
+// Init() of a reader fails synchronously.
+TEST_F(UploadDataStreamTest, InitAsyncFailureSync) {
+ // Create stream without element readers.
+ UploadDataStream stream(upload_data_);
+
+ // Set mock readers to the stream.
+ MockUploadElementReader* reader = NULL;
+
+ reader = new MockUploadElementReader;
+ reader->SetAsyncInitExpectation(OK);
+ EXPECT_CALL(*reader, IsInMemory()).WillRepeatedly(Return(false));
+ stream.element_readers_.push_back(reader);
+
+ reader = new MockUploadElementReader;
+ EXPECT_CALL(*reader, Init(_)).WillOnce(Return(ERR_FAILED));
+ EXPECT_CALL(*reader, IsInMemory()).WillRepeatedly(Return(true));
+ stream.element_readers_.push_back(reader);
+
+ // Run Init().
+ MockCompletionCallback mock_callback;
+ EXPECT_CALL(mock_callback, Run(ERR_FAILED)).Times(1);
+ EXPECT_EQ(stream.Init(mock_callback.CreateCallback()), ERR_IO_PENDING);
+ MessageLoop::current()->RunAllPending();
+}
+
void UploadDataStreamTest::FileChangedHelper(const FilePath& file_path,
const base::Time& time,
bool error_expected) {
@@ -216,7 +352,7 @@ void UploadDataStreamTest::FileChangedHelper(const FilePath& file_path,
upload_data->SetElements(elements);
scoped_ptr<UploadDataStream> stream(new UploadDataStream(upload_data));
- int error_code = stream->Init();
+ int error_code = stream->InitSync();
if (error_expected)
ASSERT_EQ(ERR_UPLOAD_FILE_CHANGED, error_code);
else
@@ -259,7 +395,7 @@ TEST_F(UploadDataStreamTest, UploadDataReused) {
// Confirm that the file is read properly.
{
UploadDataStream stream(upload_data_);
- ASSERT_EQ(OK, stream.Init());
+ ASSERT_EQ(OK, stream.InitSync());
EXPECT_EQ(kTestDataSize, stream.size());
EXPECT_EQ(kTestData, ReadFromUploadDataStream(&stream));
}
@@ -268,7 +404,7 @@ TEST_F(UploadDataStreamTest, UploadDataReused) {
// file is read properly.
{
UploadDataStream stream(upload_data_);
- ASSERT_EQ(OK, stream.Init());
+ ASSERT_EQ(OK, stream.InitSync());
EXPECT_EQ(kTestDataSize, stream.size());
EXPECT_EQ(kTestData, ReadFromUploadDataStream(&stream));
}
diff --git a/net/base/upload_element_reader.cc b/net/base/upload_element_reader.cc
index bb5cd85..a7f25f6 100644
--- a/net/base/upload_element_reader.cc
+++ b/net/base/upload_element_reader.cc
@@ -5,6 +5,7 @@
#include "net/base/upload_element_reader.h"
#include "base/logging.h"
+#include "net/base/net_errors.h"
#include "net/base/upload_bytes_element_reader.h"
#include "net/base/upload_element.h"
#include "net/base/upload_file_element_reader.h"
@@ -31,6 +32,11 @@ UploadElementReader* UploadElementReader::Create(const UploadElement& element) {
return reader;
}
+int UploadElementReader::InitSync() {
+ NOTREACHED() << "This instance does not support InitSync().";
+ return ERR_NOT_IMPLEMENTED;
+}
+
bool UploadElementReader::IsInMemory() const {
return false;
}
diff --git a/net/base/upload_element_reader.h b/net/base/upload_element_reader.h
index 3e8bcea..acb1eca 100644
--- a/net/base/upload_element_reader.h
+++ b/net/base/upload_element_reader.h
@@ -6,6 +6,7 @@
#define NET_BASE_UPLOAD_ELEMENT_READER_H_
#include "base/basictypes.h"
+#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
namespace net {
@@ -21,8 +22,13 @@ class NET_EXPORT UploadElementReader {
// Creates an appropriate UploadElementReader instance for the given element.
static UploadElementReader* Create(const UploadElement& element);
- // Initializes the instance synchronously.
- virtual int InitSync() = 0;
+ // Initializes the instance synchronously when possible, otherwise does
+ // initialization aynschronously, returns ERR_IO_PENDING and runs callback.
+ virtual int Init(const CompletionCallback& callback) = 0;
+
+ // Initializes the instance always synchronously.
+ // Use this method only in tests and Chrome Frame.
+ virtual int InitSync();
// Returns the byte-length of the element. For files that do not exist, 0
// is returned. This is done for consistency with Mozilla.
diff --git a/net/base/upload_file_element_reader.cc b/net/base/upload_file_element_reader.cc
index b71c022..86be79d 100644
--- a/net/base/upload_file_element_reader.cc
+++ b/net/base/upload_file_element_reader.cc
@@ -4,8 +4,11 @@
#include "net/base/upload_file_element_reader.h"
+#include "base/bind.h"
#include "base/file_util.h"
+#include "base/location.h"
#include "base/threading/thread_restrictions.h"
+#include "base/threading/worker_pool.h"
#include "net/base/file_stream.h"
#include "net/base/net_errors.h"
@@ -17,6 +20,58 @@ namespace {
// UploadFileElementReader::GetContentLength() when set to non-zero.
uint64 overriding_content_length = 0;
+// This method is used to implement Init().
+void InitInternal(const FilePath& path,
+ uint64 range_offset,
+ uint64 range_length,
+ const base::Time& expected_modification_time,
+ scoped_ptr<FileStream>* out_file_stream,
+ uint64* out_content_length,
+ int* out_result) {
+ scoped_ptr<FileStream> file_stream(new FileStream(NULL));
+ int64 rv = file_stream->OpenSync(
+ path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ);
+ if (rv != OK) {
+ // If the file can't be opened, we'll just upload an empty file.
+ DLOG(WARNING) << "Failed to open \"" << path.value()
+ << "\" for reading: " << rv;
+ file_stream.reset();
+ } else if (range_offset) {
+ rv = file_stream->SeekSync(FROM_BEGIN, range_offset);
+ if (rv < 0) {
+ DLOG(WARNING) << "Failed to seek \"" << path.value()
+ << "\" to offset: " << range_offset << " (" << rv << ")";
+ file_stream->CloseSync();
+ file_stream.reset();
+ }
+ }
+
+ int64 length = 0;
+ if (file_stream.get() &&
+ file_util::GetFileSize(path, &length) &&
+ range_offset < static_cast<uint64>(length)) {
+ // Compensate for the offset.
+ length = std::min(length - range_offset, range_length);
+ }
+ *out_content_length = length;
+ out_file_stream->swap(file_stream);
+
+ // 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.
+ if (!expected_modification_time.is_null()) {
+ base::PlatformFileInfo info;
+ if (file_util::GetFileInfo(path, &info) &&
+ expected_modification_time.ToTimeT() != info.last_modified.ToTimeT()) {
+ *out_result = ERR_UPLOAD_FILE_CHANGED;
+ return;
+ }
+ }
+
+ *out_result = OK;
+}
+
} // namespace
UploadFileElementReader::UploadFileElementReader(
@@ -29,7 +84,8 @@ UploadFileElementReader::UploadFileElementReader(
range_length_(range_length),
expected_modification_time_(expected_modification_time),
content_length_(0),
- bytes_remaining_(0) {
+ bytes_remaining_(0),
+ weak_ptr_factory_(this) {
}
UploadFileElementReader::~UploadFileElementReader() {
@@ -39,56 +95,42 @@ UploadFileElementReader::~UploadFileElementReader() {
file_stream_->CloseSync();
}
+int UploadFileElementReader::Init(const CompletionCallback& callback) {
+ scoped_ptr<FileStream>* file_stream = new scoped_ptr<FileStream>;
+ uint64* content_length = new uint64;
+ int* result = new int;
+ const bool posted = base::WorkerPool::PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&InitInternal,
+ path_,
+ range_offset_,
+ range_length_,
+ expected_modification_time_,
+ file_stream,
+ content_length,
+ result),
+ base::Bind(&UploadFileElementReader::OnInitCompleted,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Owned(file_stream),
+ base::Owned(content_length),
+ base::Owned(result),
+ callback),
+ true /* task_is_slow */);
+ DCHECK(posted);
+ return ERR_IO_PENDING;
+}
+
int UploadFileElementReader::InitSync() {
// Temporarily allow until fix: http://crbug.com/72001.
base::ThreadRestrictions::ScopedAllowIO allow_io;
- scoped_ptr<FileStream> file_stream(new FileStream(NULL));
- int64 rv = file_stream->OpenSync(
- path_, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ);
- if (rv != OK) {
- // If the file can't be opened, we'll just upload an empty file.
- DLOG(WARNING) << "Failed to open \"" << path_.value()
- << "\" for reading: " << rv;
- file_stream.reset();
- }
- if (file_stream.get() && range_offset_) {
- rv = file_stream->SeekSync(FROM_BEGIN, range_offset_);
- if (rv < 0) {
- DLOG(WARNING) << "Failed to seek \"" << path_.value()
- << "\" to offset: " << range_offset_ << " (" << rv
- << ")";
- file_stream->CloseSync();
- file_stream.reset();
- }
- }
- file_stream_.reset(file_stream.release());
-
- int64 length = 0;
- if (file_stream_.get() &&
- file_util::GetFileSize(path_, &length) &&
- range_offset_ < static_cast<uint64>(length)) {
- // Compensate for the offset.
- length = std::min(length - range_offset_, range_length_);
- }
- content_length_ = length;
- bytes_remaining_ = GetContentLength();
-
- // 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.
- if (!expected_modification_time_.is_null()) {
- base::PlatformFileInfo info;
- if (file_util::GetFileInfo(path_, &info) &&
- expected_modification_time_.ToTimeT() !=
- info.last_modified.ToTimeT()) {
- return ERR_UPLOAD_FILE_CHANGED;
- }
- }
-
- return OK;
+ scoped_ptr<FileStream> file_stream;
+ uint64 content_length = 0;
+ int result = OK;
+ InitInternal(path_, range_offset_, range_length_, expected_modification_time_,
+ &file_stream, &content_length, &result);
+ OnInitCompleted(&file_stream, &content_length, &result, CompletionCallback());
+ return result;
}
uint64 UploadFileElementReader::GetContentLength() const {
@@ -129,6 +171,18 @@ int UploadFileElementReader::ReadSync(char* buf, int buf_length) {
return num_bytes_to_read;
}
+void UploadFileElementReader::OnInitCompleted(
+ scoped_ptr<FileStream>* file_stream,
+ uint64* content_length,
+ int* result,
+ const CompletionCallback& callback) {
+ file_stream_.swap(*file_stream);
+ content_length_ = *content_length;
+ bytes_remaining_ = GetContentLength();
+ if (!callback.is_null())
+ callback.Run(*result);
+}
+
UploadFileElementReader::ScopedOverridingContentLengthForTests::
ScopedOverridingContentLengthForTests(uint64 value) {
overriding_content_length = value;
diff --git a/net/base/upload_file_element_reader.h b/net/base/upload_file_element_reader.h
index 34d8194..cc8e830 100644
--- a/net/base/upload_file_element_reader.h
+++ b/net/base/upload_file_element_reader.h
@@ -9,6 +9,7 @@
#include "base/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/time.h"
#include "net/base/upload_element_reader.h"
@@ -26,12 +27,19 @@ class NET_EXPORT_PRIVATE UploadFileElementReader : public UploadElementReader {
virtual ~UploadFileElementReader();
// UploadElementReader overrides:
+ virtual int Init(const CompletionCallback& callback) OVERRIDE;
virtual int InitSync() OVERRIDE;
virtual uint64 GetContentLength() const OVERRIDE;
virtual uint64 BytesRemaining() const OVERRIDE;
virtual int ReadSync(char* buf, int buf_length) OVERRIDE;
private:
+ // This method is used to implement Init().
+ void OnInitCompleted(scoped_ptr<FileStream>* file_stream,
+ uint64* content_length,
+ int* result,
+ const CompletionCallback& callback);
+
// Sets an value to override the result for GetContentLength().
// Used for tests.
struct NET_EXPORT_PRIVATE ScopedOverridingContentLengthForTests {
@@ -46,6 +54,7 @@ class NET_EXPORT_PRIVATE UploadFileElementReader : public UploadElementReader {
scoped_ptr<FileStream> file_stream_;
uint64 content_length_;
uint64 bytes_remaining_;
+ base::WeakPtrFactory<UploadFileElementReader> weak_ptr_factory_;
FRIEND_TEST_ALL_PREFIXES(UploadDataStreamTest, FileSmallerThanLength);
FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionTest,
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 844fc34b..f987806 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -747,7 +747,7 @@ int HttpNetworkTransaction::DoBuildRequest() {
request_body_.reset(NULL);
if (request_->upload_data) {
request_body_.reset(new UploadDataStream(request_->upload_data));
- const int error_code = request_body_->Init();
+ const int error_code = request_body_->InitSync();
if (error_code != OK) {
request_body_.reset(NULL);
return error_code;
diff --git a/net/http/http_stream_parser_unittest.cc b/net/http/http_stream_parser_unittest.cc
index b6cb778..9ef3cc7 100644
--- a/net/http/http_stream_parser_unittest.cc
+++ b/net/http/http_stream_parser_unittest.cc
@@ -97,7 +97,7 @@ TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_NoBody) {
TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_EmptyBody) {
scoped_refptr<UploadData> upload_data = new UploadData;
scoped_ptr<UploadDataStream> body(new UploadDataStream(upload_data));
- ASSERT_EQ(OK, body->Init());
+ ASSERT_EQ(OK, body->InitSync());
// Shouldn't be merged if upload data is empty.
ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
"some header", body.get()));
@@ -110,7 +110,7 @@ TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_ChunkedBody) {
upload_data->AppendChunk(payload.data(), payload.size(), true);
scoped_ptr<UploadDataStream> body(new UploadDataStream(upload_data));
- ASSERT_EQ(OK, body->Init());
+ ASSERT_EQ(OK, body->InitSync());
// Shouldn't be merged if upload data carries chunked data.
ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
"some header", body.get()));
@@ -129,7 +129,7 @@ TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_FileBody) {
upload_data->AppendFileRange(temp_file_path, 0, 0, base::Time());
scoped_ptr<UploadDataStream> body(new UploadDataStream(upload_data));
- ASSERT_EQ(OK, body->Init());
+ ASSERT_EQ(OK, body->InitSync());
// Shouldn't be merged if upload data carries a file, as it's not in-memory.
ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
"some header", body.get()));
@@ -141,7 +141,7 @@ TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_SmallBodyInMemory) {
upload_data->AppendBytes(payload.data(), payload.size());
scoped_ptr<UploadDataStream> body(new UploadDataStream(upload_data));
- ASSERT_EQ(OK, body->Init());
+ ASSERT_EQ(OK, body->InitSync());
// Yes, should be merged if the in-memory body is small here.
ASSERT_TRUE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
"some header", body.get()));
@@ -153,7 +153,7 @@ TEST(HttpStreamParser, ShouldMergeRequestHeadersAndBody_LargeBodyInMemory) {
upload_data->AppendBytes(payload.data(), payload.size());
scoped_ptr<UploadDataStream> body(new UploadDataStream(upload_data));
- ASSERT_EQ(OK, body->Init());
+ ASSERT_EQ(OK, body->InitSync());
// Shouldn't be merged if the in-memory body is large here.
ASSERT_FALSE(HttpStreamParser::ShouldMergeRequestHeadersAndBody(
"some header", body.get()));
@@ -226,7 +226,7 @@ TEST(HttpStreamParser, AsyncChunkAndAsyncSocket) {
scoped_ptr<UploadDataStream> upload_stream(
new UploadDataStream(upload_data));
- ASSERT_EQ(OK, upload_stream->Init());
+ ASSERT_EQ(OK, upload_stream->InitSync());
HttpRequestHeaders request_headers;
request_headers.SetHeader("Host", "localhost");
diff --git a/net/spdy/spdy_http_stream_spdy2_unittest.cc b/net/spdy/spdy_http_stream_spdy2_unittest.cc
index 58461ab..aec278a 100644
--- a/net/spdy/spdy_http_stream_spdy2_unittest.cc
+++ b/net/spdy/spdy_http_stream_spdy2_unittest.cc
@@ -164,7 +164,7 @@ TEST_F(SpdyHttpStreamSpdy2Test, SendChunkedPost) {
scoped_ptr<UploadDataStream> upload_stream(
new UploadDataStream(request.upload_data));
- ASSERT_EQ(OK, upload_stream->Init());
+ ASSERT_EQ(OK, upload_stream->InitSync());
EXPECT_EQ(ERR_IO_PENDING, http_stream.SendRequest(
headers, upload_stream.Pass(), &response, callback.callback()));
EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
@@ -259,7 +259,7 @@ TEST_F(SpdyHttpStreamSpdy2Test, DelayedSendChunkedPost) {
scoped_ptr<UploadDataStream> upload_stream(
new UploadDataStream(request.upload_data));
- ASSERT_EQ(OK, upload_stream->Init());
+ ASSERT_EQ(OK, upload_stream->InitSync());
request.upload_data->AppendChunk(kUploadData, kUploadDataSize, false);
diff --git a/net/spdy/spdy_http_stream_spdy3_unittest.cc b/net/spdy/spdy_http_stream_spdy3_unittest.cc
index 91acad0..bcd02d3 100644
--- a/net/spdy/spdy_http_stream_spdy3_unittest.cc
+++ b/net/spdy/spdy_http_stream_spdy3_unittest.cc
@@ -173,7 +173,7 @@ TEST_F(SpdyHttpStreamSpdy3Test, SendChunkedPost) {
scoped_ptr<UploadDataStream> upload_stream(
new UploadDataStream(request.upload_data));
- ASSERT_EQ(OK, upload_stream->Init());
+ ASSERT_EQ(OK, upload_stream->InitSync());
EXPECT_EQ(ERR_IO_PENDING, http_stream.SendRequest(
headers, upload_stream.Pass(), &response, callback.callback()));
EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
@@ -268,7 +268,7 @@ TEST_F(SpdyHttpStreamSpdy3Test, DelayedSendChunkedPost) {
scoped_ptr<UploadDataStream> upload_stream(
new UploadDataStream(request.upload_data));
- ASSERT_EQ(OK, upload_stream->Init());
+ ASSERT_EQ(OK, upload_stream->InitSync());
request.upload_data->AppendChunk(kUploadData, kUploadDataSize, false);
@@ -404,7 +404,7 @@ TEST_F(SpdyHttpStreamSpdy3Test, DelayedSendChunkedPostWithWindowUpdate) {
scoped_ptr<UploadDataStream> upload_stream(
new UploadDataStream(request.upload_data));
- ASSERT_EQ(OK, upload_stream->Init());
+ ASSERT_EQ(OK, upload_stream->InitSync());
request.upload_data->AppendChunk(kUploadData, kUploadDataSize, true);
diff --git a/net/spdy/spdy_network_transaction_spdy2_unittest.cc b/net/spdy/spdy_network_transaction_spdy2_unittest.cc
index b3afbf9..8710a38 100644
--- a/net/spdy/spdy_network_transaction_spdy2_unittest.cc
+++ b/net/spdy/spdy_network_transaction_spdy2_unittest.cc
@@ -1655,7 +1655,7 @@ TEST_P(SpdyNetworkTransactionSpdy2Test, EmptyPost) {
const uint64 kContentLength = 0;
scoped_ptr<UploadDataStream> stream(
new UploadDataStream(request.upload_data));
- ASSERT_EQ(OK, stream->Init());
+ ASSERT_EQ(OK, stream->InitSync());
ASSERT_EQ(kContentLength, stream->size());
scoped_ptr<SpdyFrame> req(ConstructSpdyPost(kContentLength, NULL, 0));
@@ -1700,7 +1700,7 @@ TEST_P(SpdyNetworkTransactionSpdy2Test, PostWithEarlySynReply) {
const uint64 kContentLength = sizeof(upload);
scoped_ptr<UploadDataStream> stream(
new UploadDataStream(request.upload_data));
- ASSERT_EQ(OK, stream->Init());
+ ASSERT_EQ(OK, stream->InitSync());
ASSERT_EQ(kContentLength, stream->size());
scoped_ptr<SpdyFrame> stream_reply(ConstructSpdyPostSynReply(NULL, 0));
scoped_ptr<SpdyFrame> stream_body(ConstructSpdyBodyFrame(1, true));
diff --git a/net/spdy/spdy_network_transaction_spdy3_unittest.cc b/net/spdy/spdy_network_transaction_spdy3_unittest.cc
index a348213..a43ceb4 100644
--- a/net/spdy/spdy_network_transaction_spdy3_unittest.cc
+++ b/net/spdy/spdy_network_transaction_spdy3_unittest.cc
@@ -1661,7 +1661,7 @@ TEST_P(SpdyNetworkTransactionSpdy3Test, EmptyPost) {
const uint64 kContentLength = 0;
scoped_ptr<UploadDataStream> stream(
new UploadDataStream(request.upload_data));
- ASSERT_EQ(OK, stream->Init());
+ ASSERT_EQ(OK, stream->InitSync());
ASSERT_EQ(kContentLength, stream->size());
scoped_ptr<SpdyFrame> req(ConstructSpdyPost(kContentLength, NULL, 0));
@@ -1706,7 +1706,7 @@ TEST_P(SpdyNetworkTransactionSpdy3Test, PostWithEarlySynReply) {
const uint64 kContentLength = sizeof(upload);
scoped_ptr<UploadDataStream> stream(
new UploadDataStream(request.upload_data));
- ASSERT_EQ(OK, stream->Init());
+ ASSERT_EQ(OK, stream->InitSync());
ASSERT_EQ(kContentLength, stream->size());
scoped_ptr<SpdyFrame> stream_reply(ConstructSpdyPostSynReply(NULL, 0));
scoped_ptr<SpdyFrame> stream_body(ConstructSpdyBodyFrame(1, true));