Index: content/browser/renderer_host/resource_dispatcher_host.cc |
diff --git a/content/browser/renderer_host/resource_dispatcher_host.cc b/content/browser/renderer_host/resource_dispatcher_host.cc |
index 46d2cc2abd3442ae08c956f9d31d8608da39f35c..19eea1c081af494836ad45f1fdbd7afc5d08e729 100644 |
--- a/content/browser/renderer_host/resource_dispatcher_host.cc |
+++ b/content/browser/renderer_host/resource_dispatcher_host.cc |
@@ -452,6 +452,11 @@ void ResourceDispatcherHost::OnSyncLoad( |
sync_result->routing_id()); |
} |
+// TODO(mpcomplete): hack |
+static GURL g_deferred_url; |
+static int g_deferred_child_id; |
+static int g_deferred_request_id; |
+ |
void ResourceDispatcherHost::BeginRequest( |
int request_id, |
const ResourceHostMsg_Request& request_data, |
@@ -466,6 +471,31 @@ void ResourceDispatcherHost::BeginRequest( |
base::strlcpy(url_buf, request_data.url.spec().c_str(), arraysize(url_buf)); |
base::debug::Alias(url_buf); |
+ // TODO(mpcomplete): Step 3. (See steps 1-2 below). |
+ // If the request that's coming in is a cross-process transferring, then we |
+ // want to reuse and resume the old request rather than start a new one. |
+ // I'm not entirely sure how much of the BeginRequest code should run. We |
+ // definitely want to create new ResourceHandlers and ExtraInfo, since those |
+ // are tied to the process. |
+ // Also, I'm not clear what should happen if any of the early returns are hit |
+ // before we actually resume the request via FollowDeferredRedirect. I think |
+ // we're then left with an orphaned request that will never be deleted. We |
+ // probably want to cancel it in those cases. |
+ // It's probably best to split apart BeginRequest into 2 methods, 1 for |
+ // regular requests and one for transferred ones - probably with some shared |
+ // code, but not all. |
+ net::URLRequest* deferred_request = NULL; |
+ if (!g_deferred_url.is_empty() && request_data.url == g_deferred_url) { |
+ g_deferred_url = GURL(); |
+ GlobalRequestID old_id(g_deferred_child_id, g_deferred_request_id); |
+ PendingRequestList::iterator i = pending_requests_.find(old_id); |
+ DCHECK(i != pending_requests_.end()); |
+ deferred_request = i->second; |
+ ResourceDispatcherHostRequestInfo* info = InfoForRequest(deferred_request); |
+ |
+ pending_requests_.erase(old_id); |
+ } |
+ |
const content::ResourceContext& resource_context = |
filter_->resource_context(); |
@@ -517,43 +547,49 @@ void ResourceDispatcherHost::BeginRequest( |
} |
// Construct the request. |
- net::URLRequest* request = new net::URLRequest(request_data.url, this); |
- request->set_method(request_data.method); |
- request->set_first_party_for_cookies(request_data.first_party_for_cookies); |
- request->set_referrer(referrer.spec()); |
- net::HttpRequestHeaders headers; |
- headers.AddHeadersFromString(request_data.headers); |
- request->SetExtraRequestHeaders(headers); |
- |
- int load_flags = request_data.load_flags; |
- // Although EV status is irrelevant to sub-frames and sub-resources, we have |
- // to perform EV certificate verification on all resources because an HTTP |
- // keep-alive connection created to load a sub-frame or a sub-resource could |
- // be reused to load a main frame. |
- load_flags |= net::LOAD_VERIFY_EV_CERT; |
- if (request_data.resource_type == ResourceType::MAIN_FRAME) { |
- load_flags |= net::LOAD_MAIN_FRAME; |
- } else if (request_data.resource_type == ResourceType::SUB_FRAME) { |
- load_flags |= net::LOAD_SUB_FRAME; |
- } else if (request_data.resource_type == ResourceType::PREFETCH) { |
- load_flags |= (net::LOAD_PREFETCH | net::LOAD_DO_NOT_PROMPT_FOR_LOGIN); |
- } else if (request_data.resource_type == ResourceType::FAVICON) { |
- load_flags |= net::LOAD_DO_NOT_PROMPT_FOR_LOGIN; |
- } |
- |
- if (sync_result) |
- load_flags |= net::LOAD_IGNORE_LIMITS; |
- |
- // Raw headers are sensitive, as they inclide Cookie/Set-Cookie, so only |
- // allow requesting them if requestor has ReadRawCookies permission. |
- if ((load_flags & net::LOAD_REPORT_RAW_HEADERS) |
- && !ChildProcessSecurityPolicy::GetInstance()-> |
- CanReadRawCookies(child_id)) { |
- VLOG(1) << "Denied unathorized request for raw headers"; |
- load_flags &= ~net::LOAD_REPORT_RAW_HEADERS; |
- } |
- |
- request->set_load_flags(load_flags); |
+ net::URLRequest* request; |
+ if (deferred_request) { |
+ request = deferred_request; |
+ } else { |
+ request = new net::URLRequest(request_data.url, this); |
+ request->set_method(request_data.method); |
+ request->set_first_party_for_cookies(request_data.first_party_for_cookies); |
+ request->set_referrer(referrer.spec()); |
+ net::HttpRequestHeaders headers; |
+ headers.AddHeadersFromString(request_data.headers); |
+ request->SetExtraRequestHeaders(headers); |
+ |
+ int load_flags = request_data.load_flags; |
+ // Although EV status is irrelevant to sub-frames and sub-resources, we have |
+ // to perform EV certificate verification on all resources because an HTTP |
+ // keep-alive connection created to load a sub-frame or a sub-resource could |
+ // be reused to load a main frame. |
+ load_flags |= net::LOAD_VERIFY_EV_CERT; |
+ if (request_data.resource_type == ResourceType::MAIN_FRAME) { |
+ load_flags |= net::LOAD_MAIN_FRAME; |
+ } else if (request_data.resource_type == ResourceType::SUB_FRAME) { |
+ load_flags |= net::LOAD_SUB_FRAME; |
+ } else if (request_data.resource_type == ResourceType::PREFETCH) { |
+ load_flags |= (net::LOAD_PREFETCH | net::LOAD_DO_NOT_PROMPT_FOR_LOGIN); |
+ } else if (request_data.resource_type == ResourceType::FAVICON) { |
+ load_flags |= net::LOAD_DO_NOT_PROMPT_FOR_LOGIN; |
+ } |
+ |
+ if (sync_result) |
+ load_flags |= net::LOAD_IGNORE_LIMITS; |
+ |
+ // Raw headers are sensitive, as they inclide Cookie/Set-Cookie, so only |
+ // allow requesting them if requestor has ReadRawCookies permission. |
+ if ((load_flags & net::LOAD_REPORT_RAW_HEADERS) |
+ && !ChildProcessSecurityPolicy::GetInstance()-> |
+ CanReadRawCookies(child_id)) { |
+ VLOG(1) << "Denied unathorized request for raw headers"; |
+ load_flags &= ~net::LOAD_REPORT_RAW_HEADERS; |
+ } |
+ |
+ request->set_load_flags(load_flags); |
+ } |
+ |
request->set_context( |
filter_->GetURLRequestContext(request_data.resource_type)); |
request->set_priority(DetermineRequestPriority(request_data.resource_type)); |
@@ -626,7 +662,13 @@ void ResourceDispatcherHost::BeginRequest( |
request, resource_context.appcache_service(), child_id, |
request_data.appcache_host_id, request_data.resource_type); |
- BeginRequestInternal(request); |
+ if (deferred_request) { |
+ GlobalRequestID global_id(extra_info->child_id(), extra_info->request_id()); |
+ pending_requests_[global_id] = request; |
+ request->FollowDeferredRedirect(); |
+ } else { |
+ BeginRequestInternal(request); |
+ } |
} |
void ResourceDispatcherHost::OnReleaseDownloadedFile(int request_id) { |
@@ -1185,6 +1227,13 @@ void ResourceDispatcherHost::RemovePendingRequest( |
const PendingRequestList::iterator& iter) { |
ResourceDispatcherHostRequestInfo* info = InfoForRequest(iter->second); |
+ // This is called via CancelRequestsForRoute to remove all requests for a |
+ // closing tab. We don't want to remove requests that are being transferred |
+ // to a new tab. |
+ if (info->child_id() == g_deferred_child_id && |
+ info->request_id() == g_deferred_request_id) |
+ return; |
+ |
// Remove the memory credit that we added when pushing the request onto |
// the pending list. |
IncrementOutstandingRequestsMemoryCost(-1 * info->memory_cost(), |
@@ -1205,8 +1254,12 @@ void ResourceDispatcherHost::RemovePendingRequest( |
update_load_states_timer_.Stop(); |
} |
+// TODO(mpcomplete): ILLEGAL! remove this |
+#include "chrome/browser/profiles/profile_io_data.h" |
+#include "chrome/browser/extensions/extension_info_map.h" |
// net::URLRequest::Delegate --------------------------------------------------- |
+ |
void ResourceDispatcherHost::OnReceivedRedirect(net::URLRequest* request, |
const GURL& new_url, |
bool* defer_redirect) { |
@@ -1237,6 +1290,50 @@ void ResourceDispatcherHost::OnReceivedRedirect(net::URLRequest* request, |
RemovePendingRequest(info->child_id(), info->request_id()); |
return; |
} |
+ |
+ // If we're redirecting into an extension process, we want to switch |
+ // processes. We do this by cancelling the redirect and reissuing the request, |
+ // so that the navigation controller properly assigns the right process to |
+ // host the new URL. |
+ const content::ResourceContext& resource_context = *info->context(); |
+ ProfileIOData* io_data = |
+ reinterpret_cast<ProfileIOData*>(resource_context.GetUserData(NULL)); |
+ |
+ // TODO(mpcomplete): Step 1. |
+ // This code should move into a resource handler instead. See the call to |
+ // delegate_->RequestBeginning below - the resource handler should live in |
+ // chrome/ so that it can reference extensions. |
+ if (io_data->GetExtensionInfoMap()->extensions().GetByURL(new_url) != |
+ io_data->GetExtensionInfoMap()->extensions().GetByURL(request->url())) { |
+ int render_process_id, render_view_id; |
+ if (RenderViewForRequest(request, &render_process_id, &render_view_id)) { |
+ // TODO(mpcomplete): Step 2. |
+ // This is uber hacky to short-circuit all the plumbing gunk we need to |
+ // do. We'll have to thread the child_id/request_id pair through the |
+ // navigation calls from browser to renderer and back again: |
+ // 1. new RVHD method that TabContents implements, like TransferNavigation |
+ // that issues a new navigation in a new renderer but tells it the ID |
+ // pair. Use NavigationController::LoadURL to load the request. |
+ // 2. thread the ID pair through |
+ // [browser] NavigationEntry, |
+ // [browser->renderer] ViewMsg_Navigate, |
+ // [renderer] NavigationState -> RequestExtraData, |
+ // [renderer->browser] ResourceHostMsg_RequestResource |
+ // 3. In ResourceDispatcherHost::BeginRequest (which handles the message |
+ // above), check if it is a transferred navigation. If so, proceed as I do |
+ // below when g_deferred_url is non-empty. |
+ |
+ g_deferred_url = new_url; |
+ g_deferred_child_id = render_process_id; |
+ g_deferred_request_id = info->request_id(); |
+ CallRenderViewHostDelegate( |
+ render_process_id, render_view_id, |
+ &RenderViewHostDelegate::RequestOpenURL, |
+ new_url, GURL(request->referrer()), CURRENT_TAB, info->frame_id_); |
+ *defer_redirect = true; |
+ return; |
+ } |
+ } |
scoped_refptr<ResourceResponse> response(new ResourceResponse); |
PopulateResourceResponse(request, response); |
@@ -1417,6 +1514,14 @@ bool ResourceDispatcherHost::CompleteResponseStarted(net::URLRequest* request) { |
void ResourceDispatcherHost::CancelRequest(int child_id, |
int request_id, |
bool from_renderer) { |
+ if (from_renderer && |
+ child_id == g_deferred_child_id && |
+ request_id == g_deferred_request_id) { |
+ // When the old renderer dies, it sends a message to us to cancel its |
+ // requests. |
+ return; |
+ } |
+ |
PendingRequestList::iterator i = pending_requests_.find( |
GlobalRequestID(child_id, request_id)); |
if (i == pending_requests_.end()) { |
@@ -1480,7 +1585,7 @@ int ResourceDispatcherHost::IncrementOutstandingRequestsMemoryCost( |
new_cost += cost; |
CHECK(new_cost >= 0); |
if (new_cost == 0) |
- outstanding_requests_memory_cost_map_.erase(prev_entry); |
+ outstanding_requests_memory_cost_map_.erase(child_id); |
else |
outstanding_requests_memory_cost_map_[child_id] = new_cost; |