diff options
21 files changed, 466 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 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; diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 38e71c0..07e522c 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 */, @@ -1872,6 +1872,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_ReleaseDownloadedFile, + int /* request_id */) + // Sent when a provisional load on the main frame redirects. IPC_MESSAGE_ROUTED3(ViewHostMsg_DidRedirectProvisionalLoad, int /* page_id */, @@ -1879,11 +1887,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..9f182a1 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_); + + if (request_.download_to_file) { + dispatcher_->message_sender()->Send( + new ViewHostMsg_ReleaseDownloadedFile(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..e4208a7 --- /dev/null +++ b/webkit/blob/deletable_file_reference_unittest.cc @@ -0,0 +1,54 @@ +// 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 "base/scoped_temp_dir.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace webkit_blob { + +TEST(DeletableFileReferenceTest, TestReferences) { + scoped_refptr<base::MessageLoopProxy> loop_proxy = + base::MessageLoopProxy::CreateForCurrentThread(); + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + + // Create a file. + FilePath file; + file_util::CreateTemporaryFileInDir(temp_dir.path(), &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', |