summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorjianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-24 23:37:50 +0000
committerjianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-24 23:37:50 +0000
commit7a6db4024aa668fd49741c4c34965ab674efaac6 (patch)
tree291de61ee2f86da940a5c9c0a67a79d394478a8e /net
parente8b3ddfde11a59bc910697090906dd36f0426401 (diff)
downloadchromium_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.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
-rw-r--r--net/http/http_network_transaction.cc17
-rw-r--r--net/spdy/spdy_network_transaction.cc9
-rw-r--r--net/url_request/url_request.cc10
-rw-r--r--net/url_request/url_request.h10
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.