summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/features_override.gypi1
-rw-r--r--chrome/browser/chrome_plugin_host.cc3
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc52
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.h11
-rw-r--r--chrome/common/common_param_traits.h7
-rw-r--r--chrome/common/render_messages_internal.h7
-rw-r--r--chrome/common/resource_dispatcher.cc13
-rw-r--r--chrome/plugin/chrome_plugin_host.cc6
-rw-r--r--chrome/renderer/renderer_webkitclient_impl.cc15
-rw-r--r--chrome/renderer/renderer_webkitclient_impl.h2
-rw-r--r--chrome/renderer/translate/page_translator_unittest.cc7
-rw-r--r--chrome_frame/urlmon_upload_data_stream.cc8
-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
-rw-r--r--webkit/glue/glue_serialize.cc18
-rw-r--r--webkit/glue/glue_serialize_unittest.cc1
-rw-r--r--webkit/glue/mock_resource_loader_bridge.h8
-rw-r--r--webkit/glue/resource_loader_bridge.h9
-rw-r--r--webkit/glue/webkitclient_impl.cc2
-rw-r--r--webkit/glue/webkitclient_impl.h3
-rw-r--r--webkit/glue/weburlloader_impl.cc11
-rw-r--r--webkit/tools/test_shell/simple_resource_loader_bridge.cc10
-rw-r--r--webkit/tools/test_shell/test_shell_webkit_init.h9
30 files changed, 324 insertions, 66 deletions
diff --git a/build/features_override.gypi b/build/features_override.gypi
index e511957..4b289b1 100644
--- a/build/features_override.gypi
+++ b/build/features_override.gypi
@@ -11,6 +11,7 @@
# but not listed below, it will revert to its hardcoded webkit value.
'feature_defines': [
'ENABLE_3D_CANVAS=1',
+ 'ENABLE_BLOB_SLICE=1',
'ENABLE_CHANNEL_MESSAGING=1',
'ENABLE_DATABASE=1',
'ENABLE_DATAGRID=0',
diff --git a/chrome/browser/chrome_plugin_host.cc b/chrome/browser/chrome_plugin_host.cc
index 50d9abc..56d8828 100644
--- a/chrome/browser/chrome_plugin_host.cc
+++ b/chrome/browser/chrome_plugin_host.cc
@@ -656,7 +656,8 @@ CPError STDCALL CPR_AppendFileToUpload(CPRequest* request, const char* filepath,
if (!length) length = kuint64max;
FilePath path(FilePath::FromWStringHack(UTF8ToWide(filepath)));
- handler->request()->AppendFileRangeToUpload(path, offset, length);
+ handler->request()->AppendFileRangeToUpload(path, offset, length,
+ base::Time());
return CPERR_SUCCESS;
}
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc
index 48c1cb6..de9e836 100644
--- a/chrome/browser/renderer_host/resource_message_filter.cc
+++ b/chrome/browser/renderer_host/resource_message_filter.cc
@@ -265,6 +265,17 @@ class GetRawCookiesCompletion : public net::CompletionCallback {
scoped_refptr<URLRequestContext> context_;
};
+void WriteFileSize(IPC::Message* reply_msg,
+ const file_util::FileInfo& file_info) {
+ ViewHostMsg_GetFileSize::WriteReplyParams(reply_msg, file_info.size);
+}
+
+void WriteFileModificationTime(IPC::Message* reply_msg,
+ const file_util::FileInfo& file_info) {
+ ViewHostMsg_GetFileModificationTime::WriteReplyParams(
+ reply_msg, file_info.last_modified);
+}
+
} // namespace
ResourceMessageFilter::ResourceMessageFilter(
@@ -520,6 +531,8 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) {
OnCloseCurrentConnections)
IPC_MESSAGE_HANDLER(ViewHostMsg_SetCacheMode, OnSetCacheMode)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetFileSize, OnGetFileSize)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetFileModificationTime,
+ OnGetFileModificationTime)
IPC_MESSAGE_HANDLER(ViewHostMsg_Keygen, OnKeygen)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_GetExtensionMessageBundle,
OnGetExtensionMessageBundle)
@@ -1318,18 +1331,41 @@ void ResourceMessageFilter::OnGetFileSize(const FilePath& path,
ChromeThread::PostTask(
ChromeThread::FILE, FROM_HERE,
NewRunnableMethod(
- this, &ResourceMessageFilter::OnGetFileSizeOnFileThread, path,
- reply_msg));
+ this, &ResourceMessageFilter::OnGetFileInfoOnFileThread, path,
+ reply_msg, &WriteFileSize));
}
-void ResourceMessageFilter::OnGetFileSizeOnFileThread(
- const FilePath& path, IPC::Message* reply_msg) {
+void ResourceMessageFilter::OnGetFileModificationTime(const FilePath& path,
+ IPC::Message* reply_msg) {
+ // Get file modification time only when the child process has been granted
+ // permission to upload the file.
+ if (!ChildProcessSecurityPolicy::GetInstance()->CanUploadFile(id(), path)) {
+ ViewHostMsg_GetFileModificationTime::WriteReplyParams(reply_msg,
+ base::Time());
+ Send(reply_msg);
+ return;
+ }
+
+ // Getting file modification time could take a long time if it lives on a
+ // network share, so run it on the FILE thread.
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(
+ this, &ResourceMessageFilter::OnGetFileInfoOnFileThread,
+ path, reply_msg, &WriteFileModificationTime));
+}
+
+void ResourceMessageFilter::OnGetFileInfoOnFileThread(
+ const FilePath& path,
+ IPC::Message* reply_msg,
+ FileInfoWriteFunc write_func) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
- int64 result;
- if (!file_util::GetFileSize(path, &result))
- result = -1;
- ViewHostMsg_GetFileSize::WriteReplyParams(reply_msg, result);
+ file_util::FileInfo file_info;
+ file_info.size = 0;
+ file_util::GetFileInfo(path, &file_info);
+
+ (*write_func)(reply_msg, file_info);
ChromeThread::PostTask(
ChromeThread::IO, FROM_HERE,
diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h
index c903f6e..2abc4c0 100644
--- a/chrome/browser/renderer_host/resource_message_filter.h
+++ b/chrome/browser/renderer_host/resource_message_filter.h
@@ -48,6 +48,10 @@ class URLRequestContextGetter;
struct ViewHostMsg_CreateWorker_Params;
struct WebPluginInfo;
+namespace file_util {
+struct FileInfo;
+}
+
namespace printing {
class PrinterQuery;
class PrintJobManager;
@@ -122,6 +126,8 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
private:
friend class ChromeThread;
friend class DeleteTask<ResourceMessageFilter>;
+ typedef void (*FileInfoWriteFunc)(IPC::Message* reply_msg,
+ const file_util::FileInfo& file_info);
virtual ~ResourceMessageFilter();
@@ -306,7 +312,10 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
void OnSetCacheMode(bool enabled);
void OnGetFileSize(const FilePath& path, IPC::Message* reply_msg);
- void OnGetFileSizeOnFileThread(const FilePath& path, IPC::Message* reply_msg);
+ void OnGetFileModificationTime(const FilePath& path, IPC::Message* reply_msg);
+ void OnGetFileInfoOnFileThread(const FilePath& path,
+ IPC::Message* reply_msg,
+ FileInfoWriteFunc write_func);
void OnKeygen(uint32 key_size_index, const std::string& challenge_string,
const GURL& url, std::string* signed_public_key);
void OnGetExtensionMessageBundle(const std::string& extension_id,
diff --git a/chrome/common/common_param_traits.h b/chrome/common/common_param_traits.h
index 72f84ee..426075a 100644
--- a/chrome/common/common_param_traits.h
+++ b/chrome/common/common_param_traits.h
@@ -318,6 +318,7 @@ struct ParamTraits<net::UploadData::Element> {
WriteParam(m, p.file_path());
WriteParam(m, p.file_range_offset());
WriteParam(m, p.file_range_length());
+ WriteParam(m, p.expected_file_modification_time());
}
}
static bool Read(const Message* m, void** iter, param_type* r) {
@@ -334,13 +335,17 @@ struct ParamTraits<net::UploadData::Element> {
DCHECK(type == net::UploadData::TYPE_FILE);
FilePath file_path;
uint64 offset, length;
+ base::Time expected_modification_time;
if (!ReadParam(m, iter, &file_path))
return false;
if (!ReadParam(m, iter, &offset))
return false;
if (!ReadParam(m, iter, &length))
return false;
- r->SetToFilePathRange(file_path, offset, length);
+ if (!ReadParam(m, iter, &expected_modification_time))
+ return false;
+ r->SetToFilePathRange(file_path, offset, length,
+ expected_modification_time);
}
return true;
}
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index afc9a4c..a0f5d14 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -15,6 +15,7 @@
#include "base/file_path.h"
#include "base/nullable_string16.h"
#include "base/sync_socket.h"
+#include "base/time.h"
#include "base/values.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/extensions/update_manifest.h"
@@ -2101,6 +2102,12 @@ IPC_BEGIN_MESSAGES(ViewHost)
FilePath /* path */,
int64 /* result */)
+ // Get file modification time in seconds. Set result to 0 if failed to get the
+ // file modification time.
+ IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_GetFileModificationTime,
+ FilePath /* path */,
+ base::Time /* result */)
+
// Sent by the renderer process to acknowledge receipt of a
// ViewMsg_CSSInsertRequest message and css has been inserted into the frame.
IPC_MESSAGE_ROUTED0(ViewHostMsg_OnCSSInserted)
diff --git a/chrome/common/resource_dispatcher.cc b/chrome/common/resource_dispatcher.cc
index 9df8eaf..5c2fd28 100644
--- a/chrome/common/resource_dispatcher.cc
+++ b/chrome/common/resource_dispatcher.cc
@@ -52,8 +52,11 @@ class IPCResourceLoaderBridge : public ResourceLoaderBridge {
// ResourceLoaderBridge
virtual void AppendDataToUpload(const char* data, int data_len);
- virtual void AppendFileRangeToUpload(const FilePath& path,
- uint64 offset, uint64 length);
+ virtual void AppendFileRangeToUpload(
+ const FilePath& path,
+ uint64 offset,
+ uint64 length,
+ const base::Time& expected_modification_time);
virtual void SetUploadIdentifier(int64 identifier);
virtual bool Start(Peer* peer);
virtual void Cancel();
@@ -152,12 +155,14 @@ void IPCResourceLoaderBridge::AppendDataToUpload(const char* data,
}
void IPCResourceLoaderBridge::AppendFileRangeToUpload(
- const FilePath& path, uint64 offset, uint64 length) {
+ const FilePath& path, uint64 offset, uint64 length,
+ const base::Time& expected_modification_time) {
DCHECK(request_id_ == -1) << "request already started";
if (!request_.upload_data)
request_.upload_data = new net::UploadData();
- request_.upload_data->AppendFileRange(path, offset, length);
+ request_.upload_data->AppendFileRange(path, offset, length,
+ expected_modification_time);
}
void IPCResourceLoaderBridge::SetUploadIdentifier(int64 identifier) {
diff --git a/chrome/plugin/chrome_plugin_host.cc b/chrome/plugin/chrome_plugin_host.cc
index 4561cc4..b3ae0ec 100644
--- a/chrome/plugin/chrome_plugin_host.cc
+++ b/chrome/plugin/chrome_plugin_host.cc
@@ -147,7 +147,8 @@ class PluginRequestHandlerProxy
void AppendFileRangeToUpload(const FilePath &filepath,
uint64 offset, uint64 length) {
upload_content_.push_back(net::UploadData::Element());
- upload_content_.back().SetToFilePathRange(filepath, offset, length);
+ upload_content_.back().SetToFilePathRange(filepath, offset, length,
+ base::Time());
}
CPError Start(int renderer_id, int render_view_id) {
@@ -186,7 +187,8 @@ class PluginRequestHandlerProxy
bridge_->AppendFileRangeToUpload(
upload_content_[i].file_path(),
upload_content_[i].file_range_offset(),
- upload_content_[i].file_range_length());
+ upload_content_[i].file_range_length(),
+ upload_content_[i].expected_file_modification_time());
break;
}
default: {
diff --git a/chrome/renderer/renderer_webkitclient_impl.cc b/chrome/renderer/renderer_webkitclient_impl.cc
index 534cd75..1f6736f 100644
--- a/chrome/renderer/renderer_webkitclient_impl.cc
+++ b/chrome/renderer/renderer_webkitclient_impl.cc
@@ -98,6 +98,21 @@ bool RendererWebKitClientImpl::getFileSize(const WebString& path,
return false;
}
+bool RendererWebKitClientImpl::getFileModificationTime(
+ const WebKit::WebString& path,
+ double& result) {
+ base::Time time;
+ if (RenderThread::current()->Send(
+ new ViewHostMsg_GetFileModificationTime(
+ webkit_glue::WebStringToFilePath(path), &time))) {
+ result = time.ToDoubleT();
+ return true;
+ }
+
+ result = 0;
+ return false;
+}
+
unsigned long long RendererWebKitClientImpl::visitedLinkHash(
const char* canonical_url,
size_t length) {
diff --git a/chrome/renderer/renderer_webkitclient_impl.h b/chrome/renderer/renderer_webkitclient_impl.h
index 71154c8..f041851 100644
--- a/chrome/renderer/renderer_webkitclient_impl.h
+++ b/chrome/renderer/renderer_webkitclient_impl.h
@@ -35,6 +35,8 @@ class RendererWebKitClientImpl : public webkit_glue::WebKitClientImpl {
virtual WebKit::WebCookieJar* cookieJar();
virtual bool sandboxEnabled();
virtual bool getFileSize(const WebKit::WebString& path, long long& result);
+ virtual bool getFileModificationTime(const WebKit::WebString& path,
+ double& result);
virtual unsigned long long visitedLinkHash(
const char* canonicalURL, size_t length);
virtual bool isLinkVisited(unsigned long long linkHash);
diff --git a/chrome/renderer/translate/page_translator_unittest.cc b/chrome/renderer/translate/page_translator_unittest.cc
index 18d293a..02f1b32 100644
--- a/chrome/renderer/translate/page_translator_unittest.cc
+++ b/chrome/renderer/translate/page_translator_unittest.cc
@@ -73,8 +73,11 @@ class DummyResourceLoaderBridge : public webkit_glue::ResourceLoaderBridge {
DummyResourceLoaderBridge() { }
virtual void AppendDataToUpload(const char* data, int data_len) {}
- virtual void AppendFileRangeToUpload(const FilePath& file_path,
- uint64 offset, uint64 length) {}
+ virtual void AppendFileRangeToUpload(
+ const FilePath& file_path,
+ uint64 offset,
+ uint64 length,
+ const base::Time& expected_modification_time) {}
virtual void SetUploadIdentifier(int64 identifier) {}
virtual bool Start(Peer* peer) { return false; }
virtual void Cancel() {}
diff --git a/chrome_frame/urlmon_upload_data_stream.cc b/chrome_frame/urlmon_upload_data_stream.cc
index af7a1de..2c40ca2 100644
--- a/chrome_frame/urlmon_upload_data_stream.cc
+++ b/chrome_frame/urlmon_upload_data_stream.cc
@@ -5,10 +5,12 @@
#include "chrome_frame/urlmon_upload_data_stream.h"
#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
void UrlmonUploadDataStream::Initialize(net::UploadData* upload_data) {
upload_data_ = upload_data;
- request_body_stream_.reset(new net::UploadDataStream(upload_data));
+ request_body_stream_.reset(net::UploadDataStream::Create(upload_data, NULL));
+ DCHECK(request_body_stream_.get());
}
STDMETHODIMP UrlmonUploadDataStream::Read(void* pv, ULONG cb, ULONG* read) {
@@ -69,7 +71,9 @@ STDMETHODIMP UrlmonUploadDataStream::Seek(LARGE_INTEGER move, DWORD origin,
// STREAM_SEEK_SETs to work with a 0 offset, but fail on everything else.
if (origin == STREAM_SEEK_SET && move.QuadPart == 0) {
if (request_body_stream_->position() != 0) {
- request_body_stream_.reset(new net::UploadDataStream(upload_data_));
+ request_body_stream_.reset(
+ net::UploadDataStream::Create(upload_data_, NULL));
+ DCHECK(request_body_stream_.get());
}
if (new_pos) {
new_pos->QuadPart = 0;
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.
diff --git a/webkit/glue/glue_serialize.cc b/webkit/glue/glue_serialize.cc
index 802f57d..4b4efd3 100644
--- a/webkit/glue/glue_serialize.cc
+++ b/webkit/glue/glue_serialize.cc
@@ -19,6 +19,7 @@
#include "webkit/glue/webkit_glue.h"
using WebKit::WebData;
+using WebKit::WebFileInfo;
using WebKit::WebHistoryItem;
using WebKit::WebHTTPBody;
using WebKit::WebPoint;
@@ -53,12 +54,13 @@ struct SerializeObject {
// 5: Adds support for empty FormData
// 6: Adds support for documentSequenceNumbers
// 7: Adds support for stateObject
+// 8: Adds support for file range and modification time
// Should be const, but unit tests may modify it.
//
// NOTE: If the version is -1, then the pickle contains only a URL string.
// See CreateHistoryStateForURL.
//
-int kVersion = 7;
+int kVersion = 8;
// A bunch of convenience functions to read/write to SerializeObjects.
// The serializers assume the input data is in the correct format and so does
@@ -230,6 +232,9 @@ static void WriteFormData(const WebHTTPBody& http_body, SerializeObject* obj) {
obj);
} else {
WriteString(element.filePath, obj);
+ WriteInteger64(element.fileStart, obj);
+ WriteInteger64(element.fileLength, obj);
+ WriteReal(element.fileInfo.modificationTime, obj);
}
}
WriteInteger64(http_body.identifier(), obj);
@@ -257,7 +262,16 @@ static WebHTTPBody ReadFormData(const SerializeObject* obj) {
if (length >= 0)
http_body.appendData(WebData(static_cast<const char*>(data), length));
} else {
- http_body.appendFile(ReadString(obj));
+ WebString file_path = ReadString(obj);
+ long long file_start = 0;
+ long long file_length = -1;
+ WebFileInfo file_info;
+ if (obj->version >= 8) {
+ file_start = ReadInteger64(obj);
+ file_length = ReadInteger64(obj);
+ file_info.modificationTime = ReadReal(obj);
+ }
+ http_body.appendFileRange(file_path, file_start, file_length, file_info);
}
}
if (obj->version >= 4)
diff --git a/webkit/glue/glue_serialize_unittest.cc b/webkit/glue/glue_serialize_unittest.cc
index e3d91bd..34ce09f 100644
--- a/webkit/glue/glue_serialize_unittest.cc
+++ b/webkit/glue/glue_serialize_unittest.cc
@@ -13,6 +13,7 @@
#include "webkit/glue/glue_serialize.h"
using WebKit::WebData;
+using WebKit::WebFileInfo;
using WebKit::WebHistoryItem;
using WebKit::WebHTTPBody;
using WebKit::WebPoint;
diff --git a/webkit/glue/mock_resource_loader_bridge.h b/webkit/glue/mock_resource_loader_bridge.h
index a3c40ba..7176e04 100644
--- a/webkit/glue/mock_resource_loader_bridge.h
+++ b/webkit/glue/mock_resource_loader_bridge.h
@@ -21,9 +21,11 @@ class MockResourceLoaderBridge : public webkit_glue::ResourceLoaderBridge {
}
MOCK_METHOD2(AppendDataToUpload, void(const char* data, int data_len));
- MOCK_METHOD3(AppendFileRangeToUpload, void(const FilePath& file_path,
- uint64 offset,
- uint64 length));
+ MOCK_METHOD4(AppendFileRangeToUpload,
+ void(const FilePath& file_path,
+ uint64 offset,
+ uint64 length,
+ const base::Time& expected_modification_time));
MOCK_METHOD1(SetUploadIdentifier, void(int64 identifier));
MOCK_METHOD1(Start, bool(ResourceLoaderBridge::Peer* peer));
MOCK_METHOD0(Cancel, void());
diff --git a/webkit/glue/resource_loader_bridge.h b/webkit/glue/resource_loader_bridge.h
index a1ede6c..26253f8 100644
--- a/webkit/glue/resource_loader_bridge.h
+++ b/webkit/glue/resource_loader_bridge.h
@@ -208,13 +208,16 @@ class ResourceLoaderBridge {
// Call this method before calling Start() to append the contents of a file
// to the request body. May only be used with HTTP(S) POST requests.
void AppendFileToUpload(const FilePath& file_path) {
- AppendFileRangeToUpload(file_path, 0, kuint64max);
+ AppendFileRangeToUpload(file_path, 0, kuint64max, base::Time());
}
// Call this method before calling Start() to append the contents of a file
// to the request body. May only be used with HTTP(S) POST requests.
- virtual void AppendFileRangeToUpload(const FilePath& file_path,
- uint64 offset, uint64 length) = 0;
+ virtual void AppendFileRangeToUpload(
+ const FilePath& file_path,
+ uint64 offset,
+ uint64 length,
+ const base::Time& expected_modification_time) = 0;
// Call this method before calling Start() to assign an upload identifier to
// this request. This is used to enable caching of POST responses. A value
diff --git a/webkit/glue/webkitclient_impl.cc b/webkit/glue/webkitclient_impl.cc
index 4695c24..a8fcac3 100644
--- a/webkit/glue/webkitclient_impl.cc
+++ b/webkit/glue/webkitclient_impl.cc
@@ -454,7 +454,7 @@ bool WebKitClientImpl::getFileSize(const WebKit::WebString& path,
}
bool WebKitClientImpl::getFileModificationTime(const WebKit::WebString& path,
- time_t& result) {
+ double& result) {
NOTREACHED();
return false;
}
diff --git a/webkit/glue/webkitclient_impl.h b/webkit/glue/webkitclient_impl.h
index df1f9c7..3017e94e 100644
--- a/webkit/glue/webkitclient_impl.h
+++ b/webkit/glue/webkitclient_impl.h
@@ -30,7 +30,8 @@ class WebKitClientImpl : public WebKit::WebKitClient {
virtual bool deleteEmptyDirectory(const WebKit::WebString& path);
virtual bool getFileSize(const WebKit::WebString& path, long long& result);
virtual bool getFileModificationTime(
- const WebKit::WebString& path, time_t& result);
+ const WebKit::WebString& path,
+ double& result);
virtual WebKit::WebString directoryName(const WebKit::WebString& path);
virtual WebKit::WebString pathByAppendingComponent(
const WebKit::WebString& path, const WebKit::WebString& component);
diff --git a/webkit/glue/weburlloader_impl.cc b/webkit/glue/weburlloader_impl.cc
index 421cb8f..d1d17a4 100644
--- a/webkit/glue/weburlloader_impl.cc
+++ b/webkit/glue/weburlloader_impl.cc
@@ -375,7 +375,16 @@ void WebURLLoaderImpl::Context::Start(
}
break;
case WebHTTPBody::Element::TypeFile:
- bridge_->AppendFileToUpload(WebStringToFilePath(element.filePath));
+ if (element.fileLength == -1) {
+ bridge_->AppendFileToUpload(
+ WebStringToFilePath(element.filePath));
+ } else {
+ bridge_->AppendFileRangeToUpload(
+ WebStringToFilePath(element.filePath),
+ static_cast<uint64>(element.fileStart),
+ static_cast<uint64>(element.fileLength),
+ base::Time::FromDoubleT(element.fileInfo.modificationTime));
+ }
break;
default:
NOTREACHED();
diff --git a/webkit/tools/test_shell/simple_resource_loader_bridge.cc b/webkit/tools/test_shell/simple_resource_loader_bridge.cc
index 7aac167..baf8355 100644
--- a/webkit/tools/test_shell/simple_resource_loader_bridge.cc
+++ b/webkit/tools/test_shell/simple_resource_loader_bridge.cc
@@ -515,12 +515,16 @@ class ResourceLoaderBridgeImpl : public ResourceLoaderBridge {
params_->upload->AppendBytes(data, data_len);
}
- virtual void AppendFileRangeToUpload(const FilePath& file_path,
- uint64 offset, uint64 length) {
+ virtual void AppendFileRangeToUpload(
+ const FilePath& file_path,
+ uint64 offset,
+ uint64 length,
+ const base::Time& expected_modification_time) {
DCHECK(params_.get());
if (!params_->upload)
params_->upload = new net::UploadData();
- params_->upload->AppendFileRange(file_path, offset, length);
+ params_->upload->AppendFileRange(file_path, offset, length,
+ expected_modification_time);
}
virtual void SetUploadIdentifier(int64 identifier) {
diff --git a/webkit/tools/test_shell/test_shell_webkit_init.h b/webkit/tools/test_shell/test_shell_webkit_init.h
index c182269..f2f314e 100644
--- a/webkit/tools/test_shell/test_shell_webkit_init.h
+++ b/webkit/tools/test_shell/test_shell_webkit_init.h
@@ -152,6 +152,15 @@ class TestShellWebKitInit : public webkit_glue::WebKitClientImpl {
reinterpret_cast<int64*>(&result));
}
+ virtual bool getFileModificationTime(const WebKit::WebString& path,
+ double& result) {
+ file_util::FileInfo info;
+ if (!file_util::GetFileInfo(webkit_glue::WebStringToFilePath(path), &info))
+ return false;
+ result = info.last_modified.ToDoubleT();
+ return true;
+ }
+
virtual unsigned long long visitedLinkHash(const char* canonicalURL,
size_t length) {
return 0;