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