Commit d36089ce authored by Matt Falkenhagen's avatar Matt Falkenhagen Committed by Commit Bot

PlzWorker: Support UI thread interceptors.

Bug: 985259
Change-Id: I45417af4401589c7ab47d61c63792e362ff37963
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1712952
Commit-Queue: Matt Falkenhagen <falken@chromium.org>
Reviewed-by: default avatarHiroki Nakagawa <nhiroki@chromium.org>
Cr-Commit-Position: refs/heads/master@{#680043}
parent f7f8f278
......@@ -290,6 +290,11 @@ void ServiceWorkerContextWrapper::set_storage_partition(
process_manager_->set_storage_partition(storage_partition_);
}
BrowserContext* ServiceWorkerContextWrapper::browser_context() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return process_manager()->browser_context();
}
ResourceContext* ServiceWorkerContextWrapper::resource_context() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return resource_context_;
......
......@@ -96,6 +96,9 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
void set_storage_partition(StoragePartitionImpl* storage_partition);
// UI thread.
BrowserContext* browser_context();
// The ResourceContext for the associated BrowserContext. This should only
// be accessed on the IO thread, and can be null during initialization and
// shutdown.
......
......@@ -55,4 +55,12 @@ void ServiceWorkerNavigationHandle::OnBeginNavigationCommit(
*out_provider_info = std::move(provider_info_);
}
void ServiceWorkerNavigationHandle::OnBeginWorkerCommit() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(&ServiceWorkerNavigationHandleCore::OnBeginWorkerCommit,
base::Unretained(core_)));
}
} // namespace content
......@@ -71,6 +71,8 @@ class CONTENT_EXPORT ServiceWorkerNavigationHandle {
int render_frame_id,
blink::mojom::ServiceWorkerProviderInfoForClientPtr* out_provider_info);
void OnBeginWorkerCommit();
blink::mojom::ServiceWorkerProviderInfoForClientPtr TakeProviderInfo() {
return std::move(provider_info_);
}
......@@ -81,6 +83,10 @@ class CONTENT_EXPORT ServiceWorkerNavigationHandle {
return context_wrapper_.get();
}
base::WeakPtr<ServiceWorkerNavigationHandle> AsWeakPtr() {
return weak_factory_.GetWeakPtr();
}
private:
blink::mojom::ServiceWorkerProviderInfoForClientPtr provider_info_;
......
......@@ -78,10 +78,7 @@ void InvokeRequestHandlerOnIO(
void MaybeCreateLoaderOnIO(
base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor> interceptor_on_ui,
ServiceWorkerNavigationHandleCore* handle_core,
bool are_ancestors_secure,
int frame_tree_node_id,
ResourceType resource_type,
bool skip_service_worker,
const ServiceWorkerNavigationLoaderInterceptorParams& params,
const network::ResourceRequest& tentative_resource_request,
BrowserContext* browser_context,
NavigationLoaderInterceptor::LoaderCallback loader_callback,
......@@ -110,17 +107,30 @@ void MaybeCreateLoaderOnIO(
// ServiceWorkerNavigationHandle on the UI thread, and finally passed to the
// renderer when the navigation commits.
provider_info = blink::mojom::ServiceWorkerProviderInfoForClient::New();
provider_host = ServiceWorkerProviderHost::PreCreateNavigationHost(
context_core->AsWeakPtr(), are_ancestors_secure, frame_tree_node_id,
&provider_info);
if (params.resource_type == ResourceType::kMainFrame ||
params.resource_type == ResourceType::kSubFrame) {
provider_host = ServiceWorkerProviderHost::PreCreateNavigationHost(
context_core->AsWeakPtr(), params.are_ancestors_secure,
params.frame_tree_node_id, &provider_info);
} else {
DCHECK(params.resource_type == ResourceType::kWorker ||
params.resource_type == ResourceType::kSharedWorker);
auto provider_type =
params.resource_type == ResourceType::kWorker
? blink::mojom::ServiceWorkerProviderType::kForDedicatedWorker
: blink::mojom::ServiceWorkerProviderType::kForSharedWorker;
provider_host = ServiceWorkerProviderHost::PreCreateForWebWorker(
context_core->AsWeakPtr(), params.process_id, provider_type,
&provider_info);
}
handle_core->set_provider_host(provider_host);
// Also make the inner interceptor.
DCHECK(!handle_core->interceptor());
handle_core->set_interceptor(
std::make_unique<ServiceWorkerControlleeRequestHandler>(
context_core->AsWeakPtr(), provider_host, resource_type,
skip_service_worker));
context_core->AsWeakPtr(), provider_host, params.resource_type,
params.skip_service_worker));
}
// If |initialize_provider_only| is true, we have already determined there is
......@@ -152,14 +162,9 @@ void MaybeCreateLoaderOnIO(
ServiceWorkerNavigationLoaderInterceptor::
ServiceWorkerNavigationLoaderInterceptor(
const NavigationRequestInfo& request_info,
const ServiceWorkerNavigationLoaderInterceptorParams& params,
ServiceWorkerNavigationHandle* handle)
: handle_(handle),
are_ancestors_secure_(request_info.are_ancestors_secure),
frame_tree_node_id_(request_info.frame_tree_node_id),
resource_type_(request_info.is_main_frame ? ResourceType::kMainFrame
: ResourceType::kSubFrame),
skip_service_worker_(request_info.begin_params->skip_service_worker) {
: handle_(handle), params_(params) {
DCHECK(NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled());
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
......@@ -194,10 +199,9 @@ void ServiceWorkerNavigationLoaderInterceptor::MaybeCreateLoader(
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(&MaybeCreateLoaderOnIO, GetWeakPtr(), handle_->core(),
are_ancestors_secure_, frame_tree_node_id_, resource_type_,
skip_service_worker_, tentative_resource_request,
browser_context, std::move(loader_callback),
std::move(fallback_callback), initialize_provider_only));
params_, tentative_resource_request, browser_context,
std::move(loader_callback), std::move(fallback_callback),
initialize_provider_only));
}
base::Optional<SubresourceLoaderParams>
......
......@@ -11,19 +11,36 @@
#include "content/browser/loader/navigation_loader_interceptor.h"
#include "content/browser/navigation_subresource_loader_params.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/resource_type.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_provider.mojom.h"
namespace content {
struct NavigationRequestInfo;
class ServiceWorkerNavigationHandle;
struct ServiceWorkerNavigationLoaderInterceptorParams {
// For all clients:
ResourceType resource_type = ResourceType::kMainFrame;
bool skip_service_worker = false;
// For windows:
bool is_main_frame = false;
// Whether all ancestor frames of the frame that is navigating have a secure
// origin. True for main frames.
bool are_ancestors_secure = false;
int frame_tree_node_id = RenderFrameHost::kNoFrameTreeNodeId;
// For web workers:
int process_id = ChildProcessHost::kInvalidUniqueID;
};
// This class is a work in progress for https://crbug.com/824858. It is used
// only when NavigationLoaderOnUI is enabled.
//
// Handles navigations for service worker clients (for now just documents, not
// web workers). Lives on the UI thread.
// Handles navigations for service worker clients (windows and web workers).
// Lives on the UI thread.
//
// The corresponding legacy class is ServiceWorkerControlleeRequestHandler which
// lives on the IO thread. Currently, this class just delegates to the
......@@ -32,7 +49,7 @@ class ServiceWorkerNavigationLoaderInterceptor final
: public NavigationLoaderInterceptor {
public:
ServiceWorkerNavigationLoaderInterceptor(
const NavigationRequestInfo& request_info,
const ServiceWorkerNavigationLoaderInterceptorParams& params,
ServiceWorkerNavigationHandle* handle);
~ServiceWorkerNavigationLoaderInterceptor() override;
......@@ -74,10 +91,7 @@ class ServiceWorkerNavigationLoaderInterceptor final
// |handle_| owns |this|.
ServiceWorkerNavigationHandle* const handle_;
const bool are_ancestors_secure_;
const int frame_tree_node_id_;
const ResourceType resource_type_;
const bool skip_service_worker_;
const ServiceWorkerNavigationLoaderInterceptorParams params_;
base::Optional<SubresourceLoaderParams> subresource_loader_params_;
......
......@@ -52,8 +52,16 @@ ServiceWorkerRequestHandler::CreateForNavigationUI(
return nullptr;
}
ServiceWorkerNavigationLoaderInterceptorParams params;
params.resource_type = request_info.is_main_frame ? ResourceType::kMainFrame
: ResourceType::kSubFrame;
params.skip_service_worker = request_info.begin_params->skip_service_worker;
params.is_main_frame = request_info.is_main_frame;
params.are_ancestors_secure = request_info.are_ancestors_secure;
params.frame_tree_node_id = request_info.frame_tree_node_id;
return std::make_unique<ServiceWorkerNavigationLoaderInterceptor>(
request_info, navigation_handle);
params, navigation_handle);
}
// static
......@@ -96,6 +104,36 @@ ServiceWorkerRequestHandler::CreateForNavigationIO(
request_info.begin_params->skip_service_worker);
}
// static
std::unique_ptr<NavigationLoaderInterceptor>
ServiceWorkerRequestHandler::CreateForWorkerUI(
const network::ResourceRequest& resource_request,
int process_id,
ServiceWorkerNavigationHandle* navigation_handle) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto resource_type =
static_cast<ResourceType>(resource_request.resource_type);
DCHECK(resource_type == ResourceType::kWorker ||
resource_type == ResourceType::kSharedWorker)
<< resource_request.resource_type;
// Create the handler even for insecure HTTP since it's used in the
// case of redirect to HTTPS.
if (!resource_request.url.SchemeIsHTTPOrHTTPS() &&
!OriginCanAccessServiceWorkers(resource_request.url)) {
return nullptr;
}
ServiceWorkerNavigationLoaderInterceptorParams params;
params.resource_type = resource_type;
params.skip_service_worker = resource_request.skip_service_worker;
params.process_id = process_id;
return std::make_unique<ServiceWorkerNavigationLoaderInterceptor>(
params, navigation_handle);
}
// static
std::unique_ptr<NavigationLoaderInterceptor>
ServiceWorkerRequestHandler::CreateForWorkerIO(
......
......@@ -46,7 +46,16 @@ class CONTENT_EXPORT ServiceWorkerRequestHandler {
const NavigationRequestInfo& request_info,
base::WeakPtr<ServiceWorkerProviderHost>* out_provider_host);
// Same as above but for a dedicated worker or shared worker. Called on the IO
// Returns a loader interceptor for a dedicated worker or shared worker. May
// return nullptr if the worker cannot use service workers. Called on the IO
// thread.
static std::unique_ptr<NavigationLoaderInterceptor> CreateForWorkerUI(
const network::ResourceRequest& resource_request,
int process_id,
ServiceWorkerNavigationHandle* navigation_handle);
// Returns a loader interceptor for a dedicated worker or shared worker. May
// return nullptr if the worker cannot use service workers. Called on the UI
// thread.
static std::unique_ptr<NavigationLoaderInterceptor> CreateForWorkerIO(
const network::ResourceRequest& resource_request,
......
......@@ -54,6 +54,23 @@
namespace content {
namespace {
// Runs |task| on the thread specified by |thread_id| if already on that thread,
// otherwise posts a task to that thread.
void RunOrPostTask(const base::Location& from_here,
BrowserThread::ID thread_id,
base::OnceClosure task) {
if (BrowserThread::CurrentlyOn(thread_id)) {
std::move(task).Run();
return;
}
base::PostTaskWithTraits(from_here, {thread_id}, std::move(task));
}
} // namespace
// static
void WorkerScriptFetchInitiator::Start(
int worker_process_id,
......@@ -160,8 +177,22 @@ void WorkerScriptFetchInitiator::Start(
AddAdditionalRequestHeaders(resource_request.get(), browser_context);
// Bounce to the IO thread to setup service worker and appcache support in
// case the request for the worker script will need to be intercepted by them.
// When navigation on UI is enabled, service worker and appcache work on the
// UI thread.
if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
CreateScriptLoaderOnUI(
worker_process_id, std::move(resource_request), storage_partition,
std::move(factory_bundle_for_browser),
std::move(subresource_loader_factories),
std::move(service_worker_context), service_worker_handle,
appcache_handle_core, std::move(blob_url_loader_factory),
std::move(url_loader_factory_override), std::move(callback));
return;
}
// Otherwise, bounce to the IO thread to setup service worker and appcache
// support in case the request for the worker script will need to be
// intercepted by them.
//
// This passes |resource_context| to the IO thread. |resource_context| will
// not be destroyed before the task runs, because the shutdown sequence is:
......@@ -185,6 +216,12 @@ void WorkerScriptFetchInitiator::Start(
std::move(callback)));
}
BrowserThread::ID WorkerScriptFetchInitiator::GetLoaderThreadID() {
return NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()
? BrowserThread::UI
: BrowserThread::IO;
}
std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
WorkerScriptFetchInitiator::CreateFactoryBundle(
int worker_process_id,
......@@ -255,6 +292,89 @@ void WorkerScriptFetchInitiator::AddAdditionalRequestHeaders(
SetFetchMetadataHeadersForBrowserInitiatedRequest(resource_request);
}
void WorkerScriptFetchInitiator::CreateScriptLoaderOnUI(
int worker_process_id,
std::unique_ptr<network::ResourceRequest> resource_request,
StoragePartitionImpl* storage_partition,
std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
factory_bundle_for_browser_info,
std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
subresource_loader_factories,
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
ServiceWorkerNavigationHandle* service_worker_handle,
AppCacheNavigationHandleCore* appcache_handle_core,
scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_override,
CompletionCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Create the URL loader factory for WorkerScriptLoaderFactory to use to load
// the main script.
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory;
if (blob_url_loader_factory) {
// If we have a blob_url_loader_factory just use that directly rather than
// creating a new URLLoaderFactoryBundle.
url_loader_factory = std::move(blob_url_loader_factory);
} else if (url_loader_factory_override) {
// For unit tests.
url_loader_factory = std::move(url_loader_factory_override);
} else {
// Add the default factory to the bundle for browser.
DCHECK(factory_bundle_for_browser_info);
// Get the direct network factory. This doesn't support reconnection to the
// network service after a crash, but it's OK since it's used only for a
// single request to fetch the worker's main script during startup. If the
// network service crashes, worker startup should simply fail.
network::mojom::URLLoaderFactoryPtr network_factory_ptr;
auto network_factory =
storage_partition->GetURLLoaderFactoryForBrowserProcess();
network_factory->Clone(mojo::MakeRequest(&network_factory_ptr));
factory_bundle_for_browser_info->pending_default_factory() =
network_factory_ptr.PassInterface();
url_loader_factory = base::MakeRefCounted<blink::URLLoaderFactoryBundle>(
std::move(factory_bundle_for_browser_info));
}
base::WeakPtr<AppCacheHost> appcache_host =
appcache_handle_core ? appcache_handle_core->host()->GetWeakPtr()
: nullptr;
// Start loading a web worker main script.
// TODO(nhiroki): Figure out what we should do in |wc_getter| for loading web
// worker's main script. Returning the WebContents of the closest ancestor's
// frame is a possible option, but it doesn't work when a shared worker
// creates a dedicated worker after the closest ancestor's frame is gone. The
// frame tree node ID has the same issue.
base::RepeatingCallback<WebContents*()> wc_getter =
base::BindRepeating([]() -> WebContents* { return nullptr; });
std::vector<std::unique_ptr<URLLoaderThrottle>> throttles =
GetContentClient()->browser()->CreateURLLoaderThrottles(
*resource_request, storage_partition->browser_context(), wc_getter,
nullptr /* navigation_ui_data */,
RenderFrameHost::kNoFrameTreeNodeId);
// Create a BrowserContext getter using |service_worker_context|.
// This context is aware of shutdown and safely returns a nullptr
// instead of a destroyed BrowserContext in that case.
auto browser_context_getter =
base::BindRepeating(&ServiceWorkerContextWrapper::browser_context,
std::move(service_worker_context));
WorkerScriptFetcher::CreateAndStart(
std::make_unique<WorkerScriptLoaderFactory>(
worker_process_id, service_worker_handle,
/*service_worker_handle_core=*/nullptr, std::move(appcache_host),
browser_context_getter,
base::RepeatingCallback<ResourceContext*(void)>(),
std::move(url_loader_factory)),
std::move(throttles), std::move(resource_request),
base::BindOnce(WorkerScriptFetchInitiator::DidCreateScriptLoader,
std::move(callback),
std::move(subresource_loader_factories)));
}
void WorkerScriptFetchInitiator::CreateScriptLoaderOnIO(
int worker_process_id,
std::unique_ptr<network::ResourceRequest> resource_request,
......@@ -352,23 +472,26 @@ void WorkerScriptFetchInitiator::CreateScriptLoaderOnIO(
WorkerScriptFetcher::CreateAndStart(
std::make_unique<WorkerScriptLoaderFactory>(
worker_process_id, service_worker_handle_core,
std::move(appcache_host), resource_context_getter,
std::move(url_loader_factory)),
worker_process_id,
/*service_worker_handle=*/nullptr, service_worker_handle_core,
std::move(appcache_host),
base::RepeatingCallback<BrowserContext*(void)>(),
resource_context_getter, std::move(url_loader_factory)),
std::move(throttles), std::move(resource_request),
base::BindOnce(WorkerScriptFetchInitiator::DidCreateScriptLoaderOnIO,
base::BindOnce(WorkerScriptFetchInitiator::DidCreateScriptLoader,
std::move(callback),
std::move(subresource_loader_factories)));
}
void WorkerScriptFetchInitiator::DidCreateScriptLoaderOnIO(
void WorkerScriptFetchInitiator::DidCreateScriptLoader(
CompletionCallback callback,
std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
subresource_loader_factories,
blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params,
base::Optional<SubresourceLoaderParams> subresource_loader_params,
bool success) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// This can be the UI thread or IO thread.
DCHECK_CURRENTLY_ON(GetLoaderThreadID());
// If a URLLoaderFactory for AppCache is supplied, use that.
if (subresource_loader_params &&
......@@ -388,8 +511,8 @@ void WorkerScriptFetchInitiator::DidCreateScriptLoaderOnIO(
subresource_loader_params->controller_service_worker_object_host;
}
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
RunOrPostTask(
FROM_HERE, BrowserThread::UI,
base::BindOnce(
std::move(callback), std::move(subresource_loader_factories),
std::move(main_script_load_params), std::move(controller),
......
......@@ -77,6 +77,12 @@ class WorkerScriptFetchInitiator {
StoragePartitionImpl* storage_partition,
CompletionCallback callback);
// Returns the BrowserThread::ID that the WorkerScriptLoaderFactory will be
// running on.
// TODO(crbug.com/824840): Remove this when non-NavigationLoaderOnUI code is
// removed.
static BrowserThread::ID GetLoaderThreadID();
private:
// Creates a loader factory bundle. Must be called on the UI thread.
static std::unique_ptr<blink::URLLoaderFactoryBundleInfo> CreateFactoryBundle(
......@@ -108,7 +114,23 @@ class WorkerScriptFetchInitiator {
url_loader_factory_override_info,
CompletionCallback callback);
static void DidCreateScriptLoaderOnIO(
static void CreateScriptLoaderOnUI(
int worker_process_id,
std::unique_ptr<network::ResourceRequest> resource_request,
StoragePartitionImpl* storage_partition,
std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
factory_bundle_for_browser_info,
std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
subresource_loader_factories,
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
ServiceWorkerNavigationHandle* service_worker_handle,
AppCacheNavigationHandleCore* appcache_handle_core,
scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
scoped_refptr<network::SharedURLLoaderFactory>
url_loader_factory_override,
CompletionCallback callback);
static void DidCreateScriptLoader(
CompletionCallback callback,
std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
subresource_loader_factories,
......
......@@ -6,6 +6,7 @@
#include "base/feature_list.h"
#include "content/browser/loader/navigation_url_loader_impl.h"
#include "content/browser/worker_host/worker_script_fetch_initiator.h"
#include "content/browser/worker_host/worker_script_loader.h"
#include "content/browser/worker_host/worker_script_loader_factory.h"
#include "content/common/throttling_url_loader.h"
......@@ -55,7 +56,7 @@ void WorkerScriptFetcher::CreateAndStart(
std::vector<std::unique_ptr<URLLoaderThrottle>> throttles,
std::unique_ptr<network::ResourceRequest> resource_request,
CreateAndStartCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_CURRENTLY_ON(WorkerScriptFetchInitiator::GetLoaderThreadID());
DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
// This fetcher will delete itself. See the class level comment.
(new WorkerScriptFetcher(std::move(script_loader_factory),
......@@ -71,16 +72,16 @@ WorkerScriptFetcher::WorkerScriptFetcher(
resource_request_(std::move(resource_request)),
callback_(std::move(callback)),
response_url_loader_binding_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_CURRENTLY_ON(WorkerScriptFetchInitiator::GetLoaderThreadID());
}
WorkerScriptFetcher::~WorkerScriptFetcher() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_CURRENTLY_ON(WorkerScriptFetchInitiator::GetLoaderThreadID());
}
void WorkerScriptFetcher::Start(
std::vector<std::unique_ptr<URLLoaderThrottle>> throttles) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_CURRENTLY_ON(WorkerScriptFetchInitiator::GetLoaderThreadID());
auto shared_url_loader_factory =
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
......@@ -104,13 +105,13 @@ void WorkerScriptFetcher::Start(
void WorkerScriptFetcher::OnReceiveResponse(
const network::ResourceResponseHead& response_head) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_CURRENTLY_ON(WorkerScriptFetchInitiator::GetLoaderThreadID());
response_head_ = response_head;
}
void WorkerScriptFetcher::OnStartLoadingResponseBody(
mojo::ScopedDataPipeConsumerHandle response_body) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_CURRENTLY_ON(WorkerScriptFetchInitiator::GetLoaderThreadID());
base::WeakPtr<WorkerScriptLoader> script_loader =
script_loader_factory_->GetScriptLoader();
......@@ -172,6 +173,7 @@ void WorkerScriptFetcher::OnStartLoadingResponseBody(
void WorkerScriptFetcher::OnReceiveRedirect(
const net::RedirectInfo& redirect_info,
const network::ResourceResponseHead& response_head) {
DCHECK_CURRENTLY_ON(WorkerScriptFetchInitiator::GetLoaderThreadID());
redirect_infos_.push_back(redirect_info);
redirect_response_heads_.push_back(response_head);
url_loader_->FollowRedirect({}, /* removed_headers */
......@@ -194,6 +196,7 @@ void WorkerScriptFetcher::OnTransferSizeUpdated(int32_t transfer_size_diff) {
void WorkerScriptFetcher::OnComplete(
const network::URLLoaderCompletionStatus& status) {
DCHECK_CURRENTLY_ON(WorkerScriptFetchInitiator::GetLoaderThreadID());
// We can reach here only when loading fails before receiving a response_head.
DCHECK_NE(net::OK, status.error_code);
std::move(callback_).Run(nullptr /* main_script_load_params */,
......
......@@ -32,7 +32,8 @@ class WorkerScriptLoaderFactory;
// resource loader in the renderer process will take them over.
//
// WorkerScriptFetcher deletes itself when the ownership of the loader and
// client is passed to the renderer, or on failure. It lives on the IO thread.
// client is passed to the renderer, or on failure. It lives on the IO or UI
// thread.
class WorkerScriptFetcher : public network::mojom::URLLoaderClient {
public:
using CreateAndStartCallback =
......
......@@ -26,9 +26,11 @@ class SharedURLLoaderFactory;
namespace content {
class AppCacheHost;
class BrowserContext;
class ThrottlingURLLoader;
class NavigationLoaderInterceptor;
class ResourceContext;
class ServiceWorkerNavigationHandle;
class ServiceWorkerNavigationHandleCore;
// The URLLoader for loading a shared worker script. Only used for the main
......@@ -41,7 +43,8 @@ class ServiceWorkerNavigationHandleCore;
// client. On redirects, it starts over with the new request URL, possibly
// starting a new loader and becoming the client of that.
//
// Lives on the IO thread.
// Lives on the UI thread when NavigationLoaderOnUI is enabled, and the IO
// thread otherwise.
class WorkerScriptLoader : public network::mojom::URLLoader,
public network::mojom::URLLoaderClient {
public:
......@@ -49,6 +52,10 @@ class WorkerScriptLoader : public network::mojom::URLLoader,
// the IO thread.
using ResourceContextGetter = base::RepeatingCallback<ResourceContext*(void)>;
// Returns the browser context, or nullptr during shutdown. Must be called on
// the UI thread.
using BrowserContextGetter = base::RepeatingCallback<BrowserContext*(void)>;
// |default_loader_factory| is used to load the script if the load is not
// intercepted by a feature like service worker. Typically it will load the
// script from the NetworkService. However, it may internally contain
......@@ -61,9 +68,12 @@ class WorkerScriptLoader : public network::mojom::URLLoader,
uint32_t options,
const network::ResourceRequest& resource_request,
network::mojom::URLLoaderClientPtr client,
base::WeakPtr<ServiceWorkerNavigationHandle>
service_worker_handle /* UI */,
base::WeakPtr<ServiceWorkerNavigationHandleCore>
service_worker_handle_core,
service_worker_handle_core /* IO */,
base::WeakPtr<AppCacheHost> appcache_host,
const BrowserContextGetter& browser_context_getter,
const ResourceContextGetter& resource_context_getter,
scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation);
......@@ -136,7 +146,9 @@ class WorkerScriptLoader : public network::mojom::URLLoader,
const uint32_t options_;
network::ResourceRequest resource_request_;
network::mojom::URLLoaderClientPtr client_;
base::WeakPtr<ServiceWorkerNavigationHandle> service_worker_handle_;
base::WeakPtr<ServiceWorkerNavigationHandleCore> service_worker_handle_core_;
BrowserContextGetter browser_context_getter_;
ResourceContextGetter resource_context_getter_;
scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory_;
net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
......@@ -159,4 +171,5 @@ class WorkerScriptLoader : public network::mojom::URLLoader,
};
} // namespace content
#endif // CONTENT_BROWSER_WORKER_HOST_WORKER_SCRIPT_LOADER_H_
......@@ -7,6 +7,7 @@
#include <memory>
#include "base/feature_list.h"
#include "content/browser/service_worker/service_worker_navigation_handle.h"
#include "content/browser/service_worker/service_worker_navigation_handle_core.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/browser/service_worker/service_worker_version.h"
......@@ -23,22 +24,30 @@ namespace content {
WorkerScriptLoaderFactory::WorkerScriptLoaderFactory(
int process_id,
ServiceWorkerNavigationHandleCore* service_worker_handle_core,
ServiceWorkerNavigationHandle* service_worker_handle /* UI only */,
ServiceWorkerNavigationHandleCore* service_worker_handle_core /* IO only */,
base::WeakPtr<AppCacheHost> appcache_host,
const BrowserContextGetter& browser_context_getter,
const ResourceContextGetter& resource_context_getter,
scoped_refptr<network::SharedURLLoaderFactory> loader_factory)
: process_id_(process_id),
appcache_host_(std::move(appcache_host)),
browser_context_getter_(browser_context_getter),
resource_context_getter_(resource_context_getter),
loader_factory_(std::move(loader_factory)) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_CURRENTLY_ON(WorkerScriptFetchInitiator::GetLoaderThreadID());
DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
DCHECK(service_worker_handle_core);
service_worker_handle_core_ = service_worker_handle_core->AsWeakPtr();
if (service_worker_handle) {
service_worker_handle_ = service_worker_handle->AsWeakPtr();
}
if (service_worker_handle_core) {
service_worker_handle_core_ = service_worker_handle_core->AsWeakPtr();
}
}
WorkerScriptLoaderFactory::~WorkerScriptLoaderFactory() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_CURRENTLY_ON(WorkerScriptFetchInitiator::GetLoaderThreadID());
}
void WorkerScriptLoaderFactory::CreateLoaderAndStart(
......@@ -49,7 +58,7 @@ void WorkerScriptLoaderFactory::CreateLoaderAndStart(
const network::ResourceRequest& resource_request,
network::mojom::URLLoaderClientPtr client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_CURRENTLY_ON(WorkerScriptFetchInitiator::GetLoaderThreadID());
DCHECK(resource_request.resource_type ==
static_cast<int>(ResourceType::kWorker) ||
resource_request.resource_type ==
......@@ -60,8 +69,9 @@ void WorkerScriptLoaderFactory::CreateLoaderAndStart(
// Create a WorkerScriptLoader to load the script.
auto script_loader = std::make_unique<WorkerScriptLoader>(
process_id_, routing_id, request_id, options, resource_request,
std::move(client), service_worker_handle_core_, appcache_host_,
resource_context_getter_, loader_factory_, traffic_annotation);
std::move(client), service_worker_handle_, service_worker_handle_core_,
appcache_host_, browser_context_getter_, resource_context_getter_,
loader_factory_, traffic_annotation);
script_loader_ = script_loader->GetWeakPtr();
mojo::MakeStrongBinding(std::move(script_loader), std::move(request));
}
......
......@@ -17,6 +17,8 @@ class SharedURLLoaderFactory;
namespace content {
class AppCacheHost;
class BrowserContext;
class ServiceWorkerNavigationHandle;
class ServiceWorkerNavigationHandleCore;
class ResourceContext;
class WorkerScriptLoader;
......@@ -27,7 +29,8 @@ class WorkerScriptLoader;
// It's an error to call CreateLoaderAndStart() more than a total of one time
// across this object or any of its clones.
//
// This is created per one web worker. It lives on the IO thread.
// This is created per one web worker. It lives on the UI thread when
// NavigationLoaderOnUI is enabled, and the IO thread otherwise.
class CONTENT_EXPORT WorkerScriptLoaderFactory
: public network::mojom::URLLoaderFactory {
public:
......@@ -35,14 +38,28 @@ class CONTENT_EXPORT WorkerScriptLoaderFactory
// the IO thread.
using ResourceContextGetter = base::RepeatingCallback<ResourceContext*(void)>;
// Returns the browser context, or nullptr during shutdown. Must be called on
// the UI thread.
using BrowserContextGetter = base::RepeatingCallback<BrowserContext*(void)>;
// |loader_factory| is used to load the script if the load is not intercepted
// by a feature like service worker. Typically it will load the script from
// the NetworkService. However, it may internally contain non-NetworkService
// factories used for non-http(s) URLs, e.g., a chrome-extension:// URL.
//
// NavigationLoaderOnUI:
// |service_worker_handle| and |browser_context_getter| can be
// used.
//
// Non-NavigationLoaderOnUI:
// |service_worker_handle_core| and |resource_context_getter| can
// be used.
WorkerScriptLoaderFactory(
int process_id,
ServiceWorkerNavigationHandle* service_worker_handle,
ServiceWorkerNavigationHandleCore* service_worker_handle_core,
base::WeakPtr<AppCacheHost> appcache_host,
const BrowserContextGetter& browser_context_getter,
const ResourceContextGetter& resource_context_getter,
scoped_refptr<network::SharedURLLoaderFactory> loader_factory);
~WorkerScriptLoaderFactory() override;
......@@ -62,8 +79,10 @@ class CONTENT_EXPORT WorkerScriptLoaderFactory
private:
const int process_id_;
base::WeakPtr<ServiceWorkerNavigationHandle> service_worker_handle_;
base::WeakPtr<ServiceWorkerNavigationHandleCore> service_worker_handle_core_;
base::WeakPtr<AppCacheHost> appcache_host_;
BrowserContextGetter browser_context_getter_;
ResourceContextGetter resource_context_getter_;
scoped_refptr<network::SharedURLLoaderFactory> loader_factory_;
......
......@@ -6,6 +6,7 @@
#include "base/bind_helpers.h"
#include "base/run_loop.h"
#include "content/browser/loader/navigation_url_loader_impl.h"
#include "content/browser/service_worker/embedded_worker_test_helper.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
......@@ -39,6 +40,10 @@ class WorkerScriptLoaderFactoryTest : public testing::Test {
context->storage()->LazyInitializeForTest(base::DoNothing());
base::RunLoop().RunUntilIdle();
browser_context_getter_ =
base::BindRepeating(&ServiceWorkerContextWrapper::browser_context,
helper_->context_wrapper());
resource_context_getter_ =
base::BindRepeating(&ServiceWorkerContextWrapper::resource_context,
helper_->context_wrapper());
......@@ -82,15 +87,16 @@ class WorkerScriptLoaderFactoryTest : public testing::Test {
scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory_;
std::unique_ptr<ServiceWorkerNavigationHandle> service_worker_handle_;
WorkerScriptLoaderFactory::BrowserContextGetter browser_context_getter_;
WorkerScriptLoaderFactory::ResourceContextGetter resource_context_getter_;
};
TEST_F(WorkerScriptLoaderFactoryTest, ServiceWorkerProviderHost) {
// Make the factory.
auto factory = std::make_unique<WorkerScriptLoaderFactory>(
kProcessId, service_worker_handle_->core(),
/*appcache_host=*/nullptr, resource_context_getter_,
network_loader_factory_);
kProcessId, service_worker_handle_.get(), service_worker_handle_->core(),
/*appcache_host=*/nullptr, browser_context_getter_,
resource_context_getter_, network_loader_factory_);
// Load the script.
GURL url("https://www.example.com/worker.js");
......@@ -113,7 +119,8 @@ TEST_F(WorkerScriptLoaderFactoryTest, ServiceWorkerProviderHost) {
TEST_F(WorkerScriptLoaderFactoryTest, NullServiceWorkerHandle) {
// Make the factory.
auto factory = std::make_unique<WorkerScriptLoaderFactory>(
kProcessId, service_worker_handle_->core(), nullptr /* appcache_host */,
kProcessId, service_worker_handle_.get(), service_worker_handle_->core(),
nullptr /* appcache_host */, browser_context_getter_,
resource_context_getter_, network_loader_factory_);
// Destroy the handle.
......@@ -134,9 +141,15 @@ TEST_F(WorkerScriptLoaderFactoryTest, NullServiceWorkerHandle) {
// shutdown starts between the constructor and when CreateLoaderAndStart is
// invoked.
TEST_F(WorkerScriptLoaderFactoryTest, NullResourceContext) {
if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
// Resource context is irrelevant.
return;
}
// Make the factory.
auto factory = std::make_unique<WorkerScriptLoaderFactory>(
kProcessId, service_worker_handle_->core(), nullptr /* appcache_host */,
kProcessId, service_worker_handle_.get(), service_worker_handle_->core(),
nullptr /* appcache_host */, browser_context_getter_,
resource_context_getter_, network_loader_factory_);
// Set a null resource context.
......@@ -151,6 +164,33 @@ TEST_F(WorkerScriptLoaderFactoryTest, NullResourceContext) {
EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
}
// Test a null browser context when the request starts. This happens when
// shutdown starts between the constructor and when CreateLoaderAndStart is
// invoked.
TEST_F(WorkerScriptLoaderFactoryTest, NullBrowserContext) {
if (!NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
// Browser context is irrelevant.
return;
}
// Make the factory.
auto factory = std::make_unique<WorkerScriptLoaderFactory>(
kProcessId, service_worker_handle_.get(), service_worker_handle_->core(),
nullptr /* appcache_host */, browser_context_getter_,
resource_context_getter_, network_loader_factory_);
// Set a null browser context.
helper_->context_wrapper()->Shutdown();
// Load the script.
GURL url("https://www.example.com/worker.js");
network::TestURLLoaderClient client;
network::mojom::URLLoaderPtr loader =
CreateTestLoaderAndStart(url, factory.get(), &client);
client.RunUntilComplete();
EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
}
// TODO(falken): Add a test for a shared worker that's controlled by a service
// worker.
......
# These tests currently fail when run with --enable-features=NavigationLoaderOnUI
# See https://crbug.com/824840
# service worker
Bug(none) external/wpt/html/browsers/offline/appcache/workers/appcache-worker.https.html [ Skip ]
Bug(none) virtual/not-omt-sw-fetch/external/wpt/html/browsers/offline/appcache/workers/appcache-worker.https.html [ Skip ]
Bug(none) virtual/omt-worker-fetch/external/wpt/html/browsers/offline/appcache/workers/appcache-worker.https.html [ Skip ]
Bug(none) http/tests/misc/xhtml.php [ Failure ]
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