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 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 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 67 InterceptNavigationResourceThrottle::~InterceptNavigationResourceThrottle() { 68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 69 } 70 71 void InterceptNavigationResourceThrottle::WillStartRequest(bool* defer) { 72 *defer = 73 CheckIfShouldIgnoreNavigation(request_->url(), request_->method(), false); 74 } 75 76 void InterceptNavigationResourceThrottle::WillRedirectRequest( 77 const GURL& new_url, 78 bool* defer) { 79 *defer = 80 CheckIfShouldIgnoreNavigation(new_url, GetMethodAfterRedirect(), true); 81 } 82 83 std::string InterceptNavigationResourceThrottle::GetMethodAfterRedirect() { 84 net::HttpResponseHeaders* headers = request_->response_headers(); 85 if (!headers) 86 return request_->method(); 87 return net::URLRequest::ComputeMethodForRedirect( 88 request_->method(), headers->response_code()); 89 } 90 91 bool InterceptNavigationResourceThrottle::CheckIfShouldIgnoreNavigation( 92 const GURL& url, 93 const std::string& method, 94 bool is_redirect) { 95 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); 96 if (!info) 97 return false; 98 99 int render_process_id, render_view_id; 100 if (!info->GetAssociatedRenderView(&render_process_id, &render_view_id)) 101 return false; 102 103 NavigationParams navigation_params(url, 104 Referrer(GURL(request_->referrer()), 105 info->GetReferrerPolicy()), 106 info->HasUserGesture(), 107 method == "POST", 108 info->GetPageTransition(), 109 is_redirect); 110 111 BrowserThread::PostTask( 112 BrowserThread::UI, 113 FROM_HERE, 114 base::Bind( 115 &CheckIfShouldIgnoreNavigationOnUIThread, 116 render_process_id, 117 render_view_id, 118 navigation_params, 119 should_ignore_callback_, 120 base::Bind( 121 &InterceptNavigationResourceThrottle::OnResultObtained, 122 weak_ptr_factory_.GetWeakPtr()))); 123 124 // Defer request while we wait for the UI thread to check if the navigation 125 // should be ignored. 126 return true; 127 } 128 129 void InterceptNavigationResourceThrottle::OnResultObtained( 130 bool should_ignore_navigation) { 131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 132 133 if (should_ignore_navigation) { 134 controller()->CancelAndIgnore(); 135 } else { 136 controller()->Resume(); 137 } 138 } 139 140 } // namespace navigation_interception 141