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 "content/browser/ssl/ssl_error_handler.h"
6
7#include "base/bind.h"
8#include "content/browser/frame_host/navigation_controller_impl.h"
9#include "content/browser/frame_host/render_frame_host_impl.h"
10#include "content/browser/ssl/ssl_cert_error_handler.h"
11#include "content/browser/web_contents/web_contents_impl.h"
12#include "content/public/browser/browser_thread.h"
13#include "content/public/browser/resource_request_info.h"
14#include "net/base/net_errors.h"
15#include "net/url_request/url_request.h"
16
17using net::SSLInfo;
18
19namespace content {
20
21SSLErrorHandler::SSLErrorHandler(const base::WeakPtr<Delegate>& delegate,
22                                 const GlobalRequestID& id,
23                                 ResourceType resource_type,
24                                 const GURL& url,
25                                 int render_process_id,
26                                 int render_frame_id)
27    : manager_(NULL),
28      request_id_(id),
29      delegate_(delegate),
30      render_process_id_(render_process_id),
31      render_frame_id_(render_frame_id),
32      request_url_(url),
33      resource_type_(resource_type),
34      request_has_been_notified_(false) {
35  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
36  DCHECK(delegate.get());
37
38  // This makes sure we don't disappear on the IO thread until we've given an
39  // answer to the net::URLRequest.
40  //
41  // Release in CompleteCancelRequest, CompleteContinueRequest, or
42  // CompleteTakeNoAction.
43  AddRef();
44}
45
46SSLErrorHandler::~SSLErrorHandler() {}
47
48void SSLErrorHandler::OnDispatchFailed() {
49  TakeNoAction();
50}
51
52void SSLErrorHandler::OnDispatched() {
53  TakeNoAction();
54}
55
56SSLCertErrorHandler* SSLErrorHandler::AsSSLCertErrorHandler() {
57  return NULL;
58}
59
60void SSLErrorHandler::Dispatch() {
61  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
62
63  WebContents* web_contents = NULL;
64  RenderFrameHost* render_frame_host =
65      RenderFrameHost::FromID(render_process_id_, render_frame_id_);
66  web_contents = WebContents::FromRenderFrameHost(render_frame_host);
67
68  if (!web_contents) {
69    // We arrived on the UI thread, but the tab we're looking for is no longer
70    // here.
71    OnDispatchFailed();
72    return;
73  }
74
75  // Hand ourselves off to the SSLManager.
76  manager_ =
77      static_cast<NavigationControllerImpl*>(&web_contents->GetController())->
78          ssl_manager();
79  OnDispatched();
80}
81
82void SSLErrorHandler::CancelRequest() {
83  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
84
85  // We need to complete this task on the IO thread.
86  BrowserThread::PostTask(
87      BrowserThread::IO, FROM_HERE,
88      base::Bind(
89          &SSLErrorHandler::CompleteCancelRequest, this, net::ERR_ABORTED));
90}
91
92void SSLErrorHandler::DenyRequest() {
93  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
94
95  // We need to complete this task on the IO thread.
96  BrowserThread::PostTask(
97      BrowserThread::IO, FROM_HERE,
98      base::Bind(
99          &SSLErrorHandler::CompleteCancelRequest, this,
100          net::ERR_INSECURE_RESPONSE));
101}
102
103void SSLErrorHandler::ContinueRequest() {
104  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
105
106  // We need to complete this task on the IO thread.
107  BrowserThread::PostTask(
108      BrowserThread::IO, FROM_HERE,
109      base::Bind(&SSLErrorHandler::CompleteContinueRequest, this));
110}
111
112void SSLErrorHandler::TakeNoAction() {
113  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
114
115  // We need to complete this task on the IO thread.
116  BrowserThread::PostTask(
117      BrowserThread::IO, FROM_HERE,
118      base::Bind(&SSLErrorHandler::CompleteTakeNoAction, this));
119}
120
121void SSLErrorHandler::CompleteCancelRequest(int error) {
122  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
123
124  // It is important that we notify the net::URLRequest only once.  If we try
125  // to notify the request twice, it may no longer exist and |this| might have
126  // already have been deleted.
127  DCHECK(!request_has_been_notified_);
128  if (request_has_been_notified_)
129    return;
130
131  SSLCertErrorHandler* cert_error = AsSSLCertErrorHandler();
132  const SSLInfo* ssl_info = NULL;
133  if (cert_error)
134    ssl_info = &cert_error->ssl_info();
135  if (delegate_.get())
136    delegate_->CancelSSLRequest(request_id_, error, ssl_info);
137  request_has_been_notified_ = true;
138
139  // We're done with this object on the IO thread.
140  Release();
141}
142
143void SSLErrorHandler::CompleteContinueRequest() {
144  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
145
146  // It is important that we notify the net::URLRequest only once. If we try to
147  // notify the request twice, it may no longer exist and |this| might have
148  // already have been deleted.
149  DCHECK(!request_has_been_notified_);
150  if (request_has_been_notified_)
151    return;
152
153  if (delegate_.get())
154    delegate_->ContinueSSLRequest(request_id_);
155  request_has_been_notified_ = true;
156
157  // We're done with this object on the IO thread.
158  Release();
159}
160
161void SSLErrorHandler::CompleteTakeNoAction() {
162  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
163
164  // It is important that we notify the net::URLRequest only once. If we try to
165  // notify the request twice, it may no longer exist and |this| might have
166  // already have been deleted.
167  DCHECK(!request_has_been_notified_);
168  if (request_has_been_notified_)
169    return;
170
171  request_has_been_notified_ = true;
172
173  // We're done with this object on the IO thread.
174  Release();
175}
176
177}  // namespace content
178