summaryrefslogtreecommitdiffstats
path: root/net/base
diff options
context:
space:
mode:
Diffstat (limited to 'net/base')
-rw-r--r--net/base/net_error_list.h4
-rw-r--r--net/base/upload_data.h21
-rw-r--r--net/base/upload_data_stream.cc30
-rw-r--r--net/base/upload_data_stream.h13
-rw-r--r--net/base/upload_data_stream_unittest.cc73
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);
}