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( ...@@ -132,7 +132,7 @@ ServiceWorkerContainerHost::ServiceWorkerContainerHost(
ServiceWorkerContainerHost::~ServiceWorkerContainerHost() { ServiceWorkerContainerHost::~ServiceWorkerContainerHost() {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
if (IsBackForwardCacheEnabled() && IsContainerForClient()) { if (IsContainerForClient()) {
auto* rfh = RenderFrameHostImpl::FromID(process_id(), frame_id()); auto* rfh = RenderFrameHostImpl::FromID(process_id(), frame_id());
if (rfh) if (rfh)
rfh->RemoveServiceWorkerContainerHost(client_uuid()); rfh->RemoveServiceWorkerContainerHost(client_uuid());
...@@ -446,8 +446,9 @@ void ServiceWorkerContainerHost::OnSkippedWaiting( ...@@ -446,8 +446,9 @@ void ServiceWorkerContainerHost::OnSkippedWaiting(
void ServiceWorkerContainerHost::AddMatchingRegistration( void ServiceWorkerContainerHost::AddMatchingRegistration(
ServiceWorkerRegistration* registration) { ServiceWorkerRegistration* registration) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
DCHECK(blink::ServiceWorkerScopeMatches(registration->scope(), url_)); DCHECK(blink::ServiceWorkerScopeMatches(registration->scope(),
if (!IsContextSecureForServiceWorker()) GetUrlForScopeMatch()));
if (!IsEligibleForServiceWorkerController())
return; return;
size_t key = registration->scope().spec().size(); size_t key = registration->scope().spec().size();
if (base::Contains(matching_registrations_, key)) if (base::Contains(matching_registrations_, key))
...@@ -778,12 +779,10 @@ void ServiceWorkerContainerHost::OnBeginNavigationCommit( ...@@ -778,12 +779,10 @@ void ServiceWorkerContainerHost::OnBeginNavigationCommit(
std::move(coep_reporter_to_be_passed)); std::move(coep_reporter_to_be_passed));
} }
if (IsBackForwardCacheEnabled()) {
auto* rfh = RenderFrameHostImpl::FromID(container_process_id, frame_id()); auto* rfh = RenderFrameHostImpl::FromID(container_process_id, frame_id());
// |rfh| may be null in tests (but it should not happen in production). // |rfh| may be null in tests (but it should not happen in production).
if (rfh) if (rfh)
rfh->AddServiceWorkerContainerHost(client_uuid(), GetWeakPtr()); rfh->AddServiceWorkerContainerHost(client_uuid(), GetWeakPtr());
}
DCHECK_EQ(ukm_source_id_, ukm::kInvalidSourceId); DCHECK_EQ(ukm_source_id_, ukm::kInvalidSourceId);
ukm_source_id_ = document_ukm_source_id; ukm_source_id_ = document_ukm_source_id;
...@@ -888,7 +887,7 @@ void ServiceWorkerContainerHost::SetControllerRegistration( ...@@ -888,7 +887,7 @@ void ServiceWorkerContainerHost::SetControllerRegistration(
DCHECK(IsContainerForClient()); DCHECK(IsContainerForClient());
if (controller_registration) { if (controller_registration) {
CHECK(IsContextSecureForServiceWorker()); CHECK(IsEligibleForServiceWorkerController());
DCHECK(controller_registration->active_version()); DCHECK(controller_registration->active_version());
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
DCHECK(IsMatchingRegistration(controller_registration.get())); DCHECK(IsMatchingRegistration(controller_registration.get()));
...@@ -968,13 +967,19 @@ bool ServiceWorkerContainerHost::AllowServiceWorker(const GURL& scope, ...@@ -968,13 +967,19 @@ bool ServiceWorkerContainerHost::AllowServiceWorker(const GURL& scope,
return allowed; return allowed;
} }
bool ServiceWorkerContainerHost::IsContextSecureForServiceWorker() const { bool ServiceWorkerContainerHost::IsEligibleForServiceWorkerController() const {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
DCHECK(IsContainerForClient()); DCHECK(IsContainerForClient());
if (!url_.is_valid()) if (!url_.is_valid())
return false; 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; return false;
if (is_parent_frame_secure_) if (is_parent_frame_secure_)
...@@ -1126,7 +1131,8 @@ void ServiceWorkerContainerHost::SyncMatchingRegistrations() { ...@@ -1126,7 +1131,8 @@ void ServiceWorkerContainerHost::SyncMatchingRegistrations() {
for (const auto& key_registration : registrations) { for (const auto& key_registration : registrations) {
ServiceWorkerRegistration* registration = key_registration.second; ServiceWorkerRegistration* registration = key_registration.second;
if (!registration->is_uninstalled() && if (!registration->is_uninstalled() &&
blink::ServiceWorkerScopeMatches(registration->scope(), url_)) { blink::ServiceWorkerScopeMatches(registration->scope(),
GetUrlForScopeMatch())) {
AddMatchingRegistration(registration); AddMatchingRegistration(registration);
} }
} }
...@@ -1224,7 +1230,7 @@ void ServiceWorkerContainerHost::UpdateController( ...@@ -1224,7 +1230,7 @@ void ServiceWorkerContainerHost::UpdateController(
ServiceWorkerVersion* version = ServiceWorkerVersion* version =
controller_registration_ ? controller_registration_->active_version() controller_registration_ ? controller_registration_->active_version()
: nullptr; : nullptr;
CHECK(!version || IsContextSecureForServiceWorker()); CHECK(!version || IsEligibleForServiceWorkerController());
if (version == controller_.get()) if (version == controller_.get())
return; return;
...@@ -1580,4 +1586,35 @@ bool ServiceWorkerContainerHost::CanServeContainerHostMethods( ...@@ -1580,4 +1586,35 @@ bool ServiceWorkerContainerHost::CanServeContainerHostMethods(
return true; 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 } // namespace content
...@@ -230,8 +230,8 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final ...@@ -230,8 +230,8 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final
blink::mojom::ServiceWorkerObjectInfoPtr CreateServiceWorkerObjectInfoToSend( blink::mojom::ServiceWorkerObjectInfoPtr CreateServiceWorkerObjectInfoToSend(
scoped_refptr<ServiceWorkerVersion> version); scoped_refptr<ServiceWorkerVersion> version);
// Returns a ServiceWorkerObjectHost instance for |version| for this provider // Returns a ServiceWorkerObjectHost instance for |version| for this
// host. A new instance is created if one does not already exist. // container host. A new instance is created if one does not already exist.
// ServiceWorkerObjectHost will have an ownership of the |version|. // ServiceWorkerObjectHost will have an ownership of the |version|.
base::WeakPtr<ServiceWorkerObjectHost> GetOrCreateServiceWorkerObjectHost( base::WeakPtr<ServiceWorkerObjectHost> GetOrCreateServiceWorkerObjectHost(
scoped_refptr<ServiceWorkerVersion> version); scoped_refptr<ServiceWorkerVersion> version);
...@@ -379,7 +379,7 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final ...@@ -379,7 +379,7 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final
// If non-empty, |script_url| is the script the service worker will run. // If non-empty, |script_url| is the script the service worker will run.
bool AllowServiceWorker(const GURL& scope, const GURL& script_url); 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. // worker controller.
// Analogous to Blink's Document::IsSecureContext. Because of how service // Analogous to Blink's Document::IsSecureContext. Because of how service
// worker intercepts main resource requests, this check must be done // worker intercepts main resource requests, this check must be done
...@@ -387,7 +387,7 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final ...@@ -387,7 +387,7 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final
// ServiceWorkerNetworkProviderForFrame::Create). This function uses // ServiceWorkerNetworkProviderForFrame::Create). This function uses
// |url_| and |is_parent_frame_secure_| to determine context security, so they // |url_| and |is_parent_frame_secure_| to determine context security, so they
// must be set properly before calling this function. // 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 // 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 // was committed to the renderer. When this is false, the client's URL may
...@@ -448,6 +448,19 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final ...@@ -448,6 +448,19 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final
void EnterBackForwardCacheForTesting() { is_in_back_forward_cache_ = true; } void EnterBackForwardCacheForTesting() { is_in_back_forward_cache_ = true; }
void LeaveBackForwardCacheForTesting() { is_in_back_forward_cache_ = false; } 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(); base::WeakPtr<ServiceWorkerContainerHost> GetWeakPtr();
ukm::SourceId ukm_source_id() const { return ukm_source_id_; } ukm::SourceId ukm_source_id() const { return ukm_source_id_; }
...@@ -623,7 +636,7 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final ...@@ -623,7 +636,7 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final
std::map<size_t, scoped_refptr<ServiceWorkerRegistration>>; std::map<size_t, scoped_refptr<ServiceWorkerRegistration>>;
// Contains all living registrations whose scope this client's URL starts // Contains all living registrations whose scope this client's URL starts
// with, used for .ready and claim(). It is empty if // with, used for .ready and claim(). It is empty if
// IsContextSecureForServiceWorker() is false. See also // IsEligibleForServiceWorkerController() is false. See also
// AddMatchingRegistration(). // AddMatchingRegistration().
ServiceWorkerRegistrationMap matching_registrations_; ServiceWorkerRegistrationMap matching_registrations_;
...@@ -657,6 +670,10 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final ...@@ -657,6 +670,10 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final
// The source id of the client's ExecutionContext, set on response commit. // The source id of the client's ExecutionContext, set on response commit.
ukm::SourceId ukm_source_id_ = ukm::kInvalidSourceId; 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 --------------------------------------------------- // For window clients only ---------------------------------------------------
// A token used internally to identify this context in requests. Corresponds // A token used internally to identify this context in requests. Corresponds
......
...@@ -401,20 +401,22 @@ TEST_F(ServiceWorkerContainerHostTest, ContextSecurity) { ...@@ -401,20 +401,22 @@ TEST_F(ServiceWorkerContainerHostTest, ContextSecurity) {
container_host_secure_parent->UpdateUrls( container_host_secure_parent->UpdateUrls(
GURL("http://host"), net::SiteForCookies::FromUrl(GURL("http://host")), GURL("http://host"), net::SiteForCookies::FromUrl(GURL("http://host")),
url::Origin::Create(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. // Insecure parent frame.
container_host_insecure_parent->UpdateUrls( container_host_insecure_parent->UpdateUrls(
GURL("https://host"), net::SiteForCookies::FromUrl(GURL("https://host")), GURL("https://host"), net::SiteForCookies::FromUrl(GURL("https://host")),
url::Origin::Create(GURL("https://host"))); url::Origin::Create(GURL("https://host")));
EXPECT_FALSE( EXPECT_FALSE(
container_host_insecure_parent->IsContextSecureForServiceWorker()); container_host_insecure_parent->IsEligibleForServiceWorkerController());
// Secure URL and parent frame. // Secure URL and parent frame.
container_host_secure_parent->UpdateUrls( container_host_secure_parent->UpdateUrls(
GURL("https://host"), net::SiteForCookies::FromUrl(GURL("https://host")), GURL("https://host"), net::SiteForCookies::FromUrl(GURL("https://host")),
url::Origin::Create(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. // Exceptional service worker scheme.
GURL url(std::string(kServiceWorkerScheme) + "://host"); GURL url(std::string(kServiceWorkerScheme) + "://host");
...@@ -424,13 +426,14 @@ TEST_F(ServiceWorkerContainerHostTest, ContextSecurity) { ...@@ -424,13 +426,14 @@ TEST_F(ServiceWorkerContainerHostTest, ContextSecurity) {
EXPECT_TRUE(OriginCanAccessServiceWorkers(url)); EXPECT_TRUE(OriginCanAccessServiceWorkers(url));
container_host_secure_parent->UpdateUrls( container_host_secure_parent->UpdateUrls(
url, net::SiteForCookies::FromUrl(url), origin); 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. // Exceptional service worker scheme with insecure parent frame.
container_host_insecure_parent->UpdateUrls( container_host_insecure_parent->UpdateUrls(
url, net::SiteForCookies::FromUrl(url), origin); url, net::SiteForCookies::FromUrl(url), origin);
EXPECT_FALSE( EXPECT_FALSE(
container_host_insecure_parent->IsContextSecureForServiceWorker()); container_host_insecure_parent->IsEligibleForServiceWorkerController());
} }
TEST_F(ServiceWorkerContainerHostTest, UpdateUrls_SameOriginRedirect) { TEST_F(ServiceWorkerContainerHostTest, UpdateUrls_SameOriginRedirect) {
......
...@@ -303,7 +303,7 @@ void ServiceWorkerControlleeRequestHandler::ContinueWithRegistration( ...@@ -303,7 +303,7 @@ void ServiceWorkerControlleeRequestHandler::ContinueWithRegistration(
return; return;
} }
if (!container_host_->IsContextSecureForServiceWorker()) { if (!container_host_->IsEligibleForServiceWorkerController()) {
// TODO(falken): Figure out a way to surface in the page's DevTools // TODO(falken): Figure out a way to surface in the page's DevTools
// console that the service worker was blocked for security. // console that the service worker was blocked for security.
TRACE_EVENT_WITH_FLOW1( TRACE_EVENT_WITH_FLOW1(
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "content/browser/service_worker/service_worker_accessed_callback.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 "content/common/content_export.h"
#include "services/metrics/public/cpp/ukm_source_id.h" #include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/mojom/network_context.mojom.h" #include "services/network/public/mojom/network_context.mojom.h"
...@@ -25,7 +26,6 @@ struct CrossOriginEmbedderPolicy; ...@@ -25,7 +26,6 @@ struct CrossOriginEmbedderPolicy;
namespace content { namespace content {
class ServiceWorkerContextWrapper; class ServiceWorkerContextWrapper;
class ServiceWorkerMainResourceHandleCore;
// This class is used to manage the lifetime of ServiceWorkerContainerHosts // This class is used to manage the lifetime of ServiceWorkerContainerHosts
// created for main resource requests (navigations and web workers). This is a // created for main resource requests (navigations and web workers). This is a
......
...@@ -69,6 +69,16 @@ class CONTENT_EXPORT ServiceWorkerMainResourceHandleCore { ...@@ -69,6 +69,16 @@ class CONTENT_EXPORT ServiceWorkerMainResourceHandleCore {
return container_host_; 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( void set_interceptor(
std::unique_ptr<ServiceWorkerControlleeRequestHandler> interceptor) { std::unique_ptr<ServiceWorkerControlleeRequestHandler> interceptor) {
interceptor_ = std::move(interceptor); interceptor_ = std::move(interceptor);
...@@ -90,6 +100,8 @@ class CONTENT_EXPORT ServiceWorkerMainResourceHandleCore { ...@@ -90,6 +100,8 @@ class CONTENT_EXPORT ServiceWorkerMainResourceHandleCore {
scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_; scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_;
base::WeakPtr<ServiceWorkerMainResourceHandle> ui_handle_; base::WeakPtr<ServiceWorkerMainResourceHandle> ui_handle_;
base::WeakPtr<ServiceWorkerContainerHost> container_host_; base::WeakPtr<ServiceWorkerContainerHost> container_host_;
// Only used for workers with a blob URL.
base::WeakPtr<ServiceWorkerContainerHost> parent_container_host_;
std::unique_ptr<ServiceWorkerControlleeRequestHandler> interceptor_; std::unique_ptr<ServiceWorkerControlleeRequestHandler> interceptor_;
ServiceWorkerAccessedCallback service_worker_accessed_callback_; ServiceWorkerAccessedCallback service_worker_accessed_callback_;
......
...@@ -116,6 +116,7 @@ void MaybeCreateLoaderOnCoreThread( ...@@ -116,6 +116,7 @@ void MaybeCreateLoaderOnCoreThread(
DCHECK(host_receiver); DCHECK(host_receiver);
DCHECK(client_remote); DCHECK(client_remote);
base::WeakPtr<ServiceWorkerContainerHost> container_host; base::WeakPtr<ServiceWorkerContainerHost> container_host;
bool inherit_container_host_only = false;
if (request_destination == network::mojom::RequestDestination::kDocument || if (request_destination == network::mojom::RequestDestination::kDocument ||
request_destination == network::mojom::RequestDestination::kIframe) { request_destination == network::mojom::RequestDestination::kIframe) {
...@@ -135,6 +136,18 @@ void MaybeCreateLoaderOnCoreThread( ...@@ -135,6 +136,18 @@ void MaybeCreateLoaderOnCoreThread(
container_host = context_core->CreateContainerHostForWorker( container_host = context_core->CreateContainerHostForWorker(
std::move(host_receiver), process_id, std::move(client_remote), std::move(host_receiver), process_id, std::move(client_remote),
client_info); 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); DCHECK(container_host);
handle_core->set_container_host(container_host); handle_core->set_container_host(container_host);
...@@ -146,6 +159,19 @@ void MaybeCreateLoaderOnCoreThread( ...@@ -146,6 +159,19 @@ void MaybeCreateLoaderOnCoreThread(
context_core->AsWeakPtr(), container_host, request_destination, context_core->AsWeakPtr(), container_host, request_destination,
skip_service_worker, skip_service_worker,
handle_core->service_worker_accessed_callback())); 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 // If |initialize_container_host_only| is true, we have already determined
...@@ -193,7 +219,12 @@ bool SchemeMaySupportRedirectingToHTTPS(BrowserContext* browser_context, ...@@ -193,7 +219,12 @@ bool SchemeMaySupportRedirectingToHTTPS(BrowserContext* browser_context,
// Returns true if a ServiceWorkerMainResourceLoaderInterceptor should be // Returns true if a ServiceWorkerMainResourceLoaderInterceptor should be
// created for a worker with this |url|. // 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 // Create the handler even for insecure HTTP since it's used in the
// case of redirect to HTTPS. // case of redirect to HTTPS.
return url.SchemeIsHTTPOrHTTPS() || OriginCanAccessServiceWorkers(url); return url.SchemeIsHTTPOrHTTPS() || OriginCanAccessServiceWorkers(url);
...@@ -239,9 +270,9 @@ ServiceWorkerMainResourceLoaderInterceptor::CreateForWorker( ...@@ -239,9 +270,9 @@ ServiceWorkerMainResourceLoaderInterceptor::CreateForWorker(
network::mojom::RequestDestination::kSharedWorker) network::mojom::RequestDestination::kSharedWorker)
<< resource_request.destination; << resource_request.destination;
// Create the handler even for insecure HTTP since it's used in the if (!ShouldCreateForWorker(
// case of redirect to HTTPS. resource_request.url,
if (!ShouldCreateForWorker(resource_request.url)) navigation_handle->core()->parent_container_host()))
return nullptr; return nullptr;
return base::WrapUnique(new ServiceWorkerMainResourceLoaderInterceptor( return base::WrapUnique(new ServiceWorkerMainResourceLoaderInterceptor(
......
...@@ -783,8 +783,8 @@ void ServiceWorkerRegisterJob::AddRegistrationToMatchingContainerHosts( ...@@ -783,8 +783,8 @@ void ServiceWorkerRegisterJob::AddRegistrationToMatchingContainerHosts(
!it->IsAtEnd(); it->Advance()) { !it->IsAtEnd(); it->Advance()) {
ServiceWorkerContainerHost* container_host = it->GetContainerHost(); ServiceWorkerContainerHost* container_host = it->GetContainerHost();
DCHECK(container_host->IsContainerForClient()); DCHECK(container_host->IsContainerForClient());
if (!blink::ServiceWorkerScopeMatches(registration->scope(), if (!blink::ServiceWorkerScopeMatches(
container_host->url())) { registration->scope(), container_host->GetUrlForScopeMatch())) {
continue; continue;
} }
container_host->AddMatchingRegistration(registration); container_host->AddMatchingRegistration(registration);
......
...@@ -300,7 +300,7 @@ void ServiceWorkerRegistration::ClaimClients() { ...@@ -300,7 +300,7 @@ void ServiceWorkerRegistration::ClaimClients() {
continue; continue;
// "2. If client is not a secure context, continue." // "2. If client is not a secure context, continue."
if (!container_host->IsContextSecureForServiceWorker()) if (!container_host->IsEligibleForServiceWorkerController())
continue; continue;
// "3. Let registration be the result of running Match Service Worker // "3. Let registration be the result of running Match Service Worker
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "content/browser/blob_storage/chrome_blob_storage_context.h" #include "content/browser/blob_storage/chrome_blob_storage_context.h"
#include "content/browser/loader/content_security_notifier.h" #include "content/browser/loader/content_security_notifier.h"
#include "content/browser/renderer_host/render_frame_host_impl.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_main_resource_handle.h"
#include "content/browser/service_worker/service_worker_object_host.h" #include "content/browser/service_worker/service_worker_object_host.h"
#include "content/browser/storage_partition_impl.h" #include "content/browser/storage_partition_impl.h"
...@@ -185,6 +186,24 @@ void DedicatedWorkerHost::StartScriptLoad( ...@@ -185,6 +186,24 @@ void DedicatedWorkerHost::StartScriptLoad(
service_worker_handle_ = std::make_unique<ServiceWorkerMainResourceHandle>( service_worker_handle_ = std::make_unique<ServiceWorkerMainResourceHandle>(
storage_partition_impl->GetServiceWorkerContext(), base::DoNothing()); 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. // Get a storage domain.
auto partition_domain = auto partition_domain =
nearest_ancestor_render_frame_host->GetSiteInstance()->GetPartitionDomain( nearest_ancestor_render_frame_host->GetSiteInstance()->GetPartitionDomain(
......
...@@ -2,7 +2,7 @@ This is a testharness.js-based test. ...@@ -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 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 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 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(). 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" 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(). 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