Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / prerender / prerender_resource_throttle.cc
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.
4
5 #include "chrome/browser/prerender/prerender_resource_throttle.h"
6
7 #include "chrome/browser/prerender/prerender_final_status.h"
8 #include "chrome/browser/prerender/prerender_manager.h"
9 #include "chrome/browser/prerender/prerender_util.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/render_frame_host.h"
12 #include "content/public/browser/resource_controller.h"
13 #include "content/public/browser/resource_request_info.h"
14 #include "content/public/browser/web_contents.h"
15 #include "net/url_request/url_request.h"
16
17 namespace prerender {
18
19 namespace {
20 static const char kFollowOnlyWhenPrerenderShown[] =
21     "follow-only-when-prerender-shown";
22
23 PrerenderContents* g_prerender_contents_for_testing;
24 }
25
26 void PrerenderResourceThrottle::OverridePrerenderContentsForTesting(
27     PrerenderContents* contents) {
28   g_prerender_contents_for_testing = contents;
29 }
30
31 PrerenderResourceThrottle::PrerenderResourceThrottle(net::URLRequest* request)
32     : request_(request) {
33 }
34
35 void PrerenderResourceThrottle::WillStartRequest(bool* defer) {
36   const content::ResourceRequestInfo* info =
37       content::ResourceRequestInfo::ForRequest(request_);
38   *defer = true;
39   content::BrowserThread::PostTask(
40       content::BrowserThread::UI,
41       FROM_HERE,
42       base::Bind(&PrerenderResourceThrottle::WillStartRequestOnUI,
43                  AsWeakPtr(), request_->method(), info->GetResourceType(),
44                  info->GetChildID(), info->GetRenderFrameID(),
45                  request_->url()));
46 }
47
48 void PrerenderResourceThrottle::WillRedirectRequest(const GURL& new_url,
49                                                     bool* defer) {
50   const content::ResourceRequestInfo* info =
51       content::ResourceRequestInfo::ForRequest(request_);
52   *defer = true;
53   std::string header;
54   request_->GetResponseHeaderByName(kFollowOnlyWhenPrerenderShown, &header);
55
56   content::BrowserThread::PostTask(
57       content::BrowserThread::UI,
58       FROM_HERE,
59       base::Bind(&PrerenderResourceThrottle::WillRedirectRequestOnUI,
60                  AsWeakPtr(), header, info->GetResourceType(), info->IsAsync(),
61                  info->GetChildID(), info->GetRenderFrameID(), new_url));
62 }
63
64 const char* PrerenderResourceThrottle::GetNameForLogging() const {
65   return "PrerenderResourceThrottle";
66 }
67
68 void PrerenderResourceThrottle::Resume() {
69   controller()->Resume();
70 }
71
72 void PrerenderResourceThrottle::Cancel() {
73   controller()->Cancel();
74 }
75
76 void PrerenderResourceThrottle::WillStartRequestOnUI(
77     const base::WeakPtr<PrerenderResourceThrottle>& throttle,
78     const std::string& method,
79     ResourceType::Type resource_type,
80     int render_process_id,
81     int render_frame_id,
82     const GURL& url) {
83   bool cancel = false;
84   PrerenderContents* prerender_contents =
85       PrerenderContentsFromRenderFrame(render_process_id, render_frame_id);
86   if (prerender_contents) {
87     // Abort any prerenders that spawn requests that use unsupported HTTP
88     // methods or schemes.
89     if (!PrerenderManager::IsValidHttpMethod(method)) {
90       prerender_contents->Destroy(FINAL_STATUS_INVALID_HTTP_METHOD);
91       cancel = true;
92     } else if (!PrerenderManager::DoesSubresourceURLHaveValidScheme(url)) {
93       prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME);
94       ReportUnsupportedPrerenderScheme(url);
95       cancel = true;
96 #if defined(OS_ANDROID)
97     } else if (resource_type == ResourceType::FAVICON) {
98       // Delay icon fetching until the contents are getting swapped in
99       // to conserve network usage in mobile devices.
100       prerender_contents->AddResourceThrottle(throttle);
101       return;
102 #endif
103     }
104   }
105
106   content::BrowserThread::PostTask(
107       content::BrowserThread::IO,
108       FROM_HERE,
109       base::Bind(cancel ? &PrerenderResourceThrottle::Cancel :
110                  &PrerenderResourceThrottle::Resume, throttle));
111 }
112
113 void PrerenderResourceThrottle::WillRedirectRequestOnUI(
114     const base::WeakPtr<PrerenderResourceThrottle>& throttle,
115     const std::string& follow_only_when_prerender_shown_header,
116     ResourceType::Type resource_type,
117     bool async,
118     int render_process_id,
119     int render_frame_id,
120     const GURL& new_url) {
121   bool cancel = false;
122   PrerenderContents* prerender_contents =
123       PrerenderContentsFromRenderFrame(render_process_id, render_frame_id);
124   if (prerender_contents) {
125     // Abort any prerenders with requests which redirect to invalid schemes.
126     if (!PrerenderManager::DoesURLHaveValidScheme(new_url)) {
127       prerender_contents->Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME);
128       ReportUnsupportedPrerenderScheme(new_url);
129       cancel = true;
130     } else if (follow_only_when_prerender_shown_header == "1" &&
131                resource_type != ResourceType::MAIN_FRAME) {
132       // Only defer redirects with the Follow-Only-When-Prerender-Shown
133       // header. Do not defer redirects on main frame loads.
134       if (!async) {
135         // Cancel on deferred synchronous requests. Those will
136         // indefinitely hang up a renderer process.
137         prerender_contents->Destroy(FINAL_STATUS_BAD_DEFERRED_REDIRECT);
138         cancel = true;
139       } else {
140         // Defer the redirect until the prerender is used or canceled.
141         prerender_contents->AddResourceThrottle(throttle);
142         return;
143       }
144     }
145   }
146
147   content::BrowserThread::PostTask(
148       content::BrowserThread::IO,
149       FROM_HERE,
150       base::Bind(cancel ? &PrerenderResourceThrottle::Cancel :
151                  &PrerenderResourceThrottle::Resume, throttle));
152 }
153
154 PrerenderContents* PrerenderResourceThrottle::PrerenderContentsFromRenderFrame(
155     int render_process_id, int render_frame_id) {
156   if (g_prerender_contents_for_testing)
157     return g_prerender_contents_for_testing;
158   content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
159       render_process_id, render_frame_id);
160   content::WebContents* web_contents =
161       content::WebContents::FromRenderFrameHost(rfh);
162   return PrerenderContents::FromWebContents(web_contents);
163 }
164
165 }  // namespace prerender