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_process_host.h"
11 #include "content/public/browser/render_view_host.h"
12 #include "content/public/browser/resource_controller.h"
13 #include "content/public/browser/resource_request_info.h"
14 #include "content/public/common/page_transition_types.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
19 using content::BrowserThread;
20 using content::ChildProcessSecurityPolicy;
21 using content::PageTransition;
22 using content::Referrer;
23 using content::RenderViewHost;
24 using content::ResourceRequestInfo;
25
26 namespace navigation_interception {
27
28 namespace {
29
CheckIfShouldIgnoreNavigationOnUIThread(int render_process_id,int render_view_id,const NavigationParams & navigation_params,InterceptNavigationResourceThrottle::CheckOnUIThreadCallback should_ignore_callback,base::Callback<void (bool)> callback)30 void CheckIfShouldIgnoreNavigationOnUIThread(
31 int render_process_id,
32 int render_view_id,
33 const NavigationParams& navigation_params,
34 InterceptNavigationResourceThrottle::CheckOnUIThreadCallback
35 should_ignore_callback,
36 base::Callback<void(bool)> callback) {
37
38 bool should_ignore_navigation = false;
39 RenderViewHost* rvh =
40 RenderViewHost::FromID(render_process_id, render_view_id);
41
42 if (rvh) {
43 NavigationParams validated_params(navigation_params);
44 RenderViewHost::FilterURL(
45 rvh->GetProcess(), false, &validated_params.url());
46
47 should_ignore_navigation = should_ignore_callback.Run(rvh,
48 validated_params);
49 }
50
51 BrowserThread::PostTask(
52 BrowserThread::IO,
53 FROM_HERE,
54 base::Bind(callback, should_ignore_navigation));
55 }
56
57 } // namespace
58
InterceptNavigationResourceThrottle(net::URLRequest * request,CheckOnUIThreadCallback should_ignore_callback)59 InterceptNavigationResourceThrottle::InterceptNavigationResourceThrottle(
60 net::URLRequest* request,
61 CheckOnUIThreadCallback should_ignore_callback)
62 : request_(request),
63 should_ignore_callback_(should_ignore_callback),
64 weak_ptr_factory_(this) {
65 }
66
~InterceptNavigationResourceThrottle()67 InterceptNavigationResourceThrottle::~InterceptNavigationResourceThrottle() {
68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
69 }
70
WillStartRequest(bool * defer)71 void InterceptNavigationResourceThrottle::WillStartRequest(bool* defer) {
72 *defer =
73 CheckIfShouldIgnoreNavigation(request_->url(), request_->method(), false);
74 }
75
WillRedirectRequest(const GURL & new_url,bool * defer)76 void InterceptNavigationResourceThrottle::WillRedirectRequest(
77 const GURL& new_url,
78 bool* defer) {
79 *defer =
80 CheckIfShouldIgnoreNavigation(new_url, GetMethodAfterRedirect(), true);
81 }
82
GetNameForLogging() const83 const char* InterceptNavigationResourceThrottle::GetNameForLogging() const {
84 return "InterceptNavigationResourceThrottle";
85 }
86
GetMethodAfterRedirect()87 std::string InterceptNavigationResourceThrottle::GetMethodAfterRedirect() {
88 net::HttpResponseHeaders* headers = request_->response_headers();
89 if (!headers)
90 return request_->method();
91 return net::URLRequest::ComputeMethodForRedirect(
92 request_->method(), headers->response_code());
93 }
94
CheckIfShouldIgnoreNavigation(const GURL & url,const std::string & method,bool is_redirect)95 bool InterceptNavigationResourceThrottle::CheckIfShouldIgnoreNavigation(
96 const GURL& url,
97 const std::string& method,
98 bool is_redirect) {
99 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_);
100 if (!info)
101 return false;
102
103 int render_process_id, render_view_id;
104 if (!info->GetAssociatedRenderView(&render_process_id, &render_view_id))
105 return false;
106
107 NavigationParams navigation_params(url,
108 Referrer(GURL(request_->referrer()),
109 info->GetReferrerPolicy()),
110 info->HasUserGesture(),
111 method == "POST",
112 info->GetPageTransition(),
113 is_redirect);
114
115 BrowserThread::PostTask(
116 BrowserThread::UI,
117 FROM_HERE,
118 base::Bind(
119 &CheckIfShouldIgnoreNavigationOnUIThread,
120 render_process_id,
121 render_view_id,
122 navigation_params,
123 should_ignore_callback_,
124 base::Bind(
125 &InterceptNavigationResourceThrottle::OnResultObtained,
126 weak_ptr_factory_.GetWeakPtr())));
127
128 // Defer request while we wait for the UI thread to check if the navigation
129 // should be ignored.
130 return true;
131 }
132
OnResultObtained(bool should_ignore_navigation)133 void InterceptNavigationResourceThrottle::OnResultObtained(
134 bool should_ignore_navigation) {
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
136
137 if (should_ignore_navigation) {
138 controller()->CancelAndIgnore();
139 } else {
140 controller()->Resume();
141 }
142 }
143
144 } // namespace navigation_interception
145