// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "fuchsia_web/webengine/browser/navigation_policy_throttle.h"
#include "content/public/browser/navigation_handle.h"
#include "fuchsia_web/webengine/browser/navigation_policy_handler.h"
namespace {
fuchsia::web::RequestedNavigation ToRequestedNavigation(
content::NavigationHandle* handle,
fuchsia::web::NavigationPhase phase) {
fuchsia::web::RequestedNavigation event;
event.set_id(static_cast<uint64_t>(handle->GetNavigationId()));
event.set_phase(phase);
event.set_is_main_frame(handle->IsInMainFrame());
event.set_is_same_document(handle->IsSameDocument());
event.set_is_http_post(handle->IsPost());
event.set_url(handle->GetURL().spec());
event.set_has_gesture(handle->HasUserGesture());
event.set_was_server_redirect(handle->WasServerRedirect());
return event;
}
} // namespace
NavigationPolicyThrottle::NavigationPolicyThrottle(
content::NavigationHandle* handle,
NavigationPolicyHandler* policy_handler)
: NavigationThrottle(handle),
policy_handler_(policy_handler),
navigation_handle_(handle) {
if (policy_handler->is_provider_connected()) {
policy_handler_->RegisterNavigationThrottle(this);
} else {
policy_handler_ = nullptr;
}
}
NavigationPolicyThrottle::~NavigationPolicyThrottle() {
if (policy_handler_)
policy_handler_->RemoveNavigationThrottle(this);
}
void NavigationPolicyThrottle::OnNavigationPolicyProviderDisconnected(
content::NavigationThrottle::ThrottleCheckResult check_result) {
policy_handler_ = nullptr;
if (is_paused_) {
is_paused_ = false;
CancelDeferredNavigation(check_result);
// DO NOT ADD CODE after this. The callback above will destroy the
// NavigationHandle that owns this NavigationThrottle.
}
}
void NavigationPolicyThrottle::OnRequestedNavigationEvaluated(
fuchsia::web::NavigationDecision decision) {
DCHECK(is_paused_);
is_paused_ = false;
switch (decision.Which()) {
case fuchsia::web::NavigationDecision::kProceed:
Resume();
// DO NOT ADD CODE after this. The callback above might have destroyed
// the NavigationHandle that owns this NavigationThrottle.
break;
case fuchsia::web::NavigationDecision::kAbort:
CancelDeferredNavigation(content::NavigationThrottle::CANCEL);
// DO NOT ADD CODE after this. The callback above will destroy the
// NavigationHandle that owns this NavigationThrottle.
break;
default:
NOTREACHED_IN_MIGRATION();
}
}
content::NavigationThrottle::ThrottleCheckResult
NavigationPolicyThrottle::WillStartRequest() {
return HandleNavigationPhase(fuchsia::web::NavigationPhase::START);
}
content::NavigationThrottle::ThrottleCheckResult
NavigationPolicyThrottle::WillRedirectRequest() {
return HandleNavigationPhase(fuchsia::web::NavigationPhase::REDIRECT);
}
content::NavigationThrottle::ThrottleCheckResult
NavigationPolicyThrottle::WillFailRequest() {
return HandleNavigationPhase(fuchsia::web::NavigationPhase::FAIL);
}
content::NavigationThrottle::ThrottleCheckResult
NavigationPolicyThrottle::WillProcessResponse() {
return HandleNavigationPhase(fuchsia::web::NavigationPhase::PROCESS_RESPONSE);
}
const char* NavigationPolicyThrottle::GetNameForLogging() {
return "NavigationPolicyThrottle";
}
content::NavigationThrottle::ThrottleCheckResult
NavigationPolicyThrottle::HandleNavigationPhase(
fuchsia::web::NavigationPhase phase) {
DCHECK(!is_paused_);
if (!policy_handler_) {
return content::NavigationThrottle::ThrottleCheckResult(
content::NavigationThrottle::CANCEL);
}
if (!policy_handler_->ShouldEvaluateNavigation(navigation_handle_, phase)) {
return content::NavigationThrottle::ThrottleCheckResult(
content::NavigationThrottle::PROCEED);
}
policy_handler_->EvaluateRequestedNavigation(
ToRequestedNavigation(navigation_handle_, phase),
[weak_this = weak_factory_.GetWeakPtr()](auto decision) {
if (weak_this)
weak_this->OnRequestedNavigationEvaluated(std::move(decision));
});
is_paused_ = true;
return content::NavigationThrottle::ThrottleCheckResult(
content::NavigationThrottle::DEFER);
}