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 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 // 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 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 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