diff options
author | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-24 23:37:50 +0000 |
---|---|---|
committer | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-24 23:37:50 +0000 |
commit | 7a6db4024aa668fd49741c4c34965ab674efaac6 (patch) | |
tree | 291de61ee2f86da940a5c9c0a67a79d394478a8e /net | |
parent | e8b3ddfde11a59bc910697090906dd36f0426401 (diff) | |
download | chromium_src-7a6db4024aa668fd49741c4c34965ab674efaac6.zip chromium_src-7a6db4024aa668fd49741c4c34965ab674efaac6.tar.gz chromium_src-7a6db4024aa668fd49741c4c34965ab674efaac6.tar.bz2 |
Support sending a sliced file in chromium.
BUG=none
TEST=The WebKit Layout test.
Review URL: http://codereview.chromium.org/594036
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42559 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/net_error_list.h | 4 | ||||
-rw-r--r-- | net/base/upload_data.h | 21 | ||||
-rw-r--r-- | net/base/upload_data_stream.cc | 30 | ||||
-rw-r--r-- | net/base/upload_data_stream.h | 13 | ||||
-rw-r--r-- | net/base/upload_data_stream_unittest.cc | 73 | ||||
-rw-r--r-- | net/http/http_network_transaction.cc | 17 | ||||
-rw-r--r-- | net/spdy/spdy_network_transaction.cc | 9 | ||||
-rw-r--r-- | net/url_request/url_request.cc | 10 | ||||
-rw-r--r-- | net/url_request/url_request.h | 10 |
9 files changed, 156 insertions, 31 deletions
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 9c83568..50d528a 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -58,6 +58,10 @@ NET_ERROR(INSUFFICIENT_RESOURCES, -12) // Memory allocation failed. NET_ERROR(OUT_OF_MEMORY, -13) +// The file upload failed because the file's modification time was different +// from the expectation. +NET_ERROR(UPLOAD_FILE_CHANGED, -14) + // A connection was closed (corresponding to a TCP FIN). NET_ERROR(CONNECTION_CLOSED, -100) diff --git a/net/base/upload_data.h b/net/base/upload_data.h index 3aab835..869ab68 100644 --- a/net/base/upload_data.h +++ b/net/base/upload_data.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/file_path.h" #include "base/ref_counted.h" +#include "base/time.h" #include "testing/gtest/include/gtest/gtest_prod.h" namespace net { @@ -35,6 +36,10 @@ class UploadData : public base::RefCounted<UploadData> { const FilePath& file_path() const { return file_path_; } uint64 file_range_offset() const { return file_range_offset_; } uint64 file_range_length() const { return file_range_length_; } + // If NULL time is returned, we do not do the check. + const base::Time& expected_file_modification_time() const { + return expected_file_modification_time_; + } void SetToBytes(const char* bytes, int bytes_len) { type_ = TYPE_BYTES; @@ -42,15 +47,20 @@ class UploadData : public base::RefCounted<UploadData> { } void SetToFilePath(const FilePath& path) { - SetToFilePathRange(path, 0, kuint64max); + SetToFilePathRange(path, 0, kuint64max, base::Time()); } + // If expected_modification_time is NULL, we do not check for the file + // change. Also note that the granularity for comparison is time_t, not + // the full precision. void SetToFilePathRange(const FilePath& path, - uint64 offset, uint64 length) { + uint64 offset, uint64 length, + const base::Time& expected_modification_time) { type_ = TYPE_FILE; file_path_ = path; file_range_offset_ = offset; file_range_length_ = length; + expected_file_modification_time_ = expected_modification_time; } // Returns the byte-length of the element. For files that do not exist, 0 @@ -69,6 +79,7 @@ class UploadData : public base::RefCounted<UploadData> { FilePath file_path_; uint64 file_range_offset_; uint64 file_range_length_; + base::Time expected_file_modification_time_; bool override_content_length_; uint64 content_length_; @@ -89,9 +100,11 @@ class UploadData : public base::RefCounted<UploadData> { } void AppendFileRange(const FilePath& file_path, - uint64 offset, uint64 length) { + uint64 offset, uint64 length, + const base::Time& expected_modification_time) { elements_.push_back(Element()); - elements_.back().SetToFilePathRange(file_path, offset, length); + elements_.back().SetToFilePathRange(file_path, offset, length, + expected_modification_time); } // Returns the total size in bytes of the data to upload. diff --git a/net/base/upload_data_stream.cc b/net/base/upload_data_stream.cc index 21f4ce8..a3a67fa 100644 --- a/net/base/upload_data_stream.cc +++ b/net/base/upload_data_stream.cc @@ -4,12 +4,25 @@ #include "net/base/upload_data_stream.h" +#include "base/file_util.h" #include "base/logging.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" namespace net { +UploadDataStream* UploadDataStream::Create(const UploadData* data, + int* error_code) { + scoped_ptr<UploadDataStream> stream(new UploadDataStream(data)); + int rv = stream->FillBuf(); + if (error_code) + *error_code = rv; + if (rv != OK) + return NULL; + + return stream.release(); +} + UploadDataStream::UploadDataStream(const UploadData* data) : data_(data), buf_(new IOBuffer(kBufSize)), @@ -20,7 +33,6 @@ UploadDataStream::UploadDataStream(const UploadData* data) total_size_(data->GetContentLength()), current_position_(0), eof_(false) { - FillBuf(); } UploadDataStream::~UploadDataStream() { @@ -39,7 +51,7 @@ void UploadDataStream::DidConsume(size_t num_bytes) { current_position_ += num_bytes; } -void UploadDataStream::FillBuf() { +int UploadDataStream::FillBuf() { std::vector<UploadData::Element>::const_iterator end = data_->elements().end(); @@ -66,6 +78,18 @@ void UploadDataStream::FillBuf() { } else { DCHECK(element.type() == UploadData::TYPE_FILE); + // If the underlying file has been changed, 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. + if (!element.expected_file_modification_time().is_null()) { + file_util::FileInfo info; + if (file_util::GetFileInfo(element.file_path(), &info) && + element.expected_file_modification_time().ToTimeT() != + info.last_modified.ToTimeT()) { + return ERR_UPLOAD_FILE_CHANGED; + } + } + if (!next_element_stream_.IsOpen()) { int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ; @@ -110,6 +134,8 @@ void UploadDataStream::FillBuf() { if (next_element_ == end && !buf_len_) eof_ = true; + + return OK; } } // namespace net diff --git a/net/base/upload_data_stream.h b/net/base/upload_data_stream.h index 0dd7dd3..b326dae 100644 --- a/net/base/upload_data_stream.h +++ b/net/base/upload_data_stream.h @@ -14,7 +14,11 @@ class IOBuffer; class UploadDataStream { public: - explicit UploadDataStream(const UploadData* data); + // Returns a new instance of UploadDataStream if it can be created and + // initialized successfully. If not, NULL will be returned and the error + // code will be set if the output parameter error_code is not empty. + static UploadDataStream* Create(const UploadData* data, int* error_code); + ~UploadDataStream(); // Returns the stream's buffer and buffer length. @@ -38,9 +42,14 @@ class UploadDataStream { bool eof() const { return eof_; } private: + // Protects from public access since now we have a static creator function + // which will do both creation and initialization and might return an error. + explicit UploadDataStream(const UploadData* data); + // Fills the buffer with any remaining data and sets eof_ if there was nothing // left to fill the buffer with. - void FillBuf(); + // Returns OK if the operation succeeds. Otherwise error code is returned. + int FillBuf(); const UploadData* data_; diff --git a/net/base/upload_data_stream_unittest.cc b/net/base/upload_data_stream_unittest.cc index ae8f7ff..701bad9 100644 --- a/net/base/upload_data_stream_unittest.cc +++ b/net/base/upload_data_stream_unittest.cc @@ -9,6 +9,9 @@ #include "base/basictypes.h" #include "base/file_path.h" #include "base/file_util.h" +#include "base/scoped_ptr.h" +#include "base/time.h" +#include "net/base/net_errors.h" #include "net/base/upload_data.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -26,20 +29,28 @@ class UploadDataStreamTest : public PlatformTest { public: UploadDataStreamTest() : upload_data_(new UploadData) { } + void FileChangedHelper(const FilePath& file_path, + const base::Time& time, + bool error_expected); + scoped_refptr<UploadData> upload_data_; }; TEST_F(UploadDataStreamTest, EmptyUploadData) { upload_data_->AppendBytes("", 0); - UploadDataStream stream(upload_data_); - EXPECT_TRUE(stream.eof()); + scoped_ptr<UploadDataStream> stream( + UploadDataStream::Create(upload_data_, NULL)); + ASSERT_TRUE(stream.get()); + EXPECT_TRUE(stream->eof()); } TEST_F(UploadDataStreamTest, ConsumeAll) { upload_data_->AppendBytes(kTestData, kTestDataSize); - UploadDataStream stream(upload_data_); - while (!stream.eof()) { - stream.DidConsume(stream.buf_len()); + scoped_ptr<UploadDataStream> stream( + UploadDataStream::Create(upload_data_, NULL)); + ASSERT_TRUE(stream.get()); + while (!stream->eof()) { + stream->DidConsume(stream->buf_len()); } } @@ -58,14 +69,54 @@ TEST_F(UploadDataStreamTest, FileSmallerThanLength) { upload_data_->set_elements(elements); EXPECT_EQ(kFakeSize, upload_data_->GetContentLength()); - UploadDataStream stream(upload_data_); - EXPECT_FALSE(stream.eof()); + scoped_ptr<UploadDataStream> stream( + UploadDataStream::Create(upload_data_, NULL)); + ASSERT_TRUE(stream.get()); + EXPECT_FALSE(stream->eof()); uint64 read_counter = 0; - while (!stream.eof()) { - read_counter += stream.buf_len(); - stream.DidConsume(stream.buf_len()); + while (!stream->eof()) { + read_counter += stream->buf_len(); + stream->DidConsume(stream->buf_len()); } - EXPECT_LT(read_counter, stream.size()); + EXPECT_LT(read_counter, stream->size()); + + file_util::Delete(temp_file_path, false); +} + +void UploadDataStreamTest::FileChangedHelper(const FilePath& file_path, + const base::Time& time, + bool error_expected) { + std::vector<UploadData::Element> elements; + UploadData::Element element; + element.SetToFilePathRange(file_path, 1, 2, time); + elements.push_back(element); + upload_data_->set_elements(elements); + + int error_code; + scoped_ptr<UploadDataStream> stream( + UploadDataStream::Create(upload_data_, &error_code)); + if (error_expected) + ASSERT_TRUE(!stream.get() && error_code == net::ERR_UPLOAD_FILE_CHANGED); + else + ASSERT_TRUE(stream.get() && error_code == net::OK); +} + +TEST_F(UploadDataStreamTest, FileChanged) { + FilePath temp_file_path; + ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file_path)); + ASSERT_EQ(kTestDataSize, file_util::WriteFile(temp_file_path, + kTestData, kTestDataSize)); + + file_util::FileInfo file_info; + ASSERT_TRUE(file_util::GetFileInfo(temp_file_path, &file_info)); + + // Test file not changed. + FileChangedHelper(temp_file_path, file_info.last_modified, false); + + // Test file changed. + FileChangedHelper(temp_file_path, + file_info.last_modified - base::TimeDelta::FromSeconds(1), + true); file_util::Delete(temp_file_path, false); } diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 1a2c9a0..218f26d 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -887,8 +887,12 @@ int HttpNetworkTransaction::DoSendRequest() { next_state_ = STATE_SEND_REQUEST_COMPLETE; UploadDataStream* request_body = NULL; - if (!establishing_tunnel_ && request_->upload_data) - request_body = new UploadDataStream(request_->upload_data); + if (!establishing_tunnel_ && request_->upload_data) { + int error_code; + request_body = UploadDataStream::Create(request_->upload_data, &error_code); + if (!request_body) + return error_code; + } // This is constructed lazily (instead of within our Start method), so that // we have proxy info available. @@ -1187,8 +1191,13 @@ int HttpNetworkTransaction::DoSpdySendRequest() { CHECK(spdy_session.get()); - UploadDataStream* upload_data = request_->upload_data ? - new UploadDataStream(request_->upload_data) : NULL; + UploadDataStream* upload_data = NULL; + if (request_->upload_data) { + int error_code = OK; + upload_data = UploadDataStream::Create(request_->upload_data, &error_code); + if (!upload_data) + return error_code; + } headers_valid_ = false; spdy_stream_ = spdy_session->GetOrCreateStream( *request_, upload_data, net_log_); diff --git a/net/spdy/spdy_network_transaction.cc b/net/spdy/spdy_network_transaction.cc index d7de332..c35c934 100644 --- a/net/spdy/spdy_network_transaction.cc +++ b/net/spdy/spdy_network_transaction.cc @@ -246,8 +246,13 @@ int SpdyNetworkTransaction::DoInitConnectionComplete(int result) { int SpdyNetworkTransaction::DoSendRequest() { next_state_ = STATE_SEND_REQUEST_COMPLETE; CHECK(!stream_.get()); - UploadDataStream* upload_data = request_->upload_data ? - new UploadDataStream(request_->upload_data) : NULL; + UploadDataStream* upload_data = NULL; + if (request_->upload_data) { + int error_code; + upload_data = UploadDataStream::Create(request_->upload_data, &error_code); + if (!upload_data) + return error_code; + } stream_ = spdy_->GetOrCreateStream(*request_, upload_data, net_log_); // Release the reference to |spdy_| since we don't need it anymore. spdy_ = NULL; diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index a44792d..7ada4a9 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc @@ -86,12 +86,16 @@ void URLRequest::AppendBytesToUpload(const char* bytes, int bytes_len) { upload_->AppendBytes(bytes, bytes_len); } -void URLRequest::AppendFileRangeToUpload(const FilePath& file_path, - uint64 offset, uint64 length) { +void URLRequest::AppendFileRangeToUpload( + const FilePath& file_path, + uint64 offset, + uint64 length, + const base::Time& expected_modification_time) { DCHECK(file_path.value().length() > 0 && length > 0); if (!upload_) upload_ = new UploadData(); - upload_->AppendFileRange(file_path, offset, length); + upload_->AppendFileRange(file_path, offset, length, + expected_modification_time); } void URLRequest::set_upload(net::UploadData* upload) { diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h index 81d2436..438621b 100644 --- a/net/url_request/url_request.h +++ b/net/url_request/url_request.h @@ -299,12 +299,16 @@ class URLRequest { // // When uploading data, bytes_len must be non-zero. // When uploading a file range, length must be non-zero. If length - // exceeds the end-of-file, the upload is clipped at end-of-file. + // exceeds the end-of-file, the upload is clipped at end-of-file. If the + // expected modification time is provided (non-zero), it will be used to + // check if the underlying file has been changed or not. The granularity of + // the time comparison is 1 second since time_t precision is used in WebKit. void AppendBytesToUpload(const char* bytes, int bytes_len); void AppendFileRangeToUpload(const FilePath& file_path, - uint64 offset, uint64 length); + uint64 offset, uint64 length, + const base::Time& expected_modification_time); void AppendFileToUpload(const FilePath& file_path) { - AppendFileRangeToUpload(file_path, 0, kuint64max); + AppendFileRangeToUpload(file_path, 0, kuint64max, base::Time()); } // Set the upload data directly. |