Commit 82faa92e authored by Matt Falkenhagen's avatar Matt Falkenhagen Committed by Commit Bot

service worker: Initial patch for navigation on the UI thread.

This adds ServiceWorkerNavigationLoaderInterceptor which lives on the
UI thread. Currently it just delegates to the existing interceptor on
the IO thread. The goal is to migrate things to the UI thread.

There are no new tests added as this is still initial work, but
it enables several of the existing browser tests.

Change-Id: I69d9b09c308b0e2c711a304390c04574c734a2d9
Bug: 824858
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1688592
Commit-Queue: Matt Falkenhagen <falken@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#676354}
parent 06a4958e
......@@ -1798,6 +1798,8 @@ jumbo_source_set("browser") {
"service_worker/service_worker_navigation_handle_core.h",
"service_worker/service_worker_navigation_loader.cc",
"service_worker/service_worker_navigation_loader.h",
"service_worker/service_worker_navigation_loader_interceptor.cc",
"service_worker/service_worker_navigation_loader_interceptor.h",
"service_worker/service_worker_new_script_loader.cc",
"service_worker/service_worker_new_script_loader.h",
"service_worker/service_worker_object_host.cc",
......
......@@ -83,6 +83,8 @@ class CONTENT_EXPORT NavigationLoaderInterceptor {
// requests going forward. Subclasses who want to set-up custom loader for
// subresource requests may want to override this.
//
// This is always called after MaybeCreateLoader().
//
// Note that the handler can return a null callback to MaybeCreateLoader(),
// and at the same time can return non-null SubresourceLoaderParams here if it
// does NOT want to handle the specific request given to MaybeCreateLoader()
......
......@@ -518,29 +518,34 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
base::Unretained(upload_file_system_context),
base::Unretained(appcache_handle_core));
StartInternal(request_info_.get(), service_worker_navigation_handle_core,
nullptr /* appcache_handle_core */,
StartInternal(request_info_.get(),
/*service_worker_navigation_handle=*/nullptr,
service_worker_navigation_handle_core,
/*appcache_handle_core=*/nullptr,
std::move(prefetched_signed_exchange_cache),
std::move(signed_exchange_prefetch_metric_recorder),
{} /* factory_for_webui */, url_request_context_getter,
/*factory_for_webui=*/{}, url_request_context_getter,
std::move(accept_langs));
}
void Start(
std::unique_ptr<network::SharedURLLoaderFactoryInfo>
network_loader_factory_info,
ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
AppCacheNavigationHandleCore* appcache_handle_core,
scoped_refptr<PrefetchedSignedExchangeCache>
prefetched_signed_exchange_cache,
scoped_refptr<SignedExchangePrefetchMetricRecorder>
signed_exchange_prefetch_metric_recorder,
std::unique_ptr<NavigationRequestInfo> request_info,
std::unique_ptr<NavigationUIData> navigation_ui_data,
network::mojom::URLLoaderFactoryPtrInfo factory_for_webui,
bool needs_loader_factory_interceptor,
base::Time ui_post_time,
std::string accept_langs) {
// This can be called on the UI or IO thread.
void Start(std::unique_ptr<network::SharedURLLoaderFactoryInfo>
network_loader_factory_info,
ServiceWorkerNavigationHandle*
service_worker_navigation_handle /* for UI thread only */,
ServiceWorkerNavigationHandleCore*
service_worker_navigation_handle_core /* for IO thread only */,
AppCacheNavigationHandleCore* appcache_handle_core,
scoped_refptr<PrefetchedSignedExchangeCache>
prefetched_signed_exchange_cache,
scoped_refptr<SignedExchangePrefetchMetricRecorder>
signed_exchange_prefetch_metric_recorder,
std::unique_ptr<NavigationRequestInfo> request_info,
std::unique_ptr<NavigationUIData> navigation_ui_data,
network::mojom::URLLoaderFactoryPtrInfo factory_for_webui,
bool needs_loader_factory_interceptor,
base::Time ui_post_time,
std::string accept_langs) {
DCHECK_CURRENTLY_ON(GetLoaderRequestControllerThreadID());
DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
DCHECK(!started_);
......@@ -582,25 +587,32 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
CHECK(result && blob_handles_.empty());
}
StartInternal(
request_info.get(), service_worker_navigation_handle_core,
appcache_handle_core, std::move(prefetched_signed_exchange_cache),
std::move(signed_exchange_prefetch_metric_recorder),
std::move(factory_for_webui), nullptr /* url_request_context_getter */,
std::move(accept_langs));
StartInternal(request_info.get(), service_worker_navigation_handle,
service_worker_navigation_handle_core, appcache_handle_core,
std::move(prefetched_signed_exchange_cache),
std::move(signed_exchange_prefetch_metric_recorder),
std::move(factory_for_webui),
nullptr /* url_request_context_getter */,
std::move(accept_langs));
}
// Common setup routines, called by both StartWithoutNetworkService() and
// Start(). Most parameters (except for |request_info| and
// Start() and can be called either on the UI or IO thread.
//
// Most parameters (except for |request_info| and
// |url_request_context_getter|) are for setting up feature-specific
// loaders and interceptors, and they can be null depending on the flags.
// |url_request_context_getter| is non-null only for non-NetworkService
// code paths.
//
// TODO(kinuko): Merge this back to Start() once NetworkService is fully
// shipped.
void StartInternal(
NavigationRequestInfo* request_info,
ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
ServiceWorkerNavigationHandle*
service_worker_navigation_handle /* ui thread only */,
ServiceWorkerNavigationHandleCore*
service_worker_navigation_handle_core /* io thread only */,
AppCacheNavigationHandleCore* appcache_handle_core,
scoped_refptr<PrefetchedSignedExchangeCache>
prefetched_signed_exchange_cache,
......@@ -609,6 +621,8 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
network::mojom::URLLoaderFactoryPtrInfo factory_for_webui,
net::URLRequestContextGetter* url_request_context_getter,
std::string accept_langs) {
DCHECK_CURRENTLY_ON(GetLoaderRequestControllerThreadID());
std::string accept_value = network::kFrameAcceptHeader;
// TODO(http://crbug.com/824840): Make this work on UI thread.
if (!IsNavigationLoaderOnUIEnabled()) {
......@@ -649,7 +663,7 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
}
if (IsNavigationLoaderOnUIEnabled()) {
CreateInterceptorsForUI(request_info);
CreateInterceptorsForUI(request_info, service_worker_navigation_handle);
} else {
CreateInterceptorsForIO(
request_info, service_worker_navigation_handle_core,
......@@ -678,7 +692,21 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
Restart();
}
void CreateInterceptorsForUI(NavigationRequestInfo* request_info) {
void CreateInterceptorsForUI(
NavigationRequestInfo* request_info,
ServiceWorkerNavigationHandle* service_worker_navigation_handle) {
// Set up an interceptor for service workers.
if (service_worker_navigation_handle) {
std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor =
ServiceWorkerRequestHandler::CreateForNavigationUI(
resource_request_->url, service_worker_navigation_handle,
*request_info);
// The interceptor may not be created in certain cases (e.g., the origin
// is not secure).
if (service_worker_interceptor)
interceptors_.push_back(std::move(service_worker_interceptor));
}
// See if embedders want to add interceptors.
std::vector<std::unique_ptr<URLLoaderRequestInterceptor>>
browser_interceptors =
......@@ -721,7 +749,7 @@ class NavigationURLLoaderImpl::URLLoaderRequestController
// Set-up an interceptor for service workers.
if (service_worker_navigation_handle_core) {
std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor =
ServiceWorkerRequestHandler::CreateForNavigation(
ServiceWorkerRequestHandler::CreateForNavigationIO(
resource_request_->url, service_worker_navigation_handle_core,
*request_info, &service_worker_provider_host_);
// The interceptor for service worker may not be created for some
......@@ -1756,7 +1784,7 @@ NavigationURLLoaderImpl::NavigationURLLoaderImpl(
base::BindOnce(
&URLLoaderRequestController::Start,
base::Unretained(request_controller_.get()),
std::move(network_factory_info),
std::move(network_factory_info), service_worker_navigation_handle,
service_worker_navigation_handle_core, appcache_handle_core,
std::move(prefetched_signed_exchange_cache),
std::move(signed_exchange_prefetch_metric_recorder),
......
......@@ -309,6 +309,11 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
blink::mojom::ServiceWorkerProviderType provider_type,
blink::mojom::ServiceWorkerProviderInfoForWorkerPtr* out_provider_info);
// The core context is only for use on the IO thread.
// Can be null before/during init, during/after shutdown, and after
// DeleteAndStartOver fails.
ServiceWorkerContextCore* context();
private:
friend class BackgroundSyncManagerTest;
friend class base::RefCountedThreadSafe<ServiceWorkerContextWrapper>;
......@@ -414,11 +419,6 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
blink::ServiceWorkerStatusCode status,
scoped_refptr<ServiceWorkerRegistration> registration);
// The core context is only for use on the IO thread.
// Can be null before/during init, during/after shutdown, and after
// DeleteAndStartOver fails.
ServiceWorkerContextCore* context();
void GetAllServiceWorkerRunningInfosOnIO(
GetAllServiceWorkerRunningInfosCallback callback,
scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_callback);
......
......@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/trace_event/trace_event.h"
#include "components/offline_pages/buildflags/buildflags.h"
#include "content/browser/loader/navigation_url_loader_impl.h"
#include "content/browser/navigation_subresource_loader_params.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_metrics.h"
......@@ -226,15 +227,23 @@ void ServiceWorkerControlleeRequestHandler::ContinueWithRegistration(
return;
}
if (!GetContentClient()->browser()->AllowServiceWorker(
registration->scope(), provider_host_->site_for_cookies(), GURL(),
resource_context_, provider_host_->web_contents_getter())) {
TRACE_EVENT_ASYNC_END1(
"ServiceWorker",
"ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this,
"Info", "ServiceWorker is blocked");
CompleteWithoutLoader();
return;
if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
// AllowServiceWorker() expects to be called on the IO thread with a valid
// ResourceContext, and we have a null context here, so skip calling it.
// TODO(crbug.com/926114, crbug.com/908955): Implement
// AllowServiceWorkerUI() with a browser_context instead of
// resource_context?
} else {
if (!GetContentClient()->browser()->AllowServiceWorker(
registration->scope(), provider_host_->site_for_cookies(), GURL(),
resource_context_, provider_host_->web_contents_getter())) {
TRACE_EVENT_ASYNC_END1(
"ServiceWorker",
"ServiceWorkerControlleeRequestHandler::PrepareForMainResource", this,
"Info", "ServiceWorker is blocked");
CompleteWithoutLoader();
return;
}
}
if (!provider_host_->IsContextSecureForServiceWorker()) {
......
......@@ -33,7 +33,6 @@ class ServiceWorkerVersion;
// Handles main resource requests for service worker clients (documents and
// shared workers).
// TODO(falken): Rename to ServiceWorkerNavigationLoaderInterceptor.
class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler final
: public NavigationLoaderInterceptor {
public:
......
......@@ -20,7 +20,7 @@ class ServiceWorkerNavigationHandleCore;
//
// The lifetime of the ServiceWorkerNavigationHandle, the
// ServiceWorkerNavigationHandleCore and the ServiceWorkerProviderHost are the
// following :
// following:
// 1) We create a ServiceWorkerNavigationHandle on the UI thread without
// populating the member service worker provider info. This also leads to the
// creation of a ServiceWorkerNavigationHandleCore.
......
......@@ -4,8 +4,6 @@
#include "content/browser/service_worker/service_worker_navigation_handle_core.h"
#include <utility>
#include "base/bind.h"
#include "base/task/post_task.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
......
......@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_NAVIGATION_HANDLE_CORE_H_
#include <memory>
#include <utility>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
......@@ -19,7 +20,6 @@ class ServiceWorkerContextWrapper;
class ServiceWorkerNavigationHandle;
class ServiceWorkerProviderHost;
// PlzNavigate
// This class is created on the UI thread, but should only be accessed from the
// IO thread afterwards. It is the IO thread pendant of
// ServiceWorkerNavigationHandle. See the ServiceWorkerNavigationHandle header
......@@ -36,6 +36,11 @@ class CONTENT_EXPORT ServiceWorkerNavigationHandleCore {
base::WeakPtr<ServiceWorkerProviderHost> provider_host,
blink::mojom::ServiceWorkerProviderInfoForWindowPtr provider_info);
void set_provider_host(
base::WeakPtr<ServiceWorkerProviderHost> provider_host) {
provider_host_ = std::move(provider_host);
}
// Called when the navigation is ready to commit, set the 2 IDs for the
// pre-created provider host.
void OnBeginNavigationCommit(int render_process_id, int render_frame_id);
......
......@@ -120,6 +120,7 @@ void ServiceWorkerNavigationLoader::StartRequest(
"url", resource_request.url.spec());
DCHECK(ServiceWorkerUtils::IsMainResourceType(
static_cast<ResourceType>(resource_request.resource_type)));
DCHECK_CURRENTLY_ON(BrowserThread::IO);
resource_request_ = resource_request;
if (provider_host_ && provider_host_->fetch_request_window_id()) {
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/service_worker/service_worker_navigation_loader_interceptor.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/optional.h"
#include "base/task/post_task.h"
#include "content/browser/frame_host/navigation_request_info.h"
#include "content/browser/loader/navigation_url_loader_impl.h"
#include "content/browser/navigation_subresource_loader_params.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_controllee_request_handler.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/public/browser/browser_task_traits.h"
namespace content {
namespace {
///////////////////////////////////////////////////////////////////////////////
// IO thread helpers
using SetupCallback =
base::OnceCallback<void(blink::mojom::ServiceWorkerProviderInfoForWindowPtr,
std::unique_ptr<NavigationLoaderInterceptor,
BrowserThread::DeleteOnIOThread>)>;
// Does setup on the IO thread and calls |callback| on the UI thread.
void InitOnIO(ServiceWorkerNavigationHandleCore* handle_core,
bool are_ancestors_secure,
int frame_tree_node_id,
ResourceType resource_type,
bool skip_service_worker,
SetupCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
ServiceWorkerContextCore* context_core =
handle_core->context_wrapper()->context();
if (!context_core) {
PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(std::move(callback), /*provider_info=*/nullptr,
/*interceptor=*/nullptr));
return;
}
// Make the provider host.
auto provider_info = blink::mojom::ServiceWorkerProviderInfoForWindow::New();
base::WeakPtr<ServiceWorkerProviderHost> provider_host =
ServiceWorkerProviderHost::PreCreateNavigationHost(
context_core->AsWeakPtr(), are_ancestors_secure, frame_tree_node_id,
&provider_info);
handle_core->set_provider_host(provider_host);
// TODO(crbug.com/926114): Respect |skip_service_worker|.
// Make the inner interceptor.
std::unique_ptr<ServiceWorkerControlleeRequestHandler,
BrowserThread::DeleteOnIOThread>
interceptor(new ServiceWorkerControlleeRequestHandler(
context_core->AsWeakPtr(), provider_host, resource_type));
PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(std::move(callback), std::move(provider_info),
std::move(interceptor)));
}
void LoaderCallbackWrapperOnIO(
base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor> interceptor_on_ui,
SingleRequestURLLoaderFactory::RequestHandler handler) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(
&ServiceWorkerNavigationLoaderInterceptor::LoaderCallbackWrapper,
interceptor_on_ui, std::move(handler)));
}
void FallbackCallbackWrapperOnIO(
base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor> interceptor_on_ui,
bool reset_subresource_loader_params) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(
&ServiceWorkerNavigationLoaderInterceptor::FallbackCallbackWrapper,
interceptor_on_ui, reset_subresource_loader_params));
}
void InvokeRequestHandlerOnIO(
SingleRequestURLLoaderFactory::RequestHandler handler,
const network::ResourceRequest& resource_request,
network::mojom::URLLoaderRequest request,
network::mojom::URLLoaderClientPtrInfo client_info) {
network::mojom::URLLoaderClientPtr client(std::move(client_info));
std::move(handler).Run(resource_request, std::move(request),
std::move(client));
}
///////////////////////////////////////////////////////////////////////////////
} // namespace
ServiceWorkerNavigationLoaderInterceptor::
ServiceWorkerNavigationLoaderInterceptor(
const NavigationRequestInfo& request_info,
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) {
DCHECK(NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled());
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
ServiceWorkerNavigationLoaderInterceptor::
~ServiceWorkerNavigationLoaderInterceptor() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
void ServiceWorkerNavigationLoaderInterceptor::MaybeCreateLoader(
const network::ResourceRequest& tentative_resource_request,
BrowserContext* browser_context,
ResourceContext* resource_context,
LoaderCallback loader_callback,
FallbackCallback fallback_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// First make the inner interceptor if it hasn't been done yet. We'll
// come back here after.
if (!interceptor_on_io_) {
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(
&InitOnIO, handle_->core(), are_ancestors_secure_,
frame_tree_node_id_, resource_type_, skip_service_worker_,
base::BindOnce(
&ServiceWorkerNavigationLoaderInterceptor::OnInitComplete,
GetWeakPtr(), tentative_resource_request, browser_context,
resource_context, std::move(loader_callback),
std::move(fallback_callback))));
return;
}
// Start the inner interceptor on the IO thread. It will call back to
// functions on the IO thread which hop back to LoaderCallbackWrapper() or
// FallbackCallbackWrapper() on the UI thread.
loader_callback_ = std::move(loader_callback);
fallback_callback_ = std::move(fallback_callback);
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(
&NavigationLoaderInterceptor::MaybeCreateLoader,
base::Unretained(interceptor_on_io_.get()),
tentative_resource_request, browser_context, resource_context,
base::BindOnce(&LoaderCallbackWrapperOnIO, GetWeakPtr()),
base::BindOnce(&FallbackCallbackWrapperOnIO, GetWeakPtr())));
}
base::Optional<SubresourceLoaderParams>
ServiceWorkerNavigationLoaderInterceptor::MaybeCreateSubresourceLoaderParams() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// TODO(crbug.com/926114): Implement this. The params have to be received from
// the IO thread inner interceptor before MaybeCreateLoader() is completed, so
// this function can synchronously return them.
return base::nullopt;
}
void ServiceWorkerNavigationLoaderInterceptor::OnInitComplete(
const network::ResourceRequest& tentative_resource_request,
BrowserContext* browser_context,
ResourceContext* resource_context,
LoaderCallback callback,
FallbackCallback fallback_callback,
blink::mojom::ServiceWorkerProviderInfoForWindowPtr provider_info,
std::unique_ptr<NavigationLoaderInterceptor,
BrowserThread::DeleteOnIOThread> interceptor) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!interceptor_on_io_);
interceptor_on_io_ = std::move(interceptor);
handle_->OnCreatedProviderHost(std::move(provider_info));
MaybeCreateLoader(tentative_resource_request, browser_context,
resource_context, std::move(callback),
std::move(fallback_callback));
}
void ServiceWorkerNavigationLoaderInterceptor::LoaderCallbackWrapper(
SingleRequestURLLoaderFactory::RequestHandler handler_on_io) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!handler_on_io) {
std::move(loader_callback_).Run({});
return;
}
// The inner IO thread interceptor wants to handle the request. However,
// |handler_on_io| expects to run on the IO thread. Give our own wrapper to
// the loader callback.
std::move(loader_callback_)
.Run(base::BindOnce(
&ServiceWorkerNavigationLoaderInterceptor::RequestHandlerWrapper,
GetWeakPtr(), std::move(handler_on_io)));
}
void ServiceWorkerNavigationLoaderInterceptor::FallbackCallbackWrapper(
bool reset_subresource_loader_params) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
std::move(fallback_callback_).Run(reset_subresource_loader_params);
}
base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor>
ServiceWorkerNavigationLoaderInterceptor::GetWeakPtr() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return weak_factory_.GetWeakPtr();
}
void ServiceWorkerNavigationLoaderInterceptor::RequestHandlerWrapper(
SingleRequestURLLoaderFactory::RequestHandler handler_on_io,
const network::ResourceRequest& resource_request,
network::mojom::URLLoaderRequest request,
network::mojom::URLLoaderClientPtr client) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(InvokeRequestHandlerOnIO, std::move(handler_on_io),
resource_request, std::move(request),
client.PassInterface()));
}
} // namespace content
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_NAVIGATION_LOADER_INTERCEPTOR_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_NAVIGATION_LOADER_INTERCEPTOR_H_
#include <memory>
#include "base/memory/weak_ptr.h"
#include "content/browser/loader/navigation_loader_interceptor.h"
#include "content/public/browser/browser_thread.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;
// 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.
//
// The corresponding legacy class is ServiceWorkerControlleeRequestHandler which
// lives on the IO thread. Currently, this class just delegates to the
// legacy class by posting tasks to it on the IO thread.
class ServiceWorkerNavigationLoaderInterceptor final
: public NavigationLoaderInterceptor {
public:
ServiceWorkerNavigationLoaderInterceptor(
const NavigationRequestInfo& request_info,
ServiceWorkerNavigationHandle* handle);
~ServiceWorkerNavigationLoaderInterceptor() override;
// NavigationLoaderInterceptor overrides:
// This could get called multiple times during the lifetime in redirect
// cases. (In fallback-to-network cases we basically forward the request
// to the request to the next request handler)
void MaybeCreateLoader(const network::ResourceRequest& tentative_request,
BrowserContext* browser_context,
ResourceContext* resource_context,
LoaderCallback callback,
FallbackCallback fallback_callback) override;
// Returns params with the ControllerServiceWorkerPtr if we have found
// a matching controller service worker for the |request| that is given
// to MaybeCreateLoader(). Otherwise this returns base::nullopt.
base::Optional<SubresourceLoaderParams> MaybeCreateSubresourceLoaderParams()
override;
// These are called back from the IO thread helper functions:
void OnInitComplete(
const network::ResourceRequest& tentative_resource_request,
BrowserContext* browser_context,
ResourceContext* resource_context,
LoaderCallback callback,
FallbackCallback fallback_callback,
blink::mojom::ServiceWorkerProviderInfoForWindowPtr provider_info,
std::unique_ptr<NavigationLoaderInterceptor,
BrowserThread::DeleteOnIOThread> interceptor);
void LoaderCallbackWrapper(
SingleRequestURLLoaderFactory::RequestHandler handler);
void FallbackCallbackWrapper(bool reset_subresource_loader_params);
base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor> GetWeakPtr();
private:
// Given as a callback to NavigationURLLoaderImpl.
void RequestHandlerWrapper(
SingleRequestURLLoaderFactory::RequestHandler handler_on_io,
const network::ResourceRequest& resource_request,
network::mojom::URLLoaderRequest request,
network::mojom::URLLoaderClientPtr client);
// |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_;
LoaderCallback loader_callback_;
FallbackCallback fallback_callback_;
// The inner interceptor. This actually does the work and its methods must be
// called only on the IO thread. The goal is to move everything it does to the
// UI thread so everything can be done directly there instead.
//
// Although methods must only be called on the IO thread, this is set exactly
// once and on the UI thread, so it's OK to get the pointer on the UI thread,
// e.g., to check for nullness or to pass the pointer to the IO thread.
std::unique_ptr<NavigationLoaderInterceptor, BrowserThread::DeleteOnIOThread>
interceptor_on_io_;
base::WeakPtrFactory<ServiceWorkerNavigationLoaderInterceptor> weak_factory_{
this};
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerNavigationLoaderInterceptor);
};
} // namespace content
#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_NAVIGATION_LOADER_INTERCEPTOR_H_
......@@ -13,7 +13,9 @@
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_controllee_request_handler.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_navigation_loader_interceptor.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/public/common/origin_util.h"
#include "content/public/common/url_constants.h"
......@@ -37,11 +39,31 @@ bool SchemeMaySupportRedirectingToHTTPS(const GURL& url) {
// static
std::unique_ptr<NavigationLoaderInterceptor>
ServiceWorkerRequestHandler::CreateForNavigation(
ServiceWorkerRequestHandler::CreateForNavigationUI(
const GURL& url,
ServiceWorkerNavigationHandle* navigation_handle,
const NavigationRequestInfo& request_info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Create the handler even for insecure HTTP since it's used in the
// case of redirect to HTTPS.
if (!url.SchemeIsHTTPOrHTTPS() && !OriginCanAccessServiceWorkers(url) &&
!SchemeMaySupportRedirectingToHTTPS(url)) {
return nullptr;
}
return std::make_unique<ServiceWorkerNavigationLoaderInterceptor>(
request_info, navigation_handle);
}
// static
std::unique_ptr<NavigationLoaderInterceptor>
ServiceWorkerRequestHandler::CreateForNavigationIO(
const GURL& url,
ServiceWorkerNavigationHandleCore* navigation_handle_core,
const NavigationRequestInfo& request_info,
base::WeakPtr<ServiceWorkerProviderHost>* out_provider_host) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(navigation_handle_core);
// Create the handler even for insecure HTTP since it's used in the
......
......@@ -20,6 +20,7 @@ struct ResourceRequest;
namespace content {
class ServiceWorkerNavigationHandle;
class ServiceWorkerNavigationHandleCore;
class ServiceWorkerProviderHost;
struct NavigationRequestInfo;
......@@ -30,15 +31,23 @@ struct NavigationRequestInfo;
// non-member functions?
class CONTENT_EXPORT ServiceWorkerRequestHandler {
public:
// Returns a loader interceptor for a navigation. May return nullptr
// if the navigation cannot use service workers.
static std::unique_ptr<NavigationLoaderInterceptor> CreateForNavigation(
// Returns a loader interceptor for a navigation. May return nullptr if the
// navigation cannot use service workers. Called on the UI thread.
static std::unique_ptr<NavigationLoaderInterceptor> CreateForNavigationUI(
const GURL& url,
ServiceWorkerNavigationHandle* navigation_handle,
const NavigationRequestInfo& request_info);
// Returns a loader interceptor for a navigation. May return nullptr if the
// navigation cannot use service workers. Called on the IO thread.
static std::unique_ptr<NavigationLoaderInterceptor> CreateForNavigationIO(
const GURL& url,
ServiceWorkerNavigationHandleCore* navigation_handle_core,
const NavigationRequestInfo& request_info,
base::WeakPtr<ServiceWorkerProviderHost>* out_provider_host);
// Same as above but for a dedicated worker or shared worker.
// Same as above but for a dedicated worker or shared worker. Called on the IO
// thread.
static std::unique_ptr<NavigationLoaderInterceptor> CreateForWorker(
const network::ResourceRequest& resource_request,
ServiceWorkerProviderHost* host);
......
......@@ -93,7 +93,7 @@ class ServiceWorkerRequestHandlerTest : public testing::Test {
base::UnguessableToken::Create() /* devtools_navigation_token */,
base::UnguessableToken::Create() /* devtools_frame_token */);
std::unique_ptr<NavigationLoaderInterceptor> interceptor =
ServiceWorkerRequestHandler::CreateForNavigation(
ServiceWorkerRequestHandler::CreateForNavigationIO(
GURL(url), navigation_handle_core.get(), request_info,
&service_worker_provider_host);
EXPECT_EQ(expected_handler_created, !!interceptor.get());
......
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