• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 "components/navigation_interception/intercept_navigation_resource_throttle.h"
6 
7 #include "components/navigation_interception/navigation_params.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "content/public/browser/child_process_security_policy.h"
10 #include "content/public/browser/render_frame_host.h"
11 #include "content/public/browser/render_process_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 "content/public/common/referrer.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/url_request/url_request.h"
18 #include "ui/base/page_transition_types.h"
19 
20 using content::BrowserThread;
21 using content::ChildProcessSecurityPolicy;
22 using ui::PageTransition;
23 using content::Referrer;
24 using content::RenderProcessHost;
25 using content::ResourceRequestInfo;
26 
27 namespace navigation_interception {
28 
29 namespace {
30 
CheckIfShouldIgnoreNavigationOnUIThread(int render_process_id,int render_frame_id,const NavigationParams & navigation_params,InterceptNavigationResourceThrottle::CheckOnUIThreadCallback should_ignore_callback,base::Callback<void (bool)> callback)31 void CheckIfShouldIgnoreNavigationOnUIThread(
32     int render_process_id,
33     int render_frame_id,
34     const NavigationParams& navigation_params,
35     InterceptNavigationResourceThrottle::CheckOnUIThreadCallback
36     should_ignore_callback,
37     base::Callback<void(bool)> callback) {
38   bool should_ignore_navigation = false;
39   RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id);
40   if (rph) {
41     NavigationParams validated_params(navigation_params);
42     rph->FilterURL(false, &validated_params.url());
43 
44     content::RenderFrameHost* render_frame_host =
45         content::RenderFrameHost::FromID(render_process_id, render_frame_id);
46     content::WebContents* web_contents =
47         content::WebContents::FromRenderFrameHost(render_frame_host);
48 
49     if (web_contents) {
50       should_ignore_navigation = should_ignore_callback.Run(web_contents,
51                                                             validated_params);
52     }
53   }
54 
55   BrowserThread::PostTask(
56       BrowserThread::IO,
57       FROM_HERE,
58       base::Bind(callback, should_ignore_navigation));
59 }
60 
61 } // namespace
62 
InterceptNavigationResourceThrottle(net::URLRequest * request,CheckOnUIThreadCallback should_ignore_callback)63 InterceptNavigationResourceThrottle::InterceptNavigationResourceThrottle(
64     net::URLRequest* request,
65     CheckOnUIThreadCallback should_ignore_callback)
66     : request_(request),
67       should_ignore_callback_(should_ignore_callback),
68       weak_ptr_factory_(this) {
69 }
70 
~InterceptNavigationResourceThrottle()71 InterceptNavigationResourceThrottle::~InterceptNavigationResourceThrottle() {
72   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
73 }
74 
WillStartRequest(bool * defer)75 void InterceptNavigationResourceThrottle::WillStartRequest(bool* defer) {
76   *defer =
77       CheckIfShouldIgnoreNavigation(request_->url(), request_->method(), false);
78 }
79 
WillRedirectRequest(const GURL & new_url,bool * defer)80 void InterceptNavigationResourceThrottle::WillRedirectRequest(
81     const GURL& new_url,
82     bool* defer) {
83   *defer =
84       CheckIfShouldIgnoreNavigation(new_url, GetMethodAfterRedirect(), true);
85 }
86 
GetNameForLogging() const87 const char* InterceptNavigationResourceThrottle::GetNameForLogging() const {
88   return "InterceptNavigationResourceThrottle";
89 }
90 
GetMethodAfterRedirect()91 std::string InterceptNavigationResourceThrottle::GetMethodAfterRedirect() {
92   net::HttpResponseHeaders* headers = request_->response_headers();
93   if (!headers)
94     return request_->method();
95   // TODO(davidben): Plumb net::RedirectInfo through content::ResourceThrottle
96   // and unexpose net::URLRequest::ComputeMethodForRedirect.
97   return net::URLRequest::ComputeMethodForRedirect(
98              request_->method(), headers->response_code());
99 }
100 
CheckIfShouldIgnoreNavigation(const GURL & url,const std::string & method,bool is_redirect)101 bool InterceptNavigationResourceThrottle::CheckIfShouldIgnoreNavigation(
102     const GURL& url,
103     const std::string& method,
104     bool is_redirect) {
105   const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_);
106   if (!info)
107     return false;
108 
109   int render_process_id, render_frame_id;
110   if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
111     return false;
112 
113   NavigationParams navigation_params(url,
114                                      Referrer(GURL(request_->referrer()),
115                                               info->GetReferrerPolicy()),
116                                      info->HasUserGesture(),
117                                      method == "POST",
118                                      info->GetPageTransition(),
119                                      is_redirect);
120 
121   BrowserThread::PostTask(
122       BrowserThread::UI,
123       FROM_HERE,
124       base::Bind(
125           &CheckIfShouldIgnoreNavigationOnUIThread,
126           render_process_id,
127           render_frame_id,
128           navigation_params,
129           should_ignore_callback_,
130           base::Bind(
131               &InterceptNavigationResourceThrottle::OnResultObtained,
132               weak_ptr_factory_.GetWeakPtr())));
133 
134   // Defer request while we wait for the UI thread to check if the navigation
135   // should be ignored.
136   return true;
137 }
138 
OnResultObtained(bool should_ignore_navigation)139 void InterceptNavigationResourceThrottle::OnResultObtained(
140     bool should_ignore_navigation) {
141   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
142 
143   if (should_ignore_navigation) {
144     controller()->CancelAndIgnore();
145   } else {
146     controller()->Resume();
147   }
148 }
149 
150 }  // namespace navigation_interception
151