blob: f98915ffd22c38cca63e8e2a1c4eeea588c77ecd [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/service_worker/service_worker_context_client.h"
#include <map>
#include <memory>
#include <utility>
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_checker.h"
#include "base/threading/thread_local.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "content/child/background_sync/background_sync_type_converters.h"
#include "content/child/notifications/notification_data_conversions.h"
#include "content/child/request_extra_data.h"
#include "content/child/service_worker/service_worker_dispatcher.h"
#include "content/child/service_worker/service_worker_handle_reference.h"
#include "content/child/service_worker/service_worker_network_provider.h"
#include "content/child/service_worker/service_worker_provider_context.h"
#include "content/child/service_worker/service_worker_registration_handle_reference.h"
#include "content/child/service_worker/web_service_worker_impl.h"
#include "content/child/service_worker/web_service_worker_provider_impl.h"
#include "content/child/service_worker/web_service_worker_registration_impl.h"
#include "content/child/thread_safe_sender.h"
#include "content/child/web_data_consumer_handle_impl.h"
#include "content/child/web_url_loader_impl.h"
#include "content/child/webmessageportchannel_impl.h"
#include "content/common/devtools_messages.h"
#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/service_worker_event_dispatcher.mojom.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "content/common/worker_url_loader_factory_provider.mojom.h"
#include "content/public/common/content_features.h"
#include "content/public/common/push_event_payload.h"
#include "content/public/common/referrer.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/public/renderer/document_state.h"
#include "content/renderer/devtools/devtools_agent.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/renderer_blink_platform_impl.h"
#include "content/renderer/service_worker/embedded_worker_devtools_agent.h"
#include "content/renderer/service_worker/embedded_worker_instance_client_impl.h"
#include "content/renderer/service_worker/service_worker_fetch_context_impl.h"
#include "content/renderer/service_worker/service_worker_type_converters.h"
#include "content/renderer/service_worker/service_worker_type_util.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
#include "third_party/WebKit/public/platform/InterfaceProvider.h"
#include "third_party/WebKit/public/platform/URLConversion.h"
#include "third_party/WebKit/public/platform/WebMessagePortChannel.h"
#include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/platform/modules/background_fetch/WebBackgroundFetchSettledFetch.h"
#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationData.h"
#include "third_party/WebKit/public/platform/modules/payments/WebPaymentAppRequest.h"
#include "third_party/WebKit/public/platform/modules/payments/WebPaymentAppResponse.h"
#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerClientQueryOptions.h"
#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h"
#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerNetworkProvider.h"
#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRequest.h"
#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerResponse.h"
#include "third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h"
#include "third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h"
namespace content {
namespace {
// For now client must be a per-thread instance.
base::LazyInstance<base::ThreadLocalPointer<ServiceWorkerContextClient>>::
Leaky g_worker_client_tls = LAZY_INSTANCE_INITIALIZER;
// Called on the main thread only and blink owns it.
class WebServiceWorkerNetworkProviderImpl
: public blink::WebServiceWorkerNetworkProvider {
public:
explicit WebServiceWorkerNetworkProviderImpl(
std::unique_ptr<ServiceWorkerNetworkProvider> provider)
: provider_(std::move(provider)) {}
// Blink calls this method for each request starting with the main script,
// we tag them with the provider id.
void WillSendRequest(blink::WebURLRequest& request) override {
std::unique_ptr<RequestExtraData> extra_data(new RequestExtraData);
extra_data->set_service_worker_provider_id(provider_->provider_id());
extra_data->set_originated_from_service_worker(true);
// Service workers are only available in secure contexts, so all requests
// are initiated in a secure context.
extra_data->set_initiated_in_secure_context(true);
request.SetExtraData(extra_data.release());
}
private:
std::unique_ptr<ServiceWorkerNetworkProvider> provider_;
};
class StreamHandleListener
: public blink::WebServiceWorkerStreamHandle::Listener {
public:
StreamHandleListener(
blink::mojom::ServiceWorkerStreamCallbackPtr callback_ptr)
: callback_ptr_(std::move(callback_ptr)) {}
~StreamHandleListener() override {}
void OnAborted() override { callback_ptr_->OnAborted(); }
void OnCompleted() override { callback_ptr_->OnCompleted(); }
private:
blink::mojom::ServiceWorkerStreamCallbackPtr callback_ptr_;
};
ServiceWorkerStatusCode EventResultToStatus(
blink::WebServiceWorkerEventResult result) {
switch (result) {
case blink::kWebServiceWorkerEventResultCompleted:
return SERVICE_WORKER_OK;
case blink::kWebServiceWorkerEventResultRejected:
return SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED;
}
NOTREACHED() << "Got invalid result: " << result;
return SERVICE_WORKER_ERROR_FAILED;
}
blink::WebURLRequest::FetchRequestMode GetBlinkFetchRequestMode(
FetchRequestMode mode) {
return static_cast<blink::WebURLRequest::FetchRequestMode>(mode);
}
blink::WebURLRequest::FetchCredentialsMode GetBlinkFetchCredentialsMode(
FetchCredentialsMode credentials_mode) {
return static_cast<blink::WebURLRequest::FetchCredentialsMode>(
credentials_mode);
}
blink::WebURLRequest::FetchRedirectMode GetBlinkFetchRedirectMode(
FetchRedirectMode redirect_mode) {
return static_cast<blink::WebURLRequest::FetchRedirectMode>(redirect_mode);
}
blink::WebURLRequest::RequestContext GetBlinkRequestContext(
RequestContextType request_context_type) {
return static_cast<blink::WebURLRequest::RequestContext>(
request_context_type);
}
blink::WebURLRequest::FrameType GetBlinkFrameType(
RequestContextFrameType frame_type) {
return static_cast<blink::WebURLRequest::FrameType>(frame_type);
}
blink::WebServiceWorkerClientInfo
ToWebServiceWorkerClientInfo(const ServiceWorkerClientInfo& client_info) {
DCHECK(client_info.IsValid());
blink::WebServiceWorkerClientInfo web_client_info;
web_client_info.uuid = blink::WebString::FromASCII(client_info.client_uuid);
web_client_info.page_visibility_state = client_info.page_visibility_state;
web_client_info.is_focused = client_info.is_focused;
web_client_info.url = client_info.url;
web_client_info.frame_type = GetBlinkFrameType(client_info.frame_type);
web_client_info.client_type = client_info.client_type;
return web_client_info;
}
// Converts the |request| to its equivalent type in the Blink API.
// TODO(peter): Remove this when the Mojo FetchAPIRequest type exists.
void ToWebServiceWorkerRequest(const ServiceWorkerFetchRequest& request,
blink::WebServiceWorkerRequest* web_request) {
DCHECK(web_request);
web_request->SetURL(blink::WebURL(request.url));
web_request->SetMethod(blink::WebString::FromUTF8(request.method));
for (const auto& pair : request.headers) {
web_request->SetHeader(blink::WebString::FromUTF8(pair.first),
blink::WebString::FromUTF8(pair.second));
}
if (!request.blob_uuid.empty()) {
web_request->SetBlob(blink::WebString::FromASCII(request.blob_uuid),
request.blob_size);
}
web_request->SetReferrer(
blink::WebString::FromUTF8(request.referrer.url.spec()),
request.referrer.policy);
web_request->SetMode(GetBlinkFetchRequestMode(request.mode));
web_request->SetIsMainResourceLoad(request.is_main_resource_load);
web_request->SetCredentialsMode(
GetBlinkFetchCredentialsMode(request.credentials_mode));
web_request->SetRedirectMode(
GetBlinkFetchRedirectMode(request.redirect_mode));
web_request->SetRequestContext(
GetBlinkRequestContext(request.request_context_type));
web_request->SetFrameType(GetBlinkFrameType(request.frame_type));
web_request->SetClientId(blink::WebString::FromUTF8(request.client_id));
web_request->SetIsReload(request.is_reload);
}
// Converts |response| to its equivalent type in the Blink API.
// TODO(peter): Remove this when the Mojo FetchAPIResponse type exists.
void ToWebServiceWorkerResponse(const ServiceWorkerResponse& response,
blink::WebServiceWorkerResponse* web_response) {
DCHECK(web_response);
std::vector<blink::WebURL> url_list;
for (const GURL& url : response.url_list)
url_list.push_back(blink::WebURL(url));
web_response->SetURLList(blink::WebVector<blink::WebURL>(url_list));
web_response->SetStatus(static_cast<unsigned short>(response.status_code));
web_response->SetStatusText(blink::WebString::FromUTF8(response.status_text));
web_response->SetResponseType(response.response_type);
for (const auto& pair : response.headers) {
web_response->SetHeader(blink::WebString::FromUTF8(pair.first),
blink::WebString::FromUTF8(pair.second));
}
if (!response.blob_uuid.empty()) {
web_response->SetBlob(blink::WebString::FromASCII(response.blob_uuid),
response.blob_size);
}
web_response->SetError(response.error);
web_response->SetResponseTime(response.response_time.ToInternalValue());
if (response.is_in_cache_storage) {
web_response->SetCacheStorageCacheName(
blink::WebString::FromUTF8(response.cache_storage_cache_name));
}
std::vector<blink::WebString> cors_exposed_header_names;
for (const auto& name : response.cors_exposed_header_names)
cors_exposed_header_names.push_back(blink::WebString::FromUTF8(name));
web_response->SetCorsExposedHeaderNames(
blink::WebVector<blink::WebString>(cors_exposed_header_names));
}
// Use this template in willDestroyWorkerContext to abort all the pending
// events callbacks.
template <typename T, class... TArgs>
void AbortPendingEventCallbacks(T& callbacks, TArgs... args) {
for (typename T::iterator it(&callbacks); !it.IsAtEnd(); it.Advance()) {
std::move(*it.GetCurrentValue())
.Run(SERVICE_WORKER_ERROR_ABORT, args..., base::Time::Now());
}
}
template <typename Key, typename Callback>
void AbortPendingEventCallbacks(std::map<Key, Callback>& callbacks) {
for (auto& item : callbacks)
std::move(item.second).Run(SERVICE_WORKER_ERROR_ABORT, base::Time::Now());
}
} // namespace
// Holding data that needs to be bound to the worker context on the
// worker thread.
struct ServiceWorkerContextClient::WorkerContextData {
using SimpleEventCallback =
base::OnceCallback<void(ServiceWorkerStatusCode, base::Time)>;
using ClientsCallbacksMap =
IDMap<std::unique_ptr<blink::WebServiceWorkerClientsCallbacks>>;
using ClaimClientsCallbacksMap =
IDMap<std::unique_ptr<blink::WebServiceWorkerClientsClaimCallbacks>>;
using ClientCallbacksMap =
IDMap<std::unique_ptr<blink::WebServiceWorkerClientCallbacks>>;
using SkipWaitingCallbacksMap =
IDMap<std::unique_ptr<blink::WebServiceWorkerSkipWaitingCallbacks>>;
using InstallEventCallbacksMap =
IDMap<std::unique_ptr<DispatchInstallEventCallback>>;
using ActivateEventCallbacksMap =
IDMap<std::unique_ptr<DispatchActivateEventCallback>>;
using BackgroundFetchAbortEventCallbacksMap =
IDMap<std::unique_ptr<DispatchBackgroundFetchAbortEventCallback>>;
using BackgroundFetchClickEventCallbacksMap =
IDMap<std::unique_ptr<DispatchBackgroundFetchClickEventCallback>>;
using BackgroundFetchFailEventCallbacksMap =
IDMap<std::unique_ptr<DispatchBackgroundFetchFailEventCallback>>;
using BackgroundFetchedEventCallbacksMap =
IDMap<std::unique_ptr<DispatchBackgroundFetchedEventCallback>>;
using SyncEventCallbacksMap = IDMap<std::unique_ptr<SyncCallback>>;
using NotificationClickEventCallbacksMap =
IDMap<std::unique_ptr<DispatchNotificationClickEventCallback>>;
using NotificationCloseEventCallbacksMap =
IDMap<std::unique_ptr<DispatchNotificationCloseEventCallback>>;
using PushEventCallbacksMap =
IDMap<std::unique_ptr<DispatchPushEventCallback>>;
using ExtendableMessageEventCallbacksMap =
IDMap<std::unique_ptr<DispatchExtendableMessageEventCallback>>;
using NavigationPreloadRequestsMap = IDMap<
std::unique_ptr<ServiceWorkerContextClient::NavigationPreloadRequest>>;
using InstallEventMethodsMap =
std::map<int, mojom::ServiceWorkerInstallEventMethodsAssociatedPtr>;
explicit WorkerContextData(ServiceWorkerContextClient* owner)
: event_dispatcher_binding(owner),
weak_factory(owner),
proxy_weak_factory(owner->proxy_) {}
~WorkerContextData() {
DCHECK(thread_checker.CalledOnValidThread());
}
mojo::Binding<mojom::ServiceWorkerEventDispatcher> event_dispatcher_binding;
// Pending callbacks for GetClientDocuments().
ClientsCallbacksMap clients_callbacks;
// Pending callbacks for OpenWindow() and FocusClient().
ClientCallbacksMap client_callbacks;
// Pending callbacks for SkipWaiting().
SkipWaitingCallbacksMap skip_waiting_callbacks;
// Pending callbacks for ClaimClients().
ClaimClientsCallbacksMap claim_clients_callbacks;
// Pending callbacks for Install Events.
InstallEventCallbacksMap install_event_callbacks;
// Pending callbacks for Activate Events.
ActivateEventCallbacksMap activate_event_callbacks;
// Pending callbacks for Background Fetch Abort Events.
BackgroundFetchAbortEventCallbacksMap background_fetch_abort_event_callbacks;
// Pending callbacks for Background Fetch Click Events.
BackgroundFetchClickEventCallbacksMap background_fetch_click_event_callbacks;
// Pending callbacks for Background Fetch Fail Events.
BackgroundFetchFailEventCallbacksMap background_fetch_fail_event_callbacks;
// Pending callbacks for Background Fetched Events.
BackgroundFetchedEventCallbacksMap background_fetched_event_callbacks;
// Pending callbacks for Background Sync Events.
SyncEventCallbacksMap sync_event_callbacks;
// Pending callbacks for Payment App Response.
std::map<int /* payment_request_id */,
payments::mojom::PaymentAppResponseCallbackPtr>
payment_response_callbacks;
// Pending callbacks for Payment Request Events.
std::map<int /* payment_request_id */, DispatchPaymentRequestEventCallback>
payment_request_event_callbacks;
// Pending callbacks for Notification Click Events.
NotificationClickEventCallbacksMap notification_click_event_callbacks;
// Pending callbacks for Notification Close Events.
NotificationCloseEventCallbacksMap notification_close_event_callbacks;
// Pending callbacks for Push Events.
PushEventCallbacksMap push_event_callbacks;
// Pending callbacks for Fetch Events.
std::map<int /* fetch_event_id */, SimpleEventCallback> fetch_event_callbacks;
// Pending callbacks for respondWith on each fetch event.
std::map<int /* fetch_event_id */,
mojom::ServiceWorkerFetchResponseCallbackPtr>
fetch_response_callbacks;
// Pending callbacks for Extendable Message Events.
ExtendableMessageEventCallbacksMap message_event_callbacks;
// Pending navigation preload requests.
NavigationPreloadRequestsMap preload_requests;
// Maps every install event id with its corresponding
// mojom::ServiceWorkerInstallEventMethodsAssociatedPt.
InstallEventMethodsMap install_methods_map;
base::ThreadChecker thread_checker;
base::WeakPtrFactory<ServiceWorkerContextClient> weak_factory;
base::WeakPtrFactory<blink::WebServiceWorkerContextProxy> proxy_weak_factory;
};
class ServiceWorkerContextClient::NavigationPreloadRequest final
: public mojom::URLLoaderClient {
public:
NavigationPreloadRequest(int fetch_event_id,
const GURL& url,
mojom::FetchEventPreloadHandlePtr preload_handle)
: fetch_event_id_(fetch_event_id),
url_(url),
url_loader_(std::move(preload_handle->url_loader)),
binding_(this, std::move(preload_handle->url_loader_client_request)) {}
~NavigationPreloadRequest() override {}
void OnReceiveResponse(
const ResourceResponseHead& response_head,
const base::Optional<net::SSLInfo>& ssl_info,
mojom::DownloadedTempFilePtr downloaded_file) override {
DCHECK(!response_);
DCHECK(!downloaded_file);
response_ = base::MakeUnique<blink::WebURLResponse>();
// TODO(horo): Set report_security_info to true when DevTools is attached.
const bool report_security_info = false;
WebURLLoaderImpl::PopulateURLResponse(url_, response_head, response_.get(),
report_security_info);
MaybeReportResponseToClient();
}
void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
const ResourceResponseHead& response_head) override {
DCHECK(!response_);
DCHECK(net::HttpResponseHeaders::IsRedirectResponseCode(
response_head.headers->response_code()));
ServiceWorkerContextClient* client =
ServiceWorkerContextClient::ThreadSpecificInstance();
if (!client)
return;
response_ = base::MakeUnique<blink::WebURLResponse>();
WebURLLoaderImpl::PopulateURLResponse(url_, response_head, response_.get(),
false /* report_security_info */);
client->OnNavigationPreloadResponse(fetch_event_id_, std::move(response_),
nullptr);
// This will delete |this|.
client->OnNavigationPreloadComplete(
fetch_event_id_, response_head.response_start,
response_head.encoded_data_length, 0 /* encoded_body_length */,
0 /* decoded_body_length */);
}
void OnDataDownloaded(int64_t data_length,
int64_t encoded_data_length) override {
NOTREACHED();
}
void OnUploadProgress(int64_t current_position,
int64_t total_size,
OnUploadProgressCallback ack_callback) override {
NOTREACHED();
}
void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override {}
void OnTransferSizeUpdated(int32_t transfer_size_diff) override {
}
void OnStartLoadingResponseBody(
mojo::ScopedDataPipeConsumerHandle body) override {
DCHECK(!body_.is_valid());
body_ = std::move(body);
MaybeReportResponseToClient();
}
void OnComplete(const ResourceRequestCompletionStatus& status) override {
if (status.error_code != net::OK) {
std::string message;
std::string unsanitized_message;
if (status.error_code == net::ERR_ABORTED) {
message =
"The service worker navigation preload request was cancelled "
"before 'preloadResponse' settled. If you intend to use "
"'preloadResponse', use waitUntil() or respondWith() to wait for "
"the promise to settle.";
} else {
message =
"The service worker navigation preload request failed with a "
"network error.";
unsanitized_message =
"The service worker navigation preload request failed with network "
"error: " +
net::ErrorToString(status.error_code) + ".";
}
// This will delete |this|.
ReportErrorToClient(message, unsanitized_message);
return;
}
ServiceWorkerContextClient* client =
ServiceWorkerContextClient::ThreadSpecificInstance();
if (!client)
return;
if (response_) {
// When the response body from the server is empty, OnComplete() is called
// without OnStartLoadingResponseBody().
DCHECK(!body_.is_valid());
client->OnNavigationPreloadResponse(fetch_event_id_, std::move(response_),
nullptr);
}
// This will delete |this|.
client->OnNavigationPreloadComplete(
fetch_event_id_, status.completion_time, status.encoded_data_length,
status.encoded_body_length, status.decoded_body_length);
}
private:
void MaybeReportResponseToClient() {
if (!response_ || !body_.is_valid())
return;
ServiceWorkerContextClient* client =
ServiceWorkerContextClient::ThreadSpecificInstance();
if (!client)
return;
client->OnNavigationPreloadResponse(
fetch_event_id_, std::move(response_),
base::MakeUnique<WebDataConsumerHandleImpl>(std::move(body_)));
}
void ReportErrorToClient(const std::string& message,
const std::string& unsanitized_message) {
ServiceWorkerContextClient* client =
ServiceWorkerContextClient::ThreadSpecificInstance();
if (!client)
return;
// This will delete |this|.
client->OnNavigationPreloadError(
fetch_event_id_, base::MakeUnique<blink::WebServiceWorkerError>(
blink::WebServiceWorkerError::kErrorTypeNetwork,
blink::WebString::FromUTF8(message),
blink::WebString::FromUTF8(unsanitized_message)));
}
const int fetch_event_id_;
const GURL url_;
mojom::URLLoaderPtr url_loader_;
mojo::Binding<mojom::URLLoaderClient> binding_;
std::unique_ptr<blink::WebURLResponse> response_;
mojo::ScopedDataPipeConsumerHandle body_;
};
ServiceWorkerContextClient*
ServiceWorkerContextClient::ThreadSpecificInstance() {
return g_worker_client_tls.Pointer()->Get();
}
ServiceWorkerContextClient::ServiceWorkerContextClient(
int embedded_worker_id,
int64_t service_worker_version_id,
const GURL& service_worker_scope,
const GURL& script_url,
mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
std::unique_ptr<EmbeddedWorkerInstanceClientImpl> embedded_worker_client)
: embedded_worker_id_(embedded_worker_id),
service_worker_version_id_(service_worker_version_id),
service_worker_scope_(service_worker_scope),
script_url_(script_url),
sender_(ChildThreadImpl::current()->thread_safe_sender()),
main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
proxy_(nullptr),
pending_dispatcher_request_(std::move(dispatcher_request)),
embedded_worker_client_(std::move(embedded_worker_client)) {
instance_host_ =
mojom::ThreadSafeEmbeddedWorkerInstanceHostAssociatedPtr::Create(
std::move(instance_host), main_thread_task_runner_);
TRACE_EVENT_ASYNC_BEGIN0("ServiceWorker",
"ServiceWorkerContextClient::StartingWorkerContext",
this);
TRACE_EVENT_ASYNC_STEP_INTO0(
"ServiceWorker",
"ServiceWorkerContextClient::StartingWorkerContext",
this,
"PrepareWorker");
}
ServiceWorkerContextClient::~ServiceWorkerContextClient() {}
void ServiceWorkerContextClient::OnMessageReceived(
int thread_id,
int embedded_worker_id,
const IPC::Message& message) {
CHECK_EQ(embedded_worker_id_, embedded_worker_id);
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ServiceWorkerContextClient, message)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetClient, OnDidGetClient)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetClients, OnDidGetClients)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_OpenWindowResponse,
OnOpenWindowResponse)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_OpenWindowError,
OnOpenWindowError)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FocusClientResponse,
OnFocusClientResponse)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_NavigateClientResponse,
OnNavigateClientResponse)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_NavigateClientError,
OnNavigateClientError)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidSkipWaiting, OnDidSkipWaiting)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidClaimClients, OnDidClaimClients)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ClaimClientsError, OnClaimClientsError)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
DCHECK(handled);
}
blink::WebURL ServiceWorkerContextClient::Scope() const {
return service_worker_scope_;
}
void ServiceWorkerContextClient::GetClient(
const blink::WebString& id,
std::unique_ptr<blink::WebServiceWorkerClientCallbacks> callbacks) {
DCHECK(callbacks);
int request_id = context_->client_callbacks.Add(std::move(callbacks));
Send(new ServiceWorkerHostMsg_GetClient(GetRoutingID(), request_id,
id.Utf8()));
}
void ServiceWorkerContextClient::GetClients(
const blink::WebServiceWorkerClientQueryOptions& weboptions,
std::unique_ptr<blink::WebServiceWorkerClientsCallbacks> callbacks) {
DCHECK(callbacks);
int request_id = context_->clients_callbacks.Add(std::move(callbacks));
ServiceWorkerClientQueryOptions options;
options.client_type = weboptions.client_type;
options.include_uncontrolled = weboptions.include_uncontrolled;
Send(new ServiceWorkerHostMsg_GetClients(
GetRoutingID(), request_id, options));
}
void ServiceWorkerContextClient::OpenWindow(
const blink::WebURL& url,
std::unique_ptr<blink::WebServiceWorkerClientCallbacks> callbacks) {
DCHECK(callbacks);
int request_id = context_->client_callbacks.Add(std::move(callbacks));
Send(new ServiceWorkerHostMsg_OpenWindow(
GetRoutingID(), request_id, url));
}
void ServiceWorkerContextClient::SetCachedMetadata(const blink::WebURL& url,
const char* data,
size_t size) {
std::vector<char> copy(data, data + size);
Send(new ServiceWorkerHostMsg_SetCachedMetadata(GetRoutingID(), url, copy));
}
void ServiceWorkerContextClient::ClearCachedMetadata(const blink::WebURL& url) {
Send(new ServiceWorkerHostMsg_ClearCachedMetadata(GetRoutingID(), url));
}
void ServiceWorkerContextClient::WorkerReadyForInspection() {
DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
(*instance_host_)->OnReadyForInspection();
}
void ServiceWorkerContextClient::WorkerContextFailedToStart() {
DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
DCHECK(!proxy_);
(*instance_host_)->OnScriptLoadFailed();
(*instance_host_)->OnStopped();
DCHECK(embedded_worker_client_);
embedded_worker_client_->WorkerContextDestroyed();
}
void ServiceWorkerContextClient::WorkerScriptLoaded() {
DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
DCHECK(!proxy_);
(*instance_host_)->OnScriptLoaded();
}
bool ServiceWorkerContextClient::HasAssociatedRegistration() {
return provider_context_ && provider_context_->HasAssociatedRegistration();
}
void ServiceWorkerContextClient::WorkerContextStarted(
blink::WebServiceWorkerContextProxy* proxy) {
DCHECK(!worker_task_runner_.get());
DCHECK_NE(0, WorkerThread::GetCurrentId());
worker_task_runner_ = base::ThreadTaskRunnerHandle::Get();
// g_worker_client_tls.Pointer()->Get() could return NULL if this context
// gets deleted before workerContextStarted() is called.
DCHECK(g_worker_client_tls.Pointer()->Get() == NULL);
DCHECK(!proxy_);
g_worker_client_tls.Pointer()->Set(this);
proxy_ = proxy;
// Initialize pending callback maps. This needs to be freed on the
// same thread before the worker context goes away in
// willDestroyWorkerContext.
context_.reset(new WorkerContextData(this));
ServiceWorkerRegistrationObjectInfo registration_info;
ServiceWorkerVersionAttributes version_attrs;
provider_context_->GetAssociatedRegistration(&registration_info,
&version_attrs);
DCHECK_NE(registration_info.registration_id,
kInvalidServiceWorkerRegistrationId);
DCHECK(pending_dispatcher_request_.is_pending());
DCHECK(!context_->event_dispatcher_binding.is_bound());
context_->event_dispatcher_binding.Bind(
std::move(pending_dispatcher_request_));
SetRegistrationInServiceWorkerGlobalScope(registration_info, version_attrs);
(*instance_host_)
->OnThreadStarted(WorkerThread::GetCurrentId(),
provider_context_->provider_id());
TRACE_EVENT_ASYNC_STEP_INTO0(
"ServiceWorker",
"ServiceWorkerContextClient::StartingWorkerContext",
this,
"ExecuteScript");
}
void ServiceWorkerContextClient::DidEvaluateWorkerScript(bool success) {
DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
(*instance_host_)->OnScriptEvaluated(success);
// Schedule a task to send back WorkerStarted asynchronously,
// so that at the time we send it we can be sure that the
// worker run loop has been started.
worker_task_runner_->PostTask(
FROM_HERE, base::Bind(&ServiceWorkerContextClient::SendWorkerStarted,
GetWeakPtr()));
}
void ServiceWorkerContextClient::DidInitializeWorkerContext(
v8::Local<v8::Context> context) {
GetContentClient()
->renderer()
->DidInitializeServiceWorkerContextOnWorkerThread(
context, service_worker_version_id_, script_url_);
}
void ServiceWorkerContextClient::WillDestroyWorkerContext(
v8::Local<v8::Context> context) {
// At this point WillStopCurrentWorkerThread is already called, so
// worker_task_runner_->RunsTasksInCurrentSequence() returns false
// (while we're still on the worker thread).
proxy_ = NULL;
// Aborts all the pending events callbacks.
AbortPendingEventCallbacks(context_->install_event_callbacks,
false /* has_fetch_handler */);
AbortPendingEventCallbacks(context_->activate_event_callbacks);
AbortPendingEventCallbacks(context_->background_fetch_abort_event_callbacks);
AbortPendingEventCallbacks(context_->background_fetch_click_event_callbacks);
AbortPendingEventCallbacks(context_->background_fetch_fail_event_callbacks);
AbortPendingEventCallbacks(context_->background_fetched_event_callbacks);
AbortPendingEventCallbacks(context_->sync_event_callbacks);
AbortPendingEventCallbacks(context_->notification_click_event_callbacks);
AbortPendingEventCallbacks(context_->notification_close_event_callbacks);
AbortPendingEventCallbacks(context_->push_event_callbacks);
AbortPendingEventCallbacks(context_->fetch_event_callbacks);
AbortPendingEventCallbacks(context_->message_event_callbacks);
// We have to clear callbacks now, as they need to be freed on the
// same thread.
context_.reset();
// This also lets the message filter stop dispatching messages to
// this client.
g_worker_client_tls.Pointer()->Set(NULL);
GetContentClient()->renderer()->WillDestroyServiceWorkerContextOnWorkerThread(
context, service_worker_version_id_, script_url_);
}
void ServiceWorkerContextClient::WorkerContextDestroyed() {
DCHECK(g_worker_client_tls.Pointer()->Get() == NULL);
// TODO(shimazu): The signals to the browser should be in the order:
// (1) WorkerStopped (via mojo call EmbeddedWorkerInstanceHost.OnStopped())
// (2) ProviderDestroyed (via mojo call
// ServiceWorkerDispatcherHost.OnProviderDestroyed()), this is triggered by
// the following EmbeddedWorkerInstanceClientImpl::WorkerContextDestroyed(),
// which will eventually lead to destruction of the service worker provider.
// But currently EmbeddedWorkerInstanceHost interface is associated with
// EmbeddedWorkerInstanceClient interface, and ServiceWorkerDispatcherHost
// interface is associated with the IPC channel, since they are using
// different mojo message pipes, the FIFO ordering can not be guaranteed now.
// This will be solved once ServiceWorkerProvider{Host,Client} are mojoified
// and they are also associated with EmbeddedWorkerInstanceClient in other CLs
// (https://crrev.com/2653493009 and https://crrev.com/2779763004).
(*instance_host_)->OnStopped();
DCHECK(embedded_worker_client_);
main_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&EmbeddedWorkerInstanceClientImpl::WorkerContextDestroyed,
base::Passed(&embedded_worker_client_)));
return;
}
void ServiceWorkerContextClient::CountFeature(uint32_t feature) {
Send(new EmbeddedWorkerHostMsg_CountFeature(service_worker_version_id_,
feature));
}
void ServiceWorkerContextClient::ReportException(
const blink::WebString& error_message,
int line_number,
int column_number,
const blink::WebString& source_url) {
(*instance_host_)
->OnReportException(error_message.Utf16(), line_number, column_number,
blink::WebStringToGURL(source_url));
}
void ServiceWorkerContextClient::ReportConsoleMessage(
int source,
int level,
const blink::WebString& message,
int line_number,
const blink::WebString& source_url) {
(*instance_host_)
->OnReportConsoleMessage(source, level, message.Utf16(), line_number,
blink::WebStringToGURL(source_url));
}
void ServiceWorkerContextClient::SendDevToolsMessage(
int session_id,
int call_id,
const blink::WebString& message,
const blink::WebString& state_cookie) {
// Return if this context has been stopped.
if (!embedded_worker_client_)
return;
embedded_worker_client_->devtools_agent()->SendMessage(
sender_.get(), session_id, call_id, message.Utf8(), state_cookie.Utf8());
}
blink::WebDevToolsAgentClient::WebKitClientMessageLoop*
ServiceWorkerContextClient::CreateDevToolsMessageLoop() {
return DevToolsAgent::createMessageLoopWrapper();
}
void ServiceWorkerContextClient::DidHandleActivateEvent(
int request_id,
blink::WebServiceWorkerEventResult result,
double event_dispatch_time) {
DispatchActivateEventCallback* callback =
context_->activate_event_callbacks.Lookup(request_id);
DCHECK(callback);
DCHECK(*callback);
std::move(*callback).Run(EventResultToStatus(result),
base::Time::FromDoubleT(event_dispatch_time));
context_->activate_event_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::DidHandleBackgroundFetchAbortEvent(
int request_id,
blink::WebServiceWorkerEventResult result,
double event_dispatch_time) {
DispatchBackgroundFetchAbortEventCallback* callback =
context_->background_fetch_abort_event_callbacks.Lookup(request_id);
DCHECK(callback);
DCHECK(*callback);
std::move(*callback).Run(EventResultToStatus(result),
base::Time::FromDoubleT(event_dispatch_time));
context_->background_fetch_abort_event_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::DidHandleBackgroundFetchClickEvent(
int request_id,
blink::WebServiceWorkerEventResult result,
double event_dispatch_time) {
DispatchBackgroundFetchClickEventCallback* callback =
context_->background_fetch_click_event_callbacks.Lookup(request_id);
DCHECK(callback);
DCHECK(*callback);
std::move(*callback).Run(EventResultToStatus(result),
base::Time::FromDoubleT(event_dispatch_time));
context_->background_fetch_click_event_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::DidHandleBackgroundFetchFailEvent(
int request_id,
blink::WebServiceWorkerEventResult result,
double event_dispatch_time) {
DispatchBackgroundFetchFailEventCallback* callback =
context_->background_fetch_fail_event_callbacks.Lookup(request_id);
DCHECK(callback);
DCHECK(*callback);
std::move(*callback).Run(EventResultToStatus(result),
base::Time::FromDoubleT(event_dispatch_time));
context_->background_fetch_fail_event_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::DidHandleBackgroundFetchedEvent(
int request_id,
blink::WebServiceWorkerEventResult result,
double event_dispatch_time) {
DispatchBackgroundFetchedEventCallback* callback =
context_->background_fetched_event_callbacks.Lookup(request_id);
DCHECK(callback);
DCHECK(*callback);
std::move(*callback).Run(EventResultToStatus(result),
base::Time::FromDoubleT(event_dispatch_time));
context_->background_fetched_event_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::DidHandleExtendableMessageEvent(
int request_id,
blink::WebServiceWorkerEventResult result,
double event_dispatch_time) {
DispatchExtendableMessageEventCallback* callback =
context_->message_event_callbacks.Lookup(request_id);
DCHECK(callback);
DCHECK(*callback);
std::move(*callback).Run(EventResultToStatus(result),
base::Time::FromDoubleT(event_dispatch_time));
context_->message_event_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::DidHandleInstallEvent(
int event_id,
blink::WebServiceWorkerEventResult result,
double event_dispatch_time) {
DispatchInstallEventCallback* callback =
context_->install_event_callbacks.Lookup(event_id);
DCHECK(callback);
DCHECK(*callback);
std::move(*callback).Run(EventResultToStatus(result),
proxy_->HasFetchEventHandler(),
base::Time::FromDoubleT(event_dispatch_time));
context_->install_event_callbacks.Remove(event_id);
context_->install_methods_map.erase(event_id);
}
void ServiceWorkerContextClient::RespondToFetchEventWithNoResponse(
int fetch_event_id,
double event_dispatch_time) {
const mojom::ServiceWorkerFetchResponseCallbackPtr& response_callback =
context_->fetch_response_callbacks[fetch_event_id];
DCHECK(response_callback.is_bound());
response_callback->OnFallback(base::Time::FromDoubleT(event_dispatch_time));
context_->fetch_response_callbacks.erase(fetch_event_id);
}
void ServiceWorkerContextClient::RespondToFetchEvent(
int fetch_event_id,
const blink::WebServiceWorkerResponse& web_response,
double event_dispatch_time) {
ServiceWorkerResponse response(
GetServiceWorkerResponseFromWebResponse(web_response));
const mojom::ServiceWorkerFetchResponseCallbackPtr& response_callback =
context_->fetch_response_callbacks[fetch_event_id];
if (response.blob_uuid.size()) {
// Send the legacy IPC due to the ordering issue between respondWith and
// blob.
// TODO(shimazu): mojofy this IPC after blob starts using sync IPC for
// creation or is mojofied: https://crbug.com/611935.
Send(new ServiceWorkerHostMsg_FetchEventResponse(
GetRoutingID(), fetch_event_id, response,
base::Time::FromDoubleT(event_dispatch_time)));
} else {
response_callback->OnResponse(response,
base::Time::FromDoubleT(event_dispatch_time));
}
context_->fetch_response_callbacks.erase(fetch_event_id);
}
void ServiceWorkerContextClient::RespondToFetchEventWithResponseStream(
int fetch_event_id,
const blink::WebServiceWorkerResponse& web_response,
blink::WebServiceWorkerStreamHandle* web_body_as_stream,
double event_dispatch_time) {
ServiceWorkerResponse response(
GetServiceWorkerResponseFromWebResponse(web_response));
const mojom::ServiceWorkerFetchResponseCallbackPtr& response_callback =
context_->fetch_response_callbacks[fetch_event_id];
blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream =
blink::mojom::ServiceWorkerStreamHandle::New();
blink::mojom::ServiceWorkerStreamCallbackPtr callback_ptr;
body_as_stream->callback_request = mojo::MakeRequest(&callback_ptr);
body_as_stream->stream = web_body_as_stream->DrainStreamDataPipe();
web_body_as_stream->SetListener(
base::MakeUnique<StreamHandleListener>(std::move(callback_ptr)));
response_callback->OnResponseStream(
response, std::move(body_as_stream),
base::Time::FromDoubleT(event_dispatch_time));
context_->fetch_response_callbacks.erase(fetch_event_id);
}
void ServiceWorkerContextClient::DidHandleFetchEvent(
int fetch_event_id,
blink::WebServiceWorkerEventResult result,
double event_dispatch_time) {
WorkerContextData::SimpleEventCallback callback =
std::move(context_->fetch_event_callbacks[fetch_event_id]);
DCHECK(callback);
std::move(callback).Run(EventResultToStatus(result),
base::Time::FromDoubleT(event_dispatch_time));
context_->fetch_event_callbacks.erase(fetch_event_id);
}
void ServiceWorkerContextClient::DidHandleNotificationClickEvent(
int request_id,
blink::WebServiceWorkerEventResult result,
double event_dispatch_time) {
DispatchNotificationClickEventCallback* callback =
context_->notification_click_event_callbacks.Lookup(request_id);
DCHECK(callback);
DCHECK(*callback);
std::move(*callback).Run(EventResultToStatus(result),
base::Time::FromDoubleT(event_dispatch_time));
context_->notification_click_event_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::DidHandleNotificationCloseEvent(
int request_id,
blink::WebServiceWorkerEventResult result,
double event_dispatch_time) {
DispatchNotificationCloseEventCallback* callback =
context_->notification_close_event_callbacks.Lookup(request_id);
DCHECK(callback);
DCHECK(*callback);
std::move(*callback).Run(EventResultToStatus(result),
base::Time::FromDoubleT(event_dispatch_time));
context_->notification_close_event_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::DidHandlePushEvent(
int request_id,
blink::WebServiceWorkerEventResult result,
double event_dispatch_time) {
DispatchPushEventCallback* callback =
context_->push_event_callbacks.Lookup(request_id);
DCHECK(callback);
DCHECK(*callback);
std::move(*callback).Run(EventResultToStatus(result),
base::Time::FromDoubleT(event_dispatch_time));
context_->push_event_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::DidHandleSyncEvent(
int request_id,
blink::WebServiceWorkerEventResult result,
double event_dispatch_time) {
SyncCallback* callback = context_->sync_event_callbacks.Lookup(request_id);
DCHECK(callback);
DCHECK(*callback);
std::move(*callback).Run(EventResultToStatus(result),
base::Time::FromDoubleT(event_dispatch_time));
context_->sync_event_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::RespondToPaymentRequestEvent(
int payment_request_id,
const blink::WebPaymentAppResponse& web_response,
double dispatch_event_time) {
const payments::mojom::PaymentAppResponseCallbackPtr& response_callback =
context_->payment_response_callbacks[payment_request_id];
payments::mojom::PaymentAppResponsePtr response =
payments::mojom::PaymentAppResponse::New();
response->method_name = web_response.method_name.Utf8();
response_callback->OnPaymentAppResponse(
std::move(response), base::Time::FromDoubleT(dispatch_event_time));
context_->payment_response_callbacks.erase(payment_request_id);
}
void ServiceWorkerContextClient::DidHandlePaymentRequestEvent(
int payment_request_id,
blink::WebServiceWorkerEventResult result,
double event_dispatch_time) {
DispatchPaymentRequestEventCallback callback =
std::move(context_->payment_request_event_callbacks[payment_request_id]);
std::move(callback).Run(EventResultToStatus(result),
base::Time::FromDoubleT(event_dispatch_time));
context_->payment_request_event_callbacks.erase(payment_request_id);
}
std::unique_ptr<blink::WebServiceWorkerNetworkProvider>
ServiceWorkerContextClient::CreateServiceWorkerNetworkProvider() {
DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
// Create a content::ServiceWorkerNetworkProvider for this data source so
// we can observe its requests.
std::unique_ptr<ServiceWorkerNetworkProvider> provider =
base::MakeUnique<ServiceWorkerNetworkProvider>(
MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_CONTROLLER,
true /* is_parent_frame_secure */);
provider_context_ = provider->context();
network_provider_id_ = provider->provider_id();
// Tell the network provider about which version to load.
provider->SetServiceWorkerVersionId(service_worker_version_id_,
embedded_worker_id_);
// Blink is responsible for deleting the returned object.
return base::MakeUnique<WebServiceWorkerNetworkProviderImpl>(
std::move(provider));
}
std::unique_ptr<blink::WebWorkerFetchContext>
ServiceWorkerContextClient::CreateServiceWorkerFetchContext() {
DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
DCHECK(base::FeatureList::IsEnabled(features::kOffMainThreadFetch));
mojom::WorkerURLLoaderFactoryProviderPtr worker_url_loader_factory_provider;
RenderThreadImpl::current()
->blink_platform_impl()
->GetInterfaceProvider()
->GetInterface(mojo::MakeRequest(&worker_url_loader_factory_provider));
// Blink is responsible for deleting the returned object.
return base::MakeUnique<ServiceWorkerFetchContextImpl>(
script_url_, worker_url_loader_factory_provider.PassInterface(),
network_provider_id_);
}
std::unique_ptr<blink::WebServiceWorkerProvider>
ServiceWorkerContextClient::CreateServiceWorkerProvider() {
DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
DCHECK(provider_context_);
// Blink is responsible for deleting the returned object.
return base::MakeUnique<WebServiceWorkerProviderImpl>(
sender_.get(), provider_context_.get());
}
void ServiceWorkerContextClient::PostMessageToClient(
const blink::WebString& uuid,
const blink::WebString& message,
blink::WebMessagePortChannelArray channels) {
Send(new ServiceWorkerHostMsg_PostMessageToClient(
GetRoutingID(), uuid.Utf8(), message.Utf16(),
WebMessagePortChannelImpl::ExtractMessagePorts(std::move(channels))));
}
void ServiceWorkerContextClient::Focus(
const blink::WebString& uuid,
std::unique_ptr<blink::WebServiceWorkerClientCallbacks> callback) {
DCHECK(callback);
int request_id = context_->client_callbacks.Add(std::move(callback));
Send(new ServiceWorkerHostMsg_FocusClient(GetRoutingID(), request_id,
uuid.Utf8()));
}
void ServiceWorkerContextClient::Navigate(
const blink::WebString& uuid,
const blink::WebURL& url,
std::unique_ptr<blink::WebServiceWorkerClientCallbacks> callback) {
DCHECK(callback);
int request_id = context_->client_callbacks.Add(std::move(callback));
Send(new ServiceWorkerHostMsg_NavigateClient(GetRoutingID(), request_id,
uuid.Utf8(), url));
}
void ServiceWorkerContextClient::SkipWaiting(
std::unique_ptr<blink::WebServiceWorkerSkipWaitingCallbacks> callbacks) {
DCHECK(callbacks);
int request_id = context_->skip_waiting_callbacks.Add(std::move(callbacks));
Send(new ServiceWorkerHostMsg_SkipWaiting(GetRoutingID(), request_id));
}
void ServiceWorkerContextClient::Claim(
std::unique_ptr<blink::WebServiceWorkerClientsClaimCallbacks> callbacks) {
DCHECK(callbacks);
int request_id = context_->claim_clients_callbacks.Add(std::move(callbacks));
Send(new ServiceWorkerHostMsg_ClaimClients(GetRoutingID(), request_id));
}
void ServiceWorkerContextClient::RegisterForeignFetchScopes(
int install_event_id,
const blink::WebVector<blink::WebURL>& sub_scopes,
const blink::WebVector<blink::WebSecurityOrigin>& origins) {
DCHECK(context_->install_methods_map[install_event_id].is_bound());
context_->install_methods_map[install_event_id]->RegisterForeignFetchScopes(
std::vector<GURL>(sub_scopes.begin(), sub_scopes.end()),
std::vector<url::Origin>(origins.begin(), origins.end()));
}
void ServiceWorkerContextClient::DispatchSyncEvent(
const std::string& tag,
blink::mojom::BackgroundSyncEventLastChance last_chance,
DispatchSyncEventCallback callback) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchSyncEvent");
int request_id = context_->sync_event_callbacks.Add(
base::MakeUnique<SyncCallback>(std::move(callback)));
// TODO(shimazu): Use typemap when this is moved to blink-side.
blink::WebServiceWorkerContextProxy::LastChanceOption web_last_chance =
mojo::ConvertTo<blink::WebServiceWorkerContextProxy::LastChanceOption>(
last_chance);
// TODO(jkarlin): Make this blink::WebString::FromUTF8Lenient once
// https://crrev.com/1768063002/ lands.
proxy_->DispatchSyncEvent(request_id, blink::WebString::FromUTF8(tag),
web_last_chance);
}
void ServiceWorkerContextClient::DispatchPaymentRequestEvent(
int payment_request_id,
payments::mojom::PaymentAppRequestPtr app_request,
payments::mojom::PaymentAppResponseCallbackPtr response_callback,
DispatchPaymentRequestEventCallback callback) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchPaymentRequestEvent");
context_->payment_response_callbacks.insert(
std::make_pair(payment_request_id, std::move(response_callback)));
context_->payment_request_event_callbacks.insert(
std::make_pair(payment_request_id, std::move(callback)));
blink::WebPaymentAppRequest webAppRequest =
mojo::ConvertTo<blink::WebPaymentAppRequest>(std::move(app_request));
proxy_->DispatchPaymentRequestEvent(payment_request_id, webAppRequest);
}
void ServiceWorkerContextClient::Send(IPC::Message* message) {
sender_->Send(message);
}
void ServiceWorkerContextClient::SendWorkerStarted() {
DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
TRACE_EVENT_ASYNC_END0("ServiceWorker",
"ServiceWorkerContextClient::StartingWorkerContext",
this);
(*instance_host_)->OnStarted();
}
void ServiceWorkerContextClient::SetRegistrationInServiceWorkerGlobalScope(
const ServiceWorkerRegistrationObjectInfo& info,
const ServiceWorkerVersionAttributes& attrs) {
DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
ServiceWorkerDispatcher* dispatcher =
ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
sender_.get(), main_thread_task_runner_.get());
// Register a registration and its version attributes with the dispatcher
// living on the worker thread.
scoped_refptr<WebServiceWorkerRegistrationImpl> registration(
dispatcher->GetOrCreateRegistration(info, attrs));
proxy_->SetRegistration(
WebServiceWorkerRegistrationImpl::CreateHandle(registration));
}
void ServiceWorkerContextClient::DispatchActivateEvent(
DispatchActivateEventCallback callback) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchActivateEvent");
int request_id = context_->activate_event_callbacks.Add(
base::MakeUnique<DispatchActivateEventCallback>(std::move(callback)));
proxy_->DispatchActivateEvent(request_id);
}
void ServiceWorkerContextClient::DispatchBackgroundFetchAbortEvent(
const std::string& tag,
DispatchBackgroundFetchAbortEventCallback callback) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchBackgroundFetchAbortEvent");
int request_id = context_->background_fetch_abort_event_callbacks.Add(
base::MakeUnique<DispatchBackgroundFetchAbortEventCallback>(
std::move(callback)));
proxy_->DispatchBackgroundFetchAbortEvent(request_id,
blink::WebString::FromUTF8(tag));
}
void ServiceWorkerContextClient::DispatchBackgroundFetchClickEvent(
const std::string& tag,
mojom::BackgroundFetchState state,
DispatchBackgroundFetchClickEventCallback callback) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchBackgroundFetchClickEvent");
int request_id = context_->background_fetch_click_event_callbacks.Add(
base::MakeUnique<DispatchBackgroundFetchClickEventCallback>(
std::move(callback)));
// TODO(peter): Use typemap when this is moved to blink-side.
blink::WebServiceWorkerContextProxy::BackgroundFetchState web_state =
mojo::ConvertTo<
blink::WebServiceWorkerContextProxy::BackgroundFetchState>(state);
proxy_->DispatchBackgroundFetchClickEvent(
request_id, blink::WebString::FromUTF8(tag), web_state);
}
void ServiceWorkerContextClient::DispatchBackgroundFetchFailEvent(
const std::string& tag,
const std::vector<BackgroundFetchSettledFetch>& fetches,
DispatchBackgroundFetchFailEventCallback callback) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchBackgroundFetchFailEvent");
int request_id = context_->background_fetch_fail_event_callbacks.Add(
base::MakeUnique<DispatchBackgroundFetchFailEventCallback>(
std::move(callback)));
blink::WebVector<blink::WebBackgroundFetchSettledFetch> web_fetches(
fetches.size());
for (size_t i = 0; i < fetches.size(); ++i) {
ToWebServiceWorkerRequest(fetches[i].request, &web_fetches[i].request);
ToWebServiceWorkerResponse(fetches[i].response, &web_fetches[i].response);
}
proxy_->DispatchBackgroundFetchFailEvent(
request_id, blink::WebString::FromUTF8(tag), web_fetches);
}
void ServiceWorkerContextClient::DispatchBackgroundFetchedEvent(
const std::string& tag,
const std::vector<BackgroundFetchSettledFetch>& fetches,
DispatchBackgroundFetchedEventCallback callback) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchBackgroundFetchedEvent");
int request_id = context_->background_fetched_event_callbacks.Add(
base::MakeUnique<DispatchBackgroundFetchedEventCallback>(
std::move(callback)));
blink::WebVector<blink::WebBackgroundFetchSettledFetch> web_fetches(
fetches.size());
for (size_t i = 0; i < fetches.size(); ++i) {
ToWebServiceWorkerRequest(fetches[i].request, &web_fetches[i].request);
ToWebServiceWorkerResponse(fetches[i].response, &web_fetches[i].response);
}
proxy_->DispatchBackgroundFetchedEvent(
request_id, blink::WebString::FromUTF8(tag), web_fetches);
}
void ServiceWorkerContextClient::DispatchInstallEvent(
mojom::ServiceWorkerInstallEventMethodsAssociatedPtrInfo client,
DispatchInstallEventCallback callback) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchInstallEvent");
int event_id = context_->install_event_callbacks.Add(
base::MakeUnique<DispatchInstallEventCallback>(std::move(callback)));
DCHECK(!context_->install_methods_map.count(event_id));
mojom::ServiceWorkerInstallEventMethodsAssociatedPtr install_methods;
install_methods.Bind(std::move(client));
context_->install_methods_map[event_id] = std::move(install_methods);
proxy_->DispatchInstallEvent(event_id);
}
void ServiceWorkerContextClient::DispatchExtendableMessageEvent(
mojom::ExtendableMessageEventPtr event,
DispatchExtendableMessageEventCallback callback) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchExtendableMessageEvent");
int request_id = context_->message_event_callbacks.Add(
base::MakeUnique<DispatchExtendableMessageEventCallback>(
std::move(callback)));
blink::WebMessagePortChannelArray ports =
WebMessagePortChannelImpl::CreateFromMessagePipeHandles(
std::move(event->message_ports));
if (event->source.client_info.IsValid()) {
blink::WebServiceWorkerClientInfo web_client =
ToWebServiceWorkerClientInfo(event->source.client_info);
proxy_->DispatchExtendableMessageEvent(
request_id, blink::WebString::FromUTF16(event->message),
event->source_origin, std::move(ports), web_client);
return;
}
DCHECK(event->source.service_worker_info.IsValid());
std::unique_ptr<ServiceWorkerHandleReference> handle =
ServiceWorkerHandleReference::Adopt(event->source.service_worker_info,
sender_.get());
ServiceWorkerDispatcher* dispatcher =
ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
sender_.get(), main_thread_task_runner_.get());
scoped_refptr<WebServiceWorkerImpl> worker =
dispatcher->GetOrCreateServiceWorker(std::move(handle));
proxy_->DispatchExtendableMessageEvent(
request_id, blink::WebString::FromUTF16(event->message),
event->source_origin, std::move(ports),
WebServiceWorkerImpl::CreateHandle(worker));
}
void ServiceWorkerContextClient::DispatchFetchEvent(
int fetch_event_id,
const ServiceWorkerFetchRequest& request,
mojom::FetchEventPreloadHandlePtr preload_handle,
mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
DispatchFetchEventCallback callback) {
std::unique_ptr<NavigationPreloadRequest> preload_request =
preload_handle
? base::MakeUnique<NavigationPreloadRequest>(
fetch_event_id, request.url, std::move(preload_handle))
: nullptr;
const bool navigation_preload_sent = !!preload_request;
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchFetchEvent");
context_->fetch_response_callbacks.insert(
std::make_pair(fetch_event_id, std::move(response_callback)));
context_->fetch_event_callbacks.insert(
std::make_pair(fetch_event_id, std::move(callback)));
if (preload_request) {
context_->preload_requests.AddWithID(std::move(preload_request),
fetch_event_id);
}
blink::WebServiceWorkerRequest web_request;
ToWebServiceWorkerRequest(request, &web_request);
if (request.fetch_type == ServiceWorkerFetchType::FOREIGN_FETCH) {
proxy_->DispatchForeignFetchEvent(fetch_event_id, web_request);
} else {
proxy_->DispatchFetchEvent(fetch_event_id, web_request,
navigation_preload_sent);
}
}
void ServiceWorkerContextClient::DispatchNotificationClickEvent(
const std::string& notification_id,
const PlatformNotificationData& notification_data,
int action_index,
const base::Optional<base::string16>& reply,
DispatchNotificationClickEventCallback callback) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchNotificationClickEvent");
int request_id = context_->notification_click_event_callbacks.Add(
base::MakeUnique<DispatchNotificationClickEventCallback>(
std::move(callback)));
blink::WebString web_reply;
if (reply)
web_reply = blink::WebString::FromUTF16(reply.value());
proxy_->DispatchNotificationClickEvent(
request_id, blink::WebString::FromUTF8(notification_id),
ToWebNotificationData(notification_data), action_index, web_reply);
}
void ServiceWorkerContextClient::DispatchNotificationCloseEvent(
const std::string& notification_id,
const PlatformNotificationData& notification_data,
DispatchNotificationCloseEventCallback callback) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchNotificationCloseEvent");
int request_id = context_->notification_close_event_callbacks.Add(
base::MakeUnique<DispatchNotificationCloseEventCallback>(
std::move(callback)));
proxy_->DispatchNotificationCloseEvent(
request_id, blink::WebString::FromUTF8(notification_id),
ToWebNotificationData(notification_data));
}
void ServiceWorkerContextClient::DispatchPushEvent(
const PushEventPayload& payload,
DispatchPushEventCallback callback) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchPushEvent");
int request_id = context_->push_event_callbacks.Add(
base::MakeUnique<DispatchPushEventCallback>(std::move(callback)));
// Only set data to be a valid string if the payload had decrypted data.
blink::WebString data;
if (!payload.is_null)
data.Assign(blink::WebString::FromUTF8(payload.data));
proxy_->DispatchPushEvent(request_id, data);
}
void ServiceWorkerContextClient::OnDidGetClient(
int request_id,
const ServiceWorkerClientInfo& client) {
TRACE_EVENT0("ServiceWorker", "ServiceWorkerContextClient::OnDidGetClient");
blink::WebServiceWorkerClientCallbacks* callbacks =
context_->client_callbacks.Lookup(request_id);
if (!callbacks) {
NOTREACHED() << "Got stray response: " << request_id;
return;
}
std::unique_ptr<blink::WebServiceWorkerClientInfo> web_client;
if (!client.IsEmpty()) {
DCHECK(client.IsValid());
web_client.reset(new blink::WebServiceWorkerClientInfo(
ToWebServiceWorkerClientInfo(client)));
}
callbacks->OnSuccess(std::move(web_client));
context_->client_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::OnDidGetClients(
int request_id, const std::vector<ServiceWorkerClientInfo>& clients) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnDidGetClients");
blink::WebServiceWorkerClientsCallbacks* callbacks =
context_->clients_callbacks.Lookup(request_id);
if (!callbacks) {
NOTREACHED() << "Got stray response: " << request_id;
return;
}
blink::WebServiceWorkerClientsInfo info;
blink::WebVector<blink::WebServiceWorkerClientInfo> convertedClients(
clients.size());
for (size_t i = 0; i < clients.size(); ++i)
convertedClients[i] = ToWebServiceWorkerClientInfo(clients[i]);
info.clients.Swap(convertedClients);
callbacks->OnSuccess(info);
context_->clients_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::OnOpenWindowResponse(
int request_id,
const ServiceWorkerClientInfo& client) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnOpenWindowResponse");
blink::WebServiceWorkerClientCallbacks* callbacks =
context_->client_callbacks.Lookup(request_id);
if (!callbacks) {
NOTREACHED() << "Got stray response: " << request_id;
return;
}
std::unique_ptr<blink::WebServiceWorkerClientInfo> web_client;
if (!client.IsEmpty()) {
DCHECK(client.IsValid());
web_client.reset(new blink::WebServiceWorkerClientInfo(
ToWebServiceWorkerClientInfo(client)));
}
callbacks->OnSuccess(std::move(web_client));
context_->client_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::OnOpenWindowError(
int request_id,
const std::string& message) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnOpenWindowError");
blink::WebServiceWorkerClientCallbacks* callbacks =
context_->client_callbacks.Lookup(request_id);
if (!callbacks) {
NOTREACHED() << "Got stray response: " << request_id;
return;
}
callbacks->OnError(blink::WebServiceWorkerError(
blink::WebServiceWorkerError::kErrorTypeNavigation,
blink::WebString::FromUTF8(message)));
context_->client_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::OnFocusClientResponse(
int request_id, const ServiceWorkerClientInfo& client) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnFocusClientResponse");
blink::WebServiceWorkerClientCallbacks* callback =
context_->client_callbacks.Lookup(request_id);
if (!callback) {
NOTREACHED() << "Got stray response: " << request_id;
return;
}
if (!client.IsEmpty()) {
DCHECK(client.IsValid());
std::unique_ptr<blink::WebServiceWorkerClientInfo> web_client(
new blink::WebServiceWorkerClientInfo(
ToWebServiceWorkerClientInfo(client)));
callback->OnSuccess(std::move(web_client));
} else {
callback->OnError(blink::WebServiceWorkerError(
blink::WebServiceWorkerError::kErrorTypeNotFound,
"The WindowClient was not found."));
}
context_->client_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::OnNavigateClientResponse(
int request_id,
const ServiceWorkerClientInfo& client) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnNavigateClientResponse");
blink::WebServiceWorkerClientCallbacks* callbacks =
context_->client_callbacks.Lookup(request_id);
if (!callbacks) {
NOTREACHED() << "Got stray response: " << request_id;
return;
}
std::unique_ptr<blink::WebServiceWorkerClientInfo> web_client;
if (!client.IsEmpty()) {
DCHECK(client.IsValid());
web_client.reset(new blink::WebServiceWorkerClientInfo(
ToWebServiceWorkerClientInfo(client)));
}
callbacks->OnSuccess(std::move(web_client));
context_->client_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::OnNavigateClientError(int request_id,
const GURL& url) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnNavigateClientError");
blink::WebServiceWorkerClientCallbacks* callbacks =
context_->client_callbacks.Lookup(request_id);
if (!callbacks) {
NOTREACHED() << "Got stray response: " << request_id;
return;
}
std::string message = "Cannot navigate to URL: " + url.spec();
callbacks->OnError(blink::WebServiceWorkerError(
blink::WebServiceWorkerError::kErrorTypeNavigation,
blink::WebString::FromUTF8(message)));
context_->client_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::OnDidSkipWaiting(int request_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnDidSkipWaiting");
blink::WebServiceWorkerSkipWaitingCallbacks* callbacks =
context_->skip_waiting_callbacks.Lookup(request_id);
if (!callbacks) {
NOTREACHED() << "Got stray response: " << request_id;
return;
}
callbacks->OnSuccess();
context_->skip_waiting_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::OnDidClaimClients(int request_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnDidClaimClients");
blink::WebServiceWorkerClientsClaimCallbacks* callbacks =
context_->claim_clients_callbacks.Lookup(request_id);
if (!callbacks) {
NOTREACHED() << "Got stray response: " << request_id;
return;
}
callbacks->OnSuccess();
context_->claim_clients_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::OnClaimClientsError(
int request_id,
blink::WebServiceWorkerError::ErrorType error_type,
const base::string16& message) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnClaimClientsError");
blink::WebServiceWorkerClientsClaimCallbacks* callbacks =
context_->claim_clients_callbacks.Lookup(request_id);
if (!callbacks) {
NOTREACHED() << "Got stray response: " << request_id;
return;
}
callbacks->OnError(blink::WebServiceWorkerError(
error_type, blink::WebString::FromUTF16(message)));
context_->claim_clients_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::Ping(PingCallback callback) {
std::move(callback).Run();
}
void ServiceWorkerContextClient::OnNavigationPreloadResponse(
int fetch_event_id,
std::unique_ptr<blink::WebURLResponse> response,
std::unique_ptr<blink::WebDataConsumerHandle> data_consumer_handle) {
proxy_->OnNavigationPreloadResponse(fetch_event_id, std::move(response),
std::move(data_consumer_handle));
}
void ServiceWorkerContextClient::OnNavigationPreloadError(
int fetch_event_id,
std::unique_ptr<blink::WebServiceWorkerError> error) {
proxy_->OnNavigationPreloadError(fetch_event_id, std::move(error));
context_->preload_requests.Remove(fetch_event_id);
}
void ServiceWorkerContextClient::OnNavigationPreloadComplete(
int fetch_event_id,
base::TimeTicks completion_time,
int64_t encoded_data_length,
int64_t encoded_body_length,
int64_t decoded_body_length) {
proxy_->OnNavigationPreloadComplete(
fetch_event_id, (completion_time - base::TimeTicks()).InSecondsF(),
encoded_data_length, encoded_body_length, decoded_body_length);
context_->preload_requests.Remove(fetch_event_id);
}
base::WeakPtr<ServiceWorkerContextClient>
ServiceWorkerContextClient::GetWeakPtr() {
DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
DCHECK(context_);
return context_->weak_factory.GetWeakPtr();
}
} // namespace content