| /* |
| * Copyright (C) 2013 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h" |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/feature_list.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "mojo/public/cpp/bindings/pending_remote.h" |
| #include "third_party/blink/public/common/features.h" |
| #include "third_party/blink/public/mojom/appcache/appcache.mojom-blink.h" |
| #include "third_party/blink/public/mojom/timing/worker_timing_container.mojom-blink.h" |
| #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h" |
| #include "third_party/blink/public/platform/platform.h" |
| #include "third_party/blink/public/platform/web_url.h" |
| #include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h" |
| #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" |
| #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" |
| #include "third_party/blink/renderer/bindings/core/v8/source_location.h" |
| #include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script_url.h" |
| #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h" |
| #include "third_party/blink/renderer/bindings/modules/v8/v8_notification_event_init.h" |
| #include "third_party/blink/renderer/core/dom/events/event.h" |
| #include "third_party/blink/renderer/core/execution_context/execution_context.h" |
| #include "third_party/blink/renderer/core/fetch/global_fetch.h" |
| #include "third_party/blink/renderer/core/inspector/console_message.h" |
| #include "third_party/blink/renderer/core/inspector/worker_inspector_controller.h" |
| #include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h" |
| #include "third_party/blink/renderer/core/loader/threadable_loader.h" |
| #include "third_party/blink/renderer/core/loader/worker_resource_timing_notifier_impl.h" |
| #include "third_party/blink/renderer/core/messaging/blink_transferable_message.h" |
| #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h" |
| #include "third_party/blink/renderer/core/probe/core_probes.h" |
| #include "third_party/blink/renderer/core/trustedtypes/trusted_script_url.h" |
| #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" |
| #include "third_party/blink/renderer/core/workers/worker_classic_script_loader.h" |
| #include "third_party/blink/renderer/core/workers/worker_clients.h" |
| #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h" |
| #include "third_party/blink/renderer/modules/background_fetch/background_fetch_event.h" |
| #include "third_party/blink/renderer/modules/background_fetch/background_fetch_event_init.h" |
| #include "third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h" |
| #include "third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.h" |
| #include "third_party/blink/renderer/modules/background_sync/periodic_sync_event.h" |
| #include "third_party/blink/renderer/modules/background_sync/sync_event.h" |
| #include "third_party/blink/renderer/modules/content_index/content_index_event.h" |
| #include "third_party/blink/renderer/modules/content_index/content_index_event_init.h" |
| #include "third_party/blink/renderer/modules/cookie_store/cookie_change_event.h" |
| #include "third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.h" |
| #include "third_party/blink/renderer/modules/event_target_modules.h" |
| #include "third_party/blink/renderer/modules/notifications/notification.h" |
| #include "third_party/blink/renderer/modules/notifications/notification_event.h" |
| #include "third_party/blink/renderer/modules/payments/abort_payment_event.h" |
| #include "third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.h" |
| #include "third_party/blink/renderer/modules/payments/can_make_payment_event.h" |
| #include "third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.h" |
| #include "third_party/blink/renderer/modules/payments/payment_event_data_conversion.h" |
| #include "third_party/blink/renderer/modules/payments/payment_request_event.h" |
| #include "third_party/blink/renderer/modules/payments/payment_request_event_init.h" |
| #include "third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.h" |
| #include "third_party/blink/renderer/modules/push_messaging/push_event.h" |
| #include "third_party/blink/renderer/modules/push_messaging/push_message_data.h" |
| #include "third_party/blink/renderer/modules/push_messaging/push_subscription_change_event.h" |
| #include "third_party/blink/renderer/modules/service_worker/extendable_event.h" |
| #include "third_party/blink/renderer/modules/service_worker/extendable_message_event.h" |
| #include "third_party/blink/renderer/modules/service_worker/fetch_event.h" |
| #include "third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h" |
| #include "third_party/blink/renderer/modules/service_worker/install_event.h" |
| #include "third_party/blink/renderer/modules/service_worker/respond_with_observer.h" |
| #include "third_party/blink/renderer/modules/service_worker/service_worker.h" |
| #include "third_party/blink/renderer/modules/service_worker/service_worker_client.h" |
| #include "third_party/blink/renderer/modules/service_worker/service_worker_clients.h" |
| #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h" |
| #include "third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.h" |
| #include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h" |
| #include "third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.h" |
| #include "third_party/blink/renderer/modules/service_worker/service_worker_thread.h" |
| #include "third_party/blink/renderer/modules/service_worker/service_worker_window_client.h" |
| #include "third_party/blink/renderer/modules/service_worker/wait_until_observer.h" |
| #include "third_party/blink/renderer/platform/bindings/script_state.h" |
| #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h" |
| #include "third_party/blink/renderer/platform/heap/heap.h" |
| #include "third_party/blink/renderer/platform/instrumentation/histogram.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h" |
| #include "third_party/blink/renderer/platform/network/content_security_policy_response_headers.h" |
| #include "third_party/blink/renderer/platform/weborigin/kurl.h" |
| #include "third_party/blink/renderer/platform/weborigin/security_policy.h" |
| #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| constexpr char kServiceWorkerGlobalScopeTraceScope[] = |
| "ServiceWorkerGlobalScope"; |
| |
| void DidSkipWaiting(ScriptPromiseResolver* resolver, bool success) { |
| if (!resolver->GetExecutionContext() || |
| resolver->GetExecutionContext()->IsContextDestroyed()) |
| return; |
| // Per spec the promise returned by skipWaiting() can never reject. |
| if (!success) |
| return; |
| resolver->Resolve(); |
| } |
| |
| // Creates a callback which takes an |event_id| and |status|, which calls the |
| // given event's callback with the given status and removes it from |map|. |
| template <typename MapType, typename... Args> |
| ServiceWorkerEventQueue::AbortCallback CreateAbortCallback(MapType* map, |
| Args&&... args) { |
| return WTF::Bind( |
| [](MapType* map, Args&&... args, int event_id, |
| mojom::blink::ServiceWorkerEventStatus status) { |
| auto iter = map->find(event_id); |
| DCHECK(iter != map->end()); |
| std::move(iter->value).Run(status, std::forward<Args>(args)...); |
| map->erase(iter); |
| }, |
| WTF::Unretained(map), std::forward<Args>(args)...); |
| } |
| |
| // Finds an event callback keyed by |event_id| from |map|, and runs the callback |
| // with |args|. Returns true if the callback was found and called, otherwise |
| // returns false. |
| template <typename MapType, typename... Args> |
| bool RunEventCallback(MapType* map, |
| ServiceWorkerEventQueue* event_queue, |
| int event_id, |
| Args&&... args) { |
| auto iter = map->find(event_id); |
| // The event may have been aborted. |
| if (iter == map->end()) |
| return false; |
| std::move(iter->value).Run(std::forward<Args>(args)...); |
| map->erase(iter); |
| event_queue->EndEvent(event_id); |
| return true; |
| } |
| |
| template <typename T> |
| static std::string MojoEnumToString(T mojo_enum) { |
| std::ostringstream oss; |
| oss << mojo_enum; |
| return oss.str(); |
| } |
| |
| } // namespace |
| |
| ServiceWorkerGlobalScope* ServiceWorkerGlobalScope::Create( |
| ServiceWorkerThread* thread, |
| std::unique_ptr<GlobalScopeCreationParams> creation_params, |
| std::unique_ptr<ServiceWorkerInstalledScriptsManager> |
| installed_scripts_manager, |
| mojo::PendingRemote<mojom::blink::CacheStorage> cache_storage_remote, |
| base::TimeTicks time_origin) { |
| DCHECK_EQ(creation_params->off_main_thread_fetch_option, |
| OffMainThreadWorkerScriptFetchOption::kEnabled); |
| |
| #if DCHECK_IS_ON() |
| // If the script is being loaded via script streaming, the script is not yet |
| // loaded. |
| if (installed_scripts_manager && installed_scripts_manager->IsScriptInstalled( |
| creation_params->script_url)) { |
| // CSP headers, referrer policy, and origin trial tokens will be provided by |
| // the InstalledScriptsManager in EvaluateClassicScript(). |
| DCHECK(creation_params->outside_content_security_policy_headers.IsEmpty()); |
| DCHECK_EQ(network::mojom::ReferrerPolicy::kDefault, |
| creation_params->referrer_policy); |
| DCHECK(creation_params->origin_trial_tokens->IsEmpty()); |
| } |
| #endif // DCHECK_IS_ON() |
| |
| return MakeGarbageCollected<ServiceWorkerGlobalScope>( |
| std::move(creation_params), thread, std::move(installed_scripts_manager), |
| std::move(cache_storage_remote), time_origin); |
| } |
| |
| ServiceWorkerGlobalScope::ServiceWorkerGlobalScope( |
| std::unique_ptr<GlobalScopeCreationParams> creation_params, |
| ServiceWorkerThread* thread, |
| std::unique_ptr<ServiceWorkerInstalledScriptsManager> |
| installed_scripts_manager, |
| mojo::PendingRemote<mojom::blink::CacheStorage> cache_storage_remote, |
| base::TimeTicks time_origin) |
| : WorkerGlobalScope(std::move(creation_params), thread, time_origin), |
| installed_scripts_manager_(std::move(installed_scripts_manager)), |
| cache_storage_remote_(std::move(cache_storage_remote)) { |
| // Create the event queue. At this point its timer is not started. It will be |
| // started by DidEvaluateScript(). |
| event_queue_ = std::make_unique<ServiceWorkerEventQueue>( |
| WTF::BindRepeating(&ServiceWorkerGlobalScope::OnBeforeStartEvent, |
| WrapWeakPersistent(this)), |
| WTF::BindRepeating(&ServiceWorkerGlobalScope::OnIdleTimeout, |
| WrapWeakPersistent(this))); |
| } |
| |
| ServiceWorkerGlobalScope::~ServiceWorkerGlobalScope() = default; |
| |
| bool ServiceWorkerGlobalScope::ShouldInstallV8Extensions() const { |
| return Platform::Current()->AllowScriptExtensionForServiceWorker( |
| WebSecurityOrigin(GetSecurityOrigin())); |
| } |
| |
| // https://w3c.github.io/ServiceWorker/#update |
| void ServiceWorkerGlobalScope::FetchAndRunClassicScript( |
| const KURL& script_url, |
| const FetchClientSettingsObjectSnapshot& outside_settings_object, |
| WorkerResourceTimingNotifier& outside_resource_timing_notifier, |
| const v8_inspector::V8StackTraceId& stack_id) { |
| DCHECK(!IsContextPaused()); |
| |
| if (installed_scripts_manager_) { |
| // This service worker is installed. Load and run the installed script. |
| LoadAndRunInstalledClassicScript(script_url, stack_id); |
| return; |
| } |
| |
| // Step 9. "Switching on job's worker type, run these substeps with the |
| // following options:" |
| // "classic: Fetch a classic worker script given job's serialized script url, |
| // job's client, "serviceworker", and the to-be-created environment settings |
| // object for this service worker." |
| auto context_type = mojom::RequestContextType::SERVICE_WORKER; |
| auto destination = network::mojom::RequestDestination::kServiceWorker; |
| |
| // "To perform the fetch given request, run the following steps:" |
| // Step 9.1. "Append `Service-Worker`/`script` to request's header list." |
| // Step 9.2. "Set request's cache mode to "no-cache" if any of the following |
| // are true:" |
| // Step 9.3. "Set request's service-workers mode to "none"." |
| // The browser process takes care of these steps. |
| |
| // Step 9.4. "If the is top-level flag is unset, then return the result of |
| // fetching request." |
| // This step makes sense only when the worker type is "module". For classic |
| // script fetch, the top-level flag is always set. |
| |
| // Step 9.5. "Set request's redirect mode to "error"." |
| // The browser process takes care of this step. |
| |
| // Step 9.6. "Fetch request, and asynchronously wait to run the remaining |
| // steps as part of fetch's process response for the response response." |
| WorkerClassicScriptLoader* classic_script_loader = |
| MakeGarbageCollected<WorkerClassicScriptLoader>(); |
| classic_script_loader->LoadTopLevelScriptAsynchronously( |
| *this, |
| CreateOutsideSettingsFetcher(outside_settings_object, |
| outside_resource_timing_notifier), |
| script_url, context_type, destination, |
| network::mojom::RequestMode::kSameOrigin, |
| network::mojom::CredentialsMode::kSameOrigin, |
| WTF::Bind(&ServiceWorkerGlobalScope::DidReceiveResponseForClassicScript, |
| WrapWeakPersistent(this), |
| WrapPersistent(classic_script_loader)), |
| WTF::Bind(&ServiceWorkerGlobalScope::DidFetchClassicScript, |
| WrapWeakPersistent(this), WrapPersistent(classic_script_loader), |
| stack_id)); |
| } |
| |
| void ServiceWorkerGlobalScope::FetchAndRunModuleScript( |
| const KURL& module_url_record, |
| const FetchClientSettingsObjectSnapshot& outside_settings_object, |
| WorkerResourceTimingNotifier& outside_resource_timing_notifier, |
| network::mojom::CredentialsMode credentials_mode) { |
| DCHECK(IsContextThread()); |
| |
| ModuleScriptCustomFetchType fetch_type = |
| installed_scripts_manager_ |
| ? ModuleScriptCustomFetchType::kInstalledServiceWorker |
| : ModuleScriptCustomFetchType::kWorkerConstructor; |
| FetchModuleScript(module_url_record, outside_settings_object, |
| outside_resource_timing_notifier, |
| mojom::RequestContextType::SERVICE_WORKER, |
| network::mojom::RequestDestination::kServiceWorker, |
| credentials_mode, fetch_type, |
| MakeGarbageCollected<ServiceWorkerModuleTreeClient>( |
| ScriptController()->GetScriptState())); |
| } |
| |
| void ServiceWorkerGlobalScope::Dispose() { |
| DCHECK(IsContextThread()); |
| controller_receivers_.Clear(); |
| event_queue_.reset(); |
| service_worker_host_.reset(); |
| receiver_.reset(); |
| WorkerGlobalScope::Dispose(); |
| } |
| |
| InstalledScriptsManager* |
| ServiceWorkerGlobalScope::GetInstalledScriptsManager() { |
| return installed_scripts_manager_.get(); |
| } |
| |
| void ServiceWorkerGlobalScope::CountWorkerScript(size_t script_size, |
| size_t cached_metadata_size) { |
| DCHECK_EQ(GetScriptType(), mojom::ScriptType::kClassic); |
| DEFINE_THREAD_SAFE_STATIC_LOCAL( |
| CustomCountHistogram, script_size_histogram, |
| ("ServiceWorker.ScriptSize", 1000, 5000000, 50)); |
| script_size_histogram.Count( |
| base::saturated_cast<base::Histogram::Sample>(script_size)); |
| |
| if (cached_metadata_size) { |
| DEFINE_THREAD_SAFE_STATIC_LOCAL( |
| CustomCountHistogram, script_cached_metadata_size_histogram, |
| ("ServiceWorker.ScriptCachedMetadataSize", 1000, 50000000, 50)); |
| script_cached_metadata_size_histogram.Count( |
| base::saturated_cast<base::Histogram::Sample>(cached_metadata_size)); |
| } |
| |
| CountScriptInternal(script_size, cached_metadata_size); |
| } |
| |
| void ServiceWorkerGlobalScope::CountImportedScript( |
| size_t script_size, |
| size_t cached_metadata_size) { |
| DCHECK_EQ(GetScriptType(), mojom::ScriptType::kClassic); |
| CountScriptInternal(script_size, cached_metadata_size); |
| } |
| |
| void ServiceWorkerGlobalScope::DidEvaluateScript() { |
| DCHECK(!did_evaluate_script_); |
| did_evaluate_script_ = true; |
| |
| event_queue_->Start(); |
| |
| // Skip recording UMAs for module scripts because there're no ways to get the |
| // number of static-imported scripts and the total size of the imported |
| // scripts. |
| if (GetScriptType() == mojom::ScriptType::kModule) { |
| return; |
| } |
| |
| // TODO(asamidoi,nhiroki): Record the UMAs for module scripts, or remove them |
| // if they're no longer used. |
| DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, script_count_histogram, |
| ("ServiceWorker.ScriptCount", 1, 1000, 50)); |
| script_count_histogram.Count( |
| base::saturated_cast<base::Histogram::Sample>(script_count_)); |
| DEFINE_THREAD_SAFE_STATIC_LOCAL( |
| CustomCountHistogram, script_total_size_histogram, |
| ("ServiceWorker.ScriptTotalSize", 1000, 5000000, 50)); |
| script_total_size_histogram.Count( |
| base::saturated_cast<base::Histogram::Sample>(script_total_size_)); |
| if (script_cached_metadata_total_size_) { |
| DEFINE_THREAD_SAFE_STATIC_LOCAL( |
| CustomCountHistogram, cached_metadata_histogram, |
| ("ServiceWorker.ScriptCachedMetadataTotalSize", 1000, 50000000, 50)); |
| cached_metadata_histogram.Count( |
| base::saturated_cast<base::Histogram::Sample>( |
| script_cached_metadata_total_size_)); |
| } |
| } |
| |
| void ServiceWorkerGlobalScope::DidReceiveResponseForClassicScript( |
| WorkerClassicScriptLoader* classic_script_loader) { |
| DCHECK(IsContextThread()); |
| probe::DidReceiveScriptResponse(this, classic_script_loader->Identifier()); |
| } |
| |
| // https://w3c.github.io/ServiceWorker/#update |
| void ServiceWorkerGlobalScope::DidFetchClassicScript( |
| WorkerClassicScriptLoader* classic_script_loader, |
| const v8_inspector::V8StackTraceId& stack_id) { |
| DCHECK(IsContextThread()); |
| |
| // Step 9. "If the algorithm asynchronously completes with null, then:" |
| if (classic_script_loader->Failed()) { |
| // Step 9.1. "Invoke Reject Job Promise with job and TypeError." |
| // Step 9.2. "If newestWorker is null, invoke Clear Registration algorithm |
| // passing registration as its argument." |
| // Step 9.3. "Invoke Finish Job with job and abort these steps." |
| // The browser process takes care of these steps. |
| ReportingProxy().DidFailToFetchClassicScript(); |
| // Close the worker global scope to terminate the thread. |
| close(); |
| return; |
| } |
| // The app cache ID is not used. |
| ReportingProxy().DidFetchScript(); |
| probe::ScriptImported(this, classic_script_loader->Identifier(), |
| classic_script_loader->SourceText()); |
| |
| // Step 10. "If hasUpdatedResources is false, then:" |
| // Step 10.1. "Invoke Resolve Job Promise with job and registration." |
| // Steo 10.2. "Invoke Finish Job with job and abort these steps." |
| // Step 11. "Let worker be a new service worker." |
| // Step 12. "Set worker's script url to job's script url, worker's script |
| // resource to script, worker's type to job's worker type, and worker's |
| // script resource map to updatedResourceMap." |
| // Step 13. "Append url to worker's set of used scripts." |
| // The browser process takes care of these steps. |
| |
| // Step 14. "Set worker's script resource's HTTPS state to httpsState." |
| // This is done in the constructor of WorkerGlobalScope. |
| |
| // Step 15. "Set worker's script resource's referrer policy to |
| // referrerPolicy." |
| auto referrer_policy = network::mojom::ReferrerPolicy::kDefault; |
| if (!classic_script_loader->GetReferrerPolicy().IsNull()) { |
| SecurityPolicy::ReferrerPolicyFromHeaderValue( |
| classic_script_loader->GetReferrerPolicy(), |
| kDoNotSupportReferrerPolicyLegacyKeywords, &referrer_policy); |
| } |
| |
| // Step 16. "Invoke Run Service Worker algorithm given worker, with the force |
| // bypass cache for importscripts flag set if job’s force bypass cache flag |
| // is set, and with the following callback steps given evaluationStatus:" |
| RunClassicScript( |
| classic_script_loader->ResponseURL(), referrer_policy, |
| classic_script_loader->ResponseAddressSpace(), |
| classic_script_loader->GetContentSecurityPolicy() |
| ? classic_script_loader->GetContentSecurityPolicy()->Headers() |
| : Vector<CSPHeaderAndType>(), |
| classic_script_loader->OriginTrialTokens(), |
| classic_script_loader->SourceText(), |
| classic_script_loader->ReleaseCachedMetadata(), stack_id); |
| } |
| |
| // https://w3c.github.io/ServiceWorker/#run-service-worker-algorithm |
| void ServiceWorkerGlobalScope::Initialize( |
| const KURL& response_url, |
| network::mojom::ReferrerPolicy response_referrer_policy, |
| network::mojom::IPAddressSpace response_address_space, |
| const Vector<CSPHeaderAndType>& response_csp_headers, |
| const Vector<String>* response_origin_trial_tokens, |
| int64_t appcache_id) { |
| // Step 4.5. "Set workerGlobalScope's url to serviceWorker's script url." |
| InitializeURL(response_url); |
| |
| // Step 4.6. "Set workerGlobalScope's HTTPS state to serviceWorker's script |
| // resource's HTTPS state." |
| // This is done in the constructor of WorkerGlobalScope. |
| |
| // Step 4.7. "Set workerGlobalScope's referrer policy to serviceWorker's |
| // script resource's referrer policy." |
| SetReferrerPolicy(response_referrer_policy); |
| |
| // https://wicg.github.io/cors-rfc1918/#integration-html |
| GetSecurityContext().SetAddressSpace(response_address_space); |
| |
| // This is quoted from the "Content Security Policy" algorithm in the service |
| // workers spec: |
| // "Whenever a user agent invokes Run Service Worker algorithm with a service |
| // worker serviceWorker: |
| // - If serviceWorker's script resource was delivered with a |
| // Content-Security-Policy HTTP header containing the value policy, the |
| // user agent must enforce policy for serviceWorker. |
| // - If serviceWorker's script resource was delivered with a |
| // Content-Security-Policy-Report-Only HTTP header containing the value |
| // policy, the user agent must monitor policy for serviceWorker." |
| // |
| // These should be called after SetAddressSpace() to correctly override the |
| // address space by the "treat-as-public-address" CSP directive. |
| InitContentSecurityPolicyFromVector(response_csp_headers); |
| BindContentSecurityPolicyToExecutionContext(); |
| |
| OriginTrialContext::AddTokens(this, response_origin_trial_tokens); |
| |
| // TODO(nhiroki): Clarify mappings between the steps 4.8-4.11 and |
| // implementation. |
| |
| // This should be called after OriginTrialContext::AddTokens() to install |
| // origin trial features in JavaScript's global object. |
| ScriptController()->PrepareForEvaluation(); |
| |
| // Service Workers don't use application cache. |
| DCHECK_EQ(appcache_id, mojom::blink::kAppCacheNoCacheId); |
| } |
| |
| void ServiceWorkerGlobalScope::LoadAndRunInstalledClassicScript( |
| const KURL& script_url, |
| const v8_inspector::V8StackTraceId& stack_id) { |
| DCHECK(IsContextThread()); |
| |
| DCHECK(installed_scripts_manager_); |
| DCHECK(installed_scripts_manager_->IsScriptInstalled(script_url)); |
| |
| // GetScriptData blocks until the script is received from the browser. |
| std::unique_ptr<InstalledScriptsManager::ScriptData> script_data = |
| installed_scripts_manager_->GetScriptData(script_url); |
| if (!script_data) { |
| ReportingProxy().DidFailToFetchClassicScript(); |
| // This will eventually initiate worker thread termination. See |
| // ServiceWorkerGlobalScopeProxy::DidCloseWorkerGlobalScope() for details. |
| close(); |
| return; |
| } |
| ReportingProxy().DidLoadClassicScript(); |
| |
| auto referrer_policy = network::mojom::ReferrerPolicy::kDefault; |
| if (!script_data->GetReferrerPolicy().IsNull()) { |
| SecurityPolicy::ReferrerPolicyFromHeaderValue( |
| script_data->GetReferrerPolicy(), |
| kDoNotSupportReferrerPolicyLegacyKeywords, &referrer_policy); |
| } |
| |
| // Construct a ContentSecurityPolicy object to convert |
| // ContentSecurityPolicyResponseHeaders to CSPHeaderAndType. |
| // TODO(nhiroki): Find an efficient way to do this. |
| auto* content_security_policy = MakeGarbageCollected<ContentSecurityPolicy>(); |
| content_security_policy->DidReceiveHeaders( |
| script_data->GetContentSecurityPolicyResponseHeaders()); |
| |
| RunClassicScript( |
| script_url, referrer_policy, script_data->GetResponseAddressSpace(), |
| content_security_policy->Headers(), |
| script_data->CreateOriginTrialTokens().get(), |
| script_data->TakeSourceText(), script_data->TakeMetaData(), stack_id); |
| } |
| |
| // https://w3c.github.io/ServiceWorker/#run-service-worker-algorithm |
| void ServiceWorkerGlobalScope::RunClassicScript( |
| const KURL& response_url, |
| network::mojom::ReferrerPolicy response_referrer_policy, |
| network::mojom::IPAddressSpace response_address_space, |
| const Vector<CSPHeaderAndType> response_csp_headers, |
| const Vector<String>* response_origin_trial_tokens, |
| const String& source_code, |
| std::unique_ptr<Vector<uint8_t>> cached_meta_data, |
| const v8_inspector::V8StackTraceId& stack_id) { |
| // Step 4.5-4.11 are implemented in Initialize(). |
| Initialize(response_url, response_referrer_policy, response_address_space, |
| response_csp_headers, response_origin_trial_tokens, |
| mojom::blink::kAppCacheNoCacheId); |
| |
| // Step 4.12. "Let evaluationStatus be the result of running the classic |
| // script script if script is a classic script, otherwise, the result of |
| // running the module script script if script is a module script." |
| EvaluateClassicScript(response_url, source_code, std::move(cached_meta_data), |
| stack_id); |
| } |
| |
| void ServiceWorkerGlobalScope::CountScriptInternal( |
| size_t script_size, |
| size_t cached_metadata_size) { |
| ++script_count_; |
| script_total_size_ += script_size; |
| script_cached_metadata_total_size_ += cached_metadata_size; |
| } |
| |
| ServiceWorkerClients* ServiceWorkerGlobalScope::clients() { |
| if (!clients_) |
| clients_ = ServiceWorkerClients::Create(); |
| return clients_; |
| } |
| |
| ServiceWorkerRegistration* ServiceWorkerGlobalScope::registration() { |
| return registration_; |
| } |
| |
| ::blink::ServiceWorker* ServiceWorkerGlobalScope::serviceWorker() { |
| return service_worker_; |
| } |
| |
| ScriptPromise ServiceWorkerGlobalScope::skipWaiting(ScriptState* script_state) { |
| ExecutionContext* execution_context = ExecutionContext::From(script_state); |
| // FIXME: short-term fix, see details at: |
| // https://codereview.chromium.org/535193002/. |
| if (!execution_context) |
| return ScriptPromise(); |
| |
| auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); |
| GetServiceWorkerHost()->SkipWaiting( |
| WTF::Bind(&DidSkipWaiting, WrapPersistent(resolver))); |
| return resolver->Promise(); |
| } |
| |
| void ServiceWorkerGlobalScope::BindServiceWorker( |
| mojo::PendingReceiver<mojom::blink::ServiceWorker> receiver) { |
| DCHECK(IsContextThread()); |
| DCHECK(!receiver_.is_bound()); |
| // TODO(falken): Consider adding task types for "the handle fetch task source" |
| // and "handle functional event task source" defined in the service worker |
| // spec and use them when dispatching events. |
| receiver_.Bind(std::move(receiver), |
| GetThread()->GetTaskRunner(TaskType::kInternalDefault)); |
| } |
| |
| void ServiceWorkerGlobalScope::BindControllerServiceWorker( |
| mojo::PendingReceiver<mojom::blink::ControllerServiceWorker> receiver) { |
| DCHECK(IsContextThread()); |
| DCHECK(controller_receivers_.empty()); |
| // This receiver won't get any FetchEvents because it's used only for |
| // bootstrapping, and the actual clients connect over Clone() later. kNone is |
| // passed as COEP value as a placeholder. |
| // |
| // TODO(falken): Consider adding task types for "the handle fetch task source" |
| // and "handle functional event task source" defined in the service worker |
| // spec and use them when dispatching events. |
| controller_receivers_.Add( |
| this, std::move(receiver), |
| network::mojom::blink::CrossOriginEmbedderPolicy::kNone, |
| GetThread()->GetTaskRunner(TaskType::kInternalDefault)); |
| } |
| |
| void ServiceWorkerGlobalScope::OnNavigationPreloadResponse( |
| int fetch_event_id, |
| std::unique_ptr<WebURLResponse> response, |
| mojo::ScopedDataPipeConsumerHandle data_pipe) { |
| DCHECK(IsContextThread()); |
| auto it = pending_preload_fetch_events_.find(fetch_event_id); |
| DCHECK(it != pending_preload_fetch_events_.end()); |
| FetchEvent* fetch_event = it->value.Get(); |
| DCHECK(fetch_event); |
| fetch_event->OnNavigationPreloadResponse(ScriptController()->GetScriptState(), |
| std::move(response), |
| std::move(data_pipe)); |
| } |
| |
| void ServiceWorkerGlobalScope::OnNavigationPreloadError( |
| int fetch_event_id, |
| std::unique_ptr<WebServiceWorkerError> error) { |
| DCHECK(IsContextThread()); |
| FetchEvent* fetch_event = pending_preload_fetch_events_.Take(fetch_event_id); |
| DCHECK(fetch_event); |
| // Display an error message to the console, preferring the unsanitized one if |
| // available. |
| const WebString& error_message = error->unsanitized_message.IsEmpty() |
| ? error->message |
| : error->unsanitized_message; |
| if (!error_message.IsEmpty()) { |
| AddConsoleMessage(ConsoleMessage::Create( |
| mojom::ConsoleMessageSource::kWorker, |
| mojom::ConsoleMessageLevel::kError, error_message)); |
| } |
| // Reject the preloadResponse promise. |
| fetch_event->OnNavigationPreloadError(ScriptController()->GetScriptState(), |
| std::move(error)); |
| } |
| |
| void ServiceWorkerGlobalScope::OnNavigationPreloadComplete( |
| int fetch_event_id, |
| base::TimeTicks completion_time, |
| int64_t encoded_data_length, |
| int64_t encoded_body_length, |
| int64_t decoded_body_length) { |
| DCHECK(IsContextThread()); |
| FetchEvent* fetch_event = pending_preload_fetch_events_.Take(fetch_event_id); |
| DCHECK(fetch_event); |
| fetch_event->OnNavigationPreloadComplete( |
| this, completion_time, encoded_data_length, encoded_body_length, |
| decoded_body_length); |
| } |
| |
| std::unique_ptr<ServiceWorkerEventQueue::StayAwakeToken> |
| ServiceWorkerGlobalScope::CreateStayAwakeToken() { |
| return event_queue_->CreateStayAwakeToken(); |
| } |
| |
| ServiceWorker* ServiceWorkerGlobalScope::GetOrCreateServiceWorker( |
| WebServiceWorkerObjectInfo info) { |
| if (info.version_id == mojom::blink::kInvalidServiceWorkerVersionId) |
| return nullptr; |
| ::blink::ServiceWorker* worker = service_worker_objects_.at(info.version_id); |
| if (!worker) { |
| worker = ::blink::ServiceWorker::Create(this, std::move(info)); |
| service_worker_objects_.Set(info.version_id, worker); |
| } |
| return worker; |
| } |
| |
| bool ServiceWorkerGlobalScope::AddEventListenerInternal( |
| const AtomicString& event_type, |
| EventListener* listener, |
| const AddEventListenerOptionsResolved* options) { |
| if (did_evaluate_script_) { |
| String message = String::Format( |
| "Event handler of '%s' event must be added on the initial evaluation " |
| "of worker script.", |
| event_type.Utf8().c_str()); |
| AddConsoleMessage( |
| ConsoleMessage::Create(mojom::ConsoleMessageSource::kJavaScript, |
| mojom::ConsoleMessageLevel::kWarning, message)); |
| } |
| return WorkerGlobalScope::AddEventListenerInternal(event_type, listener, |
| options); |
| } |
| |
| bool ServiceWorkerGlobalScope::FetchClassicImportedScript( |
| const KURL& script_url, |
| KURL* out_response_url, |
| String* out_source_code, |
| std::unique_ptr<Vector<uint8_t>>* out_cached_meta_data) { |
| // InstalledScriptsManager is used only for starting installed service |
| // workers. |
| if (installed_scripts_manager_) { |
| // All imported scripts must be installed. This is already checked in |
| // ServiceWorkerGlobalScope::importScripts(). |
| DCHECK(installed_scripts_manager_->IsScriptInstalled(script_url)); |
| std::unique_ptr<InstalledScriptsManager::ScriptData> script_data = |
| installed_scripts_manager_->GetScriptData(script_url); |
| if (!script_data) |
| return false; |
| *out_response_url = script_url; |
| *out_source_code = script_data->TakeSourceText(); |
| *out_cached_meta_data = script_data->TakeMetaData(); |
| // TODO(shimazu): Add appropriate probes for inspector. |
| return true; |
| } |
| // This is a new service worker. Proceed with importing scripts and installing |
| // them. |
| return WorkerGlobalScope::FetchClassicImportedScript( |
| script_url, out_response_url, out_source_code, out_cached_meta_data); |
| } |
| |
| const AtomicString& ServiceWorkerGlobalScope::InterfaceName() const { |
| return event_target_names::kServiceWorkerGlobalScope; |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchExtendableEvent( |
| Event* event, |
| WaitUntilObserver* observer) { |
| observer->WillDispatchEvent(); |
| DispatchEvent(*event); |
| |
| // Check if the worker thread is forcibly terminated during the event |
| // because of timeout etc. |
| observer->DidDispatchEvent(GetThread()->IsForciblyTerminated()); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchExtendableEventWithRespondWith( |
| Event* event, |
| WaitUntilObserver* wait_until_observer, |
| RespondWithObserver* respond_with_observer) { |
| wait_until_observer->WillDispatchEvent(); |
| respond_with_observer->WillDispatchEvent(); |
| DispatchEventResult dispatch_result = DispatchEvent(*event); |
| respond_with_observer->DidDispatchEvent(dispatch_result); |
| // false is okay because waitUntil() for events with respondWith() doesn't |
| // care about the promise rejection or an uncaught runtime script error. |
| wait_until_observer->DidDispatchEvent(false /* event_dispatch_failed */); |
| } |
| |
| void ServiceWorkerGlobalScope::Trace(blink::Visitor* visitor) { |
| visitor->Trace(clients_); |
| visitor->Trace(registration_); |
| visitor->Trace(service_worker_); |
| visitor->Trace(service_worker_objects_); |
| visitor->Trace(pending_preload_fetch_events_); |
| WorkerGlobalScope::Trace(visitor); |
| } |
| |
| bool ServiceWorkerGlobalScope::HasRelatedFetchEvent( |
| const KURL& request_url) const { |
| auto it = unresponded_fetch_event_counts_.find(request_url); |
| return it != unresponded_fetch_event_counts_.end(); |
| } |
| |
| void ServiceWorkerGlobalScope::importScripts( |
| const HeapVector<StringOrTrustedScriptURL>& urls, |
| ExceptionState& exception_state) { |
| for (const StringOrTrustedScriptURL& stringOrUrl : urls) { |
| String string_url = stringOrUrl.IsString() |
| ? stringOrUrl.GetAsString() |
| : stringOrUrl.GetAsTrustedScriptURL()->toString(); |
| |
| KURL completed_url = CompleteURL(string_url); |
| if (installed_scripts_manager_ && |
| !installed_scripts_manager_->IsScriptInstalled(completed_url)) { |
| DCHECK(installed_scripts_manager_->IsScriptInstalled(Url())); |
| exception_state.ThrowDOMException( |
| DOMExceptionCode::kNetworkError, |
| "Failed to import '" + completed_url.ElidedString() + |
| "'. importScripts() of new scripts after service worker " |
| "installation is not allowed."); |
| return; |
| } |
| } |
| WorkerGlobalScope::importScripts(urls, exception_state); |
| } |
| |
| SingleCachedMetadataHandler* |
| ServiceWorkerGlobalScope::CreateWorkerScriptCachedMetadataHandler( |
| const KURL& script_url, |
| std::unique_ptr<Vector<uint8_t>> meta_data) { |
| return MakeGarbageCollected<ServiceWorkerScriptCachedMetadataHandler>( |
| this, script_url, std::move(meta_data)); |
| } |
| |
| ScriptPromise ServiceWorkerGlobalScope::fetch(ScriptState* script_state, |
| const RequestInfo& input, |
| const RequestInit* init, |
| ExceptionState& exception_state) { |
| return GlobalFetch::fetch(script_state, *this, input, init, exception_state); |
| } |
| |
| void ServiceWorkerGlobalScope::ExceptionThrown(ErrorEvent* event) { |
| WorkerGlobalScope::ExceptionThrown(event); |
| if (WorkerThreadDebugger* debugger = |
| WorkerThreadDebugger::From(GetThread()->GetIsolate())) |
| debugger->ExceptionThrown(GetThread(), event); |
| } |
| |
| void ServiceWorkerGlobalScope::CountCacheStorageInstalledScript( |
| uint64_t script_size, |
| uint64_t script_metadata_size) { |
| ++cache_storage_installed_script_count_; |
| cache_storage_installed_script_total_size_ += script_size; |
| cache_storage_installed_script_metadata_total_size_ += script_metadata_size; |
| |
| DEFINE_THREAD_SAFE_STATIC_LOCAL( |
| CustomCountHistogram, script_size_histogram, |
| ("ServiceWorker.CacheStorageInstalledScript.ScriptSize", 1000, 5000000, |
| 50)); |
| script_size_histogram.Count( |
| base::saturated_cast<base::Histogram::Sample>(script_size)); |
| |
| if (script_metadata_size) { |
| DEFINE_THREAD_SAFE_STATIC_LOCAL( |
| CustomCountHistogram, script_metadata_size_histogram, |
| ("ServiceWorker.CacheStorageInstalledScript.CachedMetadataSize", 1000, |
| 50000000, 50)); |
| script_metadata_size_histogram.Count( |
| base::saturated_cast<base::Histogram::Sample>(script_metadata_size)); |
| } |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleInstallEvent( |
| int install_event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| SetFetchHandlerExistence(HasEventListeners(event_type_names::kFetch) |
| ? FetchHandlerExistence::EXISTS |
| : FetchHandlerExistence::DOES_NOT_EXIST); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleInstallEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(install_event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(&install_event_callbacks_, event_queue_.get(), |
| install_event_id, status, |
| HasEventListeners(event_type_names::kFetch)); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleActivateEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleActivateEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(&activate_event_callbacks_, event_queue_.get(), event_id, |
| status); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleBackgroundFetchAbortEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DidHandleBackgroundFetchAbortEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(&background_fetch_abort_event_callbacks_, event_queue_.get(), |
| event_id, status); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleBackgroundFetchClickEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DidHandleBackgroundFetchClickEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(&background_fetch_click_event_callbacks_, event_queue_.get(), |
| event_id, status); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleBackgroundFetchFailEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DidHandleBackgroundFetchFailEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(&background_fetch_fail_event_callbacks_, event_queue_.get(), |
| event_id, status); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleBackgroundFetchSuccessEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DidHandleBackgroundFetchSuccessEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(&background_fetched_event_callbacks_, event_queue_.get(), |
| event_id, status); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleExtendableMessageEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DidHandleExtendableMessageEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(&message_event_callbacks_, event_queue_.get(), event_id, |
| status); |
| } |
| |
| void ServiceWorkerGlobalScope::RespondToFetchEventWithNoResponse( |
| int fetch_event_id, |
| const KURL& request_url, |
| base::TimeTicks event_dispatch_time, |
| base::TimeTicks respond_with_settled_time) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::RespondToFetchEventWithNoResponse", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(fetch_event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); |
| DCHECK(fetch_response_callbacks_.Contains(fetch_event_id)); |
| mojo::Remote<mojom::blink::ServiceWorkerFetchResponseCallback> |
| response_callback = fetch_response_callbacks_.Take(fetch_event_id); |
| |
| auto timing = mojom::blink::ServiceWorkerFetchEventTiming::New(); |
| timing->dispatch_event_time = event_dispatch_time; |
| timing->respond_with_settled_time = respond_with_settled_time; |
| |
| NoteRespondedToFetchEvent(request_url); |
| |
| response_callback->OnFallback(std::move(timing)); |
| } |
| |
| void ServiceWorkerGlobalScope::RespondToFetchEvent( |
| int fetch_event_id, |
| const KURL& request_url, |
| mojom::blink::FetchAPIResponsePtr response, |
| base::TimeTicks event_dispatch_time, |
| base::TimeTicks respond_with_settled_time) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::RespondToFetchEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(fetch_event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); |
| DCHECK(fetch_response_callbacks_.Contains(fetch_event_id)); |
| |
| mojo::Remote<mojom::blink::ServiceWorkerFetchResponseCallback> |
| response_callback = fetch_response_callbacks_.Take(fetch_event_id); |
| |
| auto timing = mojom::blink::ServiceWorkerFetchEventTiming::New(); |
| timing->dispatch_event_time = event_dispatch_time; |
| timing->respond_with_settled_time = respond_with_settled_time; |
| |
| NoteRespondedToFetchEvent(request_url); |
| |
| response_callback->OnResponse(std::move(response), std::move(timing)); |
| } |
| |
| void ServiceWorkerGlobalScope::RespondToFetchEventWithResponseStream( |
| int fetch_event_id, |
| const KURL& request_url, |
| mojom::blink::FetchAPIResponsePtr response, |
| mojom::blink::ServiceWorkerStreamHandlePtr body_as_stream, |
| base::TimeTicks event_dispatch_time, |
| base::TimeTicks respond_with_settled_time) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::RespondToFetchEventWithResponseStream", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(fetch_event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); |
| DCHECK(fetch_response_callbacks_.Contains(fetch_event_id)); |
| mojo::Remote<mojom::blink::ServiceWorkerFetchResponseCallback> |
| response_callback = fetch_response_callbacks_.Take(fetch_event_id); |
| |
| auto timing = mojom::blink::ServiceWorkerFetchEventTiming::New(); |
| timing->dispatch_event_time = event_dispatch_time; |
| timing->respond_with_settled_time = respond_with_settled_time; |
| |
| NoteRespondedToFetchEvent(request_url); |
| |
| response_callback->OnResponseStream( |
| std::move(response), std::move(body_as_stream), std::move(timing)); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleFetchEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| // This TRACE_EVENT is used for perf benchmark to confirm if all of fetch |
| // events have completed. (crbug.com/736697) |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleFetchEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| if (!RunEventCallback(&fetch_event_callbacks_, event_queue_.get(), event_id, |
| status)) { |
| // The event may have been aborted. Its response callback also needs to be |
| // deleted. |
| fetch_response_callbacks_.erase(event_id); |
| } else { |
| // |fetch_response_callback| should be used before settling a promise for |
| // waitUntil(). |
| DCHECK(!fetch_response_callbacks_.Contains(event_id)); |
| } |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleNotificationClickEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DidHandleNotificationClickEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(¬ification_click_event_callbacks_, event_queue_.get(), |
| event_id, status); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleNotificationCloseEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DidHandleNotificationCloseEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(¬ification_close_event_callbacks_, event_queue_.get(), |
| event_id, status); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandlePushEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DidHandlePushEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(&push_event_callbacks_, event_queue_.get(), event_id, |
| status); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandlePushSubscriptionChangeEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DidHandlePushSubscriptionChangeEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(&push_subscription_change_event_callbacks_, |
| event_queue_.get(), event_id, status); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleSyncEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleSyncEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(&sync_event_callbacks_, event_queue_.get(), event_id, |
| status); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandlePeriodicSyncEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DidHandlePeriodicSyncEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(&periodic_sync_event_callbacks_, event_queue_.get(), |
| event_id, status); |
| } |
| |
| void ServiceWorkerGlobalScope::RespondToAbortPaymentEvent( |
| int event_id, |
| bool payment_aborted) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::RespondToAbortPaymentEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); |
| DCHECK(abort_payment_result_callbacks_.Contains(event_id)); |
| mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback> |
| result_callback = abort_payment_result_callbacks_.Take(event_id); |
| result_callback->OnResponseForAbortPayment(payment_aborted); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleAbortPaymentEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleAbortPaymentEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| if (RunEventCallback(&abort_payment_event_callbacks_, event_queue_.get(), |
| event_id, status)) { |
| abort_payment_result_callbacks_.erase(event_id); |
| } |
| } |
| |
| void ServiceWorkerGlobalScope::RespondToCanMakePaymentEvent( |
| int event_id, |
| bool can_make_payment) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::RespondToCanMakePaymentEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); |
| DCHECK(can_make_payment_result_callbacks_.Contains(event_id)); |
| mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback> |
| result_callback = can_make_payment_result_callbacks_.Take(event_id); |
| result_callback->OnResponseForCanMakePayment(can_make_payment); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleCanMakePaymentEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleCanMakePaymentEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| if (RunEventCallback(&can_make_payment_event_callbacks_, event_queue_.get(), |
| event_id, status)) { |
| can_make_payment_result_callbacks_.erase(event_id); |
| } |
| } |
| |
| void ServiceWorkerGlobalScope::RespondToPaymentRequestEvent( |
| int payment_event_id, |
| payments::mojom::blink::PaymentHandlerResponsePtr response) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::RespondToPaymentRequestEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(payment_event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); |
| DCHECK(payment_response_callbacks_.Contains(payment_event_id)); |
| mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback> |
| response_callback = payment_response_callbacks_.Take(payment_event_id); |
| response_callback->OnResponseForPaymentRequest(std::move(response)); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandlePaymentRequestEvent( |
| int payment_event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DidHandlePaymentRequestEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(payment_event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| if (RunEventCallback(&payment_request_event_callbacks_, event_queue_.get(), |
| payment_event_id, status)) { |
| payment_response_callbacks_.erase(payment_event_id); |
| } |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleCookieChangeEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleCookieChangeEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(&cookie_change_event_callbacks_, event_queue_.get(), |
| event_id, status); |
| } |
| |
| void ServiceWorkerGlobalScope::DidHandleContentDeleteEvent( |
| int event_id, |
| mojom::ServiceWorkerEventStatus status) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleContentDeleteEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status)); |
| RunEventCallback(&content_delete_callbacks_, event_queue_.get(), event_id, |
| status); |
| } |
| |
| void ServiceWorkerGlobalScope::SetIsInstalling(bool is_installing) { |
| is_installing_ = is_installing; |
| if (is_installing) |
| return; |
| |
| // Installing phase is finished; record the stats for the scripts that are |
| // stored in Cache storage during installation. |
| DEFINE_THREAD_SAFE_STATIC_LOCAL( |
| CustomCountHistogram, cache_storage_installed_script_count_histogram, |
| ("ServiceWorker.CacheStorageInstalledScript.Count", 1, 1000, 50)); |
| cache_storage_installed_script_count_histogram.Count( |
| base::saturated_cast<base::Histogram::Sample>( |
| cache_storage_installed_script_count_)); |
| DEFINE_THREAD_SAFE_STATIC_LOCAL( |
| CustomCountHistogram, cache_storage_installed_script_total_size_histogram, |
| ("ServiceWorker.CacheStorageInstalledScript.ScriptTotalSize", 1000, |
| 50000000, 50)); |
| cache_storage_installed_script_total_size_histogram.Count( |
| base::saturated_cast<base::Histogram::Sample>( |
| cache_storage_installed_script_total_size_)); |
| |
| if (cache_storage_installed_script_metadata_total_size_) { |
| DEFINE_THREAD_SAFE_STATIC_LOCAL( |
| CustomCountHistogram, |
| cache_storage_installed_script_metadata_total_size_histogram, |
| ("ServiceWorker.CacheStorageInstalledScript.CachedMetadataTotalSize", |
| 1000, 50000000, 50)); |
| cache_storage_installed_script_metadata_total_size_histogram.Count( |
| base::saturated_cast<base::Histogram::Sample>( |
| cache_storage_installed_script_metadata_total_size_)); |
| } |
| } |
| |
| mojo::PendingRemote<mojom::blink::CacheStorage> |
| ServiceWorkerGlobalScope::TakeCacheStorage() { |
| return std::move(cache_storage_remote_); |
| } |
| |
| mojom::blink::ServiceWorkerHost* |
| ServiceWorkerGlobalScope::GetServiceWorkerHost() { |
| DCHECK(service_worker_host_); |
| return service_worker_host_.get(); |
| } |
| |
| void ServiceWorkerGlobalScope::OnBeforeStartEvent(bool is_offline_event) { |
| DCHECK(IsContextThread()); |
| SetIsOfflineMode(is_offline_event); |
| } |
| |
| void ServiceWorkerGlobalScope::OnIdleTimeout() { |
| DCHECK(IsContextThread()); |
| // RequestedTermination() returns true if ServiceWorkerEventQueue agrees |
| // we should request the host to terminate this worker now. |
| DCHECK(RequestedTermination()); |
| // We use CrossThreadBindOnce() here because the callback may be destroyed on |
| // the main thread if the worker thread has already terminated. |
| To<ServiceWorkerGlobalScopeProxy>(ReportingProxy()) |
| .RequestTermination( |
| CrossThreadBindOnce(&ServiceWorkerGlobalScope::OnRequestedTermination, |
| WrapCrossThreadWeakPersistent(this))); |
| } |
| |
| void ServiceWorkerGlobalScope::OnRequestedTermination(bool will_be_terminated) { |
| DCHECK(IsContextThread()); |
| // This worker will be terminated soon. Ignore the message. |
| if (will_be_terminated) |
| return; |
| |
| // Push a dummy task to run all of queued tasks. This updates the |
| // idle timer too. |
| event_queue_->EnqueueNormal(WTF::Bind(&ServiceWorkerEventQueue::EndEvent, |
| WTF::Unretained(event_queue_.get())), |
| base::DoNothing(), base::nullopt); |
| } |
| |
| bool ServiceWorkerGlobalScope::RequestedTermination() const { |
| DCHECK(IsContextThread()); |
| return event_queue_->did_idle_timeout(); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchExtendableMessageEventInternal( |
| int event_id, |
| mojom::blink::ExtendableMessageEventPtr event) { |
| BlinkTransferableMessage msg = std::move(event->message); |
| MessagePortArray* ports = |
| MessagePort::EntanglePorts(*this, std::move(msg.ports)); |
| String origin; |
| if (!event->source_origin->IsOpaque()) |
| origin = event->source_origin->ToString(); |
| WaitUntilObserver* observer = nullptr; |
| Event* event_to_dispatch = nullptr; |
| |
| if (event->source_info_for_client) { |
| mojom::blink::ServiceWorkerClientInfoPtr client_info = |
| std::move(event->source_info_for_client); |
| DCHECK(!client_info->client_uuid.IsEmpty()); |
| ServiceWorkerClient* source = nullptr; |
| if (client_info->client_type == mojom::ServiceWorkerClientType::kWindow) |
| source = MakeGarbageCollected<ServiceWorkerWindowClient>(*client_info); |
| else |
| source = MakeGarbageCollected<ServiceWorkerClient>(*client_info); |
| // TODO(crbug.com/1018092): Factor out these security checks so they aren't |
| // duplicated in so many places. |
| if (msg.message->IsOriginCheckRequired()) { |
| const SecurityOrigin* target_origin = |
| GetExecutionContext()->GetSecurityOrigin(); |
| if (!msg.sender_origin || |
| !msg.sender_origin->IsSameOriginWith(target_origin)) { |
| observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kMessageerror, event_id); |
| event_to_dispatch = ExtendableMessageEvent::CreateError( |
| origin, ports, source, observer); |
| } |
| } |
| if (!event_to_dispatch) { |
| if (!msg.locked_agent_cluster_id || |
| GetExecutionContext()->IsSameAgentCluster( |
| *msg.locked_agent_cluster_id)) { |
| observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kMessage, event_id); |
| event_to_dispatch = ExtendableMessageEvent::Create( |
| std::move(msg.message), origin, ports, source, observer); |
| } else { |
| observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kMessageerror, event_id); |
| event_to_dispatch = ExtendableMessageEvent::CreateError( |
| origin, ports, source, observer); |
| } |
| } |
| DispatchExtendableEvent(event_to_dispatch, observer); |
| return; |
| } |
| |
| DCHECK_NE(event->source_info_for_service_worker->version_id, |
| mojom::blink::kInvalidServiceWorkerVersionId); |
| ::blink::ServiceWorker* source = ::blink::ServiceWorker::From( |
| GetExecutionContext(), std::move(event->source_info_for_service_worker)); |
| // TODO(crbug.com/1018092): Factor out these security checks so they aren't |
| // duplicated in so many places. |
| if (msg.message->IsOriginCheckRequired()) { |
| const SecurityOrigin* target_origin = |
| GetExecutionContext()->GetSecurityOrigin(); |
| if (!msg.sender_origin || |
| !msg.sender_origin->IsSameOriginWith(target_origin)) { |
| observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kMessageerror, event_id); |
| event_to_dispatch = |
| ExtendableMessageEvent::CreateError(origin, ports, source, observer); |
| } |
| } |
| if (!event_to_dispatch) { |
| if (!msg.locked_agent_cluster_id || |
| GetExecutionContext()->IsSameAgentCluster( |
| *msg.locked_agent_cluster_id)) { |
| observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kMessage, event_id); |
| event_to_dispatch = ExtendableMessageEvent::Create( |
| std::move(msg.message), origin, ports, source, observer); |
| } else { |
| observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kMessageerror, event_id); |
| event_to_dispatch = |
| ExtendableMessageEvent::CreateError(origin, ports, source, observer); |
| } |
| } |
| DispatchExtendableEvent(event_to_dispatch, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::StartFetchEvent( |
| mojom::blink::DispatchFetchEventParamsPtr params, |
| network::mojom::blink::CrossOriginEmbedderPolicy requestor_coep, |
| mojo::PendingRemote<mojom::blink::ServiceWorkerFetchResponseCallback> |
| response_callback, |
| DispatchFetchEventInternalCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| fetch_event_callbacks_.Set(event_id, std::move(callback)); |
| fetch_response_callbacks_.Set( |
| event_id, mojo::Remote<mojom::blink::ServiceWorkerFetchResponseCallback>( |
| std::move(response_callback))); |
| |
| // This TRACE_EVENT is used for perf benchmark to confirm if all of fetch |
| // events have completed. (crbug.com/736697) |
| TRACE_EVENT_WITH_FLOW1( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DispatchFetchEventInternal", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT, "url", |
| params->request->url.ElidedString().Utf8()); |
| |
| // Set up for navigation preload (FetchEvent#preloadResponse) if needed. |
| const bool navigation_preload_sent = !!params->preload_handle; |
| if (navigation_preload_sent) { |
| To<ServiceWorkerGlobalScopeProxy>(ReportingProxy()) |
| .SetupNavigationPreload(event_id, params->request->url, |
| std::move(params->preload_handle)); |
| } |
| |
| mojom::blink::FetchAPIRequest& fetch_request = *params->request; |
| ScriptState::Scope scope(ScriptController()->GetScriptState()); |
| auto* wait_until_observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kFetch, event_id); |
| auto* respond_with_observer = MakeGarbageCollected<FetchRespondWithObserver>( |
| this, event_id, requestor_coep, fetch_request, wait_until_observer); |
| Request* request = |
| Request::Create(ScriptController()->GetScriptState(), fetch_request, |
| Request::ForServiceWorkerFetchEvent::kTrue); |
| request->getHeaders()->SetGuard(Headers::kImmutableGuard); |
| FetchEventInit* event_init = FetchEventInit::Create(); |
| event_init->setCancelable(true); |
| event_init->setRequest(request); |
| event_init->setClientId( |
| fetch_request.is_main_resource_load ? String() : params->client_id); |
| event_init->setResultingClientId( |
| !fetch_request.is_main_resource_load ? String() : params->client_id); |
| event_init->setIsReload(fetch_request.is_reload); |
| ScriptState* script_state = ScriptController()->GetScriptState(); |
| FetchEvent* fetch_event = MakeGarbageCollected<FetchEvent>( |
| script_state, event_type_names::kFetch, event_init, respond_with_observer, |
| wait_until_observer, |
| mojo::PendingRemote<mojom::blink::WorkerTimingContainer>( |
| std::move(params->worker_timing_remote)), |
| navigation_preload_sent); |
| if (navigation_preload_sent) { |
| // Keep |fetchEvent| until OnNavigationPreloadComplete() or |
| // onNavigationPreloadError() will be called. |
| pending_preload_fetch_events_.insert(event_id, fetch_event); |
| } |
| |
| NoteNewFetchEvent(request->url()); |
| |
| DispatchExtendableEventWithRespondWith(fetch_event, wait_until_observer, |
| respond_with_observer); |
| } |
| |
| void ServiceWorkerGlobalScope::SetFetchHandlerExistence( |
| FetchHandlerExistence fetch_handler_existence) { |
| DCHECK(IsContextThread()); |
| if (fetch_handler_existence == FetchHandlerExistence::EXISTS) |
| GetThread()->GetIsolate()->IsolateInForegroundNotification(); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchFetchEventForSubresource( |
| mojom::blink::DispatchFetchEventParamsPtr params, |
| mojo::PendingRemote<mojom::blink::ServiceWorkerFetchResponseCallback> |
| response_callback, |
| DispatchFetchEventForSubresourceCallback callback) { |
| DCHECK(IsContextThread()); |
| TRACE_EVENT2("ServiceWorker", |
| "ServiceWorkerGlobalScope::DispatchFetchEventForSubresource", |
| "url", params->request->url.ElidedString().Utf8(), "queued", |
| RequestedTermination() ? "true" : "false"); |
| network::mojom::blink::CrossOriginEmbedderPolicy requestor_coep = |
| controller_receivers_.current_context(); |
| if (RequestedTermination()) { |
| event_queue_->EnqueuePending( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartFetchEvent, |
| WrapWeakPersistent(this), std::move(params), |
| std::move(requestor_coep), std::move(response_callback), |
| std::move(callback)), |
| CreateAbortCallback(&fetch_event_callbacks_), base::nullopt); |
| } else { |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartFetchEvent, |
| WrapWeakPersistent(this), std::move(params), |
| std::move(requestor_coep), std::move(response_callback), |
| std::move(callback)), |
| CreateAbortCallback(&fetch_event_callbacks_), base::nullopt); |
| } |
| } |
| |
| void ServiceWorkerGlobalScope::Clone( |
| mojo::PendingReceiver<mojom::blink::ControllerServiceWorker> receiver, |
| network::mojom::blink::CrossOriginEmbedderPolicy |
| cross_origin_embedder_policy) { |
| DCHECK(IsContextThread()); |
| controller_receivers_.Add( |
| this, std::move(receiver), cross_origin_embedder_policy, |
| GetThread()->GetTaskRunner(TaskType::kInternalDefault)); |
| } |
| |
| void ServiceWorkerGlobalScope::InitializeGlobalScope( |
| mojo::PendingAssociatedRemote<mojom::blink::ServiceWorkerHost> |
| service_worker_host, |
| mojom::blink::ServiceWorkerRegistrationObjectInfoPtr registration_info, |
| mojom::blink::ServiceWorkerObjectInfoPtr service_worker_info, |
| mojom::blink::FetchHandlerExistence fetch_hander_existence) { |
| DCHECK(IsContextThread()); |
| DCHECK(!global_scope_initialized_); |
| |
| DCHECK(service_worker_host.is_valid()); |
| DCHECK(!service_worker_host_); |
| service_worker_host_.Bind(std::move(service_worker_host), |
| GetTaskRunner(TaskType::kInternalDefault)); |
| |
| // Set ServiceWorkerGlobalScope#registration. |
| DCHECK_NE(registration_info->registration_id, |
| mojom::blink::kInvalidServiceWorkerRegistrationId); |
| DCHECK(registration_info->host_remote.is_valid()); |
| DCHECK(registration_info->receiver.is_valid()); |
| registration_ = MakeGarbageCollected<ServiceWorkerRegistration>( |
| GetExecutionContext(), std::move(registration_info)); |
| |
| // Set ServiceWorkerGlobalScope#serviceWorker. |
| DCHECK_NE(service_worker_info->version_id, |
| mojom::blink::kInvalidServiceWorkerVersionId); |
| DCHECK(service_worker_info->host_remote.is_valid()); |
| DCHECK(service_worker_info->receiver.is_valid()); |
| service_worker_ = ::blink::ServiceWorker::From( |
| GetExecutionContext(), std::move(service_worker_info)); |
| |
| SetFetchHandlerExistence(fetch_hander_existence); |
| |
| global_scope_initialized_ = true; |
| if (!pause_evaluation_) |
| ReadyToRunWorkerScript(); |
| } |
| |
| void ServiceWorkerGlobalScope::PauseEvaluation() { |
| DCHECK(IsContextThread()); |
| DCHECK(!global_scope_initialized_); |
| DCHECK(!pause_evaluation_); |
| pause_evaluation_ = true; |
| } |
| |
| void ServiceWorkerGlobalScope::ResumeEvaluation() { |
| DCHECK(IsContextThread()); |
| DCHECK(pause_evaluation_); |
| pause_evaluation_ = false; |
| if (global_scope_initialized_) |
| ReadyToRunWorkerScript(); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchInstallEvent( |
| DispatchInstallEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartInstallEvent, |
| WrapWeakPersistent(this), std::move(callback)), |
| CreateAbortCallback(&install_event_callbacks_, |
| false /* has_fetch_handler */), |
| base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartInstallEvent( |
| DispatchInstallEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| install_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DispatchInstallEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kInstall, event_id); |
| Event* event = |
| InstallEvent::Create(event_type_names::kInstall, |
| ExtendableEventInit::Create(), event_id, observer); |
| SetIsInstalling(true); |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchActivateEvent( |
| DispatchActivateEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartActivateEvent, |
| WrapWeakPersistent(this), std::move(callback)), |
| CreateAbortCallback(&activate_event_callbacks_), base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartActivateEvent( |
| DispatchActivateEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| activate_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DispatchActivateEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kActivate, event_id); |
| Event* event = ExtendableEvent::Create( |
| event_type_names::kActivate, ExtendableEventInit::Create(), observer); |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchBackgroundFetchAbortEvent( |
| mojom::blink::BackgroundFetchRegistrationPtr registration, |
| DispatchBackgroundFetchAbortEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartBackgroundFetchAbortEvent, |
| WrapWeakPersistent(this), std::move(registration), |
| std::move(callback)), |
| CreateAbortCallback(&background_fetch_abort_event_callbacks_), |
| base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartBackgroundFetchAbortEvent( |
| mojom::blink::BackgroundFetchRegistrationPtr registration, |
| DispatchBackgroundFetchAbortEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| background_fetch_abort_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DispatchBackgroundFetchAbortEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kBackgroundFetchAbort, event_id); |
| ScriptState* script_state = ScriptController()->GetScriptState(); |
| |
| // Do not remove this, |scope| is needed by |
| // BackgroundFetchEvent::Create which eventually calls ToV8. |
| ScriptState::Scope scope(script_state); |
| |
| BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create(); |
| init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>( |
| registration_, std::move(registration))); |
| |
| BackgroundFetchEvent* event = BackgroundFetchEvent::Create( |
| event_type_names::kBackgroundfetchabort, init, observer); |
| |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchBackgroundFetchClickEvent( |
| mojom::blink::BackgroundFetchRegistrationPtr registration, |
| DispatchBackgroundFetchClickEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartBackgroundFetchClickEvent, |
| WrapWeakPersistent(this), std::move(registration), |
| std::move(callback)), |
| CreateAbortCallback(&background_fetch_click_event_callbacks_), |
| base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartBackgroundFetchClickEvent( |
| mojom::blink::BackgroundFetchRegistrationPtr registration, |
| DispatchBackgroundFetchClickEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| background_fetch_click_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DispatchBackgroundFetchClickEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kBackgroundFetchClick, event_id); |
| |
| BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create(); |
| init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>( |
| registration_, std::move(registration))); |
| |
| BackgroundFetchEvent* event = BackgroundFetchEvent::Create( |
| event_type_names::kBackgroundfetchclick, init, observer); |
| |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchBackgroundFetchFailEvent( |
| mojom::blink::BackgroundFetchRegistrationPtr registration, |
| DispatchBackgroundFetchFailEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartBackgroundFetchFailEvent, |
| WrapWeakPersistent(this), std::move(registration), |
| std::move(callback)), |
| CreateAbortCallback(&background_fetch_fail_event_callbacks_), |
| base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartBackgroundFetchFailEvent( |
| mojom::blink::BackgroundFetchRegistrationPtr registration, |
| DispatchBackgroundFetchFailEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| background_fetch_fail_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DispatchBackgroundFetchFailEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kBackgroundFetchFail, event_id); |
| |
| ScriptState* script_state = ScriptController()->GetScriptState(); |
| |
| // Do not remove this, |scope| is needed by |
| // BackgroundFetchSettledEvent::Create which eventually calls ToV8. |
| ScriptState::Scope scope(script_state); |
| |
| BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create(); |
| init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>( |
| registration_, std::move(registration))); |
| |
| BackgroundFetchUpdateUIEvent* event = BackgroundFetchUpdateUIEvent::Create( |
| event_type_names::kBackgroundfetchfail, init, observer, registration_); |
| |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchBackgroundFetchSuccessEvent( |
| mojom::blink::BackgroundFetchRegistrationPtr registration, |
| DispatchBackgroundFetchSuccessEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartBackgroundFetchSuccessEvent, |
| WrapWeakPersistent(this), std::move(registration), |
| std::move(callback)), |
| CreateAbortCallback(&background_fetched_event_callbacks_), base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartBackgroundFetchSuccessEvent( |
| mojom::blink::BackgroundFetchRegistrationPtr registration, |
| DispatchBackgroundFetchSuccessEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| background_fetched_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DispatchBackgroundFetchSuccessEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kBackgroundFetchSuccess, event_id); |
| |
| ScriptState* script_state = ScriptController()->GetScriptState(); |
| |
| // Do not remove this, |scope| is needed by |
| // BackgroundFetchSettledEvent::Create which eventually calls ToV8. |
| ScriptState::Scope scope(script_state); |
| |
| BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create(); |
| init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>( |
| registration_, std::move(registration))); |
| |
| BackgroundFetchUpdateUIEvent* event = BackgroundFetchUpdateUIEvent::Create( |
| event_type_names::kBackgroundfetchsuccess, init, observer, registration_); |
| |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchExtendableMessageEvent( |
| mojom::blink::ExtendableMessageEventPtr event, |
| DispatchExtendableMessageEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartExtendableMessageEvent, |
| WrapWeakPersistent(this), std::move(event), |
| std::move(callback)), |
| CreateAbortCallback(&message_event_callbacks_), base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartExtendableMessageEvent( |
| mojom::blink::ExtendableMessageEventPtr event, |
| DispatchExtendableMessageEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| message_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DispatchExtendableMessageEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| DispatchExtendableMessageEventInternal(event_id, std::move(event)); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchFetchEventForMainResource( |
| mojom::blink::DispatchFetchEventParamsPtr params, |
| mojo::PendingRemote<mojom::blink::ServiceWorkerFetchResponseCallback> |
| response_callback, |
| DispatchFetchEventForMainResourceCallback callback) { |
| DCHECK(IsContextThread()); |
| |
| // We can use kNone as a |requestor_coep| for the main resource because it |
| // must be the same origin. |
| if (params->is_offline_capability_check) { |
| event_queue_->EnqueueOffline( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartFetchEvent, |
| WrapWeakPersistent(this), std::move(params), |
| network::mojom::blink::CrossOriginEmbedderPolicy::kNone, |
| std::move(response_callback), std::move(callback)), |
| CreateAbortCallback(&fetch_event_callbacks_), base::nullopt); |
| } else { |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartFetchEvent, |
| WrapWeakPersistent(this), std::move(params), |
| network::mojom::blink::CrossOriginEmbedderPolicy::kNone, |
| std::move(response_callback), std::move(callback)), |
| CreateAbortCallback(&fetch_event_callbacks_), base::nullopt); |
| } |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchNotificationClickEvent( |
| const String& notification_id, |
| mojom::blink::NotificationDataPtr notification_data, |
| int action_index, |
| const String& reply, |
| DispatchNotificationClickEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartNotificationClickEvent, |
| WrapWeakPersistent(this), notification_id, |
| std::move(notification_data), action_index, reply, |
| std::move(callback)), |
| CreateAbortCallback(¬ification_click_event_callbacks_), base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartNotificationClickEvent( |
| String notification_id, |
| mojom::blink::NotificationDataPtr notification_data, |
| int action_index, |
| String reply, |
| DispatchNotificationClickEventCallback callback, |
| int event_id) { |
| notification_click_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DispatchNotificationClickEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kNotificationClick, event_id); |
| NotificationEventInit* event_init = NotificationEventInit::Create(); |
| if (notification_data->actions.has_value() && 0 <= action_index && |
| action_index < static_cast<int>(notification_data->actions->size())) { |
| event_init->setAction((*notification_data->actions)[action_index]->action); |
| } |
| event_init->setNotification(Notification::Create( |
| this, notification_id, std::move(notification_data), true /* showing */)); |
| event_init->setReply(reply); |
| Event* event = NotificationEvent::Create(event_type_names::kNotificationclick, |
| event_init, observer); |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchNotificationCloseEvent( |
| const String& notification_id, |
| mojom::blink::NotificationDataPtr notification_data, |
| DispatchNotificationCloseEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartNotificationCloseEvent, |
| WrapWeakPersistent(this), notification_id, |
| std::move(notification_data), std::move(callback)), |
| CreateAbortCallback(¬ification_close_event_callbacks_), base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartNotificationCloseEvent( |
| String notification_id, |
| mojom::blink::NotificationDataPtr notification_data, |
| DispatchNotificationCloseEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| notification_close_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DispatchNotificationCloseEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kNotificationClose, event_id); |
| NotificationEventInit* event_init = NotificationEventInit::Create(); |
| event_init->setAction(WTF::String()); // initialize as null. |
| event_init->setNotification(Notification::Create(this, notification_id, |
| std::move(notification_data), |
| false /* showing */)); |
| Event* event = NotificationEvent::Create(event_type_names::kNotificationclose, |
| event_init, observer); |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchPushEvent( |
| const String& payload, |
| DispatchPushEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartPushEvent, |
| WrapWeakPersistent(this), std::move(payload), |
| std::move(callback)), |
| CreateAbortCallback(&push_event_callbacks_), |
| base::TimeDelta::FromSeconds(mojom::blink::kPushEventTimeoutSeconds)); |
| } |
| |
| void ServiceWorkerGlobalScope::StartPushEvent( |
| String payload, |
| DispatchPushEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| push_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DispatchPushEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kPush, event_id); |
| Event* event = PushEvent::Create(event_type_names::kPush, |
| PushMessageData::Create(payload), observer); |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchPushSubscriptionChangeEvent( |
| mojom::blink::PushSubscriptionPtr old_subscription, |
| mojom::blink::PushSubscriptionPtr new_subscription, |
| DispatchPushSubscriptionChangeEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartPushSubscriptionChangeEvent, |
| WrapWeakPersistent(this), std::move(old_subscription), |
| std::move(new_subscription), std::move(callback)), |
| CreateAbortCallback(&push_subscription_change_event_callbacks_), |
| base::TimeDelta::FromSeconds(mojom::blink::kPushEventTimeoutSeconds)); |
| } |
| |
| void ServiceWorkerGlobalScope::StartPushSubscriptionChangeEvent( |
| mojom::blink::PushSubscriptionPtr old_subscription, |
| mojom::blink::PushSubscriptionPtr new_subscription, |
| DispatchPushSubscriptionChangeEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| push_subscription_change_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", |
| "ServiceWorkerGlobalScope::DispatchPushSubscriptionChangeEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kPushSubscriptionChange, event_id); |
| Event* event = PushSubscriptionChangeEvent::Create( |
| event_type_names::kPushsubscriptionchange, nullptr /* new_subscription */, |
| nullptr /* old_subscription */, observer); |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchSyncEvent( |
| const String& tag, |
| bool last_chance, |
| base::TimeDelta timeout, |
| DispatchSyncEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartSyncEvent, |
| WrapWeakPersistent(this), std::move(tag), last_chance, |
| std::move(callback)), |
| CreateAbortCallback(&sync_event_callbacks_), timeout); |
| } |
| |
| void ServiceWorkerGlobalScope::StartSyncEvent( |
| String tag, |
| bool last_chance, |
| DispatchSyncEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| sync_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DispatchSyncEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kSync, event_id); |
| Event* event = |
| SyncEvent::Create(event_type_names::kSync, tag, last_chance, observer); |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchPeriodicSyncEvent( |
| const String& tag, |
| base::TimeDelta timeout, |
| DispatchPeriodicSyncEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartPeriodicSyncEvent, |
| WrapWeakPersistent(this), std::move(tag), std::move(callback)), |
| CreateAbortCallback(&periodic_sync_event_callbacks_), timeout); |
| } |
| |
| void ServiceWorkerGlobalScope::StartPeriodicSyncEvent( |
| String tag, |
| DispatchPeriodicSyncEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| periodic_sync_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DispatchPeriodicSyncEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kPeriodicSync, event_id); |
| Event* event = |
| PeriodicSyncEvent::Create(event_type_names::kPeriodicsync, tag, observer); |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchAbortPaymentEvent( |
| mojo::PendingRemote<payments::mojom::blink::PaymentHandlerResponseCallback> |
| response_callback, |
| DispatchAbortPaymentEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartAbortPaymentEvent, |
| WrapWeakPersistent(this), std::move(response_callback), |
| std::move(callback)), |
| CreateAbortCallback(&abort_payment_event_callbacks_), base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartAbortPaymentEvent( |
| mojo::PendingRemote<payments::mojom::blink::PaymentHandlerResponseCallback> |
| response_callback, |
| DispatchAbortPaymentEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| abort_payment_event_callbacks_.Set(event_id, std::move(callback)); |
| abort_payment_result_callbacks_.Set( |
| event_id, |
| mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback>( |
| std::move(response_callback))); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DispatchAbortPaymentEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* wait_until_observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kAbortPayment, event_id); |
| AbortPaymentRespondWithObserver* respond_with_observer = |
| MakeGarbageCollected<AbortPaymentRespondWithObserver>( |
| this, event_id, wait_until_observer); |
| |
| Event* event = AbortPaymentEvent::Create( |
| event_type_names::kAbortpayment, ExtendableEventInit::Create(), |
| respond_with_observer, wait_until_observer); |
| |
| DispatchExtendableEventWithRespondWith(event, wait_until_observer, |
| respond_with_observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchCanMakePaymentEvent( |
| payments::mojom::blink::CanMakePaymentEventDataPtr event_data, |
| mojo::PendingRemote<payments::mojom::blink::PaymentHandlerResponseCallback> |
| response_callback, |
| DispatchCanMakePaymentEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartCanMakePaymentEvent, |
| WrapWeakPersistent(this), std::move(event_data), |
| std::move(response_callback), std::move(callback)), |
| CreateAbortCallback(&can_make_payment_event_callbacks_), base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartCanMakePaymentEvent( |
| payments::mojom::blink::CanMakePaymentEventDataPtr event_data, |
| mojo::PendingRemote<payments::mojom::blink::PaymentHandlerResponseCallback> |
| response_callback, |
| DispatchCanMakePaymentEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| can_make_payment_event_callbacks_.Set(event_id, std::move(callback)); |
| can_make_payment_result_callbacks_.Set( |
| event_id, |
| mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback>( |
| std::move(response_callback))); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DispatchCanMakePaymentEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* wait_until_observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kCanMakePayment, event_id); |
| CanMakePaymentRespondWithObserver* respond_with_observer = |
| MakeGarbageCollected<CanMakePaymentRespondWithObserver>( |
| this, event_id, wait_until_observer); |
| |
| Event* event = CanMakePaymentEvent::Create( |
| event_type_names::kCanmakepayment, |
| PaymentEventDataConversion::ToCanMakePaymentEventInit( |
| ScriptController()->GetScriptState(), std::move(event_data)), |
| respond_with_observer, wait_until_observer); |
| |
| DispatchExtendableEventWithRespondWith(event, wait_until_observer, |
| respond_with_observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchPaymentRequestEvent( |
| payments::mojom::blink::PaymentRequestEventDataPtr event_data, |
| mojo::PendingRemote<payments::mojom::blink::PaymentHandlerResponseCallback> |
| response_callback, |
| DispatchPaymentRequestEventCallback callback) { |
| DCHECK(IsContextThread()); |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartPaymentRequestEvent, |
| WrapWeakPersistent(this), std::move(event_data), |
| std::move(response_callback), std::move(callback)), |
| CreateAbortCallback(&payment_request_event_callbacks_), base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartPaymentRequestEvent( |
| payments::mojom::blink::PaymentRequestEventDataPtr event_data, |
| mojo::PendingRemote<payments::mojom::blink::PaymentHandlerResponseCallback> |
| response_callback, |
| DispatchPaymentRequestEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| payment_request_event_callbacks_.Set(event_id, std::move(callback)); |
| payment_response_callbacks_.Set( |
| event_id, |
| mojo::Remote<payments::mojom::blink::PaymentHandlerResponseCallback>( |
| std::move(response_callback))); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DispatchPaymentRequestEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* wait_until_observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kPaymentRequest, event_id); |
| PaymentRequestRespondWithObserver* respond_with_observer = |
| PaymentRequestRespondWithObserver::Create(this, event_id, |
| wait_until_observer); |
| |
| // Update respond_with_observer to check for required information specified in |
| // the event_data during response validation. |
| if (event_data->payment_options) { |
| respond_with_observer->set_should_have_payer_name( |
| event_data->payment_options->request_payer_name); |
| respond_with_observer->set_should_have_payer_email( |
| event_data->payment_options->request_payer_email); |
| respond_with_observer->set_should_have_payer_phone( |
| event_data->payment_options->request_payer_phone); |
| respond_with_observer->set_should_have_shipping_info( |
| event_data->payment_options->request_shipping); |
| } |
| |
| mojo::PendingRemote<payments::mojom::blink::PaymentHandlerHost> |
| payment_handler_host = std::move(event_data->payment_handler_host); |
| Event* event = PaymentRequestEvent::Create( |
| event_type_names::kPaymentrequest, |
| PaymentEventDataConversion::ToPaymentRequestEventInit( |
| ScriptController()->GetScriptState(), std::move(event_data)), |
| std::move(payment_handler_host), respond_with_observer, |
| wait_until_observer); |
| |
| DispatchExtendableEventWithRespondWith(event, wait_until_observer, |
| respond_with_observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchCookieChangeEvent( |
| network::mojom::blink::CookieChangeInfoPtr change, |
| DispatchCookieChangeEventCallback callback) { |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartCookieChangeEvent, |
| WrapWeakPersistent(this), std::move(change), |
| std::move(callback)), |
| CreateAbortCallback(&cookie_change_event_callbacks_), base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartCookieChangeEvent( |
| network::mojom::blink::CookieChangeInfoPtr change, |
| DispatchCookieChangeEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| cookie_change_event_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DispatchCookieChangeEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kCookieChange, event_id); |
| |
| HeapVector<Member<CookieListItem>> changed; |
| HeapVector<Member<CookieListItem>> deleted; |
| CookieChangeEvent::ToEventInfo(change->cookie, change->cause, changed, |
| deleted); |
| Event* event = ExtendableCookieChangeEvent::Create( |
| event_type_names::kCookiechange, std::move(changed), std::move(deleted), |
| observer); |
| |
| // TODO(pwnall): Handle handle the case when |
| // (changed.IsEmpty() && deleted.IsEmpty()). |
| |
| // TODO(pwnall): Investigate dispatching this on cookieStore. |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::DispatchContentDeleteEvent( |
| const String& id, |
| DispatchContentDeleteEventCallback callback) { |
| event_queue_->EnqueueNormal( |
| WTF::Bind(&ServiceWorkerGlobalScope::StartContentDeleteEvent, |
| WrapWeakPersistent(this), id, std::move(callback)), |
| CreateAbortCallback(&content_delete_callbacks_), base::nullopt); |
| } |
| |
| void ServiceWorkerGlobalScope::StartContentDeleteEvent( |
| String id, |
| DispatchContentDeleteEventCallback callback, |
| int event_id) { |
| DCHECK(IsContextThread()); |
| content_delete_callbacks_.Set(event_id, std::move(callback)); |
| TRACE_EVENT_WITH_FLOW0( |
| "ServiceWorker", "ServiceWorkerGlobalScope::DispatchContentDeleteEvent", |
| TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope, |
| TRACE_ID_LOCAL(event_id)), |
| TRACE_EVENT_FLAG_FLOW_OUT); |
| |
| auto* observer = MakeGarbageCollected<WaitUntilObserver>( |
| this, WaitUntilObserver::kContentDelete, event_id); |
| |
| auto* init = ContentIndexEventInit::Create(); |
| init->setId(id); |
| |
| auto* event = MakeGarbageCollected<ContentIndexEvent>( |
| event_type_names::kContentdelete, init, observer); |
| |
| DispatchExtendableEvent(event, observer); |
| } |
| |
| void ServiceWorkerGlobalScope::Ping(PingCallback callback) { |
| DCHECK(IsContextThread()); |
| std::move(callback).Run(); |
| } |
| |
| void ServiceWorkerGlobalScope::SetIdleTimerDelayToZero() { |
| DCHECK(IsContextThread()); |
| DCHECK(event_queue_); |
| event_queue_->SetIdleTimerDelayToZero(); |
| } |
| |
| void ServiceWorkerGlobalScope::AddMessageToConsole( |
| mojom::blink::ConsoleMessageLevel level, |
| const String& message) { |
| AddConsoleMessage(ConsoleMessage::Create( |
| mojom::ConsoleMessageSource::kOther, level, message, |
| SourceLocation::Capture(/* url= */ "", /* line_number= */ 0, |
| /* column_number= */ 0))); |
| } |
| |
| void ServiceWorkerGlobalScope::NoteNewFetchEvent(const KURL& request_url) { |
| auto it = unresponded_fetch_event_counts_.find(request_url); |
| if (it == unresponded_fetch_event_counts_.end()) { |
| unresponded_fetch_event_counts_.insert(request_url, 1); |
| } else { |
| it->value += 1; |
| } |
| } |
| |
| void ServiceWorkerGlobalScope::NoteRespondedToFetchEvent( |
| const KURL& request_url) { |
| auto it = unresponded_fetch_event_counts_.find(request_url); |
| DCHECK_GE(it->value, 1); |
| it->value -= 1; |
| if (it->value == 0) |
| unresponded_fetch_event_counts_.erase(it); |
| } |
| |
| } // namespace blink |