diff options
Diffstat (limited to 'net/base')
-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 |
5 files changed, 122 insertions, 19 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); } |