diff options
Diffstat (limited to 'chromium/content/child/resource_dispatcher.cc')
-rw-r--r-- | chromium/content/child/resource_dispatcher.cc | 319 |
1 files changed, 184 insertions, 135 deletions
diff --git a/chromium/content/child/resource_dispatcher.cc b/chromium/content/child/resource_dispatcher.cc index c5243b56dde..95697d944d7 100644 --- a/chromium/content/child/resource_dispatcher.cc +++ b/chromium/content/child/resource_dispatcher.cc @@ -16,20 +16,23 @@ #include "base/metrics/histogram.h" #include "base/strings/string_util.h" #include "content/child/request_extra_data.h" +#include "content/child/request_info.h" #include "content/child/site_isolation_policy.h" +#include "content/child/sync_load_response.h" +#include "content/child/threaded_data_provider.h" #include "content/common/inter_process_time_ticks_converter.h" #include "content/common/resource_messages.h" +#include "content/public/child/request_peer.h" #include "content/public/child/resource_dispatcher_delegate.h" #include "content/public/common/resource_response.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" #include "net/base/request_priority.h" #include "net/http/http_response_headers.h" +#include "webkit/child/resource_loader_bridge.h" #include "webkit/common/resource_type.h" using webkit_glue::ResourceLoaderBridge; -using webkit_glue::ResourceRequestBody; -using webkit_glue::ResourceResponseInfo; namespace content { @@ -44,10 +47,7 @@ void RemoteToLocalTimeTicks( *time = converter.ToLocalTimeTicks(remote_time).ToTimeTicks(); } - -} // namespace - -static void CrashOnMapFailure() { +void CrashOnMapFailure() { #if defined(OS_WIN) DWORD last_err = GetLastError(); base::debug::Alias(&last_err); @@ -56,7 +56,7 @@ static void CrashOnMapFailure() { } // Each resource request is assigned an ID scoped to this process. -static int MakeRequestID() { +int MakeRequestID() { // NOTE: The resource_dispatcher_host also needs probably unique // request_ids, so they count down from -2 (-1 is a special we're // screwed value), while the renderer process counts up. @@ -64,25 +64,28 @@ static int MakeRequestID() { return next_request_id++; } +} // namespace + // ResourceLoaderBridge implementation ---------------------------------------- class IPCResourceLoaderBridge : public ResourceLoaderBridge { public: IPCResourceLoaderBridge(ResourceDispatcher* dispatcher, - const ResourceLoaderBridge::RequestInfo& request_info); + const RequestInfo& request_info); virtual ~IPCResourceLoaderBridge(); // ResourceLoaderBridge virtual void SetRequestBody(ResourceRequestBody* request_body) OVERRIDE; - virtual bool Start(Peer* peer) OVERRIDE; + virtual bool Start(RequestPeer* peer) OVERRIDE; virtual void Cancel() OVERRIDE; virtual void SetDefersLoading(bool value) OVERRIDE; - virtual void DidChangePriority(net::RequestPriority new_priority) OVERRIDE; + virtual void DidChangePriority(net::RequestPriority new_priority, + int intra_priority_value) OVERRIDE; + virtual bool AttachThreadedDataReceiver( + blink::WebThreadedDataReceiver* threaded_data_receiver) OVERRIDE; virtual void SyncLoad(SyncLoadResponse* response) OVERRIDE; private: - ResourceLoaderBridge::Peer* peer_; - // The resource dispatcher for this loader. The bridge doesn't own it, but // it's guaranteed to outlive the bridge. ResourceDispatcher* dispatcher_; @@ -105,9 +108,8 @@ class IPCResourceLoaderBridge : public ResourceLoaderBridge { IPCResourceLoaderBridge::IPCResourceLoaderBridge( ResourceDispatcher* dispatcher, - const ResourceLoaderBridge::RequestInfo& request_info) - : peer_(NULL), - dispatcher_(dispatcher), + const RequestInfo& request_info) + : dispatcher_(dispatcher), request_id_(-1), routing_id_(request_info.routing_id), is_synchronous_request_(false) { @@ -126,35 +128,29 @@ IPCResourceLoaderBridge::IPCResourceLoaderBridge( request_.appcache_host_id = request_info.appcache_host_id; request_.download_to_file = request_info.download_to_file; request_.has_user_gesture = request_info.has_user_gesture; - if (request_info.extra_data) { - RequestExtraData* extra_data = - static_cast<RequestExtraData*>(request_info.extra_data); - request_.render_frame_id = extra_data->render_frame_id(); - request_.is_main_frame = extra_data->is_main_frame(); - request_.frame_id = extra_data->frame_id(); - request_.parent_is_main_frame = extra_data->parent_is_main_frame(); - request_.parent_frame_id = extra_data->parent_frame_id(); - request_.allow_download = extra_data->allow_download(); - request_.transition_type = extra_data->transition_type(); - request_.should_replace_current_entry = - extra_data->should_replace_current_entry(); - request_.transferred_request_child_id = - extra_data->transferred_request_child_id(); - request_.transferred_request_request_id = - extra_data->transferred_request_request_id(); - frame_origin_ = extra_data->frame_origin(); - } else { - request_.render_frame_id = MSG_ROUTING_NONE; - request_.is_main_frame = false; - request_.frame_id = -1; - request_.parent_is_main_frame = false; - request_.parent_frame_id = -1; - request_.allow_download = true; - request_.transition_type = PAGE_TRANSITION_LINK; - request_.should_replace_current_entry = false; - request_.transferred_request_child_id = -1; - request_.transferred_request_request_id = -1; - } + + const RequestExtraData kEmptyData; + const RequestExtraData* extra_data; + if (request_info.extra_data) + extra_data = static_cast<RequestExtraData*>(request_info.extra_data); + else + extra_data = &kEmptyData; + request_.visiblity_state = extra_data->visibility_state(); + request_.render_frame_id = extra_data->render_frame_id(); + request_.is_main_frame = extra_data->is_main_frame(); + request_.parent_is_main_frame = extra_data->parent_is_main_frame(); + request_.parent_render_frame_id = extra_data->parent_render_frame_id(); + request_.allow_download = extra_data->allow_download(); + request_.transition_type = extra_data->transition_type(); + request_.should_replace_current_entry = + extra_data->should_replace_current_entry(); + request_.transferred_request_child_id = + extra_data->transferred_request_child_id(); + request_.transferred_request_request_id = + extra_data->transferred_request_request_id(); + request_.service_worker_provider_id = + extra_data->service_worker_provider_id(); + frame_origin_ = extra_data->frame_origin(); } IPCResourceLoaderBridge::~IPCResourceLoaderBridge() { @@ -164,11 +160,6 @@ 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 ResourceHostMsg_ReleaseDownloadedFile(request_id_)); - } } } @@ -179,20 +170,19 @@ void IPCResourceLoaderBridge::SetRequestBody( } // Writes a footer on the message and sends it -bool IPCResourceLoaderBridge::Start(Peer* peer) { +bool IPCResourceLoaderBridge::Start(RequestPeer* peer) { if (request_id_ != -1) { NOTREACHED() << "Starting a request twice"; return false; } - peer_ = peer; - // generate the request ID, and append it to the message - request_id_ = dispatcher_->AddPendingRequest(peer_, + request_id_ = dispatcher_->AddPendingRequest(peer, request_.resource_type, request_.origin_pid, frame_origin_, - request_.url); + request_.url, + request_.download_to_file); return dispatcher_->message_sender()->Send( new ResourceHostMsg_RequestResource(routing_id_, request_id_, request_)); @@ -204,12 +194,10 @@ void IPCResourceLoaderBridge::Cancel() { return; } - if (!is_synchronous_request_) + if (!is_synchronous_request_) { + // This also removes the the request from the dispatcher. dispatcher_->CancelPendingRequest(request_id_); - - // We can't remove the request ID from the resource dispatcher because more - // data might be pending. Sending the cancel message may cause more data - // to be flushed, and will then cause a complete message to be sent. + } } void IPCResourceLoaderBridge::SetDefersLoading(bool value) { @@ -222,13 +210,26 @@ void IPCResourceLoaderBridge::SetDefersLoading(bool value) { } void IPCResourceLoaderBridge::DidChangePriority( - net::RequestPriority new_priority) { + net::RequestPriority new_priority, + int intra_priority_value) { if (request_id_ < 0) { NOTREACHED() << "Trying to change priority of an unstarted request"; return; } - dispatcher_->DidChangePriority(routing_id_, request_id_, new_priority); + dispatcher_->DidChangePriority( + request_id_, new_priority, intra_priority_value); +} + +bool IPCResourceLoaderBridge::AttachThreadedDataReceiver( + blink::WebThreadedDataReceiver* threaded_data_receiver) { + if (request_id_ < 0) { + NOTREACHED() << "Trying to attach threaded receiver on unstarted request"; + return false; + } + + return dispatcher_->AttachThreadedDataReceiver(request_id_, + threaded_data_receiver); } void IPCResourceLoaderBridge::SyncLoad(SyncLoadResponse* response) { @@ -338,7 +339,7 @@ void ResourceDispatcher::OnUploadProgress(int request_id, int64 position, request_info->peer->OnUploadProgress(position, size); // Acknowledge receipt - message_sender()->Send(new ResourceHostMsg_UploadProgress_ACK(request_id)); + message_sender_->Send(new ResourceHostMsg_UploadProgress_ACK(request_id)); } void ResourceDispatcher::OnReceivedResponse( @@ -350,7 +351,7 @@ void ResourceDispatcher::OnReceivedResponse( request_info->response_start = ConsumeIOTimestamp(); if (delegate_) { - ResourceLoaderBridge::Peer* new_peer = + RequestPeer* new_peer = delegate_->OnReceivedResponse( request_info->peer, response_head.mime_type, request_info->url); if (new_peer) @@ -359,12 +360,12 @@ void ResourceDispatcher::OnReceivedResponse( ResourceResponseInfo renderer_response_info; ToResourceResponseInfo(*request_info, response_head, &renderer_response_info); - SiteIsolationPolicy::OnReceivedResponse(request_id, - request_info->frame_origin, - request_info->response_url, - request_info->resource_type, - request_info->origin_pid, - renderer_response_info); + request_info->site_isolation_metadata = + SiteIsolationPolicy::OnReceivedResponse(request_info->frame_origin, + request_info->response_url, + request_info->resource_type, + request_info->origin_pid, + renderer_response_info); request_info->peer->OnReceivedResponse(renderer_response_info); } @@ -416,6 +417,7 @@ void ResourceDispatcher::OnReceivedData(int request_id, TRACE_EVENT0("loader", "ResourceDispatcher::OnReceivedData"); DCHECK_GT(data_length, 0); PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); + bool send_ack = true; if (request_info && data_length > 0) { CHECK(base::SharedMemory::IsHandleValid(request_info->buffer->handle())); CHECK_GE(request_info->buffer_size, data_offset + data_length); @@ -427,27 +429,42 @@ void ResourceDispatcher::OnReceivedData(int request_id, base::TimeTicks time_start = base::TimeTicks::Now(); - const char* data_ptr = static_cast<char*>(request_info->buffer->memory()); - CHECK(data_ptr); - CHECK(data_ptr + data_offset); + const char* data_start = static_cast<char*>(request_info->buffer->memory()); + CHECK(data_start); + CHECK(data_start + data_offset); + const char* data_ptr = data_start + data_offset; // Check whether this response data is compliant with our cross-site - // document blocking policy. + // document blocking policy. We only do this for the first packet. std::string alternative_data; - bool blocked_response = SiteIsolationPolicy::ShouldBlockResponse( - request_id, data_ptr + data_offset, data_length, &alternative_data); - - // When the response is not blocked. - if (!blocked_response) { - request_info->peer->OnReceivedData( - data_ptr + data_offset, data_length, encoded_data_length); - } else if (alternative_data.size() > 0) { - // When the response is blocked, and when we have any alternative data to + if (request_info->site_isolation_metadata.get()) { + request_info->blocked_response = + SiteIsolationPolicy::ShouldBlockResponse( + request_info->site_isolation_metadata, data_ptr, data_length, + &alternative_data); + request_info->site_isolation_metadata.reset(); + + // When the response is blocked we may have any alternative data to // send to the renderer. When |alternative_data| is zero-sized, we do not // call peer's callback. - request_info->peer->OnReceivedData(alternative_data.data(), - alternative_data.size(), - alternative_data.size()); + if (request_info->blocked_response && !alternative_data.empty()) { + data_ptr = alternative_data.data(); + data_length = alternative_data.size(); + encoded_data_length = alternative_data.size(); + } + } + + if (!request_info->blocked_response || !alternative_data.empty()) { + if (request_info->threaded_data_provider) { + request_info->threaded_data_provider->OnReceivedDataOnForegroundThread( + data_ptr, data_length, encoded_data_length); + // A threaded data provider will take care of its own ACKing, as the + // data may be processed later on another thread. + send_ack = false; + } else { + request_info->peer->OnReceivedData( + data_ptr, data_length, encoded_data_length); + } } UMA_HISTOGRAM_TIMES("ResourceDispatcher.OnReceivedDataTime", @@ -455,15 +472,15 @@ void ResourceDispatcher::OnReceivedData(int request_id, } // Acknowledge the reception of this data. - message_sender()->Send(new ResourceHostMsg_DataReceived_ACK(request_id)); + if (send_ack) + message_sender_->Send(new ResourceHostMsg_DataReceived_ACK(request_id)); } void ResourceDispatcher::OnDownloadedData(int request_id, int data_len, int encoded_data_length) { // Acknowledge the reception of this message. - message_sender()->Send( - new ResourceHostMsg_DataDownloaded_ACK(request_id)); + message_sender_->Send(new ResourceHostMsg_DataDownloaded_ACK(request_id)); PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); if (!request_info) @@ -475,6 +492,7 @@ void ResourceDispatcher::OnDownloadedData(int request_id, void ResourceDispatcher::OnReceivedRedirect( int request_id, const GURL& new_url, + const GURL& new_first_party_for_cookies, const ResourceResponseHead& response_head) { TRACE_EVENT0("loader", "ResourceDispatcher::OnReceivedRedirect"); PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); @@ -482,13 +500,10 @@ void ResourceDispatcher::OnReceivedRedirect( return; request_info->response_start = ConsumeIOTimestamp(); - bool has_new_first_party_for_cookies = false; - GURL new_first_party_for_cookies; ResourceResponseInfo renderer_response_info; ToResourceResponseInfo(*request_info, response_head, &renderer_response_info); - if (request_info->peer->OnReceivedRedirect(new_url, renderer_response_info, - &has_new_first_party_for_cookies, - &new_first_party_for_cookies)) { + if (request_info->peer->OnReceivedRedirect( + new_url, new_first_party_for_cookies, renderer_response_info)) { // Double-check if the request is still around. The call above could // potentially remove it. request_info = GetPendingRequestInfo(request_id); @@ -498,9 +513,7 @@ void ResourceDispatcher::OnReceivedRedirect( // SiteIsolationPolicy later when OnReceivedResponse is called. request_info->response_url = new_url; request_info->pending_redirect_message.reset( - new ResourceHostMsg_FollowRedirect(request_id, - has_new_first_party_for_cookies, - new_first_party_for_cookies)); + new ResourceHostMsg_FollowRedirect(request_id)); if (!request_info->is_deferred) { FollowPendingRedirect(request_id, *request_info); } @@ -514,17 +527,13 @@ void ResourceDispatcher::FollowPendingRedirect( PendingRequestInfo& request_info) { IPC::Message* msg = request_info.pending_redirect_message.release(); if (msg) - message_sender()->Send(msg); + message_sender_->Send(msg); } void ResourceDispatcher::OnRequestComplete( int request_id, - int error_code, - bool was_ignored_by_handler, - const std::string& security_info, - const base::TimeTicks& browser_completion_time) { + const ResourceMsg_RequestCompleteData& request_complete_data) { TRACE_EVENT0("loader", "ResourceDispatcher::OnRequestComplete"); - SiteIsolationPolicy::OnRequestComplete(request_id); PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); if (!request_info) @@ -533,35 +542,44 @@ void ResourceDispatcher::OnRequestComplete( request_info->buffer.reset(); request_info->buffer_size = 0; - ResourceLoaderBridge::Peer* peer = request_info->peer; + RequestPeer* peer = request_info->peer; if (delegate_) { - ResourceLoaderBridge::Peer* new_peer = + RequestPeer* new_peer = delegate_->OnRequestComplete( - request_info->peer, request_info->resource_type, error_code); + request_info->peer, request_info->resource_type, + request_complete_data.error_code); if (new_peer) request_info->peer = new_peer; } base::TimeTicks renderer_completion_time = ToRendererCompletionTime( - *request_info, browser_completion_time); + *request_info, request_complete_data.completion_time); // The request ID will be removed from our pending list in the destructor. // Normally, dispatching this message causes the reference-counted request to // die immediately. - peer->OnCompletedRequest(error_code, was_ignored_by_handler, security_info, - renderer_completion_time); -} - -int ResourceDispatcher::AddPendingRequest( - ResourceLoaderBridge::Peer* callback, - ResourceType::Type resource_type, - int origin_pid, - const GURL& frame_origin, - const GURL& request_url) { + peer->OnCompletedRequest(request_complete_data.error_code, + request_complete_data.was_ignored_by_handler, + request_complete_data.exists_in_cache, + request_complete_data.security_info, + renderer_completion_time, + request_complete_data.encoded_data_length); +} + +int ResourceDispatcher::AddPendingRequest(RequestPeer* callback, + ResourceType::Type resource_type, + int origin_pid, + const GURL& frame_origin, + const GURL& request_url, + bool download_to_file) { // Compute a unique request_id for this renderer process. int id = MakeRequestID(); - pending_requests_[id] = PendingRequestInfo( - callback, resource_type, origin_pid, frame_origin, request_url); + pending_requests_[id] = PendingRequestInfo(callback, + resource_type, + origin_pid, + frame_origin, + request_url, + download_to_file); return id; } @@ -570,11 +588,18 @@ bool ResourceDispatcher::RemovePendingRequest(int request_id) { if (it == pending_requests_.end()) return false; - SiteIsolationPolicy::OnRequestComplete(request_id); PendingRequestInfo& request_info = it->second; + + bool release_downloaded_file = request_info.download_to_file; + ReleaseResourcesInMessageQueue(&request_info.deferred_message_queue); pending_requests_.erase(it); + if (release_downloaded_file) { + message_sender_->Send( + new ResourceHostMsg_ReleaseDownloadedFile(request_id)); + } + return true; } @@ -585,12 +610,10 @@ void ResourceDispatcher::CancelPendingRequest(int request_id) { return; } - SiteIsolationPolicy::OnRequestComplete(request_id); - PendingRequestInfo& request_info = it->second; - ReleaseResourcesInMessageQueue(&request_info.deferred_message_queue); - pending_requests_.erase(it); - - message_sender()->Send(new ResourceHostMsg_CancelRequest(request_id)); + // Cancel the request, and clean it up so the bridge will receive no more + // messages. + message_sender_->Send(new ResourceHostMsg_CancelRequest(request_id)); + RemovePendingRequest(request_id); } void ResourceDispatcher::SetDefersLoading(int request_id, bool value) { @@ -615,37 +638,63 @@ void ResourceDispatcher::SetDefersLoading(int request_id, bool value) { } } -void ResourceDispatcher::DidChangePriority( - int routing_id, int request_id, net::RequestPriority new_priority) { +void ResourceDispatcher::DidChangePriority(int request_id, + net::RequestPriority new_priority, + int intra_priority_value) { DCHECK(ContainsKey(pending_requests_, request_id)); - message_sender()->Send(new ResourceHostMsg_DidChangePriority( - request_id, new_priority)); + message_sender_->Send(new ResourceHostMsg_DidChangePriority( + request_id, new_priority, intra_priority_value)); +} + +bool ResourceDispatcher::AttachThreadedDataReceiver( + int request_id, blink::WebThreadedDataReceiver* threaded_data_receiver) { + PendingRequestInfo* request_info = GetPendingRequestInfo(request_id); + DCHECK(request_info); + + if (request_info->buffer != NULL) { + DCHECK(!request_info->threaded_data_provider); + request_info->threaded_data_provider = new ThreadedDataProvider( + request_id, threaded_data_receiver, request_info->buffer, + request_info->buffer_size); + return true; + } + + return false; } ResourceDispatcher::PendingRequestInfo::PendingRequestInfo() : peer(NULL), + threaded_data_provider(NULL), resource_type(ResourceType::SUB_RESOURCE), is_deferred(false), + download_to_file(false), + blocked_response(false), buffer_size(0) { } ResourceDispatcher::PendingRequestInfo::PendingRequestInfo( - webkit_glue::ResourceLoaderBridge::Peer* peer, + RequestPeer* peer, ResourceType::Type resource_type, int origin_pid, const GURL& frame_origin, - const GURL& request_url) + const GURL& request_url, + bool download_to_file) : peer(peer), + threaded_data_provider(NULL), resource_type(resource_type), origin_pid(origin_pid), is_deferred(false), url(request_url), frame_origin(frame_origin), response_url(request_url), - request_start(base::TimeTicks::Now()) { -} + download_to_file(download_to_file), + request_start(base::TimeTicks::Now()), + blocked_response(false) {} -ResourceDispatcher::PendingRequestInfo::~PendingRequestInfo() {} +ResourceDispatcher::PendingRequestInfo::~PendingRequestInfo() { + if (threaded_data_provider) + threaded_data_provider->Stop(); +} void ResourceDispatcher::DispatchMessage(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(ResourceDispatcher, message) @@ -693,7 +742,7 @@ void ResourceDispatcher::FlushDeferredMessages(int request_id) { } ResourceLoaderBridge* ResourceDispatcher::CreateBridge( - const ResourceLoaderBridge::RequestInfo& request_info) { + const RequestInfo& request_info) { return new IPCResourceLoaderBridge(this, request_info); } |