Commit 17bbb4dd authored by Sharon Yang's avatar Sharon Yang Committed by Commit Bot

[fuchsia] Implement NavigationPolicyThrottle for navigation blocking

* Add an implementation of NavigationPolicyThrottle to WebEngine
* Add NavigationPolicyHandler, which keeps track of throttles and checks
  if navigations need to be passed on to the client
* Add a FakeNavigationPolicyProvider for tests

Test: NavigationPolicyThrottleTest
Bug: 1117601
Change-Id: I0bdf94345b10d829bea4aeb85f74204970a97239
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2519039
Commit-Queue: Sharon Yang <yangsharon@chromium.org>
Reviewed-by: default avatarSergey Ulanov <sergeyu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#826625}
parent bea26525
......@@ -157,6 +157,10 @@ component("web_engine_core") {
"browser/media_resource_provider_service.h",
"browser/navigation_controller_impl.cc",
"browser/navigation_controller_impl.h",
"browser/navigation_policy_handler.cc",
"browser/navigation_policy_handler.h",
"browser/navigation_policy_throttle.cc",
"browser/navigation_policy_throttle.h",
"browser/url_request_rewrite_rules_manager.cc",
"browser/url_request_rewrite_rules_manager.h",
"browser/web_engine_browser_context.cc",
......@@ -329,8 +333,11 @@ test("web_engine_unittests") {
"browser/ax_tree_converter_unittest.cc",
"browser/cookie_manager_impl_unittest.cc",
"browser/event_filter_unittest.cc",
"browser/fake_navigation_policy_provider.cc",
"browser/fake_navigation_policy_provider.h",
"browser/frame_impl_unittest.cc",
"browser/media_player_impl_unittest.cc",
"browser/navigation_policy_throttle_unittest.cc",
"browser/url_request_rewrite_rules_manager_unittest.cc",
"common/web_engine_url_loader_throttle_unittest.cc",
"context_provider_impl_unittest.cc",
......@@ -343,6 +350,7 @@ test("web_engine_unittests") {
":switches",
":web_engine_core",
"//base/test:test_support",
"//content/test:test_support",
"//fuchsia/base:test_support",
"//mojo/core/embedder",
"//services/media_session/public/mojom",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "fuchsia/engine/browser/fake_navigation_policy_provider.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "testing/gtest/include/gtest/gtest.h"
FakeNavigationPolicyProvider::FakeNavigationPolicyProvider() = default;
FakeNavigationPolicyProvider::~FakeNavigationPolicyProvider() = default;
void FakeNavigationPolicyProvider::EvaluateRequestedNavigation(
fuchsia::web::RequestedNavigation requested_navigation,
EvaluateRequestedNavigationCallback callback) {
fuchsia::web::NavigationDecision decision;
if (should_reject_request_) {
callback(decision.WithAbort(fuchsia::web::NoArgumentsAction()));
} else {
callback(decision.WithProceed(fuchsia::web::NoArgumentsAction()));
}
requested_navigation_ = std::move(requested_navigation);
}
void FakeNavigationPolicyProvider::NotImplemented_(const std::string& name) {
NOTIMPLEMENTED() << name;
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FUCHSIA_ENGINE_BROWSER_FAKE_NAVIGATION_POLICY_PROVIDER_H_
#define FUCHSIA_ENGINE_BROWSER_FAKE_NAVIGATION_POLICY_PROVIDER_H_
#include <fuchsia/web/cpp/fidl.h>
#include <fuchsia/web/cpp/fidl_test_base.h>
class FakeNavigationPolicyProvider
: public fuchsia::web::testing::NavigationPolicyProvider_TestBase {
public:
FakeNavigationPolicyProvider();
~FakeNavigationPolicyProvider() override;
FakeNavigationPolicyProvider(const FakeNavigationPolicyProvider&) = delete;
FakeNavigationPolicyProvider& operator=(const FakeNavigationPolicyProvider&) =
delete;
void set_should_reject_request(bool reject) {
should_reject_request_ = reject;
}
fuchsia::web::RequestedNavigation* requested_navigation() {
return &requested_navigation_;
}
// fuchsia::web::NavigationPolicyProvider implementation.
void EvaluateRequestedNavigation(
fuchsia::web::RequestedNavigation requested_navigation,
EvaluateRequestedNavigationCallback callback) final;
void NotImplemented_(const std::string& name) final;
private:
fuchsia::web::RequestedNavigation requested_navigation_;
bool should_reject_request_ = false;
};
#endif // FUCHSIA_ENGINE_BROWSER_FAKE_NAVIGATION_POLICY_PROVIDER_H_
\ No newline at end of file
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "fuchsia/engine/browser/navigation_policy_handler.h"
#include <lib/fidl/cpp/binding.h>
#include "base/fuchsia/fuchsia_logging.h"
#include "content/public/browser/navigation_handle.h"
#include "fuchsia/engine/browser/navigation_policy_throttle.h"
NavigationPolicyHandler::NavigationPolicyHandler(
fuchsia::web::NavigationPolicyProviderParams params,
fidl::InterfaceHandle<fuchsia::web::NavigationPolicyProvider> delegate)
: params_(std::move(params)), provider_(delegate.Bind()) {
provider_.set_error_handler(fit::bind_member(
this, &NavigationPolicyHandler::OnNavigationPolicyProviderDisconnected));
}
NavigationPolicyHandler::~NavigationPolicyHandler() {
for (auto* throttle : navigation_throttles_) {
throttle->OnNavigationPolicyProviderDisconnected(
content::NavigationThrottle::CANCEL);
}
navigation_throttles_.clear();
}
void NavigationPolicyHandler::RegisterNavigationThrottle(
NavigationPolicyThrottle* navigation_throttle) {
navigation_throttles_.insert(navigation_throttle);
}
void NavigationPolicyHandler::RemoveNavigationThrottle(
NavigationPolicyThrottle* navigation_throttle) {
navigation_throttles_.erase(navigation_throttle);
}
void NavigationPolicyHandler::EvaluateRequestedNavigation(
fuchsia::web::RequestedNavigation requested_navigation,
fuchsia::web::NavigationPolicyProvider::EvaluateRequestedNavigationCallback
callback) {
provider_->EvaluateRequestedNavigation(std::move(requested_navigation),
std::move(callback));
}
bool NavigationPolicyHandler::ShouldEvaluateNavigation(
content::NavigationHandle* handle,
fuchsia::web::NavigationPhase phase) {
if (handle->IsInMainFrame()) {
return (phase & params_.main_frame_phases()) == phase;
}
return (phase & params_.subframe_phases()) == phase;
}
bool NavigationPolicyHandler::is_provider_connected() {
return provider_.is_bound();
}
void NavigationPolicyHandler::OnNavigationPolicyProviderDisconnected(
zx_status_t status) {
ZX_LOG(ERROR, status) << "NavigationPolicyProvider disconnected";
for (auto* throttle : navigation_throttles_) {
throttle->OnNavigationPolicyProviderDisconnected(
content::NavigationThrottle::CANCEL);
}
navigation_throttles_.clear();
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FUCHSIA_ENGINE_BROWSER_NAVIGATION_POLICY_HANDLER_H_
#define FUCHSIA_ENGINE_BROWSER_NAVIGATION_POLICY_HANDLER_H_
#include <fuchsia/web/cpp/fidl.h>
#include "base/containers/flat_set.h"
class NavigationPolicyThrottle;
namespace content {
class NavigationHandle;
} // namespace content
class NavigationPolicyHandler {
public:
NavigationPolicyHandler(
fuchsia::web::NavigationPolicyProviderParams params,
fidl::InterfaceHandle<fuchsia::web::NavigationPolicyProvider> delegate);
~NavigationPolicyHandler();
NavigationPolicyHandler(const NavigationPolicyHandler&) = delete;
NavigationPolicyHandler& operator=(const NavigationPolicyHandler&) = delete;
void RegisterNavigationThrottle(
NavigationPolicyThrottle* navigation_throttle);
void RemoveNavigationThrottle(NavigationPolicyThrottle* navigation_throttle);
fuchsia::web::NavigationPolicyProvider* navigation_policy_provider() {
return provider_.get();
}
bool is_provider_connected();
// Passes on the call to |provider_|.
void EvaluateRequestedNavigation(
fuchsia::web::RequestedNavigation requested_navigation,
fuchsia::web::NavigationPolicyProvider::
EvaluateRequestedNavigationCallback callback);
// Determines whether or not the client is interested in evaluating |handle|.
bool ShouldEvaluateNavigation(content::NavigationHandle* handle,
fuchsia::web::NavigationPhase phase);
private:
void OnNavigationPolicyProviderDisconnected(zx_status_t status);
fuchsia::web::NavigationPolicyProviderParams params_;
fuchsia::web::NavigationPolicyProviderPtr provider_;
// Keeps track of the NavigationThrottles associated with the Frame that owns
// |this|.
base::flat_set<NavigationPolicyThrottle*> navigation_throttles_;
};
#endif // FUCHSIA_ENGINE_BROWSER_NAVIGATION_POLICY_HANDLER_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "fuchsia/engine/browser/navigation_policy_throttle.h"
#include "content/public/browser/navigation_handle.h"
#include "fuchsia/engine/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) {
if (is_paused_) {
CancelDeferredNavigation(check_result);
is_paused_ = false;
}
policy_handler_ = nullptr;
}
void NavigationPolicyThrottle::OnRequestedNavigationEvaluated(
fuchsia::web::NavigationDecision decision) {
DCHECK(is_paused_);
switch (decision.Which()) {
case fuchsia::web::NavigationDecision::kProceed:
Resume();
break;
case fuchsia::web::NavigationDecision::kAbort:
CancelDeferredNavigation(content::NavigationThrottle::CANCEL);
break;
default:
NOTREACHED();
}
is_paused_ = false;
}
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_->navigation_policy_provider()->EvaluateRequestedNavigation(
ToRequestedNavigation(navigation_handle_, phase),
fit::bind_member(
this, &NavigationPolicyThrottle::OnRequestedNavigationEvaluated));
is_paused_ = true;
return content::NavigationThrottle::ThrottleCheckResult(
content::NavigationThrottle::DEFER);
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FUCHSIA_ENGINE_BROWSER_NAVIGATION_POLICY_THROTTLE_H_
#define FUCHSIA_ENGINE_BROWSER_NAVIGATION_POLICY_THROTTLE_H_
#include <fuchsia/web/cpp/fidl.h>
#include "content/public/browser/navigation_throttle.h"
class NavigationPolicyHandler;
class NavigationPolicyThrottle : public content::NavigationThrottle {
public:
explicit NavigationPolicyThrottle(content::NavigationHandle* handle,
NavigationPolicyHandler* policy_handler);
~NavigationPolicyThrottle() override;
NavigationPolicyThrottle(const NavigationPolicyThrottle&) = delete;
NavigationPolicyThrottle& operator=(const NavigationPolicyThrottle&) = delete;
void OnNavigationPolicyProviderDisconnected(ThrottleCheckResult check_result);
// content::NavigationThrottle implementation.
ThrottleCheckResult WillStartRequest() override;
ThrottleCheckResult WillRedirectRequest() override;
ThrottleCheckResult WillFailRequest() override;
ThrottleCheckResult WillProcessResponse() override;
const char* GetNameForLogging() override;
private:
void OnRequestedNavigationEvaluated(
fuchsia::web::NavigationDecision decision);
content::NavigationThrottle::ThrottleCheckResult HandleNavigationPhase(
fuchsia::web::NavigationPhase phase);
NavigationPolicyHandler* policy_handler_;
content::NavigationHandle* navigation_handle_;
// Indicates if the navigation is currently paused.
bool is_paused_ = false;
};
#endif // FUCHSIA_ENGINE_BROWSER_NAVIGATION_POLICY_THROTTLE_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "fuchsia/engine/browser/navigation_policy_throttle.h"
#include <fuchsia/web/cpp/fidl.h>
#include <lib/fidl/cpp/binding.h>
#include "base/test/task_environment.h"
#include "content/public/test/mock_navigation_handle.h"
#include "content/public/test/test_renderer_host.h"
#include "fuchsia/engine/browser/fake_navigation_policy_provider.h"
#include "fuchsia/engine/browser/navigation_policy_handler.h"
#include "testing/gtest/include/gtest/gtest.h"
class NavigationPolicyThrottleTest : public testing::Test {
public:
NavigationPolicyThrottleTest()
: policy_provider_binding_(&policy_provider_) {}
~NavigationPolicyThrottleTest() override = default;
NavigationPolicyThrottleTest(const NavigationPolicyThrottleTest&) = delete;
NavigationPolicyThrottleTest& operator=(const NavigationPolicyThrottleTest&) =
delete;
void SetUp() override {
fuchsia::web::NavigationPolicyProviderParams params;
*params.mutable_main_frame_phases() = fuchsia::web::NavigationPhase::START;
*params.mutable_subframe_phases() = fuchsia::web::NavigationPhase::REDIRECT;
policy_handler_ = std::make_unique<NavigationPolicyHandler>(
std::move(params), policy_provider_binding_.NewBinding());
}
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
std::unique_ptr<NavigationPolicyHandler> policy_handler_;
fidl::Binding<fuchsia::web::NavigationPolicyProvider>
policy_provider_binding_;
FakeNavigationPolicyProvider policy_provider_;
};
TEST_F(NavigationPolicyThrottleTest, WillStartRequest) {
policy_provider_.set_should_reject_request(false);
content::MockNavigationHandle navigation_handle;
navigation_handle.set_is_same_document(true);
NavigationPolicyThrottle throttle(&navigation_handle, policy_handler_.get());
throttle.set_cancel_deferred_navigation_callback_for_testing(
base::BindRepeating(
[](content::NavigationThrottle::ThrottleCheckResult result) {
EXPECT_EQ(content::NavigationThrottle::PROCEED, result);
}));
auto result = throttle.WillStartRequest();
EXPECT_EQ(content::NavigationThrottle::DEFER, result);
}
TEST_F(NavigationPolicyThrottleTest, WillProcessResponse) {
content::MockNavigationHandle navigation_handle;
NavigationPolicyThrottle throttle(&navigation_handle, policy_handler_.get());
throttle.set_cancel_deferred_navigation_callback_for_testing(
base::BindRepeating(
[](content::NavigationThrottle::ThrottleCheckResult result) {
EXPECT_EQ(content::NavigationThrottle::PROCEED, result);
}));
auto result = throttle.WillProcessResponse();
EXPECT_EQ(content::NavigationThrottle::PROCEED, result);
}
TEST_F(NavigationPolicyThrottleTest, WillRedirectRequest) {
content::MockNavigationHandle navigation_handle;
NavigationPolicyThrottle throttle(&navigation_handle, policy_handler_.get());
throttle.set_cancel_deferred_navigation_callback_for_testing(
base::BindRepeating(
[](content::NavigationThrottle::ThrottleCheckResult result) {
EXPECT_EQ(content::NavigationThrottle::PROCEED, result);
}));
auto result = throttle.WillProcessResponse();
EXPECT_EQ(content::NavigationThrottle::PROCEED, result);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment