[DIP] Implement CORP checks on subresources
This CL implements the CORP checks on subresources for documents using
Document-Isolation-Policy: isolate-and-require-corp and
Document-Isolation-Policy: isolate-and-credentialless. In the later
case, this check only applies to credentialled subresources.
A follow-up CL
(https://chromium-review.googlesource.com/c/chromium/src/+/5593879) will
implement proper error messaging in DevTools.
Bug: 333029144
Change-Id: I54812987b06187bbc69ee99f7fed88e5ce0b6713
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5537963
Reviewed-by: Tsuyoshi Horo <horo@chromium.org>
Reviewed-by: Joe DeBlasio <jdeblasio@chromium.org>
Reviewed-by: Mike West <mkwst@chromium.org>
Reviewed-by: Alex Rudenko <alexrudenko@chromium.org>
Reviewed-by: Mason Freed <masonf@chromium.org>
Commit-Queue: Camille Lamy <clamy@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1309953}
diff --git a/content/browser/cache_storage/cache_storage_dispatcher_host.cc b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
index e0e1348..905489d02d 100644
--- a/content/browser/cache_storage/cache_storage_dispatcher_host.cc
+++ b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
@@ -155,12 +155,15 @@
if (corp_header != response->headers.end())
corp_header_value = corp_header->second;
+ // TODO(https://issues.chromium.org/issues/333029144):
+ // Pass the appropriate DocumentIsolationPolicy for the context.
return CrossOriginResourcePolicy::IsBlockedByHeaderValue(
response->url_list.back(), response->url_list.front(),
document_origin, corp_header_value, RequestMode::kNoCors,
network::mojom::RequestDestination::kEmpty,
response->request_include_credentials, document_coep,
- coep_reporter ? coep_reporter.get() : nullptr)
+ coep_reporter ? coep_reporter.get() : nullptr,
+ network::DocumentIsolationPolicy())
.has_value();
}
diff --git a/content/browser/devtools/devtools_instrumentation.cc b/content/browser/devtools/devtools_instrumentation.cc
index c3e874d..1a021b9 100644
--- a/content/browser/devtools/devtools_instrumentation.cc
+++ b/content/browser/devtools/devtools_instrumentation.cc
@@ -750,6 +750,9 @@
protocol::String BuildBlockedByResponseReason(
network::mojom::BlockedByResponseReason reason) {
+ // TODO(crbug.com/336752983):
+ // Add specific error messages when a subresource load was blocked due to
+ // Document-Isolation-Policy (Dip).
switch (reason) {
case network::mojom::BlockedByResponseReason::
kCoepFrameResourceNeedsCoepHeader:
@@ -763,6 +766,10 @@
return protocol::Audits::BlockedByResponseReasonEnum::CorpNotSameOrigin;
case network::mojom::BlockedByResponseReason::
kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
+ case network::mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+ case network::mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
return protocol::Audits::BlockedByResponseReasonEnum::
CorpNotSameOriginAfterDefaultedToSameOriginByCoep;
case network::mojom::BlockedByResponseReason::kCorpNotSameSite:
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 2df1eadd..24143d6a 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -2203,6 +2203,14 @@
kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
return protocol::Network::BlockedReasonEnum::
CorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+ case blink::ResourceRequestBlockedReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+ return protocol::Network::BlockedReasonEnum::
+ CorpNotSameOriginAfterDefaultedToSameOriginByDip;
+ case blink::ResourceRequestBlockedReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+ return protocol::Network::BlockedReasonEnum::
+ CorpNotSameOriginAfterDefaultedToSameOriginByCoep;
case blink::ResourceRequestBlockedReason::kCorpNotSameSite:
return protocol::Network::BlockedReasonEnum::CorpNotSameSite;
case blink::ResourceRequestBlockedReason::kConversionRequest:
@@ -2233,6 +2241,14 @@
kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
return {protocol::Network::BlockedReasonEnum::
CorpNotSameOriginAfterDefaultedToSameOriginByCoep};
+ case network::mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+ return {protocol::Network::BlockedReasonEnum::
+ CorpNotSameOriginAfterDefaultedToSameOriginByDip};
+ case network::mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+ return {protocol::Network::BlockedReasonEnum::
+ CorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip};
case network::mojom::BlockedByResponseReason::kCorpNotSameOrigin:
return {protocol::Network::BlockedReasonEnum::CorpNotSameOrigin};
case network::mojom::BlockedByResponseReason::kCorpNotSameSite:
diff --git a/content/browser/interest_group/interest_group_auction_reporter_unittest.cc b/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
index 432a203..ede5054 100644
--- a/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
+++ b/content/browser/interest_group/interest_group_auction_reporter_unittest.cc
@@ -671,7 +671,8 @@
/*is_web_secure_context=*/true,
/*ip_address_space=*/network::mojom::IPAddressSpace::kPublic,
/*is_web_secure_context=*/
- network::mojom::PrivateNetworkRequestPolicy::kBlock)};
+ network::mojom::PrivateNetworkRequestPolicy::kBlock,
+ network::DocumentIsolationPolicy())};
const GURL kSellerReportUrl =
GURL("https://seller.report.test/seller-report");
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index d57ed03..3525873 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -9287,7 +9287,8 @@
return network::mojom::ClientSecurityState::New(
policies.cross_origin_embedder_policy, policies.is_web_secure_context,
- policies.ip_address_space, private_network_request_policy_);
+ policies.ip_address_space, private_network_request_policy_,
+ policies.document_isolation_policy);
}
std::string NavigationRequest::GetUserAgentOverride() {
diff --git a/content/browser/renderer_host/private_network_access_util.cc b/content/browser/renderer_host/private_network_access_util.cc
index 69abce5..888d8be 100644
--- a/content/browser/renderer_host/private_network_access_util.cc
+++ b/content/browser/renderer_host/private_network_access_util.cc
@@ -179,7 +179,8 @@
policies.cross_origin_embedder_policy, policies.is_web_secure_context,
policies.ip_address_space,
DerivePrivateNetworkRequestPolicy(policies,
- private_network_request_context));
+ private_network_request_context),
+ policies.document_isolation_policy);
}
// Special chrome schemes cannot directly be categorized in public/private/local
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index a856842..3e4e84d 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -13148,18 +13148,22 @@
// Omitted: reporting endpoint, report-only value and reporting endpoint.
network::CrossOriginEmbedderPolicy coep;
coep.value = network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
+ network::DocumentIsolationPolicy dip;
+ dip.value =
+ network::mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp;
return network::mojom::ClientSecurityState::New(
std::move(coep),
/*is_web_secure_context=*/false,
network::mojom::IPAddressSpace::kUnknown,
- network::mojom::PrivateNetworkRequestPolicy::kBlock);
+ network::mojom::PrivateNetworkRequestPolicy::kBlock, std::move(dip));
}
const PolicyContainerPolicies& policies = policy_container_host_->policies();
return network::mojom::ClientSecurityState::New(
policies.cross_origin_embedder_policy, policies.is_web_secure_context,
- policies.ip_address_space, private_network_request_policy_);
+ policies.ip_address_space, private_network_request_policy_,
+ policies.document_isolation_policy);
}
network::mojom::ClientSecurityStatePtr
diff --git a/content/browser/service_worker/service_worker_register_job.cc b/content/browser/service_worker/service_worker_register_job.cc
index 17bfa7e..7918618 100644
--- a/content/browser/service_worker/service_worker_register_job.cc
+++ b/content/browser/service_worker/service_worker_register_job.cc
@@ -509,7 +509,8 @@
creator_policy_container_policies_.ip_address_space,
DerivePrivateNetworkRequestPolicy(
creator_policy_container_policies_,
- PrivateNetworkRequestContext::kWorker)));
+ PrivateNetworkRequestContext::kWorker),
+ creator_policy_container_policies_.document_isolation_policy));
new_script_fetcher_ = std::make_unique<ServiceWorkerNewScriptFetcher>(
*context_, version, std::move(loader_factory),
@@ -613,7 +614,8 @@
creator_policy_container_policies_.ip_address_space,
DerivePrivateNetworkRequestPolicy(
creator_policy_container_policies_,
- PrivateNetworkRequestContext::kWorker)));
+ PrivateNetworkRequestContext::kWorker),
+ creator_policy_container_policies_.document_isolation_policy));
if (!loader_factory) {
// We can't continue with update checking appropriately without
// |loader_factory|. Null |loader_factory| means that the storage partition
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index d4577d4..cca2bea9 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -2076,7 +2076,8 @@
policies.ip_address_space,
DerivePrivateNetworkRequestPolicy(policies.ip_address_space,
policies.is_web_secure_context,
- PrivateNetworkRequestContext::kWorker));
+ PrivateNetworkRequestContext::kWorker),
+ policies.document_isolation_policy);
}
// static
diff --git a/content/browser/url_loader_factory_params_helper.cc b/content/browser/url_loader_factory_params_helper.cc
index 9c3e477d..6c54c2e3 100644
--- a/content/browser/url_loader_factory_params_helper.cc
+++ b/content/browser/url_loader_factory_params_helper.cc
@@ -324,12 +324,16 @@
/*top_frame_origin=*/tentative_origin, /*frame_origin=*/tentative_origin,
net::SiteForCookies::FromOrigin(tentative_origin));
+ // TODO(https://issues.chromium.org/issues/336754077):
+ // Support Document-Isolation-Policy in early hints headers instead of passing
+ // a default DocumentIsolationPolicy.
network::mojom::ClientSecurityStatePtr client_security_state =
network::mojom::ClientSecurityState::New(
early_hints.headers->cross_origin_embedder_policy,
network::IsOriginPotentiallyTrustworthy(tentative_origin),
early_hints.ip_address_space,
- network::mojom::PrivateNetworkRequestPolicy::kBlock);
+ network::mojom::PrivateNetworkRequestPolicy::kBlock,
+ network::DocumentIsolationPolicy());
return CreateParams(
process, /*origin=*/tentative_origin,
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc
index e3eee99a..e22ca62 100644
--- a/content/browser/worker_host/shared_worker_host.cc
+++ b/content/browser/worker_host/shared_worker_host.cc
@@ -44,6 +44,7 @@
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/cpp/cross_origin_embedder_policy.h"
+#include "services/network/public/cpp/document_isolation_policy.h"
#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "services/network/public/mojom/client_security_state.mojom-shared.h"
#include "services/network/public/mojom/ip_address_space.mojom-shared.h"
@@ -239,7 +240,10 @@
network::CrossOriginEmbedderPolicy(
network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp),
/*is_web_secure_context=*/false,
- network::mojom::IPAddressSpace::kUnknown, policy);
+ network::mojom::IPAddressSpace::kUnknown, policy,
+ network::DocumentIsolationPolicy(
+ network::mojom::DocumentIsolationPolicyValue::
+ kIsolateAndRequireCorp));
}
policy_container_host = std::move(creator_policy_container_host_);
diff --git a/services/network/network_service_memory_cache.cc b/services/network/network_service_memory_cache.cc
index 290ec52..6e60118b 100644
--- a/services/network/network_service_memory_cache.cc
+++ b/services/network/network_service_memory_cache.cc
@@ -31,6 +31,7 @@
#include "services/network/network_service_memory_cache_writer.h"
#include "services/network/private_network_access_checker.h"
#include "services/network/public/cpp/cross_origin_resource_policy.h"
+#include "services/network/public/cpp/document_isolation_policy.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/orb/orb_api.h"
#include "services/network/public/cpp/private_network_access_check_result.h"
@@ -453,12 +454,17 @@
const mojom::URLResponseHeadPtr& response = it->second->response_head;
+ DocumentIsolationPolicy document_isolation_policy;
+ if (factory_client_security_state) {
+ document_isolation_policy =
+ factory_client_security_state->document_isolation_policy;
+ }
std::optional<mojom::BlockedByResponseReason> blocked_reason =
CrossOriginResourcePolicy::IsBlocked(
/*request_url=*/url, /*original_url=*/url,
resource_request.request_initiator, *response, resource_request.mode,
resource_request.destination, cross_origin_embedder_policy,
- /*reporter=*/nullptr);
+ /*reporter=*/nullptr, document_isolation_policy);
if (blocked_reason.has_value())
return std::nullopt;
diff --git a/services/network/public/cpp/cross_origin_resource_policy.cc b/services/network/public/cpp/cross_origin_resource_policy.cc
index c0af585..9ce952b 100644
--- a/services/network/public/cpp/cross_origin_resource_policy.cc
+++ b/services/network/public/cpp/cross_origin_resource_policy.cc
@@ -9,9 +9,11 @@
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/http/http_response_headers.h"
#include "services/network/public/cpp/cross_origin_embedder_policy.h"
+#include "services/network/public/cpp/document_isolation_policy.h"
#include "services/network/public/cpp/initiator_lock_compatibility.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
#include "services/network/public/mojom/cross_origin_embedder_policy.mojom.h"
+#include "services/network/public/mojom/document_isolation_policy.mojom-forward.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -109,35 +111,55 @@
const std::optional<url::Origin>& request_initiator,
mojom::RequestMode request_mode,
bool request_include_credentials,
- mojom::CrossOriginEmbedderPolicyValue embedder_policy) {
+ mojom::CrossOriginEmbedderPolicyValue embedder_policy,
+ mojom::DocumentIsolationPolicyValue document_isolation_policy) {
// Browser-initiated requests are not subject to Cross-Origin-Resource-Policy.
if (!request_initiator.has_value())
return std::nullopt;
const url::Origin& initiator = request_initiator.value();
- bool require_corp;
+ bool require_corp_due_to_coep;
switch (embedder_policy) {
case mojom::CrossOriginEmbedderPolicyValue::kNone:
- require_corp = false;
+ require_corp_due_to_coep = false;
break;
case mojom::CrossOriginEmbedderPolicyValue::kCredentialless:
- require_corp = request_mode == mojom::RequestMode::kNavigate ||
- request_include_credentials;
+ require_corp_due_to_coep =
+ request_mode == mojom::RequestMode::kNavigate ||
+ request_include_credentials;
break;
case mojom::CrossOriginEmbedderPolicyValue::kRequireCorp:
- require_corp = true;
+ require_corp_due_to_coep = true;
+ break;
+ }
+
+ bool require_corp_due_to_dip;
+ switch (document_isolation_policy) {
+ case mojom::DocumentIsolationPolicyValue::kNone:
+ require_corp_due_to_dip = false;
+ break;
+
+ case mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless:
+ require_corp_due_to_dip = request_mode == mojom::RequestMode::kNavigate ||
+ request_include_credentials;
+ break;
+
+ case mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp:
+ require_corp_due_to_dip = true;
break;
}
// COEP https://mikewest.github.io/corpp/#corp-check
- bool upgrade_to_same_origin = false;
+ bool upgrade_to_same_origin_due_to_coep = false;
+ bool upgrade_to_same_origin_due_to_dip = false;
if ((policy == CrossOriginResourcePolicy::kNoHeader ||
policy == CrossOriginResourcePolicy::kParsingError) &&
- require_corp) {
+ (require_corp_due_to_coep || require_corp_due_to_dip)) {
policy = CrossOriginResourcePolicy::kSameOrigin;
- upgrade_to_same_origin = true;
+ upgrade_to_same_origin_due_to_coep = require_corp_due_to_coep;
+ upgrade_to_same_origin_due_to_dip = require_corp_due_to_dip;
}
if (policy == CrossOriginResourcePolicy::kNoHeader ||
@@ -162,10 +184,22 @@
// From https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header:
// > 4. If policy is `same-origin`, then return blocked.
if (policy == CrossOriginResourcePolicy::kSameOrigin) {
- return upgrade_to_same_origin
- ? mojom::BlockedByResponseReason::
- kCorpNotSameOriginAfterDefaultedToSameOriginByCoep
- : mojom::BlockedByResponseReason::kCorpNotSameOrigin;
+ if (upgrade_to_same_origin_due_to_coep &&
+ upgrade_to_same_origin_due_to_dip) {
+ return mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip;
+ }
+
+ if (upgrade_to_same_origin_due_to_coep) {
+ return mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+ }
+
+ if (upgrade_to_same_origin_due_to_dip) {
+ return mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip;
+ }
+ return mojom::BlockedByResponseReason::kCorpNotSameOrigin;
}
// From https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header:
@@ -193,9 +227,12 @@
mojom::RequestDestination request_destination,
bool request_include_credentials,
const CrossOriginEmbedderPolicy& embedder_policy,
- mojom::CrossOriginEmbedderPolicyReporter* reporter) {
+ mojom::CrossOriginEmbedderPolicyReporter* reporter,
+ const DocumentIsolationPolicy& document_isolation_policy) {
constexpr auto kBlockedDueToCoep = mojom::BlockedByResponseReason::
kCorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+ constexpr auto kBlockedDueToCoepAndDip = mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip;
if ((embedder_policy.report_only_value ==
mojom::CrossOriginEmbedderPolicyValue::kRequireCorp ||
(embedder_policy.report_only_value ==
@@ -204,12 +241,17 @@
reporter) {
const auto result = IsBlockedInternal(
policy, request_url, request_initiator, request_mode,
- request_include_credentials, embedder_policy.report_only_value);
- if (result == kBlockedDueToCoep ||
+ request_include_credentials, embedder_policy.report_only_value,
+ document_isolation_policy.report_only_value);
+ if (result == kBlockedDueToCoep || result == kBlockedDueToCoepAndDip ||
(result.has_value() && request_mode == mojom::RequestMode::kNavigate)) {
reporter->QueueCorpViolationReport(original_url, request_destination,
/*report_only=*/true);
}
+
+ // TODO(https://issues.chromium.org/issues/333029815)
+ // Emit a report when Document-Isolation-Policy enforcement would block
+ // subresource load.
}
if (request_mode == mojom::RequestMode::kNavigate &&
@@ -219,13 +261,18 @@
const auto result =
IsBlockedInternal(policy, request_url, request_initiator, request_mode,
- request_include_credentials, embedder_policy.value);
+ request_include_credentials, embedder_policy.value,
+ document_isolation_policy.value);
if (reporter &&
- (result == kBlockedDueToCoep ||
+ (result == kBlockedDueToCoep || result == kBlockedDueToCoepAndDip ||
(result.has_value() && request_mode == mojom::RequestMode::kNavigate))) {
reporter->QueueCorpViolationReport(original_url, request_destination,
/*report_only=*/false);
}
+
+ // TODO(https://issues.chromium.org/issues/333029815)
+ // Emit a report when Document-Isolation-Policy enforcement blocks
+ // subresource load.
return result;
}
@@ -245,7 +292,8 @@
mojom::RequestMode request_mode,
mojom::RequestDestination request_destination,
const CrossOriginEmbedderPolicy& embedder_policy,
- mojom::CrossOriginEmbedderPolicyReporter* reporter) {
+ mojom::CrossOriginEmbedderPolicyReporter* reporter,
+ const DocumentIsolationPolicy& document_isolation_policy) {
// From https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header:
// > 1. If request’s mode is not "no-cors", then return allowed.
if (request_mode != mojom::RequestMode::kNoCors)
@@ -264,7 +312,7 @@
return IsBlockedInternalWithReporting(
policy, request_url, original_url, request_initiator, request_mode,
request_destination, response.request_include_credentials,
- embedder_policy, reporter);
+ embedder_policy, reporter, document_isolation_policy);
}
// static
@@ -278,7 +326,8 @@
mojom::RequestDestination request_destination,
bool request_include_credentials,
const CrossOriginEmbedderPolicy& embedder_policy,
- mojom::CrossOriginEmbedderPolicyReporter* reporter) {
+ mojom::CrossOriginEmbedderPolicyReporter* reporter,
+ const DocumentIsolationPolicy& document_isolation_policy) {
// From https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header:
// > 1. If request’s mode is not "no-cors", then return allowed.
if (request_mode != mojom::RequestMode::kNoCors)
@@ -289,7 +338,7 @@
return IsBlockedInternalWithReporting(
policy, request_url, original_url, request_initiator, request_mode,
request_destination, request_include_credentials, embedder_policy,
- reporter);
+ reporter, document_isolation_policy);
}
// static
@@ -308,7 +357,8 @@
return IsBlockedInternalWithReporting(
policy, request_url, original_url, request_initiator,
mojom::RequestMode::kNavigate, request_destination,
- response.request_include_credentials, embedder_policy, reporter);
+ response.request_include_credentials, embedder_policy, reporter,
+ DocumentIsolationPolicy());
}
// static
diff --git a/services/network/public/cpp/cross_origin_resource_policy.h b/services/network/public/cpp/cross_origin_resource_policy.h
index e9539a35..e967582 100644
--- a/services/network/public/cpp/cross_origin_resource_policy.h
+++ b/services/network/public/cpp/cross_origin_resource_policy.h
@@ -23,6 +23,7 @@
namespace network {
struct CrossOriginEmbedderPolicy;
+struct DocumentIsolationPolicy;
// Implementation of Cross-Origin-Resource-Policy - see:
// - https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header
@@ -52,20 +53,23 @@
mojom::RequestMode request_mode,
mojom::RequestDestination request_destination,
const CrossOriginEmbedderPolicy& embedder_policy,
- mojom::CrossOriginEmbedderPolicyReporter* reporter);
+ mojom::CrossOriginEmbedderPolicyReporter* reporter,
+ const DocumentIsolationPolicy& document_isolation_policy);
// Same as IsBlocked(), but this method can take a raw value of
// Cross-Origin-Resource-Policy header instead of using a URLResponseHead.
[[nodiscard]] static std::optional<mojom::BlockedByResponseReason>
- IsBlockedByHeaderValue(const GURL& request_url,
- const GURL& original_url,
- const std::optional<url::Origin>& request_initiator,
- std::optional<std::string> corp_header_value,
- mojom::RequestMode request_mode,
- mojom::RequestDestination request_destination,
- bool request_include_credentials,
- const CrossOriginEmbedderPolicy& embedder_policy,
- mojom::CrossOriginEmbedderPolicyReporter* reporter);
+ IsBlockedByHeaderValue(
+ const GURL& request_url,
+ const GURL& original_url,
+ const std::optional<url::Origin>& request_initiator,
+ std::optional<std::string> corp_header_value,
+ mojom::RequestMode request_mode,
+ mojom::RequestDestination request_destination,
+ bool request_include_credentials,
+ const CrossOriginEmbedderPolicy& embedder_policy,
+ mojom::CrossOriginEmbedderPolicyReporter* reporter,
+ const DocumentIsolationPolicy& document_isolation_policy);
// The CORP check for navigation requests. This is expected to be called
// from the navigation algorithm.
diff --git a/services/network/public/cpp/cross_origin_resource_policy_unittest.cc b/services/network/public/cpp/cross_origin_resource_policy_unittest.cc
index 23e1659..68b32b9 100644
--- a/services/network/public/cpp/cross_origin_resource_policy_unittest.cc
+++ b/services/network/public/cpp/cross_origin_resource_policy_unittest.cc
@@ -157,7 +157,52 @@
EXPECT_FALSE(ShouldAllowSameSite("http://127.0.0.1", "http://127.0.0.1"));
}
-TEST(CrossOriginResourcePolicyTest, WithCOEP) {
+void CheckCORP(mojom::RequestMode request_mode,
+ const url::Origin& origin,
+ mojom::URLResponseHeadPtr response_info,
+ const CrossOriginEmbedderPolicy& coep,
+ const DocumentIsolationPolicy& dip,
+ std::optional<mojom::BlockedByResponseReason> expected_result,
+ bool expect_coep_report,
+ bool expect_coep_report_only) {
+ using mojom::RequestDestination;
+ const GURL original_url("https://original.example.com/x/y");
+ const GURL final_url("https://www.example.com/z/u");
+ TestCoepReporter reporter;
+ EXPECT_EQ(expected_result,
+ CrossOriginResourcePolicy::IsBlocked(
+ final_url, original_url, origin, *response_info, request_mode,
+ RequestDestination::kImage, coep, &reporter, dip));
+ if (expect_coep_report && expect_coep_report_only) {
+ ASSERT_EQ(2u, reporter.reports().size());
+ EXPECT_TRUE(reporter.reports()[0].report_only);
+ EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
+ EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kImage);
+ EXPECT_FALSE(reporter.reports()[1].report_only);
+ EXPECT_EQ(reporter.reports()[1].blocked_url, original_url);
+ EXPECT_EQ(reporter.reports()[1].destination, RequestDestination::kImage);
+ } else if (expect_coep_report) {
+ ASSERT_EQ(1u, reporter.reports().size());
+ EXPECT_FALSE(reporter.reports()[0].report_only);
+ EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
+ EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kImage);
+ } else if (expect_coep_report_only) {
+ ASSERT_EQ(1u, reporter.reports().size());
+ EXPECT_TRUE(reporter.reports()[0].report_only);
+ EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
+ EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kImage);
+ } else {
+ EXPECT_TRUE(reporter.reports().empty());
+ }
+}
+
+void RunCORPTestWithCOEPAndDIP(
+ const CrossOriginEmbedderPolicy& coep,
+ const DocumentIsolationPolicy& dip,
+ std::optional<mojom::BlockedByResponseReason> expected_result,
+ bool include_credentials,
+ bool expect_coep_report,
+ bool expect_coep_report_only) {
mojom::URLResponseHead corp_none;
mojom::URLResponseHead corp_same_origin;
mojom::URLResponseHead corp_cross_origin;
@@ -172,182 +217,432 @@
"HTTP/1.1 200 OK\n"
"cross-origin-resource-policy: cross-origin\n"));
- const GURL original_url("https://original.example.com/x/y");
- const GURL final_url("https://www.example.com/z/u");
+ corp_none.request_include_credentials = include_credentials;
+ corp_same_origin.request_include_credentials = include_credentials;
+ corp_cross_origin.request_include_credentials = include_credentials;
+
+ constexpr auto kAllow = std::nullopt;
+ using mojom::RequestMode;
url::Origin destination_origin =
url::Origin::Create(GURL("https://www.example.com"));
url::Origin another_origin =
url::Origin::Create(GURL("https://www2.example.com"));
+ // First check that COEP and DIP do not affect the following test cases.
+
+ // 1. Responses with "cross-origin-resource-policy: same-origin" are always
+ // blocked when requested cross-origin.
+ CheckCORP(RequestMode::kNoCors, another_origin, corp_same_origin.Clone(),
+ coep, dip, mojom::BlockedByResponseReason::kCorpNotSameOrigin,
+ false, false);
+
+ // 2. Responses with "cross-origin-resource-policy: cross-origin" are always
+ // allowed.
+ CheckCORP(RequestMode::kNoCors, another_origin, corp_cross_origin.Clone(),
+ coep, dip, kAllow, false, false);
+
+ // 3. Same-origin responses are always allowed.
+ CheckCORP(RequestMode::kNoCors, destination_origin, corp_same_origin.Clone(),
+ coep, dip, kAllow, false, false);
+
+ // 4. Requests whose mode is "cors" are always allowed.
+ CheckCORP(RequestMode::kCors, another_origin, corp_same_origin.Clone(), coep,
+ dip, kAllow, false, false);
+
+ // Now check that a cross-origin request without a CORP header behaves as
+ // expected.
+ CheckCORP(RequestMode::kNoCors, another_origin, corp_none.Clone(), coep, dip,
+ expected_result, expect_coep_report, expect_coep_report_only);
+}
+
+TEST(CrossOriginResourcePolicyTest, WithCOEP) {
constexpr auto kAllow = std::nullopt;
- using mojom::RequestDestination;
- using mojom::RequestMode;
struct TestCase {
- const RequestMode request_mode;
- const url::Origin origin;
- mojom::URLResponseHeadPtr response_info;
- const std::optional<mojom::BlockedByResponseReason>
- expectation_with_coep_none;
- const std::optional<mojom::BlockedByResponseReason>
- expectation_with_coep_require_corp;
- const std::optional<mojom::BlockedByResponseReason>
- expectation_with_coep_credentialless;
+ mojom::CrossOriginEmbedderPolicyValue coep_value;
+ mojom::CrossOriginEmbedderPolicyValue coep_report_only_value;
+ const std::optional<mojom::BlockedByResponseReason> expected_result;
+ bool expect_coep_report;
+ bool expect_coep_report_only;
} test_cases[] = {
- // We don't have a cross-origin-resource-policy header on a response. That
- // leads to blocking when COEP: kRequireCorp is used.
- {RequestMode::kNoCors, another_origin, corp_none.Clone(), kAllow,
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kNone, kAllow, false, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kNone,
mojom::BlockedByResponseReason::
kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kNone,
mojom::BlockedByResponseReason::
- kCorpNotSameOriginAfterDefaultedToSameOriginByCoep},
- // We have "cross-origin-resource-policy: same-origin", so regardless of
- // COEP the response is blocked.
- {RequestMode::kNoCors, another_origin, corp_same_origin.Clone(),
- mojom::BlockedByResponseReason::kCorpNotSameOrigin,
- mojom::BlockedByResponseReason::kCorpNotSameOrigin,
- mojom::BlockedByResponseReason::kCorpNotSameOrigin},
- // We have "cross-origin-resource-policy: cross-origin", so regardless of
- // COEP the response is allowed.
- {RequestMode::kNoCors, another_origin, corp_cross_origin.Clone(), kAllow,
- kAllow, kAllow},
- // The origin of the request URL and request's origin match, so regardless
- // of COEP the response is allowed.
- {RequestMode::kNoCors, destination_origin, corp_same_origin.Clone(),
- kAllow, kAllow, kAllow},
- // The request mode is "cors", so so regardless of COEP the response is
- // allowed.
- {RequestMode::kCors, another_origin, corp_same_origin.Clone(), kAllow,
- kAllow, kAllow},
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp, kAllow, false,
+ true},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ true, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ true, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless, kAllow, false,
+ false},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ true, false},
};
for (const auto& test_case : test_cases) {
- TestCoepReporter reporter;
- CrossOriginEmbedderPolicy embedder_policy;
- const bool should_be_blocked_due_to_coep =
- (test_case.expectation_with_coep_none !=
- test_case.expectation_with_coep_require_corp);
+ CrossOriginEmbedderPolicy coep;
+ coep.value = test_case.coep_value;
+ coep.report_only_value = test_case.coep_report_only_value;
+ DocumentIsolationPolicy dip;
+ RunCORPTestWithCOEPAndDIP(
+ coep, dip, test_case.expected_result, true /*include_credentials*/,
+ test_case.expect_coep_report, test_case.expect_coep_report_only);
+ }
+}
- // COEP: none, COEP-report-only: none
- EXPECT_EQ(test_case.expectation_with_coep_none,
- CrossOriginResourcePolicy::IsBlocked(
- final_url, original_url, test_case.origin,
- *test_case.response_info, test_case.request_mode,
- RequestDestination::kImage, embedder_policy, &reporter));
+TEST(CrossOriginResourcePolicyTest, WithCOEPNoCredentials) {
+ constexpr auto kAllow = std::nullopt;
- EXPECT_TRUE(reporter.reports().empty());
+ struct TestCase {
+ mojom::CrossOriginEmbedderPolicyValue coep_value;
+ mojom::CrossOriginEmbedderPolicyValue coep_report_only_value;
+ const std::optional<mojom::BlockedByResponseReason> expected_result;
+ bool expect_coep_report;
+ bool expect_coep_report_only;
+ } test_cases[] = {
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kNone, kAllow, false, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kNone, kAllow, false, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp, kAllow, false,
+ true},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ true, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp, kAllow, false,
+ true},
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless, kAllow, false,
+ false},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless, kAllow, false,
+ false},
+ };
- reporter.ClearReports();
- // COEP: require-corp, COEP-report-only: none
- embedder_policy.value = mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
- EXPECT_EQ(test_case.expectation_with_coep_require_corp,
- CrossOriginResourcePolicy::IsBlocked(
- final_url, original_url, test_case.origin,
- *test_case.response_info, test_case.request_mode,
- RequestDestination::kImage, embedder_policy, &reporter));
- if (should_be_blocked_due_to_coep) {
- ASSERT_EQ(1u, reporter.reports().size());
- EXPECT_FALSE(reporter.reports()[0].report_only);
- EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
- EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kImage);
- } else {
- EXPECT_TRUE(reporter.reports().empty());
- }
+ for (const auto& test_case : test_cases) {
+ CrossOriginEmbedderPolicy coep;
+ coep.value = test_case.coep_value;
+ coep.report_only_value = test_case.coep_report_only_value;
+ DocumentIsolationPolicy dip;
+ RunCORPTestWithCOEPAndDIP(
+ coep, dip, test_case.expected_result, false /*include_credentials*/,
+ test_case.expect_coep_report, test_case.expect_coep_report_only);
+ }
+}
- reporter.ClearReports();
- // COEP: none, COEP-report-only: require-corp
- embedder_policy.value = mojom::CrossOriginEmbedderPolicyValue::kNone;
- embedder_policy.report_only_value =
- mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
- EXPECT_EQ(test_case.expectation_with_coep_none,
- CrossOriginResourcePolicy::IsBlocked(
- final_url, original_url, test_case.origin,
- *test_case.response_info, test_case.request_mode,
- RequestDestination::kScript, embedder_policy, &reporter));
- if (should_be_blocked_due_to_coep) {
- ASSERT_EQ(1u, reporter.reports().size());
- EXPECT_TRUE(reporter.reports()[0].report_only);
- EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
- EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kScript);
- } else {
- EXPECT_TRUE(reporter.reports().empty());
- }
+TEST(CrossOriginResourcePolicyTest, WithDIP) {
+ constexpr auto kAllow = std::nullopt;
- reporter.ClearReports();
- // COEP: require-corp, COEP-report-only: require-corp
- embedder_policy.value = mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
- embedder_policy.report_only_value =
- mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
- EXPECT_EQ(test_case.expectation_with_coep_require_corp,
- CrossOriginResourcePolicy::IsBlocked(
- final_url, original_url, test_case.origin,
- *test_case.response_info, test_case.request_mode,
- RequestDestination::kEmpty, embedder_policy, &reporter));
- if (should_be_blocked_due_to_coep) {
- ASSERT_EQ(2u, reporter.reports().size());
- EXPECT_TRUE(reporter.reports()[0].report_only);
- EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
- EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kEmpty);
- EXPECT_FALSE(reporter.reports()[1].report_only);
- EXPECT_EQ(reporter.reports()[1].blocked_url, original_url);
- EXPECT_EQ(reporter.reports()[1].destination, RequestDestination::kEmpty);
- } else {
- EXPECT_TRUE(reporter.reports().empty());
- }
+ struct TestCase {
+ mojom::DocumentIsolationPolicyValue dip_value;
+ const std::optional<mojom::BlockedByResponseReason> expected_result;
+ } test_cases[] = {
+ {mojom::DocumentIsolationPolicyValue::kNone, kAllow},
+ {mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip},
+ {mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip},
+ };
- reporter.ClearReports();
- // COEP: credentialless, COEP-report-only: none
- embedder_policy.value =
- mojom::CrossOriginEmbedderPolicyValue::kCredentialless;
- EXPECT_EQ(test_case.expectation_with_coep_credentialless,
- CrossOriginResourcePolicy::IsBlocked(
- final_url, original_url, test_case.origin,
- *test_case.response_info, test_case.request_mode,
- RequestDestination::kImage, embedder_policy, &reporter));
- if (should_be_blocked_due_to_coep) {
- ASSERT_EQ(2u, reporter.reports().size());
- EXPECT_TRUE(reporter.reports()[0].report_only);
- EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
- EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kImage);
- EXPECT_FALSE(reporter.reports()[1].report_only);
- EXPECT_EQ(reporter.reports()[1].blocked_url, original_url);
- EXPECT_EQ(reporter.reports()[1].destination, RequestDestination::kImage);
- } else {
- EXPECT_TRUE(reporter.reports().empty());
- }
+ for (const auto& test_case : test_cases) {
+ CrossOriginEmbedderPolicy coep;
+ DocumentIsolationPolicy dip(test_case.dip_value);
+ RunCORPTestWithCOEPAndDIP(
+ coep, dip, test_case.expected_result, true /*include_credentials*/,
+ false /*expect_coep_report*/, false /*expect_coep_report_only*/);
+ }
+}
- reporter.ClearReports();
- // COEP: none, COEP-report-only: credentialless
- embedder_policy.value = mojom::CrossOriginEmbedderPolicyValue::kNone;
- embedder_policy.report_only_value =
- mojom::CrossOriginEmbedderPolicyValue::kCredentialless;
- EXPECT_EQ(test_case.expectation_with_coep_none,
- CrossOriginResourcePolicy::IsBlocked(
- final_url, original_url, test_case.origin,
- *test_case.response_info, test_case.request_mode,
- RequestDestination::kScript, embedder_policy, &reporter));
- EXPECT_TRUE(reporter.reports().empty());
+TEST(CrossOriginResourcePolicyTest, WithDIPNoCredentials) {
+ constexpr auto kAllow = std::nullopt;
- reporter.ClearReports();
- // COEP: credentialless, COEP-report-only: credentialless
- embedder_policy.value =
- mojom::CrossOriginEmbedderPolicyValue::kCredentialless;
- embedder_policy.report_only_value =
- mojom::CrossOriginEmbedderPolicyValue::kCredentialless;
- EXPECT_EQ(test_case.expectation_with_coep_credentialless,
- CrossOriginResourcePolicy::IsBlocked(
- final_url, original_url, test_case.origin,
- *test_case.response_info, test_case.request_mode,
- RequestDestination::kEmpty, embedder_policy, &reporter));
- if (should_be_blocked_due_to_coep) {
- ASSERT_EQ(1u, reporter.reports().size());
- EXPECT_FALSE(reporter.reports()[0].report_only);
- EXPECT_EQ(reporter.reports()[0].blocked_url, original_url);
- EXPECT_EQ(reporter.reports()[0].destination, RequestDestination::kEmpty);
- } else {
- EXPECT_TRUE(reporter.reports().empty());
- }
+ struct TestCase {
+ mojom::DocumentIsolationPolicyValue dip_value;
+ const std::optional<mojom::BlockedByResponseReason> expected_result;
+ } test_cases[] = {
+ {mojom::DocumentIsolationPolicyValue::kNone, kAllow},
+ {mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip},
+ {mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless, kAllow},
+ };
+
+ for (const auto& test_case : test_cases) {
+ CrossOriginEmbedderPolicy coep;
+ DocumentIsolationPolicy dip(test_case.dip_value);
+ RunCORPTestWithCOEPAndDIP(
+ coep, dip, test_case.expected_result, false /*include_credentials*/,
+ false /*expect_coep_report*/, false /*expect_coep_report_only*/);
+ }
+}
+
+TEST(CrossOriginResourcePolicyTest, WithCOEPAndDIP) {
+ struct TestCase {
+ mojom::CrossOriginEmbedderPolicyValue coep_value;
+ mojom::CrossOriginEmbedderPolicyValue coep_report_only_value;
+ mojom::DocumentIsolationPolicyValue dip_value;
+ const std::optional<mojom::BlockedByResponseReason> expected_result;
+ bool expect_coep_report;
+ bool expect_coep_report_only;
+ } test_cases[] = {
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+ false, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+ false, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+ false, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+ false, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, false},
+ };
+
+ for (const auto& test_case : test_cases) {
+ CrossOriginEmbedderPolicy coep;
+ coep.value = test_case.coep_value;
+ coep.report_only_value = test_case.coep_report_only_value;
+ DocumentIsolationPolicy dip(test_case.dip_value);
+ RunCORPTestWithCOEPAndDIP(
+ coep, dip, test_case.expected_result, true /*include_credentials*/,
+ test_case.expect_coep_report, test_case.expect_coep_report_only);
+ }
+}
+
+TEST(CrossOriginResourcePolicyTest, WithCOEPAndDIPNoCredentials) {
+ constexpr auto kAllow = std::nullopt;
+ struct TestCase {
+ mojom::CrossOriginEmbedderPolicyValue coep_value;
+ mojom::CrossOriginEmbedderPolicyValue coep_report_only_value;
+ mojom::DocumentIsolationPolicyValue dip_value;
+ const std::optional<mojom::BlockedByResponseReason> expected_result;
+ bool expect_coep_report;
+ bool expect_coep_report_only;
+ } test_cases[] = {
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+ false, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+ false, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+ false, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+ false, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+ false, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless, kAllow,
+ false, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless, kAllow,
+ false, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ true, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless, kAllow,
+ false, true},
+ {mojom::CrossOriginEmbedderPolicyValue::kNone,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless, kAllow,
+ false, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kRequireCorp,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless,
+ mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ true, false},
+ {mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::CrossOriginEmbedderPolicyValue::kCredentialless,
+ mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless, kAllow,
+ false, false},
+ };
+
+ for (const auto& test_case : test_cases) {
+ CrossOriginEmbedderPolicy coep;
+ coep.value = test_case.coep_value;
+ coep.report_only_value = test_case.coep_report_only_value;
+ DocumentIsolationPolicy dip(test_case.dip_value);
+ RunCORPTestWithCOEPAndDIP(
+ coep, dip, test_case.expected_result, false /*include_credentials*/,
+ test_case.expect_coep_report, test_case.expect_coep_report_only);
}
}
@@ -549,4 +844,5 @@
}
}
}
+
} // namespace network
diff --git a/services/network/public/mojom/blocked_by_response_reason.mojom b/services/network/public/mojom/blocked_by_response_reason.mojom
index 6f8d57a..5485a02 100644
--- a/services/network/public/mojom/blocked_by_response_reason.mojom
+++ b/services/network/public/mojom/blocked_by_response_reason.mojom
@@ -12,5 +12,7 @@
kCoopSandboxedIFrameCannotNavigateToCoopPage,
kCorpNotSameOrigin,
kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
kCorpNotSameSite,
};
diff --git a/services/network/public/mojom/client_security_state.mojom b/services/network/public/mojom/client_security_state.mojom
index 9bd7c41a..3f828835 100644
--- a/services/network/public/mojom/client_security_state.mojom
+++ b/services/network/public/mojom/client_security_state.mojom
@@ -5,6 +5,7 @@
module network.mojom;
import "services/network/public/mojom/cross_origin_embedder_policy.mojom";
+import "services/network/public/mojom/document_isolation_policy.mojom";
import "services/network/public/mojom/ip_address_space.mojom";
// How to treat private network requests.
@@ -52,5 +53,8 @@
// The policy to apply to private network requests.
PrivateNetworkRequestPolicy private_network_request_policy = kAllow;
+
+ // See: https://github.com/explainers-by-googlers/document-isolation-policy
+ DocumentIsolationPolicy document_isolation_policy;
};
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index fa66c32..f5ee349 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -1453,19 +1453,23 @@
if (memory_cache_)
memory_cache_->OnRedirect(url_request_.get(), request_destination_);
- const CrossOriginEmbedderPolicy kEmpty;
// Enforce the Cross-Origin-Resource-Policy (CORP) header.
+ const CrossOriginEmbedderPolicy kEmptyCoep;
const CrossOriginEmbedderPolicy& cross_origin_embedder_policy =
factory_params_->client_security_state
? factory_params_->client_security_state->cross_origin_embedder_policy
- : kEmpty;
-
+ : kEmptyCoep;
+ const DocumentIsolationPolicy kEmptyDip;
+ const DocumentIsolationPolicy& document_isolation_policy =
+ factory_params_->client_security_state
+ ? factory_params_->client_security_state->document_isolation_policy
+ : kEmptyDip;
if (std::optional<mojom::BlockedByResponseReason> blocked_reason =
CrossOriginResourcePolicy::IsBlocked(
url_request_->url(), url_request_->original_url(),
url_request_->initiator(), *response, request_mode_,
request_destination_, cross_origin_embedder_policy,
- coep_reporter_)) {
+ coep_reporter_, document_isolation_policy)) {
CompleteBlockedResponse(net::ERR_BLOCKED_BY_RESPONSE, false,
blocked_reason);
// TODO(crbug.com/40054032): Close the socket here.
@@ -1778,17 +1782,22 @@
}
// Enforce the Cross-Origin-Resource-Policy (CORP) header.
- const CrossOriginEmbedderPolicy kEmpty;
+ const CrossOriginEmbedderPolicy kEmptyCoep;
const CrossOriginEmbedderPolicy& cross_origin_embedder_policy =
factory_params_->client_security_state
? factory_params_->client_security_state->cross_origin_embedder_policy
- : kEmpty;
+ : kEmptyCoep;
+ const DocumentIsolationPolicy kEmptyDip;
+ const DocumentIsolationPolicy& document_isolation_policy =
+ factory_params_->client_security_state
+ ? factory_params_->client_security_state->document_isolation_policy
+ : kEmptyDip;
if (std::optional<mojom::BlockedByResponseReason> blocked_reason =
CrossOriginResourcePolicy::IsBlocked(
url_request_->url(), url_request_->original_url(),
url_request_->initiator(), *response_, request_mode_,
request_destination_, cross_origin_embedder_policy,
- coep_reporter_)) {
+ coep_reporter_, document_isolation_policy)) {
CompleteBlockedResponse(net::ERR_BLOCKED_BY_RESPONSE, false,
blocked_reason);
// Close the socket associated with the request, to prevent leaking
diff --git a/services/network/web_bundle/web_bundle_url_loader_factory.cc b/services/network/web_bundle/web_bundle_url_loader_factory.cc
index 9bdb248..0d83f7f 100644
--- a/services/network/web_bundle/web_bundle_url_loader_factory.cc
+++ b/services/network/web_bundle/web_bundle_url_loader_factory.cc
@@ -885,12 +885,17 @@
loader->SetBodyLength(payload_length);
// Enforce the Cross-Origin-Resource-Policy (CORP) header.
+ //
+ // TODO(crbug.com/333708501)
+ // Implement support for Document-Isolation-Policy in Web Bundles if needed,
+ // by passing a Document-Isolation-Policy at creation time and using it in the
+ // call below.
if (std::optional<mojom::BlockedByResponseReason> blocked_reason =
CrossOriginResourcePolicy::IsBlocked(
loader->url(), loader->url(), loader->request_initiator(),
*response_head, loader->request_mode(),
loader->request_destination(), cross_origin_embedder_policy_,
- coep_reporter_)) {
+ coep_reporter_, DocumentIsolationPolicy())) {
loader->CompleteBlockedResponse(net::ERR_BLOCKED_BY_RESPONSE,
blocked_reason);
return;
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 5475305..881625d 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -622,6 +622,8 @@
CoopSandboxedIFrameCannotNavigateToCoopPage
CorpNotSameOrigin
CorpNotSameOriginAfterDefaultedToSameOriginByCoep
+ CorpNotSameOriginAfterDefaultedToSameOriginByDip
+ CorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip
CorpNotSameSite
# Details for a request that has been blocked with the BLOCKED_BY_RESPONSE
@@ -5755,6 +5757,8 @@
coop-sandboxed-iframe-cannot-navigate-to-coop-page
corp-not-same-origin
corp-not-same-origin-after-defaulted-to-same-origin-by-coep
+ corp-not-same-origin-after-defaulted-to-same-origin-by-dip
+ corp-not-same-origin-after-defaulted-to-same-origin-by-coep-and-dip
corp-not-same-site
# The reason why request was blocked.
diff --git a/third_party/blink/public/platform/resource_request_blocked_reason.h b/third_party/blink/public/platform/resource_request_blocked_reason.h
index 601a8095..02310b1c 100644
--- a/third_party/blink/public/platform/resource_request_blocked_reason.h
+++ b/third_party/blink/public/platform/resource_request_blocked_reason.h
@@ -20,6 +20,8 @@
kCoopSandboxedIFrameCannotNavigateToCoopPage,
kCorpNotSameOrigin,
kCorpNotSameOriginAfterDefaultedToSameOriginByCoep,
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip,
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip,
kCorpNotSameSite,
kConversionRequest,
kSupervisedUserUrlBlocked,
diff --git a/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc b/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
index 27267c8cf..6d7b86c 100644
--- a/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_audits_issue.cc
@@ -319,6 +319,14 @@
kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
return protocol::Audits::BlockedByResponseReasonEnum::
CorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+ case network::mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+ return protocol::Audits::BlockedByResponseReasonEnum::
+ CorpNotSameOriginAfterDefaultedToSameOriginByDip;
+ case network::mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+ return protocol::Audits::BlockedByResponseReasonEnum::
+ CorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip;
case network::mojom::BlockedByResponseReason::kCorpNotSameSite:
return protocol::Audits::BlockedByResponseReasonEnum::CorpNotSameSite;
}
diff --git a/third_party/blink/renderer/core/inspector/inspector_issue_conversion.cc b/third_party/blink/renderer/core/inspector/inspector_issue_conversion.cc
index 68419e5b..aba69f9 100644
--- a/third_party/blink/renderer/core/inspector/inspector_issue_conversion.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_issue_conversion.cc
@@ -286,6 +286,14 @@
kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
return protocol::Audits::BlockedByResponseReasonEnum::
CorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+ case network::mojom::blink::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+ return protocol::Audits::BlockedByResponseReasonEnum::
+ CorpNotSameOriginAfterDefaultedToSameOriginByDip;
+ case network::mojom::blink::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+ return protocol::Audits::BlockedByResponseReasonEnum::
+ CorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip;
case network::mojom::blink::BlockedByResponseReason::kCorpNotSameSite:
return protocol::Audits::BlockedByResponseReasonEnum::CorpNotSameSite;
}
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
index da6f704..146f6fc 100644
--- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -419,6 +419,14 @@
kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
return protocol::Network::BlockedReasonEnum::
CorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+ case blink::ResourceRequestBlockedReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+ return protocol::Network::BlockedReasonEnum::
+ CorpNotSameOriginAfterDefaultedToSameOriginByDip;
+ case blink::ResourceRequestBlockedReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+ return protocol::Network::BlockedReasonEnum::
+ CorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip;
case blink::ResourceRequestBlockedReason::kCorpNotSameSite:
return protocol::Network::BlockedReasonEnum::CorpNotSameSite;
case ResourceRequestBlockedReason::kConversionRequest:
diff --git a/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc b/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc
index 359b8e4..dbb6c73 100644
--- a/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc
+++ b/third_party/blink/renderer/modules/service_worker/cross_origin_resource_policy_checker.cc
@@ -43,7 +43,8 @@
GURL(response.InternalURLList().front()), initiator_origin,
corp_header_value, request_mode, request_destination,
response.GetResponse()->RequestIncludeCredentials(), policy_,
- reporter_ ? reporter_.get() : nullptr)
+ reporter_ ? reporter_.get() : nullptr,
+ network::DocumentIsolationPolicy())
.has_value();
}
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_error.cc b/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
index f8af836..efce505 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
@@ -235,6 +235,14 @@
kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
return blink::ResourceRequestBlockedReason::
kCorpNotSameOriginAfterDefaultedToSameOriginByCoep;
+ case network::mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+ return blink::ResourceRequestBlockedReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip;
+ case network::mojom::BlockedByResponseReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+ return blink::ResourceRequestBlockedReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip;
case network::mojom::BlockedByResponseReason::kCorpNotSameSite:
return blink::ResourceRequestBlockedReason::kCorpNotSameSite;
}
@@ -314,6 +322,14 @@
kCorpNotSameOriginAfterDefaultedToSameOriginByCoep:
detail = "NotSameOriginAfterDefaultedToSameOriginByCoep";
break;
+ case ResourceRequestBlockedReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByDip:
+ detail = "NotSameOriginAfterDefaultedToSameOriginByDip";
+ break;
+ case ResourceRequestBlockedReason::
+ kCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:
+ detail = "NotSameOriginAfterDefaultedToSameOriginByCoepAndDip";
+ break;
case ResourceRequestBlockedReason::kCorpNotSameSite:
detail = "NotSameSite";
break;
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 07311ad7..b2096d57 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -3064,5 +3064,22 @@
"syg@chromium.org",
"samuelmaddock@electronjs.org"
]
+ },
+ {
+ "prefix": "document-isolation-policy",
+ "platforms": [
+ "Linux"
+ ],
+ "bases": [
+ "external/wpt/html/document-isolation-policy"
+ ],
+ "exclusive_tests": "ALL",
+ "args": [
+ "--enable-features=DocumentIsolationPolicy"
+ ],
+ "expires": "Nov 16, 2024",
+ "owners": [
+ "clamy@chromium.org"
+ ]
}
]
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/DIR_METADATA
new file mode 100644
index 0000000..ed39007
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "chrome-security-owp-team@google.com"
+buganizer_public: {
+ component_id: 1552691
+}
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/README.md b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/README.md
new file mode 100644
index 0000000..59f039e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/README.md
@@ -0,0 +1 @@
+This directory contains tests for `Document-Isolation-Policy`.
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/isolate-and-require-corp.tentative.https.html b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/isolate-and-require-corp.tentative.https.html
new file mode 100644
index 0000000..df4bd47
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/isolate-and-require-corp.tentative.https.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta name="timeout" content="long">
+<title>Document-Isolation-Policy: isolate-and-require-corp header and subresources</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script> <!-- Use token() to allow running tests in parallel -->
+<div id=log></div>
+<script>
+const HOST = get_host_info();
+const BASE = new URL("resources", location).pathname;
+
+promise_test(async t => {
+ const response = await fetch(get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-cross-origin-corp.js", {mode: "no-cors"});
+ assert_equals(response.type, "opaque");
+}, `"isolate-and-require-corp" top-level: fetch() to CORP: cross-origin response should succeed`);
+
+promise_test(async t => {
+ return promise_rejects_js(t, TypeError, fetch(get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js", {mode: "no-cors"}));
+}, `"isolate-and-require-corp" top-level: fetch() to cross-origin response without CORP should fail`);
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/isolate-and-require-corp.tentative.https.html.headers b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/isolate-and-require-corp.tentative.https.html.headers
new file mode 100644
index 0000000..bcc6f073
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/isolate-and-require-corp.tentative.https.html.headers
@@ -0,0 +1 @@
+Document-Isolation-Policy: isolate-and-require-corp
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/fetch-and-create-url.html b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/fetch-and-create-url.html
new file mode 100644
index 0000000..6b0f962
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/fetch-and-create-url.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Fetch and create Blob</title>
+<script>
+ async function responseToBlob(response) {
+ let blob;
+ try {
+ blob = await response.blob();
+ } catch (e) {
+ return { error: `blob error: ${e.name}` };
+ }
+
+ return { url: URL.createObjectURL(blob) };
+ }
+
+ async function responseToData(response) {
+ const mimeType = response.headers.get("content-type");
+
+ let text;
+ try {
+ text = await response.text();
+ } catch(e) {
+ return { error: `text error: ${e.name}` };
+ }
+
+ return { url: `data:${mimeType},${encodeURIComponent(text)}` };
+ }
+
+ async function responseToFilesystem(response) {
+ if (!window.webkitRequestFileSystem) {
+ return { error: "unimplemented" };
+ }
+
+ let blob;
+ try {
+ blob = await response.blob();
+ } catch (e) {
+ return { error: `blob error: ${e.name}` };
+ }
+
+ const fs = await new Promise(resolve => {
+ window.webkitRequestFileSystem(window.TEMPORARY, 1024*1024, resolve);
+ });
+
+ const file = await new Promise(resolve => {
+ fs.root.getFile('fetch-and-create-url', { create: true }, resolve);
+ });
+
+ const writer = await new Promise(resolve => file.createWriter(resolve));
+
+ try {
+ await new Promise((resolve, reject) => {
+ writer.onwriteend = resolve;
+ writer.onerror = reject;
+ writer.write(blob);
+ });
+ } catch (e) {
+ return { error: `file write error: ${e.name}` };
+ }
+
+ return { url: file.toURL() };
+ }
+
+ async function responseToScheme(response, scheme) {
+ switch (scheme) {
+ case "blob":
+ return responseToBlob(response);
+ case "data":
+ return responseToData(response);
+ case "filesystem":
+ return responseToFilesystem(response);
+ default:
+ return { error: `unknown scheme: ${scheme}` };
+ }
+ }
+
+ async function fetchToScheme(url, scheme) {
+ let response;
+ try {
+ response = await fetch(url);
+ } catch (e) {
+ return { error: `fetch error: ${e.name}` };
+ }
+
+ return responseToScheme(response, scheme);
+ }
+
+ const params = new URL(window.location).searchParams;
+ fetchToScheme(params.get("url"), params.get("scheme"))
+ .then((message) => { parent.postMessage(message, "*"); });
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-cross-origin-corp.js b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-cross-origin-corp.js
new file mode 100644
index 0000000..662e936
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-cross-origin-corp.js
@@ -0,0 +1 @@
+/* Just an empty JS file */
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-cross-origin-corp.js.headers b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-cross-origin-corp.js.headers
new file mode 100644
index 0000000..1b88136c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-cross-origin-corp.js.headers
@@ -0,0 +1 @@
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-no-corp.js b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-no-corp.js
new file mode 100644
index 0000000..662e936
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/nothing-no-corp.js
@@ -0,0 +1 @@
+/* Just an empty JS file */
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/shared-worker-fetch.js.py b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/shared-worker-fetch.js.py
new file mode 100644
index 0000000..bf46cd2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/shared-worker-fetch.js.py
@@ -0,0 +1,24 @@
+body = b'''
+'use strict';
+
+onconnect = (event) => {
+ const port = event.ports[0];
+
+ port.onmessage = (event) => {
+ fetch(event.data, { mode: 'no-cors' })
+ .then(
+ () => port.postMessage('success'),
+ () => port.postMessage('failure')
+ );
+ };
+
+ port.postMessage('ready');
+};'''
+
+def main(request, response):
+ headers = [(b'Content-Type', b'text/javascript')]
+
+ for value in request.GET.get_list(b'value'):
+ headers.append((b'Document-Isolation-Policy', value))
+
+ return (200, headers, body)
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/shared-worker.js b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/shared-worker.js
new file mode 100644
index 0000000..c5f2c3cc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/shared-worker.js
@@ -0,0 +1,7 @@
+onconnect = (event) => {
+ const port = event.ports[0];
+ port.onmessage = (event) => {
+ eval(event.data);
+ };
+ port.postMessage('ready');
+};
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/worker-support.js b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/worker-support.js
new file mode 100644
index 0000000..349b4eb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/resources/worker-support.js
@@ -0,0 +1,81 @@
+// Configures `url` such that the response carries a `COEP: ${value}` header.
+//
+// `url` must be a `URL` instance.
+function setDip(url, value) {
+ url.searchParams
+ .set("pipe", `header(document-isolation-policy,${value})`);
+}
+
+// Resolves the given `relativeUrl` relative to the current window's location.
+//
+// `options` can contain the following keys:
+//
+// - `dip`: value passed to `setDip()`, if present.
+// - `host`: overrides the host of the returned URL.
+//
+// Returns a `URL` instance.
+function resolveUrl(relativeUrl, options) {
+ const url = new URL(relativeUrl, window.location);
+
+ if (options !== undefined) {
+ const { dip, host } = options;
+ if (dip !== undefined) {
+ setDip(url, dip);
+ }
+ if (host !== undefined) {
+ url.host = host;
+ }
+ }
+
+ return url;
+}
+
+// Adds an iframe loaded from `url` to the current document, waiting for it to
+// load before returning.
+//
+// The returned iframe is removed from the document at the end of the test `t`.
+async function withIframe(t, url) {
+ const frame = document.createElement("iframe");
+ frame.src = url;
+
+ t.add_cleanup(() => frame.remove());
+
+ const loadedPromise = new Promise(resolve => {
+ frame.addEventListener('load', resolve, {once: true});
+ });
+ document.body.append(frame);
+ await loadedPromise;
+
+ return frame;
+}
+
+// Asynchronously waits for a single "message" event on the given `target`.
+function waitForMessage(target) {
+ return new Promise(resolve => {
+ target.addEventListener('message', resolve, {once: true});
+ });
+}
+
+// Fetches `url` from a document with DIP `creatorDip`, then serializes it
+// and returns a URL pointing to the fetched body with the given `scheme`.
+//
+// - `creatorDip` is passed to `setDip()`.
+// - `scheme` may be one of: "blob", "data" or "filesystem".
+//
+// The returned URL is valid until the end of the test `t`.
+async function createLocalUrl(t, { url, creatorDip, scheme }) {
+ const frameUrl = resolveUrl("resources/fetch-and-create-url.html", {
+ dip: creatorDip,
+ });
+ frameUrl.searchParams.set("url", url);
+ frameUrl.searchParams.set("scheme", scheme);
+
+ const messagePromise = waitForMessage(window);
+ const frame = await withIframe(t, frameUrl);
+
+ const evt = await messagePromise;
+ const message = evt.data;
+ assert_equals(message.error, undefined, "url creation error");
+
+ return message.url;
+}
diff --git a/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/shared-workers.tentative.https.html b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/shared-workers.tentative.https.html
new file mode 100644
index 0000000..d0a186f4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/document-isolation-policy/shared-workers.tentative.https.html
@@ -0,0 +1,235 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>COEP - policy derivation for Shared Workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/worker-support.js"></script>
+<body>
+<p>Verify the Document Isolation Policy for Shared Workers by performing a
+cross-origin "fetch" request for a resource that does not specify CORP. Only
+Shared Workers with the default DIP should be able to successfully perform
+this operation.</p>
+<script>
+'use strict';
+
+function makeWorkerUrl(options) {
+ return resolveUrl("resources/shared-worker-fetch.js.py", options);
+}
+
+/**
+ * Create a Shared Worker within an iframe
+ *
+ * @param {object} t - a testharness.js subtest instance (used to reset global
+ * state)
+ * @param {string} url - the URL from which the Shared Worker should be
+ * created
+ * @param {string} options.ownerDip - the Document Isolation Policy of the
+ iframe
+ */
+async function createWorker(t, url, options) {
+ const { ownerDip } = options || {};
+ const frameUrl = resolveUrl("/common/blank.html", { dip: ownerDip });
+
+ const iframe = await withIframe(t, frameUrl);
+
+ const sw = new iframe.contentWindow.SharedWorker(url);
+ sw.onerror = t.unreached_func('SharedWorker.onerror should not be called');
+
+ await new Promise((resolve) => {
+ sw.port.addEventListener('message', resolve, { once: true });
+ sw.port.start();
+ });
+
+ return sw;
+}
+
+/**
+ * Instruct a Shared Worker to fetch from a specified URL and report on the
+ * success of the operation.
+ *
+ * @param {SharedWorker} worker
+ * @param {string} url - the URL that the worker should fetch
+ */
+function fetchFromWorker(worker, url) {
+ return new Promise((resolve) => {
+ worker.port.postMessage(url);
+ worker.port.addEventListener(
+ 'message', (event) => resolve(event.data), { once: true }
+ );
+ });
+};
+
+promise_test(async (t) => {
+ const worker = await createWorker(t, makeWorkerUrl());
+ const result = await fetchFromWorker(worker,
+ get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+ assert_equals(result, 'success');
+}, 'default policy (derived from response)');
+
+promise_test(async (t) => {
+ const worker = await createWorker(t, makeWorkerUrl({ dip: 'isolate-and-require-corp' }));
+ const result = await fetchFromWorker(worker,
+ get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+ assert_equals(result, 'failure');
+}, '"isolate-and-require-corp" (derived from response)');
+
+promise_test(async (t) => {
+ const blobUrl = await createLocalUrl(t, {
+ url: makeWorkerUrl(),
+ scheme: "blob",
+ });
+
+ const workers = await Promise.all([
+ createWorker(t, blobUrl),
+ createWorker(t, blobUrl),
+ createWorker(t, blobUrl),
+ ]);
+
+ const result = await fetchFromWorker(workers[0],
+ get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+ assert_equals(result, 'success');
+}, 'default policy (derived from owner set due to use of local scheme - blob URL)');
+
+promise_test(async (t) => {
+ const blobUrl = await createLocalUrl(t, {
+ url: makeWorkerUrl(),
+ creatorDip: "isolate-and-require-corp",
+ scheme: "blob",
+ });
+
+ const workers = await Promise.all([
+ createWorker(t, blobUrl),
+ createWorker(t, blobUrl),
+ createWorker(t, blobUrl),
+ ]);
+
+ const result = await fetchFromWorker(workers[0],
+ get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+ assert_equals(result, 'failure');
+}, 'isolate-and-require-corp (derived from blob URL creator)');
+
+promise_test(async (t) => {
+ const blobUrl = await createLocalUrl(t, {
+ url: makeWorkerUrl(),
+ scheme: "blob",
+ });
+
+ const workers = await Promise.all([
+ createWorker(t, blobUrl),
+ createWorker(t, blobUrl, { ownerDip: 'isolate-and-require-corp' }),
+ createWorker(t, blobUrl),
+ ]);
+
+ const result = await fetchFromWorker(workers[0],
+ get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+ assert_equals(result, 'failure');
+}, '"isolate-and-require-corp" (derived from owner set due to use of local scheme - blob URL)');
+
+promise_test(async (t) => {
+ const dataUrl = await createLocalUrl(t, {
+ url: makeWorkerUrl(),
+ scheme: "data",
+ });
+
+ const workers = await Promise.all([
+ createWorker(t, dataUrl),
+ createWorker(t, dataUrl),
+ createWorker(t, dataUrl),
+ ]);
+
+ const result = await fetchFromWorker(workers[0],
+ get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+ assert_equals(result, 'success');
+}, 'default policy (derived from owner set due to use of local scheme - data URL)');
+
+promise_test(async (t) => {
+ const dataUrl = await createLocalUrl(t, {
+ url: makeWorkerUrl(),
+ creatorDip: "isolate-and-require-corp",
+ scheme: "data",
+ });
+
+ const workers = await Promise.all([
+ createWorker(t, dataUrl),
+ createWorker(t, dataUrl),
+ createWorker(t, dataUrl),
+ ]);
+
+ const result = await fetchFromWorker(workers[0],
+ get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+ assert_equals(result, 'success');
+}, 'default policy (not derived from data URL creator)');
+
+promise_test(async (t) => {
+ const dataUrl = await createLocalUrl(t, {
+ url: makeWorkerUrl(),
+ scheme: "data",
+ });
+
+ const workers = await Promise.all([
+ createWorker(t, dataUrl),
+ createWorker(t, dataUrl, { ownerdip: 'isolate-and-require-corp' }),
+ createWorker(t, dataUrl),
+ ]);
+
+ const result = await fetchFromWorker(workers[0],
+ get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+ assert_equals(result, 'failure');
+}, '"isolate-and-require-corp" (derived from owner set due to use of local scheme - data URL)');
+
+promise_test(async (t) => {
+ const filesystemUrl = await createLocalUrl(t, {
+ url: makeWorkerUrl(),
+ scheme: "filesystem",
+ });
+
+ const workers = await Promise.all([
+ createWorker(t, filesystemUrl),
+ createWorker(t, filesystemUrl),
+ createWorker(t, filesystemUrl),
+ ]);
+
+ const result = await fetchFromWorker(workers[0],
+ get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+ assert_equals(result, 'success');
+}, 'default policy (derived from owner set due to use of local scheme - filesystem URL)');
+
+promise_test(async (t) => {
+ const filesystemUrl = await createLocalUrl(t, {
+ url: makeWorkerUrl(),
+ creatorDip: "isolate-and-require-corp",
+ scheme: "filesystem",
+ });
+
+ const workers = await Promise.all([
+ createWorker(t, filesystemUrl),
+ createWorker(t, filesystemUrl),
+ createWorker(t, filesystemUrl),
+ ]);
+
+ const result = await fetchFromWorker(workers[0],
+ get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+ assert_equals(result, 'failure');
+}, 'isolate-and-require-corp (derived from filesystem URL creator)');
+
+promise_test(async (t) => {
+ const filesystemUrl = await createLocalUrl(t, {
+ url: makeWorkerUrl(),
+ scheme: "filesystem",
+ });
+
+ const workers = await Promise.all([
+ createWorker(t, filesystemUrl),
+ createWorker(t, filesystemUrl, { ownerDip: 'isolate-and-require-corp' }),
+ createWorker(t, filesystemUrl),
+ ]);
+
+ const result = await fetchFromWorker(workers[0],
+ get_host_info().HTTPS_REMOTE_ORIGIN+"/html/document-isolation-policy/resources/nothing-no-corp.js");
+ assert_equals(result, 'failure');
+}, '"isolate-and-require-corp" (derived from owner set due to use of local scheme - filesystem URL)');
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/virtual/document-isolation-policy/README.md b/third_party/blink/web_tests/virtual/document-isolation-policy/README.md
new file mode 100644
index 0000000..a19fdea
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/document-isolation-policy/README.md
@@ -0,0 +1,2 @@
+This suite runs document-isolation-policy WPTs with
+--enable-features=DocumentIsolationPolicy.
diff --git a/third_party/blink/web_tests/virtual/document-isolation-policy/external/wpt/html/document-isolation-policy/shared-workers.tentative.https-expected.txt b/third_party/blink/web_tests/virtual/document-isolation-policy/external/wpt/html/document-isolation-policy/shared-workers.tentative.https-expected.txt
new file mode 100644
index 0000000..2070916
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/document-isolation-policy/external/wpt/html/document-isolation-policy/shared-workers.tentative.https-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+[FAIL] isolate-and-require-corp (derived from blob URL creator)
+ assert_equals: expected "failure" but got "success"
+[FAIL] "isolate-and-require-corp" (derived from owner set due to use of local scheme - blob URL)
+ assert_equals: expected "failure" but got "success"
+[FAIL] "isolate-and-require-corp" (derived from owner set due to use of local scheme - data URL)
+ assert_equals: expected "failure" but got "success"
+[FAIL] default policy (derived from owner set due to use of local scheme - filesystem URL)
+ assert_unreached: SharedWorker.onerror should not be called Reached unreachable code
+[FAIL] isolate-and-require-corp (derived from filesystem URL creator)
+ assert_unreached: SharedWorker.onerror should not be called Reached unreachable code
+[FAIL] "isolate-and-require-corp" (derived from owner set due to use of local scheme - filesystem URL)
+ assert_unreached: SharedWorker.onerror should not be called Reached unreachable code
+Harness: the test ran to completion.
+