Home | History | Annotate | Download | only in navigation_interception
      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