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/page_transition_types.h" 16 #include "content/public/common/referrer.h" 17 #include "net/http/http_response_headers.h" 18 #include "net/url_request/url_request.h" 19 20 using content::BrowserThread; 21 using content::ChildProcessSecurityPolicy; 22 using content::PageTransition; 23 using content::Referrer; 24 using content::RenderProcessHost; 25 using content::ResourceRequestInfo; 26 27 namespace navigation_interception { 28 29 namespace { 30 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 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 71 InterceptNavigationResourceThrottle::~InterceptNavigationResourceThrottle() { 72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 73 } 74 75 void InterceptNavigationResourceThrottle::WillStartRequest(bool* defer) { 76 *defer = 77 CheckIfShouldIgnoreNavigation(request_->url(), request_->method(), false); 78 } 79 80 void InterceptNavigationResourceThrottle::WillRedirectRequest( 81 const GURL& new_url, 82 bool* defer) { 83 *defer = 84 CheckIfShouldIgnoreNavigation(new_url, GetMethodAfterRedirect(), true); 85 } 86 87 const char* InterceptNavigationResourceThrottle::GetNameForLogging() const { 88 return "InterceptNavigationResourceThrottle"; 89 } 90 91 std::string InterceptNavigationResourceThrottle::GetMethodAfterRedirect() { 92 net::HttpResponseHeaders* headers = request_->response_headers(); 93 if (!headers) 94 return request_->method(); 95 return net::URLRequest::ComputeMethodForRedirect( 96 request_->method(), headers->response_code()); 97 } 98 99 bool InterceptNavigationResourceThrottle::CheckIfShouldIgnoreNavigation( 100 const GURL& url, 101 const std::string& method, 102 bool is_redirect) { 103 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); 104 if (!info) 105 return false; 106 107 int render_process_id, render_frame_id; 108 if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id)) 109 return false; 110 111 NavigationParams navigation_params(url, 112 Referrer(GURL(request_->referrer()), 113 info->GetReferrerPolicy()), 114 info->HasUserGesture(), 115 method == "POST", 116 info->GetPageTransition(), 117 is_redirect); 118 119 BrowserThread::PostTask( 120 BrowserThread::UI, 121 FROM_HERE, 122 base::Bind( 123 &CheckIfShouldIgnoreNavigationOnUIThread, 124 render_process_id, 125 render_frame_id, 126 navigation_params, 127 should_ignore_callback_, 128 base::Bind( 129 &InterceptNavigationResourceThrottle::OnResultObtained, 130 weak_ptr_factory_.GetWeakPtr()))); 131 132 // Defer request while we wait for the UI thread to check if the navigation 133 // should be ignored. 134 return true; 135 } 136 137 void InterceptNavigationResourceThrottle::OnResultObtained( 138 bool should_ignore_navigation) { 139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 140 141 if (should_ignore_navigation) { 142 controller()->CancelAndIgnore(); 143 } else { 144 controller()->Resume(); 145 } 146 } 147 148 } // namespace navigation_interception 149