summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ssl_manager.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/ssl_manager.cc
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/ssl_manager.cc')
-rw-r--r--chrome/browser/ssl_manager.cc780
1 files changed, 780 insertions, 0 deletions
diff --git a/chrome/browser/ssl_manager.cc b/chrome/browser/ssl_manager.cc
new file mode 100644
index 0000000..c15436d
--- /dev/null
+++ b/chrome/browser/ssl_manager.cc
@@ -0,0 +1,780 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/ssl_manager.h"
+
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "chrome/app/theme/theme_resources.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/provisional_load_details.h"
+#include "chrome/browser/load_notification_details.h"
+#include "chrome/browser/load_from_memory_cache_details.h"
+#include "chrome/browser/navigation_controller.h"
+#include "chrome/browser/navigation_entry.h"
+#include "chrome/browser/render_view_host.h"
+#include "chrome/browser/resource_request_details.h"
+#include "chrome/browser/ssl_error_info.h"
+#include "chrome/browser/ssl_policy.h"
+#include "chrome/browser/standard_layout.h"
+#include "chrome/browser/tab_contents.h"
+#include "chrome/browser/tab_util.h"
+#include "chrome/browser/web_contents.h"
+#include "chrome/browser/views/info_bar_view.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/pref_service.h"
+#include "chrome/common/resource_bundle.h"
+#include "chrome/views/decision.h"
+#include "chrome/views/link.h"
+#include "net/base/cert_status_flags.h"
+#include "net/base/net_errors.h"
+#include "net/url_request/url_request.h"
+#include "webkit/glue/resource_type.h"
+#include "generated_resources.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// SSLInfoBar
+//
+// An info bar with a message and an optional link that runs a task when
+// clicked.
+
+class SSLInfoBar : public InfoBarItemView,
+ public ChromeViews::LinkController {
+ public:
+ SSLInfoBar::SSLInfoBar(SSLManager* manager,
+ const std::wstring& message,
+ const std::wstring& link_text,
+ Task* task);
+
+ virtual SSLInfoBar::~SSLInfoBar();
+
+ const std::wstring GetMessageText() const;
+
+ // ChromeViews::LinkController method.
+ virtual void LinkActivated(ChromeViews::Link* source, int event_flags);
+
+ private:
+ ChromeViews::Label* label_;
+ ChromeViews::Link* link_;
+ SSLManager* manager_;
+ scoped_ptr<Task> task_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(SSLInfoBar);
+};
+
+SSLInfoBar::SSLInfoBar(SSLManager* manager,
+ const std::wstring& message,
+ const std::wstring& link_text,
+ Task* task)
+ : label_(NULL),
+ link_(NULL),
+ manager_(manager),
+ task_(task) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ if (!message.empty()) {
+ label_ = new ChromeViews::Label(message);
+ label_->SetFont(rb.GetFont(ResourceBundle::MediumFont));
+ label_->SetHorizontalAlignment(ChromeViews::Label::ALIGN_LEFT);
+ AddChildViewLeading(label_);
+ }
+
+ if (!link_text.empty()) {
+ DCHECK(task) << L"Link and no task"; // What do you want to do when users
+ // click the link??
+ link_ = new ChromeViews::Link(link_text);
+ link_->SetFont(rb.GetFont(ResourceBundle::MediumFont));
+ link_->SetController(this);
+ AddChildViewTrailing(link_);
+ }
+
+ SetIcon(*rb.GetBitmapNamed(IDR_INFOBAR_SSL_WARNING));
+ DCHECK(manager);
+}
+
+SSLInfoBar::~SSLInfoBar() {
+ // Notify our manager that we no longer exist.
+ manager_->OnInfoBarClose(this);
+}
+
+const std::wstring SSLInfoBar::GetMessageText() const {
+ if (!label_)
+ return std::wstring();
+
+ return label_->GetText();
+}
+
+void SSLInfoBar::LinkActivated(ChromeViews::Link* source, int event_flags) {
+ if (task_.get()) {
+ task_->Run();
+ task_.reset(); // Ensures we won't run the task again.
+ }
+ Close();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// SSLManager
+
+// static
+void SSLManager::RegisterUserPrefs(PrefService* prefs) {
+ prefs->RegisterIntegerPref(prefs::kMixedContentFiltering,
+ FilterPolicy::DONT_FILTER);
+}
+
+SSLManager::SSLManager(NavigationController* controller, Delegate* delegate)
+ : controller_(controller),
+ delegate_(delegate) {
+ DCHECK(controller_);
+
+ // If do delegate is supplied, use the default policy.
+ if (!delegate_)
+ delegate_ = SSLPolicy::GetDefaultPolicy();
+
+ // Subscribe to various notifications.
+ NotificationService* service = NotificationService::current();
+ service->AddObserver(this, NOTIFY_FRAME_PROVISIONAL_LOAD_COMMITTED,
+ Source<NavigationController>(controller_));
+ service->AddObserver(this, NOTIFY_FAIL_PROVISIONAL_LOAD_WITH_ERROR,
+ Source<NavigationController>(controller_));
+ service->AddObserver(this, NOTIFY_RESOURCE_RESPONSE_STARTED,
+ Source<NavigationController>(controller_));
+ service->AddObserver(this, NOTIFY_RESOURCE_RECEIVED_REDIRECT,
+ Source<NavigationController>(controller_));
+ service->AddObserver(this, NOTIFY_LOAD_FROM_MEMORY_CACHE,
+ Source<NavigationController>(controller_));
+}
+
+SSLManager::~SSLManager() {
+ // Close any of our info bars that are still left.
+ FOR_EACH_OBSERVER(SSLInfoBar, visible_info_bars_, Close());
+
+ // Unsubscribe from various notifications.
+ NotificationService* service = NotificationService::current();
+ service->RemoveObserver(this, NOTIFY_FRAME_PROVISIONAL_LOAD_COMMITTED,
+ Source<NavigationController>(controller_));
+ service->RemoveObserver(this, NOTIFY_FAIL_PROVISIONAL_LOAD_WITH_ERROR,
+ Source<NavigationController>(controller_));
+ service->RemoveObserver(this, NOTIFY_RESOURCE_RESPONSE_STARTED,
+ Source<NavigationController>(controller_));
+ service->RemoveObserver(this, NOTIFY_RESOURCE_RECEIVED_REDIRECT,
+ Source<NavigationController>(controller_));
+ service->RemoveObserver(this, NOTIFY_LOAD_FROM_MEMORY_CACHE,
+ Source<NavigationController>(controller_));
+}
+
+// Delegate API method.
+void SSLManager::ShowMessage(const std::wstring& msg) {
+ ShowMessageWithLink(msg, std::wstring(), NULL);
+}
+
+void SSLManager::ShowMessageWithLink(const std::wstring& msg,
+ const std::wstring& link_text,
+ Task* task) {
+ if (controller_->GetPendingEntry()) {
+ // The main frame is currently loading, wait until the load is committed so
+ // to show the error on the right page (once the location bar shows the
+ // correct url).
+ if (std::find(pending_messages_.begin(), pending_messages_.end(), msg) ==
+ pending_messages_.end())
+ pending_messages_.push_back(SSLMessageInfo(msg, link_text, task));
+
+ return;
+ }
+
+ NavigationEntry* entry = controller_->GetActiveEntry();
+ if (!entry)
+ return;
+
+ // Don't show the message if the user doesn't expect an authenticated session.
+ if (entry->GetSecurityStyle() <= SECURITY_STYLE_UNAUTHENTICATED)
+ return;
+
+ InfoBarView* info_bar_view =
+ controller_->active_contents()->GetInfoBarView();
+ DCHECK(info_bar_view);
+
+ if (!info_bar_view)
+ return;
+
+ // Check if we are already displaying this message.
+ ObserverList<SSLInfoBar>::Iterator it(visible_info_bars_);
+ SSLInfoBar* info_bar;
+ while (info_bar = it.GetNext()) {
+ if (info_bar->GetMessageText() == msg)
+ return;
+ }
+
+ // Show the message.
+ info_bar = new SSLInfoBar(this, msg, link_text, task);
+ visible_info_bars_.AddObserver(info_bar);
+
+ // false indicates info_bar is not automatically removed.
+ info_bar_view->AppendInfoBarItem(info_bar, false);
+}
+
+// Delegate API method.
+void SSLManager::SetMaxSecurityStyle(SecurityStyle style) {
+ NavigationEntry* entry = controller_->GetActiveEntry();
+ if (!entry) {
+ NOTREACHED();
+ return;
+ }
+
+ if (entry->GetSecurityStyle() > style) {
+ entry->SetSecurityStyle(style);
+ controller_->EntryUpdated(entry);
+ }
+}
+
+// Delegate API method.
+void SSLManager::AddMessageToConsole(const std::wstring& msg,
+ ConsoleMessageLevel level) {
+ WebContents* web_contents =
+ controller_->GetTabContents(TAB_CONTENTS_WEB)->AsWebContents();
+ if (!web_contents)
+ return;
+
+ web_contents->AddMessageToConsole(L"", msg, level);
+}
+
+
+// Delegate API method.
+void SSLManager::DenyCertForHost(X509Certificate* cert,
+ const std::string& host) {
+ // Remember that we don't like this cert for this host.
+ // TODO(abarth): Do we want to persist this information in the user's profile?
+ cert_policy_for_host_[host].Deny(cert);
+}
+
+// Delegate API method.
+void SSLManager::AllowCertForHost(X509Certificate* cert,
+ const std::string& host) {
+ // Remember that we do like this cert for this host.
+ // TODO(abarth): Do we want to persist this information in the user's profile?
+ cert_policy_for_host_[host].Allow(cert);
+}
+
+// Delegate API method.
+X509Certificate::Policy::Judgment SSLManager::QueryPolicy(
+ X509Certificate* cert, const std::string& host) {
+ // TODO(abarth): Do we want to read this information from the user's profile?
+ return cert_policy_for_host_[host].Check(cert);
+}
+
+bool SSLManager::CanShowInsecureContent(const GURL& url) {
+ // TODO(jcampan): Do we want to read this information from the user's profile?
+ return (can_show_insecure_content_for_host_.find(url.host()) !=
+ can_show_insecure_content_for_host_.end());
+}
+
+void SSLManager::AllowShowInsecureContentForURL(const GURL& url) {
+ can_show_insecure_content_for_host_.insert(url.host());
+}
+
+void SSLManager::OnInfoBarClose(SSLInfoBar* info_bar) {
+ // |info_bar| is no longer visible. No need to track it any more.
+ visible_info_bars_.RemoveObserver(info_bar);
+}
+
+bool SSLManager::ProcessedSSLErrorFromRequest() const {
+ NavigationEntry* entry = controller_->GetActiveEntry();
+ if (!entry) {
+ NOTREACHED();
+ return false;
+ }
+
+ return net::IsCertStatusError(entry->GetSSLCertStatus());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ErrorHandler
+
+SSLManager::ErrorHandler::ErrorHandler(ResourceDispatcherHost* rdh,
+ URLRequest* request,
+ MessageLoop* ui_loop)
+ : ui_loop_(ui_loop),
+ io_loop_(MessageLoop::current()),
+ manager_(NULL),
+ resource_dispatcher_host_(rdh),
+ request_has_been_notified_(false),
+ request_id_(0, 0),
+ request_url_(request->url()) {
+ DCHECK(MessageLoop::current() != ui_loop);
+
+ ResourceDispatcherHost::ExtraRequestInfo* info =
+ ResourceDispatcherHost::ExtraInfoForRequest(request);
+ request_id_.render_process_host_id = info->render_process_host_id;
+ request_id_.request_id = info->request_id;
+
+ if (!tab_util::GetTabContentsID(request,
+ &render_process_host_id_,
+ &tab_contents_id_))
+ NOTREACHED();
+
+ // This makes sure we don't disappear on the IO thread until we've given an
+ // answer to the URLRequest.
+ //
+ // Release in CompleteCancelRequest, CompleteContinueRequest,
+ // CompleteStartRequest or CompleteTakeNoAction.
+ AddRef();
+}
+
+void SSLManager::ErrorHandler::Dispatch() {
+ DCHECK(MessageLoop::current() == ui_loop_);
+
+ TabContents* tab_contents =
+ tab_util::GetTabContentsByID(render_process_host_id_, tab_contents_id_);
+
+ if (!tab_contents) {
+ // We arrived on the UI thread, but the tab we're looking for is no longer
+ // here.
+ OnDispatchFailed();
+ return;
+ }
+
+ // Hand ourselves off to the SSLManager.
+ manager_ = tab_contents->controller()->ssl_manager();
+ OnDispatched();
+}
+
+TabContents* SSLManager::ErrorHandler::GetTabContents() {
+ return tab_util::GetTabContentsByID(render_process_host_id_,
+ tab_contents_id_);
+}
+
+void SSLManager::ErrorHandler::CancelRequest() {
+ DCHECK(MessageLoop::current() == ui_loop_);
+
+ // We need to complete this task on the IO thread.
+ io_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &SSLManager::ErrorHandler::CompleteCancelRequest,
+ net::ERR_ABORTED));
+}
+
+void SSLManager::ErrorHandler::DenyRequest() {
+ DCHECK(MessageLoop::current() == ui_loop_);
+
+ // We need to complete this task on the IO thread.
+ io_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &SSLManager::ErrorHandler::CompleteCancelRequest,
+ net::ERR_INSECURE_RESPONSE));
+}
+
+void SSLManager::ErrorHandler::ContinueRequest() {
+ DCHECK(MessageLoop::current() == ui_loop_);
+
+ // We need to complete this task on the IO thread.
+ io_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &SSLManager::ErrorHandler::CompleteContinueRequest));
+}
+
+void SSLManager::ErrorHandler::StartRequest(FilterPolicy::Type filter_policy) {
+ DCHECK(MessageLoop::current() == ui_loop_);
+
+ // We need to complete this task on the IO thread.
+ io_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &SSLManager::ErrorHandler::CompleteStartRequest, filter_policy));
+}
+
+void SSLManager::ErrorHandler::TakeNoAction() {
+ DCHECK(MessageLoop::current() == ui_loop_);
+
+ // We need to complete this task on the IO thread.
+ io_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &SSLManager::ErrorHandler::CompleteTakeNoAction));
+}
+
+void SSLManager::ErrorHandler::CompleteCancelRequest(int error) {
+ DCHECK(MessageLoop::current() == io_loop_);
+
+ // It is important that we notify the URLRequest only once. If we try to
+ // notify the request twice, it may no longer exist and |this| might have
+ // already have been deleted.
+ DCHECK(!request_has_been_notified_);
+
+ if (!request_has_been_notified_) {
+ URLRequest* request = resource_dispatcher_host_->GetURLRequest(request_id_);
+ if (request) {
+ // The request can be NULL if it was cancelled by the renderer (as the
+ // result of the user navigating to a new page from the location bar).
+ DLOG(INFO) << "CompleteCancelRequest() url: " << request->url().spec();
+ request->CancelWithError(error);
+ }
+ request_has_been_notified_ = true;
+
+ // We're done with this object on the IO thread.
+ Release();
+ }
+}
+
+void SSLManager::ErrorHandler::CompleteContinueRequest() {
+ DCHECK(MessageLoop::current() == io_loop_);
+
+ // It is important that we notify the URLRequest only once. If we try to
+ // notify the request twice, it may no longer exist and |this| might have
+ // already have been deleted.
+ DCHECK(!request_has_been_notified_);
+
+ if (!request_has_been_notified_) {
+ URLRequest* request = resource_dispatcher_host_->GetURLRequest(request_id_);
+ if (request) {
+ // The request can be NULL if it was cancelled by the renderer (as the
+ // result of the user navigating to a new page from the location bar).
+ DLOG(INFO) << "CompleteContinueRequest() url: " << request->url().spec();
+ request->ContinueDespiteLastError();
+ }
+ request_has_been_notified_ = true;
+
+ // We're done with this object on the IO thread.
+ Release();
+ }
+}
+
+void SSLManager::ErrorHandler::CompleteStartRequest(
+ FilterPolicy::Type filter_policy) {
+ DCHECK(MessageLoop::current() == io_loop_);
+
+ // It is important that we notify the URLRequest only once. If we try to
+ // notify the request twice, it may no longer exist and |this| might have
+ // already have been deleted.
+ DCHECK(!request_has_been_notified_);
+
+ if (request_has_been_notified_)
+ return;
+
+ URLRequest* request = resource_dispatcher_host_->GetURLRequest(request_id_);
+ if (request) {
+ // The request can be NULL if it was cancelled by the renderer (as the
+ // result of the user navigating to a new page from the location bar).
+ DLOG(INFO) << "CompleteStartRequest() url: " << request->url().spec();
+ // The request should not have been started (SUCCESS is the initial state).
+ DCHECK(request->status().status() == URLRequestStatus::SUCCESS);
+ ResourceDispatcherHost::ExtraRequestInfo* info =
+ ResourceDispatcherHost::ExtraInfoForRequest(request);
+ info->filter_policy = filter_policy;
+ request->Start();
+ }
+ request_has_been_notified_ = true;
+
+ // We're done with this object on the IO thread.
+ Release();
+}
+
+void SSLManager::ErrorHandler::CompleteTakeNoAction() {
+ DCHECK(MessageLoop::current() == io_loop_);
+
+ // It is important that we notify the URLRequest only once. If we try to
+ // notify the request twice, it may no longer exist and |this| might have
+ // already have been deleted.
+ DCHECK(!request_has_been_notified_);
+
+ if (!request_has_been_notified_) {
+ request_has_been_notified_ = true;
+
+ // We're done with this object on the IO thread.
+ Release();
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// CertError
+
+SSLManager::CertError::CertError(
+ ResourceDispatcherHost* rdh,
+ URLRequest* request,
+ ResourceType::Type resource_type,
+ int cert_error,
+ X509Certificate* cert,
+ MessageLoop* ui_loop)
+ : ErrorHandler(rdh, request, ui_loop),
+ cert_error_(cert_error),
+ resource_type_(resource_type) {
+ DCHECK(request == resource_dispatcher_host_->GetURLRequest(request_id_));
+
+ // We cannot use the request->ssl_info(), it's not been initialized yet, so
+ // we have to set the fields manually.
+ ssl_info_.cert = cert;
+ ssl_info_.SetCertError(cert_error);
+}
+
+// static
+void SSLManager::OnSSLCertificateError(ResourceDispatcherHost* rdh,
+ URLRequest* request,
+ int cert_error,
+ X509Certificate* cert,
+ MessageLoop* ui_loop) {
+ DLOG(INFO) << "OnSSLCertificateError() cert_error: " << cert_error <<
+ " url: " << request->url().spec();
+
+ ResourceDispatcherHost::ExtraRequestInfo* info =
+ ResourceDispatcherHost::ExtraInfoForRequest(request);
+ DCHECK(info);
+
+ // A certificate error occurred. Construct a CertError object and hand it
+ // over to the UI thread for processing.
+ ui_loop->PostTask(FROM_HERE,
+ NewRunnableMethod(new CertError(rdh, request, info->resource_type,
+ cert_error, cert, ui_loop),
+ &CertError::Dispatch));
+}
+
+// static
+void SSLManager::OnMixedContentRequest(ResourceDispatcherHost* rdh,
+ URLRequest* request,
+ MessageLoop* ui_loop) {
+ ui_loop->PostTask(FROM_HERE,
+ NewRunnableMethod(new MixedContentHandler(rdh, request, ui_loop),
+ &MixedContentHandler::Dispatch));
+}
+
+void SSLManager::OnCertError(CertError* error) {
+ // Ask our delegate to deal with the error.
+ NavigationEntry* entry = controller_->GetActiveEntry();
+ delegate()->OnCertError(entry->GetURL(), error);
+}
+
+void SSLManager::OnMixedContent(MixedContentHandler* mixed_content) {
+ // Ask our delegate to deal with the mixed content.
+ NavigationEntry* entry = controller_->GetActiveEntry();
+ delegate()->OnMixedContent(controller_, entry->GetURL(), mixed_content);
+}
+
+void SSLManager::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ // We should only be getting notifications from our controller.
+ DCHECK(source == Source<NavigationController>(controller_));
+
+ // Dispatch by type.
+ switch (type) {
+ case NOTIFY_FRAME_PROVISIONAL_LOAD_COMMITTED:
+ DidCommitProvisionalLoad(Details<ProvisionalLoadDetails>(details).ptr());
+ break;
+ case NOTIFY_FAIL_PROVISIONAL_LOAD_WITH_ERROR:
+ DidFailProvisionalLoadWithError(
+ Details<ProvisionalLoadDetails>(details).ptr());
+ break;
+ case NOTIFY_RESOURCE_RESPONSE_STARTED:
+ DidStartResourceResponse(Details<ResourceRequestDetails>(details).ptr());
+ break;
+ case NOTIFY_RESOURCE_RECEIVED_REDIRECT:
+ DidReceiveResourceRedirect(
+ Details<ResourceRedirectDetails>(details).ptr());
+ break;
+ case NOTIFY_LOAD_FROM_MEMORY_CACHE:
+ DidLoadFromMemoryCache(
+ Details<LoadFromMemoryCacheDetails>(details).ptr());
+ break;
+ default:
+ NOTREACHED() << "The SSLManager received an unexpected notification.";
+ }
+}
+
+void SSLManager::InitializeEntryIfNeeded(NavigationEntry* entry) {
+ DCHECK(entry);
+
+ // If the security style of the entry is SECURITY_STYLE_UNKNOWN, then it is a
+ // fresh entry and should get the default style.
+ if (entry->GetSecurityStyle() == SECURITY_STYLE_UNKNOWN)
+ entry->SetSecurityStyle(delegate()->GetDefaultStyle(entry->GetURL()));
+}
+
+void SSLManager::NavigationStateChanged() {
+ NavigationEntry* active_entry = controller_->GetActiveEntry();
+ if (!active_entry)
+ return; // Nothing showing yet.
+
+ // This might be a new entry we've never seen before.
+ InitializeEntryIfNeeded(active_entry);
+}
+
+void SSLManager::DidLoadFromMemoryCache(LoadFromMemoryCacheDetails* details) {
+ DCHECK(details);
+
+ // Simulate loading this resource through the usual path.
+ // Note that we specify SUB_RESOURCE as the resource type as WebCore only
+ // caches sub-resources.
+ delegate()->OnRequestStarted(this, details->url(),
+ ResourceType::SUB_RESOURCE,
+ details->ssl_cert_id(),
+ details->ssl_cert_status());
+}
+
+void SSLManager::DidCommitProvisionalLoad(ProvisionalLoadDetails* details) {
+ // Ignore in-page navigations, they should not change the security style or
+ // the info-bars.
+ if (details->in_page_navigation())
+ return;
+
+ if (details->main_frame()) {
+ // We are navigating to a new page, it's time to close the info bars. They
+ // will automagically disappear from the visible_info_bars_ list (when
+ // OnInfoBarClose is invoked).
+ // TODO(jcampan): if we are navigating to an interstitial page, we close
+ // the info-bars. That is unfortunate as if you decide to go back to the
+ // original page, the info-bars are now gone. We would need a way to
+ // restore them in that case.
+ FOR_EACH_OBSERVER(SSLInfoBar, visible_info_bars_, Close());
+
+ // Update the SSL states of the pending entry.
+ NavigationEntry* entry = controller_->GetActiveEntry();
+ if (entry) {
+ // We may not have an entry if this is a navigation to an initial blank
+ // page.
+ entry->ResetSSLStates(); // Clears mixed/unsafe content state.
+ entry->SetSSLCertID(details->ssl_cert_id());
+ entry->SetSSLCertStatus(details->ssl_cert_status());
+ entry->SetSSLSecurityBits(details->ssl_security_bits());
+ controller_->EntryUpdated(entry);
+ }
+
+ if (details->interstitial_page()) {
+ // We should not have any errors when loading an interstitial page, and as
+ // a consequence no messages.
+ DCHECK(pending_messages_.empty());
+ }
+ ShowPendingMessages();
+ }
+
+ // An HTTPS response may not have a certificate for some reason. When that
+ // happens, use the unauthenticated (HTTP) rather than the authentication
+ // broken security style so that we can detect this error condition.
+ if (net::IsCertStatusError(details->ssl_cert_status()))
+ SetMaxSecurityStyle(SECURITY_STYLE_AUTHENTICATION_BROKEN);
+ else if (details->url().SchemeIsSecure() && !details->ssl_cert_id())
+ SetMaxSecurityStyle(SECURITY_STYLE_UNAUTHENTICATED);
+}
+
+void SSLManager::DidFailProvisionalLoadWithError(
+ ProvisionalLoadDetails* details) {
+ DCHECK(details);
+ // A transitional page is not expected to fail.
+ DCHECK(!details->interstitial_page());
+
+ // Ignore in-page navigations.
+ if (details->in_page_navigation())
+ return;
+
+ if (details->main_frame() && !details->interstitial_page())
+ ClearPendingMessages();
+}
+
+void SSLManager::DidStartResourceResponse(ResourceRequestDetails* details) {
+ DCHECK(details);
+
+ // Notify our delegate that we started a resource request. Ideally, the
+ // delegate should have the ability to cancel the request, but we can't do
+ // that yet.
+ delegate()->OnRequestStarted(this, details->url(),
+ details->resource_type(),
+ details->ssl_cert_id() ,
+ details->ssl_cert_status());
+}
+
+void SSLManager::DidReceiveResourceRedirect(ResourceRedirectDetails* details) {
+ // TODO(jcampan): when we receive a redirect for a sub-resource, we may want
+ // to clear any mixed/unsafe content error that it may have triggered.
+}
+
+void SSLManager::ShowPendingMessages() {
+ std::vector<SSLMessageInfo>::const_iterator iter;
+ for (iter = pending_messages_.begin();
+ iter != pending_messages_.end(); ++iter) {
+ ShowMessageWithLink(iter->message, iter->link_text, iter->action);
+ }
+ ClearPendingMessages();
+}
+
+void SSLManager::ClearPendingMessages() {
+ pending_messages_.clear();
+}
+
+// static
+std::string SSLManager::SerializeSecurityInfo(int cert_id,
+ int cert_status,
+ int security_bits) {
+ Pickle pickle;
+ pickle.WriteInt(cert_id);
+ pickle.WriteInt(cert_status);
+ pickle.WriteInt(security_bits);
+ return std::string(static_cast<const char*>(pickle.data()), pickle.size());
+}
+
+// static
+bool SSLManager::DeserializeSecurityInfo(const std::string& state,
+ int* cert_id,
+ int* cert_status,
+ int* security_bits) {
+ DCHECK(cert_id && cert_status && security_bits);
+ if (state.empty()) {
+ // No SSL used.
+ *cert_id = 0;
+ *cert_status = 0;
+ *security_bits = -1;
+ return false;
+ }
+
+ Pickle pickle(state.data(), static_cast<int>(state.size()));
+ void * iter = NULL;
+ pickle.ReadInt(&iter, cert_id);
+ pickle.ReadInt(&iter, cert_status);
+ pickle.ReadInt(&iter, security_bits);
+ return true;
+}
+
+// static
+bool SSLManager::GetEVCertNames(const X509Certificate& cert,
+ std::wstring* short_name,
+ std::wstring* ca_name) {
+ DCHECK(short_name || ca_name);
+
+ // EV are required to have an organization name and country.
+ if (cert.subject().organization_names.empty() ||
+ cert.subject().country_name.empty()) {
+ NOTREACHED();
+ return false;
+ }
+
+ if (short_name) {
+ *short_name = l10n_util::GetStringF(
+ IDS_SECURE_CONNECTION_EV,
+ UTF8ToWide(cert.subject().organization_names[0]),
+ UTF8ToWide(cert.subject().country_name));
+ }
+
+ if (ca_name) {
+ // TODO(wtc): should we show the root CA's name instead?
+ *ca_name = l10n_util::GetStringF(
+ IDS_SECURE_CONNECTION_EV_CA,
+ UTF8ToWide(cert.issuer().organization_names[0]));
+ }
+ return true;
+}