Home | History | Annotate | Download | only in ssl
      1 // Copyright (c) 2010 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 "chrome/browser/ssl/ssl_error_handler.h"
      6 
      7 #include "chrome/browser/ssl/ssl_cert_error_handler.h"
      8 #include "chrome/browser/tab_contents/tab_util.h"
      9 #include "content/browser/browser_thread.h"
     10 #include "content/browser/renderer_host/resource_dispatcher_host.h"
     11 #include "content/browser/renderer_host/resource_dispatcher_host_request_info.h"
     12 #include "content/browser/tab_contents/tab_contents.h"
     13 #include "net/base/net_errors.h"
     14 #include "net/url_request/url_request.h"
     15 
     16 SSLErrorHandler::SSLErrorHandler(ResourceDispatcherHost* rdh,
     17                                  net::URLRequest* request,
     18                                  ResourceType::Type resource_type)
     19     : manager_(NULL),
     20       request_id_(0, 0),
     21       resource_dispatcher_host_(rdh),
     22       request_url_(request->url()),
     23       resource_type_(resource_type),
     24       request_has_been_notified_(false) {
     25   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
     26 
     27   ResourceDispatcherHostRequestInfo* info =
     28       ResourceDispatcherHost::InfoForRequest(request);
     29   request_id_.child_id = info->child_id();
     30   request_id_.request_id = info->request_id();
     31 
     32   if (!ResourceDispatcherHost::RenderViewForRequest(request,
     33                                                     &render_process_host_id_,
     34                                                     &tab_contents_id_))
     35     NOTREACHED();
     36 
     37   // This makes sure we don't disappear on the IO thread until we've given an
     38   // answer to the net::URLRequest.
     39   //
     40   // Release in CompleteCancelRequest, CompleteContinueRequest, or
     41   // CompleteTakeNoAction.
     42   AddRef();
     43 }
     44 
     45 SSLErrorHandler::~SSLErrorHandler() {}
     46 
     47 void SSLErrorHandler::OnDispatchFailed() {
     48   TakeNoAction();
     49 }
     50 
     51 void SSLErrorHandler::OnDispatched() {
     52   TakeNoAction();
     53 }
     54 
     55 SSLCertErrorHandler* SSLErrorHandler::AsSSLCertErrorHandler() {
     56   return NULL;
     57 }
     58 
     59 void SSLErrorHandler::Dispatch() {
     60   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     61 
     62   TabContents* tab_contents = GetTabContents();
     63   if (!tab_contents) {
     64     // We arrived on the UI thread, but the tab we're looking for is no longer
     65     // here.
     66     OnDispatchFailed();
     67     return;
     68   }
     69 
     70   // Hand ourselves off to the SSLManager.
     71   manager_ = tab_contents->controller().ssl_manager();
     72   OnDispatched();
     73 }
     74 
     75 TabContents* SSLErrorHandler::GetTabContents() {
     76   return tab_util::GetTabContentsByID(render_process_host_id_,
     77                                       tab_contents_id_);
     78 }
     79 
     80 void SSLErrorHandler::CancelRequest() {
     81   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     82 
     83   // We need to complete this task on the IO thread.
     84   BrowserThread::PostTask(
     85       BrowserThread::IO, FROM_HERE,
     86       NewRunnableMethod(
     87           this, &SSLErrorHandler::CompleteCancelRequest, net::ERR_ABORTED));
     88 }
     89 
     90 void SSLErrorHandler::DenyRequest() {
     91   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     92 
     93   // We need to complete this task on the IO thread.
     94   BrowserThread::PostTask(
     95       BrowserThread::IO, FROM_HERE,
     96       NewRunnableMethod(
     97           this, &SSLErrorHandler::CompleteCancelRequest,
     98           net::ERR_INSECURE_RESPONSE));
     99 }
    100 
    101 void SSLErrorHandler::ContinueRequest() {
    102   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    103 
    104   // We need to complete this task on the IO thread.
    105   BrowserThread::PostTask(
    106       BrowserThread::IO, FROM_HERE,
    107       NewRunnableMethod(this, &SSLErrorHandler::CompleteContinueRequest));
    108 }
    109 
    110 void SSLErrorHandler::TakeNoAction() {
    111   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    112 
    113   // We need to complete this task on the IO thread.
    114   BrowserThread::PostTask(
    115       BrowserThread::IO, FROM_HERE,
    116       NewRunnableMethod(this, &SSLErrorHandler::CompleteTakeNoAction));
    117 }
    118 
    119 void SSLErrorHandler::CompleteCancelRequest(int error) {
    120   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    121 
    122   // It is important that we notify the net::URLRequest only once.  If we try
    123   // to notify the request twice, it may no longer exist and |this| might have
    124   // already have been deleted.
    125   DCHECK(!request_has_been_notified_);
    126   if (request_has_been_notified_)
    127     return;
    128 
    129   net::URLRequest* request =
    130       resource_dispatcher_host_->GetURLRequest(request_id_);
    131   if (request) {
    132     // The request can be NULL if it was cancelled by the renderer (as the
    133     // result of the user navigating to a new page from the location bar).
    134     DVLOG(1) << "CompleteCancelRequest() url: " << request->url().spec();
    135     SSLCertErrorHandler* cert_error = AsSSLCertErrorHandler();
    136     if (cert_error)
    137       request->SimulateSSLError(error, cert_error->ssl_info());
    138     else
    139       request->SimulateError(error);
    140   }
    141   request_has_been_notified_ = true;
    142 
    143   // We're done with this object on the IO thread.
    144   Release();
    145 }
    146 
    147 void SSLErrorHandler::CompleteContinueRequest() {
    148   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    149 
    150   // It is important that we notify the net::URLRequest only once. If we try to
    151   // notify the request twice, it may no longer exist and |this| might have
    152   // already have been deleted.
    153   DCHECK(!request_has_been_notified_);
    154   if (request_has_been_notified_)
    155     return;
    156 
    157   net::URLRequest* request =
    158       resource_dispatcher_host_->GetURLRequest(request_id_);
    159   if (request) {
    160     // The request can be NULL if it was cancelled by the renderer (as the
    161     // result of the user navigating to a new page from the location bar).
    162     DVLOG(1) << "CompleteContinueRequest() url: " << request->url().spec();
    163     request->ContinueDespiteLastError();
    164   }
    165   request_has_been_notified_ = true;
    166 
    167   // We're done with this object on the IO thread.
    168   Release();
    169 }
    170 
    171 void SSLErrorHandler::CompleteTakeNoAction() {
    172   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    173 
    174   // It is important that we notify the net::URLRequest only once. If we try to
    175   // notify the request twice, it may no longer exist and |this| might have
    176   // already have been deleted.
    177   DCHECK(!request_has_been_notified_);
    178   if (request_has_been_notified_)
    179     return;
    180 
    181   request_has_been_notified_ = true;
    182 
    183   // We're done with this object on the IO thread.
    184   Release();
    185 }
    186