• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_tracker.h"
10 #include "chrome/browser/prerender/prerender_util.h"
11 #include "content/public/browser/resource_controller.h"
12 #include "content/public/browser/resource_request_info.h"
13 #include "net/url_request/url_request.h"
14 
15 namespace prerender {
16 
17 static const char kFollowOnlyWhenPrerenderShown[] =
18     "follow-only-when-prerender-shown";
19 
PrerenderResourceThrottle(net::URLRequest * request,PrerenderTracker * tracker)20 PrerenderResourceThrottle::PrerenderResourceThrottle(
21     net::URLRequest* request,
22     PrerenderTracker* tracker)
23     : request_(request),
24       tracker_(tracker),
25       throttled_(false) {
26 }
27 
WillStartRequest(bool * defer)28 void PrerenderResourceThrottle::WillStartRequest(bool* defer) {
29   const content::ResourceRequestInfo* info =
30       content::ResourceRequestInfo::ForRequest(request_);
31   int child_id = info->GetChildID();
32   int route_id = info->GetRouteID();
33 
34   // If the prerender was used since the throttle was added, leave it
35   // alone.
36   if (!tracker_->IsPrerenderingOnIOThread(child_id, route_id))
37     return;
38 
39   // Abort any prerenders that spawn requests that use unsupported HTTP methods
40   // or schemes.
41   if (!prerender::PrerenderManager::IsValidHttpMethod(request_->method()) &&
42       tracker_->TryCancelOnIOThread(
43           child_id, route_id, prerender::FINAL_STATUS_INVALID_HTTP_METHOD)) {
44     controller()->Cancel();
45     return;
46   }
47   if (!prerender::PrerenderManager::DoesSubresourceURLHaveValidScheme(
48           request_->url()) &&
49       tracker_->TryCancelOnIOThread(
50           child_id, route_id, prerender::FINAL_STATUS_UNSUPPORTED_SCHEME)) {
51     ReportUnsupportedPrerenderScheme(request_->url());
52     controller()->Cancel();
53     return;
54   }
55 }
56 
WillRedirectRequest(const GURL & new_url,bool * defer)57 void PrerenderResourceThrottle::WillRedirectRequest(const GURL& new_url,
58                                                     bool* defer) {
59   DCHECK(!throttled_);
60 
61   const content::ResourceRequestInfo* info =
62       content::ResourceRequestInfo::ForRequest(request_);
63   int child_id = info->GetChildID();
64   int route_id = info->GetRouteID();
65 
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;
70 
71   // Abort any prerenders with requests which redirect to invalid schemes.
72   if (!prerender::PrerenderManager::DoesURLHaveValidScheme(new_url) &&
73       tracker_->TryCancel(
74           child_id, route_id, prerender::FINAL_STATUS_UNSUPPORTED_SCHEME)) {
75     ReportUnsupportedPrerenderScheme(new_url);
76     controller()->Cancel();
77     return;
78   }
79 
80   // Only defer redirects with the Follow-Only-When-Prerender-Shown
81   // header.
82   std::string header;
83   request_->GetResponseHeaderByName(kFollowOnlyWhenPrerenderShown, &header);
84   if (header != "1")
85     return;
86 
87   // Do not defer redirects on main frame loads.
88   if (info->GetResourceType() == ResourceType::MAIN_FRAME)
89     return;
90 
91   if (!info->IsAsync()) {
92     // Cancel on deferred synchronous requests. Those will
93     // indefinitely hang up a renderer process.
94     //
95     // If the TryCancelOnIOThread fails, the UI thread won a race to
96     // use the prerender, so let the request through.
97     if (tracker_->TryCancelOnIOThread(child_id, route_id,
98                                       FINAL_STATUS_BAD_DEFERRED_REDIRECT)) {
99       controller()->Cancel();
100     }
101     return;
102   }
103 
104   // Defer the redirect until the prerender is used or
105   // canceled. It is possible for the UI thread to used the
106   // prerender at the same time. But then |tracker_| will resume
107   // the request soon in
108   // PrerenderTracker::RemovePrerenderOnIOThread.
109   *defer = true;
110   throttled_ = true;
111   tracker_->AddResourceThrottleOnIOThread(child_id, route_id,
112                                           this->AsWeakPtr());
113 }
114 
GetNameForLogging() const115 const char* PrerenderResourceThrottle::GetNameForLogging() const {
116   return "PrerenderResourceThrottle";
117 }
118 
Resume()119 void PrerenderResourceThrottle::Resume() {
120   DCHECK(throttled_);
121 
122   throttled_ = false;
123   controller()->Resume();
124 }
125 
Cancel()126 void PrerenderResourceThrottle::Cancel() {
127   DCHECK(throttled_);
128 
129   throttled_ = false;
130   controller()->Cancel();
131 }
132 
133 }  // namespace prerender
134