blob: 872ac32adc13b7fcd8c6fc3c4d7a075b3eb7d0d3 [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/devtools/protocol/security_handler.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/strings/string_number_conversions.h"
#include "content/browser/devtools/devtools_agent_host_impl.h"
#include "content/browser/renderer_host/back_forward_cache_disable.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/public/browser/back_forward_cache.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
namespace content {
namespace protocol {
// static
std::vector<SecurityHandler*> SecurityHandler::ForAgentHost(
DevToolsAgentHostImpl* host) {
return host->HandlersByName<SecurityHandler>(Security::Metainfo::domainName);
}
SecurityHandler::SecurityHandler()
: DevToolsDomainHandler(Security::Metainfo::domainName),
enabled_(false),
host_(nullptr) {
}
SecurityHandler::~SecurityHandler() = default;
void SecurityHandler::Wire(UberDispatcher* dispatcher) {
frontend_ = std::make_unique<Security::Frontend>(dispatcher->channel());
Security::Dispatcher::wire(dispatcher, this);
}
void SecurityHandler::AttachToRenderFrameHost() {
DCHECK(host_);
WebContents* web_contents = WebContents::FromRenderFrameHost(host_);
WebContentsObserver::Observe(web_contents);
// Send an initial DidChangeVisibleSecurityState event.
DCHECK(enabled_);
DidChangeVisibleSecurityState();
}
void SecurityHandler::SetRenderer(int process_host_id,
RenderFrameHostImpl* frame_host) {
host_ = frame_host;
if (enabled_ && host_)
AttachToRenderFrameHost();
}
void SecurityHandler::DidFinishNavigation(NavigationHandle* navigation_handle) {
if (cert_error_override_mode_ == CertErrorOverrideMode::kHandleEvents) {
BackForwardCache::DisableForRenderFrameHost(
navigation_handle->GetPreviousRenderFrameHostId(),
BackForwardCacheDisable::DisabledReason(
BackForwardCacheDisable::DisabledReasonId::kSecurityHandler));
FlushPendingCertificateErrorNotifications();
}
}
void SecurityHandler::FlushPendingCertificateErrorNotifications() {
for (auto& callback : cert_error_callbacks_) {
std::move(callback).second.Run(
content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL);
}
cert_error_callbacks_.clear();
}
bool SecurityHandler::IsIgnoreCertificateErrorsSet() const {
return cert_error_override_mode_ == CertErrorOverrideMode::kIgnoreAll;
}
bool SecurityHandler::NotifyCertificateError(int cert_error,
const GURL& request_url,
CertErrorCallback handler) {
if (cert_error_override_mode_ == CertErrorOverrideMode::kIgnoreAll) {
if (handler)
std::move(handler).Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE);
return true;
}
if (!enabled_)
return false;
frontend_->CertificateError(++last_cert_error_id_,
net::ErrorToShortString(cert_error),
request_url.spec());
if (!handler ||
cert_error_override_mode_ != CertErrorOverrideMode::kHandleEvents) {
return false;
}
cert_error_callbacks_[last_cert_error_id_] = std::move(handler);
return true;
}
Response SecurityHandler::Enable() {
if (host_) {
Response response = AssureTopLevelActiveFrame();
if (response.IsError())
return response;
}
enabled_ = true;
if (host_)
AttachToRenderFrameHost();
return Response::Success();
}
Response SecurityHandler::Disable() {
enabled_ = false;
cert_error_override_mode_ = CertErrorOverrideMode::kDisabled;
WebContentsObserver::Observe(nullptr);
FlushPendingCertificateErrorNotifications();
return Response::Success();
}
Response SecurityHandler::HandleCertificateError(int event_id,
const String& action) {
if (!base::Contains(cert_error_callbacks_, event_id)) {
return Response::ServerError(
String("Unknown event id: " + base::NumberToString(event_id)));
}
content::CertificateRequestResultType type =
content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
Response response = Response::Success();
if (action == Security::CertificateErrorActionEnum::Continue) {
type = content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE;
} else if (action == Security::CertificateErrorActionEnum::Cancel) {
type = content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
} else {
response = Response::ServerError(
String("Unknown Certificate Error Action: " + action));
}
std::move(cert_error_callbacks_[event_id]).Run(type);
cert_error_callbacks_.erase(event_id);
return response;
}
Response SecurityHandler::SetOverrideCertificateErrors(bool override) {
if (override) {
if (!enabled_)
return Response::ServerError("Security domain not enabled");
if (cert_error_override_mode_ == CertErrorOverrideMode::kIgnoreAll) {
return Response::ServerError(
"Certificate errors are already being ignored.");
}
cert_error_override_mode_ = CertErrorOverrideMode::kHandleEvents;
} else {
cert_error_override_mode_ = CertErrorOverrideMode::kDisabled;
FlushPendingCertificateErrorNotifications();
}
return Response::Success();
}
Response SecurityHandler::SetIgnoreCertificateErrors(bool ignore) {
if (ignore) {
if (cert_error_override_mode_ == CertErrorOverrideMode::kHandleEvents)
return Response::ServerError(
"Certificate errors are already overridden.");
cert_error_override_mode_ = CertErrorOverrideMode::kIgnoreAll;
} else {
cert_error_override_mode_ = CertErrorOverrideMode::kDisabled;
}
return Response::Success();
}
Response SecurityHandler::AssureTopLevelActiveFrame() {
DCHECK(host_);
constexpr char kCommandIsOnlyAvailableAtTopTarget[] =
"Command can only be executed on top-level targets";
if (host_->GetParentOrOuterDocument())
return Response::ServerError(kCommandIsOnlyAvailableAtTopTarget);
constexpr char kErrorInactivePage[] = "Not attached to an active page";
if (!host_->IsActive())
return Response::ServerError(kErrorInactivePage);
return Response::Success();
}
} // namespace protocol
} // namespace content