Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / prerender / prerender_resource_throttle.cc
blobb9fe1d3ec56aa930589d198e09394b7ef4dbac9a
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/prerender/prerender_resource_throttle.h"
7 #include "chrome/browser/prerender/prerender_final_status.h"
8 #include "chrome/browser/prerender/prerender_manager.h"
9 #include "chrome/browser/prerender/prerender_tracker.h"
10 #include "chrome/browser/prerender/prerender_util.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/render_frame_host.h"
13 #include "content/public/browser/resource_controller.h"
14 #include "content/public/browser/resource_request_info.h"
15 #include "content/public/browser/web_contents.h"
16 #include "net/url_request/url_request.h"
18 namespace prerender {
20 namespace {
21 static const char kFollowOnlyWhenPrerenderShown[] =
22 "follow-only-when-prerender-shown";
24 PrerenderContents* g_prerender_contents_for_testing;
27 void PrerenderResourceThrottle::OverridePrerenderContentsForTesting(
28 PrerenderContents* contents) {
29 g_prerender_contents_for_testing = contents;
32 PrerenderResourceThrottle::PrerenderResourceThrottle(
33 net::URLRequest* request,
34 PrerenderTracker* tracker)
35 : request_(request),
36 tracker_(tracker) {
39 void PrerenderResourceThrottle::WillStartRequest(bool* defer) {
40 const content::ResourceRequestInfo* info =
41 content::ResourceRequestInfo::ForRequest(request_);
42 int child_id = info->GetChildID();
43 int route_id = info->GetRouteID();
45 // If the prerender was used since the throttle was added, leave it
46 // alone.
47 if (!tracker_->IsPrerenderingOnIOThread(child_id, route_id))
48 return;
50 *defer = true;
51 content::BrowserThread::PostTask(
52 content::BrowserThread::UI,
53 FROM_HERE,
54 base::Bind(&PrerenderResourceThrottle::WillStartRequestOnUI,
55 AsWeakPtr(), request_->method(), info->GetChildID(),
56 info->GetRenderFrameID(), request_->url()));
59 void PrerenderResourceThrottle::WillRedirectRequest(const GURL& new_url,
60 bool* defer) {
61 const content::ResourceRequestInfo* info =
62 content::ResourceRequestInfo::ForRequest(request_);
63 int child_id = info->GetChildID();
64 int route_id = info->GetRouteID();
66 // If the prerender was used since the throttle was added, leave it
67 // alone.
68 if (!tracker_->IsPrerenderingOnIOThread(child_id, route_id))
69 return;
71 *defer = true;
72 std::string header;
73 request_->GetResponseHeaderByName(kFollowOnlyWhenPrerenderShown, &header);
75 content::BrowserThread::PostTask(
76 content::BrowserThread::UI,
77 FROM_HERE,
78 base::Bind(&PrerenderResourceThrottle::WillRedirectRequestOnUI,
79 AsWeakPtr(), header, info->GetResourceType(), info->IsAsync(),
80 info->GetChildID(), info->GetRenderFrameID(), new_url));
83 const char* PrerenderResourceThrottle::GetNameForLogging() const {
84 return "PrerenderResourceThrottle";
87 void PrerenderResourceThrottle::Resume() {
88 controller()->Resume();
91 void PrerenderResourceThrottle::Cancel() {
92 controller()->Cancel();
95 void PrerenderResourceThrottle::WillStartRequestOnUI(
96 const base::WeakPtr<PrerenderResourceThrottle>& throttle,
97 const std::string& method,
98 int render_process_id,
99 int render_frame_id,
100 const GURL& url) {
101 bool cancel = false;
102 PrerenderContents* prerender_contents =
103 PrerenderContentsFromRenderFrame(render_process_id, render_frame_id);
104 if (prerender_contents) {
105 // Abort any prerenders that spawn requests that use unsupported HTTP
106 // methods or schemes.
107 if (!PrerenderManager::IsValidHttpMethod(method)) {
108 prerender_contents->Destroy(FINAL_STATUS_INVALID_HTTP_METHOD);
109 cancel = true;
110 } else if (!PrerenderManager::DoesSubresourceURLHaveValidScheme(url)) {
111 prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME);
112 ReportUnsupportedPrerenderScheme(url);
113 cancel = true;
117 content::BrowserThread::PostTask(
118 content::BrowserThread::IO,
119 FROM_HERE,
120 base::Bind(cancel ? &PrerenderResourceThrottle::Cancel :
121 &PrerenderResourceThrottle::Resume, throttle));
124 void PrerenderResourceThrottle::WillRedirectRequestOnUI(
125 const base::WeakPtr<PrerenderResourceThrottle>& throttle,
126 const std::string& follow_only_when_prerender_shown_header,
127 ResourceType::Type resource_type,
128 bool async,
129 int render_process_id,
130 int render_frame_id,
131 const GURL& new_url) {
132 bool cancel = false;
133 PrerenderContents* prerender_contents =
134 PrerenderContentsFromRenderFrame(render_process_id, render_frame_id);
135 if (prerender_contents) {
136 // Abort any prerenders with requests which redirect to invalid schemes.
137 if (!PrerenderManager::DoesURLHaveValidScheme(new_url)) {
138 prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME);
139 ReportUnsupportedPrerenderScheme(new_url);
140 cancel = true;
141 } else if (follow_only_when_prerender_shown_header == "1" &&
142 resource_type != ResourceType::MAIN_FRAME) {
143 // Only defer redirects with the Follow-Only-When-Prerender-Shown
144 // header. Do not defer redirects on main frame loads.
145 if (!async) {
146 // Cancel on deferred synchronous requests. Those will
147 // indefinitely hang up a renderer process.
148 prerender_contents->Destroy(FINAL_STATUS_BAD_DEFERRED_REDIRECT);
149 cancel = true;
150 } else {
151 // Defer the redirect until the prerender is used or
152 // canceled. It is possible for the UI thread to used the
153 // prerender at the same time. But then |tracker_| will resume
154 // the request soon in
155 // PrerenderTracker::RemovePrerenderOnIOThread.
156 content::BrowserThread::PostTask(
157 content::BrowserThread::IO,
158 FROM_HERE,
159 base::Bind(&PrerenderResourceThrottle::AddResourceThrottle,
160 throttle));
161 return;
166 content::BrowserThread::PostTask(
167 content::BrowserThread::IO,
168 FROM_HERE,
169 base::Bind(cancel ? &PrerenderResourceThrottle::Cancel :
170 &PrerenderResourceThrottle::Resume, throttle));
173 PrerenderContents* PrerenderResourceThrottle::PrerenderContentsFromRenderFrame(
174 int render_process_id, int render_frame_id) {
175 if (g_prerender_contents_for_testing)
176 return g_prerender_contents_for_testing;
177 content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
178 render_process_id, render_frame_id);
179 content::WebContents* web_contents =
180 content::WebContents::FromRenderFrameHost(rfh);
181 return PrerenderContents::FromWebContents(web_contents);
184 void PrerenderResourceThrottle::AddResourceThrottle() {
185 const content::ResourceRequestInfo* info =
186 content::ResourceRequestInfo::ForRequest(request_);
187 int child_id = info->GetChildID();
188 int route_id = info->GetRouteID();
189 tracker_->AddResourceThrottleOnIOThread(child_id, route_id, AsWeakPtr());
192 } // namespace prerender