diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/content/browser/service_worker | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/content/browser/service_worker')
90 files changed, 3857 insertions, 2039 deletions
diff --git a/chromium/content/browser/service_worker/README.md b/chromium/content/browser/service_worker/README.md index a1dacf3b02a..5f35ce8c5fe 100644 --- a/chromium/content/browser/service_worker/README.md +++ b/chromium/content/browser/service_worker/README.md @@ -169,9 +169,8 @@ to request the renderer to start and stop the service worker thread. > use the same "embedded worker" classes. But it turned out only service workers > use it. -A running service worker has a corresponding host in the browser process -called `ServiceWorkerProviderHost` ([to be renamed -`ServiceWorkerHost`](https://crbug.com/931087)). +A running service worker has a corresponding host in the browser process called +`ServiceWorkerHost`. In addition, service worker clients (windows and web workers) are represented by a `ServiceWorkerContainerHost` in the browser process. This host holds diff --git a/chromium/content/browser/service_worker/embedded_worker_instance.cc b/chromium/content/browser/service_worker/embedded_worker_instance.cc index e91552b52fe..cbbcb54f1e4 100644 --- a/chromium/content/browser/service_worker/embedded_worker_instance.cc +++ b/chromium/content/browser/service_worker/embedded_worker_instance.cc @@ -14,7 +14,6 @@ #include "base/metrics/histogram_macros.h" #include "base/no_destructor.h" #include "base/optional.h" -#include "base/task/post_task.h" #include "base/trace_event/trace_event.h" #include "content/browser/bad_message.h" #include "content/browser/data_url_loader_factory.h" @@ -27,7 +26,7 @@ #include "content/browser/service_worker/service_worker_content_settings_proxy_impl.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_provider_host.h" +#include "content/browser/service_worker/service_worker_host.h" #include "content/browser/service_worker/service_worker_script_loader_factory.h" #include "content/browser/url_loader_factory_getter.h" #include "content/browser/url_loader_factory_params_helper.h" @@ -91,10 +90,10 @@ void NotifyUpdateCrossOriginEmbedderPolicyOnUI( std::move(cross_origin_embedder_policy), std::move(coep_reporter)); } -void NotifyWorkerDestroyedOnUI(int worker_process_id, int worker_route_id) { +void NotifyWorkerStoppedOnUI(int worker_process_id, int worker_route_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - ServiceWorkerDevToolsManager::GetInstance()->WorkerDestroyed( - worker_process_id, worker_route_id); + ServiceWorkerDevToolsManager::GetInstance()->WorkerStopped(worker_process_id, + worker_route_id); } void NotifyWorkerVersionInstalledOnUI(int worker_process_id, @@ -104,10 +103,14 @@ void NotifyWorkerVersionInstalledOnUI(int worker_process_id, worker_process_id, worker_route_id); } -void NotifyWorkerVersionDoomedOnUI(int worker_process_id, int worker_route_id) { +void NotifyWorkerVersionDoomedOnUI( + int worker_process_id, + int worker_route_id, + scoped_refptr<ServiceWorkerContextWrapper> context_wrapper, + int64_t version_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); ServiceWorkerDevToolsManager::GetInstance()->WorkerVersionDoomed( - worker_process_id, worker_route_id); + worker_process_id, worker_route_id, context_wrapper, version_id); } using CreateFactoryBundlesOnUICallback = base::OnceCallback<void( @@ -223,8 +226,7 @@ void SetupOnUIThread( cross_origin_embedder_policy, blink::mojom::EmbeddedWorkerStartParamsPtr params, mojo::PendingReceiver<blink::mojom::EmbeddedWorkerInstanceClient> receiver, - ServiceWorkerContextCore* context, - base::WeakPtr<ServiceWorkerContextCore> weak_context, + scoped_refptr<ServiceWorkerContextWrapper> context_wrapper, const base::Optional<base::Time>& io_post_time, SetupProcessCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -324,15 +326,15 @@ void SetupOnUIThread( } // Register to DevTools and update params accordingly. const int routing_id = rph->GetNextRoutingID(); - ServiceWorkerDevToolsManager::GetInstance()->WorkerCreated( - process_id, routing_id, context, weak_context, + ServiceWorkerDevToolsManager::GetInstance()->WorkerStarting( + process_id, routing_id, std::move(context_wrapper), params->service_worker_version_id, params->script_url, params->scope, params->is_installed, cross_origin_embedder_policy, std::move(coep_reporter_for_devtools), ¶ms->devtools_worker_token, ¶ms->wait_for_debugger); params->service_worker_route_id = routing_id; // Create DevToolsProxy here to ensure that the WorkerCreated() call is - // balanced by DevToolsProxy's destructor calling WorkerDestroyed(). + // balanced by DevToolsProxy's destructor calling WorkerStopped(). devtools_proxy = std::make_unique<EmbeddedWorkerInstance::DevToolsProxy>( process_id, routing_id); @@ -441,22 +443,24 @@ void BindCacheStorageOnUIThread( } // namespace -// Created on UI thread and moved to core thread. Proxies notifications to -// DevToolsManager that lives on UI thread. Owned by EmbeddedWorkerInstance. +// Created on the UI thread when the worker version is allcated a render process +// and then moved to the core thread. It is destroyed when the worker stops. +// Proxies notifications to DevToolsManager that lives on UI thread. +// Owned by EmbeddedWorkerInstance. class EmbeddedWorkerInstance::DevToolsProxy { public: DevToolsProxy(int process_id, int agent_route_id) : process_id_(process_id), agent_route_id_(agent_route_id), - ui_task_runner_(base::CreateSequencedTaskRunner({BrowserThread::UI})) {} + ui_task_runner_(GetUIThreadTaskRunner({})) {} ~DevToolsProxy() { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) { - NotifyWorkerDestroyedOnUI(process_id_, agent_route_id_); + NotifyWorkerStoppedOnUI(process_id_, agent_route_id_); } else { ui_task_runner_->PostTask( - FROM_HERE, base::BindOnce(NotifyWorkerDestroyedOnUI, process_id_, + FROM_HERE, base::BindOnce(NotifyWorkerStoppedOnUI, process_id_, agent_route_id_)); } } @@ -489,17 +493,6 @@ class EmbeddedWorkerInstance::DevToolsProxy { } } - void NotifyWorkerVersionDoomed() { - DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) { - NotifyWorkerVersionDoomedOnUI(process_id_, agent_route_id_); - } else { - ui_task_runner_->PostTask( - FROM_HERE, base::BindOnce(NotifyWorkerVersionDoomedOnUI, process_id_, - agent_route_id_)); - } - } - bool ShouldNotifyWorkerStopIgnored() const { return !worker_stop_ignored_notified_; } @@ -698,8 +691,8 @@ class EmbeddedWorkerInstance::StartTask { SetupOnUIThread( instance_->embedded_worker_id(), process_manager, can_use_existing_process, cross_origin_embedder_policy, - std::move(params), std::move(receiver_), context.get(), context, - base::nullopt, + std::move(params), std::move(receiver_), + base::WrapRefCounted(context->wrapper()), base::nullopt, base::BindOnce(&StartTask::OnSetupCompleted, weak_factory_.GetWeakPtr(), process_manager)); } else { @@ -709,7 +702,7 @@ class EmbeddedWorkerInstance::StartTask { &SetupOnUIThread, instance_->embedded_worker_id(), process_manager, can_use_existing_process, cross_origin_embedder_policy, std::move(params), - std::move(receiver_), context.get(), context, + std::move(receiver_), base::WrapRefCounted(context->wrapper()), base::make_optional<base::Time>(base::Time::Now()), base::BindOnce(&StartTask::OnSetupCompleted, weak_factory_.GetWeakPtr(), process_manager))); @@ -780,10 +773,6 @@ class EmbeddedWorkerInstance::StartTask { instance_->embedded_worker_id()), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "StartSituation", ServiceWorkerMetrics::StartSituationToString(start_situation)); - if (is_installed_) { - ServiceWorkerMetrics::RecordProcessCreated( - start_situation == ServiceWorkerMetrics::StartSituation::NEW_PROCESS); - } if (started_during_browser_startup_) start_situation = ServiceWorkerMetrics::StartSituation::DURING_STARTUP; @@ -858,7 +847,6 @@ class EmbeddedWorkerInstance::StartTask { EmbeddedWorkerInstance::~EmbeddedWorkerInstance() { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - devtools_proxy_.reset(); ReleaseProcess(); } @@ -954,7 +942,7 @@ EmbeddedWorkerInstance::EmbeddedWorkerInstance( devtools_attached_(false), network_accessed_for_script_(false), foreground_notified_(false), - ui_task_runner_(base::CreateSequencedTaskRunner({BrowserThread::UI})) { + ui_task_runner_(GetUIThreadTaskRunner({})) { DCHECK(owner_version_); DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK(context_); @@ -1000,8 +988,7 @@ void EmbeddedWorkerInstance::SendStartWorker( content_settings_ = base::SequenceBound<ServiceWorkerContentSettingsProxyImpl>( - base::CreateSequencedTaskRunner({BrowserThread::UI}), - params->script_url, + GetUIThreadTaskRunner({}), params->script_url, scoped_refptr<ServiceWorkerContextWrapper>(context_->wrapper()), params->content_settings_proxy.InitWithNewPipeAndPassReceiver()); @@ -1009,7 +996,7 @@ void EmbeddedWorkerInstance::SendStartWorker( inflight_start_task_->set_start_worker_sent_time(base::TimeTicks::Now()); // The host must be alive as long as |params->provider_info| is alive. - owner_version_->provider_host()->CompleteStartWorkerPreparation( + owner_version_->worker_host()->CompleteStartWorkerPreparation( process_id(), params->provider_info->browser_interface_broker .InitWithNewPipeAndPassReceiver()); @@ -1072,8 +1059,18 @@ void EmbeddedWorkerInstance::OnWorkerVersionInstalled() { } void EmbeddedWorkerInstance::OnWorkerVersionDoomed() { - if (devtools_proxy_) - devtools_proxy_->NotifyWorkerVersionDoomed(); + if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) { + NotifyWorkerVersionDoomedOnUI(process_id(), + worker_devtools_agent_route_id(), + base::WrapRefCounted(context_->wrapper()), + owner_version_->version_id()); + } else { + ui_task_runner_->PostTask( + FROM_HERE, base::BindOnce(NotifyWorkerVersionDoomedOnUI, process_id(), + worker_devtools_agent_route_id(), + base::WrapRefCounted(context_->wrapper()), + owner_version_->version_id())); + } } void EmbeddedWorkerInstance::OnScriptEvaluationStart() { @@ -1477,7 +1474,7 @@ EmbeddedWorkerInstance::MakeScriptLoaderFactoryRemote( std::move(script_bundle)); script_loader_factory_ = mojo::MakeSelfOwnedReceiver( std::make_unique<ServiceWorkerScriptLoaderFactory>( - context_, owner_version_->provider_host()->GetWeakPtr(), + context_, owner_version_->worker_host()->GetWeakPtr(), std::move(script_bundle_factory)), script_loader_factory_remote.InitWithNewPipeAndPassReceiver()); diff --git a/chromium/content/browser/service_worker/embedded_worker_instance.h b/chromium/content/browser/service_worker/embedded_worker_instance.h index 2849085fbb7..93f017347d1 100644 --- a/chromium/content/browser/service_worker/embedded_worker_instance.h +++ b/chromium/content/browser/service_worker/embedded_worker_instance.h @@ -11,8 +11,8 @@ #include <string> #include "base/callback_forward.h" +#include "base/check_op.h" #include "base/gtest_prod_util.h" -#include "base/logging.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" diff --git a/chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc b/chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc index bb469e8adf2..7588ade7972 100644 --- a/chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc +++ b/chromium/content/browser/service_worker/embedded_worker_instance_unittest.cc @@ -173,7 +173,7 @@ class EmbeddedWorkerInstanceTest : public testing::Test, scoped_refptr<ServiceWorkerVersion> version) { auto provider_info = blink::mojom::ServiceWorkerProviderInfoForStartWorker::New(); - version->provider_host_ = std::make_unique<ServiceWorkerProviderHost>( + version->worker_host_ = std::make_unique<ServiceWorkerHost>( provider_info->host_remote.InitWithNewEndpointAndPassReceiver(), version.get(), context()->AsWeakPtr()); return provider_info; diff --git a/chromium/content/browser/service_worker/embedded_worker_test_helper.cc b/chromium/content/browser/service_worker/embedded_worker_test_helper.cc index 534704c9d65..900309a3b27 100644 --- a/chromium/content/browser/service_worker/embedded_worker_test_helper.cc +++ b/chromium/content/browser/service_worker/embedded_worker_test_helper.cc @@ -16,8 +16,6 @@ #include "content/public/test/mock_render_process_host.h" #include "content/public/test/test_browser_context.h" #include "content/test/fake_network_url_loader_factory.h" -#include "mojo/public/cpp/bindings/associated_binding_set.h" -#include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "third_party/blink/public/common/service_worker/service_worker_utils.h" #include "third_party/blink/public/common/user_agent/user_agent_metadata.h" diff --git a/chromium/content/browser/service_worker/fake_service_worker.cc b/chromium/content/browser/service_worker/fake_service_worker.cc index 541f2a5ea16..6b60f6316d0 100644 --- a/chromium/content/browser/service_worker/fake_service_worker.cc +++ b/chromium/content/browser/service_worker/fake_service_worker.cc @@ -36,6 +36,10 @@ void FakeServiceWorker::RunUntilInitializeGlobalScope() { loop.Run(); } +void FakeServiceWorker::FlushForTesting() { + receiver_.FlushForTesting(); +} + void FakeServiceWorker::InitializeGlobalScope( mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerHost> service_worker_host, @@ -128,8 +132,11 @@ void FakeServiceWorker::DispatchFetchEventForMainResource( response->response_type = network::mojom::FetchResponseType::kDefault; mojo::Remote<blink::mojom::ServiceWorkerFetchResponseCallback> response_callback(std::move(pending_response_callback)); - response_callback->OnResponse( - std::move(response), blink::mojom::ServiceWorkerFetchEventTiming::New()); + auto timing = blink::mojom::ServiceWorkerFetchEventTiming::New(); + auto now = base::TimeTicks::Now(); + timing->respond_with_settled_time = now; + timing->dispatch_event_time = now; + response_callback->OnResponse(std::move(response), std::move(timing)); std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED); } diff --git a/chromium/content/browser/service_worker/fake_service_worker.h b/chromium/content/browser/service_worker/fake_service_worker.h index 7451f68f36f..7fbdfecddd8 100644 --- a/chromium/content/browser/service_worker/fake_service_worker.h +++ b/chromium/content/browser/service_worker/fake_service_worker.h @@ -50,6 +50,9 @@ class FakeServiceWorker : public blink::mojom::ServiceWorker { return fetch_handler_existence_; } + // Flush messages in the message pipe. + void FlushForTesting(); + protected: // blink::mojom::ServiceWorker overrides: void InitializeGlobalScope( diff --git a/chromium/content/browser/service_worker/service_worker_browsertest.cc b/chromium/content/browser/service_worker/service_worker_browsertest.cc index 0d6f21c2ed9..ec633594fcd 100644 --- a/chromium/content/browser/service_worker/service_worker_browsertest.cc +++ b/chromium/content/browser/service_worker/service_worker_browsertest.cc @@ -13,6 +13,7 @@ #include "base/bind_helpers.h" #include "base/callback.h" #include "base/command_line.h" +#include "base/guid.h" #include "base/json/json_reader.h" #include "base/memory/ref_counted.h" #include "base/metrics/statistics_recorder.h" @@ -40,6 +41,7 @@ #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_core_observer.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/browser/service_worker/service_worker_fetch_dispatcher.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_test_utils.h" #include "content/browser/service_worker/service_worker_version.h" @@ -937,6 +939,157 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, GetRunningServiceWorkerInfos) { running_info.render_process_id); } +// Make sure that a fetch event is dispatched to a stopped worker in the task +// which calls ServiceWorkerFetchDispatcher::Run(). +IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, + DispatchFetchEventToStoppedWorkerSynchronously) { + // Setup the server so that the test doesn't crash when tearing down. + StartServerAndNavigateToSetup(); + // This test is meaningful only when ServiceWorkerOnUI is enabled. + if (!ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) + return; + + WorkerRunningStatusObserver observer(public_context()); + EXPECT_TRUE(NavigateToURL(shell(), + embedded_test_server()->GetURL( + "/service_worker/create_service_worker.html"))); + EXPECT_EQ("DONE", EvalJs(shell(), "register('fetch_event.js');")); + observer.WaitUntilRunning(); + + ASSERT_TRUE( + BrowserThread::CurrentlyOn(ServiceWorkerContext::GetCoreThreadId())); + scoped_refptr<ServiceWorkerVersion> version = + wrapper()->GetLiveVersion(observer.version_id()); + EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version->running_status()); + + { + base::RunLoop loop; + version->StopWorker(loop.QuitClosure()); + loop.Run(); + EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version->running_status()); + } + + bool is_prepare_callback_called = false; + base::RunLoop fetch_loop; + blink::ServiceWorkerStatusCode fetch_status; + ServiceWorkerFetchDispatcher::FetchEventResult fetch_result; + blink::mojom::FetchAPIResponsePtr fetch_response; + + auto request = blink::mojom::FetchAPIRequest::New(); + request->url = embedded_test_server()->GetURL("/service_worker/in-scope"); + request->method = "GET"; + request->is_main_resource_load = true; + auto dispatcher = std::make_unique<ServiceWorkerFetchDispatcher>( + std::move(request), blink::mojom::ResourceType::kMainFrame, + /*client_id=*/base::GenerateGUID(), version, + base::BindLambdaForTesting([&]() { is_prepare_callback_called = true; }), + base::BindLambdaForTesting( + [&](blink::ServiceWorkerStatusCode status, + ServiceWorkerFetchDispatcher::FetchEventResult result, + blink::mojom::FetchAPIResponsePtr response, + blink::mojom::ServiceWorkerStreamHandlePtr, + blink::mojom::ServiceWorkerFetchEventTimingPtr, + scoped_refptr<ServiceWorkerVersion>) { + fetch_status = status; + fetch_result = result; + fetch_response = std::move(response); + fetch_loop.Quit(); + }), + /*is_offline_capability_check=*/false); + + // DispatchFetchEvent is called synchronously with dispatcher->Run() even if + // the worker is stopped. + dispatcher->Run(); + EXPECT_TRUE(is_prepare_callback_called); + EXPECT_FALSE(fetch_response); + + // Check if the fetch event is handled by fetch_event.js correctly. + fetch_loop.Run(); + ASSERT_TRUE(fetch_response); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, fetch_status); + EXPECT_EQ(ServiceWorkerFetchDispatcher::FetchEventResult::kGotResponse, + fetch_result); + EXPECT_EQ(301, fetch_response->status_code); +} + +// Check if a fetch event can be failed without crashing if starting a service +// worker fails. This is a regression test for https://crbug.com/1106977. +IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, + DispatchFetchEventToBrokenWorker) { + // Setup the server so that the test doesn't crash when tearing down. + StartServerAndNavigateToSetup(); + // This test is meaningful only when ServiceWorkerOnUI is enabled. + if (!ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) + return; + + WorkerRunningStatusObserver observer(public_context()); + EXPECT_TRUE(NavigateToURL(shell(), + embedded_test_server()->GetURL( + "/service_worker/create_service_worker.html"))); + EXPECT_EQ("DONE", EvalJs(shell(), "register('fetch_event.js');")); + observer.WaitUntilRunning(); + + ASSERT_TRUE( + BrowserThread::CurrentlyOn(ServiceWorkerContext::GetCoreThreadId())); + scoped_refptr<ServiceWorkerVersion> version = + wrapper()->GetLiveVersion(observer.version_id()); + EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version->running_status()); + + { + base::RunLoop loop; + version->StopWorker(loop.QuitClosure()); + loop.Run(); + EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version->running_status()); + } + + // Set a non-existent resource to the version. + std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> resources; + resources.push_back(storage::mojom::ServiceWorkerResourceRecord::New( + 123456789, version->script_url(), 100)); + version->script_cache_map()->resource_map_.clear(); + version->script_cache_map()->SetResources(resources); + + bool is_prepare_callback_called = false; + base::RunLoop fetch_loop; + blink::ServiceWorkerStatusCode fetch_status; + ServiceWorkerFetchDispatcher::FetchEventResult fetch_result; + + auto request = blink::mojom::FetchAPIRequest::New(); + request->url = embedded_test_server()->GetURL("/service_worker/in-scope"); + request->method = "GET"; + request->is_main_resource_load = true; + auto dispatcher = std::make_unique<ServiceWorkerFetchDispatcher>( + std::move(request), blink::mojom::ResourceType::kMainFrame, + /*client_id=*/base::GenerateGUID(), version, + base::BindLambdaForTesting([&]() { is_prepare_callback_called = true; }), + base::BindLambdaForTesting( + [&](blink::ServiceWorkerStatusCode status, + ServiceWorkerFetchDispatcher::FetchEventResult result, + blink::mojom::FetchAPIResponsePtr response, + blink::mojom::ServiceWorkerStreamHandlePtr, + blink::mojom::ServiceWorkerFetchEventTimingPtr, + scoped_refptr<ServiceWorkerVersion>) { + fetch_status = status; + fetch_result = result; + fetch_loop.Quit(); + }), + /*is_offline_capability_check=*/false); + + // DispatchFetchEvent is called synchronously with dispatcher->Run() even if + // the worker is stopped. + dispatcher->Run(); + EXPECT_TRUE(is_prepare_callback_called); + + // Check if the fetch event fails due to error of reading the resource. + fetch_loop.Run(); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kErrorDiskCache, fetch_status); + EXPECT_EQ(ServiceWorkerFetchDispatcher::FetchEventResult::kShouldFallback, + fetch_result); + + // Make sure that no crash happens in the remaining tasks. + base::RunLoop().RunUntilIdle(); +} + class ServiceWorkerEagerCacheStorageSetupTest : public ServiceWorkerBrowserTest { public: @@ -2208,8 +2361,6 @@ class CodeCacheHostInterceptor class CacheStorageContextForBadOrigin : public CacheStorageContextImpl { public: - CacheStorageContextForBadOrigin() : CacheStorageContextImpl(nullptr) {} - scoped_refptr<CacheStorageManager> CacheManager() override { // The CodeCacheHostImpl should not try to access the CacheManager() // if the origin is bad. diff --git a/chromium/content/browser/service_worker/service_worker_cache_writer.cc b/chromium/content/browser/service_worker/service_worker_cache_writer.cc index cb817330492..f7f15fa2400 100644 --- a/chromium/content/browser/service_worker/service_worker_cache_writer.cc +++ b/chromium/content/browser/service_worker/service_worker_cache_writer.cc @@ -11,6 +11,8 @@ #include "base/memory/ptr_util.h" #include "content/browser/service_worker/service_worker_disk_cache.h" #include "content/common/service_worker/service_worker_utils.h" +#include "mojo/public/cpp/system/simple_watcher.h" +#include "services/network/public/cpp/net_adapters.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" namespace { @@ -74,6 +76,12 @@ class ServiceWorkerCacheWriter::ReadResponseHeadCallbackAdapter owner_->AsyncDoLoop(result); } + void DidReadResponseHead(int result, + network::mojom::URLResponseHeadPtr response_head, + base::Optional<mojo_base::BigBuffer>) { + DidReadResponseInfo(result, std::move(response_head), nullptr); + } + void SetAsync() { async_ = true; } int result() { return result_; } @@ -162,6 +170,19 @@ ServiceWorkerCacheWriter::ServiceWorkerCacheWriter( io_pending_(false), comparing_(false), pause_when_not_identical_(pause_when_not_identical), + legacy_compare_reader_(std::move(compare_reader)), + legacy_copy_reader_(std::move(copy_reader)), + writer_(std::move(writer)) {} + +ServiceWorkerCacheWriter::ServiceWorkerCacheWriter( + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> compare_reader, + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> copy_reader, + std::unique_ptr<ServiceWorkerResponseWriter> writer, + bool pause_when_not_identical) + : state_(STATE_START), + io_pending_(false), + comparing_(false), + pause_when_not_identical_(pause_when_not_identical), compare_reader_(std::move(compare_reader)), copy_reader_(std::move(copy_reader)), writer_(std::move(writer)) {} @@ -180,6 +201,18 @@ ServiceWorkerCacheWriter::CreateForCopy( } std::unique_ptr<ServiceWorkerCacheWriter> +ServiceWorkerCacheWriter::CreateForCopy( + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> copy_reader, + std::unique_ptr<ServiceWorkerResponseWriter> writer) { + DCHECK(copy_reader); + DCHECK(writer); + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> null_remote; + return base::WrapUnique(new ServiceWorkerCacheWriter( + std::move(null_remote) /* compare_reader */, std::move(copy_reader), + std::move(writer), false /* pause_when_not_identical*/)); +} + +std::unique_ptr<ServiceWorkerCacheWriter> ServiceWorkerCacheWriter::CreateForWriteBack( std::unique_ptr<ServiceWorkerResponseWriter> writer) { DCHECK(writer); @@ -204,6 +237,22 @@ ServiceWorkerCacheWriter::CreateForComparison( pause_when_not_identical)); } +std::unique_ptr<ServiceWorkerCacheWriter> +ServiceWorkerCacheWriter::CreateForComparison( + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> compare_reader, + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> copy_reader, + std::unique_ptr<ServiceWorkerResponseWriter> writer, + bool pause_when_not_identical) { + // |compare_reader| reads data for the comparison. |copy_reader| reads + // data for copy. + DCHECK(compare_reader); + DCHECK(copy_reader); + DCHECK(writer); + return base::WrapUnique(new ServiceWorkerCacheWriter( + std::move(compare_reader), std::move(copy_reader), std::move(writer), + pause_when_not_identical)); +} + net::Error ServiceWorkerCacheWriter::MaybeWriteHeaders( network::mojom::URLResponseHeadPtr response_head, OnWriteCompleteCallback callback) { @@ -332,7 +381,8 @@ net::Error ServiceWorkerCacheWriter::StartCopy( } bool ServiceWorkerCacheWriter::IsCopying() const { - return !compare_reader_ && copy_reader_; + return !(compare_reader_ || legacy_compare_reader_) && + (copy_reader_ || legacy_copy_reader_); } int64_t ServiceWorkerCacheWriter::WriterResourceId() const { @@ -342,7 +392,7 @@ int64_t ServiceWorkerCacheWriter::WriterResourceId() const { int ServiceWorkerCacheWriter::DoStart(int result) { bytes_written_ = 0; - if (compare_reader_) { + if (compare_reader_ || legacy_compare_reader_) { state_ = STATE_READ_HEADERS_FOR_COMPARE; comparing_ = true; } else if (IsCopying()) { @@ -361,7 +411,11 @@ int ServiceWorkerCacheWriter::DoReadHeadersForCompare(int result) { DCHECK(response_head_to_write_); state_ = STATE_READ_HEADERS_FOR_COMPARE_DONE; - return ReadResponseHead(compare_reader_); + if (compare_reader_) { + return ReadResponseHead(compare_reader_.get()); + } else { + return ReadResponseHead(legacy_compare_reader_); + } } int ServiceWorkerCacheWriter::DoReadHeadersForCompareDone(int result) { @@ -385,14 +439,19 @@ int ServiceWorkerCacheWriter::DoReadDataForCompare(int result) { state_ = STATE_READ_DATA_FOR_COMPARE_DONE; compare_offset_ = 0; // If this was an EOF, don't issue a read. - if (len_to_write_ > 0) - result = ReadDataHelper(compare_reader_, data_to_read_.get(), len_to_read_); + if (len_to_write_ > 0) { + if (compare_reader_) { + result = ReadDataHelper(compare_reader_.get(), compare_data_pipe_reader_, + data_to_read_.get(), len_to_read_); + } else { + result = ReadDataHelper(legacy_compare_reader_, data_to_read_.get(), + len_to_read_); + } + } return result; } int ServiceWorkerCacheWriter::DoReadDataForCompareDone(int result) { - DCHECK(data_to_read_); - DCHECK(data_to_write_); DCHECK_EQ(len_to_read_, len_to_write_); if (result < 0) { @@ -411,6 +470,9 @@ int ServiceWorkerCacheWriter::DoReadDataForCompareDone(int result) { return pause_when_not_identical_ ? net::ERR_IO_PENDING : net::OK; } + DCHECK(data_to_read_); + DCHECK(data_to_write_); + // Compare the data from the ServiceWorker script cache to the data from the // network. if (memcmp(data_to_read_->data(), data_to_write_->data() + compare_offset_, @@ -435,8 +497,14 @@ int ServiceWorkerCacheWriter::DoReadDataForCompareDone(int result) { // that this reuses the same IOBuffer. if (compare_offset_ < static_cast<size_t>(len_to_read_)) { state_ = STATE_READ_DATA_FOR_COMPARE_DONE; - return ReadDataHelper(compare_reader_, data_to_read_.get(), - len_to_read_ - compare_offset_); + if (compare_reader_) { + return ReadDataHelper(compare_reader_.get(), compare_data_pipe_reader_, + data_to_read_.get(), + len_to_read_ - compare_offset_); + } else { + return ReadDataHelper(legacy_compare_reader_, data_to_read_.get(), + len_to_read_ - compare_offset_); + } } // Cached entry is longer than the network entry but the prefix matches. Copy @@ -455,11 +523,15 @@ int ServiceWorkerCacheWriter::DoReadDataForCompareDone(int result) { int ServiceWorkerCacheWriter::DoReadHeadersForCopy(int result) { DCHECK_GE(result, 0); - DCHECK(copy_reader_); + DCHECK(copy_reader_ || legacy_copy_reader_); bytes_copied_ = 0; data_to_copy_ = base::MakeRefCounted<net::IOBuffer>(kCopyBufferSize); state_ = STATE_READ_HEADERS_FOR_COPY_DONE; - return ReadResponseHead(copy_reader_); + if (copy_reader_) { + return ReadResponseHead(copy_reader_.get()); + } else { + return ReadResponseHead(legacy_copy_reader_); + } } int ServiceWorkerCacheWriter::DoReadHeadersForCopyDone(int result) { @@ -518,7 +590,12 @@ int ServiceWorkerCacheWriter::DoReadDataForCopy(int result) { return net::OK; } state_ = STATE_READ_DATA_FOR_COPY_DONE; - return ReadDataHelper(copy_reader_, data_to_copy_.get(), to_read); + if (copy_reader_) { + return ReadDataHelper(copy_reader_.get(), copy_data_pipe_reader_, + data_to_copy_.get(), to_read); + } else { + return ReadDataHelper(legacy_copy_reader_, data_to_copy_.get(), to_read); + } } int ServiceWorkerCacheWriter::DoReadDataForCopyDone(int result) { @@ -592,6 +669,16 @@ int ServiceWorkerCacheWriter::DoDone(int result) { // asynchronous completions. int ServiceWorkerCacheWriter::ReadResponseHead( + storage::mojom::ServiceWorkerResourceReader* reader) { + auto adapter = base::MakeRefCounted<ReadResponseHeadCallbackAdapter>( + weak_factory_.GetWeakPtr()); + reader->ReadResponseHead(base::BindOnce( + &ReadResponseHeadCallbackAdapter::DidReadResponseHead, adapter)); + adapter->SetAsync(); + return adapter->result(); +} + +int ServiceWorkerCacheWriter::ReadResponseHead( const std::unique_ptr<ServiceWorkerResponseReader>& reader) { auto adapter = base::MakeRefCounted<ReadResponseHeadCallbackAdapter>( weak_factory_.GetWeakPtr()); @@ -617,6 +704,101 @@ int ServiceWorkerCacheWriter::ReadDataHelper( return adaptor->result(); } +class ServiceWorkerCacheWriter::DataPipeReader { + public: + DataPipeReader(storage::mojom::ServiceWorkerResourceReader* reader, + ServiceWorkerCacheWriter* owner, + scoped_refptr<base::SequencedTaskRunner> runner) + : reader_(reader), + owner_(owner), + watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL, runner), + task_runner_(runner) {} + + // Reads the body up to |num_bytes| bytes. |callback| is always called + // asynchronously. + using ReadCallback = base::OnceCallback<void(int /* result */)>; + void Read(net::IOBuffer* buffer, int num_bytes, ReadCallback callback) { + DCHECK(buffer); + buffer_ = buffer; + num_bytes_to_read_ = num_bytes; + callback_ = std::move(callback); + + if (!data_.is_valid()) { + // This is the initial call of Read(). Call ReadData() to get a data pipe + // to read the body. + reader_->ReadData( + -1, + base::BindOnce(&ServiceWorkerCacheWriter::DataPipeReader::OnReadData, + weak_factory_.GetWeakPtr())); + return; + } + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&ServiceWorkerCacheWriter::DataPipeReader::ReadInternal, + weak_factory_.GetWeakPtr(), MOJO_RESULT_OK)); + } + + private: + void ReadInternal(MojoResult) { + MojoResult result = data_->ReadData(buffer_->data(), &num_bytes_to_read_, + MOJO_READ_DATA_FLAG_NONE); + if (result == MOJO_RESULT_SHOULD_WAIT) { + watcher_.ArmOrNotify(); + return; + } + if (result != MOJO_RESULT_OK) { + // Disconnected means it's the end of the body or an error occurs during + // reading the body. + // TODO(https://crbug.com/1055677): notify of errors. + num_bytes_to_read_ = 0; + } + owner_->AsyncDoLoop(num_bytes_to_read_); + } + + void OnReadData(mojo::ScopedDataPipeConsumerHandle data) { + data_ = std::move(data); + watcher_.Watch(data_.get(), + MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + base::BindRepeating( + &ServiceWorkerCacheWriter::DataPipeReader::ReadInternal, + weak_factory_.GetWeakPtr())); + ReadInternal(MOJO_RESULT_OK); + } + + // Parameters set on Read(). + net::IOBuffer* buffer_ = nullptr; + uint32_t num_bytes_to_read_ = 0; + ReadCallback callback_; + + // |reader_| is safe to be kept as a rawptr because |owner_| owns |this| and + // |reader_|, and |owner_| keeps |reader_| until it's destroyed. + storage::mojom::ServiceWorkerResourceReader* const reader_; + ServiceWorkerCacheWriter* const owner_; + + // Mojo data pipe and the watcher is set up when Read() is called for the + // first time. + mojo::ScopedDataPipeConsumerHandle data_; + mojo::SimpleWatcher watcher_; + scoped_refptr<base::SequencedTaskRunner> task_runner_; + + base::WeakPtrFactory<DataPipeReader> weak_factory_{this}; +}; + +int ServiceWorkerCacheWriter::ReadDataHelper( + storage::mojom::ServiceWorkerResourceReader* reader, + std::unique_ptr<DataPipeReader>& data_pipe_reader, + net::IOBuffer* buf, + int buf_len) { + if (!data_pipe_reader) { + data_pipe_reader = std::make_unique<DataPipeReader>( + reader, this, base::SequencedTaskRunnerHandle::Get()); + } + data_pipe_reader->Read(buf, buf_len, + base::BindOnce(&ServiceWorkerCacheWriter::AsyncDoLoop, + weak_factory_.GetWeakPtr())); + return net::ERR_IO_PENDING; +} + int ServiceWorkerCacheWriter::WriteResponseHeadToResponseWriter( const network::mojom::URLResponseHead& response_head, int response_data_size) { diff --git a/chromium/content/browser/service_worker/service_worker_cache_writer.h b/chromium/content/browser/service_worker/service_worker_cache_writer.h index 8939d623ba6..111f902c41b 100644 --- a/chromium/content/browser/service_worker/service_worker_cache_writer.h +++ b/chromium/content/browser/service_worker/service_worker_cache_writer.h @@ -13,7 +13,9 @@ #include "base/callback.h" #include "base/memory/weak_ptr.h" +#include "components/services/storage/public/mojom/service_worker_storage_control.mojom.h" #include "content/common/content_export.h" +#include "mojo/public/cpp/bindings/remote.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "services/network/public/mojom/url_response_head.mojom.h" @@ -35,6 +37,12 @@ class ServiceWorkerResponseWriter; // // This class's behavior is modelled as a state machine; see the DoLoop function // for comments about this. +// +// Note that currently we have two types of interfaces to create an instance of +// ServiceWorkerCacheWriter: storage service and non storage service. +// After storage service is shipped, we use Mojo connection to read and write +// the resource. +// See https://crbug.com/1055677 for more info. class CONTENT_EXPORT ServiceWorkerCacheWriter { public: using OnWriteCompleteCallback = base::OnceCallback<void(net::Error)>; @@ -63,9 +71,14 @@ class CONTENT_EXPORT ServiceWorkerCacheWriter { // Create a cache writer instance that copies a script already in storage. The // script is read by |copy_reader|. + // Non-storage service: static std::unique_ptr<ServiceWorkerCacheWriter> CreateForCopy( std::unique_ptr<ServiceWorkerResponseReader> copy_reader, std::unique_ptr<ServiceWorkerResponseWriter> writer); + // Storage service: + static std::unique_ptr<ServiceWorkerCacheWriter> CreateForCopy( + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> copy_reader, + std::unique_ptr<ServiceWorkerResponseWriter> writer); // Create a cache writer instance that unconditionally write back data // supplied to |MaybeWriteHeaders| and |MaybeWriteData| to storage. @@ -82,11 +95,18 @@ class CONTENT_EXPORT ServiceWorkerCacheWriter { // resumed later. If |pause_when_not_identical| is false, and the data is // different, it would be written to storage directly. |copy_reader| is used // for copying identical data blocks during writing. + // Non-storage service: static std::unique_ptr<ServiceWorkerCacheWriter> CreateForComparison( std::unique_ptr<ServiceWorkerResponseReader> compare_reader, std::unique_ptr<ServiceWorkerResponseReader> copy_reader, std::unique_ptr<ServiceWorkerResponseWriter> writer, bool pause_when_not_identical); + // Storage service: + static std::unique_ptr<ServiceWorkerCacheWriter> CreateForComparison( + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> compare_reader, + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> copy_reader, + std::unique_ptr<ServiceWorkerResponseWriter> writer, + bool pause_when_not_identical); ~ServiceWorkerCacheWriter(); @@ -140,6 +160,7 @@ class CONTENT_EXPORT ServiceWorkerCacheWriter { private: class ReadResponseHeadCallbackAdapter; + class DataPipeReader; friend class ServiceWorkerUpdateCheckTestUtils; @@ -200,11 +221,18 @@ class CONTENT_EXPORT ServiceWorkerCacheWriter { STATE_DONE, }; + // Non-storage service: ServiceWorkerCacheWriter( std::unique_ptr<ServiceWorkerResponseReader> compare_reader, std::unique_ptr<ServiceWorkerResponseReader> copy_reader, std::unique_ptr<ServiceWorkerResponseWriter> writer, bool pause_when_not_identical); + // Storage service: + ServiceWorkerCacheWriter( + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> compare_reader, + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> copy_reader, + std::unique_ptr<ServiceWorkerResponseWriter> writer, + bool pause_when_not_identical); // Drives this class's state machine. This function steps the state machine // until one of: @@ -244,11 +272,20 @@ class CONTENT_EXPORT ServiceWorkerCacheWriter { // a) Return ERR_IO_PENDING, and schedule a callback to run the state // machine's Run() later, or // b) Return some other value and do not schedule a callback. + // Non-storage service: int ReadResponseHead( const std::unique_ptr<ServiceWorkerResponseReader>& reader); int ReadDataHelper(const std::unique_ptr<ServiceWorkerResponseReader>& reader, net::IOBuffer* buf, int buf_len); + // Storage service: + // These are always case a) above. + int ReadResponseHead(storage::mojom::ServiceWorkerResourceReader* reader); + int ReadDataHelper(storage::mojom::ServiceWorkerResourceReader* reader, + std::unique_ptr<DataPipeReader>& data_pipe_reader, + net::IOBuffer* buf, + int buf_len); + // If no write observer is set through set_write_observer(), // WriteResponseHead() operates the same as // WriteResponseHeadToResponseWriter() and WriteData() operates the same as @@ -318,8 +355,15 @@ class CONTENT_EXPORT ServiceWorkerCacheWriter { WriteObserver* write_observer_ = nullptr; - std::unique_ptr<ServiceWorkerResponseReader> compare_reader_; - std::unique_ptr<ServiceWorkerResponseReader> copy_reader_; + // Non-storage service: + std::unique_ptr<ServiceWorkerResponseReader> legacy_compare_reader_; + std::unique_ptr<ServiceWorkerResponseReader> legacy_copy_reader_; + // Storage service: + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> compare_reader_; + std::unique_ptr<DataPipeReader> compare_data_pipe_reader_; + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> copy_reader_; + std::unique_ptr<DataPipeReader> copy_data_pipe_reader_; + std::unique_ptr<ServiceWorkerResponseWriter> writer_; base::WeakPtrFactory<ServiceWorkerCacheWriter> weak_factory_{this}; }; diff --git a/chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc b/chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc index b3e1810b360..1a8da42fd24 100644 --- a/chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_cache_writer_unittest.cc @@ -14,6 +14,7 @@ #include "base/containers/queue.h" #include "base/memory/ptr_util.h" #include "base/stl_util.h" +#include "base/test/task_environment.h" #include "content/browser/service_worker/service_worker_disk_cache.h" #include "content/browser/service_worker/service_worker_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -111,19 +112,24 @@ class ServiceWorkerCacheWriterTest : public ::testing::Test { } protected: + base::test::SingleThreadTaskEnvironment task_environment_; std::list<std::unique_ptr<MockServiceWorkerResponseReader>> readers_; std::list<std::unique_ptr<MockServiceWorkerResponseWriter>> writers_; std::unique_ptr<ServiceWorkerCacheWriter> cache_writer_; bool write_complete_ = false; net::Error last_error_; - std::unique_ptr<ServiceWorkerResponseReader> CreateReader() { + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> CreateReader() { + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> remote; if (readers_.empty()) - return base::WrapUnique<ServiceWorkerResponseReader>(nullptr); - std::unique_ptr<ServiceWorkerResponseReader> reader( - std::move(readers_.front())); + return remote; + auto* reader_rawptr = readers_.front().get(); + remote.Bind(reader_rawptr->BindNewPipeAndPassRemote( + // Keep the instance alive until the connection is destroyed. + base::BindOnce([](std::unique_ptr<MockServiceWorkerResponseReader>) {}, + std::move(readers_.front())))); readers_.pop_front(); - return reader; + return remote; } std::unique_ptr<ServiceWorkerResponseWriter> CreateWriter() { @@ -151,15 +157,18 @@ class ServiceWorkerCacheWriterTest : public ::testing::Test { response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>( std::string(data, base::size(data))); response_head->content_length = len; - return cache_writer_->MaybeWriteHeaders(std::move(response_head), - CreateWriteCallback()); + net::Error error = cache_writer_->MaybeWriteHeaders( + std::move(response_head), CreateWriteCallback()); + return error; } net::Error WriteData(const std::string& data) { scoped_refptr<net::IOBuffer> buf = base::MakeRefCounted<net::StringIOBuffer>(data); - return cache_writer_->MaybeWriteData(buf.get(), data.size(), - CreateWriteCallback()); + net::Error error = cache_writer_->MaybeWriteData(buf.get(), data.size(), + CreateWriteCallback()); + base::RunLoop().RunUntilIdle(); + return error; } private: @@ -322,134 +331,6 @@ TEST_F(ServiceWorkerCacheWriterTest, PassthroughDataFailAsync) { // For the Compare* tests below, the ServiceWorkerCacheWriter under test has a // reader for an existing cached response, so it will compare the response being // written to it against the existing cached response. - -TEST_F(ServiceWorkerCacheWriterTest, CompareHeadersSync) { - size_t response_size = 3; - MockServiceWorkerResponseWriter* writer = ExpectWriter(); - MockServiceWorkerResponseReader* reader = ExpectReader(); - - // Create a copy reader as it's needed to create cache writer for comparison - // though not used in this test. - ExpectReader(); - - reader->ExpectReadInfoOk(response_size, false); - Initialize(CacheWriterUsage::kForComparison, - false /* pause_when_not_identical */); - - net::Error error = WriteHeaders(response_size); - EXPECT_EQ(net::OK, error); - EXPECT_TRUE(writer->AllExpectedWritesDone()); - EXPECT_TRUE(reader->AllExpectedReadsDone()); -} - -TEST_F(ServiceWorkerCacheWriterTest, CompareDataOkSync) { - const std::string data1 = "abcdef"; - size_t response_size = data1.size(); - - MockServiceWorkerResponseWriter* writer = ExpectWriter(); - MockServiceWorkerResponseReader* reader = ExpectReader(); - - // Create a copy reader as it's needed to create cache writer for comparison - // though not used in this test. - ExpectReader(); - - reader->ExpectReadInfoOk(response_size, false); - reader->ExpectReadDataOk(data1, false); - Initialize(CacheWriterUsage::kForComparison, - false /* pause_when_not_identical */); - - net::Error error = WriteHeaders(response_size); - EXPECT_EQ(net::OK, error); - - error = WriteData(data1); - EXPECT_EQ(net::OK, error); - - EXPECT_TRUE(writer->AllExpectedWritesDone()); - EXPECT_TRUE(reader->AllExpectedReadsDone()); - EXPECT_EQ(0U, cache_writer_->bytes_written()); -} - -TEST_F(ServiceWorkerCacheWriterTest, CompareHeadersFailSync) { - size_t response_size = 3; - MockServiceWorkerResponseWriter* writer = ExpectWriter(); - MockServiceWorkerResponseReader* reader = ExpectReader(); - - // Create a copy reader as it's needed to create cache writer for comparison - // though not used in this test. - ExpectReader(); - - reader->ExpectReadInfo(response_size, false, net::ERR_FAILED); - Initialize(CacheWriterUsage::kForComparison, - false /* pause_when_not_identical */); - - EXPECT_EQ(net::ERR_FAILED, WriteHeaders(response_size)); - EXPECT_TRUE(writer->AllExpectedWritesDone()); - EXPECT_TRUE(reader->AllExpectedReadsDone()); -} - -TEST_F(ServiceWorkerCacheWriterTest, CompareDataFailSync) { - const std::string data1 = "abcdef"; - size_t response_size = data1.size(); - - MockServiceWorkerResponseWriter* writer = ExpectWriter(); - MockServiceWorkerResponseReader* reader = ExpectReader(); - - // Create a copy reader as it's needed to create cache writer for comparison - // though not used in this test. - ExpectReader(); - - reader->ExpectReadInfoOk(response_size, false); - reader->ExpectReadData(data1.c_str(), data1.length(), false, net::ERR_FAILED); - Initialize(CacheWriterUsage::kForComparison, - false /* pause_when_not_identical */); - - net::Error error = WriteHeaders(response_size); - EXPECT_EQ(net::OK, error); - - EXPECT_EQ(net::ERR_FAILED, WriteData(data1)); - - EXPECT_TRUE(writer->AllExpectedWritesDone()); - EXPECT_TRUE(reader->AllExpectedReadsDone()); - EXPECT_EQ(0U, cache_writer_->bytes_written()); -} - -TEST_F(ServiceWorkerCacheWriterTest, CompareShortCacheReads) { - const size_t kHeaderSize = 16; - const std::string& data1 = "abcdef"; - const std::string& cache_data2 = "ghi"; - const std::string& cache_data3 = "j"; - const std::string& cache_data4 = "kl"; - const std::string& net_data2 = "ghijkl"; - const std::string& data5 = "mnopqrst"; - - MockServiceWorkerResponseReader* reader = ExpectReader(); - reader->ExpectReadInfo(kHeaderSize, false, kHeaderSize); - reader->ExpectReadDataOk(data1, false); - reader->ExpectReadDataOk(cache_data2, false); - reader->ExpectReadDataOk(cache_data3, false); - reader->ExpectReadDataOk(cache_data4, false); - reader->ExpectReadDataOk(data5, false); - - // Create a copy reader and writer as they're needed to create cache writer - // for comparison though not used in this test. - ExpectReader(); - ExpectWriter(); - - Initialize(CacheWriterUsage::kForComparison, - false /* pause_when_not_identical */); - - net::Error error = WriteHeaders(kHeaderSize); - EXPECT_EQ(net::OK, error); - error = WriteData(data1); - EXPECT_EQ(net::OK, error); - error = WriteData(net_data2); - EXPECT_EQ(net::OK, error); - error = WriteData(data5); - EXPECT_EQ(net::OK, error); - EXPECT_TRUE(reader->AllExpectedReadsDone()); - EXPECT_EQ(0U, cache_writer_->bytes_written()); -} - TEST_F(ServiceWorkerCacheWriterTest, CompareDataOkAsync) { const std::string data1 = "abcdef"; size_t response_size = data1.size(); @@ -461,8 +342,8 @@ TEST_F(ServiceWorkerCacheWriterTest, CompareDataOkAsync) { ExpectReader(); ExpectWriter(); - reader->ExpectReadInfoOk(response_size, true); - reader->ExpectReadDataOk(data1, true); + reader->ExpectReadInfoOk(response_size); + reader->ExpectReadDataOk(data1); Initialize(CacheWriterUsage::kForComparison, false /* pause_when_not_identical */); @@ -486,8 +367,8 @@ TEST_F(ServiceWorkerCacheWriterTest, CompareDataManyOkAsync) { "stuvwxyz", }; size_t response_size = 0; - for (size_t i = 0; i < base::size(expected_data); ++i) - response_size += expected_data[i].size(); + for (const auto& chunk : expected_data) + response_size += chunk.size(); MockServiceWorkerResponseReader* reader = ExpectReader(); @@ -496,9 +377,9 @@ TEST_F(ServiceWorkerCacheWriterTest, CompareDataManyOkAsync) { ExpectReader(); ExpectWriter(); - reader->ExpectReadInfoOk(response_size, true); - for (size_t i = 0; i < base::size(expected_data); ++i) { - reader->ExpectReadDataOk(expected_data[i], true); + reader->ExpectReadInfoOk(response_size); + for (const auto& chunk : expected_data) { + reader->ExpectReadDataOk(chunk); } Initialize(CacheWriterUsage::kForComparison, false /* pause_when_not_identical */); @@ -507,8 +388,8 @@ TEST_F(ServiceWorkerCacheWriterTest, CompareDataManyOkAsync) { EXPECT_EQ(net::ERR_IO_PENDING, error); reader->CompletePendingRead(); - for (size_t i = 0; i < base::size(expected_data); ++i) { - error = WriteData(expected_data[i]); + for (const auto& chunk : expected_data) { + error = WriteData(chunk); EXPECT_EQ(net::ERR_IO_PENDING, error); reader->CompletePendingRead(); EXPECT_EQ(net::OK, last_error_); @@ -534,12 +415,12 @@ TEST_F(ServiceWorkerCacheWriterTest, CompareFailedCopySync) { MockServiceWorkerResponseReader* compare_reader = ExpectReader(); MockServiceWorkerResponseReader* copy_reader = ExpectReader(); - compare_reader->ExpectReadInfoOk(cache_response_size, false); - compare_reader->ExpectReadDataOk(data1, false); - compare_reader->ExpectReadDataOk(cache_data2, false); + compare_reader->ExpectReadInfoOk(cache_response_size); + compare_reader->ExpectReadDataOk(data1); + compare_reader->ExpectReadDataOk(cache_data2); - copy_reader->ExpectReadInfoOk(cache_response_size, false); - copy_reader->ExpectReadDataOk(data1, false); + copy_reader->ExpectReadInfoOk(cache_response_size); + copy_reader->ExpectReadDataOk(data1); writer->ExpectWriteInfoOk(net_response_size, false); writer->ExpectWriteDataOk(data1.size(), false); @@ -550,11 +431,25 @@ TEST_F(ServiceWorkerCacheWriterTest, CompareFailedCopySync) { false /* pause_when_not_identical */); net::Error error = WriteHeaders(net_response_size); - EXPECT_EQ(net::OK, error); + EXPECT_EQ(net::ERR_IO_PENDING, error); + compare_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); + error = WriteData(data1); - EXPECT_EQ(net::OK, error); + EXPECT_EQ(net::ERR_IO_PENDING, error); + compare_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); + error = WriteData(net_data2); - EXPECT_EQ(net::OK, error); + EXPECT_EQ(net::ERR_IO_PENDING, error); + compare_reader->CompletePendingRead(); + + // At this point, |copy_reader| is asked to read the header and data1. + copy_reader->CompletePendingRead(); + copy_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); + + // |data3| goes directly to the response writer. error = WriteData(data3); EXPECT_EQ(net::OK, error); @@ -576,13 +471,13 @@ TEST_F(ServiceWorkerCacheWriterTest, CompareFailedCopyShort) { MockServiceWorkerResponseReader* compare_reader = ExpectReader(); MockServiceWorkerResponseReader* copy_reader = ExpectReader(); - compare_reader->ExpectReadInfoOk(cache_response_size, false); - compare_reader->ExpectReadDataOk(data1, false); - compare_reader->ExpectReadDataOk(cache_data2, false); - compare_reader->ExpectReadDataOk("", false); // EOF read + compare_reader->ExpectReadInfoOk(cache_response_size); + compare_reader->ExpectReadDataOk(data1); + compare_reader->ExpectReadDataOk(cache_data2); + compare_reader->ExpectReadDataOk(""); // EOF read - copy_reader->ExpectReadInfoOk(cache_response_size, false); - copy_reader->ExpectReadDataOk(data1, false); + copy_reader->ExpectReadInfoOk(cache_response_size); + copy_reader->ExpectReadDataOk(data1); writer->ExpectWriteInfoOk(net_response_size, false); writer->ExpectWriteDataOk(data1.size(), false); @@ -593,12 +488,30 @@ TEST_F(ServiceWorkerCacheWriterTest, CompareFailedCopyShort) { false /* pause_when_not_identical */); net::Error error = WriteHeaders(net_response_size); - EXPECT_EQ(net::OK, error); + EXPECT_EQ(net::ERR_IO_PENDING, error); + // Read the header from |compare_reader|. + compare_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); + error = WriteData(data1); - EXPECT_EQ(net::OK, error); + EXPECT_EQ(net::ERR_IO_PENDING, error); + // Read |data1| from |compare_reader| for the comparison. + compare_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); + error = WriteData(net_data2); - EXPECT_EQ(net::OK, error); + EXPECT_EQ(net::ERR_IO_PENDING, error); + // Read |cache_data2| and |data3| from |compare_reader|. + compare_reader->CompletePendingRead(); + compare_reader->CompletePendingRead(); + // After that, the cache writer uses |copy_reader| to read the header and + // |data1|. + copy_reader->CompletePendingRead(); + copy_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); + error = WriteData(data3); + // |data3| is directly written to the disk. EXPECT_EQ(net::OK, error); EXPECT_TRUE(writer->AllExpectedWritesDone()); @@ -619,16 +532,16 @@ TEST_F(ServiceWorkerCacheWriterTest, CompareFailedCopyLong) { MockServiceWorkerResponseReader* compare_reader = ExpectReader(); MockServiceWorkerResponseReader* copy_reader = ExpectReader(); - compare_reader->ExpectReadInfoOk(cached_size, false); - compare_reader->ExpectReadDataOk(data1, false); - compare_reader->ExpectReadDataOk(cache_data2, false); + compare_reader->ExpectReadInfoOk(cached_size); + compare_reader->ExpectReadDataOk(data1); + compare_reader->ExpectReadDataOk(cache_data2); // The comparison should fail at the end of |cache_data2|, when the cache // writer realizes the two responses are different sizes, and then the network // data should be written back starting with |net_data2|. - copy_reader->ExpectReadInfoOk(cached_size, false); - copy_reader->ExpectReadDataOk(data1, false); - copy_reader->ExpectReadDataOk(net_data2, false); + copy_reader->ExpectReadInfoOk(cached_size); + copy_reader->ExpectReadDataOk(data1); + copy_reader->ExpectReadDataOk(net_data2); writer->ExpectWriteInfoOk(net_size, false); writer->ExpectWriteDataOk(data1.size(), false); @@ -638,13 +551,33 @@ TEST_F(ServiceWorkerCacheWriterTest, CompareFailedCopyLong) { false /* pause_when_not_identical */); net::Error error = WriteHeaders(net_size); - EXPECT_EQ(net::OK, error); + EXPECT_EQ(net::ERR_IO_PENDING, error); + // Read the header from |compare_reader| for the comparison. + compare_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); + error = WriteData(data1); - EXPECT_EQ(net::OK, error); + EXPECT_EQ(net::ERR_IO_PENDING, error); + // Read |data1| from |compare_reader| for the comparison. + compare_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); + error = WriteData(net_data2); - EXPECT_EQ(net::OK, error); + EXPECT_EQ(net::ERR_IO_PENDING, error); + // Read |cache_data2| from |compare_reader| for the comparison. + compare_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); + error = WriteData(""); - EXPECT_EQ(net::OK, error); + EXPECT_EQ(net::ERR_IO_PENDING, error); + // Diff is found and copying starts. + // Read the header from |copy_reader|. + copy_reader->CompletePendingRead(); + // Read |data1| from |copy_reader| to copy. + copy_reader->CompletePendingRead(); + // Read |net_data_2| from |copy_reader|. + copy_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); EXPECT_TRUE(writer->AllExpectedWritesDone()); EXPECT_TRUE(compare_reader->AllExpectedReadsDone()); @@ -686,13 +619,13 @@ TEST_F(ServiceWorkerCacheWriterTest, MultipleComparisonInSingleWrite) { MockServiceWorkerResponseReader* compare_reader = ExpectReader(); MockServiceWorkerResponseReader* copy_reader = ExpectReader(); - compare_reader->ExpectReadInfoOk(bytes_cached, false); + compare_reader->ExpectReadInfoOk(bytes_cached); for (const auto& data : data_from_cache) - compare_reader->ExpectReadDataOk(data, false); + compare_reader->ExpectReadDataOk(data); - copy_reader->ExpectReadInfoOk(bytes_common, false); + copy_reader->ExpectReadInfoOk(bytes_common); for (const auto& data : data_to_copy) - copy_reader->ExpectReadDataOk(data, false); + copy_reader->ExpectReadDataOk(data); writer->ExpectWriteInfoOk(bytes_from_net, false); for (const auto& data : data_expected) @@ -702,82 +635,30 @@ TEST_F(ServiceWorkerCacheWriterTest, MultipleComparisonInSingleWrite) { false /* pause_when_not_identical */); net::Error error = WriteHeaders(bytes_from_net); - EXPECT_EQ(net::OK, error); + EXPECT_EQ(net::ERR_IO_PENDING, error); + // Read the header from |compare_reader| for the comparison. + compare_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); + for (const auto& data : data_from_net) { error = WriteData(data); - EXPECT_EQ(net::OK, error); + EXPECT_EQ(net::ERR_IO_PENDING, error); + for (size_t i = 0; i < data.size(); ++i) { + // Read the body from |compare_reader|. Repeat data.size() times because + // each chunk in |data_from_cache| is 1 byte. + compare_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); + } } - EXPECT_TRUE(writer->AllExpectedWritesDone()); - EXPECT_TRUE(compare_reader->AllExpectedReadsDone()); - EXPECT_TRUE(copy_reader->AllExpectedReadsDone()); -} - -// Tests behavior when |pause_when_not_identical| is enabled and cache writer -// finishes synchronously. -TEST_F(ServiceWorkerCacheWriterTest, PauseWhenNotIdentical_SyncWriteData) { - // Data from |compare_reader|. - const std::vector<std::string> data_from_cache{"abcd"}; - - // Data for |writer|. The comparison should stop at the first block of the - // data. - const std::vector<std::string> data_from_net{"abxx"}; - - // We don't need |data_to_copy| because the network data and the cached data - // have no common blocks. - - // The written data should be the same as |data_from_net|. - const std::vector<std::string> data_expected{"abxx"}; - - size_t bytes_cached = 0; - size_t bytes_from_net = 0; - size_t bytes_expected = 0; - - for (const auto& data : data_from_cache) - bytes_cached += data.size(); - - for (const auto& data : data_from_net) - bytes_from_net += data.size(); - - for (const auto& data : data_expected) - bytes_expected += data.size(); - - MockServiceWorkerResponseWriter* writer = ExpectWriter(); - MockServiceWorkerResponseReader* compare_reader = ExpectReader(); - MockServiceWorkerResponseReader* copy_reader = ExpectReader(); - - compare_reader->ExpectReadInfoOk(bytes_cached, false); - for (const auto& data : data_from_cache) - compare_reader->ExpectReadDataOk(data, false); - - copy_reader->ExpectReadInfoOk(bytes_cached, false); - - writer->ExpectWriteInfoOk(bytes_expected, false); - for (const auto& data : data_expected) - writer->ExpectWriteDataOk(data.size(), false); - - Initialize(CacheWriterUsage::kForComparison, - true /* pause_when_not_identical */); - - net::Error error = WriteHeaders(bytes_from_net); - EXPECT_EQ(net::OK, error); - - // |cache_writer_| stops the comparison at the first block of the data. - // It should return net::ERR_IO_PENDING and |write_complete_| should remain - // false since |pause_when_not_identical| forbids proceeding to the next step. - write_complete_ = false; - error = WriteData(data_from_net[0]); - EXPECT_EQ(net::ERR_IO_PENDING, error); - EXPECT_FALSE(write_complete_); - EXPECT_EQ(0U, cache_writer_->bytes_written()); + // At the end of the chunk, there's a diff so the header and a chunk of body + // is read from |copy_reader|. Read the header from |compare_reader|. + copy_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); - // Resume |cache_writer_| with a callback. The passed callback shouldn't be - // called because this is a synchronous write. This time, the result should be - // net::OK and the expected data should be written to the storage. - error = - cache_writer_->Resume(base::BindOnce([](net::Error) { NOTREACHED(); })); - EXPECT_EQ(net::OK, error); - EXPECT_EQ(bytes_expected, cache_writer_->bytes_written()); + // Read the first chunk from |compare_reader|. + copy_reader->CompletePendingRead(); + EXPECT_EQ(net::OK, last_error_); EXPECT_TRUE(writer->AllExpectedWritesDone()); EXPECT_TRUE(compare_reader->AllExpectedReadsDone()); @@ -817,11 +698,11 @@ TEST_F(ServiceWorkerCacheWriterTest, PauseWhenNotIdentical_AsyncWriteData) { MockServiceWorkerResponseReader* compare_reader = ExpectReader(); MockServiceWorkerResponseReader* copy_reader = ExpectReader(); - compare_reader->ExpectReadInfoOk(bytes_cached, true); + compare_reader->ExpectReadInfoOk(bytes_cached); for (const auto& data : data_from_cache) - compare_reader->ExpectReadDataOk(data, true); + compare_reader->ExpectReadDataOk(data); - copy_reader->ExpectReadInfoOk(bytes_cached, true); + copy_reader->ExpectReadInfoOk(bytes_cached); writer->ExpectWriteInfoOk(bytes_expected, true); for (const auto& data : data_expected) @@ -906,9 +787,9 @@ TEST_F(ServiceWorkerCacheWriterTest, CopyScript_Async) { MockServiceWorkerResponseWriter* writer = ExpectWriter(); MockServiceWorkerResponseReader* copy_reader = ExpectReader(); - copy_reader->ExpectReadInfoOk(bytes_cached, true); + copy_reader->ExpectReadInfoOk(bytes_cached); for (const auto& data : data_from_cache) - copy_reader->ExpectReadDataOk(data, true); + copy_reader->ExpectReadDataOk(data); writer->ExpectWriteInfoOk(bytes_expected, true); for (const auto& data : data_expected) @@ -968,9 +849,9 @@ TEST_F(ServiceWorkerCacheWriterTest, CopyScript_AsyncMultipleRead) { MockServiceWorkerResponseWriter* writer = ExpectWriter(); MockServiceWorkerResponseReader* copy_reader = ExpectReader(); - copy_reader->ExpectReadInfoOk(bytes_cached, true); + copy_reader->ExpectReadInfoOk(bytes_cached); for (const auto& data : data_from_cache) - copy_reader->ExpectReadDataOk(data, true); + copy_reader->ExpectReadDataOk(data); writer->ExpectWriteInfoOk(bytes_expected, true); for (const auto& data : data_expected) @@ -1029,86 +910,6 @@ TEST_F(ServiceWorkerCacheWriterTest, CopyScript_AsyncMultipleRead) { EXPECT_TRUE(writer->AllExpectedWritesDone()); } -// Tests behavior of a cache writer used to copy script which finishes -// synchronously. -TEST_F(ServiceWorkerCacheWriterTest, CopyScript_Sync) { - // Data from |copy_reader|. - const std::vector<std::string> data_from_cache{"abcd"}; - - // The written data should be the same as |data_from_cache|. - const std::vector<std::string> data_expected{"abcd"}; - - size_t bytes_cached = 0; - size_t bytes_expected = 0; - - for (const auto& data : data_from_cache) - bytes_cached += data.size(); - - for (const auto& data : data_expected) - bytes_expected += data.size(); - - MockServiceWorkerResponseWriter* writer = ExpectWriter(); - MockServiceWorkerResponseReader* copy_reader = ExpectReader(); - - copy_reader->ExpectReadInfoOk(bytes_cached, false); - for (const auto& data : data_from_cache) - copy_reader->ExpectReadDataOk(data, false); - - writer->ExpectWriteInfoOk(bytes_expected, false); - for (const auto& data : data_expected) - writer->ExpectWriteDataOk(data.size(), false); - - Initialize(CacheWriterUsage::kForCopy, false /* pause_when_not_identical */); - - net::Error error = cache_writer_->StartCopy(CreateWriteCallback()); - - // In synchronous read and write, everything finishes synchronously. - EXPECT_EQ(net::OK, error); - EXPECT_EQ(bytes_expected, cache_writer_->bytes_written()); - EXPECT_TRUE(copy_reader->AllExpectedReadsDone()); - EXPECT_TRUE(writer->AllExpectedWritesDone()); -} - -// Tests behavior of a cache writer used to copy script that read multiple -// times and finishes synchronously. -TEST_F(ServiceWorkerCacheWriterTest, CopyScript_SyncMultiRead) { - // Data from |copy_reader|. - const std::vector<std::string> data_from_cache{"a", "bc", "d"}; - - // The written data should be the same as |data_from_cache|. - const std::vector<std::string> data_expected{"a", "bc", "d"}; - - size_t bytes_cached = 0; - size_t bytes_expected = 0; - - for (const auto& data : data_from_cache) - bytes_cached += data.size(); - - for (const auto& data : data_expected) - bytes_expected += data.size(); - - MockServiceWorkerResponseWriter* writer = ExpectWriter(); - MockServiceWorkerResponseReader* copy_reader = ExpectReader(); - - copy_reader->ExpectReadInfoOk(bytes_cached, false); - for (const auto& data : data_from_cache) - copy_reader->ExpectReadDataOk(data, false); - - writer->ExpectWriteInfoOk(bytes_expected, false); - for (const auto& data : data_expected) - writer->ExpectWriteDataOk(data.size(), false); - - Initialize(CacheWriterUsage::kForCopy, false /* pause_when_not_identical */); - - net::Error error = cache_writer_->StartCopy(CreateWriteCallback()); - - // In synchronous read and write, everything finishes synchronously. - EXPECT_EQ(net::OK, error); - EXPECT_EQ(bytes_expected, cache_writer_->bytes_written()); - EXPECT_TRUE(copy_reader->AllExpectedReadsDone()); - EXPECT_TRUE(writer->AllExpectedWritesDone()); -} - // The observer and the response writer all run synchronously. TEST_F(ServiceWorkerCacheWriterTest, ObserverSyncResponseWriterSync) { const size_t kHeaderSize = 16; diff --git a/chromium/content/browser/service_worker/service_worker_client_info.cc b/chromium/content/browser/service_worker/service_worker_client_info.cc deleted file mode 100644 index 54e413c3e3b..00000000000 --- a/chromium/content/browser/service_worker/service_worker_client_info.cc +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2018 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_client_info.h" - -namespace content { - -ServiceWorkerClientInfo::ServiceWorkerClientInfo( - blink::mojom::ServiceWorkerClientType type, - int frame_tree_node_id) - : type(type), frame_tree_node_id(frame_tree_node_id) { - DCHECK_NE(type, blink::mojom::ServiceWorkerClientType::kAll); -} - -ServiceWorkerClientInfo::ServiceWorkerClientInfo( - const ServiceWorkerClientInfo& other) = default; - -ServiceWorkerClientInfo::~ServiceWorkerClientInfo() = default; - -} // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_client_info.h b/chromium/content/browser/service_worker/service_worker_client_info.h deleted file mode 100644 index 2f7353e6da5..00000000000 --- a/chromium/content/browser/service_worker/service_worker_client_info.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2018 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_CLIENT_INFO_H_ -#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CLIENT_INFO_H_ - -#include "content/common/content_export.h" -#include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom.h" - -namespace content { - -// Holds information about a single service worker client: -// https://w3c.github.io/ServiceWorker/#client -struct CONTENT_EXPORT ServiceWorkerClientInfo { - ServiceWorkerClientInfo(blink::mojom::ServiceWorkerClientType type, - int frame_tree_node_id); - ServiceWorkerClientInfo(const ServiceWorkerClientInfo& other); - ~ServiceWorkerClientInfo(); - - // The client type. - blink::mojom::ServiceWorkerClientType type; - - int frame_tree_node_id; -}; - -} // namespace content - -#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CLIENT_INFO_H_ diff --git a/chromium/content/browser/service_worker/service_worker_client_utils.cc b/chromium/content/browser/service_worker/service_worker_client_utils.cc index 52933cd0851..bf55bcf7e6d 100644 --- a/chromium/content/browser/service_worker/service_worker_client_utils.cc +++ b/chromium/content/browser/service_worker/service_worker_client_utils.cc @@ -293,7 +293,7 @@ void NavigateClientOnUI(const GURL& url, // navigation. Not rejecting it would allow websites to prevent the user from // navigating away. See https://crbug.com/930154. NavigationRequest* ongoing_navigation_request = - rfhi->frame_tree_node()->frame_tree()->root()->navigation_request(); + rfhi->frame_tree()->root()->navigation_request(); if (ongoing_navigation_request && ongoing_navigation_request->browser_initiated()) { RunOrPostTaskOnThread( @@ -304,8 +304,8 @@ void NavigateClientOnUI(const GURL& url, } int frame_tree_node_id = rfhi->frame_tree_node()->frame_tree_node_id(); - Navigator* navigator = rfhi->frame_tree_node()->navigator(); - navigator->RequestOpenURL( + Navigator& navigator = rfhi->frame_tree_node()->navigator(); + navigator.RequestOpenURL( rfhi, url, GlobalFrameRoutingId() /* initiator_routing_id */, url::Origin::Create(script_url), nullptr /* post_body */, std::string() /* extra_headers */, @@ -535,8 +535,8 @@ void DidGetExecutionReadyClient( std::move(info)); } else { - base::PostTaskAndReplyWithResult( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTaskAndReplyWithResult( + FROM_HERE, base::BindOnce(&GetWindowClientInfoOnUI, container_host->process_id(), container_host->frame_id(), container_host->create_time(), @@ -559,8 +559,8 @@ void FocusWindowClient(ServiceWorkerContainerHost* container_host, container_host->create_time(), container_host->client_uuid()); std::move(callback).Run(std::move(info)); } else { - base::PostTaskAndReplyWithResult( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTaskAndReplyWithResult( + FROM_HERE, base::BindOnce(&FocusOnUI, container_host->process_id(), container_host->frame_id(), container_host->create_time(), diff --git a/chromium/content/browser/service_worker/service_worker_container_host.cc b/chromium/content/browser/service_worker/service_worker_container_host.cc index ba6f1e4dcad..69ea2e43fff 100644 --- a/chromium/content/browser/service_worker/service_worker_container_host.cc +++ b/chromium/content/browser/service_worker/service_worker_container_host.cc @@ -20,6 +20,7 @@ #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/content_navigation_policy.h" #include "content/common/service_worker/service_worker_utils.h" +#include "content/public/browser/global_routing_id.h" #include "content/public/common/content_client.h" #include "content/public/common/origin_util.h" #include "mojo/public/cpp/bindings/callback_helpers.h" @@ -102,8 +103,7 @@ ServiceWorkerContainerHost::ServiceWorkerContainerHost( client_uuid_(base::GenerateGUID()), is_parent_frame_secure_(is_parent_frame_secure), container_(std::move(container_remote)), - client_type_(blink::mojom::ServiceWorkerClientType::kWindow), - frame_tree_node_id_(frame_tree_node_id) { + client_info_(frame_tree_node_id) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK(IsContainerForWindowClient()); DCHECK(context_); @@ -115,17 +115,13 @@ ServiceWorkerContainerHost::ServiceWorkerContainerHost( int process_id, mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerContainer> container_remote, - blink::mojom::ServiceWorkerClientType client_type, - DedicatedWorkerId dedicated_worker_id, - SharedWorkerId shared_worker_id) + ServiceWorkerClientInfo client_info) : context_(std::move(context)), create_time_(base::TimeTicks::Now()), client_uuid_(base::GenerateGUID()), process_id_(process_id), container_(std::move(container_remote)), - client_type_(client_type), - dedicated_worker_id_(dedicated_worker_id), - shared_worker_id_(shared_worker_id) { + client_info_(client_info) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK(IsContainerForWorkerClient()); DCHECK(context_); @@ -685,35 +681,35 @@ void ServiceWorkerContainerHost::RemoveServiceWorkerObjectHost( bool ServiceWorkerContainerHost::IsContainerForServiceWorker() const { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - return client_type_ == base::nullopt; + return client_info_ == base::nullopt; } bool ServiceWorkerContainerHost::IsContainerForClient() const { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - return client_type_ != base::nullopt; + return client_info_ != base::nullopt; } blink::mojom::ServiceWorkerClientType ServiceWorkerContainerHost::GetClientType() const { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - DCHECK(client_type_); - return *client_type_; + DCHECK(client_info_); + return client_info_->type(); } bool ServiceWorkerContainerHost::IsContainerForWindowClient() const { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - return client_type_ && - *client_type_ == blink::mojom::ServiceWorkerClientType::kWindow; + return client_info_ && + client_info_->type() == blink::mojom::ServiceWorkerClientType::kWindow; } bool ServiceWorkerContainerHost::IsContainerForWorkerClient() const { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); using blink::mojom::ServiceWorkerClientType; - if (!client_type_) + if (!client_info_) return false; - return *client_type_ == ServiceWorkerClientType::kDedicatedWorker || - *client_type_ == ServiceWorkerClientType::kSharedWorker; + return client_info_->type() == ServiceWorkerClientType::kDedicatedWorker || + client_info_->type() == ServiceWorkerClientType::kSharedWorker; } ServiceWorkerClientInfo ServiceWorkerContainerHost::GetServiceWorkerClientInfo() @@ -721,7 +717,7 @@ ServiceWorkerClientInfo ServiceWorkerContainerHost::GetServiceWorkerClientInfo() DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK(IsContainerForClient()); - return ServiceWorkerClientInfo(*client_type_, frame_tree_node_id_); + return *client_info_; } void ServiceWorkerContainerHost::OnBeginNavigationCommit( @@ -778,6 +774,19 @@ void ServiceWorkerContainerHost::OnBeginNavigationCommit( TransitionToClientPhase(ClientPhase::kResponseCommitted); } +void ServiceWorkerContainerHost::OnEndNavigationCommit() { + DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); + DCHECK(IsContainerForWindowClient()); + + DCHECK(!navigation_commit_ended_); + navigation_commit_ended_ = true; + + if (controller_) { + controller_->OnControlleeNavigationCommitted(client_uuid_, process_id_, + frame_id_); + } +} + void ServiceWorkerContainerHost::CompleteWebWorkerPreparation( const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); @@ -823,7 +832,8 @@ void ServiceWorkerContainerHost::UpdateUrls( auto* registry = FrameTreeNodeIdRegistry::GetInstance(); registry->Remove(fetch_request_window_id_); fetch_request_window_id_ = base::UnguessableToken::Create(); - registry->Add(fetch_request_window_id_, frame_tree_node_id_); + registry->Add(fetch_request_window_id_, + client_info_->GetFrameTreeNodeId()); } } @@ -963,7 +973,7 @@ bool ServiceWorkerContainerHost::IsContextSecureForServiceWorker() const { return true; std::set<std::string> schemes; - GetContentClient()->browser()->GetSchemesBypassingSecureContextCheckWhitelist( + GetContentClient()->browser()->GetSchemesBypassingSecureContextCheckAllowlist( &schemes); return schemes.find(url_.scheme()) != schemes.end(); } @@ -1042,14 +1052,14 @@ ServiceWorkerRegistration* ServiceWorkerContainerHost::controller_registration() } void ServiceWorkerContainerHost::set_service_worker_host( - ServiceWorkerProviderHost* service_worker_host) { + ServiceWorkerHost* service_worker_host) { DCHECK(IsContainerForServiceWorker()); DCHECK(!service_worker_host_); DCHECK(service_worker_host); service_worker_host_ = service_worker_host; } -ServiceWorkerProviderHost* ServiceWorkerContainerHost::service_worker_host() { +ServiceWorkerHost* ServiceWorkerContainerHost::service_worker_host() { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK(IsContainerForServiceWorker()); return service_worker_host_; diff --git a/chromium/content/browser/service_worker/service_worker_container_host.h b/chromium/content/browser/service_worker/service_worker_container_host.h index 9e904186115..3cd1c8daf3b 100644 --- a/chromium/content/browser/service_worker/service_worker_container_host.h +++ b/chromium/content/browser/service_worker/service_worker_container_host.h @@ -15,11 +15,9 @@ #include "base/optional.h" #include "base/time/time.h" #include "content/browser/frame_host/back_forward_cache_metrics.h" -#include "content/browser/frame_host/frame_tree_node.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/common/content_export.h" -#include "content/public/browser/dedicated_worker_id.h" -#include "content/public/browser/shared_worker_id.h" +#include "content/public/browser/service_worker_client_info.h" #include "content/public/common/child_process_host.h" #include "mojo/public/cpp/bindings/associated_remote.h" #include "mojo/public/cpp/bindings/receiver_set.h" @@ -42,8 +40,8 @@ class ServiceWorkerObjectHostTest; } class ServiceWorkerContextCore; +class ServiceWorkerHost; class ServiceWorkerObjectHost; -class ServiceWorkerProviderHost; class ServiceWorkerRegistrationObjectHost; class ServiceWorkerVersion; @@ -84,9 +82,9 @@ class ServiceWorkerVersion; // registration settles, if need. // // For service worker execution contexts, ServiceWorkerContainerHost is owned -// by ServiceWorkerProviderHost, which in turn is owned by ServiceWorkerVersion. -// The container host and provider host are destructed when the service worker -// is stopped. +// by ServiceWorkerHost, which in turn is owned by ServiceWorkerVersion. The +// container host and worker host are destructed when the service worker is +// stopped. class CONTENT_EXPORT ServiceWorkerContainerHost final : public blink::mojom::ServiceWorkerContainerHost, public ServiceWorkerRegistration::Listener { @@ -111,9 +109,7 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final int process_id, mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerContainer> container_remote, - blink::mojom::ServiceWorkerClientType client_type, - DedicatedWorkerId dedicated_worker_id, - SharedWorkerId shared_worker_id); + ServiceWorkerClientInfo client_info); ~ServiceWorkerContainerHost() override; @@ -272,6 +268,11 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter> coep_reporter); + // For service worker window clients. Called after the navigation commits to a + // render frame host. At this point, the previous ServiceWorkerContainerHost + // for that render frame host no longer exists. + void OnEndNavigationCommit(); + // For service worker clients that are shared workers or dedicated workers. // Called when the web worker main script resource has finished loading. // Updates this host with information about the worker. @@ -407,7 +408,7 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final base::TimeTicks create_time() const { return create_time_; } int process_id() const { return process_id_; } int frame_id() const { return frame_id_; } - int frame_tree_node_id() const { return frame_tree_node_id_; } + int frame_tree_node_id() const { return client_info_->GetFrameTreeNodeId(); } // For service worker clients. const std::string& client_uuid() const; @@ -424,8 +425,8 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final ServiceWorkerRegistration* controller_registration() const; // For service worker execution contexts. - void set_service_worker_host(ServiceWorkerProviderHost* service_worker_host); - ServiceWorkerProviderHost* service_worker_host(); + void set_service_worker_host(ServiceWorkerHost* service_worker_host); + ServiceWorkerHost* service_worker_host(); // BackForwardCache: // For service worker clients that are windows. @@ -439,6 +440,8 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final // OnRestoreFromBackForwardCache will not be called. void OnRestoreFromBackForwardCache(); + bool navigation_commit_ended() const { return navigation_commit_ended_; } + void EnterBackForwardCacheForTesting() { is_in_back_forward_cache_ = true; } void LeaveBackForwardCacheForTesting() { is_in_back_forward_cache_ = false; } @@ -644,13 +647,10 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final mojo::AssociatedRemote<blink::mojom::ServiceWorkerContainer> container_; // The type of client. - const base::Optional<blink::mojom::ServiceWorkerClientType> client_type_; + const base::Optional<ServiceWorkerClientInfo> client_info_; // For window clients only --------------------------------------------------- - // The ID of the frame tree node where the navigation occurs. - const int frame_tree_node_id_ = FrameTreeNode::kFrameTreeNodeInvalidId; - // A token used internally to identify this context in requests. Corresponds // to the Fetch specification's concept of a request's associated window: // https://fetch.spec.whatwg.org/#concept-request-window. This gets reset on @@ -680,18 +680,13 @@ class CONTENT_EXPORT ServiceWorkerContainerHost final // and RenderFrameHost have the same lifetime. bool is_in_back_forward_cache_ = false; - // For worker clients only --------------------------------------------------- - - // The ID of the client, if the client is a dedicated worker. - DedicatedWorkerId dedicated_worker_id_; - - // The ID of the client, if the client is a shared worker. - SharedWorkerId shared_worker_id_; + // Indicates if OnEndNavigationCommit() was called on this container host. + bool navigation_commit_ended_ = false; // For service worker execution contexts ------------------------------------- - // The ServiceWorkerProviderHost that owns |this|. - ServiceWorkerProviderHost* service_worker_host_ = nullptr; + // The ServiceWorkerHost that owns |this|. + ServiceWorkerHost* service_worker_host_ = nullptr; base::WeakPtrFactory<ServiceWorkerContainerHost> weak_factory_{this}; }; diff --git a/chromium/content/browser/service_worker/service_worker_container_host_unittest.cc b/chromium/content/browser/service_worker/service_worker_container_host_unittest.cc index 7142ed53fa4..962d219f688 100644 --- a/chromium/content/browser/service_worker/service_worker_container_host_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_container_host_unittest.cc @@ -14,12 +14,15 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/run_loop.h" +#include "base/scoped_observer.h" #include "base/test/scoped_feature_list.h" #include "base/threading/thread_task_runner_handle.h" #include "content/browser/frame_host/frame_tree_node.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_provider_host.h" +#include "content/browser/service_worker/service_worker_context_core_observer.h" +#include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/browser/service_worker/service_worker_host.h" #include "content/browser/service_worker/service_worker_register_job.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_test_utils.h" @@ -33,7 +36,7 @@ #include "content/public/test/test_utils.h" #include "content/test/test_content_browser_client.h" #include "content/test/test_content_client.h" -#include "mojo/core/embedder/embedder.h" +#include "mojo/public/cpp/system/functions.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h" @@ -113,7 +116,7 @@ class ServiceWorkerContainerHostTest : public testing::Test { void SetUp() override { old_content_browser_client_ = SetBrowserClientForTesting(&test_content_browser_client_); - mojo::core::SetDefaultProcessErrorCallback(base::BindRepeating( + mojo::SetDefaultProcessErrorHandler(base::BindRepeating( &ServiceWorkerContainerHostTest::OnMojoError, base::Unretained(this))); helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath())); @@ -142,13 +145,12 @@ class ServiceWorkerContainerHostTest : public testing::Test { registration3_ = nullptr; helper_.reset(); SetBrowserClientForTesting(old_content_browser_client_); - mojo::core::SetDefaultProcessErrorCallback( - mojo::core::ProcessErrorCallback()); + mojo::SetDefaultProcessErrorHandler(base::NullCallback()); } - ServiceWorkerRemoteProviderEndpoint PrepareServiceWorkerContainerHost( + ServiceWorkerRemoteContainerEndpoint PrepareServiceWorkerContainerHost( const GURL& document_url) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; net::SiteForCookies site_for_cookies = net::SiteForCookies::FromUrl(document_url); url::Origin top_frame_origin = url::Origin::Create(document_url); @@ -157,12 +159,12 @@ class ServiceWorkerContainerHostTest : public testing::Test { return remote_endpoint; } - ServiceWorkerRemoteProviderEndpoint + ServiceWorkerRemoteContainerEndpoint PrepareServiceWorkerContainerHostWithSiteForCookies( const GURL& document_url, const net::SiteForCookies& site_for_cookies, const base::Optional<url::Origin>& top_frame_origin) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; CreateContainerHostInternal(document_url, site_for_cookies, top_frame_origin, &remote_endpoint); return remote_endpoint; @@ -303,12 +305,10 @@ class ServiceWorkerContainerHostTest : public testing::Test { return !container_host->versions_to_update_.empty(); } - void TestReservedClientsAreNotExposed( - blink::mojom::ServiceWorkerClientType client_type, - const GURL& url); - void TestClientPhaseTransition( - blink::mojom::ServiceWorkerClientType client_type, - const GURL& url); + void TestReservedClientsAreNotExposed(ServiceWorkerClientInfo client_info, + const GURL& url); + void TestClientPhaseTransition(ServiceWorkerClientInfo client_info, + const GURL& url); void TestBackForwardCachedClientsAreNotExposed(const GURL& url); @@ -323,7 +323,7 @@ class ServiceWorkerContainerHostTest : public testing::Test { ServiceWorkerTestContentClient test_content_client_; TestContentBrowserClient test_content_browser_client_; ContentBrowserClient* old_content_browser_client_; - std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints_; + std::vector<ServiceWorkerRemoteContainerEndpoint> remote_endpoints_; std::vector<std::string> bad_messages_; private: @@ -331,7 +331,7 @@ class ServiceWorkerContainerHostTest : public testing::Test { const GURL& document_url, const net::SiteForCookies& site_for_cookies, const base::Optional<url::Origin>& top_frame_origin, - ServiceWorkerRemoteProviderEndpoint* remote_endpoint) { + ServiceWorkerRemoteContainerEndpoint* remote_endpoint) { base::WeakPtr<ServiceWorkerContainerHost> container_host = CreateContainerHostForWindow(helper_->mock_render_process_id(), true /* is_parent_frame_secure */, @@ -626,7 +626,7 @@ TEST_F(ServiceWorkerContainerHostTest, ContentBrowserClient* old_browser_client = SetBrowserClientForTesting(&test_browser_client); - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHostWithSiteForCookies( GURL("https://www.example.com/foo"), net::SiteForCookies::FromUrl(GURL("https://www.example.com/top")), @@ -688,12 +688,11 @@ TEST_F(ServiceWorkerContainerHostTest, AllowsServiceWorker) { helper_->context()->AsWeakPtr()); registration1_->SetActiveVersion(version); - ServiceWorkerRemoteProviderEndpoint remote_endpoint; - std::unique_ptr<ServiceWorkerProviderHost> provider_host = - CreateProviderHostForServiceWorkerContext( - helper_->mock_render_process_id(), true /* is_parent_frame_secure */, - version.get(), helper_->context()->AsWeakPtr(), &remote_endpoint); - ServiceWorkerContainerHost* container_host = provider_host->container_host(); + ServiceWorkerRemoteContainerEndpoint remote_endpoint; + std::unique_ptr<ServiceWorkerHost> worker_host = CreateServiceWorkerHost( + helper_->mock_render_process_id(), true /* is_parent_frame_secure */, + version.get(), helper_->context()->AsWeakPtr(), &remote_endpoint); + ServiceWorkerContainerHost* container_host = worker_host->container_host(); ServiceWorkerTestContentBrowserClient test_browser_client; ContentBrowserClient* old_browser_client = @@ -715,7 +714,7 @@ TEST_F(ServiceWorkerContainerHostTest, AllowsServiceWorker) { } TEST_F(ServiceWorkerContainerHostTest, Register_HTTPS) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo")); EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kNone, @@ -725,7 +724,7 @@ TEST_F(ServiceWorkerContainerHostTest, Register_HTTPS) { } TEST_F(ServiceWorkerContainerHostTest, Register_NonSecureTransportLocalhost) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("http://127.0.0.3:81/foo")); EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kNone, @@ -735,7 +734,7 @@ TEST_F(ServiceWorkerContainerHostTest, Register_NonSecureTransportLocalhost) { } TEST_F(ServiceWorkerContainerHostTest, Register_InvalidScopeShouldFail) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo")); ASSERT_TRUE(bad_messages_.empty()); @@ -745,7 +744,7 @@ TEST_F(ServiceWorkerContainerHostTest, Register_InvalidScopeShouldFail) { } TEST_F(ServiceWorkerContainerHostTest, Register_InvalidScriptShouldFail) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo")); ASSERT_TRUE(bad_messages_.empty()); @@ -755,7 +754,7 @@ TEST_F(ServiceWorkerContainerHostTest, Register_InvalidScriptShouldFail) { } TEST_F(ServiceWorkerContainerHostTest, Register_NonSecureOriginShouldFail) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("http://www.example.com/foo")); ASSERT_TRUE(bad_messages_.empty()); @@ -765,7 +764,7 @@ TEST_F(ServiceWorkerContainerHostTest, Register_NonSecureOriginShouldFail) { } TEST_F(ServiceWorkerContainerHostTest, Register_CrossOriginShouldFail) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo")); ASSERT_TRUE(bad_messages_.empty()); @@ -804,7 +803,7 @@ TEST_F(ServiceWorkerContainerHostTest, Register_CrossOriginShouldFail) { } TEST_F(ServiceWorkerContainerHostTest, Register_BadCharactersShouldFail) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("https://www.example.com")); ASSERT_TRUE(bad_messages_.empty()); @@ -840,7 +839,7 @@ TEST_F(ServiceWorkerContainerHostTest, Register_BadCharactersShouldFail) { } TEST_F(ServiceWorkerContainerHostTest, Register_FileSystemDocumentShouldFail) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost( GURL("filesystem:https://www.example.com/temporary/a")); @@ -863,7 +862,7 @@ TEST_F(ServiceWorkerContainerHostTest, Register_FileSystemDocumentShouldFail) { TEST_F(ServiceWorkerContainerHostTest, Register_FileSystemScriptOrScopeShouldFail) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost( GURL("https://www.example.com/temporary/")); @@ -885,7 +884,7 @@ TEST_F(ServiceWorkerContainerHostTest, } TEST_F(ServiceWorkerContainerHostTest, EarlyContextDeletion) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo")); helper_->ShutdownContext(); @@ -899,7 +898,7 @@ TEST_F(ServiceWorkerContainerHostTest, EarlyContextDeletion) { } TEST_F(ServiceWorkerContainerHostTest, GetRegistration_Success) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo")); const GURL kScope("https://www.example.com/"); @@ -916,7 +915,7 @@ TEST_F(ServiceWorkerContainerHostTest, GetRegistration_Success) { TEST_F(ServiceWorkerContainerHostTest, GetRegistration_NotFoundShouldReturnNull) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo")); blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info; @@ -927,7 +926,7 @@ TEST_F(ServiceWorkerContainerHostTest, } TEST_F(ServiceWorkerContainerHostTest, GetRegistration_CrossOriginShouldFail) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo")); ASSERT_TRUE(bad_messages_.empty()); @@ -937,7 +936,7 @@ TEST_F(ServiceWorkerContainerHostTest, GetRegistration_CrossOriginShouldFail) { } TEST_F(ServiceWorkerContainerHostTest, GetRegistration_InvalidScopeShouldFail) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo")); ASSERT_TRUE(bad_messages_.empty()); @@ -947,7 +946,7 @@ TEST_F(ServiceWorkerContainerHostTest, GetRegistration_InvalidScopeShouldFail) { TEST_F(ServiceWorkerContainerHostTest, GetRegistration_NonSecureOriginShouldFail) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("http://www.example.com/foo")); ASSERT_TRUE(bad_messages_.empty()); @@ -957,7 +956,7 @@ TEST_F(ServiceWorkerContainerHostTest, } TEST_F(ServiceWorkerContainerHostTest, GetRegistrations_SecureOrigin) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo")); EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kNone, @@ -966,7 +965,7 @@ TEST_F(ServiceWorkerContainerHostTest, GetRegistrations_SecureOrigin) { TEST_F(ServiceWorkerContainerHostTest, GetRegistrations_NonSecureOriginShouldFail) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareServiceWorkerContainerHost(GURL("http://www.example.com/foo")); ASSERT_TRUE(bad_messages_.empty()); @@ -978,25 +977,24 @@ TEST_F(ServiceWorkerContainerHostTest, // when iterating over client container hosts. If it were, it'd be undesirably // exposed via the Clients API. void ServiceWorkerContainerHostTest::TestReservedClientsAreNotExposed( - blink::mojom::ServiceWorkerClientType client_type, + ServiceWorkerClientInfo client_info, const GURL& url) { { mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerContainer> client_remote; mojo::PendingAssociatedReceiver<blink::mojom::ServiceWorkerContainerHost> host_receiver; - auto provider_info = - blink::mojom::ServiceWorkerProviderInfoForClient::New(); - provider_info->client_receiver = + auto container_info = + blink::mojom::ServiceWorkerContainerInfoForClient::New(); + container_info->client_receiver = client_remote.InitWithNewEndpointAndPassReceiver(); host_receiver = - provider_info->host_remote.InitWithNewEndpointAndPassReceiver(); + container_info->host_remote.InitWithNewEndpointAndPassReceiver(); base::WeakPtr<ServiceWorkerContainerHost> container_host = context_->CreateContainerHostForWorker( std::move(host_receiver), helper_->mock_render_process_id(), - std::move(client_remote), client_type, DedicatedWorkerId(), - SharedWorkerId()); + std::move(client_remote), client_info); container_host->UpdateUrls(url, net::SiteForCookies::FromUrl(url), url::Origin::Create(url)); EXPECT_FALSE(CanFindClientContainerHost(container_host.get())); @@ -1011,7 +1009,7 @@ void ServiceWorkerContainerHostTest::TestReservedClientsAreNotExposed( /*are_ancestors_secure=*/true); base::WeakPtr<ServiceWorkerContainerHost> container_host = std::move(host_and_info->host); - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; remote_endpoint.BindForWindow(std::move(host_and_info->info)); FinishNavigation(container_host.get()); @@ -1030,14 +1028,14 @@ TEST_F(ServiceWorkerContainerHostTestWithPlzDedicatedWorker, ASSERT_TRUE( base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker)); TestReservedClientsAreNotExposed( - blink::mojom::ServiceWorkerClientType::kDedicatedWorker, + ServiceWorkerClientInfo(DedicatedWorkerId()), GURL("https://www.example.com/dedicated_worker.js")); } TEST_F(ServiceWorkerContainerHostTest, ReservedClientsAreNotExposedToClientsApiForSharedWorker) { TestReservedClientsAreNotExposed( - blink::mojom::ServiceWorkerClientType::kSharedWorker, + ServiceWorkerClientInfo(SharedWorkerId()), GURL("https://www.example.com/shared_worker.js")); } @@ -1048,7 +1046,7 @@ TEST_F(ServiceWorkerContainerHostTest, ClientPhaseForWindow) { /*are_ancestors_secure=*/true); base::WeakPtr<ServiceWorkerContainerHost> container_host = std::move(host_and_info->host); - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; remote_endpoint.BindForWindow(std::move(host_and_info->info)); EXPECT_FALSE(container_host->is_response_committed()); EXPECT_FALSE(container_host->is_execution_ready()); @@ -1067,23 +1065,23 @@ TEST_F(ServiceWorkerContainerHostTest, ClientPhaseForWindow) { // Tests the client phase transitions for workers. void ServiceWorkerContainerHostTest::TestClientPhaseTransition( - blink::mojom::ServiceWorkerClientType client_type, + ServiceWorkerClientInfo client_info, const GURL& url) { mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerContainer> client_remote; mojo::PendingAssociatedReceiver<blink::mojom::ServiceWorkerContainerHost> host_receiver; - auto provider_info = blink::mojom::ServiceWorkerProviderInfoForClient::New(); - provider_info->client_receiver = + auto container_info = + blink::mojom::ServiceWorkerContainerInfoForClient::New(); + container_info->client_receiver = client_remote.InitWithNewEndpointAndPassReceiver(); host_receiver = - provider_info->host_remote.InitWithNewEndpointAndPassReceiver(); + container_info->host_remote.InitWithNewEndpointAndPassReceiver(); base::WeakPtr<ServiceWorkerContainerHost> container_host = helper_->context()->CreateContainerHostForWorker( std::move(host_receiver), helper_->mock_render_process_id(), - std::move(client_remote), client_type, DedicatedWorkerId(), - SharedWorkerId()); + std::move(client_remote), client_info); EXPECT_FALSE(container_host->is_response_committed()); EXPECT_FALSE(container_host->is_execution_ready()); @@ -1101,14 +1099,13 @@ TEST_F(ServiceWorkerContainerHostTestWithPlzDedicatedWorker, ASSERT_TRUE( base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker)); TestClientPhaseTransition( - blink::mojom::ServiceWorkerClientType::kDedicatedWorker, + ServiceWorkerClientInfo(DedicatedWorkerId()), GURL("https://www.example.com/dedicated_worker.js")); } TEST_F(ServiceWorkerContainerHostTest, ClientPhaseForSharedWorker) { - TestClientPhaseTransition( - blink::mojom::ServiceWorkerClientType::kSharedWorker, - GURL("https://www.example.com/shared_worker.js")); + TestClientPhaseTransition(ServiceWorkerClientInfo(SharedWorkerId()), + GURL("https://www.example.com/shared_worker.js")); } // Run tests with BackForwardCache. @@ -1137,7 +1134,7 @@ class ServiceWorkerContainerHostTestWithBackForwardCache // exposed via the Clients API. void ServiceWorkerContainerHostTest::TestBackForwardCachedClientsAreNotExposed( const GURL& url) { - std::unique_ptr<ServiceWorkerProviderHost> provider_host; + std::unique_ptr<ServiceWorkerHost> worker_host; { // Create an active version. scoped_refptr<ServiceWorkerVersion> version = @@ -1146,11 +1143,11 @@ void ServiceWorkerContainerHostTest::TestBackForwardCachedClientsAreNotExposed( 1 /* version_id */, helper_->context()->AsWeakPtr()); registration1_->SetActiveVersion(version); - ServiceWorkerRemoteProviderEndpoint remote_endpoint; - provider_host = CreateProviderHostForServiceWorkerContext( + ServiceWorkerRemoteContainerEndpoint remote_endpoint; + worker_host = CreateServiceWorkerHost( helper_->mock_render_process_id(), true /* is_parent_frame_secure */, version.get(), helper_->context()->AsWeakPtr(), &remote_endpoint); - ASSERT_TRUE(provider_host); + ASSERT_TRUE(worker_host); } { std::unique_ptr<ServiceWorkerContainerHostAndInfo> host_and_info = @@ -1158,7 +1155,7 @@ void ServiceWorkerContainerHostTest::TestBackForwardCachedClientsAreNotExposed( /*are_ancestors_secure=*/true); base::WeakPtr<ServiceWorkerContainerHost> container_host = std::move(host_and_info->host); - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; remote_endpoint.BindForWindow(std::move(host_and_info->info)); FinishNavigation(container_host.get()); @@ -1185,6 +1182,108 @@ TEST_F(ServiceWorkerContainerHostTestWithBackForwardCache, GURL("https://www.example.com/sw.js")); } +class TestServiceWorkerContextCoreObserver + : public ServiceWorkerContextCoreObserver { + public: + explicit TestServiceWorkerContextCoreObserver( + ServiceWorkerContextWrapper* wrapper) + : observer_(this) { + observer_.Add(wrapper); + } + + void OnControlleeAdded(int64_t version_id, + const std::string& uuid, + const ServiceWorkerClientInfo& info) override { + ++on_controllee_added_count_; + } + void OnControlleeRemoved(int64_t version_id, + const std::string& uuid) override { + ++on_controllee_removed_count_; + } + void OnControlleeNavigationCommitted( + int64_t version_id, + const std::string& uuid, + GlobalFrameRoutingId render_frame_host_id) override { + ++on_controllee_navigation_committed_count_; + } + + int on_controllee_added_count() const { return on_controllee_added_count_; } + int on_controllee_removed_count() const { + return on_controllee_removed_count_; + } + int on_controllee_navigation_committed_count() const { + return on_controllee_navigation_committed_count_; + } + + private: + int on_controllee_added_count_ = 0; + int on_controllee_removed_count_ = 0; + int on_controllee_navigation_committed_count_ = 0; + + ScopedObserver<ServiceWorkerContextWrapper, ServiceWorkerContextCoreObserver> + observer_; +}; + +TEST_F(ServiceWorkerContainerHostTestWithBackForwardCache, ControlleeEvents) { + TestServiceWorkerContextCoreObserver observer(helper_->context_wrapper()); + + // Create a host. + std::unique_ptr<ServiceWorkerContainerHostAndInfo> host_and_info = + CreateContainerHostAndInfoForWindow(helper_->context()->AsWeakPtr(), + /*are_ancestors_secure=*/true); + base::WeakPtr<ServiceWorkerContainerHost> container_host = + std::move(host_and_info->host); + remote_endpoints_.emplace_back(); + remote_endpoints_.back().BindForWindow(std::move(host_and_info->info)); + auto container = std::make_unique<MockServiceWorkerContainer>( + std::move(*remote_endpoints_.back().client_receiver())); + + // Create an active version and then start the navigation. + scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion( + registration1_.get(), GURL("https://www.example.com/sw.js"), + blink::mojom::ScriptType::kClassic, 1 /* version_id */, + helper_->context()->AsWeakPtr()); + version->set_fetch_handler_existence( + ServiceWorkerVersion::FetchHandlerExistence::EXISTS); + version->SetStatus(ServiceWorkerVersion::ACTIVATED); + registration1_->SetActiveVersion(version); + + // Finish the navigation. + FinishNavigation(container_host.get()); + container_host->SetControllerRegistration( + registration1_, false /* notify_controllerchange */); + remote_endpoints_.back().host_remote()->get()->OnExecutionReady(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(observer.on_controllee_added_count(), 1); + EXPECT_EQ(observer.on_controllee_navigation_committed_count(), 0); + EXPECT_EQ(observer.on_controllee_removed_count(), 0); + + // The navigation commit ending should send the + // OnControlleeNavigationCommitted() notification. + container_host->OnEndNavigationCommit(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(observer.on_controllee_added_count(), 1); + EXPECT_EQ(observer.on_controllee_navigation_committed_count(), 1); + EXPECT_EQ(observer.on_controllee_removed_count(), 0); + + version->MoveControlleeToBackForwardCacheMap(container_host->client_uuid()); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(observer.on_controllee_added_count(), 1); + EXPECT_EQ(observer.on_controllee_navigation_committed_count(), 1); + EXPECT_EQ(observer.on_controllee_removed_count(), 1); + + version->RestoreControlleeFromBackForwardCacheMap( + container_host->client_uuid()); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(observer.on_controllee_added_count(), 2); + EXPECT_EQ(observer.on_controllee_navigation_committed_count(), 2); + EXPECT_EQ(observer.on_controllee_removed_count(), 1); +} + // Tests that the service worker involved with a navigation (via // AddServiceWorkerToUpdate) is updated when the host for the navigation is // destroyed. diff --git a/chromium/content/browser/service_worker/service_worker_context_core.cc b/chromium/content/browser/service_worker/service_worker_context_core.cc index 331e16f4a02..7818fc7bb9e 100644 --- a/chromium/content/browser/service_worker/service_worker_context_core.cc +++ b/chromium/content/browser/service_worker/service_worker_context_core.cc @@ -18,7 +18,6 @@ #include "base/memory/ptr_util.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_util.h" -#include "base/task/post_task.h" #include "base/threading/thread_task_runner_handle.h" #include "content/browser/frame_host/frame_tree_node.h" #include "content/browser/frame_host/render_frame_host_impl.h" @@ -221,7 +220,7 @@ class ClearAllServiceWorkersHelper friend class base::RefCounted<ClearAllServiceWorkersHelper>; ~ClearAllServiceWorkersHelper() { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - base::PostTask(FROM_HERE, {BrowserThread::UI}, std::move(callback_)); + GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(callback_)); } base::OnceClosure callback_; @@ -391,8 +390,8 @@ void ServiceWorkerContextCore::HasMainFrameWindowClient(const GURL& origin, base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), result)); } else { - base::PostTaskAndReplyWithResult( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTaskAndReplyWithResult( + FROM_HERE, base::BindOnce(&FrameListContainsMainFrameOnUI, std::move(render_frames)), std::move(callback)); @@ -433,12 +432,9 @@ ServiceWorkerContextCore::CreateContainerHostForWorker( int process_id, mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerContainer> container_remote, - blink::mojom::ServiceWorkerClientType client_type, - DedicatedWorkerId dedicated_worker_id, - SharedWorkerId shared_worker_id) { + ServiceWorkerClientInfo client_info) { auto container_host = std::make_unique<ServiceWorkerContainerHost>( - AsWeakPtr(), process_id, std::move(container_remote), client_type, - dedicated_worker_id, shared_worker_id); + AsWeakPtr(), process_id, std::move(container_remote), client_info); ServiceWorkerContainerHost* container_host_ptr = container_host.get(); @@ -703,6 +699,7 @@ void ServiceWorkerContextCore::AddLiveRegistration( } void ServiceWorkerContextCore::RemoveLiveRegistration(int64_t id) { + DCHECK(live_registrations_.find(id) != live_registrations_.end()); live_registrations_.erase(id); } @@ -878,6 +875,15 @@ void ServiceWorkerContextCore::NotifyRegistrationStored(int64_t registration_id, registration_id, scope); } +void ServiceWorkerContextCore::NotifyAllRegistrationsDeletedForOrigin( + const url::Origin& origin) { + DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); + observer_list_->Notify( + FROM_HERE, + &ServiceWorkerContextCoreObserver::OnAllRegistrationsDeletedForOrigin, + origin); +} + void ServiceWorkerContextCore::OnStorageWiped() { observer_list_->Notify(FROM_HERE, &ServiceWorkerContextCoreObserver::OnStorageWiped); @@ -896,9 +902,9 @@ void ServiceWorkerContextCore::OnControlleeAdded( const std::string& client_uuid, const ServiceWorkerClientInfo& client_info) { DCHECK_EQ(this, version->context().get()); - observer_list_->Notify( - FROM_HERE, &ServiceWorkerContextCoreObserver::OnControlleeAdded, - version->version_id(), version->scope(), client_uuid, client_info); + observer_list_->Notify(FROM_HERE, + &ServiceWorkerContextCoreObserver::OnControlleeAdded, + version->version_id(), client_uuid, client_info); } void ServiceWorkerContextCore::OnControlleeRemoved( @@ -907,7 +913,7 @@ void ServiceWorkerContextCore::OnControlleeRemoved( DCHECK_EQ(this, version->context().get()); observer_list_->Notify(FROM_HERE, &ServiceWorkerContextCoreObserver::OnControlleeRemoved, - version->version_id(), version->scope(), client_uuid); + version->version_id(), client_uuid); } void ServiceWorkerContextCore::OnNoControllees(ServiceWorkerVersion* version) { @@ -923,6 +929,18 @@ void ServiceWorkerContextCore::OnNoControllees(ServiceWorkerVersion* version) { version->version_id(), version->scope()); } +void ServiceWorkerContextCore::OnControlleeNavigationCommitted( + ServiceWorkerVersion* version, + const std::string& client_uuid, + GlobalFrameRoutingId render_frame_host_id) { + DCHECK_EQ(this, version->context().get()); + + observer_list_->Notify( + FROM_HERE, + &ServiceWorkerContextCoreObserver::OnControlleeNavigationCommitted, + version->version_id(), client_uuid, render_frame_host_id); +} + void ServiceWorkerContextCore::OnRunningStateChanged( ServiceWorkerVersion* version) { DCHECK_EQ(this, version->context().get()); diff --git a/chromium/content/browser/service_worker/service_worker_context_core.h b/chromium/content/browser/service_worker/service_worker_context_core.h index aa95543013b..bec8b4d81c5 100644 --- a/chromium/content/browser/service_worker/service_worker_context_core.h +++ b/chromium/content/browser/service_worker/service_worker_context_core.h @@ -25,6 +25,7 @@ #include "content/browser/service_worker/service_worker_storage.h" #include "content/common/content_export.h" #include "content/public/browser/dedicated_worker_id.h" +#include "content/public/browser/global_routing_id.h" #include "content/public/browser/service_worker_context.h" #include "content/public/browser/shared_worker_id.h" #include "mojo/public/cpp/bindings/associated_receiver_set.h" @@ -141,6 +142,14 @@ class CONTENT_EXPORT ServiceWorkerContextCore void OnControlleeRemoved(ServiceWorkerVersion* version, const std::string& client_uuid); + // Called when the navigation for a window client commits to a render frame + // host. Also called asynchronously to preserve the ordering with + // OnControlleeAdded and OnControlleeRemoved. + void OnControlleeNavigationCommitted( + ServiceWorkerVersion* version, + const std::string& client_uuid, + GlobalFrameRoutingId render_frame_host_id); + // Called when all controllees are removed. // Note regarding BackForwardCache integration: // Clients in back-forward cache don't count as controllees. @@ -217,9 +226,7 @@ class CONTENT_EXPORT ServiceWorkerContextCore int process_id, mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerContainer> container_remote, - blink::mojom::ServiceWorkerClientType client_type, - DedicatedWorkerId dedicated_worker_id, - SharedWorkerId shared_worker_id); + ServiceWorkerClientInfo client_info); // Updates the client UUID of an existing container host. void UpdateContainerHostClientID(const std::string& current_client_uuid, @@ -282,6 +289,8 @@ class CONTENT_EXPORT ServiceWorkerContextCore // does not own these object or influence their lifetime. ServiceWorkerRegistration* GetLiveRegistration(int64_t registration_id); void AddLiveRegistration(ServiceWorkerRegistration* registration); + // RemoveLiveRegistration removes registration from |live_registrations_| + // and notifies all observers of the id of the registration removed. void RemoveLiveRegistration(int64_t registration_id); const std::map<int64_t, ServiceWorkerRegistration*>& GetLiveRegistrations() const { @@ -332,6 +341,9 @@ class CONTENT_EXPORT ServiceWorkerContextCore // Called by ServiceWorkerStorage when StoreRegistration() succeeds. void NotifyRegistrationStored(int64_t registration_id, const GURL& scope); + // Called on the core thread and notifies observers that all registrations + // have been deleted for a particular origin. + void NotifyAllRegistrationsDeletedForOrigin(const url::Origin& origin); URLLoaderFactoryGetter* loader_factory_getter() { return loader_factory_getter_.get(); @@ -402,7 +414,7 @@ class CONTENT_EXPORT ServiceWorkerContextCore // |container_host_by_uuid_| owns container hosts for service worker clients. // Container hosts for service worker execution contexts are owned by - // ServiceWorkerProviderHost. + // ServiceWorkerHost. ContainerHostByClientUUIDMap container_host_by_uuid_; std::unique_ptr< diff --git a/chromium/content/browser/service_worker/service_worker_context_core_observer.h b/chromium/content/browser/service_worker/service_worker_context_core_observer.h index fec34e98652..e8ebdb686e7 100644 --- a/chromium/content/browser/service_worker/service_worker_context_core_observer.h +++ b/chromium/content/browser/service_worker/service_worker_context_core_observer.h @@ -13,6 +13,7 @@ #include "base/time/time.h" #include "content/browser/service_worker/service_worker_info.h" #include "content/browser/service_worker/service_worker_version.h" +#include "content/public/browser/global_routing_id.h" #include "third_party/blink/public/mojom/service_worker/service_worker_container_type.mojom.h" #include "url/gurl.h" @@ -71,13 +72,15 @@ class ServiceWorkerContextCoreObserver { virtual void OnReportConsoleMessage(int64_t version_id, const ConsoleMessage& message) {} virtual void OnControlleeAdded(int64_t version_id, - const GURL& scope, const std::string& uuid, const ServiceWorkerClientInfo& info) {} virtual void OnControlleeRemoved(int64_t version_id, - const GURL& scope, const std::string& uuid) {} virtual void OnNoControllees(int64_t version_id, const GURL& scope) {} + virtual void OnControlleeNavigationCommitted( + int64_t version_id, + const std::string& uuid, + GlobalFrameRoutingId render_frame_host_id) {} // Called when the ServiceWorkerContainer.register() promise is resolved. // // This is called before the service worker registration is persisted to @@ -92,9 +95,23 @@ class ServiceWorkerContextCoreObserver { // add user data to the registration. virtual void OnRegistrationStored(int64_t registration_id, const GURL& scope) {} + + // Called after a task has been posted to delete a registration from storage. + // This is roughly equivalent to the same time that the promise for + // unregister() would be resolved. This means the live + // ServiceWorkerRegistration may still exist, and the deletion operator may + // not yet have finished. virtual void OnRegistrationDeleted(int64_t registration_id, const GURL& scope) {} + // Called after all registrations for |origin| are deleted from storage. There + // may still be live registrations for this origin in the kUninstalling or + // kUninstalled state. + // + // This is called after OnRegistrationDeleted(). It is called once + // ServiceWorkerRegistry gets confirmation that the delete operation finished. + virtual void OnAllRegistrationsDeletedForOrigin(const url::Origin& origin) {} + // Notified when the storage corruption recovery is completed and all stored // data is wiped out. virtual void OnStorageWiped() {} diff --git a/chromium/content/browser/service_worker/service_worker_context_core_unittest.cc b/chromium/content/browser/service_worker/service_worker_context_core_unittest.cc index f403b351fb0..21f7bbc753a 100644 --- a/chromium/content/browser/service_worker/service_worker_context_core_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_context_core_unittest.cc @@ -152,7 +152,7 @@ class ServiceWorkerContextCoreTest : public testing::Test, private: BrowserTaskEnvironment task_environment_; std::unique_ptr<EmbeddedWorkerTestHelper> helper_; - std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints_; + std::vector<ServiceWorkerRemoteContainerEndpoint> remote_endpoints_; GURL scope_for_wait_for_activated_; base::OnceClosure quit_closure_for_wait_for_activated_; bool is_observing_context_ = false; diff --git a/chromium/content/browser/service_worker/service_worker_context_unittest.cc b/chromium/content/browser/service_worker/service_worker_context_unittest.cc index 448978641cf..163d627c95c 100644 --- a/chromium/content/browser/service_worker/service_worker_context_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_context_unittest.cc @@ -17,8 +17,8 @@ #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_core_observer.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/browser/service_worker/service_worker_host.h" #include "content/browser/service_worker/service_worker_metrics.h" -#include "content/browser/service_worker/service_worker_provider_host.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_storage.h" #include "content/browser/service_worker/service_worker_test_utils.h" @@ -266,7 +266,10 @@ class TestServiceWorkerContextObserver : public ServiceWorkerContextObserver { RegistrationStored, VersionActivated, VersionRedundant, + ControlleeAdded, + ControlleeRemoved, NoControllees, + ControlleeNavigationCommitted, VersionStartedRunning, VersionStoppedRunning, Destruct @@ -318,6 +321,23 @@ class TestServiceWorkerContextObserver : public ServiceWorkerContextObserver { events_.push_back(log); } + void OnControlleeAdded(int64_t version_id, + const std::string& client_uuid, + const ServiceWorkerClientInfo& client_info) override { + EventLog log; + log.type = EventType::ControlleeAdded; + log.version_id = version_id; + events_.push_back(log); + } + + void OnControlleeRemoved(int64_t version_id, + const std::string& client_uuid) override { + EventLog log; + log.type = EventType::ControlleeRemoved; + log.version_id = version_id; + events_.push_back(log); + } + void OnNoControllees(int64_t version_id, const GURL& scope) override { EventLog log; log.type = EventType::NoControllees; @@ -326,6 +346,16 @@ class TestServiceWorkerContextObserver : public ServiceWorkerContextObserver { events_.push_back(log); } + void OnControlleeNavigationCommitted( + int64_t version_id, + const std::string& client_uuid, + GlobalFrameRoutingId render_frame_host_id) override { + EventLog log; + log.type = EventType::ControlleeNavigationCommitted; + log.version_id = version_id; + events_.push_back(log); + } + void OnVersionStartedRunning( int64_t version_id, const ServiceWorkerRunningInfo& running_info) override { @@ -403,8 +433,9 @@ TEST_F(ServiceWorkerContextTest, RegistrationCompletedObserver) { EXPECT_EQ(scope, events[2].url); } -// Make sure OnNoControllees is called on observer. -TEST_F(ServiceWorkerContextTest, NoControlleesObserver) { +// Make sure OnControlleeAdded, OnControlleeRemoved and OnNoControllees are +// called on observer. +TEST_F(ServiceWorkerContextTest, Observer_ControlleeEvents) { GURL scope("https://www.example.com/"); GURL script_url("https://www.example.com/service_worker.js"); blink::mojom::ServiceWorkerRegistrationOptions options; @@ -420,24 +451,38 @@ TEST_F(ServiceWorkerContextTest, NoControlleesObserver) { ServiceWorkerVersion::FetchHandlerExistence::EXISTS); version->SetStatus(ServiceWorkerVersion::ACTIVATED); - ServiceWorkerRemoteProviderEndpoint endpoint; + ServiceWorkerRemoteContainerEndpoint endpoint; base::WeakPtr<ServiceWorkerContainerHost> container_host = CreateContainerHostForWindow(helper_->mock_render_process_id(), true, context()->AsWeakPtr(), &endpoint); + TestServiceWorkerContextObserver observer(context_wrapper()); + version->AddControllee(container_host.get()); base::RunLoop().RunUntilIdle(); - TestServiceWorkerContextObserver observer(context_wrapper()); + ASSERT_EQ(1u, observer.events().size()); + EXPECT_EQ(TestServiceWorkerContextObserver::EventType::ControlleeAdded, + observer.events()[0].type); + + version->OnControlleeNavigationCommitted(container_host->client_uuid(), + container_host->process_id(), + container_host->frame_id()); + base::RunLoop().RunUntilIdle(); + + ASSERT_EQ(2u, observer.events().size()); + EXPECT_EQ(TestServiceWorkerContextObserver::EventType:: + ControlleeNavigationCommitted, + observer.events()[1].type); version->RemoveControllee(container_host->client_uuid()); base::RunLoop().RunUntilIdle(); - ASSERT_EQ(1u, observer.events().size()); + ASSERT_EQ(4u, observer.events().size()); + EXPECT_EQ(TestServiceWorkerContextObserver::EventType::ControlleeRemoved, + observer.events()[2].type); EXPECT_EQ(TestServiceWorkerContextObserver::EventType::NoControllees, - observer.events()[0].type); - EXPECT_EQ(scope, observer.events()[0].url); - EXPECT_EQ(2l, observer.events()[0].version_id); + observer.events()[3].type); } // Make sure OnVersionActivated is called on observer. @@ -977,7 +1022,7 @@ TEST_F(ServiceWorkerContextTest, ContainerHostIterator) { const int kRenderProcessId2 = 2; const GURL kOrigin1 = GURL("https://www.example.com/"); const GURL kOrigin2 = GURL("https://another-origin.example.net/"); - std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints; + std::vector<ServiceWorkerRemoteContainerEndpoint> remote_endpoints; // Host1 : process_id=1, origin1. remote_endpoints.emplace_back(); @@ -1020,17 +1065,16 @@ TEST_F(ServiceWorkerContextTest, ContainerHostIterator) { blink::mojom::ScriptType::kClassic, 1L /* version_id */, helper_->context()->AsWeakPtr()); remote_endpoints.emplace_back(); - // ServiceWorkrProviderHost creates ServiceWorkerContainerHost for a service - // worker execution context. - std::unique_ptr<ServiceWorkerProviderHost> provider_host4 = - CreateProviderHostForServiceWorkerContext( - kRenderProcessId2, true /* is_parent_frame_secure */, version.get(), - context()->AsWeakPtr(), &remote_endpoints.back()); + // ServiceWorkerHost creates ServiceWorkerContainerHost for a service worker + // execution context. + std::unique_ptr<ServiceWorkerHost> worker_host4 = CreateServiceWorkerHost( + kRenderProcessId2, true /* is_parent_frame_secure */, version.get(), + context()->AsWeakPtr(), &remote_endpoints.back()); ASSERT_TRUE(container_host1); ASSERT_TRUE(container_host2); ASSERT_TRUE(container_host3); - ASSERT_TRUE(provider_host4->container_host()); + ASSERT_TRUE(worker_host4->container_host()); // Iterate over the client container hosts that belong to kOrigin1. std::set<ServiceWorkerContainerHost*> results; @@ -1045,7 +1089,7 @@ TEST_F(ServiceWorkerContextTest, ContainerHostIterator) { EXPECT_TRUE(base::Contains(results, container_host3.get())); // Iterate over the container hosts that belong to kOrigin2. This should not - // include provider_host4->container_host() as it's not for controllee. + // include worker_host4->container_host() as it's not for controllee. results.clear(); for (auto it = context()->GetClientContainerHostIterator( kOrigin2, true /* include_reserved_clients */, diff --git a/chromium/content/browser/service_worker/service_worker_context_watcher.cc b/chromium/content/browser/service_worker/service_worker_context_watcher.cc index 12c7fb7b89d..f179bc8687d 100644 --- a/chromium/content/browser/service_worker/service_worker_context_watcher.cc +++ b/chromium/content/browser/service_worker/service_worker_context_watcher.cc @@ -8,7 +8,6 @@ #include "base/bind.h" #include "base/stl_util.h" -#include "base/task/post_task.h" #include "content/browser/service_worker/embedded_worker_status.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_version.h" @@ -103,13 +102,13 @@ void ServiceWorkerContextWatcher::OnStoredRegistrationsOnCoreThread( ++version_it; } - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce( &ServiceWorkerContextWatcher::RunWorkerRegistrationUpdatedCallback, this, std::move(registrations))); - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce( &ServiceWorkerContextWatcher::RunWorkerVersionUpdatedCallback, this, std::move(versions))); @@ -163,8 +162,8 @@ void ServiceWorkerContextWatcher::SendRegistrationInfo( registrations->push_back( ServiceWorkerRegistrationInfo(scope, registration_id, delete_flag)); } - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce( &ServiceWorkerContextWatcher::RunWorkerRegistrationUpdatedCallback, this, std::move(registrations))); @@ -176,8 +175,8 @@ void ServiceWorkerContextWatcher::SendVersionInfo( std::unique_ptr<std::vector<ServiceWorkerVersionInfo>> versions = std::make_unique<std::vector<ServiceWorkerVersionInfo>>(); versions->push_back(version_info); - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce( &ServiceWorkerContextWatcher::RunWorkerVersionUpdatedCallback, this, std::move(versions))); @@ -311,8 +310,8 @@ void ServiceWorkerContextWatcher::OnErrorReported(int64_t version_id, auto it = version_info_map_.find(version_id); if (it != version_info_map_.end()) registration_id = it->second->registration_id; - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce( &ServiceWorkerContextWatcher::RunWorkerErrorReportedCallback, this, registration_id, version_id, std::make_unique<ErrorInfo>(info))); @@ -329,8 +328,8 @@ void ServiceWorkerContextWatcher::OnReportConsoleMessage( if (it != version_info_map_.end()) registration_id = it->second->registration_id; - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce( &ServiceWorkerContextWatcher::RunWorkerErrorReportedCallback, this, registration_id, version_id, @@ -340,7 +339,6 @@ void ServiceWorkerContextWatcher::OnReportConsoleMessage( void ServiceWorkerContextWatcher::OnControlleeAdded( int64_t version_id, - const GURL& scope, const std::string& uuid, const ServiceWorkerClientInfo& info) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); @@ -355,7 +353,6 @@ void ServiceWorkerContextWatcher::OnControlleeAdded( } void ServiceWorkerContextWatcher::OnControlleeRemoved(int64_t version_id, - const GURL& scope, const std::string& uuid) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); auto it = version_info_map_.find(version_id); diff --git a/chromium/content/browser/service_worker/service_worker_context_watcher.h b/chromium/content/browser/service_worker/service_worker_context_watcher.h index a2f529f5974..41097058874 100644 --- a/chromium/content/browser/service_worker/service_worker_context_watcher.h +++ b/chromium/content/browser/service_worker/service_worker_context_watcher.h @@ -105,11 +105,9 @@ class CONTENT_EXPORT ServiceWorkerContextWatcher void OnReportConsoleMessage(int64_t version_id, const ConsoleMessage& message) override; void OnControlleeAdded(int64_t version_id, - const GURL& scope, const std::string& uuid, const ServiceWorkerClientInfo& info) override; void OnControlleeRemoved(int64_t version_id, - const GURL& scope, const std::string& uuid) override; void OnRegistrationCompleted(int64_t registration_id, const GURL& scope) override; diff --git a/chromium/content/browser/service_worker/service_worker_context_wrapper.cc b/chromium/content/browser/service_worker/service_worker_context_wrapper.cc index 5deb12403ec..9573ca1bd9f 100644 --- a/chromium/content/browser/service_worker/service_worker_context_wrapper.cc +++ b/chromium/content/browser/service_worker/service_worker_context_wrapper.cc @@ -27,10 +27,10 @@ #include "content/browser/loader/navigation_url_loader_impl.h" #include "content/browser/service_worker/embedded_worker_status.h" #include "content/browser/service_worker/service_worker_container_host.h" -#include "content/browser/service_worker/service_worker_context_watcher.h" +#include "content/browser/service_worker/service_worker_host.h" +#include "content/browser/service_worker/service_worker_metrics.h" #include "content/browser/service_worker/service_worker_object_host.h" #include "content/browser/service_worker/service_worker_process_manager.h" -#include "content/browser/service_worker/service_worker_provider_host.h" #include "content/browser/service_worker/service_worker_quota_client.h" #include "content/browser/service_worker/service_worker_version.h" #include "content/browser/storage_partition_impl.h" @@ -45,6 +45,7 @@ #include "content/public/common/content_features.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "net/base/url_util.h" +#include "storage/browser/quota/quota_client_type.h" #include "storage/browser/quota/quota_manager_proxy.h" #include "storage/browser/quota/special_storage_policy.h" #include "third_party/blink/public/common/service_worker/service_worker_status_code.h" @@ -58,8 +59,8 @@ namespace { void WorkerStarted(ServiceWorkerContextWrapper::StatusCallback callback, blink::ServiceWorkerStatusCode status) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - base::PostTask(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(callback), status)); + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), status)); } void StartActiveWorkerOnCoreThread( @@ -76,8 +77,8 @@ void StartActiveWorkerOnCoreThread( base::BindOnce(WorkerStarted, std::move(callback))); return; } - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), blink::ServiceWorkerStatusCode::kErrorNotFound)); } @@ -155,8 +156,8 @@ void FinishRegistrationOnCoreThread( const std::string& status_message, int64_t registration_id) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - base::PostTask(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(callback), + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), status == blink::ServiceWorkerStatusCode::kOk)); } @@ -164,8 +165,8 @@ void FinishUnregistrationOnCoreThread( ServiceWorkerContext::ResultCallback callback, blink::ServiceWorkerStatusCode status) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - base::PostTask(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(callback), + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), status == blink::ServiceWorkerStatusCode::kOk)); } @@ -223,12 +224,6 @@ ServiceWorkerContextWrapper::ServiceWorkerContextWrapper( // Add this object as an observer of the wrapped |context_core_|. This lets us // forward observer methods to observers outside of content. core_observer_list_->AddObserver(this); - - watcher_ = base::MakeRefCounted<ServiceWorkerContextWatcher>( - this, - base::BindRepeating(&ServiceWorkerContextWrapper::OnRegistrationUpdated, - base::Unretained(this)), - base::DoNothing(), base::DoNothing()); } void ServiceWorkerContextWrapper::Init( @@ -268,11 +263,6 @@ void ServiceWorkerContextWrapper::Init( base::RetainedRef(loader_factory_getter), std::move( non_network_pending_loader_factory_bundle_for_update_check))); - - // The watcher also runs or posts a core thread task which must run after - // InitOnCoreThread(), so start it after posting that task above. - if (watcher_) - watcher_->Start(); } void ServiceWorkerContextWrapper::Shutdown() { @@ -280,10 +270,6 @@ void ServiceWorkerContextWrapper::Shutdown() { storage_partition_ = nullptr; process_manager_->Shutdown(); - if (watcher_) { - watcher_->Stop(); - watcher_ = nullptr; - } // Use explicit feature check here instead of RunOrPostTaskOnThread(), since // the feature may be disabled but in unit tests we are considered both on the @@ -292,8 +278,8 @@ void ServiceWorkerContextWrapper::Shutdown() { if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) { ShutdownOnCoreThread(); } else { - base::PostTask( - FROM_HERE, {BrowserThread::IO}, + GetIOThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&ServiceWorkerContextWrapper::ShutdownOnCoreThread, this)); } @@ -364,10 +350,18 @@ void ServiceWorkerContextWrapper::OnRegistrationStored(int64_t registration_id, const GURL& scope) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + registered_origins_.insert(url::Origin::Create(scope.GetOrigin())); + for (auto& observer : observer_list_) observer.OnRegistrationStored(registration_id, scope); } +void ServiceWorkerContextWrapper::OnAllRegistrationsDeletedForOrigin( + const url::Origin& origin) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + registered_origins_.erase(origin); +} + void ServiceWorkerContextWrapper::OnReportConsoleMessage( int64_t version_id, const ConsoleMessage& message) { @@ -377,6 +371,25 @@ void ServiceWorkerContextWrapper::OnReportConsoleMessage( observer.OnReportConsoleMessage(version_id, message); } +void ServiceWorkerContextWrapper::OnControlleeAdded( + int64_t version_id, + const std::string& client_uuid, + const ServiceWorkerClientInfo& client_info) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + for (auto& observer : observer_list_) + observer.OnControlleeAdded(version_id, client_uuid, client_info); +} + +void ServiceWorkerContextWrapper::OnControlleeRemoved( + int64_t version_id, + const std::string& client_uuid) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + for (auto& observer : observer_list_) + observer.OnControlleeRemoved(version_id, client_uuid); +} + void ServiceWorkerContextWrapper::OnNoControllees(int64_t version_id, const GURL& scope) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -385,6 +398,17 @@ void ServiceWorkerContextWrapper::OnNoControllees(int64_t version_id, observer.OnNoControllees(version_id, scope); } +void ServiceWorkerContextWrapper::OnControlleeNavigationCommitted( + int64_t version_id, + const std::string& uuid, + GlobalFrameRoutingId render_frame_host_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + for (auto& observer : observer_list_) + observer.OnControlleeNavigationCommitted(version_id, uuid, + render_frame_host_id); +} + void ServiceWorkerContextWrapper::OnStarted(int64_t version_id, const GURL& scope, int process_id, @@ -463,8 +487,8 @@ void ServiceWorkerContextWrapper::RegisterServiceWorker( return; } if (!context_core_) { - base::PostTask(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(callback), false)); + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), false)); return; } blink::mojom::ServiceWorkerRegistrationOptions options_to_pass( @@ -492,8 +516,8 @@ void ServiceWorkerContextWrapper::UnregisterServiceWorker( return; } if (!context_core_) { - base::PostTask(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(callback), false)); + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), false)); return; } @@ -540,6 +564,32 @@ void ServiceWorkerContextWrapper::CountExternalRequestsForTest( origin, std::move(callback))); } +bool ServiceWorkerContextWrapper::MaybeHasRegistrationForOrigin( + const url::Origin& origin) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!registrations_initialized_) { + return true; + } + if (registered_origins_.find(origin) != registered_origins_.end()) { + return true; + } + return false; +} + +void ServiceWorkerContextWrapper::WaitForRegistrationsInitializedForTest() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (registrations_initialized_) + return; + base::RunLoop loop; + on_registrations_initialized_ = loop.QuitClosure(); + loop.Run(); +} + +void ServiceWorkerContextWrapper::AddRegistrationToRegisteredOriginsForTest( + const url::Origin& origin) { + registered_origins_.insert(origin); +} + void ServiceWorkerContextWrapper::GetAllOriginsInfo( GetUsageInfoCallback callback) { RunOrPostTaskOnCoreThread( @@ -560,7 +610,8 @@ void ServiceWorkerContextWrapper::GetAllOriginsInfoOnCoreThread( } context()->registry()->GetAllRegistrationsInfos(base::BindOnce( &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins, - this, std::move(callback), std::move(callback_runner))); + this, base::TimeTicks::Now(), std::move(callback), + std::move(callback_runner))); } void ServiceWorkerContextWrapper::DeleteForOrigin(const GURL& origin, @@ -631,8 +682,8 @@ void ServiceWorkerContextWrapper::CheckHasServiceWorker( return; } if (!context_core_) { - base::PostTask(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(callback), + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), ServiceWorkerCapability::NO_SERVICE_WORKER)); return; } @@ -653,8 +704,8 @@ void ServiceWorkerContextWrapper::CheckOfflineCapability( return; } if (!context_core_) { - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), OfflineCapability::kUnsupported)); return; } @@ -676,7 +727,7 @@ void ServiceWorkerContextWrapper::ClearAllServiceWorkersForTest( } if (!context_core_) { - base::PostTask(FROM_HERE, {BrowserThread::UI}, std::move(callback)); + GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(callback)); return; } context_core_->ClearAllServiceWorkersForTest(std::move(callback)); @@ -777,7 +828,7 @@ void ServiceWorkerContextWrapper::DidStartServiceWorkerForMessageDispatch( event->message = std::move(message); event->source_origin = url::Origin::Create(source_origin); event->source_info_for_service_worker = - version->provider_host() + version->worker_host() ->container_host() ->GetOrCreateServiceWorkerObjectHost(version) ->CreateCompleteObjectInfoToSend(); @@ -1075,6 +1126,66 @@ void ServiceWorkerContextWrapper::GetAllRegistrationsOnCoreThread( context_core_->registry()->GetAllRegistrationsInfos(std::move(callback)); } +void ServiceWorkerContextWrapper::GetInstalledRegistrationOrigins( + base::Optional<std::string> host_filter, + GetInstalledRegistrationOriginsCallback callback) { + RunOrPostTaskOnCoreThread( + FROM_HERE, base::BindOnce(&ServiceWorkerContextWrapper:: + GetInstalledRegistrationOriginsOnCoreThread, + this, host_filter, std::move(callback), + base::ThreadTaskRunnerHandle::Get())); +} + +void ServiceWorkerContextWrapper::GetInstalledRegistrationOriginsOnCoreThread( + base::Optional<std::string> host_filter, + GetInstalledRegistrationOriginsCallback callback, + scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_callback) { + DCHECK_CURRENTLY_ON(GetCoreThreadId()); + + if (!context_core_) { + task_runner_for_callback->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), std::set<url::Origin>())); + return; + } + + context()->registry()->storage()->GetRegisteredOrigins(base::BindOnce( + &ServiceWorkerContextWrapper:: + DidGetRegisteredOriginsForGetInstalledRegistrationOrigins, + host_filter, std::move(callback), task_runner_for_callback)); +} + +void ServiceWorkerContextWrapper::GetStorageUsageForOrigin( + const url::Origin& origin, + GetStorageUsageForOriginCallback callback) { + RunOrPostTaskOnCoreThread( + FROM_HERE, + base::BindOnce( + &ServiceWorkerContextWrapper::GetStorageUsageForOriginOnCoreThread, + this, origin, + base::BindOnce( + [](GetStorageUsageForOriginCallback callback, + scoped_refptr<base::TaskRunner> callback_runner, + blink::ServiceWorkerStatusCode status, int64_t usage) { + callback_runner->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), status, usage)); + }, + std::move(callback), base::ThreadTaskRunnerHandle::Get()))); +} + +void ServiceWorkerContextWrapper::GetStorageUsageForOriginOnCoreThread( + const url::Origin& origin, + GetStorageUsageForOriginCallback callback) { + DCHECK_CURRENTLY_ON(GetCoreThreadId()); + if (!context_core_) { + std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort, 0); + return; + } + context_core_->registry()->GetStorageUsageForOrigin(origin, + std::move(callback)); +} + void ServiceWorkerContextWrapper::GetRegistrationsForOrigin( const url::Origin& origin, GetRegistrationsCallback callback) { @@ -1176,11 +1287,11 @@ void ServiceWorkerContextWrapper::GetRegistrationUserKeysAndDataByKeyPrefix( base::BindOnce( [](GetUserKeysAndDataCallback callback, scoped_refptr<base::TaskRunner> callback_runner, - const base::flat_map<std::string, std::string>& data_map, - blink::ServiceWorkerStatusCode status) { + blink::ServiceWorkerStatusCode status, + const base::flat_map<std::string, std::string>& data_map) { callback_runner->PostTask( FROM_HERE, - base::BindOnce(std::move(callback), data_map, status)); + base::BindOnce(std::move(callback), status, data_map)); }, std::move(callback), base::ThreadTaskRunnerHandle::Get()))); } @@ -1192,8 +1303,8 @@ void ServiceWorkerContextWrapper:: GetUserKeysAndDataCallback callback) { DCHECK_CURRENTLY_ON(GetCoreThreadId()); if (!context_core_) { - std::move(callback).Run(base::flat_map<std::string, std::string>(), - blink::ServiceWorkerStatusCode::kErrorAbort); + std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort, + base::flat_map<std::string, std::string>()); return; } context_core_->registry()->GetUserKeysAndDataByKeyPrefix( @@ -1412,8 +1523,8 @@ void ServiceWorkerContextWrapper::StartServiceWorker(const GURL& scope, return; } if (!context_core_) { - base::PostTask(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(callback), + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), blink::ServiceWorkerStatusCode::kErrorAbort)); return; } @@ -1504,7 +1615,9 @@ void ServiceWorkerContextWrapper::InitOnCoreThread( if (quota_manager_proxy) { quota_manager_proxy->RegisterClient( - base::MakeRefCounted<ServiceWorkerQuotaClient>(this)); + base::MakeRefCounted<ServiceWorkerQuotaClient>(this), + storage::QuotaClientType::kServiceWorker, + {blink::mojom::StorageType::kTemporary}); } context_core_ = std::make_unique<ServiceWorkerContextCore>( @@ -1512,6 +1625,11 @@ void ServiceWorkerContextWrapper::InitOnCoreThread( special_storage_policy, loader_factory_getter, std::move(non_network_pending_loader_factory_bundle_for_update_check), core_observer_list_.get(), this); + + if (storage_partition_) { + context()->registry()->storage()->GetRegisteredOrigins(base::BindOnce( + &ServiceWorkerContextWrapper::DidGetRegisteredOrigins, this)); + } } void ServiceWorkerContextWrapper::FindRegistrationForScopeOnCoreThread( @@ -1639,6 +1757,7 @@ void ServiceWorkerContextWrapper::DidDeleteAndStartOver( } void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins( + base::TimeTicks start_time, GetUsageInfoCallback callback, scoped_refptr<base::TaskRunner> callback_runner, blink::ServiceWorkerStatusCode status, @@ -1664,6 +1783,10 @@ void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins( for (const auto& origin_info_pair : origins) { usage_infos.push_back(origin_info_pair.second); } + + ServiceWorkerMetrics::RecordGetAllOriginsInfoTime(base::TimeTicks::Now() - + start_time); + callback_runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), usage_infos)); } @@ -1673,16 +1796,16 @@ void ServiceWorkerContextWrapper::DidCheckHasServiceWorker( ServiceWorkerCapability capability) { DCHECK_CURRENTLY_ON(GetCoreThreadId()); - base::PostTask(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(callback), capability)); + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), capability)); } void ServiceWorkerContextWrapper::DidCheckOfflineCapability( CheckOfflineCapabilityCallback callback, OfflineCapability capability) { DCHECK_CURRENTLY_ON(GetCoreThreadId()); - base::PostTask(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(callback), capability)); + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), capability)); } void ServiceWorkerContextWrapper::DidFindRegistrationForUpdate( @@ -1721,8 +1844,8 @@ void ServiceWorkerContextWrapper::CountExternalRequests( } } - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), pending_external_request_count)); } @@ -1802,8 +1925,8 @@ void ServiceWorkerContextWrapper:: StartServiceWorkerForNavigationHintResult result) { DCHECK_CURRENTLY_ON(GetCoreThreadId()); ServiceWorkerMetrics::RecordStartServiceWorkerForNavigationHintResult(result); - base::PostTask(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(callback), result)); + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), result)); } void ServiceWorkerContextWrapper::StopAllServiceWorkersOnCoreThread( @@ -1966,44 +2089,41 @@ void ServiceWorkerContextWrapper::DidSetUpLoaderFactoryForUpdateCheck( std::move(callback).Run(std::move(loader_factory)); } -bool ServiceWorkerContextWrapper::HasRegistrationForOrigin( - const GURL& origin) const { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - return !registrations_initialized_ || - registrations_for_origin_.find(origin) != - registrations_for_origin_.end(); -} - -void ServiceWorkerContextWrapper::WaitForRegistrationsInitializedForTest() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (registrations_initialized_) - return; - base::RunLoop loop; - on_registrations_initialized_ = loop.QuitClosure(); - loop.Run(); +void ServiceWorkerContextWrapper::DidGetRegisteredOrigins( + std::vector<url::Origin> origins) { + DCHECK_CURRENTLY_ON(GetCoreThreadId()); + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, + base::BindOnce( + &ServiceWorkerContextWrapper::InitializeRegisteredOriginsOnUI, this, + std::move(origins))); } -void ServiceWorkerContextWrapper::OnRegistrationUpdated( - const std::vector<ServiceWorkerRegistrationInfo>& registrations) { +void ServiceWorkerContextWrapper::InitializeRegisteredOriginsOnUI( + std::vector<url::Origin> origins) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - // The first call will initialize stored registrations. + registered_origins_.insert(origins.begin(), origins.end()); registrations_initialized_ = true; - - for (const auto& registration : registrations) { - GURL origin = registration.scope.GetOrigin(); - int64_t registration_id = registration.registration_id; - if (registration.delete_flag == ServiceWorkerRegistrationInfo::IS_DELETED) { - auto& registration_ids = registrations_for_origin_[origin]; - registration_ids.erase(registration_id); - if (registration_ids.empty()) - registrations_for_origin_.erase(origin); - } else { - registrations_for_origin_[origin].insert(registration_id); - } - } - if (on_registrations_initialized_) std::move(on_registrations_initialized_).Run(); } +// static +void ServiceWorkerContextWrapper:: + DidGetRegisteredOriginsForGetInstalledRegistrationOrigins( + base::Optional<std::string> host_filter, + GetInstalledRegistrationOriginsCallback callback, + scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_callback, + std::vector<url::Origin> origins) { + std::set<url::Origin> filtered_origins; + for (const auto& origin : origins) { + if (host_filter.has_value() && host_filter.value() != origin.host()) + continue; + filtered_origins.insert(origin); + } + task_runner_for_callback->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), std::move(filtered_origins))); +} + } // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_context_wrapper.h b/chromium/content/browser/service_worker/service_worker_context_wrapper.h index 2b55f068327..d654ff5ac3d 100644 --- a/chromium/content/browser/service_worker/service_worker_context_wrapper.h +++ b/chromium/content/browser/service_worker/service_worker_context_wrapper.h @@ -47,7 +47,6 @@ class BrowserContext; class ChromeBlobStorageContext; class ResourceContext; class ServiceWorkerContextObserver; -class ServiceWorkerContextWatcher; class StoragePartitionImpl; class URLLoaderFactoryGetter; @@ -76,6 +75,10 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper ServiceWorkerRegistry::GetUserKeysAndDataCallback; using GetUserDataForAllRegistrationsCallback = ServiceWorkerRegistry::GetUserDataForAllRegistrationsCallback; + using GetInstalledRegistrationOriginsCallback = + base::OnceCallback<void(const std::set<url::Origin>& origins)>; + using GetStorageUsageForOriginCallback = + ServiceWorkerRegistry::GetStorageUsageForOriginCallback; explicit ServiceWorkerContextWrapper(BrowserContext* browser_context); @@ -123,9 +126,19 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper const GURL& scope) override; void OnRegistrationStored(int64_t registration_id, const GURL& scope) override; + void OnAllRegistrationsDeletedForOrigin(const url::Origin& origin) override; void OnReportConsoleMessage(int64_t version_id, const ConsoleMessage& message) override; + void OnControlleeAdded(int64_t version_id, + const std::string& uuid, + const ServiceWorkerClientInfo& info) override; + void OnControlleeRemoved(int64_t version_id, + const std::string& uuid) override; void OnNoControllees(int64_t version_id, const GURL& scope) override; + void OnControlleeNavigationCommitted( + int64_t version_id, + const std::string& uuid, + GlobalFrameRoutingId render_frame_host_id) override; void OnStarted(int64_t version_id, const GURL& scope, int process_id, @@ -154,6 +167,10 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper void CountExternalRequestsForTest( const GURL& url, CountExternalRequestsCallback callback) override; + bool MaybeHasRegistrationForOrigin(const url::Origin& origin) override; + void WaitForRegistrationsInitializedForTest() override; + void AddRegistrationToRegisteredOriginsForTest( + const url::Origin& origin) override; void GetAllOriginsInfo(GetUsageInfoCallback callback) override; void DeleteForOrigin(const GURL& origin, ResultCallback callback) override; void PerformStorageCleanup(base::OnceClosure callback) override; @@ -295,6 +312,24 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper const std::string& key_prefix, StatusCallback callback); + // Returns a set of origins which have at least one stored registration. + // The set doesn't include installing/uninstalling/uninstalled registrations. + // When |host_filter| is specified the set only includes origins whose host + // matches |host_filter|. + // This function can be called from any thread and the callback is called on + // that thread. + void GetInstalledRegistrationOrigins( + base::Optional<std::string> host_filter, + GetInstalledRegistrationOriginsCallback callback); + + // Returns total resource size stored in the storage for |origin|. + // This can be called from any thread and the callback is called on that + // thread. + void GetStorageUsageForOrigin(const url::Origin& origin, + GetStorageUsageForOriginCallback callback); + + // Returns a list of ServiceWorkerRegistration for |origin|. The list includes + // stored registrations and installing (not stored yet) registrations. // Must be called on the core thread, and the callback is called on that // thread. This restriction is because the callback gets pointers to live // registrations, which live on the core thread. @@ -321,10 +356,6 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper // DeleteAndStartOver fails. ServiceWorkerContextCore* context(); - // Whether |origin| has any registrations. Must be called on UI thread. - bool HasRegistrationForOrigin(const GURL& origin) const; - void WaitForRegistrationsInitializedForTest(); - // This must be called on the core thread, and the |callback| also runs on // the core thread which can be called with nullptr on failure. void GetLoaderFactoryForUpdateCheck( @@ -384,6 +415,7 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper void DidDeleteAndStartOver(blink::ServiceWorkerStatusCode status); void DidGetAllRegistrationsForGetAllOrigins( + base::TimeTicks start_time, GetUsageInfoCallback callback, scoped_refptr<base::TaskRunner> callback_runner, blink::ServiceWorkerStatusCode status, @@ -452,10 +484,17 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper base::OnceCallback<void(scoped_refptr<network::SharedURLLoaderFactory>)> callback); - // Called when the stored registrations are loaded, and each time a new - // service worker is registered. - void OnRegistrationUpdated( - const std::vector<ServiceWorkerRegistrationInfo>& registrations); + // These methods are used as a callback for GetRegisteredOrigins when + // initialising on the core thread, so registered origins can be tracked + // on the UI thread as well. + void DidGetRegisteredOrigins(std::vector<url::Origin> origins); + void InitializeRegisteredOriginsOnUI(std::vector<url::Origin> origins); + + static void DidGetRegisteredOriginsForGetInstalledRegistrationOrigins( + base::Optional<std::string> host_filter, + GetInstalledRegistrationOriginsCallback callback, + scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_callback, + std::vector<url::Origin> origins); // Temporary for crbug.com/824858. void GetAllOriginsInfoOnCoreThread( @@ -535,6 +574,13 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper void StopAllServiceWorkersOnCoreThread( base::OnceClosure callback, scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_callback); + void GetInstalledRegistrationOriginsOnCoreThread( + base::Optional<std::string> host_filter, + GetInstalledRegistrationOriginsCallback callback, + scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_callback); + void GetStorageUsageForOriginOnCoreThread( + const url::Origin& origin, + GetStorageUsageForOriginCallback callback); // Observers of |context_core_| which live within content's implementation // boundary. Shared with |context_core_|. @@ -566,16 +612,14 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper base::flat_map<int64_t /* version_id */, ServiceWorkerRunningInfo> running_service_workers_; - // Maps the origin to a set of registration ids for that origin. Must be - // accessed on UI thread. + // A set of origins that have at least one registration. See + // HasRegistrationForOrigin() for details. Must be accessed on the UI thread. // TODO(http://crbug.com/824858): This can be removed when service workers are // fully converted to running on the UI thread. - base::flat_map<GURL, base::flat_set<int64_t>> registrations_for_origin_; + std::set<url::Origin> registered_origins_; bool registrations_initialized_ = false; base::OnceClosure on_registrations_initialized_; - scoped_refptr<ServiceWorkerContextWatcher> watcher_; - // Temporary for moving context core to the UI thread. scoped_refptr<base::TaskRunner> core_thread_task_runner_; diff --git a/chromium/content/browser/service_worker/service_worker_context_wrapper_unittest.cc b/chromium/content/browser/service_worker/service_worker_context_wrapper_unittest.cc index 10624f2b307..5551d917b76 100644 --- a/chromium/content/browser/service_worker/service_worker_context_wrapper_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_context_wrapper_unittest.cc @@ -62,6 +62,48 @@ class ServiceWorkerContextWrapperTest : public testing::Test { ServiceWorkerRegistry* registry() { return context()->registry(); } ServiceWorkerStorage* storage() { return context()->storage(); } + blink::ServiceWorkerStatusCode StoreRegistration( + scoped_refptr<ServiceWorkerRegistration> registration) { + blink::ServiceWorkerStatusCode result; + base::RunLoop loop; + registry()->StoreRegistration( + registration.get(), registration->waiting_version(), + base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { + result = status; + loop.Quit(); + })); + loop.Run(); + return result; + } + + blink::ServiceWorkerStatusCode DeleteRegistration( + scoped_refptr<ServiceWorkerRegistration> registration) { + blink::ServiceWorkerStatusCode result; + base::RunLoop loop; + registry()->DeleteRegistration( + registration, registration->scope().GetOrigin(), + base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { + result = status; + loop.Quit(); + })); + loop.Run(); + return result; + } + + std::set<url::Origin> GetInstalledRegistrationOrigins( + base::Optional<std::string> host_filter) { + std::set<url::Origin> result; + base::RunLoop loop; + wrapper_->GetInstalledRegistrationOrigins( + host_filter, + base::BindLambdaForTesting([&](const std::set<url::Origin>& origins) { + result = origins; + loop.Quit(); + })); + loop.Run(); + return result; + } + protected: BrowserTaskEnvironment task_environment_{BrowserTaskEnvironment::IO_MAINLOOP}; base::ScopedTempDir user_data_directory_; @@ -102,8 +144,279 @@ TEST_F(ServiceWorkerContextWrapperTest, HasRegistration) { // Now test that registrations are recognized. wrapper_->WaitForRegistrationsInitializedForTest(); - EXPECT_TRUE(wrapper_->HasRegistrationForOrigin(GURL("https://example.com"))); - EXPECT_FALSE(wrapper_->HasRegistrationForOrigin(GURL("https://example.org"))); + EXPECT_TRUE(wrapper_->MaybeHasRegistrationForOrigin( + url::Origin::Create(GURL("https://example.com")))); + EXPECT_FALSE(wrapper_->MaybeHasRegistrationForOrigin( + url::Origin::Create(GURL("https://example.org")))); +} + +// This test involves storing two registrations for the same origin to storage +// and deleting one of them to check that MaybeHasRegistrationForOrigin still +// correctly returns TRUE since there is still one registration for the origin, +// and should only return FALSE when ALL registrations for that origin have been +// deleted from storage. +TEST_F(ServiceWorkerContextWrapperTest, DeleteRegistrationsForSameOrigin) { + wrapper_->WaitForRegistrationsInitializedForTest(); + + // Make two registrations for same origin. + GURL scope1("https://example1.com/abc/"); + GURL script1("https://example1.com/abc/sw.js"); + scoped_refptr<ServiceWorkerRegistration> registration1 = + CreateServiceWorkerRegistrationAndVersion(context(), scope1, script1, + /*resource_id=*/1); + GURL scope2("https://example1.com/xyz/"); + GURL script2("https://example1.com/xyz/sw.js"); + scoped_refptr<ServiceWorkerRegistration> registration2 = + CreateServiceWorkerRegistrationAndVersion(context(), scope2, script2, 1); + + // Store both registrations. + ASSERT_EQ(StoreRegistration(registration1), + blink::ServiceWorkerStatusCode::kOk); + ASSERT_EQ(StoreRegistration(registration2), + blink::ServiceWorkerStatusCode::kOk); + + // Delete one of the registrations. + ASSERT_EQ(DeleteRegistration(registration1), + blink::ServiceWorkerStatusCode::kOk); + + // Run loop until idle to wait for + // ServiceWorkerRegistry::DidDeleteRegistration() to be executed, and make + // sure that NotifyAllRegistrationsDeletedForOrigin() is not called. + base::RunLoop().RunUntilIdle(); + + // Now test that a registration for an origin is still recognized. + EXPECT_TRUE(wrapper_->MaybeHasRegistrationForOrigin( + url::Origin::Create(GURL("https://example1.com")))); + + // Remove second registration. + ASSERT_EQ(DeleteRegistration(registration2), + blink::ServiceWorkerStatusCode::kOk); + + // Run loop until idle to wait for + // ServiceWorkerRegistry::DidDeleteRegistration() to be executed, and make + // sure that this time NotifyAllRegistrationsDeletedForOrigin() is called. + base::RunLoop().RunUntilIdle(); + + // Now test that origin does not have any registrations. + EXPECT_FALSE(wrapper_->MaybeHasRegistrationForOrigin( + url::Origin::Create(GURL("https://example1.com")))); +} + +// This tests deleting registrations from storage and checking that even if live +// registrations may exist, MaybeHasRegistrationForOrigin correctly returns +// FALSE since the registrations do not exist in storage. +TEST_F(ServiceWorkerContextWrapperTest, DeleteRegistration) { + wrapper_->WaitForRegistrationsInitializedForTest(); + + // Make registration. + GURL scope1("https://example2.com/"); + GURL script1("https://example2.com/"); + scoped_refptr<ServiceWorkerRegistration> registration = + CreateServiceWorkerRegistrationAndVersion(context(), scope1, script1, + /*resource_id=*/1); + + // Store registration. + ASSERT_EQ(StoreRegistration(registration), + blink::ServiceWorkerStatusCode::kOk); + + wrapper_->OnRegistrationCompleted(registration->id(), registration->scope()); + base::RunLoop().RunUntilIdle(); + + // Now test that a registration is recognized. + EXPECT_TRUE(wrapper_->MaybeHasRegistrationForOrigin( + url::Origin::Create(GURL("https://example2.com")))); + + // Delete registration from storage. + ASSERT_EQ(DeleteRegistration(registration), + blink::ServiceWorkerStatusCode::kOk); + + // Finish deleting registration from storage. + base::RunLoop().RunUntilIdle(); + + // Now test that origin does not have any registrations. This should return + // FALSE even when live registrations may exist, as the registrations have + // been deleted from storage. + EXPECT_FALSE(wrapper_->MaybeHasRegistrationForOrigin( + url::Origin::Create(GURL("https://example2.com")))); +} + +// GetInstalledRegistrationOrigins tests: + +// No registration. +TEST_F(ServiceWorkerContextWrapperTest, GetInstalledRegistrationOrigins_Empty) { + wrapper_->WaitForRegistrationsInitializedForTest(); + + // No registration stored yet. + std::set<url::Origin> registered_origins = + GetInstalledRegistrationOrigins(base::nullopt); + EXPECT_EQ(registered_origins.size(), 0UL); +} + +// On registration. +TEST_F(ServiceWorkerContextWrapperTest, GetInstalledRegistrationOrigins_One) { + const GURL scope("https://example.com/"); + const GURL script("https://example.com/sw.js"); + const url::Origin origin = url::Origin::Create(scope.GetOrigin()); + + wrapper_->WaitForRegistrationsInitializedForTest(); + scoped_refptr<ServiceWorkerRegistration> registration = + CreateServiceWorkerRegistrationAndVersion(context(), scope, script, + /*resource_id=*/1); + ASSERT_EQ(StoreRegistration(registration), + blink::ServiceWorkerStatusCode::kOk); + base::RunLoop().RunUntilIdle(); + + std::set<url::Origin> installed_origins = + GetInstalledRegistrationOrigins(base::nullopt); + ASSERT_EQ(installed_origins.size(), 1UL); + EXPECT_EQ(*installed_origins.begin(), origin); +} + +// Two registrations from the same origin. +TEST_F(ServiceWorkerContextWrapperTest, + GetInstalledRegistrationOrigins_SameOrigin) { + const GURL scope1("https://example.com/foo"); + const GURL script1("https://example.com/foo/sw.js"); + const url::Origin origin = url::Origin::Create(scope1.GetOrigin()); + const GURL scope2("https://example.com/bar"); + const GURL script2("https://example.com/bar/sw.js"); + + wrapper_->WaitForRegistrationsInitializedForTest(); + + scoped_refptr<ServiceWorkerRegistration> registration1 = + CreateServiceWorkerRegistrationAndVersion(context(), scope1, script1, + /*resource_id=*/1); + ASSERT_EQ(StoreRegistration(registration1), + blink::ServiceWorkerStatusCode::kOk); + scoped_refptr<ServiceWorkerRegistration> registration2 = + CreateServiceWorkerRegistrationAndVersion(context(), scope2, script2, + /*resource_id=*/2); + ASSERT_EQ(StoreRegistration(registration2), + blink::ServiceWorkerStatusCode::kOk); + base::RunLoop().RunUntilIdle(); + + std::set<url::Origin> installed_origins = + GetInstalledRegistrationOrigins(base::nullopt); + ASSERT_EQ(installed_origins.size(), 1UL); + EXPECT_EQ(*installed_origins.begin(), origin); +} + +// Two registrations from different origins. +TEST_F(ServiceWorkerContextWrapperTest, + GetInstalledRegistrationOrigins_DifferentOrigin) { + const GURL scope1("https://example1.com/foo"); + const GURL script1("https://example1.com/foo/sw.js"); + const url::Origin origin1 = url::Origin::Create(scope1.GetOrigin()); + const GURL scope2("https://example2.com/bar"); + const GURL script2("https://example2.com/bar/sw.js"); + const url::Origin origin2 = url::Origin::Create(scope2.GetOrigin()); + + wrapper_->WaitForRegistrationsInitializedForTest(); + + scoped_refptr<ServiceWorkerRegistration> registration1 = + CreateServiceWorkerRegistrationAndVersion(context(), scope1, script1, + /*resource_id=*/1); + ASSERT_EQ(StoreRegistration(registration1), + blink::ServiceWorkerStatusCode::kOk); + scoped_refptr<ServiceWorkerRegistration> registration2 = + CreateServiceWorkerRegistrationAndVersion(context(), scope2, script2, + /*resource_id=*/2); + ASSERT_EQ(StoreRegistration(registration2), + blink::ServiceWorkerStatusCode::kOk); + base::RunLoop().RunUntilIdle(); + + std::set<url::Origin> installed_origins = + GetInstalledRegistrationOrigins(base::nullopt); + ASSERT_EQ(installed_origins.size(), 2UL); + EXPECT_TRUE(base::Contains(installed_origins, origin1)); + EXPECT_TRUE(base::Contains(installed_origins, origin2)); +} + +// One registration, host filter matches it. +TEST_F(ServiceWorkerContextWrapperTest, + GetInstalledRegistrationOrigins_HostFilterMatch) { + const GURL scope("https://example.com/"); + const GURL script("https://example.com/sw.js"); + const url::Origin origin = url::Origin::Create(scope.GetOrigin()); + + wrapper_->WaitForRegistrationsInitializedForTest(); + scoped_refptr<ServiceWorkerRegistration> registration = + CreateServiceWorkerRegistrationAndVersion(context(), scope, script, + /*resource_id=*/1); + ASSERT_EQ(StoreRegistration(registration), + blink::ServiceWorkerStatusCode::kOk); + base::RunLoop().RunUntilIdle(); + + std::set<url::Origin> installed_origins = + GetInstalledRegistrationOrigins("example.com"); + ASSERT_EQ(installed_origins.size(), 1UL); + EXPECT_EQ(*installed_origins.begin(), origin); +} + +// One registration, host filter does not match it. +TEST_F(ServiceWorkerContextWrapperTest, + GetInstalledRegistrationOrigins_HostFilterNoMatch) { + const GURL scope("https://example.com/"); + const GURL script("https://example.com/sw.js"); + const url::Origin origin = url::Origin::Create(scope.GetOrigin()); + + wrapper_->WaitForRegistrationsInitializedForTest(); + scoped_refptr<ServiceWorkerRegistration> registration = + CreateServiceWorkerRegistrationAndVersion(context(), scope, script, + /*resource_id=*/1); + ASSERT_EQ(StoreRegistration(registration), + blink::ServiceWorkerStatusCode::kOk); + base::RunLoop().RunUntilIdle(); + + std::set<url::Origin> installed_origins = + GetInstalledRegistrationOrigins("example.test"); + EXPECT_EQ(installed_origins.size(), 0UL); +} + +// Two registrations, one is deleted, only the other one is returned. +TEST_F(ServiceWorkerContextWrapperTest, + GetInstalledRegistrationOrigins_DeletedRegistration) { + const GURL scope1("https://example1.com/foo"); + const GURL script1("https://example1.com/foo/sw.js"); + const url::Origin origin1 = url::Origin::Create(scope1.GetOrigin()); + const GURL scope2("https://example2.com/bar"); + const GURL script2("https://example2.com/bar/sw.js"); + const url::Origin origin2 = url::Origin::Create(scope2.GetOrigin()); + + wrapper_->WaitForRegistrationsInitializedForTest(); + + scoped_refptr<ServiceWorkerRegistration> registration1 = + CreateServiceWorkerRegistrationAndVersion(context(), scope1, script1, + /*resource_id=*/1); + ASSERT_EQ(StoreRegistration(registration1), + blink::ServiceWorkerStatusCode::kOk); + scoped_refptr<ServiceWorkerRegistration> registration2 = + CreateServiceWorkerRegistrationAndVersion(context(), scope2, script2, + /*resource_id=*/2); + ASSERT_EQ(StoreRegistration(registration2), + blink::ServiceWorkerStatusCode::kOk); + base::RunLoop().RunUntilIdle(); + + { + std::set<url::Origin> installed_origins = + GetInstalledRegistrationOrigins(base::nullopt); + ASSERT_EQ(installed_origins.size(), 2UL); + EXPECT_TRUE(base::Contains(installed_origins, origin1)); + EXPECT_TRUE(base::Contains(installed_origins, origin2)); + } + + // Delete |registration2|. + ASSERT_EQ(DeleteRegistration(registration2), + blink::ServiceWorkerStatusCode::kOk); + base::RunLoop().RunUntilIdle(); + + // After |registration2| is deleted, only |origin1| should be returned. + { + std::set<url::Origin> installed_origins = + GetInstalledRegistrationOrigins(base::nullopt); + ASSERT_EQ(installed_origins.size(), 1UL); + EXPECT_EQ(*installed_origins.begin(), origin1); + } } } // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc b/chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc index 679d926f14e..e2c6c9759ee 100644 --- a/chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc +++ b/chromium/content/browser/service_worker/service_worker_controllee_request_handler.cc @@ -16,8 +16,8 @@ #include "content/browser/service_worker/service_worker_container_host.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_main_resource_loader.h" #include "content/browser/service_worker/service_worker_metrics.h" -#include "content/browser/service_worker/service_worker_navigation_loader.h" #include "content/browser/service_worker/service_worker_object_host.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/common/service_worker/service_worker_utils.h" @@ -471,9 +471,9 @@ void ServiceWorkerControlleeRequestHandler::ContinueWithActivatedVersion( } // Finally, we want to forward to the service worker! Make a - // ServiceWorkerNavigationLoader which does that work. - loader_wrapper_ = std::make_unique<ServiceWorkerNavigationLoaderWrapper>( - std::make_unique<ServiceWorkerNavigationLoader>( + // ServiceWorkerMainResourceLoader which does that work. + loader_wrapper_ = std::make_unique<ServiceWorkerMainResourceLoaderWrapper>( + std::make_unique<ServiceWorkerMainResourceLoader>( std::move(fallback_callback_), container_host_, base::WrapRefCounted(context_->loader_factory_getter()))); @@ -484,7 +484,7 @@ void ServiceWorkerControlleeRequestHandler::ContinueWithActivatedVersion( TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "Info", "Forwarded to the ServiceWorker"); std::move(loader_callback_) - .Run(base::BindOnce(&ServiceWorkerNavigationLoader::StartRequest, + .Run(base::BindOnce(&ServiceWorkerMainResourceLoader::StartRequest, loader_wrapper_->get()->AsWeakPtr())); } diff --git a/chromium/content/browser/service_worker/service_worker_controllee_request_handler.h b/chromium/content/browser/service_worker/service_worker_controllee_request_handler.h index fe3b8be1ddd..bb32752f5bf 100644 --- a/chromium/content/browser/service_worker/service_worker_controllee_request_handler.h +++ b/chromium/content/browser/service_worker/service_worker_controllee_request_handler.h @@ -17,7 +17,7 @@ #include "base/time/time.h" #include "content/browser/loader/single_request_url_loader_factory.h" #include "content/browser/service_worker/service_worker_accessed_callback.h" -#include "content/browser/service_worker/service_worker_navigation_loader.h" +#include "content/browser/service_worker/service_worker_main_resource_loader.h" #include "content/common/content_export.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/mojom/fetch_api.mojom.h" @@ -36,7 +36,7 @@ class ServiceWorkerVersion; // Handles main resource requests for service worker clients (documents and // shared workers). // -// TODO(crbug.com/824858): Merge into ServiceWorkerNavigationLoaderInterceptor +// TODO(crbug.com/824858): Merge into ServiceWorkerMainResourceLoaderInterceptor // after the service worker core thread changes to the UI thread. class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler final { public: @@ -71,7 +71,7 @@ class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler final { const network::ResourceRequest& tentative_request); // Exposed for testing. - ServiceWorkerNavigationLoader* loader() { + ServiceWorkerMainResourceLoader* loader() { return loader_wrapper_ ? loader_wrapper_->get() : nullptr; } @@ -113,7 +113,7 @@ class CONTENT_EXPORT ServiceWorkerControlleeRequestHandler final { // If true, service workers are bypassed for request interception. const bool skip_service_worker_; - std::unique_ptr<ServiceWorkerNavigationLoaderWrapper> loader_wrapper_; + std::unique_ptr<ServiceWorkerMainResourceLoaderWrapper> loader_wrapper_; BrowserContext* browser_context_; ResourceContext* resource_context_; GURL stripped_url_; diff --git a/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc index bd1151b1658..1c70031bb17 100644 --- a/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc @@ -19,7 +19,7 @@ #include "content/browser/service_worker/service_worker_container_host.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_provider_host.h" +#include "content/browser/service_worker/service_worker_host.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_test_utils.h" #include "content/public/browser/resource_context.h" @@ -70,7 +70,7 @@ class ServiceWorkerControlleeRequestHandlerTest : public testing::Test { base::DoNothing(), base::DoNothing()); } - ServiceWorkerNavigationLoader* loader() { return handler_->loader(); } + ServiceWorkerMainResourceLoader* loader() { return handler_->loader(); } void SetHandler( std::unique_ptr<ServiceWorkerControlleeRequestHandler> handler) { @@ -145,7 +145,7 @@ class ServiceWorkerControlleeRequestHandlerTest : public testing::Test { net::TestDelegate url_request_delegate_; GURL scope_; GURL script_url_; - std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints_; + std::vector<ServiceWorkerRemoteContainerEndpoint> remote_endpoints_; }; class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient { diff --git a/chromium/content/browser/service_worker/service_worker_database.cc b/chromium/content/browser/service_worker/service_worker_database.cc index 54323ba4897..19f04328c7e 100644 --- a/chromium/content/browser/service_worker/service_worker_database.cc +++ b/chromium/content/browser/service_worker/service_worker_database.cc @@ -5,6 +5,7 @@ #include "content/browser/service_worker/service_worker_database.h" #include "base/command_line.h" +#include "base/debug/crash_logging.h" #include "base/files/file_util.h" #include "base/location.h" #include "base/logging.h" @@ -448,9 +449,58 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetRegistrationsForOrigin( return status; } +ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetUsageForOrigin( + const url::Origin& origin, + int64_t& out_usage) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + out_usage = 0; + + Status status = LazyOpen(false); + if (IsNewOrNonexistentDatabase(status)) + return Status::kOk; + if (status != Status::kOk) + return status; + + std::string prefix = CreateRegistrationKeyPrefix(origin.GetURL()); + + // Read all registrations. + { + std::unique_ptr<leveldb::Iterator> itr( + db_->NewIterator(leveldb::ReadOptions())); + for (itr->Seek(prefix); itr->Valid(); itr->Next()) { + status = LevelDBStatusToServiceWorkerDBStatus(itr->status()); + if (status != Status::kOk) + break; + + if (!RemovePrefix(itr->key().ToString(), prefix, nullptr)) + break; + + storage::mojom::ServiceWorkerRegistrationDataPtr registration; + status = ParseRegistrationData(itr->value().ToString(), ®istration); + if (status != Status::kOk) + break; + out_usage += registration->resources_total_size_bytes; + } + } + + // Count reading all registrations as one "read operation" for UMA + // purposes. + HandleReadResult(FROM_HERE, status); + if (status != Status::kOk) { + out_usage = 0; + } + + return status; +} + ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetAllRegistrations( std::vector<storage::mojom::ServiceWorkerRegistrationDataPtr>* registrations) { + static base::debug::CrashKeyString* crash_key = + base::debug::AllocateCrashKeyString("num_registrations", + base::debug::CrashKeySize::Size32); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(registrations->empty()); @@ -465,6 +515,9 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetAllRegistrations( db_->NewIterator(leveldb::ReadOptions())); for (itr->Seek(service_worker_internals::kRegKeyPrefix); itr->Valid(); itr->Next()) { + base::debug::ScopedCrashKeyString num_registrations_crash( + crash_key, base::NumberToString(registrations->size())); + status = LevelDBStatusToServiceWorkerDBStatus(itr->status()); if (status != Status::kOk) { registrations->clear(); @@ -484,7 +537,8 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetAllRegistrations( registrations->push_back(std::move(registration)); } } - + UMA_HISTOGRAM_COUNTS_10000("ServiceWorker.RegistrationCount", + registrations->size()); HandleReadResult(FROM_HERE, status); return status; } @@ -1221,7 +1275,7 @@ ServiceWorkerDatabase::DeleteUserDataForAllRegistrationsByKeyPrefix( } ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetUncommittedResourceIds( - std::set<int64_t>* ids) { + std::vector<int64_t>* ids) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return ReadResourceIds(service_worker_internals::kUncommittedResIdKeyPrefix, ids); @@ -1229,7 +1283,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetUncommittedResourceIds( ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteUncommittedResourceIds( - const std::set<int64_t>& ids) { + const std::vector<int64_t>& ids) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); leveldb::WriteBatch batch; Status status = WriteResourceIdsInBatch( @@ -1240,14 +1294,14 @@ ServiceWorkerDatabase::WriteUncommittedResourceIds( } ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetPurgeableResourceIds( - std::set<int64_t>* ids) { + std::vector<int64_t>* ids) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return ReadResourceIds(service_worker_internals::kPurgeableResIdKeyPrefix, ids); } ServiceWorkerDatabase::Status ServiceWorkerDatabase::ClearPurgeableResourceIds( - const std::set<int64_t>& ids) { + const std::vector<int64_t>& ids) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); Status status = LazyOpen(false); if (IsNewOrNonexistentDatabase(status)) @@ -1263,7 +1317,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ClearPurgeableResourceIds( ServiceWorkerDatabase::Status ServiceWorkerDatabase::PurgeUncommittedResourceIds( - const std::set<int64_t>& ids) { + const std::vector<int64_t>& ids) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); Status status = LazyOpen(false); if (IsNewOrNonexistentDatabase(status)) @@ -1815,7 +1869,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteResourceRecords( ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadResourceIds( const char* id_key_prefix, - std::set<int64_t>* ids) { + std::vector<int64_t>* ids) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(id_key_prefix); DCHECK(ids->empty()); @@ -1827,12 +1881,13 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadResourceIds( return status; { + std::set<int64_t> unique_ids; std::unique_ptr<leveldb::Iterator> itr( db_->NewIterator(leveldb::ReadOptions())); for (itr->Seek(id_key_prefix); itr->Valid(); itr->Next()) { status = LevelDBStatusToServiceWorkerDBStatus(itr->status()); if (status != Status::kOk) { - ids->clear(); + unique_ids.clear(); break; } @@ -1843,11 +1898,12 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadResourceIds( int64_t resource_id; status = ParseId(unprefixed, &resource_id); if (status != Status::kOk) { - ids->clear(); + unique_ids.clear(); break; } - ids->insert(resource_id); + unique_ids.insert(resource_id); } + *ids = std::vector<int64_t>(unique_ids.begin(), unique_ids.end()); } HandleReadResult(FROM_HERE, status); @@ -1856,7 +1912,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadResourceIds( ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteResourceIdsInBatch( const char* id_key_prefix, - const std::set<int64_t>& ids, + const std::vector<int64_t>& ids, leveldb::WriteBatch* batch) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(id_key_prefix); @@ -1878,7 +1934,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteResourceIdsInBatch( ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteResourceIdsInBatch( const char* id_key_prefix, - const std::set<int64_t>& ids, + const std::vector<int64_t>& ids, leveldb::WriteBatch* batch) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(id_key_prefix); diff --git a/chromium/content/browser/service_worker/service_worker_database.h b/chromium/content/browser/service_worker/service_worker_database.h index 286a4286f7a..dd3058fbcfd 100644 --- a/chromium/content/browser/service_worker/service_worker_database.h +++ b/chromium/content/browser/service_worker/service_worker_database.h @@ -96,6 +96,9 @@ class CONTENT_EXPORT ServiceWorkerDatabase { std::vector<std::vector<storage::mojom::ServiceWorkerResourceRecordPtr>>* opt_resources_list); + // Reads the total resource size stored in the database for |origin|. + Status GetUsageForOrigin(const url::Origin& origin, int64_t& out_usage); + // Reads all registrations from the database. Returns OK if successfully read // or not found. Otherwise, returns an error. Status GetAllRegistrations( @@ -240,24 +243,24 @@ class CONTENT_EXPORT ServiceWorkerDatabase { // Reads resource ids from the uncommitted list. Returns OK on success. // Otherwise clears |ids| and returns an error. - Status GetUncommittedResourceIds(std::set<int64_t>* ids); + Status GetUncommittedResourceIds(std::vector<int64_t>* ids); // Writes resource ids into the uncommitted list. Returns OK on success. // Otherwise writes nothing and returns an error. - Status WriteUncommittedResourceIds(const std::set<int64_t>& ids); + Status WriteUncommittedResourceIds(const std::vector<int64_t>& ids); // Reads resource ids from the purgeable list. Returns OK on success. // Otherwise clears |ids| and returns an error. - Status GetPurgeableResourceIds(std::set<int64_t>* ids); + Status GetPurgeableResourceIds(std::vector<int64_t>* ids); // Deletes resource ids from the purgeable list. Returns OK on success. // Otherwise deletes nothing and returns an error. - Status ClearPurgeableResourceIds(const std::set<int64_t>& ids); + Status ClearPurgeableResourceIds(const std::vector<int64_t>& ids); // Writes resource ids into the purgeable list and removes them from the // uncommitted list. Returns OK on success. Otherwise writes nothing and // returns an error. - Status PurgeUncommittedResourceIds(const std::set<int64_t>& ids); + Status PurgeUncommittedResourceIds(const std::vector<int64_t>& ids); // Deletes all data for |origins|, namely, unique origin, registrations and // resource records. Resources are moved to the purgeable list. Returns OK if @@ -333,19 +336,19 @@ class CONTENT_EXPORT ServiceWorkerDatabase { // Reads resource ids for |id_key_prefix| from the database. Returns OK if // it's successfully read or not found in the database. Otherwise, returns an // error. - Status ReadResourceIds(const char* id_key_prefix, std::set<int64_t>* ids); + Status ReadResourceIds(const char* id_key_prefix, std::vector<int64_t>* ids); // Write resource ids for |id_key_prefix| into the database. Returns OK on // success. Otherwise, returns writes nothing and returns an error. Status WriteResourceIdsInBatch(const char* id_key_prefix, - const std::set<int64_t>& ids, + const std::vector<int64_t>& ids, leveldb::WriteBatch* batch); // Deletes resource ids for |id_key_prefix| from the database. Returns OK if // it's successfully deleted or not found in the database. Otherwise, returns // an error. Status DeleteResourceIdsInBatch(const char* id_key_prefix, - const std::set<int64_t>& ids, + const std::vector<int64_t>& ids, leveldb::WriteBatch* batch); // Deletes all user data for |registration_id| from the database. Returns OK diff --git a/chromium/content/browser/service_worker/service_worker_database_unittest.cc b/chromium/content/browser/service_worker/service_worker_database_unittest.cc index 2595362644b..7f5c03feeae 100644 --- a/chromium/content/browser/service_worker/service_worker_database_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_database_unittest.cc @@ -276,11 +276,9 @@ TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) { EXPECT_EQ(0, ids.res_id); // Writing uncommitted resources bumps the next available resource id. - const int64_t kUncommittedIds[] = {0, 1, 3, 5, 6, 10}; - EXPECT_EQ( - ServiceWorkerDatabase::Status::kOk, - database->WriteUncommittedResourceIds(std::set<int64_t>( - kUncommittedIds, kUncommittedIds + base::size(kUncommittedIds)))); + const std::vector<int64_t> kUncommittedIds = {0, 1, 3, 5, 6, 10}; + EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, + database->WriteUncommittedResourceIds(kUncommittedIds)); EXPECT_EQ( ServiceWorkerDatabase::Status::kOk, database->GetNextAvailableIds(&ids.reg_id, &ids.ver_id, &ids.res_id)); @@ -289,10 +287,9 @@ TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) { EXPECT_EQ(11, ids.res_id); // Writing purgeable resources bumps the next available id. - const int64_t kPurgeableIds[] = {4, 12, 16, 17, 20}; + const std::vector<int64_t> kPurgeableIds = {4, 12, 16, 17, 20}; EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, - database->WriteUncommittedResourceIds(std::set<int64_t>( - kPurgeableIds, kPurgeableIds + base::size(kPurgeableIds)))); + database->WriteUncommittedResourceIds(kPurgeableIds)); EXPECT_EQ( ServiceWorkerDatabase::Status::kOk, database->GetNextAvailableIds(&ids.reg_id, &ids.ver_id, &ids.res_id)); @@ -336,9 +333,9 @@ TEST(ServiceWorkerDatabaseTest, GetNextAvailableIds) { // Same with resources. int64_t kLowResourceId = 15; + std::vector<int64_t> resource_ids = {kLowResourceId}; EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, - database->WriteUncommittedResourceIds( - std::set<int64_t>(&kLowResourceId, &kLowResourceId + 1))); + database->WriteUncommittedResourceIds(resource_ids)); // Close and reopen the database to verify the stored values. database.reset(CreateDatabase(database_dir.GetPath())); @@ -651,11 +648,11 @@ TEST(ServiceWorkerDatabaseTest, Registration_Basic) { // Write a resource to the uncommitted list to make sure that writing // registration removes resource ids associated with the registration from // the uncommitted list. - std::set<int64_t> uncommitted_ids; - uncommitted_ids.insert(resources[0]->resource_id); + std::vector<int64_t> uncommitted_ids; + uncommitted_ids.push_back(resources[0]->resource_id); EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, database->WriteUncommittedResourceIds(uncommitted_ids)); - std::set<int64_t> uncommitted_ids_out; + std::vector<int64_t> uncommitted_ids_out; EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, database->GetUncommittedResourceIds(&uncommitted_ids_out)); EXPECT_EQ(uncommitted_ids, uncommitted_ids_out); @@ -709,7 +706,7 @@ TEST(ServiceWorkerDatabaseTest, Registration_Basic) { database->ReadRegistrationOrigin(data.registration_id, &origin_out)); // Resources should be purgeable because these are no longer referred. - std::set<int64_t> purgeable_ids_out; + std::vector<int64_t> purgeable_ids_out; EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, database->GetPurgeableResourceIds(&purgeable_ids_out)); EXPECT_EQ(2u, purgeable_ids_out.size()); @@ -836,7 +833,7 @@ TEST(ServiceWorkerDatabaseTest, Registration_Overwrite) { VerifyRegistrationData(*updated_data, *data_out); VerifyResourceRecords(resources2, resources_out); - std::set<int64_t> purgeable_ids_out; + std::vector<int64_t> purgeable_ids_out; EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, database->GetPurgeableResourceIds(&purgeable_ids_out)); EXPECT_EQ(2u, purgeable_ids_out.size()); @@ -904,7 +901,7 @@ TEST(ServiceWorkerDatabaseTest, Registration_Multiple) { database->ReadRegistrationOrigin(data2.registration_id, &origin_out)); EXPECT_EQ(origin, origin_out); - std::set<int64_t> purgeable_ids_out; + std::vector<int64_t> purgeable_ids_out; EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, database->GetPurgeableResourceIds(&purgeable_ids_out)); EXPECT_TRUE(purgeable_ids_out.empty()); @@ -1863,29 +1860,24 @@ TEST(ServiceWorkerDatabaseTest, UncommittedAndPurgeableResourceIds) { std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); // Write {1, 2, 3} into the uncommitted list. - std::set<int64_t> ids1; - ids1.insert(1); - ids1.insert(2); - ids1.insert(3); + std::vector<int64_t> ids1 = {1, 2, 3}; EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, database->WriteUncommittedResourceIds(ids1)); - std::set<int64_t> ids_out; + std::vector<int64_t> ids_out; EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, database->GetUncommittedResourceIds(&ids_out)); EXPECT_EQ(ids1, ids_out); // Write {2, 4} into the uncommitted list. - std::set<int64_t> ids2; - ids2.insert(2); - ids2.insert(4); + std::vector<int64_t> ids2 = {2, 4}; EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, database->WriteUncommittedResourceIds(ids2)); ids_out.clear(); EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, database->GetUncommittedResourceIds(&ids_out)); - std::set<int64_t> expected = base::STLSetUnion<std::set<int64_t>>(ids1, ids2); + std::vector<int64_t> expected = {1, 2, 3, 4}; EXPECT_EQ(expected, ids_out); // Move {2, 4} from the uncommitted list to the purgeable list. @@ -1908,7 +1900,7 @@ TEST(ServiceWorkerDatabaseTest, UncommittedAndPurgeableResourceIds) { ids_out.clear(); EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, database->GetUncommittedResourceIds(&ids_out)); - expected = base::STLSetDifference<std::set<int64_t>>(ids1, ids2); + expected = {1, 3}; EXPECT_EQ(expected, ids_out); } @@ -2018,7 +2010,7 @@ TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) { EXPECT_EQ(origin2, origin_out); // The resources associated with |origin1| should be purgeable. - std::set<int64_t> purgeable_ids_out; + std::vector<int64_t> purgeable_ids_out; EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, database->GetPurgeableResourceIds(&purgeable_ids_out)); EXPECT_EQ(4u, purgeable_ids_out.size()); diff --git a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc index ae523422b85..4dd9f0f70af 100644 --- a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc +++ b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.cc @@ -12,7 +12,6 @@ #include "base/bind_helpers.h" #include "base/containers/queue.h" #include "base/feature_list.h" -#include "base/task/post_task.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" #include "content/browser/child_process_security_policy_impl.h" @@ -32,6 +31,7 @@ #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" +#include "content/public/browser/global_request_id.h" #include "content/public/browser/render_process_host.h" #include "content/public/common/content_client.h" #include "content/public/common/navigation_policy.h" @@ -45,7 +45,6 @@ #include "net/traffic_annotation/network_traffic_annotation.h" #include "net/url_request/url_request.h" #include "services/network/public/cpp/wrapper_shared_url_loader_factory.h" -#include "services/network/throttling/throttling_controller.h" #include "third_party/blink/public/common/service_worker/service_worker_status_code.h" namespace content { @@ -192,8 +191,8 @@ class DelegatingURLLoaderClient final : public network::mojom::URLLoaderClient { if (!worker_id_ || !devtools_enabled_) return; while (!devtools_callbacks.empty()) { - base::PostTask(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(devtools_callbacks.front()), + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(devtools_callbacks.front()), *worker_id_, devtools_request_id_)); devtools_callbacks.pop(); } @@ -534,6 +533,13 @@ void ServiceWorkerFetchDispatcher::StartWorker() { GetEventType(), base::BindOnce(&ServiceWorkerFetchDispatcher::DidStartWorker, weak_factory_.GetWeakPtr())); + + if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled() && + version_->is_endpoint_ready()) { + // For an active service worker, the endpoint becomes ready synchronously + // with StartWorker(). In that case, we can dispatch FetchEvent immediately. + DispatchFetchEvent(); + } } void ServiceWorkerFetchDispatcher::DidStartWorker( @@ -547,17 +553,19 @@ void ServiceWorkerFetchDispatcher::DidStartWorker( DidFail(status); return; } - DispatchFetchEvent(); + if (!IsEventDispatched()) { + DispatchFetchEvent(); + } } void ServiceWorkerFetchDispatcher::DispatchFetchEvent() { - DCHECK_EQ(EmbeddedWorkerStatus::RUNNING, version_->running_status()) + DCHECK(EmbeddedWorkerStatus::STARTING == version_->running_status() || + EmbeddedWorkerStatus::RUNNING == version_->running_status()) << "Worker stopped too soon after it was started."; TRACE_EVENT_WITH_FLOW0("ServiceWorker", "ServiceWorkerFetchDispatcher::DispatchFetchEvent", TRACE_ID_LOCAL(this), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - // Grant the service worker's process access to files in the request body. if (request_->body) { GrantFileAccessToProcess(version_->embedded_worker()->process_id(), @@ -598,16 +606,7 @@ void ServiceWorkerFetchDispatcher::DispatchFetchEvent() { auto params = blink::mojom::DispatchFetchEventParams::New(); params->request = std::move(request_); params->client_id = client_id_; - if (is_offline_capability_check_) { - // TODO(crbug.com/1031950): We have to set up |preload_handle_| correctly so - // that event.preloadResponse is valid one if navigation preload is enabled. - - // At present, an offline-capability-check fetch event is not calling - // MayStartNavigationPreload() so |preload_handle_| is null here. - DCHECK(!preload_handle_); - } else { - params->preload_handle = std::move(preload_handle_); - } + params->preload_handle = std::move(preload_handle_); params->is_offline_capability_check = is_offline_capability_check_; // TODO(https://crbug.com/900700): Make the remote connected to a receiver @@ -637,9 +636,9 @@ void ServiceWorkerFetchDispatcher::DidFail( "ServiceWorker", "ServiceWorkerFetchDispatcher::DidFail", TRACE_ID_LOCAL(this), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "status", status); - Complete(status, FetchEventResult::kShouldFallback, - blink::mojom::FetchAPIResponse::New(), nullptr /* body_as_stream */, - nullptr /* timing */); + RunCallback(status, FetchEventResult::kShouldFallback, + blink::mojom::FetchAPIResponse::New(), + nullptr /* body_as_stream */, nullptr /* timing */); } void ServiceWorkerFetchDispatcher::DidFinish( @@ -652,17 +651,21 @@ void ServiceWorkerFetchDispatcher::DidFinish( "ServiceWorkerFetchDispatcher::DidFinish", TRACE_ID_LOCAL(this), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - Complete(blink::ServiceWorkerStatusCode::kOk, fetch_result, - std::move(response), std::move(body_as_stream), std::move(timing)); + RunCallback(blink::ServiceWorkerStatusCode::kOk, fetch_result, + std::move(response), std::move(body_as_stream), + std::move(timing)); } -void ServiceWorkerFetchDispatcher::Complete( +void ServiceWorkerFetchDispatcher::RunCallback( blink::ServiceWorkerStatusCode status, FetchEventResult fetch_result, blink::mojom::FetchAPIResponsePtr response, blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream, blink::mojom::ServiceWorkerFetchEventTimingPtr timing) { - DCHECK(fetch_callback_); + // Fetch dispatcher can be completed at this point due to a failure of + // starting up a worker. In that case, let's simply ignore it. + if (!fetch_callback_) + return; std::move(fetch_callback_) .Run(status, fetch_result, std::move(response), std::move(body_as_stream), @@ -684,6 +687,23 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload( if (request_->body) return false; + // When the fetch event is for an offline capability check, respond to the + // navigation preload with a network disconnected error, to simulate offline. + if (is_offline_capability_check_) { + mojo::PendingRemote<network::mojom::URLLoader> url_loader_to_pass; + mojo::Remote<network::mojom::URLLoaderClient> url_loader_client; + auto dummy_receiver = url_loader_to_pass.InitWithNewPipeAndPassReceiver(); + + preload_handle_ = blink::mojom::FetchEventPreloadHandle::New(); + preload_handle_->url_loader = std::move(url_loader_to_pass); + preload_handle_->url_loader_client_receiver = + url_loader_client.BindNewPipeAndPassReceiver(); + + url_loader_client->OnComplete( + network::URLLoaderCompletionStatus(net::ERR_INTERNET_DISCONNECTED)); + return true; + } + network::ResourceRequest resource_request(original_request); if (resource_type_ == blink::mojom::ResourceType::kMainFrame) { resource_request.resource_type = static_cast<int>( @@ -699,8 +719,6 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload( DCHECK(net::HttpUtil::IsValidHeaderValue( version_->navigation_preload_state().header)); - ServiceWorkerMetrics::RecordNavigationPreloadRequestHeaderSize( - version_->navigation_preload_state().header.length()); resource_request.headers.SetHeader( "Service-Worker-Navigation-Preload", version_->navigation_preload_state().header); @@ -709,8 +727,8 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload( scoped_refptr<network::SharedURLLoaderFactory> factory; mojo::PendingRemote<network::mojom::URLLoaderFactory> network_factory; - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&CreateNetworkFactoryForNavigationPreloadOnUI, frame_tree_node_id, std::move(context_wrapper), network_factory.InitWithNewPipeAndPassReceiver())); @@ -727,10 +745,6 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload( auto url_loader_client = std::make_unique<DelegatingURLLoaderClient>( std::move(inner_url_loader_client), resource_request); - // Get a unique request id across browser-initiated navigations and navigation - // preloads. - int request_id = GlobalRequestID::MakeBrowserInitiated().request_id; - // Start the network request for the URL using the network factory. // TODO(falken): What to do about routing_id. mojo::PendingRemote<network::mojom::URLLoaderClient> @@ -740,7 +754,8 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload( factory->CreateLoaderAndStart( url_loader.InitWithNewPipeAndPassReceiver(), -1 /* routing_id? */, - request_id, network::mojom::kURLLoadOptionNone, resource_request, + GlobalRequestID::MakeBrowserInitiated().request_id, + network::mojom::kURLLoadOptionNone, resource_request, std::move(url_loader_client_to_pass), net::MutableNetworkTrafficAnnotationTag( kNavigationPreloadTrafficAnnotation)); @@ -758,6 +773,10 @@ ServiceWorkerMetrics::EventType ServiceWorkerFetchDispatcher::GetEventType() return ResourceTypeToEventType(resource_type_); } +bool ServiceWorkerFetchDispatcher::IsEventDispatched() const { + return request_.is_null(); +} + // static void ServiceWorkerFetchDispatcher::OnFetchEventFinished( ServiceWorkerVersion* version, diff --git a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h index c24c6308b43..b7756b77122 100644 --- a/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h +++ b/chromium/content/browser/service_worker/service_worker_fetch_dispatcher.h @@ -91,11 +91,11 @@ class CONTENT_EXPORT ServiceWorkerFetchDispatcher { blink::mojom::FetchAPIResponsePtr response, blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream, blink::mojom::ServiceWorkerFetchEventTimingPtr timing); - void Complete(blink::ServiceWorkerStatusCode status, - FetchEventResult fetch_result, - blink::mojom::FetchAPIResponsePtr response, - blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream, - blink::mojom::ServiceWorkerFetchEventTimingPtr timing); + void RunCallback(blink::ServiceWorkerStatusCode status, + FetchEventResult fetch_result, + blink::mojom::FetchAPIResponsePtr response, + blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream, + blink::mojom::ServiceWorkerFetchEventTimingPtr timing); // The fetch event stays open until all respondWith() and waitUntil() promises // are settled. This function is called once the renderer signals that @@ -109,6 +109,8 @@ class CONTENT_EXPORT ServiceWorkerFetchDispatcher { ServiceWorkerMetrics::EventType GetEventType() const; + bool IsEventDispatched() const; + blink::mojom::FetchAPIRequestPtr request_; std::string client_id_; scoped_refptr<ServiceWorkerVersion> version_; diff --git a/chromium/content/browser/service_worker/service_worker_provider_host.cc b/chromium/content/browser/service_worker/service_worker_host.cc index 18ca2aeffce..136443f9328 100644 --- a/chromium/content/browser/service_worker/service_worker_provider_host.cc +++ b/chromium/content/browser/service_worker/service_worker_host.cc @@ -2,7 +2,7 @@ // 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_provider_host.h" +#include "content/browser/service_worker/service_worker_host.h" #include <utility> @@ -48,26 +48,26 @@ void CreateQuicTransportConnectorImpl( } // anonymous namespace -ServiceWorkerProviderHost::ServiceWorkerProviderHost( +ServiceWorkerHost::ServiceWorkerHost( mojo::PendingAssociatedReceiver<blink::mojom::ServiceWorkerContainerHost> host_receiver, - ServiceWorkerVersion* running_hosted_version, + ServiceWorkerVersion* version, base::WeakPtr<ServiceWorkerContextCore> context) - : running_hosted_version_(running_hosted_version), + : version_(version), container_host_(std::make_unique<content::ServiceWorkerContainerHost>( std::move(context))), host_receiver_(container_host_.get(), std::move(host_receiver)) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - DCHECK(running_hosted_version_); + DCHECK(version_); container_host_->set_service_worker_host(this); container_host_->UpdateUrls( - running_hosted_version_->script_url(), - net::SiteForCookies::FromUrl(running_hosted_version_->script_url()), - running_hosted_version_->script_origin()); + version_->script_url(), + net::SiteForCookies::FromUrl(version_->script_url()), + version_->script_origin()); } -ServiceWorkerProviderHost::~ServiceWorkerProviderHost() { +ServiceWorkerHost::~ServiceWorkerHost() { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); // Explicitly destroy the ServiceWorkerContainerHost to release @@ -75,12 +75,12 @@ ServiceWorkerProviderHost::~ServiceWorkerProviderHost() { // that. Otherwise, this destructor can trigger their Mojo connection error // handlers, which would call back into halfway destroyed |this|. This is // because they are associated with the ServiceWorker interface, which can be - // destroyed while in this destructor (|running_hosted_version_|'s - // |event_dispatcher_|). See https://crbug.com/854993. + // destroyed while in this destructor (|version_|'s |event_dispatcher_|). + // See https://crbug.com/854993. container_host_.reset(); } -void ServiceWorkerProviderHost::CompleteStartWorkerPreparation( +void ServiceWorkerHost::CompleteStartWorkerPreparation( int process_id, mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker> broker_receiver) { @@ -91,33 +91,29 @@ void ServiceWorkerProviderHost::CompleteStartWorkerPreparation( broker_receiver_.Bind(std::move(broker_receiver)); } -void ServiceWorkerProviderHost::CreateQuicTransportConnector( +void ServiceWorkerHost::CreateQuicTransportConnector( mojo::PendingReceiver<blink::mojom::QuicTransportConnector> receiver) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); RunOrPostTaskOnThread( FROM_HERE, BrowserThread::UI, base::BindOnce(&CreateQuicTransportConnectorImpl, worker_process_id_, - running_hosted_version_->script_origin(), - std::move(receiver))); + version_->script_origin(), std::move(receiver))); } -void ServiceWorkerProviderHost::BindCacheStorage( +void ServiceWorkerHost::BindCacheStorage( mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK(!base::FeatureList::IsEnabled( blink::features::kEagerCacheStorageSetupForServiceWorkers)); - running_hosted_version_->embedded_worker()->BindCacheStorage( - std::move(receiver)); + version_->embedded_worker()->BindCacheStorage(std::move(receiver)); } -base::WeakPtr<ServiceWorkerProviderHost> -ServiceWorkerProviderHost::GetWeakPtr() { +base::WeakPtr<ServiceWorkerHost> ServiceWorkerHost::GetWeakPtr() { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); return weak_factory_.GetWeakPtr(); } -void ServiceWorkerProviderHost::ReportNoBinderForInterface( - const std::string& error) { +void ServiceWorkerHost::ReportNoBinderForInterface(const std::string& error) { broker_receiver_.ReportBadMessage(error + " for the service worker scope"); } diff --git a/chromium/content/browser/service_worker/service_worker_provider_host.h b/chromium/content/browser/service_worker/service_worker_host.h index d8afd0194ee..e9daa763c9e 100644 --- a/chromium/content/browser/service_worker/service_worker_provider_host.h +++ b/chromium/content/browser/service_worker/service_worker_host.h @@ -2,8 +2,8 @@ // 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_PROVIDER_HOST_H_ -#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_HOST_H_ +#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_HOST_H_ +#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_HOST_H_ #include <memory> #include <string> @@ -37,28 +37,23 @@ namespace content { class ServiceWorkerContextCore; class ServiceWorkerVersion; -// ServiceWorkerProviderHost is the host of a service worker execution context -// in the renderer process. One ServiceWorkerProviderHost instance hosts one -// service worker execution context instance. +// ServiceWorkerHost is the host of a service worker execution context in the +// renderer process. One ServiceWorkerHost instance hosts one service worker +// execution context instance. // -// ServiceWorkerProviderHost lives on the service worker core thread, since all -// nearly all browser process service worker machinery lives on the service -// worker core thread. -// -// TODO(https://crbug.com/931087): Rename this to ServiceWorkerHost. -class CONTENT_EXPORT ServiceWorkerProviderHost { +// ServiceWorkerHost lives on the service worker core thread, since all nearly +// all browser process service worker machinery lives on the service worker core +// thread. +class CONTENT_EXPORT ServiceWorkerHost { public: - ServiceWorkerProviderHost( - mojo::PendingAssociatedReceiver<blink::mojom::ServiceWorkerContainerHost> - host_receiver, - ServiceWorkerVersion* running_hosted_version, - base::WeakPtr<ServiceWorkerContextCore> context); - ~ServiceWorkerProviderHost(); + ServiceWorkerHost(mojo::PendingAssociatedReceiver< + blink::mojom::ServiceWorkerContainerHost> host_receiver, + ServiceWorkerVersion* version, + base::WeakPtr<ServiceWorkerContextCore> context); + ~ServiceWorkerHost(); int worker_process_id() const { return worker_process_id_; } - ServiceWorkerVersion* running_hosted_version() const { - return running_hosted_version_; - } + ServiceWorkerVersion* version() const { return version_; } // Completes initialization of this provider host. It is called once a // renderer process has been found to host the worker. @@ -77,19 +72,18 @@ class CONTENT_EXPORT ServiceWorkerProviderHost { return container_host_.get(); } - base::WeakPtr<ServiceWorkerProviderHost> GetWeakPtr(); + base::WeakPtr<ServiceWorkerHost> GetWeakPtr(); void ReportNoBinderForInterface(const std::string& error); private: int worker_process_id_ = ChildProcessHost::kInvalidUniqueID; - // The instance of service worker this provider hosts. - // Raw pointer is safe because the version owns |this|. - ServiceWorkerVersion* const running_hosted_version_; + // The service worker being hosted. Raw pointer is safe because the version + // owns |this|. + ServiceWorkerVersion* const version_; - BrowserInterfaceBrokerImpl<ServiceWorkerProviderHost, - const ServiceWorkerVersionInfo&> + BrowserInterfaceBrokerImpl<ServiceWorkerHost, const ServiceWorkerVersionInfo&> broker_{this}; mojo::Receiver<blink::mojom::BrowserInterfaceBroker> broker_receiver_{ &broker_}; @@ -99,11 +93,11 @@ class CONTENT_EXPORT ServiceWorkerProviderHost { mojo::AssociatedReceiver<blink::mojom::ServiceWorkerContainerHost> host_receiver_; - base::WeakPtrFactory<ServiceWorkerProviderHost> weak_factory_{this}; + base::WeakPtrFactory<ServiceWorkerHost> weak_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderHost); + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerHost); }; } // namespace content -#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_HOST_H_ +#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_HOST_H_ diff --git a/chromium/content/browser/service_worker/service_worker_info.h b/chromium/content/browser/service_worker/service_worker_info.h index 76b2e6514f0..78af74044c3 100644 --- a/chromium/content/browser/service_worker/service_worker_info.h +++ b/chromium/content/browser/service_worker/service_worker_info.h @@ -20,8 +20,8 @@ namespace content { +class ServiceWorkerClientInfo; enum class EmbeddedWorkerStatus; -struct ServiceWorkerClientInfo; struct CONTENT_EXPORT ServiceWorkerVersionInfo { public: diff --git a/chromium/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc b/chromium/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc index 3107253371c..855ef9e27de 100644 --- a/chromium/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc @@ -21,6 +21,7 @@ #include "net/base/io_buffer.h" #include "net/base/test_completion_callback.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/blob/blob_utils.h" #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h" namespace content { @@ -300,7 +301,7 @@ TEST_F(ServiceWorkerInstalledScriptsSenderTest, FailedToSendBody) { TEST_F(ServiceWorkerInstalledScriptsSenderTest, FailedToSendMetaData) { const GURL kMainScriptURL = version()->script_url(); std::string long_meta_data = "I'm the meta data!"; - long_meta_data.resize(3E6, '!'); + long_meta_data.resize(blink::BlobUtils::GetDataPipeCapacity(3E6) + 1, '!'); std::map<GURL, ExpectedScriptInfo> kExpectedScriptInfoMap = { {kMainScriptURL, {1, diff --git a/chromium/content/browser/service_worker/service_worker_internals_ui.cc b/chromium/content/browser/service_worker/service_worker_internals_ui.cc index fada516d742..1d86f96b8fd 100644 --- a/chromium/content/browser/service_worker/service_worker_internals_ui.cc +++ b/chromium/content/browser/service_worker/service_worker_internals_ui.cc @@ -36,6 +36,7 @@ #include "content/public/browser/web_ui_data_source.h" #include "content/public/common/child_process_host.h" #include "content/public/common/url_constants.h" +#include "services/network/public/mojom/content_security_policy.mojom.h" #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h" using base::DictionaryValue; @@ -56,8 +57,8 @@ void OperationCompleteCallback(WeakPtr<ServiceWorkerInternalsUI> internals, int callback_id, blink::ServiceWorkerStatusCode status) { if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { - base::PostTask(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(OperationCompleteCallback, internals, + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(OperationCompleteCallback, internals, callback_id, status)); return; } @@ -159,9 +160,9 @@ void UpdateVersionInfo(const ServiceWorkerVersionInfo& version, for (auto& it : version.clients) { auto client = DictionaryValue(); client.SetStringPath("client_id", it.first); - if (it.second.type == blink::mojom::ServiceWorkerClientType::kWindow) { + if (it.second.type() == blink::mojom::ServiceWorkerClientType::kWindow) { WebContents* web_contents = - WebContents::FromFrameTreeNodeId(it.second.frame_tree_node_id); + WebContents::FromFrameTreeNodeId(it.second.GetFrameTreeNodeId()); if (web_contents) client.SetStringPath("url", web_contents->GetURL().spec()); } @@ -221,8 +222,8 @@ void DidGetStoredRegistrationsOnCoreThread( blink::ServiceWorkerStatusCode status, const std::vector<ServiceWorkerRegistrationInfo>& stored_registrations) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - base::PostTask( - FROM_HERE, {BrowserThread::UI}, + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), context->GetAllLiveRegistrationInfo(), context->GetAllLiveVersionInfo(), stored_registrations)); } @@ -349,7 +350,8 @@ ServiceWorkerInternalsUI::ServiceWorkerInternalsUI(WebUI* web_ui) : WebUIController(web_ui), next_partition_id_(0) { WebUIDataSource* source = WebUIDataSource::Create(kChromeUIServiceWorkerInternalsHost); - source->OverrideContentSecurityPolicyScriptSrc( + source->OverrideContentSecurityPolicy( + network::mojom::CSPDirectiveName::ScriptSrc, "script-src chrome://resources 'self' 'unsafe-eval';"); source->UseStringsJs(); source->AddResourcePath("serviceworker_internals.js", diff --git a/chromium/content/browser/service_worker/service_worker_job_unittest.cc b/chromium/content/browser/service_worker/service_worker_job_unittest.cc index d51ddca1d09..646f0e40095 100644 --- a/chromium/content/browser/service_worker/service_worker_job_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_job_unittest.cc @@ -203,7 +203,7 @@ class ServiceWorkerJobTest : public testing::Test { BrowserTaskEnvironment task_environment_; std::unique_ptr<EmbeddedWorkerTestHelper> helper_; - std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints_; + std::vector<ServiceWorkerRemoteContainerEndpoint> remote_endpoints_; }; scoped_refptr<ServiceWorkerRegistration> ServiceWorkerJobTest::RunRegisterJob( @@ -432,10 +432,10 @@ TEST_F(ServiceWorkerJobTest, Unregister) { observer.RunUntilActivated(registration->installing_version(), runner); scoped_refptr<ServiceWorkerVersion> version = registration->active_version(); - ServiceWorkerProviderHost* provider_host = - registration->active_version()->provider_host(); - ASSERT_NE(nullptr, provider_host); - ServiceWorkerContainerHost* container_host = provider_host->container_host(); + ServiceWorkerHost* worker_host = + registration->active_version()->worker_host(); + ASSERT_NE(nullptr, worker_host); + ServiceWorkerContainerHost* container_host = worker_host->container_host(); // One ServiceWorkerRegistrationObjectHost should have been created for the // new registration. EXPECT_EQ(1UL, container_host->registration_object_hosts_.size()); @@ -448,7 +448,7 @@ TEST_F(ServiceWorkerJobTest, Unregister) { WaitForVersionRunningStatus(version, EmbeddedWorkerStatus::STOPPED); // The service worker registration object host and service worker object host - // have been destroyed together with |provider_host| by the above + // have been destroyed together with |worker_host| by the above // unregistration. Then |registration| and |version| should be the last one // reference to the corresponding instance. EXPECT_TRUE(registration->HasOneRef()); @@ -534,11 +534,11 @@ TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) { // During the above registration, a service worker registration object host // for ServiceWorkerGlobalScope#registration has been created/added into - // |provider_host|. - ServiceWorkerProviderHost* provider_host = - old_registration->active_version()->provider_host(); - ASSERT_NE(nullptr, provider_host); - ServiceWorkerContainerHost* container_host = provider_host->container_host(); + // |worker_host|. + ServiceWorkerHost* worker_host = + old_registration->active_version()->worker_host(); + ASSERT_NE(nullptr, worker_host); + ServiceWorkerContainerHost* container_host = worker_host->container_host(); // Clear all service worker object hosts. container_host->service_worker_object_hosts_.clear(); @@ -1122,7 +1122,7 @@ TEST_F(ServiceWorkerJobTest, HasFetchHandler) { // Test that clients are alerted of new registrations if they are // in-scope, so that Clients.claim() or ServiceWorkerContainer.ready work // correctly. -TEST_F(ServiceWorkerJobTest, AddRegistrationToMatchingProviderHosts) { +TEST_F(ServiceWorkerJobTest, AddRegistrationToMatchingerHosts) { GURL scope("https://www.example.com/scope/"); GURL in_scope("https://www.example.com/scope/page"); GURL out_scope("https://www.example.com/page"); @@ -1441,11 +1441,11 @@ TEST_F(ServiceWorkerUpdateJobTest, RegisterWithDifferentUpdateViaCache) { // During the above registration, a service worker registration object host // for ServiceWorkerGlobalScope#registration has been created/added into - // |provider_host|. - ServiceWorkerProviderHost* provider_host = - old_registration->active_version()->provider_host(); - ASSERT_TRUE(provider_host); - ServiceWorkerContainerHost* container_host = provider_host->container_host(); + // |worker_host|. + ServiceWorkerHost* worker_host = + old_registration->active_version()->worker_host(); + ASSERT_TRUE(worker_host); + ServiceWorkerContainerHost* container_host = worker_host->container_host(); // Remove references to |old_registration| so that |old_registration| is the // only reference to the registration. diff --git a/chromium/content/browser/service_worker/service_worker_main_resource_handle.cc b/chromium/content/browser/service_worker/service_worker_main_resource_handle.cc index 3fd46f7d7fe..43565c71451 100644 --- a/chromium/content/browser/service_worker/service_worker_main_resource_handle.cc +++ b/chromium/content/browser/service_worker/service_worker_main_resource_handle.cc @@ -34,13 +34,13 @@ ServiceWorkerMainResourceHandle::~ServiceWorkerMainResourceHandle() { core_); } -void ServiceWorkerMainResourceHandle::OnCreatedProviderHost( - blink::mojom::ServiceWorkerProviderInfoForClientPtr provider_info) { +void ServiceWorkerMainResourceHandle::OnCreatedContainerHost( + blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(provider_info->host_remote.is_valid() && - provider_info->client_receiver.is_valid()); + DCHECK(container_info->host_remote.is_valid() && + container_info->client_receiver.is_valid()); - provider_info_ = std::move(provider_info); + container_info_ = std::move(container_info); } void ServiceWorkerMainResourceHandle::OnBeginNavigationCommit( @@ -49,10 +49,10 @@ void ServiceWorkerMainResourceHandle::OnBeginNavigationCommit( const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy, mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter> coep_reporter, - blink::mojom::ServiceWorkerProviderInfoForClientPtr* out_provider_info) { + blink::mojom::ServiceWorkerContainerInfoForClientPtr* out_container_info) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - // We may have failed to pre-create the provider host. - if (!provider_info_) + // We may have failed to pre-create the container host. + if (!container_info_) return; ServiceWorkerContextWrapper::RunOrPostTaskOnCoreThread( FROM_HERE, @@ -60,7 +60,16 @@ void ServiceWorkerMainResourceHandle::OnBeginNavigationCommit( &ServiceWorkerMainResourceHandleCore::OnBeginNavigationCommit, base::Unretained(core_), render_process_id, render_frame_id, cross_origin_embedder_policy, std::move(coep_reporter))); - *out_provider_info = std::move(provider_info_); + *out_container_info = std::move(container_info_); +} + +void ServiceWorkerMainResourceHandle::OnEndNavigationCommit() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + ServiceWorkerContextWrapper::RunOrPostTaskOnCoreThread( + FROM_HERE, + base::BindOnce( + &ServiceWorkerMainResourceHandleCore::OnEndNavigationCommit, + base::Unretained(core_))); } void ServiceWorkerMainResourceHandle::OnBeginWorkerCommit( diff --git a/chromium/content/browser/service_worker/service_worker_main_resource_handle.h b/chromium/content/browser/service_worker/service_worker_main_resource_handle.h index c7786a29008..13caaaa9cc8 100644 --- a/chromium/content/browser/service_worker/service_worker_main_resource_handle.h +++ b/chromium/content/browser/service_worker/service_worker_main_resource_handle.h @@ -26,37 +26,38 @@ namespace content { class ServiceWorkerContextWrapper; class ServiceWorkerMainResourceHandleCore; -// This class is used to manage the lifetime of ServiceWorkerProviderHosts +// This class is used to manage the lifetime of ServiceWorkerContainerHosts // created for main resource requests (navigations and web workers). This is a // UI thread class, with a pendant class on the core thread, the // ServiceWorkerMainResourceHandleCore. // // The lifetime of the ServiceWorkerMainResourceHandle, the -// ServiceWorkerMainResourceHandleCore and the ServiceWorkerProviderHost are the -// following: +// ServiceWorkerMainResourceHandleCore and the ServiceWorkerContainerHost are +// the following: // 1) We create a ServiceWorkerMainResourceHandle on the UI thread without -// populating the member service worker provider info. This also leads to the +// populating the member service worker container info. This also leads to the // creation of a ServiceWorkerMainResourceHandleCore. // // 2) When the navigation request is sent to the core thread, we include a // pointer to the ServiceWorkerMainResourceHandleCore. // -// 3) If we pre-create a ServiceWorkerProviderHost for this navigation, it -// is added to ServiceWorkerContextCore and its provider info is passed to +// 3) If we pre-create a ServiceWorkerContainerHost for this navigation, it +// is added to ServiceWorkerContextCore and its container info is passed to // ServiceWorkerMainResourceHandle on the UI thread via // ServiceWorkerMainResourceHandleCore. See -// ServiceWorkerMainResourceHandleCore::OnCreatedProviderHost() and -// ServiceWorkerMainResourceHandle::OnCreatedProviderHost() for details. +// ServiceWorkerMainResourceHandleCore::OnCreatedContainerHost() and +// ServiceWorkerMainResourceHandle::OnCreatedContainerHost() for details. // // 4) When the navigation is ready to commit, the NavigationRequest will // call ServiceWorkerMainResourceHandle::OnBeginNavigationCommit() to -// - complete the initialization for the ServiceWorkerProviderHost. -// - take out the provider info to be sent as part of navigation commit IPC. +// - complete the initialization for the ServiceWorkerContainerHost. +// - take out the container info to be sent as part of navigation commit +// IPC. // // 5) When the navigation finishes, the ServiceWorkerMainResourceHandle is // destroyed. The destructor of the ServiceWorkerMainResourceHandle destroys -// the provider info which in turn leads to the destruction of an unclaimed -// ServiceWorkerProviderHost, and posts a task to destroy the +// the container info which in turn leads to the destruction of an unclaimed +// ServiceWorkerContainerHost, and posts a task to destroy the // ServiceWorkerMainResourceHandleCore on the core thread. class CONTENT_EXPORT ServiceWorkerMainResourceHandle { public: @@ -65,42 +66,46 @@ class CONTENT_EXPORT ServiceWorkerMainResourceHandle { ServiceWorkerAccessedCallback on_service_worker_accessed); ~ServiceWorkerMainResourceHandle(); - // Called after a ServiceWorkerProviderHost tied with |provider_info| - // was pre-created for the navigation. - void OnCreatedProviderHost( - blink::mojom::ServiceWorkerProviderInfoForClientPtr provider_info); + // Called after a ServiceWorkerContainerHost tied with |container_info| was + // pre-created for the navigation. + void OnCreatedContainerHost( + blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info); // Called when the navigation is ready to commit. // Provides |render_process_id|, |render_frame_id|, and - // |cross_origin_embedder_policy| to the pre-created provider host. Fills in - // |out_provider_info| so the caller can send it to the renderer process as + // |cross_origin_embedder_policy| to the pre-created container host. Fills in + // |out_container_info| so the caller can send it to the renderer process as // part of the navigation commit IPC. - // |out_provider_info| can be filled as null if we failed to pre-create the - // provider host for some security reasons. + // |out_container_info| can be filled as null if we failed to pre-create the + // container host for some security reasons. void OnBeginNavigationCommit( int render_process_id, int render_frame_id, const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy, mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter> coep_reporter, - blink::mojom::ServiceWorkerProviderInfoForClientPtr* out_provider_info); + blink::mojom::ServiceWorkerContainerInfoForClientPtr* out_container_info); + + // Called after the renderer reports back that the navigation has been + // committed. + void OnEndNavigationCommit(); // Similar to OnBeginNavigationCommit() for shared workers (and dedicated // workers when PlzDedicatedWorker is on). - // |cross_origin_embedder_policy| is passed to the pre-created provider + // |cross_origin_embedder_policy| is passed to the pre-created container // host. void OnBeginWorkerCommit( const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy); - blink::mojom::ServiceWorkerProviderInfoForClientPtr TakeProviderInfo() { - return std::move(provider_info_); + blink::mojom::ServiceWorkerContainerInfoForClientPtr TakeContainerInfo() { + return std::move(container_info_); } - bool has_provider_info() const { return !!provider_info_; } + bool has_container_info() const { return !!container_info_; } ServiceWorkerMainResourceHandleCore* core() { return core_; } - const ServiceWorkerContextWrapper* context_wrapper() const { + ServiceWorkerContextWrapper* context_wrapper() { return context_wrapper_.get(); } @@ -109,7 +114,7 @@ class CONTENT_EXPORT ServiceWorkerMainResourceHandle { } private: - blink::mojom::ServiceWorkerProviderInfoForClientPtr provider_info_; + blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info_; ServiceWorkerMainResourceHandleCore* core_; scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_; diff --git a/chromium/content/browser/service_worker/service_worker_main_resource_handle_core.cc b/chromium/content/browser/service_worker/service_worker_main_resource_handle_core.cc index 7cd6d9022ee..62766a45e8b 100644 --- a/chromium/content/browser/service_worker/service_worker_main_resource_handle_core.cc +++ b/chromium/content/browser/service_worker/service_worker_main_resource_handle_core.cc @@ -40,6 +40,11 @@ void ServiceWorkerMainResourceHandleCore::OnBeginNavigationCommit( std::move(coep_reporter)); } } +void ServiceWorkerMainResourceHandleCore::OnEndNavigationCommit() { + DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); + if (container_host_) + container_host_->OnEndNavigationCommit(); +} void ServiceWorkerMainResourceHandleCore::OnBeginWorkerCommit( const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy) { diff --git a/chromium/content/browser/service_worker/service_worker_main_resource_handle_core.h b/chromium/content/browser/service_worker/service_worker_main_resource_handle_core.h index aac0082f657..5397df2c8da 100644 --- a/chromium/content/browser/service_worker/service_worker_main_resource_handle_core.h +++ b/chromium/content/browser/service_worker/service_worker_main_resource_handle_core.h @@ -49,6 +49,7 @@ class CONTENT_EXPORT ServiceWorkerMainResourceHandleCore { const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy, mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter> coep_reporter); + void OnEndNavigationCommit(); void OnBeginWorkerCommit( const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy); diff --git a/chromium/content/browser/service_worker/service_worker_navigation_loader.cc b/chromium/content/browser/service_worker/service_worker_main_resource_loader.cc index 07b61ef023b..a54ddc9d48f 100644 --- a/chromium/content/browser/service_worker/service_worker_navigation_loader.cc +++ b/chromium/content/browser/service_worker/service_worker_main_resource_loader.cc @@ -2,7 +2,7 @@ // 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.h" +#include "content/browser/service_worker/service_worker_main_resource_loader.h" #include <sstream> #include <string> @@ -45,12 +45,12 @@ std::string ComposeFetchEventResultString( } // namespace // This class waits for completion of a stream response from the service worker. -// It calls ServiceWorkerNavigationLoader::CommitCompleted() upon completion of -// the response. -class ServiceWorkerNavigationLoader::StreamWaiter +// It calls ServiceWorkerMainResourceLoader::CommitCompleted() upon completion +// of the response. +class ServiceWorkerMainResourceLoader::StreamWaiter : public blink::mojom::ServiceWorkerStreamCallback { public: - StreamWaiter(ServiceWorkerNavigationLoader* owner, + StreamWaiter(ServiceWorkerMainResourceLoader* owner, mojo::PendingReceiver<blink::mojom::ServiceWorkerStreamCallback> callback_receiver) : owner_(owner), receiver_(this, std::move(callback_receiver)) { @@ -69,13 +69,13 @@ class ServiceWorkerNavigationLoader::StreamWaiter } private: - ServiceWorkerNavigationLoader* owner_; + ServiceWorkerMainResourceLoader* owner_; mojo::Receiver<blink::mojom::ServiceWorkerStreamCallback> receiver_; DISALLOW_COPY_AND_ASSIGN(StreamWaiter); }; -ServiceWorkerNavigationLoader::ServiceWorkerNavigationLoader( +ServiceWorkerMainResourceLoader::ServiceWorkerMainResourceLoader( NavigationLoaderInterceptor::FallbackCallback fallback_callback, base::WeakPtr<ServiceWorkerContainerHost> container_host, scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter) @@ -84,21 +84,21 @@ ServiceWorkerNavigationLoader::ServiceWorkerNavigationLoader( url_loader_factory_getter_(std::move(url_loader_factory_getter)) { TRACE_EVENT_WITH_FLOW0( "ServiceWorker", - "ServiceWorkerNavigationLoader::ServiceWorkerNavigationLoader", this, + "ServiceWorkerMainResourceLoader::ServiceWorkerMainResourceLoader", this, TRACE_EVENT_FLAG_FLOW_OUT); response_head_->load_timing.request_start = base::TimeTicks::Now(); response_head_->load_timing.request_start_time = base::Time::Now(); } -ServiceWorkerNavigationLoader::~ServiceWorkerNavigationLoader() { +ServiceWorkerMainResourceLoader::~ServiceWorkerMainResourceLoader() { TRACE_EVENT_WITH_FLOW0( "ServiceWorker", - "ServiceWorkerNavigationLoader::~ServiceWorkerNavigationloader", this, + "ServiceWorkerMainResourceLoader::~ServiceWorkerNavigationloader", this, TRACE_EVENT_FLAG_FLOW_IN); } -void ServiceWorkerNavigationLoader::DetachedFromRequest() { +void ServiceWorkerMainResourceLoader::DetachedFromRequest() { is_detached_ = true; // Clear |fallback_callback_| since it's no longer safe to invoke it because // the bound object has been destroyed. @@ -106,21 +106,21 @@ void ServiceWorkerNavigationLoader::DetachedFromRequest() { DeleteIfNeeded(); } -base::WeakPtr<ServiceWorkerNavigationLoader> -ServiceWorkerNavigationLoader::AsWeakPtr() { +base::WeakPtr<ServiceWorkerMainResourceLoader> +ServiceWorkerMainResourceLoader::AsWeakPtr() { return weak_factory_.GetWeakPtr(); } -void ServiceWorkerNavigationLoader::StartRequest( +void ServiceWorkerMainResourceLoader::StartRequest( const network::ResourceRequest& resource_request, mojo::PendingReceiver<network::mojom::URLLoader> receiver, mojo::PendingRemote<network::mojom::URLLoaderClient> client) { TRACE_EVENT_WITH_FLOW1("ServiceWorker", - "ServiceWorkerNavigationLoader::StartRequest", this, + "ServiceWorkerMainResourceLoader::StartRequest", this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "url", resource_request.url.spec()); - DCHECK(ServiceWorkerUtils::IsMainResourceType( - static_cast<blink::mojom::ResourceType>(resource_request.resource_type))); + DCHECK(ServiceWorkerUtils::IsMainRequestDestination( + resource_request.destination)); DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); resource_request_ = resource_request; @@ -133,7 +133,7 @@ void ServiceWorkerNavigationLoader::StartRequest( DCHECK(!url_loader_client_.is_bound()); receiver_.Bind(std::move(receiver)); receiver_.set_disconnect_handler( - base::BindOnce(&ServiceWorkerNavigationLoader::OnConnectionClosed, + base::BindOnce(&ServiceWorkerMainResourceLoader::OnConnectionClosed, base::Unretained(this))); url_loader_client_.Bind(std::move(client)); @@ -166,15 +166,18 @@ void ServiceWorkerNavigationLoader::StartRequest( blink::mojom::FetchAPIRequest::From(resource_request_), static_cast<blink::mojom::ResourceType>(resource_request_.resource_type), container_host_->client_uuid(), active_worker, - base::BindOnce(&ServiceWorkerNavigationLoader::DidPrepareFetchEvent, + base::BindOnce(&ServiceWorkerMainResourceLoader::DidPrepareFetchEvent, weak_factory_.GetWeakPtr(), active_worker, active_worker->running_status()), - base::BindOnce(&ServiceWorkerNavigationLoader::DidDispatchFetchEvent, + base::BindOnce(&ServiceWorkerMainResourceLoader::DidDispatchFetchEvent, weak_factory_.GetWeakPtr()), /*is_offline_capability_check=*/false); - did_navigation_preload_ = fetch_dispatcher_->MaybeStartNavigationPreload( - resource_request_, url_loader_factory_getter_.get(), std::move(context), - container_host_->frame_tree_node_id()); + + if (container_host_->IsContainerForWindowClient()) { + did_navigation_preload_ = fetch_dispatcher_->MaybeStartNavigationPreload( + resource_request_, url_loader_factory_getter_.get(), std::move(context), + container_host_->frame_tree_node_id()); + } // Record worker start time here as |fetch_dispatcher_| will start a service // worker if there is no running service worker. @@ -183,10 +186,10 @@ void ServiceWorkerNavigationLoader::StartRequest( fetch_dispatcher_->Run(); } -void ServiceWorkerNavigationLoader::CommitResponseHeaders() { +void ServiceWorkerMainResourceLoader::CommitResponseHeaders() { DCHECK(url_loader_client_.is_bound()); TRACE_EVENT_WITH_FLOW2( - "ServiceWorker", "ServiceWorkerNavigationLoader::CommitResponseHeaders", + "ServiceWorker", "ServiceWorkerMainResourceLoader::CommitResponseHeaders", this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "response_code", response_head_->headers->response_code(), "status_text", response_head_->headers->GetStatusText()); @@ -194,13 +197,13 @@ void ServiceWorkerNavigationLoader::CommitResponseHeaders() { url_loader_client_->OnReceiveResponse(response_head_.Clone()); } -void ServiceWorkerNavigationLoader::CommitResponseBody( +void ServiceWorkerMainResourceLoader::CommitResponseBody( mojo::ScopedDataPipeConsumerHandle response_body) { TransitionToStatus(Status::kSentBody); url_loader_client_->OnStartLoadingResponseBody(std::move(response_body)); } -void ServiceWorkerNavigationLoader::CommitEmptyResponseAndComplete() { +void ServiceWorkerMainResourceLoader::CommitEmptyResponseAndComplete() { mojo::ScopedDataPipeProducerHandle producer_handle; mojo::ScopedDataPipeConsumerHandle consumer_handle; if (CreateDataPipe(nullptr, &producer_handle, &consumer_handle) != @@ -215,10 +218,10 @@ void ServiceWorkerNavigationLoader::CommitEmptyResponseAndComplete() { CommitCompleted(net::OK, "No body exists."); } -void ServiceWorkerNavigationLoader::CommitCompleted(int error_code, - const char* reason) { +void ServiceWorkerMainResourceLoader::CommitCompleted(int error_code, + const char* reason) { TRACE_EVENT_WITH_FLOW2( - "ServiceWorker", "ServiceWorkerNavigationLoader::CommitCompleted", this, + "ServiceWorker", "ServiceWorkerMainResourceLoader::CommitCompleted", this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "error_code", net::ErrorToString(error_code), "reason", TRACE_STR_COPY(reason)); @@ -234,11 +237,11 @@ void ServiceWorkerNavigationLoader::CommitCompleted(int error_code, network::URLLoaderCompletionStatus(error_code)); } -void ServiceWorkerNavigationLoader::DidPrepareFetchEvent( +void ServiceWorkerMainResourceLoader::DidPrepareFetchEvent( scoped_refptr<ServiceWorkerVersion> version, EmbeddedWorkerStatus initial_worker_status) { TRACE_EVENT_WITH_FLOW1( - "ServiceWorker", "ServiceWorkerNavigationLoader::DidPrepareFetchEvent", + "ServiceWorker", "ServiceWorkerMainResourceLoader::DidPrepareFetchEvent", this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "initial_worker_status", EmbeddedWorkerInstance::StatusToString(initial_worker_status)); @@ -253,7 +256,7 @@ void ServiceWorkerNavigationLoader::DidPrepareFetchEvent( devtools_attached_ = version->embedded_worker()->devtools_attached(); } -void ServiceWorkerNavigationLoader::DidDispatchFetchEvent( +void ServiceWorkerMainResourceLoader::DidDispatchFetchEvent( blink::ServiceWorkerStatusCode status, ServiceWorkerFetchDispatcher::FetchEventResult fetch_result, blink::mojom::FetchAPIResponsePtr response, @@ -264,7 +267,7 @@ void ServiceWorkerNavigationLoader::DidDispatchFetchEvent( DCHECK_EQ(status_, Status::kStarted); TRACE_EVENT_WITH_FLOW2( - "ServiceWorker", "ServiceWorkerNavigationLoader::DidDispatchFetchEvent", + "ServiceWorker", "ServiceWorkerMainResourceLoader::DidDispatchFetchEvent", this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "status", blink::ServiceWorkerStatusToString(status), "result", ComposeFetchEventResultString(fetch_result, *response)); @@ -321,7 +324,7 @@ void ServiceWorkerNavigationLoader::DidDispatchFetchEvent( std::move(body_as_stream)); } -void ServiceWorkerNavigationLoader::StartResponse( +void ServiceWorkerMainResourceLoader::StartResponse( blink::mojom::FetchAPIResponsePtr response, scoped_refptr<ServiceWorkerVersion> version, blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream) { @@ -339,6 +342,10 @@ void ServiceWorkerNavigationLoader::StartResponse( response_head_->load_timing.receive_headers_end = response_head_->load_timing.receive_headers_start; response_source_ = response->response_source; + response_head_->load_timing.service_worker_fetch_start = + fetch_event_timing_->dispatch_event_time; + response_head_->load_timing.service_worker_respond_with_settled = + fetch_event_timing_->respond_with_settled_time; // Make the navigated page inherit the SSLInfo from its controller service // worker's script. This affects the HTTPS padlock, etc, shown by the @@ -355,7 +362,7 @@ void ServiceWorkerNavigationLoader::StartResponse( *response_head_); if (redirect_info) { TRACE_EVENT_WITH_FLOW2( - "ServiceWorker", "ServiceWorkerNavigationLoader::StartResponse", this, + "ServiceWorker", "ServiceWorkerMainResourceLoader::StartResponse", this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", "redirect", "redirect url", redirect_info->new_url.spec()); @@ -373,10 +380,10 @@ void ServiceWorkerNavigationLoader::StartResponse( // Handle a stream response body. if (!body_as_stream.is_null() && body_as_stream->stream.is_valid()) { - TRACE_EVENT_WITH_FLOW1("ServiceWorker", - "ServiceWorkerNavigationLoader::StartResponse", this, - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, - "result", "stream response"); + TRACE_EVENT_WITH_FLOW1( + "ServiceWorker", "ServiceWorkerMainResourceLoader::StartResponse", this, + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", + "stream response"); stream_waiter_ = std::make_unique<StreamWaiter>( this, std::move(body_as_stream->callback_receiver)); CommitResponseBody(std::move(body_as_stream->stream)); @@ -391,17 +398,17 @@ void ServiceWorkerNavigationLoader::StartResponse( mojo::ScopedDataPipeConsumerHandle data_pipe; int error = ServiceWorkerLoaderHelpers::ReadBlobResponseBody( &body_as_blob_, response->blob->size, - base::BindOnce(&ServiceWorkerNavigationLoader::OnBlobReadingComplete, + base::BindOnce(&ServiceWorkerMainResourceLoader::OnBlobReadingComplete, weak_factory_.GetWeakPtr()), &data_pipe); if (error != net::OK) { CommitCompleted(error, "Failed to read blob body"); return; } - TRACE_EVENT_WITH_FLOW1("ServiceWorker", - "ServiceWorkerNavigationLoader::StartResponse", this, - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, - "result", "blob response"); + TRACE_EVENT_WITH_FLOW1( + "ServiceWorker", "ServiceWorkerMainResourceLoader::StartResponse", this, + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", + "blob response"); CommitResponseBody(std::move(data_pipe)); // We continue in OnBlobReadingComplete(). @@ -409,7 +416,7 @@ void ServiceWorkerNavigationLoader::StartResponse( } TRACE_EVENT_WITH_FLOW1("ServiceWorker", - "ServiceWorkerNavigationLoader::StartResponse", this, + "ServiceWorkerMainResourceLoader::StartResponse", this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", "no body"); @@ -418,7 +425,7 @@ void ServiceWorkerNavigationLoader::StartResponse( // URLLoader implementation---------------------------------------- -void ServiceWorkerNavigationLoader::FollowRedirect( +void ServiceWorkerMainResourceLoader::FollowRedirect( const std::vector<std::string>& removed_headers, const net::HttpRequestHeaders& modified_headers, const net::HttpRequestHeaders& modified_cors_exempt_headers, @@ -426,23 +433,24 @@ void ServiceWorkerNavigationLoader::FollowRedirect( NOTIMPLEMENTED(); } -void ServiceWorkerNavigationLoader::SetPriority(net::RequestPriority priority, - int32_t intra_priority_value) { +void ServiceWorkerMainResourceLoader::SetPriority( + net::RequestPriority priority, + int32_t intra_priority_value) { NOTIMPLEMENTED(); } -void ServiceWorkerNavigationLoader::PauseReadingBodyFromNet() {} +void ServiceWorkerMainResourceLoader::PauseReadingBodyFromNet() {} -void ServiceWorkerNavigationLoader::ResumeReadingBodyFromNet() {} +void ServiceWorkerMainResourceLoader::ResumeReadingBodyFromNet() {} -void ServiceWorkerNavigationLoader::OnBlobReadingComplete(int net_error) { +void ServiceWorkerMainResourceLoader::OnBlobReadingComplete(int net_error) { CommitCompleted(net_error, "Blob has been read."); body_as_blob_.reset(); } -void ServiceWorkerNavigationLoader::OnConnectionClosed() { +void ServiceWorkerMainResourceLoader::OnConnectionClosed() { TRACE_EVENT_WITH_FLOW0( - "ServiceWorker", "ServiceWorkerNavigationLoader::OnConnectionClosed", + "ServiceWorker", "ServiceWorkerMainResourceLoader::OnConnectionClosed", this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); // The fetch dispatcher or stream waiter may still be running. Don't let them @@ -462,12 +470,12 @@ void ServiceWorkerNavigationLoader::OnConnectionClosed() { DeleteIfNeeded(); } -void ServiceWorkerNavigationLoader::DeleteIfNeeded() { +void ServiceWorkerMainResourceLoader::DeleteIfNeeded() { if (!receiver_.is_bound() && is_detached_) delete this; } -void ServiceWorkerNavigationLoader::RecordTimingMetrics(bool handled) { +void ServiceWorkerMainResourceLoader::RecordTimingMetrics(bool handled) { DCHECK(fetch_event_timing_); DCHECK(!completion_time_.is_null()); @@ -543,7 +551,7 @@ void ServiceWorkerNavigationLoader::RecordTimingMetrics(bool handled) { } } -void ServiceWorkerNavigationLoader::TransitionToStatus(Status new_status) { +void ServiceWorkerMainResourceLoader::TransitionToStatus(Status new_status) { #if DCHECK_IS_ON() switch (new_status) { case Status::kNotStarted: @@ -577,11 +585,12 @@ void ServiceWorkerNavigationLoader::TransitionToStatus(Status new_status) { completion_time_ = base::TimeTicks::Now(); } -ServiceWorkerNavigationLoaderWrapper::ServiceWorkerNavigationLoaderWrapper( - std::unique_ptr<ServiceWorkerNavigationLoader> loader) +ServiceWorkerMainResourceLoaderWrapper::ServiceWorkerMainResourceLoaderWrapper( + std::unique_ptr<ServiceWorkerMainResourceLoader> loader) : loader_(std::move(loader)) {} -ServiceWorkerNavigationLoaderWrapper::~ServiceWorkerNavigationLoaderWrapper() { +ServiceWorkerMainResourceLoaderWrapper:: + ~ServiceWorkerMainResourceLoaderWrapper() { if (loader_) loader_.release()->DetachedFromRequest(); } diff --git a/chromium/content/browser/service_worker/service_worker_navigation_loader.h b/chromium/content/browser/service_worker/service_worker_main_resource_loader.h index 76796bb0b98..48ebd466b30 100644 --- a/chromium/content/browser/service_worker/service_worker_navigation_loader.h +++ b/chromium/content/browser/service_worker/service_worker_main_resource_loader.h @@ -2,8 +2,8 @@ // 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_H_ -#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_NAVIGATION_LOADER_H_ +#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_MAIN_RESOURCE_LOADER_H_ +#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_MAIN_RESOURCE_LOADER_H_ #include <memory> #include <string> @@ -32,7 +32,7 @@ namespace content { class ServiceWorkerContainerHost; class ServiceWorkerVersion; -// ServiceWorkerNavigationLoader is the URLLoader used for main resource +// ServiceWorkerMainResourceLoader is the URLLoader used for main resource // requests (i.e., navigation and shared worker requests) that go through a // service worker. This loader is only used for the main resource request; once // the response is delivered, the resulting client loads subresources via @@ -41,7 +41,7 @@ class ServiceWorkerVersion; // This class is owned by ServiceWorkerControlleeRequestHandler until it is // bound to a URLLoader request. After it is bound |this| is kept alive until // the Mojo connection to this URLLoader is dropped. -class CONTENT_EXPORT ServiceWorkerNavigationLoader +class CONTENT_EXPORT ServiceWorkerMainResourceLoader : public network::mojom::URLLoader { public: // Created by ServiceWorkerControlleeRequestHandler @@ -49,7 +49,7 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoader // // For the navigation case, this job typically works in the following order: // 1. ServiceWorkerControlleeRequestHandler::MaybeCreateLoader() creates the - // ServiceWorkerNavigationLoader, passing StartRequest() as the + // ServiceWorkerMainResourceLoader, passing StartRequest() as the // RequestHandler. // 2. At this point, the NavigationURLLoaderImpl can throttle the request, // and invoke the RequestHandler later with a possibly modified request. @@ -65,12 +65,12 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoader // // Loads for shared workers work similarly, except SharedWorkerScriptLoader // is used instead of NavigationURLLoaderImpl. - ServiceWorkerNavigationLoader( + ServiceWorkerMainResourceLoader( NavigationLoaderInterceptor::FallbackCallback fallback_callback, base::WeakPtr<ServiceWorkerContainerHost> container_host, scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter); - ~ServiceWorkerNavigationLoader() override; + ~ServiceWorkerMainResourceLoader() override; // Passed as the RequestHandler for // NavigationLoaderInterceptor::MaybeCreateLoader. @@ -86,7 +86,7 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoader // endpoint is held by the client. void DetachedFromRequest(); - base::WeakPtr<ServiceWorkerNavigationLoader> AsWeakPtr(); + base::WeakPtr<ServiceWorkerMainResourceLoader> AsWeakPtr(); private: class StreamWaiter; @@ -186,26 +186,26 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoader Status status_ = Status::kNotStarted; bool is_detached_ = false; - base::WeakPtrFactory<ServiceWorkerNavigationLoader> weak_factory_{this}; + base::WeakPtrFactory<ServiceWorkerMainResourceLoader> weak_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(ServiceWorkerNavigationLoader); + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerMainResourceLoader); }; // Owns a loader and calls DetachedFromRequest() to release it. -class ServiceWorkerNavigationLoaderWrapper { +class ServiceWorkerMainResourceLoaderWrapper { public: - explicit ServiceWorkerNavigationLoaderWrapper( - std::unique_ptr<ServiceWorkerNavigationLoader> loader); - ~ServiceWorkerNavigationLoaderWrapper(); + explicit ServiceWorkerMainResourceLoaderWrapper( + std::unique_ptr<ServiceWorkerMainResourceLoader> loader); + ~ServiceWorkerMainResourceLoaderWrapper(); - ServiceWorkerNavigationLoader* get() { return loader_.get(); } + ServiceWorkerMainResourceLoader* get() { return loader_.get(); } private: - std::unique_ptr<ServiceWorkerNavigationLoader> loader_; + std::unique_ptr<ServiceWorkerMainResourceLoader> loader_; - DISALLOW_COPY_AND_ASSIGN(ServiceWorkerNavigationLoaderWrapper); + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerMainResourceLoaderWrapper); }; } // namespace content -#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_NAVIGATION_LOADER_H_ +#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_MAIN_RESOURCE_LOADER_H_ diff --git a/chromium/content/browser/service_worker/service_worker_navigation_loader_interceptor.cc b/chromium/content/browser/service_worker/service_worker_main_resource_loader_interceptor.cc index 23166ec06e5..701b8f9d0ec 100644 --- a/chromium/content/browser/service_worker/service_worker_navigation_loader_interceptor.cc +++ b/chromium/content/browser/service_worker/service_worker_main_resource_loader_interceptor.cc @@ -2,7 +2,7 @@ // 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 "content/browser/service_worker/service_worker_main_resource_loader_interceptor.h" #include <memory> #include <utility> @@ -17,7 +17,6 @@ #include "content/browser/service_worker/service_worker_controllee_request_handler.h" #include "content/browser/service_worker/service_worker_main_resource_handle.h" #include "content/browser/service_worker/service_worker_main_resource_handle_core.h" -#include "content/browser/service_worker/service_worker_provider_host.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/common/origin_util.h" #include "content/public/common/url_constants.h" @@ -33,7 +32,7 @@ namespace { void LoaderCallbackWrapperOnCoreThread( ServiceWorkerMainResourceHandleCore* handle_core, - base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor> interceptor_on_ui, + base::WeakPtr<ServiceWorkerMainResourceLoaderInterceptor> interceptor_on_ui, NavigationLoaderInterceptor::LoaderCallback loader_callback, SingleRequestURLLoaderFactory::RequestHandler handler) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); @@ -47,13 +46,13 @@ void LoaderCallbackWrapperOnCoreThread( RunOrPostTaskOnThread( FROM_HERE, BrowserThread::UI, base::BindOnce( - &ServiceWorkerNavigationLoaderInterceptor::LoaderCallbackWrapper, + &ServiceWorkerMainResourceLoaderInterceptor::LoaderCallbackWrapper, interceptor_on_ui, std::move(subresource_loader_params), std::move(loader_callback), std::move(handler))); } void FallbackCallbackWrapperOnCoreThread( - base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor> interceptor_on_ui, + base::WeakPtr<ServiceWorkerMainResourceLoaderInterceptor> interceptor_on_ui, NavigationLoaderInterceptor::FallbackCallback fallback_callback, bool reset_subresource_loader_params) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); @@ -61,7 +60,7 @@ void FallbackCallbackWrapperOnCoreThread( RunOrPostTaskOnThread( FROM_HERE, BrowserThread::UI, base::BindOnce( - &ServiceWorkerNavigationLoaderInterceptor::FallbackCallbackWrapper, + &ServiceWorkerMainResourceLoaderInterceptor::FallbackCallbackWrapper, interceptor_on_ui, std::move(fallback_callback), reset_subresource_loader_params)); } @@ -79,7 +78,7 @@ void InvokeRequestHandlerOnCoreThread( // Does setup on the the core thread and calls back to // |interceptor_on_ui->LoaderCallbackWrapper()| on the UI thread. void MaybeCreateLoaderOnCoreThread( - base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor> interceptor_on_ui, + base::WeakPtr<ServiceWorkerMainResourceLoaderInterceptor> interceptor_on_ui, ServiceWorkerMainResourceHandleCore* handle_core, blink::mojom::ResourceType resource_type, bool skip_service_worker, @@ -114,7 +113,7 @@ void MaybeCreateLoaderOnCoreThread( if (!handle_core->container_host()) { // This is the initial request before redirects, so make the container host. - // Its lifetime is tied to the |provider_info| in the + // Its lifetime is tied to the |container_info| in the // ServiceWorkerMainResourceHandle on the UI thread and which will be passed // to the renderer when the navigation commits. DCHECK(host_receiver); @@ -129,13 +128,15 @@ void MaybeCreateLoaderOnCoreThread( } else { DCHECK(resource_type == blink::mojom::ResourceType::kWorker || resource_type == blink::mojom::ResourceType::kSharedWorker); - auto client_type = + + ServiceWorkerClientInfo client_info = resource_type == blink::mojom::ResourceType::kWorker - ? blink::mojom::ServiceWorkerClientType::kDedicatedWorker - : blink::mojom::ServiceWorkerClientType::kSharedWorker; + ? ServiceWorkerClientInfo(dedicated_worker_id) + : ServiceWorkerClientInfo(shared_worker_id); + container_host = context_core->CreateContainerHostForWorker( std::move(host_receiver), process_id, std::move(client_remote), - client_type, dedicated_worker_id, shared_worker_id); + client_info); } DCHECK(container_host); handle_core->set_container_host(container_host); @@ -182,8 +183,8 @@ bool SchemeMaySupportRedirectingToHTTPS(const GURL& url) { #endif // OS_CHROMEOS } -// Returns true if a ServiceWorkerNavigationLoaderInterceptor should be created -// for a worker with this |url|. +// Returns true if a ServiceWorkerMainResourceLoaderInterceptor should be +// created for a worker with this |url|. bool ShouldCreateForWorker(const GURL& url) { // Create the handler even for insecure HTTP since it's used in the // case of redirect to HTTPS. @@ -195,28 +196,29 @@ bool ShouldCreateForWorker(const GURL& url) { } // namespace std::unique_ptr<NavigationLoaderInterceptor> -ServiceWorkerNavigationLoaderInterceptor::CreateForNavigation( +ServiceWorkerMainResourceLoaderInterceptor::CreateForNavigation( const GURL& url, base::WeakPtr<ServiceWorkerMainResourceHandle> navigation_handle, const NavigationRequestInfo& request_info) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (!ShouldCreateForNavigation(url)) + if (!ShouldCreateForNavigation( + url, request_info.begin_params->request_destination)) { return nullptr; + } - return std::unique_ptr<ServiceWorkerNavigationLoaderInterceptor>( - new ServiceWorkerNavigationLoaderInterceptor( - std::move(navigation_handle), - request_info.is_main_frame ? blink::mojom::ResourceType::kMainFrame - : blink::mojom::ResourceType::kSubFrame, - request_info.begin_params->skip_service_worker, - request_info.are_ancestors_secure, request_info.frame_tree_node_id, - ChildProcessHost::kInvalidUniqueID, DedicatedWorkerId(), - SharedWorkerId())); + return base::WrapUnique(new ServiceWorkerMainResourceLoaderInterceptor( + std::move(navigation_handle), + request_info.is_main_frame ? blink::mojom::ResourceType::kMainFrame + : blink::mojom::ResourceType::kSubFrame, + request_info.begin_params->skip_service_worker, + request_info.are_ancestors_secure, request_info.frame_tree_node_id, + ChildProcessHost::kInvalidUniqueID, DedicatedWorkerId(), + SharedWorkerId())); } std::unique_ptr<NavigationLoaderInterceptor> -ServiceWorkerNavigationLoaderInterceptor::CreateForWorker( +ServiceWorkerMainResourceLoaderInterceptor::CreateForWorker( const network::ResourceRequest& resource_request, int process_id, DedicatedWorkerId dedicated_worker_id, @@ -235,20 +237,19 @@ ServiceWorkerNavigationLoaderInterceptor::CreateForWorker( if (!ShouldCreateForWorker(resource_request.url)) return nullptr; - return std::unique_ptr<ServiceWorkerNavigationLoaderInterceptor>( - new ServiceWorkerNavigationLoaderInterceptor( - std::move(navigation_handle), resource_type, - resource_request.skip_service_worker, /*are_ancestors_secure=*/false, - FrameTreeNode::kFrameTreeNodeInvalidId, process_id, - dedicated_worker_id, shared_worker_id)); + return base::WrapUnique(new ServiceWorkerMainResourceLoaderInterceptor( + std::move(navigation_handle), resource_type, + resource_request.skip_service_worker, /*are_ancestors_secure=*/false, + FrameTreeNode::kFrameTreeNodeInvalidId, process_id, dedicated_worker_id, + shared_worker_id)); } -ServiceWorkerNavigationLoaderInterceptor:: - ~ServiceWorkerNavigationLoaderInterceptor() { +ServiceWorkerMainResourceLoaderInterceptor:: + ~ServiceWorkerMainResourceLoaderInterceptor() { DCHECK_CURRENTLY_ON(BrowserThread::UI); } -void ServiceWorkerNavigationLoaderInterceptor::MaybeCreateLoader( +void ServiceWorkerMainResourceLoaderInterceptor::MaybeCreateLoader( const network::ResourceRequest& tentative_resource_request, BrowserContext* browser_context, LoaderCallback loader_callback, @@ -261,23 +262,23 @@ void ServiceWorkerNavigationLoaderInterceptor::MaybeCreateLoader( mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerContainer> client_remote; - // If this is the first request before redirects, a provider info has not yet + // If this is the first request before redirects, a container info has not yet // been created. - if (!handle_->has_provider_info()) { - auto provider_info = - blink::mojom::ServiceWorkerProviderInfoForClient::New(); + if (!handle_->has_container_info()) { + auto container_info = + blink::mojom::ServiceWorkerContainerInfoForClient::New(); host_receiver = - provider_info->host_remote.InitWithNewEndpointAndPassReceiver(); - provider_info->client_receiver = + container_info->host_remote.InitWithNewEndpointAndPassReceiver(); + container_info->client_receiver = client_remote.InitWithNewEndpointAndPassReceiver(); - handle_->OnCreatedProviderHost(std::move(provider_info)); + handle_->OnCreatedContainerHost(std::move(container_info)); } bool initialize_container_host_only = false; LoaderCallback original_callback; if (!ServiceWorkerContext::IsServiceWorkerOnUIEnabled() && - !handle_->context_wrapper()->HasRegistrationForOrigin( - tentative_resource_request.url.GetOrigin())) { + !handle_->context_wrapper()->MaybeHasRegistrationForOrigin( + url::Origin::Create(tentative_resource_request.url))) { // We have no registrations, so it's safe to continue the request now // without blocking on the IO thread. Give a dummy callback to the // IO thread interceptor, and we'll run the original callback immediately @@ -306,12 +307,13 @@ void ServiceWorkerNavigationLoaderInterceptor::MaybeCreateLoader( } base::Optional<SubresourceLoaderParams> -ServiceWorkerNavigationLoaderInterceptor::MaybeCreateSubresourceLoaderParams() { +ServiceWorkerMainResourceLoaderInterceptor:: + MaybeCreateSubresourceLoaderParams() { DCHECK_CURRENTLY_ON(BrowserThread::UI); return std::move(subresource_loader_params_); } -void ServiceWorkerNavigationLoaderInterceptor::LoaderCallbackWrapper( +void ServiceWorkerMainResourceLoaderInterceptor::LoaderCallbackWrapper( base::Optional<SubresourceLoaderParams> subresource_loader_params, LoaderCallback loader_callback, SingleRequestURLLoaderFactory::RequestHandler handler_on_core_thread) { @@ -339,25 +341,25 @@ void ServiceWorkerNavigationLoaderInterceptor::LoaderCallbackWrapper( // wrapper to the loader callback. std::move(loader_callback) .Run(base::MakeRefCounted<SingleRequestURLLoaderFactory>(base::BindOnce( - &ServiceWorkerNavigationLoaderInterceptor::RequestHandlerWrapper, + &ServiceWorkerMainResourceLoaderInterceptor::RequestHandlerWrapper, GetWeakPtr(), std::move(handler_on_core_thread)))); } -void ServiceWorkerNavigationLoaderInterceptor::FallbackCallbackWrapper( +void ServiceWorkerMainResourceLoaderInterceptor::FallbackCallbackWrapper( FallbackCallback fallback_callback, bool reset_subresource_loader_params) { DCHECK_CURRENTLY_ON(BrowserThread::UI); std::move(fallback_callback).Run(reset_subresource_loader_params); } -base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor> -ServiceWorkerNavigationLoaderInterceptor::GetWeakPtr() { +base::WeakPtr<ServiceWorkerMainResourceLoaderInterceptor> +ServiceWorkerMainResourceLoaderInterceptor::GetWeakPtr() { DCHECK_CURRENTLY_ON(BrowserThread::UI); return weak_factory_.GetWeakPtr(); } -ServiceWorkerNavigationLoaderInterceptor:: - ServiceWorkerNavigationLoaderInterceptor( +ServiceWorkerMainResourceLoaderInterceptor:: + ServiceWorkerMainResourceLoaderInterceptor( base::WeakPtr<ServiceWorkerMainResourceHandle> handle, blink::mojom::ResourceType resource_type, bool skip_service_worker, @@ -379,15 +381,23 @@ ServiceWorkerNavigationLoaderInterceptor:: } // static -bool ServiceWorkerNavigationLoaderInterceptor::ShouldCreateForNavigation( - const GURL& url) { +bool ServiceWorkerMainResourceLoaderInterceptor::ShouldCreateForNavigation( + const GURL& url, + network::mojom::RequestDestination request_destination) { + // <embed> and <object> navigations must bypass the service worker, per the + // discussion in https://w3c.github.io/ServiceWorker/#implementer-concerns. + if (request_destination == network::mojom::RequestDestination::kEmbed || + request_destination == network::mojom::RequestDestination::kObject) { + return false; + } + // Create the handler even for insecure HTTP since it's used in the // case of redirect to HTTPS. return url.SchemeIsHTTPOrHTTPS() || OriginCanAccessServiceWorkers(url) || SchemeMaySupportRedirectingToHTTPS(url); } -void ServiceWorkerNavigationLoaderInterceptor::RequestHandlerWrapper( +void ServiceWorkerMainResourceLoaderInterceptor::RequestHandlerWrapper( SingleRequestURLLoaderFactory::RequestHandler handler_on_core_thread, const network::ResourceRequest& resource_request, mojo::PendingReceiver<network::mojom::URLLoader> receiver, diff --git a/chromium/content/browser/service_worker/service_worker_navigation_loader_interceptor.h b/chromium/content/browser/service_worker/service_worker_main_resource_loader_interceptor.h index f6afa906886..692ce5a5495 100644 --- a/chromium/content/browser/service_worker/service_worker_navigation_loader_interceptor.h +++ b/chromium/content/browser/service_worker/service_worker_main_resource_loader_interceptor.h @@ -2,8 +2,8 @@ // 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_ +#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_MAIN_RESOURCE_LOADER_INTERCEPTOR_H_ +#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_MAIN_RESOURCE_LOADER_INTERCEPTOR_H_ #include <memory> @@ -33,17 +33,17 @@ struct NavigationRequestInfo; // The corresponding legacy class is ServiceWorkerControlleeRequestHandler which // lives on the service worker context core thread. Currently, this class just // delegates to the legacy class by posting tasks to it on the core thread. -class CONTENT_EXPORT ServiceWorkerNavigationLoaderInterceptor final +class CONTENT_EXPORT ServiceWorkerMainResourceLoaderInterceptor final : public NavigationLoaderInterceptor { public: - // Creates a ServiceWorkerNavigationLoaderInterceptor for a navigation. + // Creates a ServiceWorkerMainResourceLoaderInterceptor for a navigation. // Returns nullptr if the interceptor could not be created for this |url|. static std::unique_ptr<NavigationLoaderInterceptor> CreateForNavigation( const GURL& url, base::WeakPtr<ServiceWorkerMainResourceHandle> navigation_handle, const NavigationRequestInfo& request_info); - // Creates a ServiceWorkerNavigationLoaderInterceptor for a worker. + // Creates a ServiceWorkerMainResourceLoaderInterceptor for a worker. // Returns nullptr if the interceptor could not be created for the URL of the // worker. static std::unique_ptr<NavigationLoaderInterceptor> CreateForWorker( @@ -53,7 +53,7 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoaderInterceptor final SharedWorkerId shared_worker_id, base::WeakPtr<ServiceWorkerMainResourceHandle> navigation_handle); - ~ServiceWorkerNavigationLoaderInterceptor() override; + ~ServiceWorkerMainResourceLoaderInterceptor() override; // NavigationLoaderInterceptor overrides: @@ -78,12 +78,12 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoaderInterceptor final void FallbackCallbackWrapper(FallbackCallback fallback_callback, bool reset_subresource_loader_params); - base::WeakPtr<ServiceWorkerNavigationLoaderInterceptor> GetWeakPtr(); + base::WeakPtr<ServiceWorkerMainResourceLoaderInterceptor> GetWeakPtr(); private: - friend class ServiceWorkerNavigationLoaderInterceptorTest; + friend class ServiceWorkerMainResourceLoaderInterceptorTest; - ServiceWorkerNavigationLoaderInterceptor( + ServiceWorkerMainResourceLoaderInterceptor( base::WeakPtr<ServiceWorkerMainResourceHandle> handle, blink::mojom::ResourceType resource_type, bool skip_service_worker, @@ -93,9 +93,11 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoaderInterceptor final DedicatedWorkerId dedicated_worker_id, SharedWorkerId shared_worker_id); - // Returns true if a ServiceWorkerNavigationLoaderInterceptor should be + // Returns true if a ServiceWorkerMainResourceLoaderInterceptor should be // created for a navigation to |url|. - static bool ShouldCreateForNavigation(const GURL& url); + static bool ShouldCreateForNavigation( + const GURL& url, + network::mojom::RequestDestination request_destination); // Given as a callback to NavigationURLLoaderImpl. void RequestHandlerWrapper( @@ -129,12 +131,12 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoaderInterceptor final base::Optional<SubresourceLoaderParams> subresource_loader_params_; - base::WeakPtrFactory<ServiceWorkerNavigationLoaderInterceptor> weak_factory_{ - this}; + base::WeakPtrFactory<ServiceWorkerMainResourceLoaderInterceptor> + weak_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(ServiceWorkerNavigationLoaderInterceptor); + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerMainResourceLoaderInterceptor); }; } // namespace content -#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_NAVIGATION_LOADER_INTERCEPTOR_H_ +#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_MAIN_RESOURCE_LOADER_INTERCEPTOR_H_ diff --git a/chromium/content/browser/service_worker/service_worker_main_resource_loader_interceptor_unittest.cc b/chromium/content/browser/service_worker/service_worker_main_resource_loader_interceptor_unittest.cc new file mode 100644 index 00000000000..d76725acb7d --- /dev/null +++ b/chromium/content/browser/service_worker/service_worker_main_resource_loader_interceptor_unittest.cc @@ -0,0 +1,79 @@ +// Copyright 2020 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_main_resource_loader_interceptor.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace content { + +class ServiceWorkerMainResourceLoaderInterceptorTest : public testing::Test { + public: + bool ShouldCreateForNavigation( + const GURL& url, + network::mojom::RequestDestination request_destination) { + return ServiceWorkerMainResourceLoaderInterceptor:: + ShouldCreateForNavigation(url, request_destination); + } +}; + +TEST_F(ServiceWorkerMainResourceLoaderInterceptorTest, + ShouldCreateForNavigation_HTTP) { + EXPECT_TRUE( + ShouldCreateForNavigation(GURL("http://host/scope/doc"), + network::mojom::RequestDestination::kDocument)); + EXPECT_FALSE( + ShouldCreateForNavigation(GURL("http://host/scope/doc"), + network::mojom::RequestDestination::kEmbed)); + EXPECT_FALSE( + ShouldCreateForNavigation(GURL("http://host/scope/doc"), + network::mojom::RequestDestination::kObject)); +} + +TEST_F(ServiceWorkerMainResourceLoaderInterceptorTest, + ShouldCreateForNavigation_HTTPS) { + EXPECT_TRUE( + ShouldCreateForNavigation(GURL("https://host/scope/doc"), + network::mojom::RequestDestination::kDocument)); + EXPECT_FALSE( + ShouldCreateForNavigation(GURL("https://host/scope/doc"), + network::mojom::RequestDestination::kEmbed)); + EXPECT_FALSE( + ShouldCreateForNavigation(GURL("https://host/scope/doc"), + network::mojom::RequestDestination::kObject)); +} + +TEST_F(ServiceWorkerMainResourceLoaderInterceptorTest, + ShouldCreateForNavigation_FTP) { + EXPECT_FALSE( + ShouldCreateForNavigation(GURL("ftp://host/scope/doc"), + network::mojom::RequestDestination::kDocument)); + EXPECT_FALSE( + ShouldCreateForNavigation(GURL("ftp://host/scope/doc"), + network::mojom::RequestDestination::kEmbed)); + EXPECT_FALSE( + ShouldCreateForNavigation(GURL("ftp://host/scope/doc"), + network::mojom::RequestDestination::kObject)); +} + +TEST_F(ServiceWorkerMainResourceLoaderInterceptorTest, + ShouldCreateForNavigation_ExternalFileScheme) { + bool expected_handler_created = false; +#if defined(OS_CHROMEOS) + expected_handler_created = true; +#endif // OS_CHROMEOS + EXPECT_EQ( + expected_handler_created, + ShouldCreateForNavigation(GURL("externalfile:drive/doc"), + network::mojom::RequestDestination::kDocument)); + EXPECT_FALSE( + ShouldCreateForNavigation(GURL("externalfile:drive/doc"), + network::mojom::RequestDestination::kEmbed)); + EXPECT_FALSE( + ShouldCreateForNavigation(GURL("externalfile:drive/doc"), + network::mojom::RequestDestination::kObject)); +} + +} // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_navigation_loader_unittest.cc b/chromium/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc index a8b46fb282f..7c54afa69ab 100644 --- a/chromium/content/browser/service_worker/service_worker_navigation_loader_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc @@ -2,7 +2,7 @@ // 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.h" +#include "content/browser/service_worker/service_worker_main_resource_loader.h" #include <string> #include <utility> @@ -44,7 +44,7 @@ #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h" namespace content { -namespace service_worker_navigation_loader_unittest { +namespace service_worker_main_resource_loader_unittest { void ReceiveRequestHandler( SingleRequestURLLoaderFactory::RequestHandler* out_handler, @@ -53,11 +53,17 @@ void ReceiveRequestHandler( } blink::mojom::FetchAPIResponsePtr OkResponse( - blink::mojom::SerializedBlobPtr blob_body) { + blink::mojom::SerializedBlobPtr blob_body, + network::mojom::FetchResponseSource response_source, + base::Time response_time, + std::string cache_storage_cache_name) { auto response = blink::mojom::FetchAPIResponse::New(); response->status_code = 200; response->status_text = "OK"; response->response_type = network::mojom::FetchResponseType::kDefault; + response->response_source = response_source; + response->response_time = response_time; + response->cache_storage_cache_name = cache_storage_cache_name; response->blob = std::move(blob_body); if (response->blob) { response->headers.emplace("Content-Length", @@ -169,7 +175,8 @@ class FetchEventServiceWorker : public FakeServiceWorker { void DeferResponse() { response_mode_ = ResponseMode::kDeferredResponse; } void FinishRespondWith() { response_callback_->OnResponse( - OkResponse(nullptr /* blob_body */), + OkResponse(nullptr /* blob_body */, response_source_, response_time_, + cache_storage_cache_name_), blink::mojom::ServiceWorkerFetchEventTiming::New()); response_callback_.FlushForTesting(); std::move(finish_callback_) @@ -195,6 +202,16 @@ class FetchEventServiceWorker : public FakeServiceWorker { run_loop.Run(); } + void SetResponseSource(network::mojom::FetchResponseSource source) { + response_source_ = source; + } + + void SetCacheStorageCacheName(std::string cache_name) { + cache_storage_cache_name_ = cache_name; + } + + void SetResponseTime(base::Time time) { response_time_ = time; } + protected: void DispatchFetchEventForMainResource( blink::mojom::DispatchFetchEventParamsPtr params, @@ -209,6 +226,11 @@ class FetchEventServiceWorker : public FakeServiceWorker { if (params->request->body) request_body_ = params->request->body; + auto timing = blink::mojom::ServiceWorkerFetchEventTiming::New(); + auto now = base::TimeTicks::Now(); + timing->dispatch_event_time = now; + timing->respond_with_settled_time = now; + mojo::Remote<blink::mojom::ServiceWorkerFetchResponseCallback> response_callback(std::move(pending_response_callback)); switch (response_mode_) { @@ -219,35 +241,35 @@ class FetchEventServiceWorker : public FakeServiceWorker { break; case ResponseMode::kBlob: response_callback->OnResponse( - OkResponse(std::move(blob_body_)), - blink::mojom::ServiceWorkerFetchEventTiming::New()); + OkResponse(std::move(blob_body_), response_source_, response_time_, + cache_storage_cache_name_), + std::move(timing)); std::move(finish_callback) .Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED); break; case ResponseMode::kStream: response_callback->OnResponseStream( - OkResponse(nullptr /* blob_body */), std::move(stream_handle_), - blink::mojom::ServiceWorkerFetchEventTiming::New()); + OkResponse(nullptr /* blob_body */, response_source_, + response_time_, cache_storage_cache_name_), + std::move(stream_handle_), std::move(timing)); + std::move(finish_callback) .Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED); break; case ResponseMode::kFallbackResponse: - response_callback->OnFallback( - blink::mojom::ServiceWorkerFetchEventTiming::New()); + response_callback->OnFallback(std::move(timing)); std::move(finish_callback) .Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED); break; case ResponseMode::kErrorResponse: - response_callback->OnResponse( - ErrorResponse(), - blink::mojom::ServiceWorkerFetchEventTiming::New()); + response_callback->OnResponse(ErrorResponse(), std::move(timing)); std::move(finish_callback) .Run(blink::mojom::ServiceWorkerEventStatus::REJECTED); break; case ResponseMode::kFailFetchEventDispatch: // Simulate failure by stopping the worker before the event finishes. // This causes ServiceWorkerVersion::StartRequest() to call its error - // callback, which triggers ServiceWorkerNavigationLoader's dispatch + // callback, which triggers ServiceWorkerMainResourceLoader's dispatch // failed behavior. embedded_worker_instance_client_->host()->OnStopped(); @@ -268,21 +290,20 @@ class FetchEventServiceWorker : public FakeServiceWorker { case ResponseMode::kEarlyResponse: finish_callback_ = std::move(finish_callback); response_callback->OnResponse( - OkResponse(nullptr /* blob_body */), - blink::mojom::ServiceWorkerFetchEventTiming::New()); + OkResponse(nullptr /* blob_body */, response_source_, + response_time_, cache_storage_cache_name_), + std::move(timing)); // Now the caller must call FinishWaitUntil() to finish the event. break; case ResponseMode::kRedirect: - response_callback->OnResponse( - RedirectResponse(redirected_url_.spec()), - blink::mojom::ServiceWorkerFetchEventTiming::New()); + response_callback->OnResponse(RedirectResponse(redirected_url_.spec()), + std::move(timing)); std::move(finish_callback) .Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED); break; case ResponseMode::kHeaders: - response_callback->OnResponse( - HeadersResponse(headers_), - blink::mojom::ServiceWorkerFetchEventTiming::New()); + response_callback->OnResponse(HeadersResponse(headers_), + std::move(timing)); std::move(finish_callback) .Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED); break; @@ -332,6 +353,12 @@ class FetchEventServiceWorker : public FakeServiceWorker { FakeEmbeddedWorkerInstanceClient* const embedded_worker_instance_client_; + network::mojom::FetchResponseSource response_source_ = + network::mojom::FetchResponseSource::kUnspecified; + + std::string cache_storage_cache_name_; + base::Time response_time_; + DISALLOW_COPY_AND_ASSIGN(FetchEventServiceWorker); }; @@ -343,7 +370,6 @@ network::mojom::URLResponseHeadPtr CreateResponseInfoFromServiceWorker() { head->was_fallback_required_by_service_worker = false; head->url_list_via_service_worker = std::vector<GURL>(); head->response_type = network::mojom::FetchResponseType::kDefault; - head->is_in_cache_storage = false; head->cache_storage_cache_name = std::string(); head->did_service_worker_navigation_preload = false; return head; @@ -352,17 +378,17 @@ network::mojom::URLResponseHeadPtr CreateResponseInfoFromServiceWorker() { const char kHistogramMainResourceFetchEvent[] = "ServiceWorker.FetchEvent.MainResource.Status"; -// ServiceWorkerNavigationLoaderTest is for testing the handling of requests -// by a service worker via ServiceWorkerNavigationLoader. +// ServiceWorkerMainResourceLoaderTest is for testing the handling of requests +// by a service worker via ServiceWorkerMainResourceLoader. // // Of course, no actual service worker runs in the unit test, it is simulated // via EmbeddedWorkerTestHelper receiving IPC messages from the browser and // responding as if a service worker is running in the renderer. -class ServiceWorkerNavigationLoaderTest : public testing::Test { +class ServiceWorkerMainResourceLoaderTest : public testing::Test { public: - ServiceWorkerNavigationLoaderTest() + ServiceWorkerMainResourceLoaderTest() : task_environment_(BrowserTaskEnvironment::IO_MAINLOOP) {} - ~ServiceWorkerNavigationLoaderTest() override = default; + ~ServiceWorkerMainResourceLoaderTest() override = default; void SetUp() override { helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath()); @@ -420,7 +446,7 @@ class ServiceWorkerNavigationLoaderTest : public testing::Test { container_host_ = CreateContainerHostForWindow( helper_->mock_render_process_id(), /*is_parent_frame_secure=*/true, helper_->context()->AsWeakPtr(), - &provider_endpoints_); + &container_endpoints_); container_host_->UpdateUrls(request->url, net::SiteForCookies::FromUrl(request->url), url::Origin::Create(request->url)); @@ -429,9 +455,9 @@ class ServiceWorkerNavigationLoaderTest : public testing::Test { registration_, /*notify_controllerchange=*/false); } - // Create a ServiceWorkerNavigationLoader. - loader_ = std::make_unique<ServiceWorkerNavigationLoader>( - base::BindOnce(&ServiceWorkerNavigationLoaderTest::Fallback, + // Create a ServiceWorkerMainResourceLoader. + loader_ = std::make_unique<ServiceWorkerMainResourceLoader>( + base::BindOnce(&ServiceWorkerMainResourceLoaderTest::Fallback, base::Unretained(this)), container_host_, base::WrapRefCounted<URLLoaderFactoryGetter>( @@ -442,7 +468,7 @@ class ServiceWorkerNavigationLoaderTest : public testing::Test { client_.CreateRemote()); } - // The |fallback_callback| passed to the ServiceWorkerNavigationLoader in + // The |fallback_callback| passed to the ServiceWorkerMainResourceLoader in // StartRequest(). void Fallback(bool reset_subresource_loader_params) { did_call_fallback_callback_ = true; @@ -451,7 +477,7 @@ class ServiceWorkerNavigationLoaderTest : public testing::Test { std::move(quit_closure_for_fallback_callback_).Run(); } - // Runs until the ServiceWorkerNavigationLoader created in StartRequest() + // Runs until the ServiceWorkerMainResourceLoader created in StartRequest() // calls the |fallback_callback| given to it. The argument passed to // |fallback_callback| is saved in |reset_subresurce_loader_params_|. void RunUntilFallbackCallback() { @@ -472,11 +498,20 @@ class ServiceWorkerNavigationLoaderTest : public testing::Test { EXPECT_EQ(expected_info.url_list_via_service_worker, info.url_list_via_service_worker); EXPECT_EQ(expected_info.response_type, info.response_type); + EXPECT_EQ(expected_info.response_time, info.response_time); EXPECT_FALSE(info.load_timing.service_worker_start_time.is_null()); EXPECT_FALSE(info.load_timing.service_worker_ready_time.is_null()); + EXPECT_FALSE(info.load_timing.service_worker_fetch_start.is_null()); + EXPECT_FALSE( + info.load_timing.service_worker_respond_with_settled.is_null()); EXPECT_LT(info.load_timing.service_worker_start_time, info.load_timing.service_worker_ready_time); - EXPECT_EQ(expected_info.is_in_cache_storage, info.is_in_cache_storage); + EXPECT_LE(info.load_timing.service_worker_ready_time, + info.load_timing.service_worker_fetch_start); + EXPECT_LE(info.load_timing.service_worker_fetch_start, + info.load_timing.service_worker_respond_with_settled); + EXPECT_EQ(expected_info.service_worker_response_source, + info.service_worker_response_source); EXPECT_EQ(expected_info.cache_storage_cache_name, info.cache_storage_cache_name); EXPECT_EQ(expected_info.did_service_worker_navigation_preload, @@ -491,6 +526,7 @@ class ServiceWorkerNavigationLoaderTest : public testing::Test { request->mode = network::mojom::RequestMode::kNavigate; request->credentials_mode = network::mojom::CredentialsMode::kInclude; request->redirect_mode = network::mojom::RedirectMode::kManual; + request->destination = network::mojom::RequestDestination::kDocument; return request; } @@ -506,17 +542,17 @@ class ServiceWorkerNavigationLoaderTest : public testing::Test { FetchEventServiceWorker* service_worker_; storage::BlobStorageContext blob_context_; network::TestURLLoaderClient client_; - std::unique_ptr<ServiceWorkerNavigationLoader> loader_; + std::unique_ptr<ServiceWorkerMainResourceLoader> loader_; mojo::Remote<network::mojom::URLLoader> loader_remote_; base::WeakPtr<ServiceWorkerContainerHost> container_host_; - ServiceWorkerRemoteProviderEndpoint provider_endpoints_; + ServiceWorkerRemoteContainerEndpoint container_endpoints_; bool did_call_fallback_callback_ = false; bool reset_subresource_loader_params_ = false; base::OnceClosure quit_closure_for_fallback_callback_; }; -TEST_F(ServiceWorkerNavigationLoaderTest, Basic) { +TEST_F(ServiceWorkerMainResourceLoaderTest, Basic) { base::HistogramTester histogram_tester; // Perform the request. @@ -540,13 +576,13 @@ TEST_F(ServiceWorkerNavigationLoaderTest, Basic) { 1); } -TEST_F(ServiceWorkerNavigationLoaderTest, NoActiveWorker) { +TEST_F(ServiceWorkerMainResourceLoaderTest, NoActiveWorker) { base::HistogramTester histogram_tester; // Make a container host without a controller. container_host_ = CreateContainerHostForWindow( helper_->mock_render_process_id(), /*is_parent_frame_secure=*/true, - helper_->context()->AsWeakPtr(), &provider_endpoints_); + helper_->context()->AsWeakPtr(), &container_endpoints_); container_host_->UpdateUrls( GURL("https://example.com/"), net::SiteForCookies::FromUrl(GURL("https://example.com/")), @@ -566,7 +602,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, NoActiveWorker) { } // Test that the request body is passed to the fetch event. -TEST_F(ServiceWorkerNavigationLoaderTest, RequestBody) { +TEST_F(ServiceWorkerMainResourceLoaderTest, RequestBody) { const std::string kData = "hi this is the request body"; // Create a request with a body. @@ -587,7 +623,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, RequestBody) { EXPECT_EQ(kData, body); } -TEST_F(ServiceWorkerNavigationLoaderTest, BlobResponse) { +TEST_F(ServiceWorkerMainResourceLoaderTest, BlobResponse) { base::HistogramTester histogram_tester; // Construct the blob to respond with. @@ -603,6 +639,12 @@ TEST_F(ServiceWorkerNavigationLoaderTest, BlobResponse) { storage::BlobImpl::Create(std::move(blob_handle), blob->blob.InitWithNewPipeAndPassReceiver()); service_worker_->RespondWithBlob(std::move(blob)); + service_worker_->SetResponseSource( + network::mojom::FetchResponseSource::kCacheStorage); + std::string cache_name = "v1"; + service_worker_->SetCacheStorageCacheName(cache_name); + base::Time response_time = base::Time::Now(); + service_worker_->SetResponseTime(response_time); // Perform the request. StartRequest(CreateRequest()); @@ -610,7 +652,12 @@ TEST_F(ServiceWorkerNavigationLoaderTest, BlobResponse) { auto& info = client_.response_head(); EXPECT_EQ(200, info->headers->response_code()); - ExpectResponseInfo(*info, *CreateResponseInfoFromServiceWorker()); + auto expected_info = CreateResponseInfoFromServiceWorker(); + expected_info->response_time = response_time; + expected_info->cache_storage_cache_name = cache_name; + expected_info->service_worker_response_source = + network::mojom::FetchResponseSource::kCacheStorage; + ExpectResponseInfo(*info, *expected_info); EXPECT_EQ(33, info->content_length); // Test the body. @@ -629,7 +676,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, BlobResponse) { } // Tell the helper to respond with a non-existent Blob. -TEST_F(ServiceWorkerNavigationLoaderTest, BrokenBlobResponse) { +TEST_F(ServiceWorkerMainResourceLoaderTest, BrokenBlobResponse) { base::HistogramTester histogram_tester; const std::string kBrokenUUID = "broken_uuid"; @@ -669,7 +716,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, BrokenBlobResponse) { 0); } -TEST_F(ServiceWorkerNavigationLoaderTest, StreamResponse) { +TEST_F(ServiceWorkerMainResourceLoaderTest, StreamResponse) { base::HistogramTester histogram_tester; // Construct the Stream to respond with. @@ -717,7 +764,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, StreamResponse) { } // Test when a stream response body is aborted. -TEST_F(ServiceWorkerNavigationLoaderTest, StreamResponse_Abort) { +TEST_F(ServiceWorkerMainResourceLoaderTest, StreamResponse_Abort) { base::HistogramTester histogram_tester; // Construct the Stream to respond with. @@ -767,7 +814,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, StreamResponse_Abort) { } // Test when the loader is cancelled while a stream response is being written. -TEST_F(ServiceWorkerNavigationLoaderTest, StreamResponseAndCancel) { +TEST_F(ServiceWorkerMainResourceLoaderTest, StreamResponseAndCancel) { base::HistogramTester histogram_tester; // Construct the Stream to respond with. @@ -797,7 +844,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, StreamResponseAndCancel) { loader_remote_.reset(); base::RunLoop().RunUntilIdle(); - // Although ServiceWorkerNavigationLoader resets its URLLoaderClient pointer + // Although ServiceWorkerMainResourceLoader resets its URLLoaderClient pointer // on connection error, the URLLoaderClient still exists. In this test, it is // |client_| which owns the data pipe, so it's still valid to write data to // it. @@ -823,7 +870,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, StreamResponseAndCancel) { // Test when the service worker responds with network fallback. // i.e., does not call respondWith(). -TEST_F(ServiceWorkerNavigationLoaderTest, FallbackResponse) { +TEST_F(ServiceWorkerMainResourceLoaderTest, FallbackResponse) { base::HistogramTester histogram_tester; service_worker_->RespondWithFallback(); @@ -848,7 +895,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, FallbackResponse) { } // Test when the service worker rejects the FetchEvent. -TEST_F(ServiceWorkerNavigationLoaderTest, ErrorResponse) { +TEST_F(ServiceWorkerMainResourceLoaderTest, ErrorResponse) { base::HistogramTester histogram_tester; service_worker_->RespondWithError(); @@ -868,7 +915,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, ErrorResponse) { } // Test when dispatching the fetch event to the service worker failed. -TEST_F(ServiceWorkerNavigationLoaderTest, FailFetchDispatch) { +TEST_F(ServiceWorkerMainResourceLoaderTest, FailFetchDispatch) { base::HistogramTester histogram_tester; service_worker_->FailToDispatchFetchEvent(); @@ -892,7 +939,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, FailFetchDispatch) { // Test when the respondWith() promise resolves before the waitUntil() promise // resolves. The response should be received before the event finishes. -TEST_F(ServiceWorkerNavigationLoaderTest, EarlyResponse) { +TEST_F(ServiceWorkerMainResourceLoaderTest, EarlyResponse) { service_worker_->RespondEarly(); // Perform the request. @@ -911,7 +958,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, EarlyResponse) { } // Test responding to the fetch event with a redirect response. -TEST_F(ServiceWorkerNavigationLoaderTest, Redirect) { +TEST_F(ServiceWorkerMainResourceLoaderTest, Redirect) { base::HistogramTester histogram_tester; GURL new_url("https://example.com/redirected"); service_worker_->RespondWithRedirectResponse(new_url); @@ -933,9 +980,9 @@ TEST_F(ServiceWorkerNavigationLoaderTest, Redirect) { blink::ServiceWorkerStatusCode::kOk, 1); } -TEST_F(ServiceWorkerNavigationLoaderTest, Lifetime) { +TEST_F(ServiceWorkerMainResourceLoaderTest, Lifetime) { StartRequest(CreateRequest()); - base::WeakPtr<ServiceWorkerNavigationLoader> loader = loader_->AsWeakPtr(); + base::WeakPtr<ServiceWorkerMainResourceLoader> loader = loader_->AsWeakPtr(); ASSERT_TRUE(loader); client_.RunUntilComplete(); @@ -955,7 +1002,7 @@ TEST_F(ServiceWorkerNavigationLoaderTest, Lifetime) { // |loader_| is deleted here. LSan test will alert if it leaks. } -TEST_F(ServiceWorkerNavigationLoaderTest, ConnectionErrorDuringFetchEvent) { +TEST_F(ServiceWorkerMainResourceLoaderTest, ConnectionErrorDuringFetchEvent) { service_worker_->DeferResponse(); StartRequest(CreateRequest()); @@ -976,12 +1023,12 @@ TEST_F(ServiceWorkerNavigationLoaderTest, ConnectionErrorDuringFetchEvent) { base::RunLoop().RunUntilIdle(); } -TEST_F(ServiceWorkerNavigationLoaderTest, CancelNavigationDuringFetchEvent) { +TEST_F(ServiceWorkerMainResourceLoaderTest, CancelNavigationDuringFetchEvent) { StartRequest(CreateRequest()); // Delete the container host during the request. The load should abort without // crashing. - provider_endpoints_.host_remote()->reset(); + container_endpoints_.host_remote()->reset(); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(container_host_); @@ -989,5 +1036,5 @@ TEST_F(ServiceWorkerNavigationLoaderTest, CancelNavigationDuringFetchEvent) { EXPECT_EQ(net::ERR_ABORTED, client_.completion_status().error_code); } -} // namespace service_worker_navigation_loader_unittest +} // namespace service_worker_main_resource_loader_unittest } // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_metrics.cc b/chromium/content/browser/service_worker/service_worker_metrics.cc index 57b27dd84c8..33b37fbf430 100644 --- a/chromium/content/browser/service_worker/service_worker_metrics.cc +++ b/chromium/content/browser/service_worker/service_worker_metrics.cc @@ -438,11 +438,6 @@ void ServiceWorkerMetrics::RecordFetchEventStatus( } } -void ServiceWorkerMetrics::RecordProcessCreated(bool is_new_process) { - UMA_HISTOGRAM_BOOLEAN("EmbeddedWorkerInstance.ProcessCreated", - is_new_process); -} - void ServiceWorkerMetrics::RecordStartWorkerTiming(const StartTimes& times, StartSituation situation) { if (!ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) { @@ -543,12 +538,6 @@ void ServiceWorkerMetrics::RecordStartStatusAfterFailure( } } -void ServiceWorkerMetrics::RecordNavigationPreloadRequestHeaderSize( - size_t size) { - UMA_HISTOGRAM_COUNTS_100000("ServiceWorker.NavigationPreload.HeaderSize", - size); -} - void ServiceWorkerMetrics::RecordRuntime(base::TimeDelta time) { // Start at 1 second since we expect service worker to last at least this // long: the update timer and idle timeout timer run on the order of seconds. @@ -601,4 +590,8 @@ void ServiceWorkerMetrics::RecordByteForByteUpdateCheckStatus( } } +void ServiceWorkerMetrics::RecordGetAllOriginsInfoTime(base::TimeDelta time) { + base::UmaHistogramMediumTimes("ServiceWorker.GetAllOriginsInfoTime", time); +} + } // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_metrics.h b/chromium/content/browser/service_worker/service_worker_metrics.h index 5abbd860241..22eb3f27d9d 100644 --- a/chromium/content/browser/service_worker/service_worker_metrics.h +++ b/chromium/content/browser/service_worker/service_worker_metrics.h @@ -224,8 +224,6 @@ class ServiceWorkerMetrics { static void RecordFetchEventStatus(bool is_main_resource, blink::ServiceWorkerStatusCode status); - static void RecordProcessCreated(bool is_new_process); - CONTENT_EXPORT static void RecordStartWorkerTiming(const StartTimes& times, StartSituation situation); static void RecordStartWorkerTimingClockConsistency( @@ -267,6 +265,8 @@ class ServiceWorkerMetrics { blink::ServiceWorkerStatusCode status, bool has_found_update); + static void RecordGetAllOriginsInfoTime(base::TimeDelta time); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceWorkerMetrics); }; diff --git a/chromium/content/browser/service_worker/service_worker_navigation_loader_interceptor_unittest.cc b/chromium/content/browser/service_worker/service_worker_navigation_loader_interceptor_unittest.cc deleted file mode 100644 index c19d457b71a..00000000000 --- a/chromium/content/browser/service_worker/service_worker_navigation_loader_interceptor_unittest.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2020 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 "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -namespace content { - -class ServiceWorkerNavigationLoaderInterceptorTest : public testing::Test { - public: - bool ShouldCreateForNavigation(const GURL& url) { - return ServiceWorkerNavigationLoaderInterceptor::ShouldCreateForNavigation( - url); - } -}; - -TEST_F(ServiceWorkerNavigationLoaderInterceptorTest, - ShouldCreateForNavigation_HTTP) { - EXPECT_TRUE(ShouldCreateForNavigation(GURL("http://host/scope/doc"))); -} - -TEST_F(ServiceWorkerNavigationLoaderInterceptorTest, - ShouldCreateForNavigation_HTTPS) { - EXPECT_TRUE(ShouldCreateForNavigation(GURL("https://host/scope/doc"))); -} - -TEST_F(ServiceWorkerNavigationLoaderInterceptorTest, - ShouldCreateForNavigation_FTP) { - EXPECT_FALSE(ShouldCreateForNavigation(GURL("ftp://host/scope/doc"))); -} - -TEST_F(ServiceWorkerNavigationLoaderInterceptorTest, - ShouldCreateForNavigation_ExternalFileScheme) { - bool expected_handler_created = false; -#if defined(OS_CHROMEOS) - expected_handler_created = true; -#endif // OS_CHROMEOS - EXPECT_EQ(expected_handler_created, - ShouldCreateForNavigation(GURL("externalfile:drive/doc"))); -} - -} // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_new_script_loader.cc b/chromium/content/browser/service_worker/service_worker_new_script_loader.cc index 5ce7b1c5c80..f3fa77e0b2e 100644 --- a/chromium/content/browser/service_worker/service_worker_new_script_loader.cc +++ b/chromium/content/browser/service_worker/service_worker_new_script_loader.cc @@ -102,7 +102,7 @@ ServiceWorkerNewScriptLoader::ServiceWorkerNewScriptLoader( network::mojom::RequestDestination::kServiceWorker); if (is_main_script) { // Request SSLInfo. It will be persisted in service worker storage and - // may be used by ServiceWorkerNavigationLoader for navigations handled + // may be used by ServiceWorkerMainResourceLoader for navigations handled // by this service worker. options |= network::mojom::kURLLoadOptionSendSSLInfoWithResponse; diff --git a/chromium/content/browser/service_worker/service_worker_object_host.cc b/chromium/content/browser/service_worker/service_worker_object_host.cc index 8e8565665e0..8de61b59e6f 100644 --- a/chromium/content/browser/service_worker/service_worker_object_host.cc +++ b/chromium/content/browser/service_worker/service_worker_object_host.cc @@ -10,7 +10,7 @@ #include "content/browser/service_worker/service_worker_container_host.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_provider_host.h" +#include "content/browser/service_worker/service_worker_host.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_type_converters.h" #include "content/common/service_worker/service_worker_utils.h" @@ -128,11 +128,10 @@ bool PrepareExtendableMessageEventFromServiceWorker( DCHECK(source_container_host->IsContainerForServiceWorker()); blink::mojom::ServiceWorkerObjectInfoPtr source_worker_info; base::WeakPtr<ServiceWorkerObjectHost> service_worker_object_host = - worker->provider_host() + worker->worker_host() ->container_host() ->GetOrCreateServiceWorkerObjectHost( - source_container_host->service_worker_host() - ->running_hosted_version()); + source_container_host->service_worker_host()->version()); if (service_worker_object_host) { // CreateCompleteObjectInfoToSend() is safe because |source_worker_info| // will be sent immediately by the caller of this function. @@ -289,9 +288,8 @@ void ServiceWorkerObjectHost::DispatchExtendableMessageEvent( if (container_host_->IsContainerForServiceWorker()) { // Clamp timeout to the sending worker's remaining timeout, to prevent // postMessage from keeping workers alive forever. - base::TimeDelta timeout = container_host_->service_worker_host() - ->running_hosted_version() - ->remaining_timeout(); + base::TimeDelta timeout = + container_host_->service_worker_host()->version()->remaining_timeout(); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, diff --git a/chromium/content/browser/service_worker/service_worker_object_host_unittest.cc b/chromium/content/browser/service_worker/service_worker_object_host_unittest.cc index 6eab59040ab..800a1ac5f4e 100644 --- a/chromium/content/browser/service_worker/service_worker_object_host_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_object_host_unittest.cc @@ -229,7 +229,7 @@ TEST_F(ServiceWorkerObjectHostTest, OnVersionStateChanged) { SetUpRegistration(scope, script_url); registration_->SetInstallingVersion(version_); - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; base::WeakPtr<ServiceWorkerContainerHost> container_host = CreateContainerHostForWindow( helper_->mock_render_process_id(), true /* is_parent_frame_secure */, @@ -282,7 +282,7 @@ TEST_F(ServiceWorkerObjectHostTest, // execution context (e.g., self.registration.active inside the active // worker and self.serviceWorker). ServiceWorkerContainerHost* container_host = - version_->provider_host()->container_host(); + version_->worker_host()->container_host(); blink::mojom::ServiceWorkerObjectInfoPtr info = container_host->GetOrCreateServiceWorkerObjectHost(version_) ->CreateCompleteObjectInfoToSend(); @@ -379,7 +379,7 @@ TEST_F(ServiceWorkerObjectHostTest, DispatchExtendableMessageEvent_FromClient) { WebContentsTester::CreateTestWebContents(helper_->browser_context(), nullptr)); RenderFrameHost* frame_host = web_contents->GetMainFrame(); - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; base::WeakPtr<ServiceWorkerContainerHost> container_host = CreateContainerHostForWindow( frame_host->GetProcess()->GetID(), true /* is_parent_frame_secure */, @@ -436,7 +436,7 @@ TEST_F(ServiceWorkerObjectHostTest, OnConnectionError) { // Set up the case where the last reference to the version is owned by the // service worker object host. ServiceWorkerContainerHost* container_host = - version_->provider_host()->container_host(); + version_->worker_host()->container_host(); ServiceWorkerVersion* version_rawptr = version_.get(); version_ = nullptr; ASSERT_TRUE(version_rawptr->HasOneRef()); diff --git a/chromium/content/browser/service_worker/service_worker_offline_capability_check_browsertest.cc b/chromium/content/browser/service_worker/service_worker_offline_capability_check_browsertest.cc index 9b3688bca19..47a47339315 100644 --- a/chromium/content/browser/service_worker/service_worker_offline_capability_check_browsertest.cc +++ b/chromium/content/browser/service_worker/service_worker_offline_capability_check_browsertest.cc @@ -689,4 +689,24 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerOfflineCapabilityCheckBrowserTest, CheckOfflineCapability("/service_worker/empty.html?offline")); } +// Sites with a service worker that enable navigation preload are identified +// as supporting offline capability only when they return a valid response in +// offline mode. +IN_PROC_BROWSER_TEST_F(ServiceWorkerOfflineCapabilityCheckBrowserTest, + CheckOfflineCapabilityForNavigationPreload) { + EXPECT_TRUE(NavigateToURL(shell(), + embedded_test_server()->GetURL( + "/service_worker/create_service_worker.html"))); + EXPECT_EQ("DONE", EvalJs(shell(), + "register('navigation_preload_worker.js')")); + + EXPECT_EQ(OfflineCapability::kUnsupported, + CheckOfflineCapability("/service_worker/empty.html")); + + EXPECT_EQ( + OfflineCapability::kSupported, + CheckOfflineCapability( + "/service_worker/empty.html?navpreload_or_offline")); +} + } // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_offline_capability_checker.cc b/chromium/content/browser/service_worker/service_worker_offline_capability_checker.cc index 4a216827f97..52304d4fad2 100644 --- a/chromium/content/browser/service_worker/service_worker_offline_capability_checker.cc +++ b/chromium/content/browser/service_worker/service_worker_offline_capability_checker.cc @@ -11,6 +11,7 @@ #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_version.h" #include "content/browser/storage_partition_impl.h" +#include "content/common/fetch/fetch_request_type_converters.h" #include "url/gurl.h" namespace content { @@ -82,18 +83,35 @@ void ServiceWorkerOfflineCapabilityChecker::DidFindRegistration( return; } - auto request = blink::mojom::FetchAPIRequest::New(); - request->url = url_; - request->method = "GET"; - request->is_main_resource_load = true; + network::ResourceRequest resource_request; + resource_request.url = url_; + resource_request.method = "GET"; + resource_request.mode = network::mojom::RequestMode::kNavigate; + resource_request.resource_type = + static_cast<int>(blink::mojom::ResourceType::kMainFrame); + + // Store the weak reference to ServiceWorkerContextCore before + // |preferred_version| moves. + base::WeakPtr<ServiceWorkerContextCore> context = + preferred_version->context(); + if (!context) { + std::move(callback_).Run(OfflineCapability::kUnsupported); + return; + } fetch_dispatcher_ = std::make_unique<ServiceWorkerFetchDispatcher>( - std::move(request), blink::mojom::ResourceType::kMainFrame, + blink::mojom::FetchAPIRequest::From(resource_request), + static_cast<blink::mojom::ResourceType>(resource_request.resource_type), base::GenerateGUID() /* client_id */, std::move(preferred_version), base::DoNothing() /* prepare callback */, base::BindOnce(&ServiceWorkerOfflineCapabilityChecker::OnFetchResult, base::Unretained(this)), /*is_offline_capability_check=*/true); + + fetch_dispatcher_->MaybeStartNavigationPreload( + resource_request, context->loader_factory_getter(), + context->wrapper(), /*frame_tree_node_id=*/-1); + fetch_dispatcher_->Run(); } diff --git a/chromium/content/browser/service_worker/service_worker_process_manager.cc b/chromium/content/browser/service_worker/service_worker_process_manager.cc index cca04c6aeda..f145516871b 100644 --- a/chromium/content/browser/service_worker/service_worker_process_manager.cc +++ b/chromium/content/browser/service_worker/service_worker_process_manager.cc @@ -9,7 +9,6 @@ #include <algorithm> #include <utility> -#include "base/task/post_task.h" #include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/site_instance_impl.h" @@ -202,6 +201,6 @@ namespace std { // thread. void default_delete<content::ServiceWorkerProcessManager>::operator()( content::ServiceWorkerProcessManager* ptr) const { - base::DeleteSoon(FROM_HERE, {content::BrowserThread::UI}, ptr); + content::GetUIThreadTaskRunner({})->DeleteSoon(FROM_HERE, ptr); } } // namespace std diff --git a/chromium/content/browser/service_worker/service_worker_process_manager_unittest.cc b/chromium/content/browser/service_worker/service_worker_process_manager_unittest.cc index 67d7c2a114b..d089d7a1e41 100644 --- a/chromium/content/browser/service_worker/service_worker_process_manager_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_process_manager_unittest.cc @@ -109,7 +109,7 @@ TEST_F(ServiceWorkerProcessManagerTest, std::unique_ptr<MockRenderProcessHost> host(CreateRenderProcessHost()); host->Init(); RenderProcessHostImpl::AddFrameWithSite(browser_context_.get(), host.get(), - kSiteUrl); + SiteInfo(kSiteUrl)); const std::map<int, scoped_refptr<SiteInstance>>& processes = worker_process_map(); @@ -139,7 +139,7 @@ TEST_F(ServiceWorkerProcessManagerTest, EXPECT_TRUE(processes.empty()); RenderProcessHostImpl::RemoveFrameWithSite(browser_context_.get(), host.get(), - kSiteUrl); + SiteInfo(kSiteUrl)); } TEST_F(ServiceWorkerProcessManagerTest, @@ -150,7 +150,7 @@ TEST_F(ServiceWorkerProcessManagerTest, // Create a process that is hosting a frame with kSiteUrl. std::unique_ptr<MockRenderProcessHost> host(CreateRenderProcessHost()); RenderProcessHostImpl::AddFrameWithSite(browser_context_.get(), host.get(), - kSiteUrl); + SiteInfo(kSiteUrl)); const std::map<int, scoped_refptr<SiteInstance>>& processes = worker_process_map(); @@ -179,7 +179,7 @@ TEST_F(ServiceWorkerProcessManagerTest, EXPECT_TRUE(processes.empty()); RenderProcessHostImpl::RemoveFrameWithSite(browser_context_.get(), host.get(), - kSiteUrl); + SiteInfo(kSiteUrl)); } TEST_F(ServiceWorkerProcessManagerTest, AllocateWorkerProcess_InShutdown) { diff --git a/chromium/content/browser/service_worker/service_worker_quota_client.cc b/chromium/content/browser/service_worker/service_worker_quota_client.cc index 7cb9b81224c..31b9ec70f27 100644 --- a/chromium/content/browser/service_worker/service_worker_quota_client.cc +++ b/chromium/content/browser/service_worker/service_worker_quota_client.cc @@ -1,47 +1,36 @@ // Copyright 2014 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_quota_client.h" +#include <string> +#include <utility> +#include <vector> + #include "base/bind.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_usage_info.h" +#include "third_party/blink/public/mojom/quota/quota_types.mojom-shared.h" +#include "third_party/blink/public/mojom/quota/quota_types.mojom.h" +#include "url/gurl.h" +#include "url/origin.h" using blink::mojom::StorageType; using storage::QuotaClient; namespace content { namespace { -void ReportOrigins(QuotaClient::GetOriginsCallback callback, - bool restrict_on_host, - const std::string host, - const std::vector<StorageUsageInfo>& usage_info) { - std::set<url::Origin> origins; - for (const StorageUsageInfo& info : usage_info) { - if (restrict_on_host && info.origin.host() != host) { - continue; - } - origins.insert(info.origin); - } - std::move(callback).Run(origins); -} - void ReportToQuotaStatus(QuotaClient::DeletionCallback callback, bool status) { std::move(callback).Run(status ? blink::mojom::QuotaStatusCode::kOk : blink::mojom::QuotaStatusCode::kUnknown); } void FindUsageForOrigin(QuotaClient::GetUsageCallback callback, - const GURL& origin, - const std::vector<StorageUsageInfo>& usage_info) { - for (const auto& info : usage_info) { - if (info.origin.GetURL() == origin) { - std::move(callback).Run(info.total_size_bytes); - return; - } - } - std::move(callback).Run(0); + blink::ServiceWorkerStatusCode status, + int64_t usage) { + std::move(callback).Run(usage); } } // namespace @@ -53,49 +42,31 @@ ServiceWorkerQuotaClient::ServiceWorkerQuotaClient( ServiceWorkerQuotaClient::~ServiceWorkerQuotaClient() { } -storage::QuotaClientType ServiceWorkerQuotaClient::type() const { - return storage::QuotaClientType::kServiceWorker; -} - void ServiceWorkerQuotaClient::GetOriginUsage(const url::Origin& origin, StorageType type, GetUsageCallback callback) { - if (type != StorageType::kTemporary) { - std::move(callback).Run(0); - return; - } - context_->GetAllOriginsInfo(base::BindOnce( - &FindUsageForOrigin, std::move(callback), origin.GetURL())); + DCHECK_EQ(type, StorageType::kTemporary); + context_->GetStorageUsageForOrigin( + origin, base::BindOnce(&FindUsageForOrigin, std::move(callback))); } void ServiceWorkerQuotaClient::GetOriginsForType(StorageType type, GetOriginsCallback callback) { - if (type != StorageType::kTemporary) { - std::move(callback).Run(std::set<url::Origin>()); - return; - } - context_->GetAllOriginsInfo( - base::BindOnce(&ReportOrigins, std::move(callback), false, "")); + DCHECK_EQ(type, StorageType::kTemporary); + context_->GetInstalledRegistrationOrigins(base::nullopt, std::move(callback)); } void ServiceWorkerQuotaClient::GetOriginsForHost(StorageType type, const std::string& host, GetOriginsCallback callback) { - if (type != StorageType::kTemporary) { - std::move(callback).Run(std::set<url::Origin>()); - return; - } - context_->GetAllOriginsInfo( - base::BindOnce(&ReportOrigins, std::move(callback), true, host)); + DCHECK_EQ(type, StorageType::kTemporary); + context_->GetInstalledRegistrationOrigins(host, std::move(callback)); } void ServiceWorkerQuotaClient::DeleteOriginData(const url::Origin& origin, StorageType type, DeletionCallback callback) { - if (type != StorageType::kTemporary) { - std::move(callback).Run(blink::mojom::QuotaStatusCode::kOk); - return; - } + DCHECK_EQ(type, StorageType::kTemporary); context_->DeleteForOrigin( origin.GetURL(), base::BindOnce(&ReportToQuotaStatus, std::move(callback))); @@ -104,15 +75,8 @@ void ServiceWorkerQuotaClient::DeleteOriginData(const url::Origin& origin, void ServiceWorkerQuotaClient::PerformStorageCleanup( blink::mojom::StorageType type, base::OnceClosure callback) { - if (type != StorageType::kTemporary) { - std::move(callback).Run(); - return; - } + DCHECK_EQ(type, StorageType::kTemporary); context_->PerformStorageCleanup(std::move(callback)); } -bool ServiceWorkerQuotaClient::DoesSupport(StorageType type) const { - return type == StorageType::kTemporary; -} - } // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_quota_client.h b/chromium/content/browser/service_worker/service_worker_quota_client.h index 3e4d51c20b8..885e5988d03 100644 --- a/chromium/content/browser/service_worker/service_worker_quota_client.h +++ b/chromium/content/browser/service_worker/service_worker_quota_client.h @@ -5,13 +5,17 @@ #ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_QUOTA_CLIENT_H_ #define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_QUOTA_CLIENT_H_ +#include "base/callback_forward.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "content/common/content_export.h" #include "storage/browser/quota/quota_client.h" #include "storage/browser/quota/quota_client_type.h" #include "third_party/blink/public/mojom/quota/quota_types.mojom.h" -#include "url/origin.h" + +namespace url { +class Origin; +} // namespace url namespace content { class ServiceWorkerContextWrapper; @@ -22,7 +26,6 @@ class ServiceWorkerQuotaClient : public storage::QuotaClient { ServiceWorkerContextWrapper* context); // QuotaClient method overrides - storage::QuotaClientType type() const override; void OnQuotaManagerDestroyed() override {} void GetOriginUsage(const url::Origin& origin, blink::mojom::StorageType type, @@ -37,7 +40,9 @@ class ServiceWorkerQuotaClient : public storage::QuotaClient { DeletionCallback callback) override; void PerformStorageCleanup(blink::mojom::StorageType type, base::OnceClosure callback) override; - bool DoesSupport(blink::mojom::StorageType type) const override; + + static constexpr storage::QuotaClientType kType = + storage::QuotaClientType::kServiceWorker; private: friend class ServiceWorkerContextWrapper; diff --git a/chromium/content/browser/service_worker/service_worker_register_job.cc b/chromium/content/browser/service_worker/service_worker_register_job.cc index 06effef92e9..c7586d5ee6d 100644 --- a/chromium/content/browser/service_worker/service_worker_register_job.cc +++ b/chromium/content/browser/service_worker/service_worker_register_job.cc @@ -30,7 +30,6 @@ #include "content/common/service_worker/service_worker_utils.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" -#include "mojo/public/cpp/bindings/associated_binding.h" #include "net/base/net_errors.h" #include "third_party/blink/public/common/service_worker/service_worker_type_converters.h" #include "third_party/blink/public/common/service_worker/service_worker_utils.h" diff --git a/chromium/content/browser/service_worker/service_worker_registration.cc b/chromium/content/browser/service_worker/service_worker_registration.cc index 5375e02473d..4673d32e1ac 100644 --- a/chromium/content/browser/service_worker/service_worker_registration.cc +++ b/chromium/content/browser/service_worker/service_worker_registration.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/metrics/histogram_macros.h" #include "base/threading/thread_task_runner_handle.h" #include "content/browser/service_worker/embedded_worker_status.h" #include "content/browser/service_worker/service_worker_container_host.h" @@ -138,6 +139,9 @@ void ServiceWorkerRegistration::NotifyVersionAttributesChanged( ServiceWorkerRegistrationInfo ServiceWorkerRegistration::GetInfo() { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); + UMA_HISTOGRAM_COUNTS_10000("ServiceWorker.RegistrationInfo.ScopeLength", + scope().spec().length()); + return ServiceWorkerRegistrationInfo( scope(), update_via_cache(), registration_id_, is_deleted() ? ServiceWorkerRegistrationInfo::IS_DELETED diff --git a/chromium/content/browser/service_worker/service_worker_registration.h b/chromium/content/browser/service_worker/service_worker_registration.h index 6a504b87657..c59f1fe3cfa 100644 --- a/chromium/content/browser/service_worker/service_worker_registration.h +++ b/chromium/content/browser/service_worker/service_worker_registration.h @@ -11,7 +11,6 @@ #include <string> #include <vector> -#include "base/logging.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" diff --git a/chromium/content/browser/service_worker/service_worker_registration_object_host.cc b/chromium/content/browser/service_worker/service_worker_registration_object_host.cc index 0d61c5f7dcf..b930d95bafc 100644 --- a/chromium/content/browser/service_worker/service_worker_registration_object_host.cc +++ b/chromium/content/browser/service_worker/service_worker_registration_object_host.cc @@ -12,8 +12,8 @@ #include "content/browser/service_worker/service_worker_container_host.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_host.h" #include "content/browser/service_worker/service_worker_object_host.h" -#include "content/browser/service_worker/service_worker_provider_host.h" #include "content/common/service_worker/service_worker_utils.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -187,7 +187,7 @@ void ServiceWorkerRegistrationObjectHost::Update( // with an "InvalidStateError" DOMException and abort these steps. ServiceWorkerVersion* version = nullptr; if (container_host_->IsContainerForServiceWorker()) { - version = container_host_->service_worker_host()->running_hosted_version(); + version = container_host_->service_worker_host()->version(); DCHECK(version); if (ServiceWorkerVersion::Status::INSTALLING == version->status()) { // This can happen if update() is called during execution of the diff --git a/chromium/content/browser/service_worker/service_worker_registration_unittest.cc b/chromium/content/browser/service_worker/service_worker_registration_unittest.cc index ea7b997d4ae..c71ed3a6148 100644 --- a/chromium/content/browser/service_worker/service_worker_registration_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_registration_unittest.cc @@ -31,7 +31,7 @@ #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_core_observer.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" -#include "content/browser/service_worker/service_worker_provider_host.h" +#include "content/browser/service_worker/service_worker_host.h" #include "content/browser/service_worker/service_worker_register_job.h" #include "content/browser/service_worker/service_worker_registration_object_host.h" #include "content/browser/service_worker/service_worker_test_utils.h" @@ -44,9 +44,9 @@ #include "content/public/test/url_loader_interceptor.h" #include "content/test/fake_network.h" #include "content/test/test_content_browser_client.h" -#include "mojo/core/embedder/embedder.h" #include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/pending_associated_receiver.h" +#include "mojo/public/cpp/system/functions.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h" @@ -315,7 +315,7 @@ TEST_F(ServiceWorkerRegistrationTest, FailedRegistrationNoCrash) { auto registration = base::MakeRefCounted<ServiceWorkerRegistration>( options, kRegistrationId, context()->AsWeakPtr()); // Prepare a ServiceWorkerContainerHost. - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; base::WeakPtr<ServiceWorkerContainerHost> container_host = CreateContainerHostForWindow(helper_->mock_render_process_id(), true /* is_parent_frame_secure */, @@ -553,7 +553,7 @@ class ServiceWorkerActivationTest : public ServiceWorkerRegistrationTest, FakeServiceWorker* version_2_service_worker_ = nullptr; base::WeakPtr<ServiceWorkerContainerHost> container_host_; - ServiceWorkerRemoteProviderEndpoint remote_endpoint_; + ServiceWorkerRemoteContainerEndpoint remote_endpoint_; int inflight_request_id_ = -1; DISALLOW_COPY_AND_ASSIGN(ServiceWorkerActivationTest); @@ -790,14 +790,13 @@ class ServiceWorkerRegistrationObjectHostTest protected: void SetUp() override { ServiceWorkerRegistrationTest::SetUp(); - mojo::core::SetDefaultProcessErrorCallback(base::AdaptCallbackForRepeating( + mojo::SetDefaultProcessErrorHandler(base::AdaptCallbackForRepeating( base::BindOnce(&ServiceWorkerRegistrationObjectHostTest::OnMojoError, base::Unretained(this)))); } void TearDown() override { - mojo::core::SetDefaultProcessErrorCallback( - mojo::core::ProcessErrorCallback()); + mojo::SetDefaultProcessErrorHandler(base::NullCallback()); ServiceWorkerRegistrationTest::TearDown(); } @@ -925,10 +924,10 @@ class ServiceWorkerRegistrationObjectHostTest return registration->id(); } - ServiceWorkerRemoteProviderEndpoint PrepareContainerHost( + ServiceWorkerRemoteContainerEndpoint PrepareContainerHost( const GURL& document_url, base::WeakPtr<ServiceWorkerContainerHost>* out_container_host) { - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; base::WeakPtr<ServiceWorkerContainerHost> container_host = CreateContainerHostForWindow(helper_->mock_render_process_id(), true /* is_parent_frame_secure */, @@ -989,7 +988,7 @@ TEST_F(ServiceWorkerRegistrationObjectHostTest, BreakConnection_Destroy) { const GURL kScope("https://www.example.com/"); const GURL kScriptUrl("https://www.example.com/sw.js"); int64_t registration_id = SetUpRegistration(kScope, kScriptUrl); - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareContainerHost(kScope, nullptr /* out_container_host */); blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info = GetRegistrationFromRemote(remote_endpoint.host_remote()->get(), kScope); @@ -1007,7 +1006,7 @@ TEST_P(ServiceWorkerRegistrationObjectHostUpdateTest, Update_Success) { const GURL kScope("https://www.example.com/"); const GURL kScriptUrl("https://www.example.com/sw.js"); SetUpRegistration(kScope, kScriptUrl); - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareContainerHost(kScope, nullptr /* out_container_host */); mojo::AssociatedRemote<blink::mojom::ServiceWorkerRegistrationObjectHost> registration_host; @@ -1029,7 +1028,7 @@ TEST_P(ServiceWorkerRegistrationObjectHostUpdateTest, const GURL kScriptUrl("https://www.example.com/sw.js"); SetUpRegistration(kScope, kScriptUrl); base::WeakPtr<ServiceWorkerContainerHost> container_host; - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareContainerHost(kScope, &container_host); blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info = GetRegistrationFromRemote(remote_endpoint.host_remote()->get(), kScope); @@ -1050,7 +1049,7 @@ TEST_P(ServiceWorkerRegistrationObjectHostUpdateTest, const GURL kScope("https://www.example.com/"); const GURL kScriptUrl("https://www.example.com/sw.js"); SetUpRegistration(kScope, kScriptUrl); - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareContainerHost(kScope, nullptr /* out_container_host */); blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info = GetRegistrationFromRemote(remote_endpoint.host_remote()->get(), kScope); @@ -1077,7 +1076,7 @@ TEST_P(ServiceWorkerRegistrationObjectHostUpdateTest, const GURL kScope("https://www.example.com/"); const GURL kScriptUrl("https://www.example.com/sw.js"); int64_t registration_id = SetUpRegistration(kScope, kScriptUrl); - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareContainerHost(kScope, nullptr /* out_container_host */); mojo::AssociatedRemote<blink::mojom::ServiceWorkerRegistrationObjectHost> registration_host; @@ -1144,7 +1143,7 @@ TEST_P(ServiceWorkerRegistrationObjectHostUpdateTest, CreateVersion(registration.get(), kScriptUrl); version->SetStatus(ServiceWorkerVersion::ACTIVATED); - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; base::WeakPtr<ServiceWorkerContainerHost> container_host = CreateContainerHostForWindow(helper_->mock_render_process_id(), true /* is_parent_frame_secure */, @@ -1175,7 +1174,7 @@ TEST_F(ServiceWorkerRegistrationObjectHostTest, Unregister_Success) { const GURL kScope("https://www.example.com/"); const GURL kScriptUrl("https://www.example.com/sw.js"); int64_t registration_id = SetUpRegistration(kScope, kScriptUrl); - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareContainerHost(kScope, nullptr /* out_container_host */); mojo::AssociatedRemote<blink::mojom::ServiceWorkerRegistrationObjectHost> registration_host; @@ -1205,7 +1204,7 @@ TEST_F(ServiceWorkerRegistrationObjectHostTest, const GURL kScriptUrl("https://www.example.com/sw.js"); SetUpRegistration(kScope, kScriptUrl); base::WeakPtr<ServiceWorkerContainerHost> container_host; - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareContainerHost(kScope, &container_host); blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info = GetRegistrationFromRemote(remote_endpoint.host_remote()->get(), kScope); @@ -1227,7 +1226,7 @@ TEST_F(ServiceWorkerRegistrationObjectHostTest, const GURL kScope("https://www.example.com/"); const GURL kScriptUrl("https://www.example.com/sw.js"); SetUpRegistration(kScope, kScriptUrl); - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareContainerHost(kScope, nullptr /* out_container_host */); blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info = GetRegistrationFromRemote(remote_endpoint.host_remote()->get(), kScope); @@ -1247,7 +1246,7 @@ TEST_F(ServiceWorkerRegistrationObjectHostTest, SetVersionAttributes) { const GURL kScope("https://www.example.com/"); const GURL kScriptUrl("https://www.example.com/sw.js"); int64_t registration_id = SetUpRegistration(kScope, kScriptUrl); - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareContainerHost(kScope, nullptr /* out_container_host */); blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info = GetRegistrationFromRemote(remote_endpoint.host_remote()->get(), kScope); @@ -1331,7 +1330,7 @@ TEST_F(ServiceWorkerRegistrationObjectHostTest, SetUpdateViaCache) { const GURL kScope("https://www.example.com/"); const GURL kScriptUrl("https://www.example.com/sw.js"); int64_t registration_id = SetUpRegistration(kScope, kScriptUrl); - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareContainerHost(kScope, nullptr /* out_container_host */); blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info = GetRegistrationFromRemote(remote_endpoint.host_remote()->get(), kScope); @@ -1382,7 +1381,7 @@ TEST_P(ServiceWorkerRegistrationObjectHostUpdateTest, UpdateFound) { const GURL kScope("https://www.example.com/"); const GURL kScriptUrl("https://www.example.com/sw.js"); int64_t registration_id = SetUpRegistration(kScope, kScriptUrl); - ServiceWorkerRemoteProviderEndpoint remote_endpoint = + ServiceWorkerRemoteContainerEndpoint remote_endpoint = PrepareContainerHost(kScope, nullptr /* out_container_host */); blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info = GetRegistrationFromRemote(remote_endpoint.host_remote()->get(), kScope); diff --git a/chromium/content/browser/service_worker/service_worker_registry.cc b/chromium/content/browser/service_worker/service_worker_registry.cc index 363274a46d6..edd43add84f 100644 --- a/chromium/content/browser/service_worker/service_worker_registry.cc +++ b/chromium/content/browser/service_worker/service_worker_registry.cc @@ -16,6 +16,7 @@ #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_info.h" #include "content/browser/service_worker/service_worker_registration.h" +#include "content/browser/service_worker/service_worker_storage_control_impl.h" #include "content/browser/service_worker/service_worker_version.h" #include "content/common/service_worker/service_worker_utils.h" #include "content/public/browser/browser_task_traits.h" @@ -121,9 +122,10 @@ ServiceWorkerRegistry::ServiceWorkerRegistry( storage::QuotaManagerProxy* quota_manager_proxy, storage::SpecialStoragePolicy* special_storage_policy) : context_(context), - storage_(ServiceWorkerStorage::Create(user_data_directory, - std::move(database_task_runner), - quota_manager_proxy)), + storage_control_(std::make_unique<ServiceWorkerStorageControlImpl>( + ServiceWorkerStorage::Create(user_data_directory, + std::move(database_task_runner), + quota_manager_proxy))), special_storage_policy_(special_storage_policy) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK(context_); @@ -134,7 +136,8 @@ ServiceWorkerRegistry::ServiceWorkerRegistry( ServiceWorkerContextCore* context, ServiceWorkerRegistry* old_registry) : context_(context), - storage_(ServiceWorkerStorage::Create(old_registry->storage())), + storage_control_(std::make_unique<ServiceWorkerStorageControlImpl>( + ServiceWorkerStorage::Create(old_registry->storage()))), special_storage_policy_(old_registry->special_storage_policy_) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK(context_); @@ -143,6 +146,10 @@ ServiceWorkerRegistry::ServiceWorkerRegistry( ServiceWorkerRegistry::~ServiceWorkerRegistry() = default; +ServiceWorkerStorage* ServiceWorkerRegistry::storage() const { + return storage_control_->storage(); +} + void ServiceWorkerRegistry::CreateNewRegistration( blink::mojom::ServiceWorkerRegistrationOptions options, NewRegistrationCallback callback) { @@ -279,6 +286,23 @@ void ServiceWorkerRegistry::GetRegistrationsForOrigin( weak_factory_.GetWeakPtr(), std::move(callback), origin)); } +void ServiceWorkerRegistry::GetStorageUsageForOrigin( + const url::Origin& origin, + GetStorageUsageForOriginCallback callback) { + DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); + storage()->GetUsageForOrigin( + origin, + base::BindOnce( + [](GetStorageUsageForOriginCallback callback, + storage::mojom::ServiceWorkerDatabaseStatus database_status, + int64_t usage) { + blink::ServiceWorkerStatusCode status = + DatabaseStatusToStatusCode(database_status); + std::move(callback).Run(status, usage); + }, + std::move(callback))); +} + void ServiceWorkerRegistry::GetAllRegistrationsInfos( GetRegistrationsInfosCallback callback) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); @@ -361,10 +385,10 @@ void ServiceWorkerRegistry::StoreRegistration( version->cross_origin_embedder_policy().value(); } - auto resources = std::make_unique<ResourceList>(); - version->script_cache_map()->GetResources(resources.get()); + ResourceList resources; + version->script_cache_map()->GetResources(&resources); - if (resources->empty()) { + if (resources.empty()) { RunSoon(FROM_HERE, base::BindOnce(std::move(callback), blink::ServiceWorkerStatusCode::kErrorFailed)); @@ -372,7 +396,7 @@ void ServiceWorkerRegistry::StoreRegistration( } uint64_t resources_total_size_bytes = 0; - for (const auto& resource : *resources) { + for (const auto& resource : resources) { DCHECK_GE(resource->size_bytes, 0); resources_total_size_bytes += resource->size_bytes; } @@ -430,9 +454,9 @@ void ServiceWorkerRegistry::NotifyDoneInstallingRegistration( ResourceList resources; version->script_cache_map()->GetResources(&resources); - std::set<int64_t> resource_ids; + std::vector<int64_t> resource_ids; for (const auto& resource : resources) - resource_ids.insert(resource->resource_id); + resource_ids.push_back(resource->resource_id); DoomUncommittedResources(resource_ids); } } @@ -449,7 +473,7 @@ void ServiceWorkerRegistry::UpdateToActiveState(int64_t registration_id, const GURL& origin, StatusCallback callback) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - storage()->UpdateToActiveState( + GetRemoteStorageControl()->UpdateToActiveState( registration_id, origin, base::BindOnce(&ServiceWorkerRegistry::DidUpdateToActiveState, weak_factory_.GetWeakPtr(), origin, std::move(callback))); @@ -499,11 +523,12 @@ void ServiceWorkerRegistry::StoreUncommittedResourceId(int64_t resource_id, void ServiceWorkerRegistry::DoomUncommittedResource(int64_t resource_id) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); - DoomUncommittedResources(std::set<int64_t>(&resource_id, &resource_id + 1)); + std::vector<int64_t> resource_ids = {resource_id}; + DoomUncommittedResources(resource_ids); } void ServiceWorkerRegistry::DoomUncommittedResources( - const std::set<int64_t>& resource_ids) { + const std::vector<int64_t>& resource_ids) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); storage()->DoomUncommittedResources( resource_ids, @@ -565,8 +590,8 @@ void ServiceWorkerRegistry::GetUserKeysAndDataByKeyPrefix( key_prefix.empty()) { RunSoon(FROM_HERE, base::BindOnce(std::move(callback), - base::flat_map<std::string, std::string>(), - blink::ServiceWorkerStatusCode::kErrorFailed)); + blink::ServiceWorkerStatusCode::kErrorFailed, + base::flat_map<std::string, std::string>())); return; } @@ -1194,9 +1219,12 @@ void ServiceWorkerRegistry::DidDeleteRegistration( if (registration) registration->UnsetStored(); - if (special_storage_policy_ && - origin_state == ServiceWorkerStorage::OriginState::kDelete) { - tracked_origins_for_policy_update_.erase(url::Origin::Create(origin)); + if (origin_state == ServiceWorkerStorage::OriginState::kDelete) { + context_->NotifyAllRegistrationsDeletedForOrigin( + url::Origin::Create(origin)); + if (special_storage_policy_) { + tracked_origins_for_policy_update_.erase(url::Origin::Create(origin)); + } } std::move(callback).Run(status); @@ -1220,7 +1248,7 @@ void ServiceWorkerRegistry::DidWriteUncommittedResourceIds( } void ServiceWorkerRegistry::DidDoomUncommittedResourceIds( - const std::set<int64_t>& resource_ids, + const std::vector<int64_t>& resource_ids, storage::mojom::ServiceWorkerDatabaseStatus status) { if (status != storage::mojom::ServiceWorkerDatabaseStatus::kOk) { ScheduleDeleteAndStartOver(); @@ -1231,8 +1259,8 @@ void ServiceWorkerRegistry::DidDoomUncommittedResourceIds( void ServiceWorkerRegistry::DidGetUserData( GetUserDataCallback callback, - const std::vector<std::string>& data, - storage::mojom::ServiceWorkerDatabaseStatus status) { + storage::mojom::ServiceWorkerDatabaseStatus status, + const std::vector<std::string>& data) { if (status != storage::mojom::ServiceWorkerDatabaseStatus::kOk && status != storage::mojom::ServiceWorkerDatabaseStatus::kErrorNotFound) { ScheduleDeleteAndStartOver(); @@ -1242,14 +1270,14 @@ void ServiceWorkerRegistry::DidGetUserData( void ServiceWorkerRegistry::DidGetUserKeysAndData( GetUserKeysAndDataCallback callback, - const base::flat_map<std::string, std::string>& data_map, - storage::mojom::ServiceWorkerDatabaseStatus status) { + storage::mojom::ServiceWorkerDatabaseStatus status, + const base::flat_map<std::string, std::string>& data_map) { DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); if (status != storage::mojom::ServiceWorkerDatabaseStatus::kOk && status != storage::mojom::ServiceWorkerDatabaseStatus::kErrorNotFound) { ScheduleDeleteAndStartOver(); } - std::move(callback).Run(data_map, DatabaseStatusToStatusCode(status)); + std::move(callback).Run(DatabaseStatusToStatusCode(status), data_map); } void ServiceWorkerRegistry::DidStoreUserData( @@ -1375,4 +1403,18 @@ bool ServiceWorkerRegistry::ShouldPurgeOnShutdown(const url::Origin& origin) { !special_storage_policy_->IsStorageProtected(origin.GetURL()); } +mojo::Remote<storage::mojom::ServiceWorkerStorageControl>& +ServiceWorkerRegistry::GetRemoteStorageControl() { + DCHECK(!(remote_storage_control_.is_bound() && + !remote_storage_control_.is_connected())) + << "Rebinding is not supported yet."; + + if (!remote_storage_control_.is_bound()) { + storage_control_->Bind( + remote_storage_control_.BindNewPipeAndPassReceiver()); + } + + return remote_storage_control_; +} + } // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_registry.h b/chromium/content/browser/service_worker/service_worker_registry.h index aad45746807..2f475c6a338 100644 --- a/chromium/content/browser/service_worker/service_worker_registry.h +++ b/chromium/content/browser/service_worker/service_worker_registry.h @@ -13,6 +13,7 @@ #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_storage.h" #include "content/common/content_export.h" +#include "mojo/public/cpp/bindings/remote.h" namespace base { class SequencedTaskRunner; @@ -27,6 +28,7 @@ namespace content { class ServiceWorkerContextCore; class ServiceWorkerVersion; +class ServiceWorkerStorageControlImpl; class ServiceWorkerRegistryTest; FORWARD_DECLARE_TEST(ServiceWorkerRegistryTest, StoragePolicyChange); @@ -56,11 +58,14 @@ class CONTENT_EXPORT ServiceWorkerRegistry { base::OnceCallback<void(const std::vector<std::string>& data, blink::ServiceWorkerStatusCode status)>; using GetUserKeysAndDataCallback = base::OnceCallback<void( - const base::flat_map<std::string, std::string>& data_map, - blink::ServiceWorkerStatusCode status)>; + blink::ServiceWorkerStatusCode status, + const base::flat_map<std::string, std::string>& data_map)>; using GetUserDataForAllRegistrationsCallback = base::OnceCallback<void( const std::vector<std::pair<int64_t, std::string>>& user_data, blink::ServiceWorkerStatusCode status)>; + using GetStorageUsageForOriginCallback = + base::OnceCallback<void(blink::ServiceWorkerStatusCode status, + int64_t usage)>; using StatusCallback = base::OnceCallback<void(blink::ServiceWorkerStatusCode status)>; @@ -78,7 +83,7 @@ class CONTENT_EXPORT ServiceWorkerRegistry { ~ServiceWorkerRegistry(); - ServiceWorkerStorage* storage() const { return storage_.get(); } + ServiceWorkerStorage* storage() const; // Creates a new in-memory representation of registration. Can be null when // storage is disabled. This method must be called after storage is @@ -132,7 +137,13 @@ class CONTENT_EXPORT ServiceWorkerRegistry { void GetRegistrationsForOrigin(const GURL& origin, GetRegistrationsCallback callback); + // Reads the total resource size stored in the storage for a given origin. + void GetStorageUsageForOrigin(const url::Origin& origin, + GetStorageUsageForOriginCallback callback); + // Returns info about all stored and initially installing registrations. + // TODO(crbug.com/807440,1055677): Consider removing this method. Getting all + // registrations at once might not be a good idea. void GetAllRegistrationsInfos(GetRegistrationsInfosCallback callback); ServiceWorkerRegistration* GetUninstallingRegistration(const GURL& scope); @@ -191,7 +202,7 @@ class CONTENT_EXPORT ServiceWorkerRegistry { StatusCallback callback); void StoreUncommittedResourceId(int64_t resource_id, const GURL& origin); void DoomUncommittedResource(int64_t resource_id); - void DoomUncommittedResources(const std::set<int64_t>& resource_ids); + void DoomUncommittedResources(const std::vector<int64_t>& resource_ids); void GetUserData(int64_t registration_id, const std::vector<std::string>& keys, GetUserDataCallback callback); @@ -308,15 +319,15 @@ class CONTENT_EXPORT ServiceWorkerRegistry { void DidWriteUncommittedResourceIds( storage::mojom::ServiceWorkerDatabaseStatus status); void DidDoomUncommittedResourceIds( - const std::set<int64_t>& resource_ids, + const std::vector<int64_t>& resource_ids, storage::mojom::ServiceWorkerDatabaseStatus status); void DidGetUserData(GetUserDataCallback callback, - const std::vector<std::string>& data, - storage::mojom::ServiceWorkerDatabaseStatus status); + storage::mojom::ServiceWorkerDatabaseStatus status, + const std::vector<std::string>& data); void DidGetUserKeysAndData( GetUserKeysAndDataCallback callback, - const base::flat_map<std::string, std::string>& data_map, - storage::mojom::ServiceWorkerDatabaseStatus status); + storage::mojom::ServiceWorkerDatabaseStatus status, + const base::flat_map<std::string, std::string>& data_map); void DidStoreUserData(StatusCallback callback, storage::mojom::ServiceWorkerDatabaseStatus status); void DidClearUserData(StatusCallback callback, @@ -345,10 +356,19 @@ class CONTENT_EXPORT ServiceWorkerRegistry { void OnStoragePolicyChanged(); bool ShouldPurgeOnShutdown(const url::Origin& origin); + mojo::Remote<storage::mojom::ServiceWorkerStorageControl>& + GetRemoteStorageControl(); + // The ServiceWorkerContextCore object must outlive this. ServiceWorkerContextCore* const context_; - std::unique_ptr<ServiceWorkerStorage> storage_; + mojo::Remote<storage::mojom::ServiceWorkerStorageControl> + remote_storage_control_; + // TODO(crbug.com/1055677): Remove this field after all storage operations are + // called via |remote_storage_control_|. An instance of this impl should live + // in the storage service. + std::unique_ptr<ServiceWorkerStorageControlImpl> storage_control_; + bool is_storage_disabled_ = false; const scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_; diff --git a/chromium/content/browser/service_worker/service_worker_registry_unittest.cc b/chromium/content/browser/service_worker/service_worker_registry_unittest.cc index ec182e5ae24..66b8ea9c279 100644 --- a/chromium/content/browser/service_worker/service_worker_registry_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_registry_unittest.cc @@ -16,6 +16,20 @@ namespace content { +namespace { + +void FindCallback(base::OnceClosure quit_closure, + base::Optional<blink::ServiceWorkerStatusCode>* result, + scoped_refptr<ServiceWorkerRegistration>* found, + blink::ServiceWorkerStatusCode status, + scoped_refptr<ServiceWorkerRegistration> registration) { + *result = status; + *found = std::move(registration); + std::move(quit_closure).Run(); +} + +} // namespace + class ServiceWorkerRegistryTest : public testing::Test { public: ServiceWorkerRegistryTest() @@ -26,9 +40,8 @@ class ServiceWorkerRegistryTest : public testing::Test { user_data_directory_path_ = user_data_directory_.GetPath(); special_storage_policy_ = base::MakeRefCounted<storage::MockSpecialStoragePolicy>(); - helper_ = std::make_unique<EmbeddedWorkerTestHelper>( - user_data_directory_path_, special_storage_policy_.get()); - registry()->storage()->LazyInitializeForTest(); + InitializeTestHelper(); + LazyInitialize(); } void TearDown() override { @@ -44,6 +57,35 @@ class ServiceWorkerRegistryTest : public testing::Test { return special_storage_policy_.get(); } + void InitializeTestHelper() { + helper_ = std::make_unique<EmbeddedWorkerTestHelper>( + user_data_directory_path_, special_storage_policy_.get()); + } + + void LazyInitialize() { registry()->storage()->LazyInitializeForTest(); } + + void SimulateRestart() { + // Need to reset |helper_| then wait for scheduled tasks to be finished + // because |helper_| has TestBrowserContext and the dtor schedules storage + // cleanup tasks. + helper_.reset(); + base::RunLoop().RunUntilIdle(); + InitializeTestHelper(); + LazyInitialize(); + } + + blink::ServiceWorkerStatusCode FindRegistrationForClientUrl( + const GURL& document_url, + scoped_refptr<ServiceWorkerRegistration>* registration) { + base::Optional<blink::ServiceWorkerStatusCode> result; + base::RunLoop loop; + registry()->FindRegistrationForClientUrl( + document_url, base::BindOnce(&FindCallback, loop.QuitClosure(), &result, + registration)); + loop.Run(); + return result.value(); + } + blink::ServiceWorkerStatusCode StoreRegistration( scoped_refptr<ServiceWorkerRegistration> registration, scoped_refptr<ServiceWorkerVersion> version) { @@ -59,6 +101,22 @@ class ServiceWorkerRegistryTest : public testing::Test { return result; } + blink::ServiceWorkerStatusCode GetAllRegistrationsInfos( + std::vector<ServiceWorkerRegistrationInfo>* registrations) { + base::Optional<blink::ServiceWorkerStatusCode> result; + base::RunLoop loop; + registry()->GetAllRegistrationsInfos(base::BindLambdaForTesting( + [&](blink::ServiceWorkerStatusCode status, + const std::vector<ServiceWorkerRegistrationInfo>& infos) { + result = status; + *registrations = infos; + loop.Quit(); + })); + EXPECT_FALSE(result.has_value()); // always async + loop.Run(); + return result.value(); + } + private: // |user_data_directory_| must be declared first to preserve destructor order. base::ScopedTempDir user_data_directory_; @@ -69,6 +127,140 @@ class ServiceWorkerRegistryTest : public testing::Test { std::unique_ptr<EmbeddedWorkerTestHelper> helper_; }; +TEST_F(ServiceWorkerRegistryTest, FindRegistration_LongestScopeMatch) { + LazyInitialize(); + const GURL kDocumentUrl("http://www.example.com/scope/foo"); + scoped_refptr<ServiceWorkerRegistration> found_registration; + + // Registration for "/scope/". + const GURL kScope1("http://www.example.com/scope/"); + const GURL kScript1("http://www.example.com/script1.js"); + scoped_refptr<ServiceWorkerRegistration> live_registration1 = + CreateServiceWorkerRegistrationAndVersion(context(), kScope1, kScript1, + /*resource_id=*/1); + + // Registration for "/scope/foo". + const GURL kScope2("http://www.example.com/scope/foo"); + const GURL kScript2("http://www.example.com/script2.js"); + scoped_refptr<ServiceWorkerRegistration> live_registration2 = + CreateServiceWorkerRegistrationAndVersion(context(), kScope2, kScript2, + /*resource_id=*/2); + + // Registration for "/scope/foobar". + const GURL kScope3("http://www.example.com/scope/foobar"); + const GURL kScript3("http://www.example.com/script3.js"); + scoped_refptr<ServiceWorkerRegistration> live_registration3 = + CreateServiceWorkerRegistrationAndVersion(context(), kScope3, kScript3, + /*resource_id=*/3); + + // Notify storage of them being installed. + registry()->NotifyInstallingRegistration(live_registration1.get()); + registry()->NotifyInstallingRegistration(live_registration2.get()); + registry()->NotifyInstallingRegistration(live_registration3.get()); + + // Find a registration among installing ones. + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, + FindRegistrationForClientUrl(kDocumentUrl, &found_registration)); + EXPECT_EQ(live_registration2, found_registration); + found_registration = nullptr; + + // Store registrations. + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, + StoreRegistration(live_registration1, + live_registration1->waiting_version())); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, + StoreRegistration(live_registration2, + live_registration2->waiting_version())); + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, + StoreRegistration(live_registration3, + live_registration3->waiting_version())); + + // Notify storage of installations no longer happening. + registry()->NotifyDoneInstallingRegistration( + live_registration1.get(), nullptr, blink::ServiceWorkerStatusCode::kOk); + registry()->NotifyDoneInstallingRegistration( + live_registration2.get(), nullptr, blink::ServiceWorkerStatusCode::kOk); + registry()->NotifyDoneInstallingRegistration( + live_registration3.get(), nullptr, blink::ServiceWorkerStatusCode::kOk); + + // Find a registration among installed ones. + EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, + FindRegistrationForClientUrl(kDocumentUrl, &found_registration)); + EXPECT_EQ(live_registration2, found_registration); +} + +// Tests that fields of ServiceWorkerRegistrationInfo are filled correctly. +TEST_F(ServiceWorkerRegistryTest, RegistrationInfoFields) { + const GURL kScope("http://www.example.com/scope/"); + const GURL kScript("http://www.example.com/script1.js"); + scoped_refptr<ServiceWorkerRegistration> registration = + CreateServiceWorkerRegistrationAndVersion(context(), kScope, kScript, + /*resource_id=*/1); + + // Set some fields to check ServiceWorkerStorage serializes/deserializes + // these fields correctly. + registration->SetUpdateViaCache( + blink::mojom::ServiceWorkerUpdateViaCache::kImports); + registration->EnableNavigationPreload(true); + registration->SetNavigationPreloadHeader("header"); + + registry()->NotifyInstallingRegistration(registration.get()); + ASSERT_EQ(StoreRegistration(registration, registration->waiting_version()), + blink::ServiceWorkerStatusCode::kOk); + + std::vector<ServiceWorkerRegistrationInfo> all_registrations; + EXPECT_EQ(GetAllRegistrationsInfos(&all_registrations), + blink::ServiceWorkerStatusCode::kOk); + ASSERT_EQ(all_registrations.size(), 1UL); + + ServiceWorkerRegistrationInfo info = all_registrations[0]; + EXPECT_EQ(info.scope, registration->scope()); + EXPECT_EQ(info.update_via_cache, registration->update_via_cache()); + EXPECT_EQ(info.registration_id, registration->id()); + EXPECT_EQ(info.navigation_preload_enabled, + registration->navigation_preload_state().enabled); + EXPECT_EQ(info.navigation_preload_header_length, + registration->navigation_preload_state().header.size()); +} + +// Tests loading a registration with an enabled navigation preload state, as +// well as a custom header value. +TEST_F(ServiceWorkerRegistryTest, EnabledNavigationPreloadState) { + const GURL kScope("https://valid.example.com/scope"); + const GURL kScript("https://valid.example.com/script.js"); + const std::string kHeaderValue("custom header value"); + + scoped_refptr<ServiceWorkerRegistration> registration = + CreateServiceWorkerRegistrationAndVersion(context(), kScope, kScript, + /*resource_id=*/1); + ServiceWorkerVersion* version = registration->waiting_version(); + version->SetStatus(ServiceWorkerVersion::ACTIVATED); + registration->SetActiveVersion(version); + registration->EnableNavigationPreload(true); + registration->SetNavigationPreloadHeader(kHeaderValue); + + ASSERT_EQ(StoreRegistration(registration, version), + blink::ServiceWorkerStatusCode::kOk); + + // Simulate browser shutdown and restart. + registration = nullptr; + version = nullptr; + SimulateRestart(); + + scoped_refptr<ServiceWorkerRegistration> found_registration; + EXPECT_EQ(FindRegistrationForClientUrl(kScope, &found_registration), + blink::ServiceWorkerStatusCode::kOk); + const blink::mojom::NavigationPreloadState& registration_state = + found_registration->navigation_preload_state(); + EXPECT_TRUE(registration_state.enabled); + EXPECT_EQ(registration_state.header, kHeaderValue); + ASSERT_TRUE(found_registration->active_version()); + const blink::mojom::NavigationPreloadState& state = + found_registration->active_version()->navigation_preload_state(); + EXPECT_TRUE(state.enabled); + EXPECT_EQ(state.header, kHeaderValue); +} + // Tests that storage policy changes are observed. TEST_F(ServiceWorkerRegistryTest, StoragePolicyChange) { const GURL kScope("http://www.example.com/scope/"); diff --git a/chromium/content/browser/service_worker/service_worker_script_cache_map.h b/chromium/content/browser/service_worker/service_worker_script_cache_map.h index ef8a55e24a0..affc4bcf4bc 100644 --- a/chromium/content/browser/service_worker/service_worker_script_cache_map.h +++ b/chromium/content/browser/service_worker/service_worker_script_cache_map.h @@ -73,6 +73,8 @@ class CONTENT_EXPORT ServiceWorkerScriptCacheMap { friend class ServiceWorkerVersion; friend class ServiceWorkerVersionBrowserTest; FRIEND_TEST_ALL_PREFIXES(ServiceWorkerReadFromCacheJobTest, ResourceNotFound); + FRIEND_TEST_ALL_PREFIXES(ServiceWorkerBrowserTest, + DispatchFetchEventToBrokenWorker); ServiceWorkerScriptCacheMap( ServiceWorkerVersion* owner, diff --git a/chromium/content/browser/service_worker/service_worker_script_loader_factory.cc b/chromium/content/browser/service_worker/service_worker_script_loader_factory.cc index 57335f6ad2c..3a03b8c7a56 100644 --- a/chromium/content/browser/service_worker/service_worker_script_loader_factory.cc +++ b/chromium/content/browser/service_worker/service_worker_script_loader_factory.cc @@ -8,13 +8,13 @@ #include <string> #include <utility> -#include "base/debug/crash_logging.h" +#include "base/strings/string_number_conversions.h" #include "content/browser/service_worker/service_worker_cache_writer.h" #include "content/browser/service_worker/service_worker_consts.h" #include "content/browser/service_worker/service_worker_context_core.h" +#include "content/browser/service_worker/service_worker_host.h" #include "content/browser/service_worker/service_worker_installed_script_loader.h" #include "content/browser/service_worker/service_worker_new_script_loader.h" -#include "content/browser/service_worker/service_worker_provider_host.h" #include "content/browser/service_worker/service_worker_updated_script_loader.h" #include "content/browser/service_worker/service_worker_version.h" #include "mojo/public/cpp/bindings/remote.h" @@ -27,16 +27,15 @@ namespace content { ServiceWorkerScriptLoaderFactory::ServiceWorkerScriptLoaderFactory( base::WeakPtr<ServiceWorkerContextCore> context, - base::WeakPtr<ServiceWorkerProviderHost> provider_host, + base::WeakPtr<ServiceWorkerHost> worker_host, scoped_refptr<network::SharedURLLoaderFactory> loader_factory_for_new_scripts) : context_(context), - provider_host_(provider_host), + worker_host_(worker_host), loader_factory_for_new_scripts_( std::move(loader_factory_for_new_scripts)) { DCHECK(loader_factory_for_new_scripts_ || - ServiceWorkerVersion::IsInstalled( - provider_host_->running_hosted_version()->status())); + ServiceWorkerVersion::IsInstalled(worker_host_->version()->status())); } ServiceWorkerScriptLoaderFactory::~ServiceWorkerScriptLoaderFactory() = default; @@ -78,8 +77,7 @@ void ServiceWorkerScriptLoaderFactory::CreateLoaderAndStart( // using ServiceWorkerNewScriptLoader. // Case A and C: - scoped_refptr<ServiceWorkerVersion> version = - provider_host_->running_hosted_version(); + scoped_refptr<ServiceWorkerVersion> version = worker_host_->version(); int64_t resource_id = version->script_cache_map()->LookupResourceId(resource_request.url); if (resource_id != blink::mojom::kInvalidServiceWorkerResourceId) { @@ -156,11 +154,10 @@ void ServiceWorkerScriptLoaderFactory::Update( bool ServiceWorkerScriptLoaderFactory::CheckIfScriptRequestIsValid( const network::ResourceRequest& resource_request) { - if (!context_ || !provider_host_) + if (!context_ || !worker_host_) return false; - scoped_refptr<ServiceWorkerVersion> version = - provider_host_->running_hosted_version(); + scoped_refptr<ServiceWorkerVersion> version = worker_host_->version(); if (!version) return false; @@ -205,8 +202,7 @@ void ServiceWorkerScriptLoaderFactory::CopyScript( storage->CreateResponseReader(resource_id), storage->CreateResponseWriter(new_resource_id)); - scoped_refptr<ServiceWorkerVersion> version = - provider_host_->running_hosted_version(); + scoped_refptr<ServiceWorkerVersion> version = worker_host_->version(); version->script_cache_map()->NotifyStartedCaching(url, new_resource_id); net::Error error = cache_writer_->StartCopy( @@ -228,8 +224,7 @@ void ServiceWorkerScriptLoaderFactory::OnCopyScriptFinished( net::Error error) { int64_t resource_size = cache_writer_->bytes_written(); cache_writer_.reset(); - scoped_refptr<ServiceWorkerVersion> version = - provider_host_->running_hosted_version(); + scoped_refptr<ServiceWorkerVersion> version = worker_host_->version(); if (error != net::OK) { version->script_cache_map()->NotifyFinishedCaching( @@ -273,8 +268,8 @@ void ServiceWorkerScriptLoaderFactory::OnResourceIdAssignedForNewScriptLoader( mojo::MakeSelfOwnedReceiver( ServiceWorkerNewScriptLoader::CreateAndStart( routing_id, request_id, options, resource_request, std::move(client), - provider_host_->running_hosted_version(), - loader_factory_for_new_scripts_, traffic_annotation, resource_id), + worker_host_->version(), loader_factory_for_new_scripts_, + traffic_annotation, resource_id), std::move(receiver)); } diff --git a/chromium/content/browser/service_worker/service_worker_script_loader_factory.h b/chromium/content/browser/service_worker/service_worker_script_loader_factory.h index 99867e40ebb..ccda38cf72b 100644 --- a/chromium/content/browser/service_worker/service_worker_script_loader_factory.h +++ b/chromium/content/browser/service_worker/service_worker_script_loader_factory.h @@ -22,7 +22,7 @@ namespace content { class ServiceWorkerCacheWriter; class ServiceWorkerContextCore; -class ServiceWorkerProviderHost; +class ServiceWorkerHost; // Created per one running service worker for loading its scripts. This is kept // alive while the WebServiceWorkerNetworkProvider in the renderer process is @@ -50,7 +50,7 @@ class CONTENT_EXPORT ServiceWorkerScriptLoaderFactory // error. ServiceWorkerScriptLoaderFactory( base::WeakPtr<ServiceWorkerContextCore> context, - base::WeakPtr<ServiceWorkerProviderHost> provider_host, + base::WeakPtr<ServiceWorkerHost> worker_host, scoped_refptr<network::SharedURLLoaderFactory> loader_factory_for_new_scripts); ~ServiceWorkerScriptLoaderFactory() override; @@ -108,7 +108,7 @@ class CONTENT_EXPORT ServiceWorkerScriptLoaderFactory int64_t resource_id); base::WeakPtr<ServiceWorkerContextCore> context_; - base::WeakPtr<ServiceWorkerProviderHost> provider_host_; + base::WeakPtr<ServiceWorkerHost> worker_host_; // Can be null if this factory is for an installed service worker. scoped_refptr<network::SharedURLLoaderFactory> loader_factory_for_new_scripts_; diff --git a/chromium/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc b/chromium/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc index 4a739dfa676..7030d15da9c 100644 --- a/chromium/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc @@ -45,12 +45,12 @@ class ServiceWorkerScriptLoaderFactoryTest : public testing::Test { context->registry(), registration_.get(), script_url_, blink::mojom::ScriptType::kClassic); - provider_host_ = CreateProviderHostForServiceWorkerContext( + worker_host_ = CreateServiceWorkerHost( helper_->mock_render_process_id(), true /* is_parent_frame_secure */, version_.get(), context->AsWeakPtr(), &remote_endpoint_); factory_ = std::make_unique<ServiceWorkerScriptLoaderFactory>( - helper_->context()->AsWeakPtr(), provider_host_->GetWeakPtr(), + helper_->context()->AsWeakPtr(), worker_host_->GetWeakPtr(), helper_->url_loader_factory_getter()->GetNetworkFactory()); } @@ -79,8 +79,8 @@ class ServiceWorkerScriptLoaderFactoryTest : public testing::Test { GURL script_url_; scoped_refptr<ServiceWorkerRegistration> registration_; scoped_refptr<ServiceWorkerVersion> version_; - std::unique_ptr<ServiceWorkerProviderHost> provider_host_; - ServiceWorkerRemoteProviderEndpoint remote_endpoint_; + std::unique_ptr<ServiceWorkerHost> worker_host_; + ServiceWorkerRemoteContainerEndpoint remote_endpoint_; std::unique_ptr<ServiceWorkerScriptLoaderFactory> factory_; }; @@ -102,8 +102,8 @@ TEST_F(ServiceWorkerScriptLoaderFactoryTest, Redundant) { EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code); } -TEST_F(ServiceWorkerScriptLoaderFactoryTest, NoProviderHost) { - provider_host_.reset(); +TEST_F(ServiceWorkerScriptLoaderFactoryTest, NoWorkerHost) { + worker_host_.reset(); network::TestURLLoaderClient client; mojo::PendingRemote<network::mojom::URLLoader> loader = diff --git a/chromium/content/browser/service_worker/service_worker_single_script_update_checker.cc b/chromium/content/browser/service_worker/service_worker_single_script_update_checker.cc index f14d3f499f9..d2307f134cd 100644 --- a/chromium/content/browser/service_worker/service_worker_single_script_update_checker.cc +++ b/chromium/content/browser/service_worker/service_worker_single_script_update_checker.cc @@ -180,7 +180,7 @@ ServiceWorkerSingleScriptUpdateChecker::ServiceWorkerSingleScriptUpdateChecker( static_cast<int>(blink::mojom::ResourceType::kServiceWorker); // Request SSLInfo. It will be persisted in service worker storage and - // may be used by ServiceWorkerNavigationLoader for navigations handled + // may be used by ServiceWorkerMainResourceLoader for navigations handled // by this service worker. options |= network::mojom::kURLLoadOptionSendSSLInfoWithResponse; } else { @@ -216,14 +216,11 @@ ServiceWorkerSingleScriptUpdateChecker::ServiceWorkerSingleScriptUpdateChecker( std::move(compare_reader), std::move(copy_reader), std::move(writer), /*pause_when_not_identical=*/true); - // Get a unique request id across browser-initiated navigations and navigation - // preloads. - const int request_id = GlobalRequestID::MakeBrowserInitiated().request_id; network_loader_ = ServiceWorkerUpdatedScriptLoader:: ThrottlingURLLoaderCoreWrapper::CreateLoaderAndStart( loader_factory->Clone(), browser_context_getter, MSG_ROUTING_NONE, - request_id, options, resource_request, - network_client_receiver_.BindNewPipeAndPassRemote(), + GlobalRequestID::MakeBrowserInitiated().request_id, options, + resource_request, network_client_receiver_.BindNewPipeAndPassRemote(), kUpdateCheckTrafficAnnotation); DCHECK_EQ(network_loader_state_, ServiceWorkerUpdatedScriptLoader::LoaderState::kNotStarted); diff --git a/chromium/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc b/chromium/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc index 63ec02749f1..26ed8c14481 100644 --- a/chromium/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc @@ -174,19 +174,7 @@ class ServiceWorkerSingleScriptUpdateCheckerTest : public testing::Test { DISALLOW_COPY_AND_ASSIGN(ServiceWorkerSingleScriptUpdateCheckerTest); }; -class ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest - : public ServiceWorkerSingleScriptUpdateCheckerTest, - public testing::WithParamInterface<bool> { - public: - static bool IsAsync() { return GetParam(); } -}; - -INSTANTIATE_TEST_SUITE_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTestP, - ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, - testing::Bool()); - -TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, - Identical_SingleRead) { +TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest, Identical_SingleRead) { // Response body from the network. const std::string body_from_net("abcdef"); @@ -201,8 +189,8 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, auto copy_reader = std::make_unique<MockServiceWorkerResponseReader>(); auto writer = std::make_unique<MockServiceWorkerResponseWriter>(); MockServiceWorkerResponseReader* compare_reader_rawptr = compare_reader.get(); - compare_reader->ExpectReadOk(body_from_storage, TotalBytes(body_from_storage), - IsAsync()); + compare_reader->ExpectReadOk(body_from_storage, + TotalBytes(body_from_storage)); base::Optional<CheckResult> check_result; std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker> checker = @@ -211,19 +199,17 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, std::move(copy_reader), std::move(writer), loader_factory.get(), &check_result); - if (IsAsync()) { - // Blocked on reading the header. - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Blocked on reading the header. + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the header, and then blocked on reading the body. - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the header, and then blocked on reading the body. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body. - compare_reader_rawptr->CompletePendingRead(); - } + // Unblock the body. + compare_reader_rawptr->CompletePendingRead(); // Complete the comparison of the body. It should be identical. base::RunLoop().RunUntilIdle(); @@ -234,8 +220,7 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, EXPECT_TRUE(compare_reader_rawptr->AllExpectedReadsDone()); } -TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, - Identical_MultipleRead) { +TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest, Identical_MultipleRead) { // Response body from the network. const std::string body_from_net("abcdef"); @@ -250,8 +235,8 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, auto copy_reader = std::make_unique<MockServiceWorkerResponseReader>(); auto writer = std::make_unique<MockServiceWorkerResponseWriter>(); MockServiceWorkerResponseReader* compare_reader_rawptr = compare_reader.get(); - compare_reader->ExpectReadOk(body_from_storage, TotalBytes(body_from_storage), - IsAsync()); + compare_reader->ExpectReadOk(body_from_storage, + TotalBytes(body_from_storage)); base::Optional<CheckResult> check_result; std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker> checker = @@ -260,24 +245,22 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, std::move(copy_reader), std::move(writer), loader_factory.get(), &check_result); - if (IsAsync()) { - // Blocked on reading the header. - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Blocked on reading the header. + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the header, and then blocked on reading the body. - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the header, and then blocked on reading the body. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body ("abc"). - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the body ("abc"). + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body ("def"). - compare_reader_rawptr->CompletePendingRead(); - } + // Unblock the body ("def"). + compare_reader_rawptr->CompletePendingRead(); // Complete the comparison of the body. It should be identical. base::RunLoop().RunUntilIdle(); @@ -288,7 +271,7 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, EXPECT_TRUE(compare_reader_rawptr->AllExpectedReadsDone()); } -TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, Identical_Empty) { +TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest, Identical_Empty) { // Response body from the network, which is empty. const std::string body_from_net(""); @@ -303,8 +286,8 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, Identical_Empty) { auto copy_reader = std::make_unique<MockServiceWorkerResponseReader>(); auto writer = std::make_unique<MockServiceWorkerResponseWriter>(); MockServiceWorkerResponseReader* compare_reader_rawptr = compare_reader.get(); - compare_reader->ExpectReadOk(body_from_storage, TotalBytes(body_from_storage), - IsAsync()); + compare_reader->ExpectReadOk(body_from_storage, + TotalBytes(body_from_storage)); base::Optional<CheckResult> check_result; std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker> checker = @@ -313,16 +296,14 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, Identical_Empty) { std::move(copy_reader), std::move(writer), loader_factory.get(), &check_result); - if (IsAsync()) { - // Blocked on reading the header. - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Blocked on reading the header. + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the header. The initial block of the network body is empty, and - // the empty body is passed to the cache writer. It will finish the - // comparison immediately. - compare_reader_rawptr->CompletePendingRead(); - } + // Unblock the header. The initial block of the network body is empty, and + // the empty body is passed to the cache writer. It will finish the + // comparison immediately. + compare_reader_rawptr->CompletePendingRead(); // Both network and storage are empty. The result should be kIdentical. base::RunLoop().RunUntilIdle(); @@ -333,7 +314,7 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, Identical_Empty) { EXPECT_FALSE(check_result.value().paused_state); } -TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, +TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest, Different_SingleRead_NetworkIsLonger) { // Response body from the network. const std::string body_from_net = "abcdef"; @@ -349,8 +330,8 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, auto copy_reader = std::make_unique<MockServiceWorkerResponseReader>(); auto writer = std::make_unique<MockServiceWorkerResponseWriter>(); MockServiceWorkerResponseReader* compare_reader_rawptr = compare_reader.get(); - compare_reader->ExpectReadOk(body_from_storage, TotalBytes(body_from_storage), - IsAsync()); + compare_reader->ExpectReadOk(body_from_storage, + TotalBytes(body_from_storage)); base::Optional<CheckResult> check_result; std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker> checker = @@ -359,25 +340,23 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, std::move(copy_reader), std::move(writer), loader_factory.get(), &check_result); - if (IsAsync()) { - // Blocked on reading the header. - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Blocked on reading the header. + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the header, and then blocked on reading the body. - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the header, and then blocked on reading the body. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body ("abc"). - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the body ("abc"). + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body from storage (""). The cache writer detects the end of - // the body from the disk cache. - compare_reader_rawptr->CompletePendingRead(); - } + // Unblock the body from storage (""). The cache writer detects the end of + // the body from the disk cache. + compare_reader_rawptr->CompletePendingRead(); // Complete the comparison of the body. It should be different. base::RunLoop().RunUntilIdle(); @@ -388,7 +367,7 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, EXPECT_TRUE(compare_reader_rawptr->AllExpectedReadsDone()); } -TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, +TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest, Different_SingleRead_StorageIsLonger) { // Response body from the network. const std::string body_from_net = "abc"; @@ -404,8 +383,8 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, auto copy_reader = std::make_unique<MockServiceWorkerResponseReader>(); auto writer = std::make_unique<MockServiceWorkerResponseWriter>(); MockServiceWorkerResponseReader* compare_reader_rawptr = compare_reader.get(); - compare_reader->ExpectReadOk(body_from_storage, TotalBytes(body_from_storage), - IsAsync()); + compare_reader->ExpectReadOk(body_from_storage, + TotalBytes(body_from_storage)); base::Optional<CheckResult> check_result; std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker> checker = @@ -414,20 +393,18 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, std::move(copy_reader), std::move(writer), loader_factory.get(), &check_result); - if (IsAsync()) { - // Blocked on reading the header. - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Blocked on reading the header. + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the header, and then blocked on reading the body. - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the header, and then blocked on reading the body. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body ("abc"). At this point, data from the network reaches - // the end. - compare_reader_rawptr->CompletePendingRead(); - } + // Unblock the body ("abc"). At this point, data from the network reaches + // the end. + compare_reader_rawptr->CompletePendingRead(); // Complete the comparison of the body. It should be different. base::RunLoop().RunUntilIdle(); @@ -444,7 +421,7 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, // Regression test for https://crbug.com/995146. // It should detect the update appropriately even when OnComplete() arrives // after the end of the body. -TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, +TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest, Different_SingleRead_EndOfTheBodyFirst) { // Response body from the network. const std::string body_from_net = "abc"; @@ -456,8 +433,8 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, auto copy_reader = std::make_unique<MockServiceWorkerResponseReader>(); auto writer = std::make_unique<MockServiceWorkerResponseWriter>(); MockServiceWorkerResponseReader* compare_reader_rawptr = compare_reader.get(); - compare_reader->ExpectReadOk(body_from_storage, TotalBytes(body_from_storage), - IsAsync()); + compare_reader->ExpectReadOk(body_from_storage, + TotalBytes(body_from_storage)); auto loader_factory = std::make_unique<network::TestURLLoaderFactory>(); base::Optional<CheckResult> check_result; @@ -497,20 +474,18 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, mojo::BlockingCopyFromString(body_from_net, body_producer); body_producer.reset(); - if (IsAsync()) { - // Blocked on reading the header. - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Blocked on reading the header. + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the header, and then blocked on reading the body. - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the header, and then blocked on reading the body. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body ("abc"). At this point, data from the network reaches - // the end. - compare_reader_rawptr->CompletePendingRead(); - } + // Unblock the body ("abc"). At this point, data from the network reaches + // the end. + compare_reader_rawptr->CompletePendingRead(); // Comparison should not finish until OnComplete() is called. base::RunLoop().RunUntilIdle(); @@ -530,7 +505,7 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, EXPECT_FALSE(compare_reader_rawptr->AllExpectedReadsDone()); } -TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, +TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest, Different_SingleRead_DifferentBody) { // Response body from the network. const std::string body_from_net = "abc"; @@ -546,8 +521,8 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, auto copy_reader = std::make_unique<MockServiceWorkerResponseReader>(); auto writer = std::make_unique<MockServiceWorkerResponseWriter>(); MockServiceWorkerResponseReader* compare_reader_rawptr = compare_reader.get(); - compare_reader->ExpectReadOk(body_from_storage, TotalBytes(body_from_storage), - IsAsync()); + compare_reader->ExpectReadOk(body_from_storage, + TotalBytes(body_from_storage)); base::Optional<CheckResult> check_result; std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker> checker = @@ -556,19 +531,17 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, std::move(copy_reader), std::move(writer), loader_factory.get(), &check_result); - if (IsAsync()) { - // Blocked on reading the header. - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Blocked on reading the header. + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the header, and then blocked on reading the body. - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the header, and then blocked on reading the body. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body ("abx"). - compare_reader_rawptr->CompletePendingRead(); - } + // Unblock the body ("abx"). + compare_reader_rawptr->CompletePendingRead(); // Complete the comparison of the body. It should be different. base::RunLoop().RunUntilIdle(); @@ -579,7 +552,7 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, EXPECT_TRUE(compare_reader_rawptr->AllExpectedReadsDone()); } -TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, +TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest, Different_MultipleRead_NetworkIsLonger) { // Response body from the network. const std::string body_from_net = "abcdef"; @@ -595,8 +568,8 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, auto copy_reader = std::make_unique<MockServiceWorkerResponseReader>(); auto writer = std::make_unique<MockServiceWorkerResponseWriter>(); MockServiceWorkerResponseReader* compare_reader_rawptr = compare_reader.get(); - compare_reader->ExpectReadOk(body_from_storage, TotalBytes(body_from_storage), - IsAsync()); + compare_reader->ExpectReadOk(body_from_storage, + TotalBytes(body_from_storage)); base::Optional<CheckResult> check_result; std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker> checker = @@ -605,32 +578,30 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, std::move(copy_reader), std::move(writer), loader_factory.get(), &check_result); - if (IsAsync()) { - // Blocked on reading the header. - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Blocked on reading the header. + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the header, and then blocked on reading the body. - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the header, and then blocked on reading the body. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body from storage ("ab"), and then blocked on reading the - // body again. - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the body from storage ("ab"), and then blocked on reading the + // body again. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body from storage ("c"), and then blocked on reading the body - // again. - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the body from storage ("c"), and then blocked on reading the body + // again. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body from storage (""). The cache writer detects the end of - // the body from the disk cache. - compare_reader_rawptr->CompletePendingRead(); - } + // Unblock the body from storage (""). The cache writer detects the end of + // the body from the disk cache. + compare_reader_rawptr->CompletePendingRead(); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(check_result.has_value()); @@ -640,7 +611,7 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, EXPECT_TRUE(compare_reader_rawptr->AllExpectedReadsDone()); } -TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, +TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest, Different_MultipleRead_StorageIsLonger) { // Response body from the network. const std::string body_from_net = "abc"; @@ -656,8 +627,8 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, auto copy_reader = std::make_unique<MockServiceWorkerResponseReader>(); auto writer = std::make_unique<MockServiceWorkerResponseWriter>(); MockServiceWorkerResponseReader* compare_reader_rawptr = compare_reader.get(); - compare_reader->ExpectReadOk(body_from_storage, TotalBytes(body_from_storage), - IsAsync()); + compare_reader->ExpectReadOk(body_from_storage, + TotalBytes(body_from_storage)); base::Optional<CheckResult> check_result; std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker> checker = @@ -666,26 +637,24 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, std::move(copy_reader), std::move(writer), loader_factory.get(), &check_result); - if (IsAsync()) { - // Blocked on reading the header. - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Blocked on reading the header. + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the header, and then blocked on reading the body. - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the header, and then blocked on reading the body. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body from storage ("ab"), and then blocked on reading the - // body again. - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the body from storage ("ab"), and then blocked on reading the + // body again. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body from storage ("c"). At this point, data from the network - // reaches the end. - compare_reader_rawptr->CompletePendingRead(); - } + // Unblock the body from storage ("c"). At this point, data from the network + // reaches the end. + compare_reader_rawptr->CompletePendingRead(); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(check_result.has_value()); @@ -698,7 +667,7 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, EXPECT_FALSE(compare_reader_rawptr->AllExpectedReadsDone()); } -TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, +TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest, Different_MultipleRead_DifferentBody) { // Response body from the network. const std::string body_from_net = "abc"; @@ -714,8 +683,8 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, auto copy_reader = std::make_unique<MockServiceWorkerResponseReader>(); auto writer = std::make_unique<MockServiceWorkerResponseWriter>(); MockServiceWorkerResponseReader* compare_reader_rawptr = compare_reader.get(); - compare_reader->ExpectReadOk(body_from_storage, TotalBytes(body_from_storage), - IsAsync()); + compare_reader->ExpectReadOk(body_from_storage, + TotalBytes(body_from_storage)); base::Optional<CheckResult> check_result; std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker> checker = @@ -724,26 +693,24 @@ TEST_P(ServiceWorkerSingleScriptUpdateCheckerToggleAsyncTest, std::move(copy_reader), std::move(writer), loader_factory.get(), &check_result); - if (IsAsync()) { - // Blocked on reading the header. - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Blocked on reading the header. + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the header, and then blocked on reading the body. - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the header, and then blocked on reading the body. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body from storage ("ab"), and then blocked on reading the - // body again. - compare_reader_rawptr->CompletePendingRead(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(check_result.has_value()); + // Unblock the body from storage ("ab"), and then blocked on reading the + // body again. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(check_result.has_value()); - // Unblock the body from storage ("x"), which is different from the body - // from the network. - compare_reader_rawptr->CompletePendingRead(); - } + // Unblock the body from storage ("x"), which is different from the body + // from the network. + compare_reader_rawptr->CompletePendingRead(); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(check_result.has_value()); @@ -766,8 +733,8 @@ TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest, auto copy_reader = std::make_unique<MockServiceWorkerResponseReader>(); auto writer = std::make_unique<MockServiceWorkerResponseWriter>(); MockServiceWorkerResponseReader* compare_reader_rawptr = compare_reader.get(); - compare_reader->ExpectReadOk(body_from_storage, TotalBytes(body_from_storage), - /*async=*/true); + compare_reader->ExpectReadOk(body_from_storage, + TotalBytes(body_from_storage)); base::Optional<CheckResult> check_result; std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker> checker = @@ -1101,8 +1068,8 @@ TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest, PathRestrictionPass) { auto copy_reader = std::make_unique<MockServiceWorkerResponseReader>(); auto writer = std::make_unique<MockServiceWorkerResponseWriter>(); MockServiceWorkerResponseReader* compare_reader_rawptr = compare_reader.get(); - compare_reader->ExpectReadOk(body_from_storage, TotalBytes(body_from_storage), - false /* async */); + compare_reader->ExpectReadOk(body_from_storage, + TotalBytes(body_from_storage)); base::Optional<CheckResult> check_result; std::unique_ptr<ServiceWorkerSingleScriptUpdateChecker> checker = @@ -1112,6 +1079,16 @@ TEST_F(ServiceWorkerSingleScriptUpdateCheckerTest, PathRestrictionPass) { blink::mojom::ServiceWorkerUpdateViaCache::kNone, base::TimeDelta(), std::move(compare_reader), std::move(copy_reader), std::move(writer), loader_factory.get(), &check_result); + + // Blocked on reading the header. + base::RunLoop().RunUntilIdle(); + + // Unblock the header, and then blocked on reading the body. + compare_reader_rawptr->CompletePendingRead(); + base::RunLoop().RunUntilIdle(); + + // Unblock the body from the storage ("abcdef"), and the comparison ends. + compare_reader_rawptr->CompletePendingRead(); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(check_result.has_value()); diff --git a/chromium/content/browser/service_worker/service_worker_storage.cc b/chromium/content/browser/service_worker/service_worker_storage.cc index 7d0f4facc2b..4d89284d004 100644 --- a/chromium/content/browser/service_worker/service_worker_storage.cc +++ b/chromium/content/browser/service_worker/service_worker_storage.cc @@ -295,6 +295,33 @@ void ServiceWorkerStorage::GetRegistrationsForOrigin( std::move(registrations), std::move(resource_lists))); } +void ServiceWorkerStorage::GetUsageForOrigin( + const url::Origin& origin, + GetUsageForOriginCallback callback) { + switch (state_) { + case STORAGE_STATE_DISABLED: + RunSoon(FROM_HERE, + base::BindOnce(std::move(callback), + ServiceWorkerDatabase::Status::kErrorDisabled, + /*usage=*/0)); + return; + case STORAGE_STATE_INITIALIZING: // Fall-through. + case STORAGE_STATE_UNINITIALIZED: + LazyInitialize(base::BindOnce(&ServiceWorkerStorage::GetUsageForOrigin, + weak_factory_.GetWeakPtr(), origin, + std::move(callback))); + return; + case STORAGE_STATE_INITIALIZED: + break; + } + + database_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&ServiceWorkerStorage::GetUsageForOriginInDB, + database_.get(), base::ThreadTaskRunnerHandle::Get(), + origin, std::move(callback))); +} + void ServiceWorkerStorage::GetAllRegistrations( GetAllRegistrationsCallback callback) { switch (state_) { @@ -328,7 +355,7 @@ void ServiceWorkerStorage::GetAllRegistrations( void ServiceWorkerStorage::StoreRegistrationData( storage::mojom::ServiceWorkerRegistrationDataPtr registration_data, - std::unique_ptr<ResourceList> resources, + ResourceList resources, StoreRegistrationDataCallback callback) { DCHECK_EQ(state_, STORAGE_STATE_INITIALIZED); @@ -510,17 +537,17 @@ void ServiceWorkerStorage::StoreUncommittedResourceId( if (!has_checked_for_stale_resources_) DeleteStaleResources(); + std::vector<int64_t> resource_ids = {resource_id}; base::PostTaskAndReplyWithResult( database_task_runner_.get(), FROM_HERE, base::BindOnce(&ServiceWorkerDatabase::WriteUncommittedResourceIds, - base::Unretained(database_.get()), - std::set<int64_t>(&resource_id, &resource_id + 1)), + base::Unretained(database_.get()), resource_ids), base::BindOnce(&ServiceWorkerStorage::DidWriteUncommittedResourceIds, weak_factory_.GetWeakPtr(), std::move(callback), origin)); } void ServiceWorkerStorage::DoomUncommittedResources( - const std::set<int64_t>& resource_ids, + const std::vector<int64_t>& resource_ids, DatabaseStatusCallback callback) { DCHECK(STORAGE_STATE_INITIALIZED == state_ || STORAGE_STATE_DISABLED == state_) @@ -576,8 +603,9 @@ void ServiceWorkerStorage::GetUserData(int64_t registration_id, switch (state_) { case STORAGE_STATE_DISABLED: RunSoon(FROM_HERE, - base::BindOnce(std::move(callback), std::vector<std::string>(), - ServiceWorkerDatabase::Status::kErrorDisabled)); + base::BindOnce(std::move(callback), + ServiceWorkerDatabase::Status::kErrorDisabled, + std::vector<std::string>())); return; case STORAGE_STATE_INITIALIZING: // Fall-through. case STORAGE_STATE_UNINITIALIZED: @@ -608,8 +636,9 @@ void ServiceWorkerStorage::GetUserDataByKeyPrefix( switch (state_) { case STORAGE_STATE_DISABLED: RunSoon(FROM_HERE, - base::BindOnce(std::move(callback), std::vector<std::string>(), - ServiceWorkerDatabase::Status::kErrorDisabled)); + base::BindOnce(std::move(callback), + ServiceWorkerDatabase::Status::kErrorDisabled, + std::vector<std::string>())); return; case STORAGE_STATE_INITIALIZING: // Fall-through. case STORAGE_STATE_UNINITIALIZED: @@ -642,8 +671,8 @@ void ServiceWorkerStorage::GetUserKeysAndDataByKeyPrefix( case STORAGE_STATE_DISABLED: RunSoon(FROM_HERE, base::BindOnce(std::move(callback), - base::flat_map<std::string, std::string>(), - ServiceWorkerDatabase::Status::kErrorDisabled)); + ServiceWorkerDatabase::Status::kErrorDisabled, + base::flat_map<std::string, std::string>())); return; case STORAGE_STATE_INITIALIZING: // Fall-through. case STORAGE_STATE_UNINITIALIZED: @@ -886,13 +915,6 @@ void ServiceWorkerStorage::PurgeResources( StartPurgingResources(resource_ids); } -void ServiceWorkerStorage::PurgeResources( - const std::set<int64_t>& resource_ids) { - if (!has_checked_for_stale_resources_) - DeleteStaleResources(); - StartPurgingResources(resource_ids); -} - void ServiceWorkerStorage::ApplyPolicyUpdates( const std::vector<storage::mojom::LocalStoragePolicyUpdatePtr>& policy_updates) { @@ -1139,14 +1161,6 @@ void ServiceWorkerStorage::OnDiskCacheInitialized(int rv) { } void ServiceWorkerStorage::StartPurgingResources( - const std::set<int64_t>& resource_ids) { - DCHECK(has_checked_for_stale_resources_); - for (int64_t resource_id : resource_ids) - purgeable_resource_ids_.push_back(resource_id); - ContinuePurgingResources(); -} - -void ServiceWorkerStorage::StartPurgingResources( const std::vector<int64_t>& resource_ids) { DCHECK(has_checked_for_stale_resources_); for (int64_t resource_id : resource_ids) @@ -1198,7 +1212,7 @@ void ServiceWorkerStorage::OnResourcePurged(int64_t id, int rv) { // TODO(falken): Is it always OK to ClearPurgeableResourceIds if |rv| is // failure? The disk cache entry might still remain and once we remove its // purgeable id, we will never retry deleting it. - std::set<int64_t> ids = {id}; + std::vector<int64_t> ids = {id}; database_task_runner_->PostTask( FROM_HERE, base::BindOnce( @@ -1265,7 +1279,7 @@ void ServiceWorkerStorage::CollectStaleResourcesFromDB( ServiceWorkerDatabase* database, scoped_refptr<base::SequencedTaskRunner> original_task_runner, GetResourcesCallback callback) { - std::set<int64_t> ids; + std::vector<int64_t> ids; ServiceWorkerDatabase::Status status = database->GetUncommittedResourceIds(&ids); if (status != ServiceWorkerDatabase::Status::kOk) { @@ -1364,13 +1378,12 @@ void ServiceWorkerStorage::WriteRegistrationInDB( ServiceWorkerDatabase* database, scoped_refptr<base::SequencedTaskRunner> original_task_runner, storage::mojom::ServiceWorkerRegistrationDataPtr registration, - std::unique_ptr<ResourceList> resources, + ResourceList resources, WriteRegistrationCallback callback) { DCHECK(database); - DCHECK(resources); ServiceWorkerDatabase::DeletedVersion deleted_version; ServiceWorkerDatabase::Status status = - database->WriteRegistration(*registration, *resources, &deleted_version); + database->WriteRegistration(*registration, resources, &deleted_version); original_task_runner->PostTask( FROM_HERE, base::BindOnce(std::move(callback), registration->script.GetOrigin(), @@ -1484,6 +1497,19 @@ void ServiceWorkerStorage::FindForIdOnlyInDB( std::move(callback)); } +// static +void ServiceWorkerStorage::GetUsageForOriginInDB( + ServiceWorkerDatabase* database, + scoped_refptr<base::SequencedTaskRunner> original_task_runner, + url::Origin origin, + GetUsageForOriginCallback callback) { + int64_t usage = 0; + ServiceWorkerDatabase::Status status = + database->GetUsageForOrigin(origin, usage); + original_task_runner->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), status, usage)); +} + void ServiceWorkerStorage::GetUserDataInDB( ServiceWorkerDatabase* database, scoped_refptr<base::SequencedTaskRunner> original_task_runner, @@ -1494,7 +1520,7 @@ void ServiceWorkerStorage::GetUserDataInDB( ServiceWorkerDatabase::Status status = database->ReadUserData(registration_id, keys, &values); original_task_runner->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), values, status)); + FROM_HERE, base::BindOnce(std::move(callback), status, values)); } void ServiceWorkerStorage::GetUserDataByKeyPrefixInDB( @@ -1507,7 +1533,7 @@ void ServiceWorkerStorage::GetUserDataByKeyPrefixInDB( ServiceWorkerDatabase::Status status = database->ReadUserDataByKeyPrefix(registration_id, key_prefix, &values); original_task_runner->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), values, status)); + FROM_HERE, base::BindOnce(std::move(callback), status, values)); } void ServiceWorkerStorage::GetUserKeysAndDataByKeyPrefixInDB( @@ -1521,7 +1547,7 @@ void ServiceWorkerStorage::GetUserKeysAndDataByKeyPrefixInDB( database->ReadUserKeysAndDataByKeyPrefix(registration_id, key_prefix, &data_map); original_task_runner->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), data_map, status)); + FROM_HERE, base::BindOnce(std::move(callback), status, data_map)); } void ServiceWorkerStorage::GetUserDataForAllRegistrationsInDB( diff --git a/chromium/content/browser/service_worker/service_worker_storage.h b/chromium/content/browser/service_worker/service_worker_storage.h index 0e9f0dcd321..63e356b7d20 100644 --- a/chromium/content/browser/service_worker/service_worker_storage.h +++ b/chromium/content/browser/service_worker/service_worker_storage.h @@ -42,6 +42,7 @@ class ServiceWorkerDiskCache; class ServiceWorkerResponseMetadataWriter; class ServiceWorkerResponseReader; class ServiceWorkerResponseWriter; +class ServiceWorkerStorageControlImplTest; namespace service_worker_storage_unittest { class ServiceWorkerStorageTest; @@ -79,6 +80,9 @@ class CONTENT_EXPORT ServiceWorkerStorage { ServiceWorkerDatabase::Status status, std::unique_ptr<RegistrationList> registrations, std::unique_ptr<std::vector<ResourceList>> resource_lists)>; + using GetUsageForOriginCallback = + base::OnceCallback<void(ServiceWorkerDatabase::Status status, + int64_t usage)>; using GetAllRegistrationsCallback = base::OnceCallback<void(ServiceWorkerDatabase::Status status, std::unique_ptr<RegistrationList> registrations)>; @@ -99,11 +103,9 @@ class CONTENT_EXPORT ServiceWorkerStorage { using DatabaseStatusCallback = base::OnceCallback<void(ServiceWorkerDatabase::Status status)>; using GetUserDataInDBCallback = - base::OnceCallback<void(const std::vector<std::string>& data, - ServiceWorkerDatabase::Status)>; - using GetUserKeysAndDataInDBCallback = base::OnceCallback<void( - const base::flat_map<std::string, std::string>& data_map, - ServiceWorkerDatabase::Status)>; + storage::mojom::ServiceWorkerStorageControl::GetUserDataCallback; + using GetUserKeysAndDataInDBCallback = storage::mojom:: + ServiceWorkerStorageControl::GetUserKeysAndDataByKeyPrefixCallback; using GetUserDataForAllRegistrationsInDBCallback = base::OnceCallback<void( const std::vector<std::pair<int64_t, std::string>>& user_data, ServiceWorkerDatabase::Status)>; @@ -141,13 +143,17 @@ class CONTENT_EXPORT ServiceWorkerStorage { void GetRegistrationsForOrigin(const GURL& origin, GetRegistrationsDataCallback callback); + // Reads the total resource size stored in the storage for a given origin. + void GetUsageForOrigin(const url::Origin& origin, + GetUsageForOriginCallback callback); + // Returns all stored registrations. void GetAllRegistrations(GetAllRegistrationsCallback callback); // Stores |registration_data| and |resources| on persistent storage. void StoreRegistrationData( storage::mojom::ServiceWorkerRegistrationDataPtr registration_data, - std::unique_ptr<ResourceList> resources, + ResourceList resources, StoreRegistrationDataCallback callback); // Updates the state of the registration's stored version to active. @@ -199,7 +205,7 @@ class CONTENT_EXPORT ServiceWorkerStorage { // Removes resource ids from uncommitted list, adds them to the purgeable list // and purges them. - void DoomUncommittedResources(const std::set<int64_t>& resource_ids, + void DoomUncommittedResources(const std::vector<int64_t>& resource_ids, DatabaseStatusCallback callback); // Provide a storage mechanism to read/write arbitrary data associated with @@ -291,7 +297,6 @@ class CONTENT_EXPORT ServiceWorkerStorage { // the uncommitted resource keys. void PurgeResources(const ResourceList& resources); void PurgeResources(const std::vector<int64_t>& resource_ids); - void PurgeResources(const std::set<int64_t>& resource_ids); // Applies |policy_updates|. void ApplyPolicyUpdates( @@ -303,6 +308,7 @@ class CONTENT_EXPORT ServiceWorkerStorage { void SetPurgingCompleteCallbackForTest(base::OnceClosure callback); private: + friend class ServiceWorkerStorageControlImplTest; friend class service_worker_storage_unittest::ServiceWorkerStorageTest; friend class service_worker_storage_unittest:: ServiceWorkerResourceStorageTest; @@ -409,7 +415,6 @@ class CONTENT_EXPORT ServiceWorkerStorage { void InitializeDiskCache(); void OnDiskCacheInitialized(int rv); - void StartPurgingResources(const std::set<int64_t>& resource_ids); void StartPurgingResources(const std::vector<int64_t>& resource_ids); void StartPurgingResources(const ResourceList& resources); void ContinuePurgingResources(); @@ -450,7 +455,7 @@ class CONTENT_EXPORT ServiceWorkerStorage { ServiceWorkerDatabase* database, scoped_refptr<base::SequencedTaskRunner> original_task_runner, storage::mojom::ServiceWorkerRegistrationDataPtr registration, - std::unique_ptr<ResourceList> resources, + ResourceList resources, WriteRegistrationCallback callback); static void FindForClientUrlInDB( ServiceWorkerDatabase* database, @@ -473,6 +478,11 @@ class CONTENT_EXPORT ServiceWorkerStorage { scoped_refptr<base::SequencedTaskRunner> original_task_runner, int64_t registration_id, FindInDBCallback callback); + static void GetUsageForOriginInDB( + ServiceWorkerDatabase* database, + scoped_refptr<base::SequencedTaskRunner> original_task_runner, + url::Origin origin, + GetUsageForOriginCallback callback); static void GetUserDataInDB( ServiceWorkerDatabase* database, scoped_refptr<base::SequencedTaskRunner> original_task_runner, diff --git a/chromium/content/browser/service_worker/service_worker_storage_control_impl.cc b/chromium/content/browser/service_worker/service_worker_storage_control_impl.cc index b771697e424..3667bc14151 100644 --- a/chromium/content/browser/service_worker/service_worker_storage_control_impl.cc +++ b/chromium/content/browser/service_worker/service_worker_storage_control_impl.cc @@ -5,48 +5,14 @@ #include "content/browser/service_worker/service_worker_storage_control_impl.h" #include "content/browser/service_worker/service_worker_resource_ops.h" -#include "content/browser/service_worker/service_worker_storage.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" namespace content { namespace { -using ResourceList = - std::vector<storage::mojom::ServiceWorkerResourceRecordPtr>; - -void DidFindRegistration( - base::OnceCallback< - void(storage::mojom::ServiceWorkerFindRegistrationResultPtr)> callback, - storage::mojom::ServiceWorkerRegistrationDataPtr data, - std::unique_ptr<ResourceList> resources, - storage::mojom::ServiceWorkerDatabaseStatus status) { - ResourceList resource_list = - resources ? std::move(*resources) : ResourceList(); - std::move(callback).Run( - storage::mojom::ServiceWorkerFindRegistrationResult::New( - status, std::move(data), std::move(resource_list))); -} - -void DidStoreRegistration( - ServiceWorkerStorageControlImpl::StoreRegistrationCallback callback, - storage::mojom::ServiceWorkerDatabaseStatus status, - int64_t deleted_version_id, - const std::vector<int64_t>& newly_purgeable_resources) { - // TODO(bashi): Figure out how to purge resources. - std::move(callback).Run(status); -} - -void DidDeleteRegistration( - ServiceWorkerStorageControlImpl::DeleteRegistrationCallback callback, - storage::mojom::ServiceWorkerDatabaseStatus status, - ServiceWorkerStorage::OriginState origin_state, - int64_t deleted_version_id, - const std::vector<int64_t>& newly_purgeable_resources) { - // TODO(bashi): Figure out how to purge resources. - std::move(callback).Run(status, origin_state); -} - void DidGetRegistrationsForOrigin( ServiceWorkerStorageControlImpl::GetRegistrationsForOriginCallback callback, storage::mojom::ServiceWorkerDatabaseStatus status, @@ -68,26 +34,6 @@ void DidGetRegistrationsForOrigin( std::move(callback).Run(status, std::move(registrations)); } -void DidGetUserData( - ServiceWorkerStorageControlImpl::GetUserDataCallback callback, - const std::vector<std::string>& values, - storage::mojom::ServiceWorkerDatabaseStatus status) { - // TODO(bashi): Change ServiceWorkerStorage::GetUserDataInDBCallback to remove - // this indirection (the order of |values| and |status| is different). - std::move(callback).Run(status, values); -} - -void DidGetKeysAndUserData( - ServiceWorkerStorageControlImpl::GetUserKeysAndDataByKeyPrefixCallback - callback, - const base::flat_map<std::string, std::string>& user_data, - storage::mojom::ServiceWorkerDatabaseStatus status) { - // TODO(bashi): Change ServiceWorkerStorage::GetUserKeysAndDataInDBCallback to - // remove this indirection (the order of |user_data| and |status| is - // different). - std::move(callback).Run(status, user_data); -} - void DidGetUserDataForAllRegistrations( ServiceWorkerStorageControlImpl::GetUserDataForAllRegistrationsCallback callback, @@ -104,6 +50,46 @@ void DidGetUserDataForAllRegistrations( } // namespace +class ServiceWorkerLiveVersionRefImpl + : public storage::mojom::ServiceWorkerLiveVersionRef { + public: + ServiceWorkerLiveVersionRefImpl( + base::WeakPtr<ServiceWorkerStorageControlImpl> storage, + int64_t version_id) + : storage_(std::move(storage)), version_id_(version_id) { + DCHECK_NE(version_id_, blink::mojom::kInvalidServiceWorkerVersionId); + receivers_.set_disconnect_handler( + base::BindRepeating(&ServiceWorkerLiveVersionRefImpl::OnDisconnect, + base::Unretained(this))); + } + ~ServiceWorkerLiveVersionRefImpl() override = default; + + void Add(mojo::PendingReceiver<storage::mojom::ServiceWorkerLiveVersionRef> + receiver) { + receivers_.Add(this, std::move(receiver)); + } + + void set_purgeable_resources( + const std::vector<int64_t>& purgeable_resources) { + DCHECK(purgeable_resources_.empty()); + purgeable_resources_ = purgeable_resources; + } + const std::vector<int64_t>& purgeable_resources() const { + return purgeable_resources_; + } + + private: + void OnDisconnect() { + if (storage_ && receivers_.empty()) + storage_->OnNoLiveVersion(version_id_); + } + + base::WeakPtr<ServiceWorkerStorageControlImpl> storage_; + const int64_t version_id_; + std::vector<int64_t /*resource_id*/> purgeable_resources_; + mojo::ReceiverSet<storage::mojom::ServiceWorkerLiveVersionRef> receivers_; +}; + ServiceWorkerStorageControlImpl::ServiceWorkerStorageControlImpl( std::unique_ptr<ServiceWorkerStorage> storage) : storage_(std::move(storage)) { @@ -112,6 +98,24 @@ ServiceWorkerStorageControlImpl::ServiceWorkerStorageControlImpl( ServiceWorkerStorageControlImpl::~ServiceWorkerStorageControlImpl() = default; +void ServiceWorkerStorageControlImpl::Bind( + mojo::PendingReceiver<storage::mojom::ServiceWorkerStorageControl> + receiver) { + // There should be one connection at most for now because this class hasn't + // moved to the storage service yet. + DCHECK(receivers_.empty()) + << "ServiceWorkerStorageControl doesn't support multiple connections yet"; + + receivers_.Add(this, std::move(receiver)); +} + +void ServiceWorkerStorageControlImpl::OnNoLiveVersion(int64_t version_id) { + auto it = live_versions_.find(version_id); + DCHECK(it != live_versions_.end()); + storage_->PurgeResources(it->second->purgeable_resources()); + live_versions_.erase(it); +} + void ServiceWorkerStorageControlImpl::LazyInitializeForTest() { storage_->LazyInitializeForTest(); } @@ -120,14 +124,18 @@ void ServiceWorkerStorageControlImpl::FindRegistrationForClientUrl( const GURL& client_url, FindRegistrationForClientUrlCallback callback) { storage_->FindRegistrationForClientUrl( - client_url, base::BindOnce(&DidFindRegistration, std::move(callback))); + client_url, + base::BindOnce(&ServiceWorkerStorageControlImpl::DidFindRegistration, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } void ServiceWorkerStorageControlImpl::FindRegistrationForScope( const GURL& scope, FindRegistrationForClientUrlCallback callback) { storage_->FindRegistrationForScope( - scope, base::BindOnce(&DidFindRegistration, std::move(callback))); + scope, + base::BindOnce(&ServiceWorkerStorageControlImpl::DidFindRegistration, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } void ServiceWorkerStorageControlImpl::FindRegistrationForId( @@ -136,7 +144,8 @@ void ServiceWorkerStorageControlImpl::FindRegistrationForId( FindRegistrationForClientUrlCallback callback) { storage_->FindRegistrationForId( registration_id, origin, - base::BindOnce(&DidFindRegistration, std::move(callback))); + base::BindOnce(&ServiceWorkerStorageControlImpl::DidFindRegistration, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } void ServiceWorkerStorageControlImpl::GetRegistrationsForOrigin( @@ -151,13 +160,10 @@ void ServiceWorkerStorageControlImpl::StoreRegistration( storage::mojom::ServiceWorkerRegistrationDataPtr registration, std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> resources, StoreRegistrationCallback callback) { - // TODO(bashi): Change the signature of - // ServiceWorkerStorage::StoreRegistrationData() to take a const reference. storage_->StoreRegistrationData( - std::move(registration), - std::make_unique<ServiceWorkerStorage::ResourceList>( - std::move(resources)), - base::BindOnce(&DidStoreRegistration, std::move(callback))); + std::move(registration), std::move(resources), + base::BindOnce(&ServiceWorkerStorageControlImpl::DidStoreRegistration, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } void ServiceWorkerStorageControlImpl::DeleteRegistration( @@ -166,7 +172,8 @@ void ServiceWorkerStorageControlImpl::DeleteRegistration( DeleteRegistrationCallback callback) { storage_->DeleteRegistration( registration_id, origin, - base::BindOnce(&DidDeleteRegistration, std::move(callback))); + base::BindOnce(&ServiceWorkerStorageControlImpl::DidDeleteRegistration, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } void ServiceWorkerStorageControlImpl::UpdateToActiveState( @@ -210,7 +217,9 @@ void ServiceWorkerStorageControlImpl::GetNewRegistrationId( void ServiceWorkerStorageControlImpl::GetNewVersionId( GetNewVersionIdCallback callback) { - storage_->GetNewVersionId(std::move(callback)); + storage_->GetNewVersionId( + base::BindOnce(&ServiceWorkerStorageControlImpl::DidGetNewVersionId, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } void ServiceWorkerStorageControlImpl::GetNewResourceId( @@ -247,12 +256,25 @@ void ServiceWorkerStorageControlImpl::CreateResourceMetadataWriter( std::move(writer)); } +void ServiceWorkerStorageControlImpl::StoreUncommittedResourceId( + int64_t resource_id, + const GURL& origin, + StoreUncommittedResourceIdCallback callback) { + storage_->StoreUncommittedResourceId(resource_id, origin, + std::move(callback)); +} + +void ServiceWorkerStorageControlImpl::DoomUncommittedResources( + const std::vector<int64_t>& resource_ids, + DoomUncommittedResourcesCallback callback) { + storage_->DoomUncommittedResources(resource_ids, std::move(callback)); +} + void ServiceWorkerStorageControlImpl::GetUserData( int64_t registration_id, const std::vector<std::string>& keys, GetUserDataCallback callback) { - storage_->GetUserData(registration_id, keys, - base::BindOnce(&DidGetUserData, std::move(callback))); + storage_->GetUserData(registration_id, keys, std::move(callback)); } void ServiceWorkerStorageControlImpl::StoreUserData( @@ -275,18 +297,16 @@ void ServiceWorkerStorageControlImpl::GetUserDataByKeyPrefix( int64_t registration_id, const std::string& key_prefix, GetUserDataByKeyPrefixCallback callback) { - storage_->GetUserDataByKeyPrefix( - registration_id, key_prefix, - base::BindOnce(&DidGetUserData, std::move(callback))); + storage_->GetUserDataByKeyPrefix(registration_id, key_prefix, + std::move(callback)); } void ServiceWorkerStorageControlImpl::GetUserKeysAndDataByKeyPrefix( int64_t registration_id, const std::string& key_prefix, GetUserKeysAndDataByKeyPrefixCallback callback) { - storage_->GetUserKeysAndDataByKeyPrefix( - registration_id, key_prefix, - base::BindOnce(&DidGetKeysAndUserData, std::move(callback))); + storage_->GetUserKeysAndDataByKeyPrefix(registration_id, key_prefix, + std::move(callback)); } void ServiceWorkerStorageControlImpl::ClearUserDataByKeyPrefixes( @@ -327,4 +347,92 @@ void ServiceWorkerStorageControlImpl::ApplyPolicyUpdates( storage_->ApplyPolicyUpdates(std::move(policy_updates)); } +void ServiceWorkerStorageControlImpl::DidFindRegistration( + base::OnceCallback< + void(storage::mojom::ServiceWorkerFindRegistrationResultPtr)> callback, + storage::mojom::ServiceWorkerRegistrationDataPtr data, + std::unique_ptr<ResourceList> resources, + storage::mojom::ServiceWorkerDatabaseStatus status) { + ResourceList resource_list = + resources ? std::move(*resources) : ResourceList(); + + mojo::PendingRemote<storage::mojom::ServiceWorkerLiveVersionRef> + remote_reference; + if (data && + data->version_id != blink::mojom::kInvalidServiceWorkerVersionId) { + DCHECK_EQ(status, storage::mojom::ServiceWorkerDatabaseStatus::kOk); + auto it = live_versions_.find(data->version_id); + if (it == live_versions_.end()) { + remote_reference = CreateLiveVersionReference(data->version_id); + } else { + it->second->Add(remote_reference.InitWithNewPipeAndPassReceiver()); + } + } + + std::move(callback).Run( + storage::mojom::ServiceWorkerFindRegistrationResult::New( + status, std::move(remote_reference), std::move(data), + std::move(resource_list))); +} + +void ServiceWorkerStorageControlImpl::DidStoreRegistration( + StoreRegistrationCallback callback, + storage::mojom::ServiceWorkerDatabaseStatus status, + int64_t deleted_version_id, + const std::vector<int64_t>& newly_purgeable_resources) { + MaybePurgeResources(deleted_version_id, newly_purgeable_resources); + std::move(callback).Run(status); +} + +void ServiceWorkerStorageControlImpl::DidDeleteRegistration( + DeleteRegistrationCallback callback, + storage::mojom::ServiceWorkerDatabaseStatus status, + ServiceWorkerStorage::OriginState origin_state, + int64_t deleted_version_id, + const std::vector<int64_t>& newly_purgeable_resources) { + MaybePurgeResources(deleted_version_id, newly_purgeable_resources); + std::move(callback).Run(status, origin_state); +} + +void ServiceWorkerStorageControlImpl::DidGetNewVersionId( + GetNewVersionIdCallback callback, + int64_t version_id) { + mojo::PendingRemote<storage::mojom::ServiceWorkerLiveVersionRef> + remote_reference; + if (version_id != blink::mojom::kInvalidServiceWorkerVersionId) { + remote_reference = CreateLiveVersionReference(version_id); + } + std::move(callback).Run(version_id, std::move(remote_reference)); +} + +mojo::PendingRemote<storage::mojom::ServiceWorkerLiveVersionRef> +ServiceWorkerStorageControlImpl::CreateLiveVersionReference( + int64_t version_id) { + DCHECK_NE(version_id, blink::mojom::kInvalidServiceWorkerVersionId); + DCHECK(!base::Contains(live_versions_, version_id)); + + mojo::PendingRemote<storage::mojom::ServiceWorkerLiveVersionRef> + remote_reference; + auto reference = std::make_unique<ServiceWorkerLiveVersionRefImpl>( + weak_ptr_factory_.GetWeakPtr(), version_id); + reference->Add(remote_reference.InitWithNewPipeAndPassReceiver()); + live_versions_[version_id] = std::move(reference); + return remote_reference; +} + +void ServiceWorkerStorageControlImpl::MaybePurgeResources( + int64_t version_id, + const std::vector<int64_t>& purgeable_resources) { + if (version_id == blink::mojom::kInvalidServiceWorkerVersionId || + purgeable_resources.size() == 0) + return; + + if (base::Contains(live_versions_, version_id)) { + live_versions_[version_id]->set_purgeable_resources( + std::move(purgeable_resources)); + } else { + storage_->PurgeResources(std::move(purgeable_resources)); + } +} + } // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_storage_control_impl.h b/chromium/content/browser/service_worker/service_worker_storage_control_impl.h index 63320c98b19..e76695eac81 100644 --- a/chromium/content/browser/service_worker/service_worker_storage_control_impl.h +++ b/chromium/content/browser/service_worker/service_worker_storage_control_impl.h @@ -7,13 +7,17 @@ #include <memory> +#include "base/containers/flat_map.h" +#include "base/memory/weak_ptr.h" #include "components/services/storage/public/mojom/service_worker_storage_control.mojom.h" +#include "content/browser/service_worker/service_worker_storage.h" #include "content/common/content_export.h" #include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver_set.h" namespace content { -class ServiceWorkerStorage; +class ServiceWorkerLiveVersionRefImpl; // This class wraps ServiceWorkerStorage to implement mojo interface defined by // the storage service, i.e., ServiceWorkerStorageControl. @@ -32,6 +36,15 @@ class CONTENT_EXPORT ServiceWorkerStorageControlImpl ~ServiceWorkerStorageControlImpl() override; + // TODO(crbug.com/1055677): Remove this accessor after all + // ServiceWorkerStorage method calls are replaced with mojo methods. + ServiceWorkerStorage* storage() const { return storage_.get(); } + + void Bind(mojo::PendingReceiver<storage::mojom::ServiceWorkerStorageControl> + receiver); + + void OnNoLiveVersion(int64_t version_id); + void LazyInitializeForTest(); private: @@ -88,6 +101,13 @@ class CONTENT_EXPORT ServiceWorkerStorageControlImpl int64_t resource_id, mojo::PendingReceiver<storage::mojom::ServiceWorkerResourceMetadataWriter> writer) override; + void StoreUncommittedResourceId( + int64_t resource_id, + const GURL& origin, + StoreUncommittedResourceIdCallback callback) override; + void DoomUncommittedResources( + const std::vector<int64_t>& resource_ids, + DoomUncommittedResourcesCallback callback) override; void GetUserData(int64_t registration_id, const std::vector<std::string>& keys, GetUserDataCallback callback) override; @@ -123,7 +143,44 @@ class CONTENT_EXPORT ServiceWorkerStorageControlImpl const std::vector<storage::mojom::LocalStoragePolicyUpdatePtr> policy_updates) override; + using ResourceList = + std::vector<storage::mojom::ServiceWorkerResourceRecordPtr>; + + // Callbacks for ServiceWorkerStorage methods. + void DidFindRegistration( + base::OnceCallback<void( + storage::mojom::ServiceWorkerFindRegistrationResultPtr)> callback, + storage::mojom::ServiceWorkerRegistrationDataPtr data, + std::unique_ptr<ResourceList> resources, + storage::mojom::ServiceWorkerDatabaseStatus status); + void DidStoreRegistration( + StoreRegistrationCallback callback, + storage::mojom::ServiceWorkerDatabaseStatus status, + int64_t deleted_version_id, + const std::vector<int64_t>& newly_purgeable_resources); + void DidDeleteRegistration( + DeleteRegistrationCallback callback, + storage::mojom::ServiceWorkerDatabaseStatus status, + ServiceWorkerStorage::OriginState origin_state, + int64_t deleted_version_id, + const std::vector<int64_t>& newly_purgeable_resources); + void DidGetNewVersionId(GetNewVersionIdCallback callback, int64_t version_id); + + mojo::PendingRemote<storage::mojom::ServiceWorkerLiveVersionRef> + CreateLiveVersionReference(int64_t version_id); + + void MaybePurgeResources(int64_t version_id, + const std::vector<int64_t>& purgeable_resources); + const std::unique_ptr<ServiceWorkerStorage> storage_; + + mojo::ReceiverSet<storage::mojom::ServiceWorkerStorageControl> receivers_; + + base::flat_map<int64_t /*version_id*/, + std::unique_ptr<ServiceWorkerLiveVersionRefImpl>> + live_versions_; + + base::WeakPtrFactory<ServiceWorkerStorageControlImpl> weak_ptr_factory_{this}; }; } // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_storage_control_impl_unittest.cc b/chromium/content/browser/service_worker/service_worker_storage_control_impl_unittest.cc index f6b40a65171..c87699128f5 100644 --- a/chromium/content/browser/service_worker/service_worker_storage_control_impl_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_storage_control_impl_unittest.cc @@ -30,6 +30,8 @@ namespace content { using DatabaseStatus = storage::mojom::ServiceWorkerDatabaseStatus; +using RegistrationData = storage::mojom::ServiceWorkerRegistrationDataPtr; +using ResourceRecord = storage::mojom::ServiceWorkerResourceRecordPtr; using FindRegistrationResult = storage::mojom::ServiceWorkerFindRegistrationResultPtr; @@ -52,6 +54,11 @@ struct DeleteRegistrationResult { storage::mojom::ServiceWorkerStorageOriginState origin_state; }; +struct GetNewVersionIdResult { + int64_t version_id; + mojo::PendingRemote<storage::mojom::ServiceWorkerLiveVersionRef> reference; +}; + struct GetUserDataResult { DatabaseStatus status; std::vector<std::string> values; @@ -190,7 +197,7 @@ class ServiceWorkerStorageControlImplTest : public testing::Test { storage()->FindRegistrationForClientUrl( client_url, base::BindLambdaForTesting([&](FindRegistrationResult result) { - return_value = result.Clone(); + return_value = std::move(result); loop.Quit(); })); loop.Run(); @@ -202,7 +209,7 @@ class ServiceWorkerStorageControlImplTest : public testing::Test { base::RunLoop loop; storage()->FindRegistrationForScope( scope, base::BindLambdaForTesting([&](FindRegistrationResult result) { - return_value = result.Clone(); + return_value = std::move(result); loop.Quit(); })); loop.Run(); @@ -216,7 +223,7 @@ class ServiceWorkerStorageControlImplTest : public testing::Test { storage()->FindRegistrationForId( registration_id, origin, base::BindLambdaForTesting([&](FindRegistrationResult result) { - return_value = result.Clone(); + return_value = std::move(result); loop.Quit(); })); loop.Run(); @@ -243,7 +250,7 @@ class ServiceWorkerStorageControlImplTest : public testing::Test { } DatabaseStatus StoreRegistration( - storage::mojom::ServiceWorkerRegistrationDataPtr registration, + RegistrationData registration, std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> resources) { DatabaseStatus out_status; base::RunLoop loop; @@ -345,16 +352,19 @@ class ServiceWorkerStorageControlImplTest : public testing::Test { return return_value; } - int64_t GetNewVersionId() { - int64_t return_value; + GetNewVersionIdResult GetNewVersionId() { + GetNewVersionIdResult result; base::RunLoop loop; - storage()->GetNewVersionId( - base::BindLambdaForTesting([&](int64_t version_id) { - return_value = version_id; + storage()->GetNewVersionId(base::BindLambdaForTesting( + [&](int64_t version_id, + mojo::PendingRemote<storage::mojom::ServiceWorkerLiveVersionRef> + reference) { + result.version_id = version_id; + result.reference = std::move(reference); loop.Quit(); })); loop.Run(); - return return_value; + return result; } int64_t GetNewResourceId() { @@ -369,6 +379,33 @@ class ServiceWorkerStorageControlImplTest : public testing::Test { return return_value; } + DatabaseStatus StoreUncommittedResourceId(int64_t resource_id, + const GURL& origin) { + DatabaseStatus return_value; + base::RunLoop loop; + storage()->StoreUncommittedResourceId( + resource_id, origin, + base::BindLambdaForTesting([&](DatabaseStatus status) { + return_value = status; + loop.Quit(); + })); + loop.Run(); + return return_value; + } + + DatabaseStatus DoomUncommittedResources( + const std::vector<int64_t> resource_ids) { + DatabaseStatus return_value; + base::RunLoop loop; + storage()->DoomUncommittedResources( + resource_ids, base::BindLambdaForTesting([&](DatabaseStatus status) { + return_value = status; + loop.Quit(); + })); + loop.Run(); + return return_value; + } + GetUserDataResult GetUserData(int64_t registration_id, const std::vector<std::string>& keys) { GetUserDataResult result; @@ -511,17 +548,14 @@ class ServiceWorkerStorageControlImplTest : public testing::Test { return return_value; } - // Create a registration with a single resource and stores the registration. - DatabaseStatus CreateAndStoreRegistration(int64_t registration_id, - int64_t version_id, - int64_t resource_id, - const GURL& scope, - const GURL& script_url, - int64_t script_size) { - std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> resources; - resources.push_back(storage::mojom::ServiceWorkerResourceRecord::New( - resource_id, script_url, script_size)); - + // Creates a registration with the given resource records. + RegistrationData CreateRegistrationData( + int64_t registration_id, + int64_t version_id, + const GURL& scope, + const GURL& script_url, + const std::vector<storage::mojom::ServiceWorkerResourceRecordPtr>& + resources) { auto data = storage::mojom::ServiceWorkerRegistrationData::New(); data->registration_id = registration_id; data->version_id = version_id; @@ -536,11 +570,53 @@ class ServiceWorkerStorageControlImplTest : public testing::Test { } data->resources_total_size_bytes = resources_total_size_bytes; + return data; + } + + // Creates a registration with a single resource and stores the registration. + DatabaseStatus CreateAndStoreRegistration(int64_t registration_id, + int64_t version_id, + int64_t resource_id, + const GURL& scope, + const GURL& script_url, + int64_t script_size) { + std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> resources; + resources.push_back(storage::mojom::ServiceWorkerResourceRecord::New( + resource_id, script_url, script_size)); + + RegistrationData data = CreateRegistrationData( + registration_id, version_id, scope, script_url, resources); + DatabaseStatus status = StoreRegistration(std::move(data), std::move(resources)); return status; } + int WriteResource(int64_t resource_id, const std::string& data) { + auto response_head = network::mojom::URLResponseHead::New(); + response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>( + net::HttpUtil::AssembleRawHeaders( + "HTTP/1.1 200 OK\n" + "Content-Type: application/javascript\n")); + response_head->headers->GetMimeType(&response_head->mime_type); + + mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> writer = + CreateResourceWriter(resource_id); + int result = WriteResponseHead(writer.get(), std::move(response_head)); + if (result < 0) + return result; + + mojo_base::BigBuffer buffer(base::as_bytes(base::make_span(data))); + result = WriteResponseData(writer.get(), std::move(buffer)); + return result; + } + + std::string ReadResource(int64_t resource_id, int data_size) { + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> reader = + CreateResourceReader(resource_id); + return ReadResponseData(reader.get(), data_size); + } + mojo::Remote<storage::mojom::ServiceWorkerResourceReader> CreateResourceReader(int64_t resource_id) { mojo::Remote<storage::mojom::ServiceWorkerResourceReader> reader; @@ -565,6 +641,22 @@ class ServiceWorkerStorageControlImplTest : public testing::Test { return writer; } + // Helper function that reads uncommitted resource ids from database. + std::vector<int64_t> GetUncommittedResourceIds() { + std::vector<int64_t> ids; + base::RunLoop loop; + ServiceWorkerStorage* internal_storage = storage_impl_->storage(); + ServiceWorkerDatabase* database_raw = internal_storage->database_.get(); + internal_storage->database_task_runner_->PostTask( + FROM_HERE, base::BindLambdaForTesting([&]() { + EXPECT_EQ(ServiceWorkerDatabase::Status::kOk, + database_raw->GetUncommittedResourceIds(&ids)); + loop.Quit(); + })); + loop.Run(); + return ids; + } + private: base::ScopedTempDir user_data_directory_; BrowserTaskEnvironment task_environment_; @@ -607,7 +699,7 @@ TEST_F(ServiceWorkerStorageControlImplTest, StoreAndDeleteRegistration) { LazyInitializeForTest(); const int64_t kRegistrationId = GetNewResourceId(); - const int64_t kVersionId = GetNewVersionId(); + const int64_t kVersionId = GetNewVersionId().version_id; // Create a registration data with a single resource. std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> resources; @@ -682,7 +774,7 @@ TEST_F(ServiceWorkerStorageControlImplTest, UpdateToActiveState) { // Preparation: Store a registration. const int64_t registration_id = GetNewRegistrationId(); - const int64_t version_id = GetNewVersionId(); + const int64_t version_id = GetNewVersionId().version_id; const int64_t resource_id = GetNewResourceId(); DatabaseStatus status = CreateAndStoreRegistration(registration_id, version_id, resource_id, @@ -719,7 +811,7 @@ TEST_F(ServiceWorkerStorageControlImplTest, UpdateLastUpdateCheckTime) { // Preparation: Store a registration. const int64_t registration_id = GetNewRegistrationId(); - const int64_t version_id = GetNewVersionId(); + const int64_t version_id = GetNewVersionId().version_id; const int64_t resource_id = GetNewResourceId(); DatabaseStatus status = CreateAndStoreRegistration(registration_id, version_id, resource_id, @@ -757,7 +849,7 @@ TEST_F(ServiceWorkerStorageControlImplTest, Update) { // Preparation: Store a registration. const int64_t registration_id = GetNewRegistrationId(); - const int64_t version_id = GetNewVersionId(); + const int64_t version_id = GetNewVersionId().version_id; const int64_t resource_id = GetNewResourceId(); DatabaseStatus status = CreateAndStoreRegistration(registration_id, version_id, resource_id, @@ -806,14 +898,14 @@ TEST_F(ServiceWorkerStorageControlImplTest, GetRegistrationsForOrigin) { // Store two registrations which have the same origin. DatabaseStatus status; const int64_t registration_id1 = GetNewRegistrationId(); - const int64_t version_id1 = GetNewVersionId(); + const int64_t version_id1 = GetNewVersionId().version_id; const int64_t resource_id1 = GetNewResourceId(); status = CreateAndStoreRegistration(registration_id1, version_id1, resource_id1, kScope1, kScriptUrl1, kScriptSize); ASSERT_EQ(status, DatabaseStatus::kOk); const int64_t registration_id2 = GetNewRegistrationId(); - const int64_t version_id2 = GetNewVersionId(); + const int64_t version_id2 = GetNewVersionId().version_id; const int64_t resource_id2 = GetNewResourceId(); status = CreateAndStoreRegistration(registration_id2, version_id2, resource_id2, @@ -933,6 +1025,83 @@ TEST_F(ServiceWorkerStorageControlImplTest, WriteAndReadResource) { } } +// Tests that uncommitted resources can be listed on storage and these resources +// will be committed when a registration is stored with these resources. +TEST_F(ServiceWorkerStorageControlImplTest, UncommittedResources) { + const GURL kScope("https://www.example.com/"); + const GURL kScriptUrl("https://www.example.com/sw.js"); + const GURL kImportedScriptUrl("https://www.example.com/imported.js"); + + LazyInitializeForTest(); + + // Preparation: Create a registration with two resources. These aren't written + // to storage yet. + std::vector<ResourceRecord> resources; + const int64_t resource_id1 = GetNewResourceId(); + const std::string resource_data1 = "main script data"; + resources.push_back(storage::mojom::ServiceWorkerResourceRecord::New( + resource_id1, kScriptUrl, resource_data1.size())); + + const int64_t resource_id2 = GetNewResourceId(); + const std::string resource_data2 = "imported script data"; + resources.push_back(storage::mojom::ServiceWorkerResourceRecord::New( + resource_id2, kImportedScriptUrl, resource_data2.size())); + + const int64_t registration_id = GetNewRegistrationId(); + const int64_t version_id = GetNewVersionId().version_id; + RegistrationData registration_data = CreateRegistrationData( + registration_id, version_id, kScope, kScriptUrl, resources); + + // Put these resources ids on the uncommitted list in storage. + DatabaseStatus status; + status = StoreUncommittedResourceId(resource_id1, kScope.GetOrigin()); + ASSERT_EQ(status, DatabaseStatus::kOk); + status = StoreUncommittedResourceId(resource_id2, kScope.GetOrigin()); + ASSERT_EQ(status, DatabaseStatus::kOk); + + std::vector<int64_t> uncommitted_ids = GetUncommittedResourceIds(); + EXPECT_EQ(uncommitted_ids.size(), 2UL); + + // Write responses and the registration data. + int result; + result = WriteResource(resource_id1, resource_data1); + ASSERT_GT(result, 0); + result = WriteResource(resource_id2, resource_data2); + ASSERT_GT(result, 0); + status = + StoreRegistration(std::move(registration_data), std::move(resources)); + ASSERT_EQ(status, DatabaseStatus::kOk); + + // Storing registration should take the resource ids out of the uncommitted + // list. + uncommitted_ids = GetUncommittedResourceIds(); + EXPECT_TRUE(uncommitted_ids.empty()); +} + +// Tests that uncommitted resource ids are purged by DoomUncommittedResources. +TEST_F(ServiceWorkerStorageControlImplTest, DoomUncommittedResources) { + const GURL kScope("https://www.example.com/"); + + LazyInitializeForTest(); + + const int64_t resource_id1 = GetNewResourceId(); + const int64_t resource_id2 = GetNewResourceId(); + + DatabaseStatus status; + status = StoreUncommittedResourceId(resource_id1, kScope.GetOrigin()); + ASSERT_EQ(status, DatabaseStatus::kOk); + status = StoreUncommittedResourceId(resource_id2, kScope.GetOrigin()); + ASSERT_EQ(status, DatabaseStatus::kOk); + + std::vector<int64_t> uncommitted_ids = GetUncommittedResourceIds(); + EXPECT_EQ(uncommitted_ids.size(), 2UL); + + status = DoomUncommittedResources({resource_id1, resource_id2}); + ASSERT_EQ(status, DatabaseStatus::kOk); + uncommitted_ids = GetUncommittedResourceIds(); + EXPECT_TRUE(uncommitted_ids.empty()); +} + // Tests that storing/getting user data for a registration work. TEST_F(ServiceWorkerStorageControlImplTest, StoreAndGetUserData) { const GURL kScope("https://www.example.com/"); @@ -942,7 +1111,7 @@ TEST_F(ServiceWorkerStorageControlImplTest, StoreAndGetUserData) { LazyInitializeForTest(); const int64_t registration_id = GetNewRegistrationId(); - const int64_t version_id = GetNewVersionId(); + const int64_t version_id = GetNewVersionId().version_id; const int64_t resource_id = GetNewResourceId(); DatabaseStatus status; status = CreateAndStoreRegistration(registration_id, version_id, resource_id, @@ -1002,7 +1171,7 @@ TEST_F(ServiceWorkerStorageControlImplTest, StoreAndGetUserData) { // Delete the registration and store a new registration for the same // scope. const int64_t new_registration_id = GetNewRegistrationId(); - const int64_t new_version_id = GetNewVersionId(); + const int64_t new_version_id = GetNewVersionId().version_id; const int64_t new_resource_id = GetNewResourceId(); { DeleteRegistrationResult result = @@ -1033,7 +1202,7 @@ TEST_F(ServiceWorkerStorageControlImplTest, StoreAndGetUserDataByKeyPrefix) { LazyInitializeForTest(); const int64_t registration_id = GetNewRegistrationId(); - const int64_t version_id = GetNewVersionId(); + const int64_t version_id = GetNewVersionId().version_id; const int64_t resource_id = GetNewResourceId(); DatabaseStatus status; status = CreateAndStoreRegistration(registration_id, version_id, resource_id, @@ -1111,14 +1280,14 @@ TEST_F(ServiceWorkerStorageControlImplTest, // Preparation: Create and store two registrations. DatabaseStatus status; const int64_t registration_id1 = GetNewRegistrationId(); - const int64_t version_id1 = GetNewVersionId(); + const int64_t version_id1 = GetNewVersionId().version_id; const int64_t resource_id1 = GetNewResourceId(); status = CreateAndStoreRegistration(registration_id1, version_id1, resource_id1, kScope1, kScriptUrl1, kScriptSize); ASSERT_EQ(status, DatabaseStatus::kOk); const int64_t registration_id2 = GetNewRegistrationId(); - const int64_t version_id2 = GetNewVersionId(); + const int64_t version_id2 = GetNewVersionId().version_id; const int64_t resource_id2 = GetNewResourceId(); status = CreateAndStoreRegistration(registration_id2, version_id2, resource_id2, @@ -1215,14 +1384,14 @@ TEST_F(ServiceWorkerStorageControlImplTest, ApplyPolicyUpdates) { // Preparation: Create and store two registrations. DatabaseStatus status; const int64_t registration_id1 = GetNewRegistrationId(); - const int64_t version_id1 = GetNewVersionId(); + const int64_t version_id1 = GetNewVersionId().version_id; const int64_t resource_id1 = GetNewResourceId(); status = CreateAndStoreRegistration(registration_id1, version_id1, resource_id1, kScope1, kScriptUrl1, kScriptSize); ASSERT_EQ(status, DatabaseStatus::kOk); const int64_t registration_id2 = GetNewRegistrationId(); - const int64_t version_id2 = GetNewVersionId(); + const int64_t version_id2 = GetNewVersionId().version_id; const int64_t resource_id2 = GetNewResourceId(); status = CreateAndStoreRegistration(registration_id2, version_id2, resource_id2, @@ -1248,4 +1417,92 @@ TEST_F(ServiceWorkerStorageControlImplTest, ApplyPolicyUpdates) { } } +TEST_F(ServiceWorkerStorageControlImplTest, TrackRunningVersion) { + const GURL kScope("https://www.example.com/"); + const GURL kScriptUrl("https://www.example.com/sw.js"); + const GURL kImportedScriptUrl("https://www.example.com/imported.js"); + + LazyInitializeForTest(); + + // Preparation: Create a registration with two resources (The main script and + // an imported script). + int result; + std::vector<ResourceRecord> resources; + const int64_t resource_id1 = GetNewResourceId(); + const std::string resource_data1 = "main script data"; + result = WriteResource(resource_id1, resource_data1); + ASSERT_GT(result, 0); + resources.push_back(storage::mojom::ServiceWorkerResourceRecord::New( + resource_id1, kScriptUrl, resource_data1.size())); + + const int64_t resource_id2 = GetNewResourceId(); + const std::string resource_data2 = "imported script data"; + result = WriteResource(resource_id2, resource_data2); + ASSERT_GT(result, 0); + resources.push_back(storage::mojom::ServiceWorkerResourceRecord::New( + resource_id2, kImportedScriptUrl, resource_data2.size())); + + const int64_t registration_id = GetNewRegistrationId(); + GetNewVersionIdResult new_version_id_result = GetNewVersionId(); + ASSERT_NE(new_version_id_result.version_id, + blink::mojom::kInvalidServiceWorkerVersionId); + const int64_t version_id = new_version_id_result.version_id; + RegistrationData registration_data = CreateRegistrationData( + registration_id, version_id, kScope, kScriptUrl, resources); + DatabaseStatus status = + StoreRegistration(std::move(registration_data), std::move(resources)); + ASSERT_EQ(status, DatabaseStatus::kOk); + + // Create two references, one from GetNewVersionId() and the other from + // FindRegistrationForId(). + mojo::Remote<storage::mojom::ServiceWorkerLiveVersionRef> reference1; + ASSERT_TRUE(new_version_id_result.reference); + reference1.Bind(std::move(new_version_id_result.reference)); + + mojo::Remote<storage::mojom::ServiceWorkerLiveVersionRef> reference2; + { + FindRegistrationResult result = + FindRegistrationForId(registration_id, kScope.GetOrigin()); + ASSERT_EQ(result->status, DatabaseStatus::kOk); + ASSERT_TRUE(result->version_reference); + reference2.Bind(std::move(result->version_reference)); + } + + // Drop the first reference and delete the registration. + reference1.reset(); + { + DeleteRegistrationResult result = + DeleteRegistration(registration_id, kScope.GetOrigin()); + ASSERT_EQ(result.status, DatabaseStatus::kOk); + } + + // Make sure all tasks are ran. + // TODO(bashi): Don't rely on RunAllTasksUntilIdle()? + content::RunAllTasksUntilIdle(); + + // Resources shouldn't be purged because there is an active reference. + { + std::string read_resource_data1 = + ReadResource(resource_id1, resource_data1.size()); + ASSERT_EQ(read_resource_data1, resource_data1); + std::string read_resource_data2 = + ReadResource(resource_id2, resource_data2.size()); + ASSERT_EQ(read_resource_data2, resource_data2); + } + + // Drop the second reference. + reference2.reset(); + content::RunAllTasksUntilIdle(); + + // Resources should have been purged. + { + std::string read_resource_data1 = + ReadResource(resource_id1, resource_data1.size()); + ASSERT_EQ(read_resource_data1, ""); + std::string read_resource_data2 = + ReadResource(resource_id2, resource_data2.size()); + ASSERT_EQ(read_resource_data2, ""); + } +} + } // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_storage_unittest.cc b/chromium/content/browser/service_worker/service_worker_storage_unittest.cc index 281985eedec..95b5bb61f54 100644 --- a/chromium/content/browser/service_worker/service_worker_storage_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_storage_unittest.cc @@ -333,6 +333,23 @@ class ServiceWorkerStorageTest : public testing::Test { return result.value(); } + ServiceWorkerDatabase::Status DeleteRegistrationById(int64_t registration_id, + const GURL& origin) { + ServiceWorkerDatabase::Status result; + base::RunLoop loop; + storage()->DeleteRegistration( + registration_id, origin, + base::BindLambdaForTesting( + [&](ServiceWorkerDatabase::Status status, + ServiceWorkerStorage::OriginState, int64_t deleted_version, + const std::vector<int64_t>& newly_purgeable_resources) { + result = status; + loop.Quit(); + })); + loop.Run(); + return result; + } + blink::ServiceWorkerStatusCode GetAllRegistrationsInfos( std::vector<ServiceWorkerRegistrationInfo>* registrations) { base::Optional<blink::ServiceWorkerStatusCode> result; @@ -349,6 +366,22 @@ class ServiceWorkerStorageTest : public testing::Test { return result.value(); } + blink::ServiceWorkerStatusCode GetStorageUsageForOrigin( + const url::Origin& origin, + int64_t& out_usage) { + blink::ServiceWorkerStatusCode result; + base::RunLoop loop; + registry()->GetStorageUsageForOrigin( + origin, base::BindLambdaForTesting( + [&](blink::ServiceWorkerStatusCode status, int64_t usage) { + result = status; + out_usage = usage; + loop.Quit(); + })); + loop.Run(); + return result; + } + blink::ServiceWorkerStatusCode GetRegistrationsForOrigin( const GURL& origin, std::vector<scoped_refptr<ServiceWorkerRegistration>>* registrations) { @@ -566,8 +599,8 @@ class ServiceWorkerStorageTest : public testing::Test { loop.Run(); } - std::set<int64_t> GetPurgeableResourceIdsFromDB() { - std::set<int64_t> ids; + std::vector<int64_t> GetPurgeableResourceIdsFromDB() { + std::vector<int64_t> ids; base::RunLoop loop; ServiceWorkerDatabase* database_raw = database(); storage()->database_task_runner_->PostTask( @@ -580,8 +613,8 @@ class ServiceWorkerStorageTest : public testing::Test { return ids; } - std::set<int64_t> GetUncommittedResourceIdsFromDB() { - std::set<int64_t> ids; + std::vector<int64_t> GetUncommittedResourceIdsFromDB() { + std::vector<int64_t> ids; base::RunLoop loop; ServiceWorkerDatabase* database_raw = database(); storage()->database_task_runner_->PostTask( @@ -1219,39 +1252,6 @@ TEST_F(ServiceWorkerStorageTest, EXPECT_TRUE(data_list_out.empty()); } -TEST_F(ServiceWorkerStorageTest, GetAllRegistrationsInfosFields) { - LazyInitialize(); - const GURL kScope("http://www.example.com/scope/"); - const GURL kScript("http://www.example.com/script1.js"); - scoped_refptr<ServiceWorkerRegistration> registration = - CreateServiceWorkerRegistrationAndVersion(context(), kScope, kScript, - /*resource_id=*/1); - - // Set some fields to check ServiceWorkerStorage serializes/deserializes - // these fields correctly. - registration->SetUpdateViaCache( - blink::mojom::ServiceWorkerUpdateViaCache::kImports); - registration->EnableNavigationPreload(true); - registration->SetNavigationPreloadHeader("header"); - - registry()->NotifyInstallingRegistration(registration.get()); - EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, - StoreRegistration(registration, registration->waiting_version())); - std::vector<ServiceWorkerRegistrationInfo> all_registrations; - EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, - GetAllRegistrationsInfos(&all_registrations)); - ASSERT_EQ(1u, all_registrations.size()); - - ServiceWorkerRegistrationInfo info = all_registrations[0]; - EXPECT_EQ(registration->scope(), info.scope); - EXPECT_EQ(registration->update_via_cache(), info.update_via_cache); - EXPECT_EQ(registration->id(), info.registration_id); - EXPECT_EQ(registration->navigation_preload_state().enabled, - info.navigation_preload_enabled); - EXPECT_EQ(registration->navigation_preload_state().header.size(), - info.navigation_preload_header_length); -} - class ServiceWorkerResourceStorageTest : public ServiceWorkerStorageTest { public: void SetUp() override { @@ -1293,7 +1293,7 @@ class ServiceWorkerResourceStorageTest : public ServiceWorkerStorageTest { registry()->StoreUncommittedResourceId(resource_id1_, scope_); registry()->StoreUncommittedResourceId(resource_id2_, scope_); - std::set<int64_t> verify_ids = GetUncommittedResourceIdsFromDB(); + std::vector<int64_t> verify_ids = GetUncommittedResourceIdsFromDB(); EXPECT_EQ(2u, verify_ids.size()); // And dump something in the disk cache for them. @@ -1440,7 +1440,7 @@ TEST_F(ServiceWorkerResourceStorageTest, DeleteRegistration_ActiveVersion) { registry()->UpdateToActiveState(registration_->id(), registration_->scope().GetOrigin(), base::DoNothing()); - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; base::WeakPtr<ServiceWorkerContainerHost> container_host = CreateContainerHostForWindow(33 /* dummy render process id */, true /* is_parent_frame_secure */, @@ -1477,7 +1477,7 @@ TEST_F(ServiceWorkerResourceStorageDiskTest, CleanupOnRestart) { registry()->UpdateToActiveState(registration_->id(), registration_->scope().GetOrigin(), base::DoNothing()); - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; base::WeakPtr<ServiceWorkerContainerHost> container_host = CreateContainerHostForWindow(33 /* dummy render process id */, true /* is_parent_frame_secure */, @@ -1488,7 +1488,7 @@ TEST_F(ServiceWorkerResourceStorageDiskTest, CleanupOnRestart) { // but keep them available. EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, DeleteRegistration(registration_, scope_.GetOrigin())); - std::set<int64_t> verify_ids = GetPurgeableResourceIdsFromDB(); + std::vector<int64_t> verify_ids = GetPurgeableResourceIdsFromDB(); EXPECT_EQ(2u, verify_ids.size()); EXPECT_TRUE(VerifyBasicResponse(storage(), resource_id1_, true)); @@ -1615,7 +1615,7 @@ TEST_F(ServiceWorkerResourceStorageTest, UpdateRegistration) { registry()->UpdateToActiveState(registration_->id(), registration_->scope().GetOrigin(), base::DoNothing()); - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; base::WeakPtr<ServiceWorkerContainerHost> container_host = CreateContainerHostForWindow( 33 /* dummy render process id */, true /* is_parent_frame_secure */, @@ -1700,68 +1700,6 @@ TEST_F(ServiceWorkerResourceStorageTest, UpdateRegistration_NoLiveVersion) { EXPECT_FALSE(VerifyBasicResponse(storage(), resource_id2_, false)); } -TEST_F(ServiceWorkerStorageTest, FindRegistration_LongestScopeMatch) { - LazyInitialize(); - const GURL kDocumentUrl("http://www.example.com/scope/foo"); - scoped_refptr<ServiceWorkerRegistration> found_registration; - - // Registration for "/scope/". - const GURL kScope1("http://www.example.com/scope/"); - const GURL kScript1("http://www.example.com/script1.js"); - scoped_refptr<ServiceWorkerRegistration> live_registration1 = - CreateServiceWorkerRegistrationAndVersion(context(), kScope1, kScript1, - /*resource_id=*/1); - - // Registration for "/scope/foo". - const GURL kScope2("http://www.example.com/scope/foo"); - const GURL kScript2("http://www.example.com/script2.js"); - scoped_refptr<ServiceWorkerRegistration> live_registration2 = - CreateServiceWorkerRegistrationAndVersion(context(), kScope2, kScript2, - /*resource_id=*/2); - - // Registration for "/scope/foobar". - const GURL kScope3("http://www.example.com/scope/foobar"); - const GURL kScript3("http://www.example.com/script3.js"); - scoped_refptr<ServiceWorkerRegistration> live_registration3 = - CreateServiceWorkerRegistrationAndVersion(context(), kScope3, kScript3, - /*resource_id=*/3); - - // Notify storage of them being installed. - registry()->NotifyInstallingRegistration(live_registration1.get()); - registry()->NotifyInstallingRegistration(live_registration2.get()); - registry()->NotifyInstallingRegistration(live_registration3.get()); - - // Find a registration among installing ones. - EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, - FindRegistrationForClientUrl(kDocumentUrl, &found_registration)); - EXPECT_EQ(live_registration2, found_registration); - found_registration = nullptr; - - // Store registrations. - EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, - StoreRegistration(live_registration1, - live_registration1->waiting_version())); - EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, - StoreRegistration(live_registration2, - live_registration2->waiting_version())); - EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, - StoreRegistration(live_registration3, - live_registration3->waiting_version())); - - // Notify storage of installations no longer happening. - registry()->NotifyDoneInstallingRegistration( - live_registration1.get(), nullptr, blink::ServiceWorkerStatusCode::kOk); - registry()->NotifyDoneInstallingRegistration( - live_registration2.get(), nullptr, blink::ServiceWorkerStatusCode::kOk); - registry()->NotifyDoneInstallingRegistration( - live_registration3.get(), nullptr, blink::ServiceWorkerStatusCode::kOk); - - // Find a registration among installed ones. - EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, - FindRegistrationForClientUrl(kDocumentUrl, &found_registration)); - EXPECT_EQ(live_registration2, found_registration); -} - // Test fixture that uses disk storage, rather than memory. Useful for tests // that test persistence by simulating browser shutdown and restart. class ServiceWorkerStorageDiskTest : public ServiceWorkerStorageTest { @@ -2090,6 +2028,68 @@ TEST_F(ServiceWorkerStorageDiskTest, RegisteredOriginCount) { } } +// Tests reading storage usage from database. +TEST_F(ServiceWorkerStorageTest, GetStorageUsageForOrigin) { + const GURL kScope1("https://www.example.com/foo/"); + const GURL kScript1("https://www.example.com/foo/sw.js"); + const GURL kScope2("https://www.example.com/bar/"); + const GURL kScript2("https://www.example.com/bar/sw.js"); + const GURL kScript3("https://www.example.com/bar/sub.js"); + + // Preparation: Store two registrations. + RegistrationData data1; + data1.registration_id = 1; + data1.scope = kScope1; + data1.script = kScript1; + data1.version_id = 1; + data1.is_active = true; + std::vector<ResourceRecord> resources1; + resources1.push_back(CreateResourceRecord(1, kScript1, 123)); + data1.resources_total_size_bytes = 0; + for (auto& resource : resources1) { + data1.resources_total_size_bytes += resource->size_bytes; + } + WriteRegistrationToDB(data1, std::move(resources1)); + + RegistrationData data2; + data2.registration_id = 2; + data2.scope = kScope2; + data2.script = kScript2; + data2.version_id = 1; + data2.is_active = true; + std::vector<ResourceRecord> resources2; + resources2.push_back(CreateResourceRecord(2, kScript2, 456)); + resources2.push_back(CreateResourceRecord(3, kScript3, 789)); + data2.resources_total_size_bytes = 0; + for (auto& resource : resources2) { + data2.resources_total_size_bytes += resource->size_bytes; + } + WriteRegistrationToDB(data2, std::move(resources2)); + + // Storage usage should report total resource size from two registrations. + const url::Origin origin = url::Origin::Create(kScope1.GetOrigin()); + int64_t usage; + EXPECT_EQ(GetStorageUsageForOrigin(origin, usage), + blink::ServiceWorkerStatusCode::kOk); + EXPECT_EQ(usage, data1.resources_total_size_bytes + + data2.resources_total_size_bytes); + + // Delete the first registration. Storage usage should report only the second + // registration. + EXPECT_EQ(DeleteRegistrationById(data1.registration_id, origin.GetURL()), + ServiceWorkerDatabase::Status::kOk); + EXPECT_EQ(GetStorageUsageForOrigin(origin, usage), + blink::ServiceWorkerStatusCode::kOk); + EXPECT_EQ(usage, data2.resources_total_size_bytes); + + // Delete the second registration. No storage usage should be reported. + EXPECT_EQ(DeleteRegistrationById(data2.registration_id, origin.GetURL()), + ServiceWorkerDatabase::Status::kOk); + EXPECT_EQ(GetStorageUsageForOrigin(origin, usage), + blink::ServiceWorkerStatusCode::kOk); + EXPECT_EQ(usage, 0); +} + // Tests loading a registration with a disabled navigation preload // state. TEST_F(ServiceWorkerStorageDiskTest, DisabledNavigationPreloadState) { @@ -2127,44 +2127,5 @@ TEST_F(ServiceWorkerStorageDiskTest, DisabledNavigationPreloadState) { EXPECT_EQ("true", state.header); } -// Tests loading a registration with an enabled navigation preload state, as -// well as a custom header value. -TEST_F(ServiceWorkerStorageDiskTest, EnabledNavigationPreloadState) { - LazyInitialize(); - const GURL kScope("https://valid.example.com/scope"); - const GURL kScript("https://valid.example.com/script.js"); - const std::string kHeaderValue("custom header value"); - scoped_refptr<ServiceWorkerRegistration> registration = - CreateServiceWorkerRegistrationAndVersion(context(), kScope, kScript, - /*resource_id=*/1); - ServiceWorkerVersion* version = registration->waiting_version(); - version->SetStatus(ServiceWorkerVersion::ACTIVATED); - registration->SetActiveVersion(version); - registration->EnableNavigationPreload(true); - registration->SetNavigationPreloadHeader(kHeaderValue); - - EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, - StoreRegistration(registration, version)); - - // Simulate browser shutdown and restart. - registration = nullptr; - version = nullptr; - InitializeTestHelper(); - LazyInitialize(); - - scoped_refptr<ServiceWorkerRegistration> found_registration; - EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, - FindRegistrationForClientUrl(kScope, &found_registration)); - const blink::mojom::NavigationPreloadState& registration_state = - found_registration->navigation_preload_state(); - EXPECT_TRUE(registration_state.enabled); - EXPECT_EQ(kHeaderValue, registration_state.header); - ASSERT_TRUE(found_registration->active_version()); - const blink::mojom::NavigationPreloadState& state = - found_registration->active_version()->navigation_preload_state(); - EXPECT_TRUE(state.enabled); - EXPECT_EQ(kHeaderValue, state.header); -} - } // namespace service_worker_storage_unittest } // namespace content diff --git a/chromium/content/browser/service_worker/service_worker_test_utils.cc b/chromium/content/browser/service_worker/service_worker_test_utils.cc index a99d755c05d..d073ab43966 100644 --- a/chromium/content/browser/service_worker/service_worker_test_utils.cc +++ b/chromium/content/browser/service_worker/service_worker_test_utils.cc @@ -22,7 +22,7 @@ #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_database.h" #include "content/browser/service_worker/service_worker_disk_cache.h" -#include "content/browser/service_worker/service_worker_provider_host.h" +#include "content/browser/service_worker/service_worker_host.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_storage.h" #include "content/common/frame.mojom.h" @@ -34,6 +34,8 @@ #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h" +#include "mojo/public/cpp/system/data_pipe.h" +#include "mojo/public/cpp/system/data_pipe_utils.h" #include "net/base/completion_once_callback.h" #include "net/base/io_buffer.h" #include "net/base/test_completion_callback.h" @@ -104,7 +106,7 @@ class MockPendingSharedURLLoaderFactory final class FakeNavigationClient : public mojom::NavigationClient { public: using ReceivedProviderInfoCallback = base::OnceCallback<void( - blink::mojom::ServiceWorkerProviderInfoForClientPtr)>; + blink::mojom::ServiceWorkerContainerInfoForClientPtr)>; explicit FakeNavigationClient( ReceivedProviderInfoCallback on_received_callback) @@ -125,12 +127,12 @@ class FakeNavigationClient : public mojom::NavigationClient { subresource_overrides, blink::mojom::ControllerServiceWorkerInfoPtr controller_service_worker_info, - blink::mojom::ServiceWorkerProviderInfoForClientPtr provider_info, + blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info, mojo::PendingRemote<network::mojom::URLLoaderFactory> prefetch_loader_factory, const base::UnguessableToken& devtools_navigation_token, CommitNavigationCallback callback) override { - std::move(on_received_callback_).Run(std::move(provider_info)); + std::move(on_received_callback_).Run(std::move(container_info)); std::move(callback).Run(nullptr, nullptr); } void CommitFailedNavigation( @@ -254,30 +256,32 @@ storage::mojom::ServiceWorkerResourceRecordPtr WriteToDiskCacheSyncInternal( } // namespace -ServiceWorkerRemoteProviderEndpoint::ServiceWorkerRemoteProviderEndpoint() {} -ServiceWorkerRemoteProviderEndpoint::ServiceWorkerRemoteProviderEndpoint( - ServiceWorkerRemoteProviderEndpoint&& other) +ServiceWorkerRemoteContainerEndpoint::ServiceWorkerRemoteContainerEndpoint() = + default; +ServiceWorkerRemoteContainerEndpoint::ServiceWorkerRemoteContainerEndpoint( + ServiceWorkerRemoteContainerEndpoint&& other) : navigation_client_(std::move(other.navigation_client_)), host_remote_(std::move(other.host_remote_)), client_receiver_(std::move(other.client_receiver_)) {} -ServiceWorkerRemoteProviderEndpoint::~ServiceWorkerRemoteProviderEndpoint() {} +ServiceWorkerRemoteContainerEndpoint::~ServiceWorkerRemoteContainerEndpoint() = + default; -void ServiceWorkerRemoteProviderEndpoint::BindForWindow( - blink::mojom::ServiceWorkerProviderInfoForClientPtr info) { +void ServiceWorkerRemoteContainerEndpoint::BindForWindow( + blink::mojom::ServiceWorkerContainerInfoForClientPtr info) { // We establish a message pipe for connecting |navigation_client_| to a fake // navigation client, then simulate sending the navigation commit IPC which - // carries a service worker provider info over it, then the provider info + // carries a service worker container info over it, then the container info // received there gets its |host_remote| and |client_receiver| associated // with a message pipe so that their users later can make Mojo calls without // crash. - blink::mojom::ServiceWorkerProviderInfoForClientPtr received_info; + blink::mojom::ServiceWorkerContainerInfoForClientPtr received_info; base::RunLoop loop(base::RunLoop::Type::kNestableTasksAllowed); mojo::MakeSelfOwnedReceiver( std::make_unique<FakeNavigationClient>(base::BindOnce( [](base::OnceClosure quit_closure, - blink::mojom::ServiceWorkerProviderInfoForClientPtr* out_info, - blink::mojom::ServiceWorkerProviderInfoForClientPtr info) { + blink::mojom::ServiceWorkerContainerInfoForClientPtr* out_info, + blink::mojom::ServiceWorkerContainerInfoForClientPtr info) { *out_info = std::move(info); std::move(quit_closure).Run(); }, @@ -300,14 +304,14 @@ void ServiceWorkerRemoteProviderEndpoint::BindForWindow( host_remote_.Bind(std::move(received_info->host_remote)); } -void ServiceWorkerRemoteProviderEndpoint::BindForServiceWorker( +void ServiceWorkerRemoteContainerEndpoint::BindForServiceWorker( blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr info) { host_remote_.Bind(std::move(info->host_remote)); } ServiceWorkerContainerHostAndInfo::ServiceWorkerContainerHostAndInfo( base::WeakPtr<ServiceWorkerContainerHost> host, - blink::mojom::ServiceWorkerProviderInfoForClientPtr info) + blink::mojom::ServiceWorkerContainerInfoForClientPtr info) : host(std::move(host)), info(std::move(info)) {} ServiceWorkerContainerHostAndInfo::~ServiceWorkerContainerHostAndInfo() = @@ -317,7 +321,7 @@ base::WeakPtr<ServiceWorkerContainerHost> CreateContainerHostForWindow( int process_id, bool is_parent_frame_secure, base::WeakPtr<ServiceWorkerContextCore> context, - ServiceWorkerRemoteProviderEndpoint* output_endpoint) { + ServiceWorkerRemoteContainerEndpoint* output_endpoint) { std::unique_ptr<ServiceWorkerContainerHostAndInfo> host_and_info = CreateContainerHostAndInfoForWindow(context, is_parent_frame_secure); base::WeakPtr<ServiceWorkerContainerHost> container_host = @@ -345,13 +349,13 @@ CreateContainerHostAndInfoForWindow( client_remote; mojo::PendingAssociatedReceiver<blink::mojom::ServiceWorkerContainerHost> host_receiver; - auto info = blink::mojom::ServiceWorkerProviderInfoForClient::New(); + auto info = blink::mojom::ServiceWorkerContainerInfoForClient::New(); info->client_receiver = client_remote.InitWithNewEndpointAndPassReceiver(); host_receiver = info->host_remote.InitWithNewEndpointAndPassReceiver(); return std::make_unique<ServiceWorkerContainerHostAndInfo>( context->CreateContainerHostForWindow( std::move(host_receiver), are_ancestors_secure, - std::move(client_remote), FrameTreeNode::kFrameTreeNodeInvalidId), + std::move(client_remote), /*frame_tree_node_id=*/1), std::move(info)); } @@ -388,16 +392,15 @@ void StopServiceWorker(ServiceWorkerVersion* version) { run_loop.Run(); } -std::unique_ptr<ServiceWorkerProviderHost> -CreateProviderHostForServiceWorkerContext( +std::unique_ptr<ServiceWorkerHost> CreateServiceWorkerHost( int process_id, bool is_parent_frame_secure, ServiceWorkerVersion* hosted_version, base::WeakPtr<ServiceWorkerContextCore> context, - ServiceWorkerRemoteProviderEndpoint* output_endpoint) { + ServiceWorkerRemoteContainerEndpoint* output_endpoint) { auto provider_info = blink::mojom::ServiceWorkerProviderInfoForStartWorker::New(); - auto host = std::make_unique<ServiceWorkerProviderHost>( + auto host = std::make_unique<ServiceWorkerHost>( provider_info->host_remote.InitWithNewEndpointAndPassReceiver(), hosted_version, std::move(context)); @@ -543,6 +546,14 @@ MockServiceWorkerResponseReader::MockServiceWorkerResponseReader() MockServiceWorkerResponseReader::~MockServiceWorkerResponseReader() {} +mojo::PendingRemote<storage::mojom::ServiceWorkerResourceReader> +MockServiceWorkerResponseReader::BindNewPipeAndPassRemote( + base::OnceClosure disconnect_handler) { + auto remote = receiver_.BindNewPipeAndPassRemote(); + receiver_.set_disconnect_handler(std::move(disconnect_handler)); + return remote; +} + void MockServiceWorkerResponseReader::ReadInfo( HttpResponseInfoIOBuffer* info_buf, net::CompletionOnceCallback callback) { @@ -560,14 +571,8 @@ void MockServiceWorkerResponseReader::ReadInfo( DCHECK(!expected_reads_.empty()); ExpectedRead expected = expected_reads_.front(); EXPECT_TRUE(expected.info); - if (expected.async) { - pending_info_ = info_buf; - pending_callback_ = std::move(callback); - } else { - expected_reads_.pop(); - info_buf->response_data_size = expected.len; - std::move(callback).Run(expected.result); - } + pending_info_ = info_buf; + pending_callback_ = std::move(callback); } void MockServiceWorkerResponseReader::ReadData( @@ -578,69 +583,105 @@ void MockServiceWorkerResponseReader::ReadData( ExpectedRead expected = expected_reads_.front(); EXPECT_FALSE(expected.info); EXPECT_LE(static_cast<int>(expected.len), buf_len); - if (expected.async) { - pending_callback_ = std::move(callback); - pending_buffer_ = buf; - pending_buffer_len_ = static_cast<size_t>(buf_len); - } else { - expected_reads_.pop(); - if (expected.len > 0) { - size_t to_read = std::min(static_cast<size_t>(buf_len), expected.len); - memcpy(buf->data(), expected.data, to_read); - } - std::move(callback).Run(expected.result); - } + pending_callback_ = std::move(callback); + pending_buffer_ = buf; + pending_buffer_len_ = static_cast<size_t>(buf_len); } -void MockServiceWorkerResponseReader::ExpectReadInfo(size_t len, - bool async, - int result) { - expected_reads_.push(ExpectedRead(len, async, result)); +void MockServiceWorkerResponseReader::ReadResponseHead( + storage::mojom::ServiceWorkerResourceReader::ReadResponseHeadCallback + callback) { + pending_read_response_head_callback_ = std::move(callback); } -void MockServiceWorkerResponseReader::ExpectReadInfoOk(size_t len, bool async) { - expected_reads_.push(ExpectedRead(len, async, len)); +void MockServiceWorkerResponseReader::ReadData(int64_t, + ReadDataCallback callback) { + DCHECK(!body_.is_valid()); + mojo::ScopedDataPipeConsumerHandle consumer; + MojoCreateDataPipeOptions options; + options.struct_size = sizeof(MojoCreateDataPipeOptions); + options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE; + options.element_num_bytes = 1; + options.capacity_num_bytes = expected_max_data_bytes_; + mojo::CreateDataPipe(&options, &body_, &consumer); + std::move(callback).Run(std::move(std::move(consumer))); +} + +void MockServiceWorkerResponseReader::ExpectReadInfo(size_t len, int result) { + expected_reads_.push(ExpectedRead(len, result)); +} + +void MockServiceWorkerResponseReader::ExpectReadInfoOk(size_t len) { + expected_reads_.push(ExpectedRead(len, len)); } void MockServiceWorkerResponseReader::ExpectReadData(const char* data, size_t len, - bool async, int result) { - expected_reads_.push(ExpectedRead(data, len, async, result)); + expected_max_data_bytes_ = std::max(expected_max_data_bytes_, len); + expected_reads_.push(ExpectedRead(data, len, result)); } -void MockServiceWorkerResponseReader::ExpectReadDataOk(const std::string& data, - bool async) { - expected_reads_.push( - ExpectedRead(data.data(), data.size(), async, data.size())); +void MockServiceWorkerResponseReader::ExpectReadDataOk( + const std::string& data) { + expected_reads_.push(ExpectedRead(data.data(), data.size(), data.size())); } void MockServiceWorkerResponseReader::ExpectReadOk( const std::vector<std::string>& stored_data, - const size_t bytes_stored, - const bool async) { - ExpectReadInfoOk(bytes_stored, async); + const size_t bytes_stored) { + ExpectReadInfoOk(bytes_stored); for (const auto& data : stored_data) - ExpectReadDataOk(data, async); + ExpectReadDataOk(data); } void MockServiceWorkerResponseReader::CompletePendingRead() { DCHECK(!expected_reads_.empty()); ExpectedRead expected = expected_reads_.front(); expected_reads_.pop(); - EXPECT_TRUE(expected.async); + + // Legacy API calls. + // TODO(https://crbug.com/1055677): Remove this when ReadInfo() and legacy + // ReadData() are removed. + if (pending_callback_) { + if (expected.info) { + pending_info_->response_data_size = expected.len; + std::move(pending_callback_).Run(expected.result); + } else { + if (expected.len > 0) { + size_t to_read = + std::min(static_cast<size_t>(pending_buffer_len_), expected.len); + memcpy(pending_buffer_->data(), expected.data, to_read); + } + std::move(pending_callback_).Run(expected.result); + } + return; + } + + // Make sure that all messages are received at this point. + receiver_.FlushForTesting(); + if (expected.info) { - pending_info_->response_data_size = expected.len; + DCHECK(pending_read_response_head_callback_); + auto response_head = network::mojom::URLResponseHead::New(); + response_head->headers = + base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.0 200 OK\0\0"); + response_head->content_length = expected.len; + std::move(pending_read_response_head_callback_) + .Run(expected.result, std::move(response_head), + /*metadata=*/base::nullopt); } else { - size_t to_read = std::min(pending_buffer_len_, expected.len); - if (to_read > 0) - memcpy(pending_buffer_->data(), expected.data, to_read); + if (expected.len == 0) { + body_.reset(); + } else { + DCHECK(body_.is_valid()); + EXPECT_TRUE(mojo::BlockingCopyFromString( + std::string(expected.data, expected.len), body_)); + } } - pending_info_ = nullptr; - pending_buffer_ = nullptr; - net::CompletionOnceCallback callback = std::move(pending_callback_); - pending_callback_.Reset(); - std::move(callback).Run(expected.result); + + // Wait until the body is received by the user of the response reader. + base::RunLoop().RunUntilIdle(); } MockServiceWorkerResponseWriter::MockServiceWorkerResponseWriter() diff --git a/chromium/content/browser/service_worker/service_worker_test_utils.h b/chromium/content/browser/service_worker/service_worker_test_utils.h index 79e1ec6379e..335ab186148 100644 --- a/chromium/content/browser/service_worker/service_worker_test_utils.h +++ b/chromium/content/browser/service_worker/service_worker_test_utils.h @@ -12,10 +12,11 @@ #include "base/command_line.h" #include "base/memory/weak_ptr.h" #include "base/task/post_task.h" +#include "components/services/storage/public/mojom/service_worker_storage_control.mojom.h" #include "content/browser/service_worker/service_worker_cache_writer.h" #include "content/browser/service_worker/service_worker_database.h" #include "content/browser/service_worker/service_worker_disk_cache.h" -#include "content/browser/service_worker/service_worker_provider_host.h" +#include "content/browser/service_worker/service_worker_host.h" #include "content/browser/service_worker/service_worker_single_script_update_checker.h" #include "content/common/navigation_client.mojom.h" #include "content/public/browser/browser_task_traits.h" @@ -33,7 +34,7 @@ namespace content { class EmbeddedWorkerTestHelper; class ServiceWorkerContextCore; -class ServiceWorkerProviderHost; +class ServiceWorkerHost; class ServiceWorkerRegistry; class ServiceWorkerStorage; class ServiceWorkerVersion; @@ -65,16 +66,16 @@ blink::ServiceWorkerStatusCode StartServiceWorker( void StopServiceWorker(ServiceWorkerVersion* version); -// Container for keeping the Mojo connection to the service worker provider on +// Container for keeping the Mojo connection to the service worker container on // the renderer alive. -class ServiceWorkerRemoteProviderEndpoint { +class ServiceWorkerRemoteContainerEndpoint { public: - ServiceWorkerRemoteProviderEndpoint(); - ServiceWorkerRemoteProviderEndpoint( - ServiceWorkerRemoteProviderEndpoint&& other); - ~ServiceWorkerRemoteProviderEndpoint(); + ServiceWorkerRemoteContainerEndpoint(); + ServiceWorkerRemoteContainerEndpoint( + ServiceWorkerRemoteContainerEndpoint&& other); + ~ServiceWorkerRemoteContainerEndpoint(); - void BindForWindow(blink::mojom::ServiceWorkerProviderInfoForClientPtr info); + void BindForWindow(blink::mojom::ServiceWorkerContainerInfoForClientPtr info); void BindForServiceWorker( blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr info); @@ -96,26 +97,26 @@ class ServiceWorkerRemoteProviderEndpoint { // blink::mojom::EmbeddedWorkerInstanceClient connection if in the future we // really need to make |host_remote_| and |client_receiver_| usable for it. mojo::Remote<mojom::NavigationClient> navigation_client_; - // Bound with content::ServiceWorkerProviderHost. The provider host will be + // Bound with content::ServiceWorkerContainerHost. The container host will be // removed asynchronously when this remote is closed. mojo::AssociatedRemote<blink::mojom::ServiceWorkerContainerHost> host_remote_; // This is the other end of // mojo::PendingAssociatedRemote<ServiceWorkerContainer> owned by - // content::ServiceWorkerProviderHost. + // content::ServiceWorkerContainerHost. mojo::PendingAssociatedReceiver<blink::mojom::ServiceWorkerContainer> client_receiver_; - DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRemoteProviderEndpoint); + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerRemoteContainerEndpoint); }; struct ServiceWorkerContainerHostAndInfo { ServiceWorkerContainerHostAndInfo( base::WeakPtr<ServiceWorkerContainerHost> host, - blink::mojom::ServiceWorkerProviderInfoForClientPtr); + blink::mojom::ServiceWorkerContainerInfoForClientPtr); ~ServiceWorkerContainerHostAndInfo(); base::WeakPtr<ServiceWorkerContainerHost> host; - blink::mojom::ServiceWorkerProviderInfoForClientPtr info; + blink::mojom::ServiceWorkerContainerInfoForClientPtr info; DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContainerHostAndInfo); }; @@ -127,7 +128,7 @@ base::WeakPtr<ServiceWorkerContainerHost> CreateContainerHostForWindow( int process_id, bool is_parent_frame_secure, base::WeakPtr<ServiceWorkerContextCore> context, - ServiceWorkerRemoteProviderEndpoint* output_endpoint); + ServiceWorkerRemoteContainerEndpoint* output_endpoint); // Creates a container host that can be used for a navigation. std::unique_ptr<ServiceWorkerContainerHostAndInfo> @@ -135,13 +136,12 @@ CreateContainerHostAndInfoForWindow( base::WeakPtr<ServiceWorkerContextCore> context, bool are_ancestors_secure); -std::unique_ptr<ServiceWorkerProviderHost> -CreateProviderHostForServiceWorkerContext( +std::unique_ptr<ServiceWorkerHost> CreateServiceWorkerHost( int process_id, bool is_parent_frame_secure, ServiceWorkerVersion* hosted_version, base::WeakPtr<ServiceWorkerContextCore> context, - ServiceWorkerRemoteProviderEndpoint* output_endpoint); + ServiceWorkerRemoteContainerEndpoint* output_endpoint); // Calls CreateNewRegistration() synchronously. scoped_refptr<ServiceWorkerRegistration> CreateNewServiceWorkerRegistration( @@ -226,18 +226,29 @@ int64_t GetNewResourceIdSync(ServiceWorkerStorage* storage); // must be completed by the test using CompletePendingRead(). // These is a convenience method AllExpectedReadsDone() which returns whether // there are any expected reads that have not yet happened. -class MockServiceWorkerResponseReader : public ServiceWorkerResponseReader { +class MockServiceWorkerResponseReader + : public ServiceWorkerResponseReader, + public storage::mojom::ServiceWorkerResourceReader { public: MockServiceWorkerResponseReader(); ~MockServiceWorkerResponseReader() override; - // ServiceWorkerResponseReader overrides + mojo::PendingRemote<storage::mojom::ServiceWorkerResourceReader> + BindNewPipeAndPassRemote(base::OnceClosure disconnect_handler); + + // ServiceWorkerResponseReader overrides: void ReadInfo(HttpResponseInfoIOBuffer* info_buf, net::CompletionOnceCallback callback) override; void ReadData(net::IOBuffer* buf, int buf_len, net::CompletionOnceCallback callback) override; + // storage::mojom::ServiceWorkerResourceReader overrides: + void ReadResponseHead( + storage::mojom::ServiceWorkerResourceReader::ReadResponseHeadCallback + callback) override; + void ReadData(int64_t, ReadDataCallback callback) override; + // Test helpers. ExpectReadInfo() and ExpectReadData() give precise control // over both the data to be written and the result to return. // ExpectReadInfoOk() and ExpectReadDataOk() are convenience functions for @@ -245,20 +256,20 @@ class MockServiceWorkerResponseReader : public ServiceWorkerResponseReader { // Expect a call to ReadInfo() on this reader. For these functions, |len| will // be used as |response_data_size|, not as the length of this particular read. - void ExpectReadInfo(size_t len, bool async, int result); - void ExpectReadInfoOk(size_t len, bool async); + // TODO(https://crbug.com/1055677): Rename this to ExpectReadResponseHead(). + void ExpectReadInfo(size_t len, int result); + void ExpectReadInfoOk(size_t len); // Expect a call to ReadData() on this reader. For these functions, |len| is // the length of the data to be written back; in ExpectReadDataOk(), |len| is // implicitly the length of |data|. - void ExpectReadData(const char* data, size_t len, bool async, int result); - void ExpectReadDataOk(const std::string& data, bool async); + void ExpectReadData(const char* data, size_t len, int result); + void ExpectReadDataOk(const std::string& data); // Convenient method for calling ExpectReadInfoOk() with the length being // |bytes_stored|, and ExpectReadDataOk() for each element of |stored_data|. void ExpectReadOk(const std::vector<std::string>& stored_data, - const size_t bytes_stored, - const bool async); + const size_t bytes_stored); // Complete a pending async read. It is an error to call this function without // a pending async read (ie, a previous call to ReadInfo() or ReadData() @@ -270,23 +281,31 @@ class MockServiceWorkerResponseReader : public ServiceWorkerResponseReader { private: struct ExpectedRead { - ExpectedRead(size_t len, bool async, int result) - : data(nullptr), len(len), info(true), async(async), result(result) {} - ExpectedRead(const char* data, size_t len, bool async, int result) - : data(data), len(len), info(false), async(async), result(result) {} + ExpectedRead(size_t len, int result) + : data(nullptr), len(len), info(true), result(result) {} + ExpectedRead(const char* data, size_t len, int result) + : data(data), len(len), info(false), result(result) {} const char* data; size_t len; bool info; - bool async; int result; }; base::queue<ExpectedRead> expected_reads_; + size_t expected_max_data_bytes_ = 0; + scoped_refptr<net::IOBuffer> pending_buffer_; size_t pending_buffer_len_; scoped_refptr<HttpResponseInfoIOBuffer> pending_info_; net::CompletionOnceCallback pending_callback_; + mojo::Receiver<storage::mojom::ServiceWorkerResourceReader> receiver_{this}; + storage::mojom::ServiceWorkerResourceReader::ReadResponseHeadCallback + pending_read_response_head_callback_; + storage::mojom::ServiceWorkerResourceReader::ReadDataCallback + pending_read_data_callback_; + mojo::ScopedDataPipeProducerHandle body_; + DISALLOW_COPY_AND_ASSIGN(MockServiceWorkerResponseReader); }; diff --git a/chromium/content/browser/service_worker/service_worker_updated_script_loader.cc b/chromium/content/browser/service_worker/service_worker_updated_script_loader.cc index 5e2fd29c0cb..1d4c25ad57b 100644 --- a/chromium/content/browser/service_worker/service_worker_updated_script_loader.cc +++ b/chromium/content/browser/service_worker/service_worker_updated_script_loader.cc @@ -13,7 +13,6 @@ #include "base/task/post_task.h" #include "content/browser/appcache/appcache_disk_cache_ops.h" #include "content/browser/frame_host/frame_tree_node.h" -#include "content/browser/loader/url_loader_throttles.h" #include "content/browser/service_worker/service_worker_cache_writer.h" #include "content/browser/service_worker/service_worker_consts.h" #include "content/browser/service_worker/service_worker_context_core.h" @@ -25,6 +24,7 @@ #include "content/common/service_worker/service_worker_utils.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/content_browser_client.h" +#include "content/public/browser/url_loader_throttles.h" #include "content/public/common/content_client.h" #include "net/base/ip_endpoint.h" #include "net/base/load_flags.h" diff --git a/chromium/content/browser/service_worker/service_worker_version.cc b/chromium/content/browser/service_worker/service_worker_version.cc index ec5148ecd36..961defbb7dd 100644 --- a/chromium/content/browser/service_worker/service_worker_version.cc +++ b/chromium/content/browser/service_worker/service_worker_version.cc @@ -12,6 +12,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/check.h" #include "base/command_line.h" #include "base/debug/dump_without_crashing.h" #include "base/guid.h" @@ -35,8 +36,8 @@ #include "content/browser/service_worker/service_worker_container_host.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_host.h" #include "content/browser/service_worker/service_worker_installed_scripts_sender.h" -#include "content/browser/service_worker/service_worker_provider_host.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/common/content_navigation_policy.h" #include "content/common/service_worker/service_worker_utils.h" @@ -388,12 +389,19 @@ ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() { script_origin(), registration_id(), version_id(), embedded_worker()->process_id(), embedded_worker()->thread_id(), embedded_worker()->worker_devtools_agent_route_id()); + + UMA_HISTOGRAM_COUNTS_10000("ServiceWorker.VersionInfo.ScriptURLLength", + info.script_url.spec().length()); + for (const auto& controllee : controllee_map_) { ServiceWorkerContainerHost* container_host = controllee.second; info.clients.emplace(container_host->client_uuid(), container_host->GetServiceWorkerClientInfo()); } + UMA_HISTOGRAM_COUNTS_10000("ServiceWorker.VersionInfo.ClientCount", + info.clients.size()); + info.script_response_time = script_response_time_for_devtools_; if (!main_script_response_) return info; @@ -458,7 +466,7 @@ void ServiceWorkerVersion::StartWorker(ServiceWorkerMetrics::EventType purpose, // Ensure the live registration during starting worker so that the worker can // get associated with it in - // ServiceWorkerProviderHost::CompleteStartWorkerPreparation. + // ServiceWorkerHost::CompleteStartWorkerPreparation. context_->registry()->FindRegistrationForId( registration_id_, scope_.GetOrigin(), base::BindOnce( @@ -476,6 +484,12 @@ void ServiceWorkerVersion::StopWorker(base::OnceClosure callback) { switch (running_status()) { case EmbeddedWorkerStatus::STARTING: case EmbeddedWorkerStatus::RUNNING: { + // Endpoint isn't available after calling StopWorker(). This needs to be + // set here without waiting until the worker is actually stopped because + // subsequent StartWorker() may read the flag to decide whether an event + // can be dispatched or not. + is_endpoint_ready_ = false; + // EmbeddedWorkerInstance::Stop() may synchronously call // ServiceWorkerVersion::OnStopped() and destroy |this|. This protection // avoids it. @@ -582,8 +596,9 @@ int ServiceWorkerVersion::StartRequestWithCustomTimeout( StatusCallback error_callback, const base::TimeDelta& timeout, TimeoutBehavior timeout_behavior) { - DCHECK_EQ(EmbeddedWorkerStatus::RUNNING, running_status()) - << "Can only start a request with a running worker."; + DCHECK(EmbeddedWorkerStatus::RUNNING == running_status() || + EmbeddedWorkerStatus::STARTING == running_status()) + << "Can only start a request with a running or starting worker."; DCHECK(event_type == ServiceWorkerMetrics::EventType::INSTALL || event_type == ServiceWorkerMetrics::EventType::ACTIVATE || event_type == ServiceWorkerMetrics::EventType::MESSAGE || @@ -753,14 +768,11 @@ void ServiceWorkerVersion::AddControllee( CHECK_NE(status_, INSTALLED); CHECK_NE(status_, REDUNDANT); - if (base::FeatureList::IsEnabled( - features::kServiceWorkerTerminationOnNoControllee) && - !HasControllee()) { - // If the service worker starts to control a new client and the service - // worker needs to work, let's extend the idle timeout to the default value. - UpdateIdleDelayIfNeeded(base::TimeDelta::FromSeconds( - blink::mojom::kServiceWorkerDefaultIdleDelayInSeconds)); - } + // Set the idle timeout to the default value if there's no controllee and the + // worker is running because the worker's idle delay has been set to a shorter + // value when all controllee are gone. + MaybeUpdateIdleDelayForTerminationOnNoControllee(base::TimeDelta::FromSeconds( + blink::mojom::kServiceWorkerDefaultIdleDelayInSeconds)); controllee_map_[uuid] = container_host; embedded_worker_->UpdateForegroundPriority(); @@ -777,6 +789,14 @@ void ServiceWorkerVersion::AddControllee( FROM_HERE, base::BindOnce(&ServiceWorkerVersion::NotifyControlleeAdded, weak_factory_.GetWeakPtr(), uuid, container_host->GetServiceWorkerClientInfo())); + + // Also send a notification if OnEndNavigationCommit() was already invoked for + // this container. + if (container_host->navigation_commit_ended()) { + OnControlleeNavigationCommitted(container_host->client_uuid(), + container_host->process_id(), + container_host->frame_id()); + } } void ServiceWorkerVersion::RemoveControllee(const std::string& client_uuid) { @@ -787,22 +807,38 @@ void ServiceWorkerVersion::RemoveControllee(const std::string& client_uuid) { embedded_worker_->UpdateForegroundPriority(); // Notify observers asynchronously since this gets called during - // ServiceWorkerProviderHost's destructor, and we don't want observers to do - // work during that. + // ServiceWorkerHost's destructor, and we don't want observers to do work + // during that. base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&ServiceWorkerVersion::NotifyControlleeRemoved, weak_factory_.GetWeakPtr(), client_uuid)); - if (base::FeatureList::IsEnabled( - features::kServiceWorkerTerminationOnNoControllee) && - !HasControllee()) { - // Terminate the worker after all controllees are gone with a delay set by - // |kTerminationDelayParam|, which is provided by the field trial. - // When a new controllee checks in before the delay passes, the idle delay - // is set to the default in AddControllee(). - UpdateIdleDelayIfNeeded( - base::TimeDelta::FromMilliseconds(kTerminationDelayParam.Get())); - } + // When a new controllee checks in before the delay passes, the idle delay + // is set to the default in AddControllee(). + MaybeUpdateIdleDelayForTerminationOnNoControllee( + base::TimeDelta::FromMilliseconds(kTerminationDelayParam.Get())); +} + +void ServiceWorkerVersion::OnControlleeNavigationCommitted( + const std::string& client_uuid, + int process_id, + int frame_id) { + DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); + +#if DCHECK_IS_ON() + // Ensures this function is only called for a known window client. + auto it = controllee_map_.find(client_uuid); + DCHECK(it != controllee_map_.end()); + + DCHECK_EQ(it->second->GetClientType(), + blink::mojom::ServiceWorkerClientType::kWindow); +#endif // DCHECK_IS_ON() + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(&ServiceWorkerVersion::NotifyControlleeNavigationCommitted, + weak_factory_.GetWeakPtr(), client_uuid, + GlobalFrameRoutingId(process_id, frame_id))); } void ServiceWorkerVersion::MoveControlleeToBackForwardCacheMap( @@ -998,15 +1034,17 @@ void ServiceWorkerVersion::InitializeGlobalScope( /*subresource_loader_factories=*/nullptr); } - DCHECK(provider_host_); + DCHECK(worker_host_); + DCHECK(service_worker_remote_); service_worker_remote_->InitializeGlobalScope( std::move(service_worker_host_), - provider_host_->container_host() - ->CreateServiceWorkerRegistrationObjectInfo(std::move(registration)), - provider_host_->container_host()->CreateServiceWorkerObjectInfoToSend( - this), + worker_host_->container_host()->CreateServiceWorkerRegistrationObjectInfo( + std::move(registration)), + worker_host_->container_host()->CreateServiceWorkerObjectInfoToSend(this), fetch_handler_existence_, std::move(subresource_loader_factories), std::move(reporting_observer_receiver_)); + + is_endpoint_ready_ = true; } void ServiceWorkerVersion::SetValidOriginTrialTokens( @@ -1170,6 +1208,9 @@ void ServiceWorkerVersion::OnStarted( for (const std::string& request_uuid : pending_external_requests) StartExternalRequest(request_uuid); } + + MaybeUpdateIdleDelayForTerminationOnNoControllee( + base::TimeDelta::FromMilliseconds(kTerminationDelayParam.Get())); } void ServiceWorkerVersion::OnStopping() { @@ -1807,8 +1848,8 @@ void ServiceWorkerVersion::StartWorkerInternal() { auto provider_info = blink::mojom::ServiceWorkerProviderInfoForStartWorker::New(); - DCHECK(!provider_host_); - provider_host_ = std::make_unique<ServiceWorkerProviderHost>( + DCHECK(!worker_host_); + worker_host_ = std::make_unique<content::ServiceWorkerHost>( provider_info->host_remote.InitWithNewEndpointAndPassReceiver(), this, context()); @@ -1844,11 +1885,13 @@ void ServiceWorkerVersion::StartWorkerInternal() { base::BindOnce(&OnConnectionError, embedded_worker_->AsWeakPtr())); receiver_.reset(); receiver_.Bind(service_worker_host_.InitWithNewEndpointAndPassReceiver()); + // Initialize the global scope now if the worker won't be paused. Otherwise, // delay initialization until the main script is loaded. - if (!initialize_global_scope_after_main_script_loaded_) + if (!initialize_global_scope_after_main_script_loaded_) { InitializeGlobalScope(/*script_loader_factories=*/nullptr, /*subresource_loader_factories=*/nullptr); + } if (!controller_receiver_.is_valid()) { controller_receiver_ = remote_controller_.BindNewPipeAndPassReceiver(); @@ -1926,8 +1969,8 @@ void ServiceWorkerVersion::OnTimeoutTimer() { // Detach the worker. Remove |this| as a listener first; otherwise // OnStoppedInternal might try to restart before the new worker // is created. Also, protect |this|, since swapping out the - // EmbeddedWorkerInstance could destroy our ServiceWorkerProviderHost - // which could in turn destroy |this|. + // EmbeddedWorkerInstance could destroy our ServiceWorkerHost which could in + // turn destroy |this|. scoped_refptr<ServiceWorkerVersion> protect_this(this); embedded_worker_->RemoveObserver(this); embedded_worker_->Detach(); @@ -2206,13 +2249,14 @@ void ServiceWorkerVersion::OnStoppedInternal(EmbeddedWorkerStatus old_status) { request_timeouts_.clear(); external_request_uuid_to_request_id_.clear(); service_worker_remote_.reset(); + is_endpoint_ready_ = false; remote_controller_.reset(); DCHECK(!controller_receiver_.is_valid()); installed_scripts_sender_.reset(); receiver_.reset(); pending_external_requests_.clear(); worker_is_idle_on_renderer_ = true; - provider_host_.reset(); + worker_host_.reset(); for (auto& observer : observers_) observer.OnRunningStateChanged(this); @@ -2298,6 +2342,13 @@ void ServiceWorkerVersion::NotifyControlleeRemoved(const std::string& uuid) { } } +void ServiceWorkerVersion::NotifyControlleeNavigationCommitted( + const std::string& uuid, + GlobalFrameRoutingId render_frame_host_id) { + if (context_) + context_->OnControlleeNavigationCommitted(this, uuid, render_frame_host_id); +} + void ServiceWorkerVersion::PrepareForUpdate( std::map<GURL, ServiceWorkerUpdateChecker::ComparedScriptInfo> compared_script_info_map, @@ -2377,10 +2428,16 @@ void ServiceWorkerVersion::MaybeReportConsoleMessageToInternals( script_url_); } -void ServiceWorkerVersion::UpdateIdleDelayIfNeeded(base::TimeDelta delay) { - // The idle delay can be updated only when the worker is still running. - bool update_idle_delay = running_status() == EmbeddedWorkerStatus::STARTING || - running_status() == EmbeddedWorkerStatus::RUNNING; +void ServiceWorkerVersion::MaybeUpdateIdleDelayForTerminationOnNoControllee( + base::TimeDelta delay) { + if (!base::FeatureList::IsEnabled( + features::kServiceWorkerTerminationOnNoControllee) || + HasControllee() || running_status() != EmbeddedWorkerStatus::RUNNING) { + return; + } + + // The idle delay can be updated only when the worker is running. + bool update_idle_delay = running_status() == EmbeddedWorkerStatus::RUNNING; // The idle delay should not be updated when the worker needs to be // terminated ASAP so that the new worker can be activated soon. diff --git a/chromium/content/browser/service_worker/service_worker_version.h b/chromium/content/browser/service_worker/service_worker_version.h index 3de68c59447..7be6c0988c9 100644 --- a/chromium/content/browser/service_worker/service_worker_version.h +++ b/chromium/content/browser/service_worker/service_worker_version.h @@ -32,7 +32,6 @@ #include "content/browser/frame_host/back_forward_cache_metrics.h" #include "content/browser/service_worker/embedded_worker_instance.h" #include "content/browser/service_worker/embedded_worker_status.h" -#include "content/browser/service_worker/service_worker_client_info.h" #include "content/browser/service_worker/service_worker_client_utils.h" #include "content/browser/service_worker/service_worker_metrics.h" #include "content/browser/service_worker/service_worker_ping_controller.h" @@ -41,6 +40,8 @@ #include "content/common/content_export.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/global_routing_id.h" +#include "content/public/browser/service_worker_client_info.h" #include "ipc/ipc_message.h" #include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/pending_associated_remote.h" @@ -66,8 +67,8 @@ namespace content { class ServiceWorkerContainerHost; class ServiceWorkerContextCore; +class ServiceWorkerHost; class ServiceWorkerInstalledScriptsSender; -class ServiceWorkerProviderHost; class ServiceWorkerRegistration; struct ServiceWorkerVersionInfo; @@ -109,9 +110,9 @@ namespace service_worker_registration_unittest { class ServiceWorkerActivationTest; } // namespace service_worker_registration_unittest -namespace service_worker_navigation_loader_unittest { -class ServiceWorkerNavigationLoaderTest; -} // namespace service_worker_navigation_loader_unittest +namespace service_worker_main_resource_loader_unittest { +class ServiceWorkerMainResourceLoaderTest; +} // namespace service_worker_main_resource_loader_unittest // This class corresponds to a specific version of a ServiceWorker // script for a given scope. When a script is upgraded, there may be @@ -270,9 +271,6 @@ class CONTENT_EXPORT ServiceWorkerVersion // subresources). bool OnRequestTermination(); - // Skips waiting and forces this version to become activated. - void SkipWaitingFromDevTools(); - // Schedules an update to be run 'soon'. void ScheduleUpdate(); @@ -341,7 +339,8 @@ class CONTENT_EXPORT ServiceWorkerVersion // code and the dispatch time. See service_worker.mojom. SimpleEventCallback CreateSimpleEventCallback(int request_id); - // This must be called when the worker is running. + // This must be called when is_endpoint_ready() returns true, which is after + // InitializeGlobalScope() is called. blink::mojom::ServiceWorker* endpoint() { DCHECK(running_status() == EmbeddedWorkerStatus::STARTING || running_status() == EmbeddedWorkerStatus::RUNNING); @@ -349,6 +348,8 @@ class CONTENT_EXPORT ServiceWorkerVersion return service_worker_remote_.get(); } + bool is_endpoint_ready() const { return is_endpoint_ready_; } + // Returns the 'controller' interface ptr of this worker. It is expected that // the worker is already starting or running, or is going to be started soon. // TODO(kinuko): Relying on the callsites to start the worker when it's @@ -366,6 +367,12 @@ class CONTENT_EXPORT ServiceWorkerVersion void AddControllee(ServiceWorkerContainerHost* container_host); void RemoveControllee(const std::string& client_uuid); + // Called when the navigation for a window client commits to a render frame + // host. + void OnControlleeNavigationCommitted(const std::string& client_uuid, + int process_id, + int frame_id); + // Called when a controllee goes into back-forward cache. void MoveControlleeToBackForwardCacheMap(const std::string& client_uuid); // Called when a back-forward cached controllee is restored. @@ -395,11 +402,11 @@ class CONTENT_EXPORT ServiceWorkerVersion ServiceWorkerContainerHost* controllee, BackForwardCacheMetrics::NotRestoredReason reason); - // The provider host hosting this version. Only valid while the version is + // The worker host hosting this version. Only valid while the version is // running. - ServiceWorkerProviderHost* provider_host() { - DCHECK(provider_host_); - return provider_host_.get(); + content::ServiceWorkerHost* worker_host() { + DCHECK(worker_host_); + return worker_host_.get(); } base::WeakPtr<ServiceWorkerContextCore> context() const { return context_; } @@ -532,9 +539,9 @@ class CONTENT_EXPORT ServiceWorkerVersion // // On each request that dispatches a fetch event to this worker (or would // have, in the case of a no-fetch event worker), this count is incremented. - // When the browser-side provider host receives a hint from the renderer that + // When the browser-side worker host receives a hint from the renderer that // it is a good time to update the service worker, the count is decremented. - // It is also decremented when if the provider host is destroyed before + // It is also decremented when if the worker host is destroyed before // receiving the hint. // // When the count transitions from 1 to 0, update is scheduled. @@ -595,8 +602,8 @@ class CONTENT_EXPORT ServiceWorkerVersion friend class ServiceWorkerVersionBrowserTest; friend class ServiceWorkerActivationTest; friend class service_worker_version_unittest::ServiceWorkerVersionTest; - friend class service_worker_navigation_loader_unittest:: - ServiceWorkerNavigationLoaderTest; + friend class service_worker_main_resource_loader_unittest:: + ServiceWorkerMainResourceLoaderTest; FRIEND_TEST_ALL_PREFIXES(service_worker_controllee_request_handler_unittest:: ServiceWorkerControlleeRequestHandlerTest, @@ -855,6 +862,9 @@ class CONTENT_EXPORT ServiceWorkerVersion void NotifyControlleeAdded(const std::string& uuid, const ServiceWorkerClientInfo& info); void NotifyControlleeRemoved(const std::string& uuid); + void NotifyControlleeNavigationCommitted( + const std::string& uuid, + GlobalFrameRoutingId render_frame_host_id); void GetClientOnExecutionReady(const std::string& client_uuid, GetClientCallback callback, @@ -866,9 +876,10 @@ class CONTENT_EXPORT ServiceWorkerVersion std::unique_ptr<blink::PendingURLLoaderFactoryBundle> subresource_loader_factories); - // Update the idle delay if the worker is starting or running and we don't + // When ServiceWorkerTerminationOnNoControlle is enabled and there's no + // controllee, update the idle delay if the worker is running and we don't // have to terminate the worker ASAP (e.g. for activation). - void UpdateIdleDelayIfNeeded(base::TimeDelta delay); + void MaybeUpdateIdleDelayForTerminationOnNoControllee(base::TimeDelta delay); const int64_t version_id_; const int64_t registration_id_; @@ -902,6 +913,9 @@ class CONTENT_EXPORT ServiceWorkerVersion Status status_ = NEW; std::unique_ptr<EmbeddedWorkerInstance> embedded_worker_; + // True if endpoint() is ready to dispatch events, which means + // InitializeGlobalScope() is already called. + bool is_endpoint_ready_ = false; std::vector<StatusCallback> start_callbacks_; std::vector<base::OnceClosure> stop_callbacks_; std::vector<base::OnceClosure> status_change_callbacks_; @@ -954,10 +968,9 @@ class CONTENT_EXPORT ServiceWorkerVersion // (e.g. activation). bool needs_to_be_terminated_asap_ = false; - // Keeps track of the provider hosting this running service worker for this - // version. |provider_host_| is always valid as long as this version is - // running. - std::unique_ptr<ServiceWorkerProviderHost> provider_host_; + // The host for this version's running service worker. |worker_host_| is + // always valid as long as this version is running. + std::unique_ptr<content::ServiceWorkerHost> worker_host_; // |controllee_map_| and |bfcached_controllee_map_| should not share the same // controllee. diff --git a/chromium/content/browser/service_worker/service_worker_version_browsertest.cc b/chromium/content/browser/service_worker/service_worker_version_browsertest.cc index d3705cc8d4c..90d1ea262fb 100644 --- a/chromium/content/browser/service_worker/service_worker_version_browsertest.cc +++ b/chromium/content/browser/service_worker/service_worker_version_browsertest.cc @@ -34,7 +34,7 @@ #include "content/browser/service_worker/service_worker_context_core_observer.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/service_worker/service_worker_fetch_dispatcher.h" -#include "content/browser/service_worker/service_worker_provider_host.h" +#include "content/browser/service_worker/service_worker_host.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_test_utils.h" #include "content/browser/service_worker/service_worker_version.h" @@ -844,7 +844,7 @@ class ServiceWorkerVersionBrowserTest : public ContentBrowserTest { scoped_refptr<ServiceWorkerVersion> version_; scoped_refptr<ServiceWorkerContextWrapper> wrapper_; std::unique_ptr<ServiceWorkerFetchDispatcher> fetch_dispatcher_; - std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints_; + std::vector<ServiceWorkerRemoteContainerEndpoint> remote_endpoints_; }; class WaitForLoaded : public EmbeddedWorkerInstance::Listener { diff --git a/chromium/content/browser/service_worker/service_worker_version_unittest.cc b/chromium/content/browser/service_worker/service_worker_version_unittest.cc index 37c33a12bc9..28ecdf60bca 100644 --- a/chromium/content/browser/service_worker/service_worker_version_unittest.cc +++ b/chromium/content/browser/service_worker/service_worker_version_unittest.cc @@ -14,6 +14,7 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" +#include "base/test/bind_test_util.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/simple_test_tick_clock.h" @@ -168,11 +169,11 @@ class ServiceWorkerVersionTest : public testing::Test { return ServiceWorkerVersion::FetchHandlerExistence::EXISTS; } - ServiceWorkerRemoteProviderEndpoint ActivateWithControllee( + ServiceWorkerRemoteContainerEndpoint ActivateWithControllee( int controllee_process_id = 33) { version_->SetStatus(ServiceWorkerVersion::ACTIVATED); registration_->SetActiveVersion(version_); - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; base::WeakPtr<ServiceWorkerContainerHost> container_host = CreateContainerHostForWindow( controllee_process_id, true /* is_parent_frame_secure */, @@ -425,7 +426,7 @@ TEST_F(ServiceWorkerVersionTest, Doom) { // Add a controllee. version_->SetStatus(ServiceWorkerVersion::ACTIVATED); registration_->SetActiveVersion(version_); - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; base::WeakPtr<ServiceWorkerContainerHost> container_host = CreateContainerHostForWindow( 33 /* dummy render process id */, true /* is_parent_frame_secure */, @@ -1189,7 +1190,7 @@ TEST_F(ServiceWorkerVersionTest, // Add a controllee, but don't begin the navigation commit yet. This will // cause the client to have an invalid process id like we see in real // navigations. - ServiceWorkerRemoteProviderEndpoint remote_endpoint; + ServiceWorkerRemoteContainerEndpoint remote_endpoint; std::unique_ptr<ServiceWorkerContainerHostAndInfo> host_and_info = CreateContainerHostAndInfoForWindow(helper_->context()->AsWeakPtr(), /*are_ancestors_secure=*/true); @@ -1481,7 +1482,7 @@ class ServiceWorkerVersionTerminationOnNoControlleeTest private: base::test::ScopedFeatureList feature_list_; - std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints_; + std::vector<ServiceWorkerRemoteContainerEndpoint> remote_endpoints_; }; // static @@ -1624,5 +1625,64 @@ TEST_P(ServiceWorkerVersionTerminationOnNoControlleeTest, StoppedWorker) { version_->RemoveControllee(controllee->client_uuid()); } +// FakeEmbeddedWorkerInstanceClient which waits to call OnStarted() until +// CallOnStarted() is called. +class WaitToCallOnStartedEmbeddedWorkerInstanceClient + : public FakeEmbeddedWorkerInstanceClient { + public: + explicit WaitToCallOnStartedEmbeddedWorkerInstanceClient( + EmbeddedWorkerTestHelper* helper) + : FakeEmbeddedWorkerInstanceClient(helper) {} + + void CallOnStarted() { + host()->OnStarted(blink::mojom::ServiceWorkerStartStatus::kNormalCompletion, + true /* has_fetch_handler */, helper()->GetNextThreadId(), + blink::mojom::EmbeddedWorkerStartTiming::New()); + } + + protected: + void EvaluateScript() override { host()->OnScriptEvaluationStart(); } +}; + +// Call AddControllee() and RemoveControllee() while starting a worker. +// This is a regression test for https://crbug.com/1099744. +TEST_P(ServiceWorkerVersionTerminationOnNoControlleeTest, + RemoveControlleeBeforeStarted) { + version_->SetStatus(ServiceWorkerVersion::ACTIVATED); + EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version_->running_status()); + auto* embedded_worker_in_renderer = helper_->AddNewPendingInstanceClient< + WaitToCallOnStartedEmbeddedWorkerInstanceClient>(helper_.get()); + auto* service_worker_in_renderer = + helper_->AddNewPendingServiceWorker<FakeServiceWorker>(helper_.get()); + base::RunLoop loop; + version_->StartWorker( + ServiceWorkerMetrics::EventType::UNKNOWN, + base::BindLambdaForTesting( + [&](blink::ServiceWorkerStatusCode) { loop.Quit(); })); + + // Add and remove controllee during starting the worker. This doesn't update + // the idle delay. + ServiceWorkerContainerHost* controllee = CreateControllee(); + version_->AddControllee(controllee); + version_->RemoveControllee(controllee->client_uuid()); + service_worker_in_renderer->RunUntilInitializeGlobalScope(); + EXPECT_FALSE(service_worker_in_renderer->idle_delay().has_value()); + EXPECT_EQ(EmbeddedWorkerStatus::STARTING, version_->running_status()); + + // Start the worker and make sure the fake service worker receives all the + // messages. At the OnStarted message, the browser sends the idle timeout + // because there's no controllee at this point. + embedded_worker_in_renderer->CallOnStarted(); + loop.Run(); + service_worker_in_renderer->FlushForTesting(); + EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version_->running_status()); + if (IsTerminationEnabled()) { + EXPECT_EQ(kTerminationDelay, + service_worker_in_renderer->idle_delay().value()); + } else { + EXPECT_FALSE(service_worker_in_renderer->idle_delay().has_value()); + } +} + } // namespace service_worker_version_unittest } // namespace content |