diff options
Diffstat (limited to 'chrome/browser/renderer_host')
10 files changed, 127 insertions, 19 deletions
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 a2509fb..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()->GrantReadFile( - 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 8085d93..9126eb9 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_ReleaseDownloadedFile, + OnReleaseDownloadedFile) 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::OnReleaseDownloadedFile(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,28 @@ 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()->GrantReadFile( + 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. +} + bool ResourceDispatcherHost::Send(IPC::Message* message) { delete message; return false; @@ -847,6 +890,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 +1842,9 @@ bool ResourceDispatcherHost::IsResourceDispatcherHostMessage( case ViewHostMsg_CancelRequest::ID: case ViewHostMsg_FollowRedirect::ID: case ViewHostMsg_ClosePage_ACK::ID: + case ViewHostMsg_ReleaseDownloadedFile::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..95909d3be 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 OnReleaseDownloadedFile(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 client no longer needs them. + 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; |