Commit 8ac99965 authored by Asami Doi's avatar Asami Doi Committed by Commit Bot

PlzDedicatedWorker: Inherits the service worker of a creator document

According to the spec, "Window clients and worker clients with a blob
URL can inherit the active service worker of their creator document or
owner".
https://w3c.github.io/ServiceWorker/#control-and-use-worker-client

In this CL, DedicatedWorker created from a blob URL inherits its creator
document's ServiceWorkerContainerHost. The creator's
ServiceWorkerContainerHost is stored in SWMainResourceHandleCore.
A container host inherits a controller from creator's host
in SWMainResourceLoaderInterceptor if the URL is a blob URL and the
creator's host exists.

Bug: 1017034
Change-Id: I07599794c3a49d91898caa18a4cbfe395754085d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2409472Reviewed-by: default avatarMakoto Shimazu <shimazu@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Reviewed-by: default avatarHiroki Nakagawa <nhiroki@chromium.org>
Commit-Queue: Hiroki Nakagawa <nhiroki@chromium.org>
Cr-Commit-Position: refs/heads/master@{#825790}
parent 45fe0314
......@@ -132,7 +132,7 @@ ServiceWorkerContainerHost::ServiceWorkerContainerHost(
ServiceWorkerContainerHost::~ServiceWorkerContainerHost() {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
if (IsBackForwardCacheEnabled() && IsContainerForClient()) {
if (IsContainerForClient()) {
auto* rfh = RenderFrameHostImpl::FromID(process_id(), frame_id());
if (rfh)
rfh->RemoveServiceWorkerContainerHost(client_uuid());
......@@ -446,8 +446,9 @@ void ServiceWorkerContainerHost::OnSkippedWaiting(
void ServiceWorkerContainerHost::AddMatchingRegistration(
ServiceWorkerRegistration* registration) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
DCHECK(blink::ServiceWorkerScopeMatches(registration->scope(), url_));
if (!IsContextSecureForServiceWorker())
DCHECK(blink::ServiceWorkerScopeMatches(registration->scope(),
GetUrlForScopeMatch()));
if (!IsEligibleForServiceWorkerController())
return;
size_t key = registration->scope().spec().size();
if (base::Contains(matching_registrations_, key))
......@@ -778,12 +779,10 @@ void ServiceWorkerContainerHost::OnBeginNavigationCommit(
std::move(coep_reporter_to_be_passed));
}
if (IsBackForwardCacheEnabled()) {
auto* rfh = RenderFrameHostImpl::FromID(container_process_id, frame_id());
// |rfh| may be null in tests (but it should not happen in production).
if (rfh)
rfh->AddServiceWorkerContainerHost(client_uuid(), GetWeakPtr());
}
auto* rfh = RenderFrameHostImpl::FromID(container_process_id, frame_id());
// |rfh| may be null in tests (but it should not happen in production).
if (rfh)
rfh->AddServiceWorkerContainerHost(client_uuid(), GetWeakPtr());
DCHECK_EQ(ukm_source_id_, ukm::kInvalidSourceId);
ukm_source_id_ = document_ukm_source_id;
......@@ -888,7 +887,7 @@ void ServiceWorkerContainerHost::SetControllerRegistration(
DCHECK(IsContainerForClient());
if (controller_registration) {
CHECK(IsContextSecureForServiceWorker());
CHECK(IsEligibleForServiceWorkerController());
DCHECK(controller_registration->active_version());
#if DCHECK_IS_ON()
DCHECK(IsMatchingRegistration(controller_registration.get()));
......@@ -968,13 +967,19 @@ bool ServiceWorkerContainerHost::AllowServiceWorker(const GURL& scope,
return allowed;
}
bool ServiceWorkerContainerHost::IsContextSecureForServiceWorker() const {
bool ServiceWorkerContainerHost::IsEligibleForServiceWorkerController() const {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
DCHECK(IsContainerForClient());
if (!url_.is_valid())
return false;
if (!OriginCanAccessServiceWorkers(url_))
// Pass GetUrlForScopeMatch() instead of `url_` because we cannot take the
// origin of `url_` when it's a blob URL (see https://crbug.com/1144717). It's
// guaranteed that the URL returned by GetURLForScopeMatch() has the same
// logical origin as `url_`.
// TODO(asamidoi): Add url::Origin member for ServiceWorkerContainerHost and
// use it as the argument of OriginCanAccessServiceWorkers().
if (!OriginCanAccessServiceWorkers(GetUrlForScopeMatch()))
return false;
if (is_parent_frame_secure_)
......@@ -1126,7 +1131,8 @@ void ServiceWorkerContainerHost::SyncMatchingRegistrations() {
for (const auto& key_registration : registrations) {
ServiceWorkerRegistration* registration = key_registration.second;
if (!registration->is_uninstalled() &&
blink::ServiceWorkerScopeMatches(registration->scope(), url_)) {
blink::ServiceWorkerScopeMatches(registration->scope(),
GetUrlForScopeMatch())) {
AddMatchingRegistration(registration);
}
}
......@@ -1224,7 +1230,7 @@ void ServiceWorkerContainerHost::UpdateController(
ServiceWorkerVersion* version =
controller_registration_ ? controller_registration_->active_version()
: nullptr;
CHECK(!version || IsContextSecureForServiceWorker());
CHECK(!version || IsEligibleForServiceWorkerController());
if (version == controller_.get())
return;
......@@ -1580,4 +1586,35 @@ bool ServiceWorkerContainerHost::CanServeContainerHostMethods(
return true;
}
const GURL& ServiceWorkerContainerHost::GetUrlForScopeMatch() const {
DCHECK(IsContainerForClient());
if (!scope_match_url_for_blob_client_.is_empty())
return scope_match_url_for_blob_client_;
return url_;
}
void ServiceWorkerContainerHost::InheritControllerFrom(
ServiceWorkerContainerHost& creator_host,
const GURL& blob_url) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
DCHECK(IsContainerForClient());
DCHECK_EQ(blink::mojom::ServiceWorkerClientType::kDedicatedWorker,
GetClientType());
DCHECK(blob_url.SchemeIsBlob());
UpdateUrls(blob_url, net::SiteForCookies::FromUrl(blob_url),
creator_host.top_frame_origin());
// Let `scope_match_url_for_blob_client_` be the creator's url for scope match
// because a client should be handled by the service worker of its creator.
scope_match_url_for_blob_client_ = creator_host.GetUrlForScopeMatch();
// Inherit the controller of the creator.
if (creator_host.controller_registration()) {
AddMatchingRegistration(creator_host.controller_registration());
SetControllerRegistration(creator_host.controller_registration(),
false /* notify_controllerchange */);
}
}
} // namespace content
......@@ -230,8 +230,8 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final
blink::mojom::ServiceWorkerObjectInfoPtr CreateServiceWorkerObjectInfoToSend(
scoped_refptr<ServiceWorkerVersion> version);
// Returns a ServiceWorkerObjectHost instance for |version| for this provider
// host. A new instance is created if one does not already exist.
// Returns a ServiceWorkerObjectHost instance for |version| for this
// container host. A new instance is created if one does not already exist.
// ServiceWorkerObjectHost will have an ownership of the |version|.
base::WeakPtr<ServiceWorkerObjectHost> GetOrCreateServiceWorkerObjectHost(
scoped_refptr<ServiceWorkerVersion> version);
......@@ -379,7 +379,7 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final
// If non-empty, |script_url| is the script the service worker will run.
bool AllowServiceWorker(const GURL& scope, const GURL& script_url);
// Returns whether this provider host is secure enough to have a service
// Returns whether this container host is secure enough to have a service
// worker controller.
// Analogous to Blink's Document::IsSecureContext. Because of how service
// worker intercepts main resource requests, this check must be done
......@@ -387,7 +387,7 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final
// ServiceWorkerNetworkProviderForFrame::Create). This function uses
// |url_| and |is_parent_frame_secure_| to determine context security, so they
// must be set properly before calling this function.
bool IsContextSecureForServiceWorker() const;
bool IsEligibleForServiceWorkerController() const;
// For service worker clients. True if the response for the main resource load
// was committed to the renderer. When this is false, the client's URL may
......@@ -448,6 +448,19 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final
void EnterBackForwardCacheForTesting() { is_in_back_forward_cache_ = true; }
void LeaveBackForwardCacheForTesting() { is_in_back_forward_cache_ = false; }
// For service worker clients. Returns the URL that is used for scope matching
// algorithm. This can be different from url() in the case of blob URL
// workers. In that case, url() may be like "blob://https://a.test" and the
// scope matching URL is "https://a.test", inherited from the parent container
// host.
const GURL& GetUrlForScopeMatch() const;
// For service worker clients that are dedicated workers. Inherits the
// controller of the creator document or worker. Used when the client was
// created with a blob URL.
void InheritControllerFrom(ServiceWorkerContainerHost& creator_host,
const GURL& blob_url);
base::WeakPtr<ServiceWorkerContainerHost> GetWeakPtr();
ukm::SourceId ukm_source_id() const { return ukm_source_id_; }
......@@ -623,7 +636,7 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final
std::map<size_t, scoped_refptr<ServiceWorkerRegistration>>;
// Contains all living registrations whose scope this client's URL starts
// with, used for .ready and claim(). It is empty if
// IsContextSecureForServiceWorker() is false. See also
// IsEligibleForServiceWorkerController() is false. See also
// AddMatchingRegistration().
ServiceWorkerRegistrationMap matching_registrations_;
......@@ -657,6 +670,10 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final
// The source id of the client's ExecutionContext, set on response commit.
ukm::SourceId ukm_source_id_ = ukm::kInvalidSourceId;
// The URL used for service worker scope matching. It is empty except in the
// case of a service worker client with a blob URL.
GURL scope_match_url_for_blob_client_;
// For window clients only ---------------------------------------------------
// A token used internally to identify this context in requests. Corresponds
......
......@@ -401,20 +401,22 @@ TEST_F(ServiceWorkerContainerHostTest, ContextSecurity) {
container_host_secure_parent->UpdateUrls(
GURL("http://host"), net::SiteForCookies::FromUrl(GURL("http://host")),
url::Origin::Create(GURL("http://host")));
EXPECT_FALSE(container_host_secure_parent->IsContextSecureForServiceWorker());
EXPECT_FALSE(
container_host_secure_parent->IsEligibleForServiceWorkerController());
// Insecure parent frame.
container_host_insecure_parent->UpdateUrls(
GURL("https://host"), net::SiteForCookies::FromUrl(GURL("https://host")),
url::Origin::Create(GURL("https://host")));
EXPECT_FALSE(
container_host_insecure_parent->IsContextSecureForServiceWorker());
container_host_insecure_parent->IsEligibleForServiceWorkerController());
// Secure URL and parent frame.
container_host_secure_parent->UpdateUrls(
GURL("https://host"), net::SiteForCookies::FromUrl(GURL("https://host")),
url::Origin::Create(GURL("https://host")));
EXPECT_TRUE(container_host_secure_parent->IsContextSecureForServiceWorker());
EXPECT_TRUE(
container_host_secure_parent->IsEligibleForServiceWorkerController());
// Exceptional service worker scheme.
GURL url(std::string(kServiceWorkerScheme) + "://host");
......@@ -424,13 +426,14 @@ TEST_F(ServiceWorkerContainerHostTest, ContextSecurity) {
EXPECT_TRUE(OriginCanAccessServiceWorkers(url));
container_host_secure_parent->UpdateUrls(
url, net::SiteForCookies::FromUrl(url), origin);
EXPECT_TRUE(container_host_secure_parent->IsContextSecureForServiceWorker());
EXPECT_TRUE(
container_host_secure_parent->IsEligibleForServiceWorkerController());
// Exceptional service worker scheme with insecure parent frame.
container_host_insecure_parent->UpdateUrls(
url, net::SiteForCookies::FromUrl(url), origin);
EXPECT_FALSE(
container_host_insecure_parent->IsContextSecureForServiceWorker());
container_host_insecure_parent->IsEligibleForServiceWorkerController());
}
TEST_F(ServiceWorkerContainerHostTest, UpdateUrls_SameOriginRedirect) {
......
......@@ -303,7 +303,7 @@ void ServiceWorkerControlleeRequestHandler::ContinueWithRegistration(
return;
}
if (!container_host_->IsContextSecureForServiceWorker()) {
if (!container_host_->IsEligibleForServiceWorkerController()) {
// TODO(falken): Figure out a way to surface in the page's DevTools
// console that the service worker was blocked for security.
TRACE_EVENT_WITH_FLOW1(
......
......@@ -8,6 +8,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/service_worker/service_worker_accessed_callback.h"
#include "content/browser/service_worker/service_worker_main_resource_handle_core.h"
#include "content/common/content_export.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/mojom/network_context.mojom.h"
......@@ -25,7 +26,6 @@ struct CrossOriginEmbedderPolicy;
namespace content {
class ServiceWorkerContextWrapper;
class ServiceWorkerMainResourceHandleCore;
// This class is used to manage the lifetime of ServiceWorkerContainerHosts
// created for main resource requests (navigations and web workers). This is a
......
......@@ -69,6 +69,16 @@ class CONTENT_EXPORT ServiceWorkerMainResourceHandleCore {
return container_host_;
}
void set_parent_container_host(
base::WeakPtr<ServiceWorkerContainerHost> container_host) {
DCHECK(!parent_container_host_);
parent_container_host_ = std::move(container_host);
}
base::WeakPtr<ServiceWorkerContainerHost> parent_container_host() {
return parent_container_host_;
}
void set_interceptor(
std::unique_ptr<ServiceWorkerControlleeRequestHandler> interceptor) {
interceptor_ = std::move(interceptor);
......@@ -90,6 +100,8 @@ class CONTENT_EXPORT ServiceWorkerMainResourceHandleCore {
scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_;
base::WeakPtr<ServiceWorkerMainResourceHandle> ui_handle_;
base::WeakPtr<ServiceWorkerContainerHost> container_host_;
// Only used for workers with a blob URL.
base::WeakPtr<ServiceWorkerContainerHost> parent_container_host_;
std::unique_ptr<ServiceWorkerControlleeRequestHandler> interceptor_;
ServiceWorkerAccessedCallback service_worker_accessed_callback_;
......
......@@ -116,6 +116,7 @@ void MaybeCreateLoaderOnCoreThread(
DCHECK(host_receiver);
DCHECK(client_remote);
base::WeakPtr<ServiceWorkerContainerHost> container_host;
bool inherit_container_host_only = false;
if (request_destination == network::mojom::RequestDestination::kDocument ||
request_destination == network::mojom::RequestDestination::kIframe) {
......@@ -135,6 +136,18 @@ void MaybeCreateLoaderOnCoreThread(
container_host = context_core->CreateContainerHostForWorker(
std::move(host_receiver), process_id, std::move(client_remote),
client_info);
// For the blob worker case, inherit the controller from the worker's
// parent. See
// https://w3c.github.io/ServiceWorker/#control-and-use-worker-client
base::WeakPtr<ServiceWorkerContainerHost> parent_container_host =
handle_core->parent_container_host();
if (parent_container_host &&
tentative_resource_request.url.SchemeIsBlob()) {
container_host->InheritControllerFrom(*parent_container_host,
tentative_resource_request.url);
inherit_container_host_only = true;
}
}
DCHECK(container_host);
handle_core->set_container_host(container_host);
......@@ -146,6 +159,19 @@ void MaybeCreateLoaderOnCoreThread(
context_core->AsWeakPtr(), container_host, request_destination,
skip_service_worker,
handle_core->service_worker_accessed_callback()));
// For the blob worker case, we only inherit the controller and do not
// let it intercept the requests. Blob URLs are not eligible to go through
// service worker interception. So just call the loader callback now.
// We don't use the interceptor but have to set it because we need
// ControllerServiceWorkerInfoPtr and ServiceWorkerObjectHost from the
// subresource loader params which is created by the interceptor.
if (inherit_container_host_only) {
LoaderCallbackWrapperOnCoreThread(
handle_core, std::move(interceptor_on_ui), std::move(loader_callback),
/*handler=*/{});
return;
}
}
// If |initialize_container_host_only| is true, we have already determined
......@@ -193,7 +219,12 @@ bool SchemeMaySupportRedirectingToHTTPS(BrowserContext* browser_context,
// Returns true if a ServiceWorkerMainResourceLoaderInterceptor should be
// created for a worker with this |url|.
bool ShouldCreateForWorker(const GURL& url) {
bool ShouldCreateForWorker(
const GURL& url,
base::WeakPtr<ServiceWorkerContainerHost> parent_container_host) {
// Blob URL can be controlled by a parent's controller.
if (url.SchemeIsBlob() && parent_container_host)
return true;
// Create the handler even for insecure HTTP since it's used in the
// case of redirect to HTTPS.
return url.SchemeIsHTTPOrHTTPS() || OriginCanAccessServiceWorkers(url);
......@@ -239,9 +270,9 @@ ServiceWorkerMainResourceLoaderInterceptor::CreateForWorker(
network::mojom::RequestDestination::kSharedWorker)
<< resource_request.destination;
// Create the handler even for insecure HTTP since it's used in the
// case of redirect to HTTPS.
if (!ShouldCreateForWorker(resource_request.url))
if (!ShouldCreateForWorker(
resource_request.url,
navigation_handle->core()->parent_container_host()))
return nullptr;
return base::WrapUnique(new ServiceWorkerMainResourceLoaderInterceptor(
......
......@@ -783,8 +783,8 @@ void ServiceWorkerRegisterJob::AddRegistrationToMatchingContainerHosts(
!it->IsAtEnd(); it->Advance()) {
ServiceWorkerContainerHost* container_host = it->GetContainerHost();
DCHECK(container_host->IsContainerForClient());
if (!blink::ServiceWorkerScopeMatches(registration->scope(),
container_host->url())) {
if (!blink::ServiceWorkerScopeMatches(
registration->scope(), container_host->GetUrlForScopeMatch())) {
continue;
}
container_host->AddMatchingRegistration(registration);
......
......@@ -300,7 +300,7 @@ void ServiceWorkerRegistration::ClaimClients() {
continue;
// "2. If client is not a secure context, continue."
if (!container_host->IsContextSecureForServiceWorker())
if (!container_host->IsEligibleForServiceWorkerController())
continue;
// "3. Let registration be the result of running Match Service Worker
......
......@@ -12,6 +12,7 @@
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
#include "content/browser/loader/content_security_notifier.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/service_worker/service_worker_container_host.h"
#include "content/browser/service_worker/service_worker_main_resource_handle.h"
#include "content/browser/service_worker/service_worker_object_host.h"
#include "content/browser/storage_partition_impl.h"
......@@ -185,6 +186,24 @@ void DedicatedWorkerHost::StartScriptLoad(
service_worker_handle_ = std::make_unique<ServiceWorkerMainResourceHandle>(
storage_partition_impl->GetServiceWorkerContext(), base::DoNothing());
// For blob URL workers, inherit the controller from the worker's parent.
// See https://w3c.github.io/ServiceWorker/#control-and-use-worker-client
if (script_url.SchemeIsBlob()) {
if (creator_render_frame_host_id_) {
base::WeakPtr<ServiceWorkerContainerHost> creator_container_host =
RenderFrameHostImpl::FromID(creator_render_frame_host_id_.value())
->GetLastCommittedServiceWorkerHost();
service_worker_handle_->core()->set_parent_container_host(
creator_container_host);
} else {
// TODO(https://crbug.com/1017034): When this worker is nested, the worker
// should inherit the active service worker from the parent worker host.
// Implement this behavior.
NOTIMPLEMENTED();
}
}
// Get a storage domain.
auto partition_domain =
nearest_ancestor_render_frame_host->GetSiteInstance()->GetPartitionDomain(
......
......@@ -2,7 +2,7 @@ This is a testharness.js-based test.
FAIL Same-origin blob URL iframe should inherit service worker controller. assert_equals: blob URL iframe should inherit controller expected (string) "https://web-platform.test:8444/service-workers/service-worker/resources/local-url-inherit-controller-worker.js" but got (object) null
FAIL Same-origin blob URL iframe should intercept fetch(). assert_equals: blob URL iframe should intercept fetch expected "intercepted" but got "Hello world\n"
FAIL Same-origin blob URL worker should inherit service worker controller. promise_test: Unhandled rejection with value: "Uncaught TypeError: Cannot read property 'controller' of undefined"
FAIL Same-origin blob URL worker should intercept fetch(). assert_equals: blob URL worker should intercept fetch expected "intercepted" but got "Hello world\n"
PASS Same-origin blob URL worker should intercept fetch().
PASS Data URL iframe should not intercept fetch().
FAIL Data URL worker should not inherit service worker controller. promise_test: Unhandled rejection with value: "Uncaught TypeError: Cannot read property 'controller' of undefined"
PASS Data URL worker should not intercept fetch().
......
This is a testharness.js-based test.
PASS Prepare a service worker.
PASS Prepare a normal iframe.
PASS Prepare an iframe sandboxed by <iframe sandbox="allow-scripts">.
PASS Prepare an iframe sandboxed by <iframe sandbox="allow-scripts allow-same-origin">.
PASS Prepare an iframe sandboxed by CSP HTTP header with allow-scripts.
PASS Prepare an iframe sandboxed by CSP HTTP header with allow-scripts and allow-same-origin.
PASS Fetch request from a normal iframe
FAIL Fetch request from a worker in a normal iframe assert_equals: The fetch request should be handled by SW. expected 1 but got 0
PASS Request for an iframe in the normal iframe
PASS Request for an sandboxed iframe with allow-scripts flag in the normal iframe
PASS Request for an sandboxed iframe with allow-scripts and allow-same-origin flag in the normal iframe
PASS Fetch request from iframe sandboxed by an attribute with allow-scripts flag
PASS Fetch request from a worker in iframe sandboxed by an attribute with allow-scripts flag
PASS Request for an iframe in the iframe sandboxed by an attribute with allow-scripts flag
PASS Request for an sandboxed iframe with allow-scripts flag in the iframe sandboxed by an attribute with allow-scripts flag
PASS Request for an sandboxed iframe with allow-scripts and allow-same-origin flag in the iframe sandboxed by an attribute with allow-scripts flag
PASS Fetch request from iframe sandboxed by an attribute with allow-scripts and allow-same-origin flag
FAIL Fetch request from a worker in iframe sandboxed by an attribute with allow-scripts and allow-same-origin flag assert_equals: The fetch request should be handled by SW. expected 1 but got 0
PASS Request for an iframe in the iframe sandboxed by an attribute with allow-scripts and allow-same-origin flag
PASS Request for an sandboxed iframe with allow-scripts flag in the iframe sandboxed by attribute with allow-scripts and allow-same-origin flag
PASS Request for an sandboxed iframe with allow-scripts and allow-same-origin flag in the iframe sandboxed by attribute with allow-scripts and allow-same-origin flag
PASS Fetch request from iframe sandboxed by CSP HTTP header with allow-scripts flag
PASS Request for an iframe in the iframe sandboxed by CSP HTTP header with allow-scripts flag
PASS Request for an sandboxed iframe with allow-scripts flag in the iframe sandboxed by CSP HTTP header with allow-scripts flag
PASS Request for an sandboxed iframe with allow-scripts and allow-same-origin flag in the iframe sandboxed by CSP HTTP header with allow-scripts flag
PASS Fetch request from iframe sandboxed by CSP HTTP header with allow-scripts and allow-same-origin flag
PASS Request for an iframe in the iframe sandboxed by CSP HTTP header with allow-scripts and allow-same-origin flag
PASS Request for an sandboxed iframe with allow-scripts flag in the iframe sandboxed by CSP HTTP header with allow-scripts and allow-same-origin flag
PASS Request for an sandboxed iframe with allow-scripts and allow-same-origin flag in the iframe sandboxed by CSP HTTP header with allow-scripts and allow-same-origin flag
Harness: the test ran to completion.
This is a testharness.js-based test.
PASS Prepare a service worker.
PASS Prepare an iframe sandboxed by CSP HTTP header with allow-scripts.
PASS Prepare an iframe sandboxed by CSP HTTP header with allow-scripts and allow-same-origin.
PASS Fetch request from a worker in iframe sandboxed by CSP HTTP header allow-scripts flag
FAIL Fetch request from a worker in iframe sandboxed by CSP HTTP header with allow-scripts and allow-same-origin flag assert_equals: The request should be handled by SW. expected 1 but got 0
Harness: the test ran to completion.
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