summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/net/blob_url_request_job_factory.cc20
-rw-r--r--chrome/browser/renderer_host/async_resource_handler.cc6
-rw-r--r--chrome/browser/renderer_host/async_resource_handler.h1
-rw-r--r--chrome/browser/renderer_host/redirect_to_file_resource_handler.cc32
-rw-r--r--chrome/browser/renderer_host/redirect_to_file_resource_handler.h9
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.cc50
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.h24
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host_request_info.cc6
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host_request_info.h12
-rw-r--r--chrome/browser/renderer_host/resource_handler.h6
-rw-r--r--chrome/browser/renderer_host/sync_resource_handler.cc1
-rw-r--r--chrome/common/render_messages_internal.h27
-rw-r--r--chrome/common/resource_dispatcher.cc149
-rw-r--r--chrome/common/resource_dispatcher.h8
-rw-r--r--webkit/blob/deletable_file_reference.cc63
-rw-r--r--webkit/blob/deletable_file_reference.h49
-rw-r--r--webkit/blob/deletable_file_reference_unittest.cc51
-rw-r--r--webkit/blob/webkit_blob.gypi2
-rw-r--r--webkit/glue/weburlloader_impl.cc7
-rw-r--r--webkit/tools/test_shell/simple_resource_loader_bridge.cc56
-rw-r--r--webkit/tools/test_shell/test_shell.gypi1
21 files changed, 464 insertions, 116 deletions
diff --git a/chrome/browser/net/blob_url_request_job_factory.cc b/chrome/browser/net/blob_url_request_job_factory.cc
index dab29d5..7297795 100644
--- a/chrome/browser/net/blob_url_request_job_factory.cc
+++ b/chrome/browser/net/blob_url_request_job_factory.cc
@@ -7,6 +7,8 @@
#include "chrome/browser/chrome_blob_storage_context.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/net/chrome_url_request_context.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
#include "chrome/common/url_constants.h"
#include "webkit/blob/blob_storage_controller.h"
#include "webkit/blob/blob_url_request_job.h"
@@ -15,12 +17,20 @@ namespace {
URLRequestJob* BlobURLRequestJobFactory(URLRequest* request,
const std::string& scheme) {
- webkit_blob::BlobStorageController* blob_storage_controller =
- static_cast<ChromeURLRequestContext*>(request->context())->
- blob_storage_context()->controller();
+ scoped_refptr<webkit_blob::BlobData> data;
+ ResourceDispatcherHostRequestInfo* info =
+ ResourceDispatcherHost::InfoForRequest(request);
+ if (info) {
+ // Resource dispatcher host already looked up the blob data.
+ data = info->requested_blob_data();
+ } else {
+ // This request is not coming thru resource dispatcher host.
+ data = static_cast<ChromeURLRequestContext*>(request->context())->
+ blob_storage_context()->
+ controller()->GetBlobDataFromUrl(request->url());
+ }
return new webkit_blob::BlobURLRequestJob(
- request,
- blob_storage_controller->GetBlobDataFromUrl(request->url()),
+ request, data,
ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE));
}
diff --git a/chrome/browser/renderer_host/async_resource_handler.cc b/chrome/browser/renderer_host/async_resource_handler.cc
index 5e5dfa5..803b91b 100644
--- a/chrome/browser/renderer_host/async_resource_handler.cc
+++ b/chrome/browser/renderer_host/async_resource_handler.cc
@@ -217,6 +217,12 @@ bool AsyncResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
return true;
}
+void AsyncResourceHandler::OnDataDownloaded(
+ int request_id, int bytes_downloaded) {
+ receiver_->Send(new ViewMsg_Resource_DataDownloaded(
+ routing_id_, request_id, bytes_downloaded));
+}
+
bool AsyncResourceHandler::OnResponseCompleted(
int request_id,
const URLRequestStatus& status,
diff --git a/chrome/browser/renderer_host/async_resource_handler.h b/chrome/browser/renderer_host/async_resource_handler.h
index 191fdb8..be89d87 100644
--- a/chrome/browser/renderer_host/async_resource_handler.h
+++ b/chrome/browser/renderer_host/async_resource_handler.h
@@ -38,6 +38,7 @@ class AsyncResourceHandler : public ResourceHandler {
const URLRequestStatus& status,
const std::string& security_info);
void OnRequestClosed();
+ void OnDataDownloaded(int request_id, int bytes_downloaded);
static void GlobalCleanup();
diff --git a/chrome/browser/renderer_host/redirect_to_file_resource_handler.cc b/chrome/browser/renderer_host/redirect_to_file_resource_handler.cc
index b1470b1..94a5c77 100644
--- a/chrome/browser/renderer_host/redirect_to_file_resource_handler.cc
+++ b/chrome/browser/renderer_host/redirect_to_file_resource_handler.cc
@@ -16,6 +16,9 @@
#include "net/base/io_buffer.h"
#include "net/base/mime_sniffer.h"
#include "net/base/net_errors.h"
+#include "webkit/blob/deletable_file_reference.h"
+
+using webkit_blob::DeletableFileReference;
// TODO(darin): Use the buffer sizing algorithm from AsyncResourceHandler.
static const int kReadBufSize = 32768;
@@ -56,8 +59,8 @@ bool RedirectToFileResourceHandler::OnResponseStarted(
int request_id,
ResourceResponse* response) {
if (response->response_head.status.is_success()) {
- DCHECK(!file_path_.empty());
- response->response_head.download_file_path = file_path_;
+ DCHECK(deletable_file_ && !deletable_file_->path().empty());
+ response->response_head.download_file_path = deletable_file_->path();
}
return next_handler_->OnResponseStarted(request_id, response);
}
@@ -66,7 +69,7 @@ bool RedirectToFileResourceHandler::OnWillStart(int request_id,
const GURL& url,
bool* defer) {
request_id_ = request_id;
- if (file_path_.empty()) {
+ if (!deletable_file_) {
// Defer starting the request until we have created the temporary file.
// TODO(darin): This is sub-optimal. We should not delay starting the
// network request like this.
@@ -123,6 +126,9 @@ bool RedirectToFileResourceHandler::OnReadCompleted(int request_id,
if (BufIsFull())
host_->PauseRequest(process_id_, request_id, true);
+ if (*bytes_read > 0)
+ next_handler_->OnDataDownloaded(request_id, *bytes_read);
+
return WriteMore();
}
@@ -134,21 +140,13 @@ bool RedirectToFileResourceHandler::OnResponseCompleted(
}
void RedirectToFileResourceHandler::OnRequestClosed() {
- next_handler_->OnRequestClosed();
-
- // The renderer no longer has a WebURLLoader open to this request, so we can
- // close and unlink the file.
-
// We require this explicit call to Close since file_stream_ was constructed
// directly from a PlatformFile.
file_stream_->Close();
file_stream_.reset();
+ deletable_file_ = NULL;
- // TODO(dumi): delete the temp file when it's no longer needed.
- // TODO(dumi): revoke the privilege to upload this file.
- // base::FileUtilProxy::Delete(
- // ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE),
- // file_path_, NULL);
+ next_handler_->OnRequestClosed();
}
RedirectToFileResourceHandler::~RedirectToFileResourceHandler() {
@@ -159,12 +157,14 @@ void RedirectToFileResourceHandler::DidCreateTemporaryFile(
base::PlatformFileError /*error_code*/,
base::PassPlatformFile file_handle,
FilePath file_path) {
- file_path_ = file_path;
+ deletable_file_ = DeletableFileReference::GetOrCreate(
+ file_path,
+ ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE));
file_stream_.reset(new net::FileStream(file_handle.ReleaseValue(),
base::PLATFORM_FILE_WRITE |
base::PLATFORM_FILE_ASYNC));
- ChildProcessSecurityPolicy::GetInstance()->GrantUploadFile(
- process_id_, file_path);
+ host_->RegisterDownloadedTempFile(
+ process_id_, request_id_, deletable_file_.get());
host_->StartDeferredRequest(process_id_, request_id_);
}
diff --git a/chrome/browser/renderer_host/redirect_to_file_resource_handler.h b/chrome/browser/renderer_host/redirect_to_file_resource_handler.h
index 0e82e3b..4929711 100644
--- a/chrome/browser/renderer_host/redirect_to_file_resource_handler.h
+++ b/chrome/browser/renderer_host/redirect_to_file_resource_handler.h
@@ -21,6 +21,10 @@ class FileStream;
class GrowableIOBuffer;
}
+namespace webkit_blob {
+class DeletableFileReference;
+}
+
// Redirects network data to a file. This is intended to be layered in front
// of either the AsyncResourceHandler or the SyncResourceHandler.
class RedirectToFileResourceHandler : public ResourceHandler {
@@ -71,11 +75,14 @@ class RedirectToFileResourceHandler : public ResourceHandler {
bool buf_write_pending_;
int write_cursor_;
- FilePath file_path_;
scoped_ptr<net::FileStream> file_stream_;
net::CompletionCallbackImpl<RedirectToFileResourceHandler> write_callback_;
bool write_callback_pending_;
+ // We create a DeletableFileReference for the temp file created as
+ // a result of the download.
+ scoped_refptr<webkit_blob::DeletableFileReference> deletable_file_;
+
DISALLOW_COPY_AND_ASSIGN(RedirectToFileResourceHandler);
};
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc
index 899f077..0cd78d59 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc
@@ -71,6 +71,7 @@
#include "webkit/appcache/appcache_interceptor.h"
#include "webkit/appcache/appcache_interfaces.h"
#include "webkit/blob/blob_storage_controller.h"
+#include "webkit/blob/deletable_file_reference.h"
// TODO(oshima): Enable this for other platforms.
#if defined(OS_CHROMEOS)
@@ -89,6 +90,7 @@
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
+using webkit_blob::DeletableFileReference;
// ----------------------------------------------------------------------------
@@ -321,7 +323,10 @@ bool ResourceDispatcherHost::OnMessageReceived(const IPC::Message& message,
IPC_BEGIN_MESSAGE_MAP_EX(ResourceDispatcherHost, message, *message_was_ok)
IPC_MESSAGE_HANDLER(ViewHostMsg_RequestResource, OnRequestResource)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SyncLoad, OnSyncLoad)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ResourceLoaderDeleted,
+ OnResourceLoaderDeleted)
IPC_MESSAGE_HANDLER(ViewHostMsg_DataReceived_ACK, OnDataReceivedACK)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DataDownloaded_ACK, OnDataDownloadedACK)
IPC_MESSAGE_HANDLER(ViewHostMsg_UploadProgress_ACK, OnUploadProgressACK)
IPC_MESSAGE_HANDLER(ViewHostMsg_CancelRequest, OnCancelRequest)
IPC_MESSAGE_HANDLER(ViewHostMsg_FollowRedirect, OnFollowRedirect)
@@ -375,7 +380,7 @@ void ResourceDispatcherHost::BeginRequest(
}
// Might need to resolve the blob references in the upload data.
- if (request_data.upload_data) {
+ if (request_data.upload_data && context) {
context->blob_storage_context()->controller()->
ResolveBlobReferencesInUploadData(request_data.upload_data.get());
}
@@ -423,6 +428,7 @@ void ResourceDispatcherHost::BeginRequest(
this);
}
+ // The RedirectToFileResourceHandler depends on being next in the chain.
if (request_data.download_to_file)
handler = new RedirectToFileResourceHandler(handler, child_id, this);
@@ -517,6 +523,15 @@ void ResourceDispatcherHost::BeginRequest(
chrome_browser_net::SetOriginProcessUniqueIDForRequest(
request_data.origin_child_id, request);
+ if (request->url().SchemeIs(chrome::kBlobScheme) && context) {
+ // Hang on to a reference to ensure the blob is not released prior
+ // to the job being started.
+ webkit_blob::BlobStorageController* controller =
+ context->blob_storage_context()->controller();
+ extra_info->set_requested_blob_data(
+ controller->GetBlobDataFromUrl(request->url()));
+ }
+
// Have the appcache associate its extra info with the request.
appcache::AppCacheInterceptor::SetExtraRequestInfo(
request, context ? context->appcache_service() : NULL, child_id,
@@ -525,6 +540,12 @@ void ResourceDispatcherHost::BeginRequest(
BeginRequestInternal(request);
}
+void ResourceDispatcherHost::OnResourceLoaderDeleted(int request_id) {
+ DCHECK(pending_requests_.end() ==
+ pending_requests_.find(GlobalRequestID(receiver_->id(), request_id)));
+ UnregisterDownloadedTempFile(receiver_->id(), request_id);
+}
+
void ResourceDispatcherHost::OnDataReceivedACK(int request_id) {
DataReceivedACK(receiver_->id(), request_id);
}
@@ -552,6 +573,29 @@ void ResourceDispatcherHost::DataReceivedACK(int child_id,
}
}
+void ResourceDispatcherHost::OnDataDownloadedACK(int request_id) {
+ // TODO(michaeln): maybe throttle DataDownloaded messages
+}
+
+void ResourceDispatcherHost::RegisterDownloadedTempFile(
+ int receiver_id, int request_id, DeletableFileReference* reference) {
+ // Note: receiver_id is the child_id is the render_process_id...
+ registered_temp_files_[receiver_id][request_id] = reference;
+ ChildProcessSecurityPolicy::GetInstance()->GrantUploadFile(
+ receiver_id, reference->path());
+}
+
+void ResourceDispatcherHost::UnregisterDownloadedTempFile(
+ int receiver_id, int request_id) {
+ DeletableFilesMap& map = registered_temp_files_[receiver_id];
+ DeletableFilesMap::iterator found = map.find(request_id);
+ if (found == map.end())
+ return;
+ map.erase(found);
+ // TODO(michaeln): revoke access to this file upon the file's deletion.
+}
+
+
bool ResourceDispatcherHost::Send(IPC::Message* message) {
delete message;
return false;
@@ -847,6 +891,7 @@ int ResourceDispatcherHost::GetOutstandingRequestsMemoryCost(
void ResourceDispatcherHost::CancelRequestsForProcess(int child_id) {
socket_stream_dispatcher_host_->CancelRequestsForProcess(child_id);
CancelRequestsForRoute(child_id, -1 /* cancel all */);
+ registered_temp_files_.erase(child_id);
}
void ResourceDispatcherHost::CancelRequestsForRoute(int child_id,
@@ -1798,8 +1843,9 @@ bool ResourceDispatcherHost::IsResourceDispatcherHostMessage(
case ViewHostMsg_CancelRequest::ID:
case ViewHostMsg_FollowRedirect::ID:
case ViewHostMsg_ClosePage_ACK::ID:
+ case ViewHostMsg_ResourceLoaderDeleted::ID:
case ViewHostMsg_DataReceived_ACK::ID:
- case ViewHostMsg_DownloadProgress_ACK::ID:
+ case ViewHostMsg_DataDownloaded_ACK::ID:
case ViewHostMsg_UploadProgress_ACK::ID:
case ViewHostMsg_SyncLoad::ID:
return true;
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.h b/chrome/browser/renderer_host/resource_dispatcher_host.h
index 1878177..76b8df5 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.h
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.h
@@ -47,6 +47,10 @@ struct GlobalRequestID;
struct ViewHostMsg_Resource_Request;
struct ViewMsg_ClosePage_Params;
+namespace webkit_blob {
+class DeletableFileReference;
+}
+
class ResourceDispatcherHost : public URLRequest::Delegate {
public:
// Implemented by the client of ResourceDispatcherHost to receive messages in
@@ -264,6 +268,15 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// messages sent.
void DataReceivedACK(int process_unique_id, int request_id);
+ // Maintains a collection of temp files created in support of
+ // the download_to_file capability. Used to grant access to the
+ // child process and to defer deletion of the file until it's
+ // no longer needed.
+ void RegisterDownloadedTempFile(
+ int receiver_id, int request_id,
+ webkit_blob::DeletableFileReference* reference);
+ void UnregisterDownloadedTempFile(int receiver_id, int request_id);
+
// Needed for the sync IPC message dispatcher macros.
bool Send(IPC::Message* message);
@@ -397,11 +410,13 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
IPC::Message* sync_result, // only valid for sync
int route_id); // only valid for async
void OnDataReceivedACK(int request_id);
+ void OnDataDownloadedACK(int request_id);
void OnUploadProgressACK(int request_id);
void OnCancelRequest(int request_id);
void OnFollowRedirect(int request_id,
bool has_new_first_party_for_cookies,
const GURL& new_first_party_for_cookies);
+ void OnResourceLoaderDeleted(int request_id);
ResourceHandler* CreateSafeBrowsingResourceHandler(
ResourceHandler* handler, int child_id, int route_id,
@@ -432,6 +447,15 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
PendingRequestList pending_requests_;
+ // Collection of temp files downloaded for child processes via
+ // the download_to_file mechanism. We avoid deleting them until
+ // the loader in the client has been deleted.
+ typedef std::map<int, scoped_refptr<webkit_blob::DeletableFileReference> >
+ DeletableFilesMap; // key is request id
+ typedef std::map<int, DeletableFilesMap>
+ RegisteredTempFiles; // key is child process id
+ RegisteredTempFiles registered_temp_files_;
+
// A timer that periodically calls UpdateLoadStates while pending_requests_
// is not empty.
base::RepeatingTimer<ResourceDispatcherHost> update_load_states_timer_;
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host_request_info.cc b/chrome/browser/renderer_host/resource_dispatcher_host_request_info.cc
index eeac6f0..30ca189 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host_request_info.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_request_info.cc
@@ -7,6 +7,7 @@
#include "chrome/browser/login_prompt.h"
#include "chrome/browser/renderer_host/resource_handler.h"
#include "chrome/browser/ssl/ssl_client_auth_handler.h"
+#include "webkit/blob/blob_data.h"
ResourceDispatcherHostRequestInfo::ResourceDispatcherHostRequestInfo(
ResourceHandler* handler,
@@ -61,3 +62,8 @@ void ResourceDispatcherHostRequestInfo::set_ssl_client_auth_handler(
SSLClientAuthHandler* s) {
ssl_client_auth_handler_ = s;
}
+
+void ResourceDispatcherHostRequestInfo::set_requested_blob_data(
+ webkit_blob::BlobData* data) {
+ requested_blob_data_ = data;
+}
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host_request_info.h b/chrome/browser/renderer_host/resource_dispatcher_host_request_info.h
index f5b7535..9d5e386 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host_request_info.h
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_request_info.h
@@ -21,6 +21,10 @@ class ResourceDispatcherHost;
class ResourceHandler;
class SSLClientAuthHandler;
+namespace webkit_blob {
+class BlobData;
+}
+
// Holds the data ResourceDispatcherHost associates with each request.
// Retrieve this data by calling ResourceDispatcherHost::InfoForRequest.
class ResourceDispatcherHostRequestInfo : public URLRequest::UserData {
@@ -160,6 +164,13 @@ class ResourceDispatcherHostRequestInfo : public URLRequest::UserData {
int host_renderer_id() const { return host_renderer_id_; }
int host_render_view_id() const { return host_render_view_id_; }
+ // We hold a reference to the requested blob data to ensure it doesn't
+ // get finally released prior to the URLRequestJob being started.
+ webkit_blob::BlobData* requested_blob_data() const {
+ return requested_blob_data_.get();
+ }
+ void set_requested_blob_data(webkit_blob::BlobData* data);
+
private:
friend class ResourceDispatcherHost;
@@ -214,6 +225,7 @@ class ResourceDispatcherHostRequestInfo : public URLRequest::UserData {
base::TimeTicks last_upload_ticks_;
bool waiting_for_upload_progress_ack_;
int memory_cost_;
+ scoped_refptr<webkit_blob::BlobData> requested_blob_data_;
// "Private" data accessible only to ResourceDispatcherHost (use the
// accessors above for consistency).
diff --git a/chrome/browser/renderer_host/resource_handler.h b/chrome/browser/renderer_host/resource_handler.h
index a03e50d..b6758ae 100644
--- a/chrome/browser/renderer_host/resource_handler.h
+++ b/chrome/browser/renderer_host/resource_handler.h
@@ -80,6 +80,12 @@ class ResourceHandler
// This is a signal that the associated URLRequest isn't valid anymore.
virtual void OnRequestClosed() = 0;
+ // This notification is synthesized by the RedirectToFileResourceHandler
+ // to indicate progress of 'download_to_file' requests. OnReadCompleted
+ // calls are consumed by the RedirectToFileResourceHandler and replaced
+ // with OnDataDownloaded calls.
+ virtual void OnDataDownloaded(int request_id, int bytes_downloaded) {}
+
protected:
friend class ChromeThread;
friend class DeleteTask<ResourceHandler>;
diff --git a/chrome/browser/renderer_host/sync_resource_handler.cc b/chrome/browser/renderer_host/sync_resource_handler.cc
index 6638084..16c057a 100644
--- a/chrome/browser/renderer_host/sync_resource_handler.cc
+++ b/chrome/browser/renderer_host/sync_resource_handler.cc
@@ -63,6 +63,7 @@ bool SyncResourceHandler::OnResponseStarted(int request_id,
result_.headers = response->response_head.headers;
result_.mime_type = response->response_head.mime_type;
result_.charset = response->response_head.charset;
+ result_.download_file_path = response->response_head.download_file_path;
result_.request_time = response->response_head.request_time;
result_.response_time = response->response_head.response_time;
result_.connection_id = response->response_head.connection_id;
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 0149bf4..6437c05 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -303,13 +303,6 @@ IPC_BEGIN_MESSAGES(View)
int /* request_id */,
std::vector<char> /* data */)
- // Sent as download progress is being made, size of the resource may be
- // unknown, in that case |size| is -1.
- IPC_MESSAGE_ROUTED3(ViewMsg_Resource_DownloadProgress,
- int /* request_id */,
- int64 /* position */,
- int64 /* size */)
-
// Sent as upload progress is being made.
IPC_MESSAGE_ROUTED3(ViewMsg_Resource_UploadProgress,
int /* request_id */,
@@ -331,6 +324,13 @@ IPC_BEGIN_MESSAGES(View)
base::SharedMemoryHandle /* data */,
int /* data_len */)
+ // Sent when some data from a resource request has been downloaded to
+ // file. This is only called in the 'download_to_file' case and replaces
+ // ViewMsg_Resource_DataReceived in the call sequence in that case.
+ IPC_MESSAGE_ROUTED2(ViewMsg_Resource_DataDownloaded,
+ int /* request_id */,
+ int /* data_len */)
+
// Sent when the request has been completed.
IPC_MESSAGE_ROUTED4(ViewMsg_Resource_RequestComplete,
int /* request_id */,
@@ -1868,6 +1868,14 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_MESSAGE_ROUTED1(ViewHostMsg_DataReceived_ACK,
int /* request_id */)
+ // Sent when the renderer has processed a DataDownloaded message.
+ IPC_MESSAGE_ROUTED1(ViewHostMsg_DataDownloaded_ACK,
+ int /* request_id */)
+
+ // Sent when the renderer process deletes a resource loader.
+ IPC_MESSAGE_CONTROL1(ViewHostMsg_ResourceLoaderDeleted,
+ int /* request_id */)
+
// Sent when a provisional load on the main frame redirects.
IPC_MESSAGE_ROUTED3(ViewHostMsg_DidRedirectProvisionalLoad,
int /* page_id */,
@@ -1875,11 +1883,6 @@ IPC_BEGIN_MESSAGES(ViewHost)
GURL /* url redirected to */)
// Sent by the renderer process to acknowledge receipt of a
- // DownloadProgress message.
- IPC_MESSAGE_ROUTED1(ViewHostMsg_DownloadProgress_ACK,
- int /* request_id */)
-
- // Sent by the renderer process to acknowledge receipt of a
// UploadProgress message.
IPC_MESSAGE_ROUTED1(ViewHostMsg_UploadProgress_ACK,
int /* request_id */)
diff --git a/chrome/common/resource_dispatcher.cc b/chrome/common/resource_dispatcher.cc
index b274ace..c0706a5 100644
--- a/chrome/common/resource_dispatcher.cc
+++ b/chrome/common/resource_dispatcher.cc
@@ -143,6 +143,11 @@ IPCResourceLoaderBridge::~IPCResourceLoaderBridge() {
// this operation may fail, as the dispatcher will have preemptively
// removed us when the renderer sends the ReceivedAllData message.
dispatcher_->RemovePendingRequest(request_id_);
+
+ // Tell the browser process we're deleted so it can reclaim resources its
+ // holding on our behalf, like a downloaded temp file.
+ dispatcher_->message_sender()->Send(
+ new ViewHostMsg_ResourceLoaderDeleted(request_id_));
}
}
@@ -260,6 +265,7 @@ void IPCResourceLoaderBridge::SyncLoad(SyncLoadResponse* response) {
response->connection_reused = result.connection_reused;
response->load_timing = result.load_timing;
response->data.swap(result.data);
+ response->download_file_path = result.download_file_path;
}
} // namespace webkit_glue
@@ -289,30 +295,26 @@ bool ResourceDispatcher::OnMessageReceived(const IPC::Message& message) {
return true;
}
- PendingRequestList::iterator it = pending_requests_.find(request_id);
- if (it == pending_requests_.end()) {
- // This might happen for kill()ed requests on the webkit end, so perhaps it
- // shouldn't be a warning...
- DLOG(WARNING) << "Got response for a nonexistent or finished request";
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info) {
// Release resources in the message if it is a data message.
ReleaseResourcesInDataMessage(message);
return true;
}
- PendingRequestInfo& request_info = it->second;
- if (request_info.is_deferred) {
- request_info.deferred_message_queue.push_back(new IPC::Message(message));
+ if (request_info->is_deferred) {
+ request_info->deferred_message_queue.push_back(new IPC::Message(message));
return true;
}
// Make sure any deferred messages are dispatched before we dispatch more.
- if (!request_info.deferred_message_queue.empty()) {
+ if (!request_info->deferred_message_queue.empty()) {
FlushDeferredMessages(request_id);
// The request could have been deferred now. If yes then the current
// message has to be queued up. The request_info instance should remain
// valid here as there are pending messages for it.
DCHECK(pending_requests_.find(request_id) != pending_requests_.end());
- if (request_info.is_deferred) {
- request_info.deferred_message_queue.push_back(new IPC::Message(message));
+ if (request_info->is_deferred) {
+ request_info->deferred_message_queue.push_back(new IPC::Message(message));
return true;
}
}
@@ -321,22 +323,27 @@ bool ResourceDispatcher::OnMessageReceived(const IPC::Message& message) {
return true;
}
-void ResourceDispatcher::OnUploadProgress(
- const IPC::Message& message, int request_id, int64 position, int64 size) {
+ResourceDispatcher::PendingRequestInfo*
+ResourceDispatcher::GetPendingRequestInfo(int request_id) {
PendingRequestList::iterator it = pending_requests_.find(request_id);
if (it == pending_requests_.end()) {
- // this might happen for kill()ed requests on the webkit end, so perhaps
- // it shouldn't be a warning...
- DLOG(WARNING) << "Got upload progress for a nonexistent or "
- "finished request";
- return;
+ // This might happen for kill()ed requests on the webkit end, so perhaps it
+ // shouldn't be a warning...
+ DLOG(WARNING) << "Received message for a nonexistent or finished request";
+ return NULL;
}
+ return &(it->second);
+}
- PendingRequestInfo& request_info = it->second;
+void ResourceDispatcher::OnUploadProgress(
+ const IPC::Message& message, int request_id, int64 position, int64 size) {
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
+ return;
RESOURCE_LOG("Dispatching upload progress for " <<
- request_info.peer->GetURLForDebugging().possibly_invalid_spec());
- request_info.peer->OnUploadProgress(position, size);
+ request_info->peer->GetURLForDebugging().possibly_invalid_spec());
+ request_info->peer->OnUploadProgress(position, size);
// Acknowledge receipt
message_sender()->Send(
@@ -345,44 +352,34 @@ void ResourceDispatcher::OnUploadProgress(
void ResourceDispatcher::OnReceivedResponse(
int request_id, const ResourceResponseHead& response_head) {
- PendingRequestList::iterator it = pending_requests_.find(request_id);
- if (it == pending_requests_.end()) {
- // This might happen for kill()ed requests on the webkit end, so perhaps it
- // shouldn't be a warning...
- DLOG(WARNING) << "Got response for a nonexistent or finished request";
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
return;
- }
- PendingRequestInfo& request_info = it->second;
if (response_head.replace_extension_localization_templates) {
webkit_glue::ResourceLoaderBridge::Peer* new_peer =
ExtensionLocalizationPeer::CreateExtensionLocalizationPeer(
- request_info.peer, message_sender(), response_head.mime_type,
- request_info.url);
+ request_info->peer, message_sender(), response_head.mime_type,
+ request_info->url);
if (new_peer)
- request_info.peer = new_peer;
+ request_info->peer = new_peer;
}
RESOURCE_LOG("Dispatching response for " <<
- request_info.peer->GetURLForDebugging().possibly_invalid_spec());
- request_info.peer->OnReceivedResponse(response_head, false);
+ request_info->peer->GetURLForDebugging().possibly_invalid_spec());
+ request_info->peer->OnReceivedResponse(response_head, false);
}
void ResourceDispatcher::OnReceivedCachedMetadata(
int request_id, const std::vector<char>& data) {
- PendingRequestList::iterator it = pending_requests_.find(request_id);
- if (it == pending_requests_.end()) {
- // this might happen for kill()ed requests on the webkit end, so perhaps
- // it shouldn't be a warning...
- DLOG(WARNING) << "Got metadata for a nonexistent or finished request";
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
return;
- }
if (data.size()) {
- PendingRequestInfo& request_info = it->second;
RESOURCE_LOG("Dispatching " << data.size() << " metadata bytes for " <<
- request_info.peer->GetURLForDebugging().possibly_invalid_spec());
- request_info.peer->OnReceivedCachedMetadata(&data.front(), data.size());
+ request_info->peer->GetURLForDebugging().possibly_invalid_spec());
+ request_info->peer->OnReceivedCachedMetadata(&data.front(), data.size());
}
}
@@ -398,45 +395,50 @@ void ResourceDispatcher::OnReceivedData(const IPC::Message& message,
DCHECK((shm_valid && data_len > 0) || (!shm_valid && !data_len));
base::SharedMemory shared_mem(shm_handle, true); // read only
- PendingRequestList::iterator it = pending_requests_.find(request_id);
- if (it == pending_requests_.end()) {
- // this might happen for kill()ed requests on the webkit end, so perhaps
- // it shouldn't be a warning...
- DLOG(WARNING) << "Got data for a nonexistent or finished request";
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
return;
- }
-
- PendingRequestInfo& request_info = it->second;
if (data_len > 0 && shared_mem.Map(data_len)) {
RESOURCE_LOG("Dispatching " << data_len << " bytes for " <<
- request_info.peer->GetURLForDebugging().possibly_invalid_spec());
+ request_info->peer->GetURLForDebugging().possibly_invalid_spec());
const char* data = static_cast<char*>(shared_mem.memory());
- request_info.peer->OnReceivedData(data, data_len);
+ request_info->peer->OnReceivedData(data, data_len);
}
}
+void ResourceDispatcher::OnDownloadedData(const IPC::Message& message,
+ int request_id,
+ int data_len) {
+ // Acknowledge the reception of this message.
+ message_sender()->Send(
+ new ViewHostMsg_DataDownloaded_ACK(message.routing_id(), request_id));
+
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
+ return;
+
+ RESOURCE_LOG("Dispatching " << data_len << " downloaded for " <<
+ request_info->peer->GetURLForDebugging().possibly_invalid_spec());
+ request_info->peer->OnDownloadedData(data_len);
+}
+
void ResourceDispatcher::OnReceivedRedirect(
const IPC::Message& message,
int request_id,
const GURL& new_url,
const webkit_glue::ResourceLoaderBridge::ResponseInfo& info) {
- PendingRequestList::iterator it = pending_requests_.find(request_id);
- if (it == pending_requests_.end()) {
- // this might happen for kill()ed requests on the webkit end, so perhaps
- // it shouldn't be a warning...
- DLOG(WARNING) << "Got data for a nonexistent or finished request";
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
return;
- }
- PendingRequestInfo& request_info = it->second;
-
- RESOURCE_LOG("Dispatching redirect for " <<
- request_info.peer->GetURLForDebugging().possibly_invalid_spec());
+ RESOURCE_LOG(
+ "Dispatching redirect for " <<
+ request_info->peer->GetURLForDebugging().possibly_invalid_spec());
bool has_new_first_party_for_cookies = false;
GURL new_first_party_for_cookies;
- if (request_info.peer->OnReceivedRedirect(new_url, info,
+ if (request_info->peer->OnReceivedRedirect(new_url, info,
&has_new_first_party_for_cookies,
&new_first_party_for_cookies)) {
message_sender()->Send(
@@ -452,30 +454,25 @@ void ResourceDispatcher::OnRequestComplete(int request_id,
const URLRequestStatus& status,
const std::string& security_info,
const base::Time& completion_time) {
- PendingRequestList::iterator it = pending_requests_.find(request_id);
- if (it == pending_requests_.end()) {
- // this might happen for kill()ed requests on the webkit end, so perhaps
- // it shouldn't be a warning...
- DLOG(WARNING) << "Got 'complete' for a nonexistent or finished request";
+ PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+ if (!request_info)
return;
- }
- PendingRequestInfo& request_info = it->second;
- webkit_glue::ResourceLoaderBridge::Peer* peer = request_info.peer;
+ webkit_glue::ResourceLoaderBridge::Peer* peer = request_info->peer;
RESOURCE_LOG("Dispatching complete for " <<
- request_info.peer->GetURLForDebugging().possibly_invalid_spec());
+ peer->GetURLForDebugging().possibly_invalid_spec());
if (status.status() == URLRequestStatus::CANCELED &&
status.os_error() != net::ERR_ABORTED) {
// Resource canceled with a specific error are filtered.
SecurityFilterPeer* new_peer =
SecurityFilterPeer::CreateSecurityFilterPeerForDeniedRequest(
- request_info.resource_type,
- request_info.peer,
+ request_info->resource_type,
+ request_info->peer,
status.os_error());
if (new_peer) {
- request_info.peer = new_peer;
+ request_info->peer = new_peer;
peer = new_peer;
}
}
@@ -552,6 +549,7 @@ void ResourceDispatcher::DispatchMessage(const IPC::Message& message) {
ViewMsg_Resource_ReceivedCachedMetadata, OnReceivedCachedMetadata)
IPC_MESSAGE_HANDLER(ViewMsg_Resource_ReceivedRedirect, OnReceivedRedirect)
IPC_MESSAGE_HANDLER(ViewMsg_Resource_DataReceived, OnReceivedData)
+ IPC_MESSAGE_HANDLER(ViewMsg_Resource_DataDownloaded, OnDownloadedData)
IPC_MESSAGE_HANDLER(ViewMsg_Resource_RequestComplete, OnRequestComplete)
IPC_END_MESSAGE_MAP()
}
@@ -604,6 +602,7 @@ bool ResourceDispatcher::IsResourceDispatcherMessage(
case ViewMsg_Resource_ReceivedCachedMetadata::ID:
case ViewMsg_Resource_ReceivedRedirect::ID:
case ViewMsg_Resource_DataReceived::ID:
+ case ViewMsg_Resource_DataDownloaded::ID:
case ViewMsg_Resource_RequestComplete::ID:
return true;
diff --git a/chrome/common/resource_dispatcher.h b/chrome/common/resource_dispatcher.h
index e2a2de0..77e08ac 100644
--- a/chrome/common/resource_dispatcher.h
+++ b/chrome/common/resource_dispatcher.h
@@ -82,6 +82,10 @@ class ResourceDispatcher {
};
typedef base::hash_map<int, PendingRequestInfo> PendingRequestList;
+ // Helper to lookup the info based on the request_id.
+ // May return NULL if the request as been canceled from the client side.
+ PendingRequestInfo* GetPendingRequestInfo(int request_id);
+
// Message response handlers, called by the message handler for this process.
void OnUploadProgress(
const IPC::Message& message,
@@ -100,6 +104,10 @@ class ResourceDispatcher {
int request_id,
base::SharedMemoryHandle data,
int data_len);
+ void OnDownloadedData(
+ const IPC::Message& message,
+ int request_id,
+ int data_len);
void OnRequestComplete(
int request_id,
const URLRequestStatus& status,
diff --git a/webkit/blob/deletable_file_reference.cc b/webkit/blob/deletable_file_reference.cc
new file mode 100644
index 0000000..b005eeb
--- /dev/null
+++ b/webkit/blob/deletable_file_reference.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "webkit/blob/deletable_file_reference.h"
+
+#include <map>
+#include "base/file_util.h"
+#include "base/file_util_proxy.h"
+#include "base/message_loop_proxy.h"
+#include "base/singleton.h"
+
+namespace webkit_blob {
+
+namespace {
+
+typedef std::map<FilePath, DeletableFileReference*> DeleteableFileMap;
+
+DeleteableFileMap* map() {
+ return Singleton<DeleteableFileMap>::get();
+}
+
+} // namespace
+
+// static
+scoped_refptr<DeletableFileReference> DeletableFileReference::Get(
+ const FilePath& path) {
+ DeleteableFileMap::iterator found = map()->find(path);
+ DeletableFileReference* reference =
+ (found == map()->end()) ? NULL : found->second;
+ return scoped_refptr<DeletableFileReference>(reference);
+}
+
+// static
+scoped_refptr<DeletableFileReference> DeletableFileReference::GetOrCreate(
+ const FilePath& path, base::MessageLoopProxy* file_thread) {
+ DCHECK(file_thread);
+ typedef std::pair<DeleteableFileMap::iterator, bool> InsertResult;
+ InsertResult result = map()->insert(
+ DeleteableFileMap::value_type(path, NULL));
+ if (result.second == false)
+ return scoped_refptr<DeletableFileReference>(result.first->second);
+
+ // Wasn't in the map, create a new reference and store the pointer.
+ scoped_refptr<DeletableFileReference> reference =
+ new DeletableFileReference(path, file_thread);
+ result.first->second = reference.get();
+ return reference;
+}
+
+DeletableFileReference::DeletableFileReference(
+ const FilePath& path, base::MessageLoopProxy* file_thread)
+ : path_(path), file_thread_(file_thread) {
+ DCHECK(map()->find(path_)->second == NULL);
+}
+
+DeletableFileReference::~DeletableFileReference() {
+ DCHECK(map()->find(path_)->second == this);
+ map()->erase(path_);
+ base::FileUtilProxy::Delete(file_thread_, path_, NULL);
+}
+
+} // namespace webkit_blob
diff --git a/webkit/blob/deletable_file_reference.h b/webkit/blob/deletable_file_reference.h
new file mode 100644
index 0000000..9578c10
--- /dev/null
+++ b/webkit/blob/deletable_file_reference.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBKIT_BLOB_DELETABLE_FILE_REFERENCE_H_
+#define WEBKIT_BLOB_DELETABLE_FILE_REFERENCE_H_
+#pragma once
+
+#include "base/file_path.h"
+#include "base/ref_counted.h"
+
+namespace base {
+class MessageLoopProxy;
+}
+
+namespace webkit_blob {
+
+// A refcounted wrapper around a FilePath that schedules the file
+// to be deleted upon final release.
+class DeletableFileReference : public base::RefCounted<DeletableFileReference> {
+ public:
+ // Returns a DeletableFileReference for the given path, if no reference
+ // for this path exists returns NULL.
+ static scoped_refptr<DeletableFileReference> Get(const FilePath& path);
+
+ // Returns a DeletableFileReference for the given path, creating a new
+ // reference if none yet exists.
+ static scoped_refptr<DeletableFileReference> GetOrCreate(
+ const FilePath& path, base::MessageLoopProxy* file_thread);
+
+ // The full file path.
+ const FilePath& path() const { return path_; }
+
+ private:
+ friend class base::RefCounted<DeletableFileReference>;
+
+ DeletableFileReference(
+ const FilePath& path, base::MessageLoopProxy* file_thread);
+ ~DeletableFileReference();
+
+ const FilePath path_;
+ scoped_refptr<base::MessageLoopProxy> file_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeletableFileReference);
+};
+
+} // namespace webkit_blob
+
+#endif // BASE_DELETABLE_FILE_REFERENCE_H_
diff --git a/webkit/blob/deletable_file_reference_unittest.cc b/webkit/blob/deletable_file_reference_unittest.cc
new file mode 100644
index 0000000..4a92612
--- /dev/null
+++ b/webkit/blob/deletable_file_reference_unittest.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "webkit/blob/deletable_file_reference.h"
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace webkit_blob {
+
+TEST(DeletableFileReferenceTest, TestReferences) {
+ scoped_refptr<base::MessageLoopProxy> loop_proxy =
+ base::MessageLoopProxy::CreateForCurrentThread();
+
+ // Create a file.
+ FilePath file;
+ file_util::CreateTemporaryFile(&file);
+ EXPECT_TRUE(file_util::PathExists(file));
+
+ // Create a first reference to that file.
+ scoped_refptr<DeletableFileReference> reference1;
+ reference1 = DeletableFileReference::Get(file);
+ EXPECT_FALSE(reference1.get());
+ reference1 = DeletableFileReference::GetOrCreate(file, loop_proxy);
+ EXPECT_TRUE(reference1.get());
+ EXPECT_TRUE(file == reference1->path());
+
+ // Get a second reference to that file.
+ scoped_refptr<DeletableFileReference> reference2;
+ reference2 = DeletableFileReference::Get(file);
+ EXPECT_EQ(reference1.get(), reference2.get());
+ reference2 = DeletableFileReference::GetOrCreate(file, loop_proxy);
+ EXPECT_EQ(reference1.get(), reference2.get());
+
+ // Drop the first reference, the file and reference should still be there.
+ reference1 = NULL;
+ EXPECT_TRUE(DeletableFileReference::Get(file).get());
+ MessageLoop::current()->RunAllPending();
+ EXPECT_TRUE(file_util::PathExists(file));
+
+ // Drop the second reference, the file and reference should get deleted.
+ reference2 = NULL;
+ EXPECT_FALSE(DeletableFileReference::Get(file).get());
+ MessageLoop::current()->RunAllPending();
+ EXPECT_FALSE(file_util::PathExists(file));
+}
+
+} // namespace webkit_blob
diff --git a/webkit/blob/webkit_blob.gypi b/webkit/blob/webkit_blob.gypi
index e057efb..eb4b3be 100644
--- a/webkit/blob/webkit_blob.gypi
+++ b/webkit/blob/webkit_blob.gypi
@@ -20,6 +20,8 @@
'blob_storage_controller.h',
'blob_url_request_job.cc',
'blob_url_request_job.h',
+ 'deletable_file_reference.cc',
+ 'deletable_file_reference.h',
],
'conditions': [
['inside_chromium_build==0', {
diff --git a/webkit/glue/weburlloader_impl.cc b/webkit/glue/weburlloader_impl.cc
index 528626e..aa63fc2 100644
--- a/webkit/glue/weburlloader_impl.cc
+++ b/webkit/glue/weburlloader_impl.cc
@@ -284,6 +284,7 @@ class WebURLLoaderImpl::Context : public base::RefCounted<Context>,
scoped_ptr<ResourceLoaderBridge> bridge_;
scoped_ptr<FtpDirectoryListingResponseDelegate> ftp_listing_delegate_;
scoped_ptr<MultipartResponseDelegate> multipart_delegate_;
+ scoped_ptr<ResourceLoaderBridge> completed_bridge_;
// TODO(japhet): Storing this is a temporary hack for site isolation logging.
WebURL response_url_;
@@ -598,8 +599,10 @@ void WebURLLoaderImpl::Context::OnCompletedRequest(
multipart_delegate_.reset(NULL);
}
- // Prevent any further IPC to the browser now that we're complete.
- bridge_.reset();
+ // Prevent any further IPC to the browser now that we're complete, but
+ // don't delete it to keep any downloaded temp files alive.
+ DCHECK(!completed_bridge_.get());
+ completed_bridge_.swap(bridge_);
if (client_) {
if (status.status() != URLRequestStatus::SUCCESS) {
diff --git a/webkit/tools/test_shell/simple_resource_loader_bridge.cc b/webkit/tools/test_shell/simple_resource_loader_bridge.cc
index acffef9..1feb389 100644
--- a/webkit/tools/test_shell/simple_resource_loader_bridge.cc
+++ b/webkit/tools/test_shell/simple_resource_loader_bridge.cc
@@ -33,8 +33,10 @@
#include "webkit/tools/test_shell/simple_resource_loader_bridge.h"
#include "base/file_path.h"
+#include "base/file_util.h"
#include "base/logging.h"
#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
#if defined(OS_MACOSX) || defined(OS_WIN)
#include "base/nss_util.h"
#endif
@@ -44,6 +46,7 @@
#include "base/thread.h"
#include "base/waitable_event.h"
#include "net/base/cookie_store.h"
+#include "net/base/file_stream.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -62,6 +65,7 @@
#include "webkit/appcache/appcache_interfaces.h"
#include "webkit/blob/blob_storage_controller.h"
#include "webkit/blob/blob_url_request_job.h"
+#include "webkit/blob/deletable_file_reference.h"
#include "webkit/glue/resource_loader_bridge.h"
#include "webkit/tools/test_shell/simple_appcache_system.h"
#include "webkit/tools/test_shell/simple_socket_stream_bridge.h"
@@ -71,6 +75,7 @@
using webkit_glue::ResourceLoaderBridge;
using net::StaticCookiePolicy;
using net::HttpResponseHeaders;
+using webkit_blob::DeletableFileReference;
namespace {
@@ -174,6 +179,7 @@ struct RequestParams {
int load_flags;
ResourceType::Type request_type;
int appcache_host_id;
+ bool download_to_file;
scoped_refptr<net::UploadData> upload;
};
@@ -188,7 +194,8 @@ class RequestProxy : public URLRequest::Delegate,
public:
// Takes ownership of the params.
RequestProxy()
- : buf_(new net::IOBuffer(kDataSize)),
+ : download_to_file_(false),
+ buf_(new net::IOBuffer(kDataSize)),
last_upload_position_(0) {
}
@@ -267,6 +274,17 @@ class RequestProxy : public URLRequest::Delegate,
peer_->OnReceivedData(buf_copy.get(), bytes_read);
}
+ void NotifyDownloadedData(int bytes_read) {
+ if (!peer_)
+ return;
+
+ // Continue reading more data, see the comment in NotifyReceivedData.
+ g_io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &RequestProxy::AsyncReadData));
+
+ peer_->OnDownloadedData(bytes_read);
+ }
+
void NotifyCompletedRequest(const URLRequestStatus& status,
const std::string& security_info,
const base::Time& complete_time) {
@@ -306,6 +324,17 @@ class RequestProxy : public URLRequest::Delegate,
SimpleAppCacheSystem::SetExtraRequestInfo(
request_.get(), params->appcache_host_id, params->request_type);
+ download_to_file_ = params->download_to_file;
+ if (download_to_file_) {
+ FilePath path;
+ if (file_util::CreateTemporaryFile(&path)) {
+ downloaded_file_ = DeletableFileReference::GetOrCreate(
+ path, base::MessageLoopProxy::CreateForCurrentThread());
+ file_stream_.Open(
+ path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE);
+ }
+ }
+
request_->Start();
if (request_->has_upload() &&
@@ -377,6 +406,13 @@ class RequestProxy : public URLRequest::Delegate,
}
virtual void OnReceivedData(int bytes_read) {
+ if (download_to_file_) {
+ file_stream_.Write(buf_->data(), bytes_read, NULL);
+ owner_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &RequestProxy::NotifyDownloadedData, bytes_read));
+ return;
+ }
+
owner_loop_->PostTask(FROM_HERE, NewRunnableMethod(
this, &RequestProxy::NotifyReceivedData, bytes_read));
}
@@ -384,6 +420,8 @@ class RequestProxy : public URLRequest::Delegate,
virtual void OnCompletedRequest(const URLRequestStatus& status,
const std::string& security_info,
const base::Time& complete_time) {
+ if (download_to_file_)
+ file_stream_.Close();
owner_loop_->PostTask(FROM_HERE, NewRunnableMethod(
this,
&RequestProxy::NotifyCompletedRequest,
@@ -486,6 +524,8 @@ class RequestProxy : public URLRequest::Delegate,
request->GetMimeType(&info->mime_type);
request->GetCharset(&info->charset);
info->content_length = request->GetExpectedContentSize();
+ if (downloaded_file_)
+ info->download_file_path = downloaded_file_->path();
SimpleAppCacheSystem::GetExtraResponseInfo(
request,
&info->appcache_id,
@@ -494,6 +534,11 @@ class RequestProxy : public URLRequest::Delegate,
scoped_ptr<URLRequest> request_;
+ // Support for request.download_to_file behavior.
+ bool download_to_file_;
+ net::FileStream file_stream_;
+ scoped_refptr<DeletableFileReference> downloaded_file_;
+
// Size of our async IO data buffers
static const int kDataSize = 16*1024;
@@ -553,13 +598,18 @@ class SyncRequestProxy : public RequestProxy {
}
virtual void OnReceivedData(int bytes_read) {
- result_->data.append(buf_->data(), bytes_read);
+ if (download_to_file_)
+ file_stream_.Write(buf_->data(), bytes_read, NULL);
+ else
+ result_->data.append(buf_->data(), bytes_read);
AsyncReadData(); // read more (may recurse)
}
virtual void OnCompletedRequest(const URLRequestStatus& status,
const std::string& security_info,
const base::Time& complete_time) {
+ if (download_to_file_)
+ file_stream_.Close();
result_->status = status;
event_.Signal();
}
@@ -577,7 +627,6 @@ class ResourceLoaderBridgeImpl : public ResourceLoaderBridge {
const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info)
: params_(new RequestParams),
proxy_(NULL) {
- DCHECK(!request_info.download_to_file); // Not implemented yet!
params_->method = request_info.method;
params_->url = request_info.url;
params_->first_party_for_cookies = request_info.first_party_for_cookies;
@@ -586,6 +635,7 @@ class ResourceLoaderBridgeImpl : public ResourceLoaderBridge {
params_->load_flags = request_info.load_flags;
params_->request_type = request_info.request_type;
params_->appcache_host_id = request_info.appcache_host_id;
+ params_->download_to_file = request_info.download_to_file;
}
virtual ~ResourceLoaderBridgeImpl() {
diff --git a/webkit/tools/test_shell/test_shell.gypi b/webkit/tools/test_shell/test_shell.gypi
index 3f23600..e047d37 100644
--- a/webkit/tools/test_shell/test_shell.gypi
+++ b/webkit/tools/test_shell/test_shell.gypi
@@ -370,6 +370,7 @@
'../../appcache/mock_appcache_storage_unittest.cc',
'../../blob/blob_storage_controller_unittest.cc',
'../../blob/blob_url_request_job_unittest.cc',
+ '../../blob/deletable_file_reference_unittest.cc',
'../../database/databases_table_unittest.cc',
'../../database/database_tracker_unittest.cc',
'../../database/database_util_unittest.cc',