blob: e85457d037a2794f2f1c73504ba65e8611387a06 [file] [log] [blame]
// Copyright 2018 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 "content/browser/frame_host/origin_policy_throttle.h"
#include "content/public/browser/origin_policy_commands.h"
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "content/browser/frame_host/navigation_handle_impl.h"
#include "content/browser/frame_host/navigation_request.h"
#include "content/browser/storage_partition_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "services/network/public/mojom/origin_policy_manager.mojom.h"
#include "url/origin.h"
namespace content {
// Implement the public "API" from
// content/public/browser/origin_policy_commands.h:
void OriginPolicyAddExceptionFor(BrowserContext* browser_context,
const GURL& url) {
OriginPolicyThrottle::AddExceptionFor(browser_context, url);
}
// static
bool OriginPolicyThrottle::ShouldRequestOriginPolicy(const GURL& url) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
bool origin_policy_enabled =
base::FeatureList::IsEnabled(features::kOriginPolicy) ||
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableExperimentalWebPlatformFeatures);
if (!origin_policy_enabled)
return false;
if (!url.SchemeIs(url::kHttpsScheme))
return false;
return true;
}
// static
std::unique_ptr<NavigationThrottle>
OriginPolicyThrottle::MaybeCreateThrottleFor(NavigationHandle* handle) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(handle);
if (!ShouldRequestOriginPolicy(handle->GetURL()))
return nullptr;
return base::WrapUnique(new OriginPolicyThrottle(handle));
}
// static
void OriginPolicyThrottle::AddExceptionFor(BrowserContext* browser_context,
const GURL& url) {
DCHECK(browser_context);
StoragePartitionImpl* storage_partition = static_cast<StoragePartitionImpl*>(
BrowserContext::GetStoragePartitionForSite(browser_context, url));
network::mojom::OriginPolicyManager* origin_policy_manager =
storage_partition->GetOriginPolicyManagerForBrowserProcess();
origin_policy_manager->AddExceptionFor(url::Origin::Create(url));
}
OriginPolicyThrottle::~OriginPolicyThrottle() {}
NavigationThrottle::ThrottleCheckResult
OriginPolicyThrottle::WillStartRequest() {
// TODO(vogelheim): It might be faster in the common case to optimistically
// fetch the policy indicated in the request already here. This would
// be faster if the last known version is the current version, but
// slower (and wasteful of bandwidth) if the server sends us a new
// version. It's unclear how much the upside is, though.
return NavigationThrottle::PROCEED;
}
NavigationThrottle::ThrottleCheckResult
OriginPolicyThrottle::WillProcessResponse() {
DCHECK(navigation_handle());
// If no test origin policy is set, look at the actual origin policy from the
// response.
const base::Optional<network::OriginPolicy>& origin_policy =
GetTestOriginPolicy().has_value()
? GetTestOriginPolicy()
: static_cast<NavigationHandleImpl*>(navigation_handle())
->navigation_request()
->response()
->head.origin_policy;
// If there is no origin_policy, treat this case as
// network::OriginPolicyState::kNoPolicyApplies.
if (!origin_policy.has_value()) {
return NavigationThrottle::PROCEED;
}
switch (origin_policy->state) {
case network::OriginPolicyState::kCannotLoadPolicy:
case network::OriginPolicyState::kInvalidRedirect:
case network::OriginPolicyState::kOther:
return NavigationThrottle::ThrottleCheckResult(
NavigationThrottle::CANCEL, net::ERR_BLOCKED_BY_CLIENT,
GetContentClient()->browser()->GetOriginPolicyErrorPage(
origin_policy->state, navigation_handle()));
case network::OriginPolicyState::kNoPolicyApplies:
case network::OriginPolicyState::kLoaded:
return NavigationThrottle::PROCEED;
}
}
const char* OriginPolicyThrottle::GetNameForLogging() {
return "OriginPolicyThrottle";
}
// static
void OriginPolicyThrottle::SetOriginPolicyForTesting(
const network::OriginPolicy& origin_policy) {
base::Optional<network::OriginPolicy> new_test_origin_policy = origin_policy;
GetTestOriginPolicy().swap(new_test_origin_policy);
}
// static
void OriginPolicyThrottle::ResetOriginPolicyForTesting() {
GetTestOriginPolicy().reset();
}
OriginPolicyThrottle::OriginPolicyThrottle(NavigationHandle* handle)
: NavigationThrottle(handle) {}
// static
base::Optional<network::OriginPolicy>&
OriginPolicyThrottle::GetTestOriginPolicy() {
static base::NoDestructor<base::Optional<network::OriginPolicy>>
test_origin_policy;
return *test_origin_policy;
}
} // namespace content