blob: d802fbaeeb8f431618591139b27b38bc61007ae0 [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 <memory>
#include <utility>
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/histogram.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/trace_event/trace_event.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/webmessageportchannel_impl.h"
#include "content/common/devtools_messages.h"
#include "content/common/message_port_messages.h"
#include "content/common/mojo/service_registry_impl.h"
#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/service_worker_messages.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/background_sync/background_sync_client_impl.h"
#include "content/renderer/devtools/devtools_agent.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/service_worker/embedded_worker_dispatcher.h"
#include "content/renderer/service_worker/service_worker_type_util.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.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/modules/background_sync/WebSyncRegistration.h"
#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationData.h"
#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerClientQueryOptions.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/WebDataSource.h"
#include "third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h"
#include "third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h"
#include "third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerNetworkProvider.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;
void CallWorkerContextDestroyedOnMainThread(int embedded_worker_id) {
if (!RenderThreadImpl::current() ||
!RenderThreadImpl::current()->embedded_worker_dispatcher())
return;
RenderThreadImpl::current()->embedded_worker_dispatcher()->
WorkerContextDestroyed(embedded_worker_id);
}
// We store an instance of this class in the "extra data" of the WebDataSource
// and attach a ServiceWorkerNetworkProvider to it as base::UserData.
// (see createServiceWorkerNetworkProvider).
class DataSourceExtraData
: public blink::WebDataSource::ExtraData,
public base::SupportsUserData {
public:
DataSourceExtraData() {}
~DataSourceExtraData() override {}
};
// Called on the main thread only and blink owns it.
class WebServiceWorkerNetworkProviderImpl
: public blink::WebServiceWorkerNetworkProvider {
public:
// Blink calls this method for each request starting with the main script,
// we tag them with the provider id.
void willSendRequest(blink::WebDataSource* data_source,
blink::WebURLRequest& request) override {
ServiceWorkerNetworkProvider* provider =
ServiceWorkerNetworkProvider::FromDocumentState(
static_cast<DataSourceExtraData*>(data_source->getExtraData()));
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);
request.setExtraData(extra_data.release());
}
};
void SendPostMessageToClientOnMainThread(
ThreadSafeSender* sender,
int routing_id,
const std::string& uuid,
const base::string16& message,
std::unique_ptr<blink::WebMessagePortChannelArray> channels) {
sender->Send(new ServiceWorkerHostMsg_PostMessageToClient(
routing_id, uuid, message,
WebMessagePortChannelImpl::ExtractMessagePortIDs(std::move(channels))));
}
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 = base::UTF8ToUTF16(client_info.client_uuid);
web_client_info.pageVisibilityState = client_info.page_visibility_state;
web_client_info.isFocused = client_info.is_focused;
web_client_info.url = client_info.url;
web_client_info.frameType = GetBlinkFrameType(client_info.frame_type);
web_client_info.clientType = client_info.client_type;
return web_client_info;
}
} // namespace
// Holding data that needs to be bound to the worker context on the
// worker thread.
struct ServiceWorkerContextClient::WorkerContextData {
using ClientsCallbacksMap =
IDMap<blink::WebServiceWorkerClientsCallbacks, IDMapOwnPointer>;
using ClaimClientsCallbacksMap =
IDMap<blink::WebServiceWorkerClientsClaimCallbacks, IDMapOwnPointer>;
using ClientCallbacksMap =
IDMap<blink::WebServiceWorkerClientCallbacks, IDMapOwnPointer>;
using SkipWaitingCallbacksMap =
IDMap<blink::WebServiceWorkerSkipWaitingCallbacks, IDMapOwnPointer>;
using SyncEventCallbacksMap =
IDMap<const mojo::Callback<void(blink::mojom::ServiceWorkerEventStatus)>,
IDMapOwnPointer>;
explicit WorkerContextData(ServiceWorkerContextClient* owner)
: weak_factory(owner), proxy_weak_factory(owner->proxy_) {}
~WorkerContextData() {
DCHECK(thread_checker.CalledOnValidThread());
}
// 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 Background Sync Events
SyncEventCallbacksMap sync_event_callbacks;
ServiceRegistryImpl service_registry;
base::ThreadChecker thread_checker;
base::WeakPtrFactory<ServiceWorkerContextClient> weak_factory;
base::WeakPtrFactory<blink::WebServiceWorkerContextProxy> proxy_weak_factory;
};
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,
int worker_devtools_agent_route_id)
: embedded_worker_id_(embedded_worker_id),
service_worker_version_id_(service_worker_version_id),
service_worker_scope_(service_worker_scope),
script_url_(script_url),
worker_devtools_agent_route_id_(worker_devtools_agent_route_id),
sender_(ChildThreadImpl::current()->thread_safe_sender()),
main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
proxy_(nullptr) {
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_ActivateEvent, OnActivateEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ExtendableMessageEvent,
OnExtendableMessageEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FetchEvent, OnFetchEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_InstallEvent, OnInstallEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_NotificationClickEvent,
OnNotificationClickEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_NotificationCloseEvent,
OnNotificationCloseEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_PushEvent, OnPushEvent)
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_HANDLER(ServiceWorkerMsg_Ping, OnPing);
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
DCHECK(handled);
}
void ServiceWorkerContextClient::BindServiceRegistry(
shell::mojom::InterfaceProviderRequest services,
shell::mojom::InterfaceProviderPtr exposed_services) {
context_->service_registry.Bind(std::move(services));
context_->service_registry.BindRemoteServiceProvider(
std::move(exposed_services));
}
blink::WebURL ServiceWorkerContextClient::scope() const {
return service_worker_scope_;
}
void ServiceWorkerContextClient::getClient(
const blink::WebString& id,
blink::WebServiceWorkerClientCallbacks* callbacks) {
DCHECK(callbacks);
int request_id = context_->client_callbacks.Add(callbacks);
Send(new ServiceWorkerHostMsg_GetClient(
GetRoutingID(), request_id, base::UTF16ToUTF8(base::StringPiece16(id))));
}
void ServiceWorkerContextClient::getClients(
const blink::WebServiceWorkerClientQueryOptions& weboptions,
blink::WebServiceWorkerClientsCallbacks* callbacks) {
DCHECK(callbacks);
int request_id = context_->clients_callbacks.Add(callbacks);
ServiceWorkerClientQueryOptions options;
options.client_type = weboptions.clientType;
options.include_uncontrolled = weboptions.includeUncontrolled;
Send(new ServiceWorkerHostMsg_GetClients(
GetRoutingID(), request_id, options));
}
void ServiceWorkerContextClient::openWindow(
const blink::WebURL& url,
blink::WebServiceWorkerClientCallbacks* callbacks) {
DCHECK(callbacks);
int request_id = context_->client_callbacks.Add(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() {
Send(new EmbeddedWorkerHostMsg_WorkerReadyForInspection(embedded_worker_id_));
}
void ServiceWorkerContextClient::workerContextFailedToStart() {
DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
DCHECK(!proxy_);
Send(new EmbeddedWorkerHostMsg_WorkerScriptLoadFailed(embedded_worker_id_));
RenderThreadImpl::current()->embedded_worker_dispatcher()->
WorkerContextDestroyed(embedded_worker_id_);
}
void ServiceWorkerContextClient::workerScriptLoaded() {
DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
DCHECK(!proxy_);
Send(new EmbeddedWorkerHostMsg_WorkerScriptLoaded(embedded_worker_id_));
}
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);
// Register Mojo services.
context_->service_registry.ServiceRegistry::AddService(
base::Bind(&BackgroundSyncClientImpl::Create));
SetRegistrationInServiceWorkerGlobalScope(registration_info, version_attrs);
Send(new EmbeddedWorkerHostMsg_WorkerThreadStarted(
embedded_worker_id_, WorkerThread::GetCurrentId(),
provider_context_->provider_id()));
TRACE_EVENT_ASYNC_STEP_INTO0(
"ServiceWorker",
"ServiceWorkerContextClient::StartingWorkerContext",
this,
"ExecuteScript");
}
void ServiceWorkerContextClient::didEvaluateWorkerScript(bool success) {
Send(new EmbeddedWorkerHostMsg_WorkerScriptEvaluated(
embedded_worker_id_, 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, embedded_worker_id_, script_url_);
}
void ServiceWorkerContextClient::willDestroyWorkerContext(
v8::Local<v8::Context> context) {
// At this point WillStopCurrentWorkerThread is already called, so
// worker_task_runner_->RunsTasksOnCurrentThread() returns false
// (while we're still on the worker thread).
proxy_ = NULL;
// 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, embedded_worker_id_, script_url_);
}
void ServiceWorkerContextClient::workerContextDestroyed() {
DCHECK(g_worker_client_tls.Pointer()->Get() == NULL);
// Now we should be able to free the WebEmbeddedWorker container on the
// main thread.
main_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&CallWorkerContextDestroyedOnMainThread,
embedded_worker_id_));
}
void ServiceWorkerContextClient::reportException(
const blink::WebString& error_message,
int line_number,
int column_number,
const blink::WebString& source_url) {
Send(new EmbeddedWorkerHostMsg_ReportException(
embedded_worker_id_, error_message, 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) {
EmbeddedWorkerHostMsg_ReportConsoleMessage_Params params;
params.source_identifier = source;
params.message_level = level;
params.message = message;
params.line_number = line_number;
params.source_url = blink::WebStringToGURL(source_url);
Send(new EmbeddedWorkerHostMsg_ReportConsoleMessage(
embedded_worker_id_, params));
}
void ServiceWorkerContextClient::sendDevToolsMessage(
int session_id,
int call_id,
const blink::WebString& message,
const blink::WebString& state_cookie) {
DevToolsAgent::SendChunkedProtocolMessage(
sender_.get(), worker_devtools_agent_route_id_, 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) {
Send(new ServiceWorkerHostMsg_ActivateEventFinished(
GetRoutingID(), request_id, result));
}
void ServiceWorkerContextClient::didHandleExtendableMessageEvent(
int request_id,
blink::WebServiceWorkerEventResult result) {
Send(new ServiceWorkerHostMsg_ExtendableMessageEventFinished(
GetRoutingID(), request_id, result));
}
void ServiceWorkerContextClient::didHandleInstallEvent(
int request_id,
blink::WebServiceWorkerEventResult result) {
Send(new ServiceWorkerHostMsg_InstallEventFinished(
GetRoutingID(), request_id, result, proxy_->hasFetchEventHandler()));
}
void ServiceWorkerContextClient::didHandleFetchEvent(int request_id) {
Send(new ServiceWorkerHostMsg_FetchEventFinished(
GetRoutingID(), request_id,
SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
ServiceWorkerResponse()));
}
void ServiceWorkerContextClient::didHandleFetchEvent(
int request_id,
const blink::WebServiceWorkerResponse& web_response) {
ServiceWorkerHeaderMap headers;
GetServiceWorkerHeaderMapFromWebResponse(web_response, &headers);
ServiceWorkerHeaderList cors_exposed_header_names;
GetCorsExposedHeaderNamesFromWebResponse(web_response,
&cors_exposed_header_names);
ServiceWorkerResponse response(
web_response.url(), web_response.status(),
web_response.statusText().utf8(), web_response.responseType(), headers,
web_response.blobUUID().utf8(), web_response.blobSize(),
web_response.streamURL(), web_response.error(),
base::Time::FromInternalValue(web_response.responseTime()),
!web_response.cacheStorageCacheName().isNull(),
web_response.cacheStorageCacheName().utf8(), cors_exposed_header_names);
Send(new ServiceWorkerHostMsg_FetchEventFinished(
GetRoutingID(), request_id,
SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE,
response));
}
void ServiceWorkerContextClient::didHandleNotificationClickEvent(
int request_id,
blink::WebServiceWorkerEventResult result) {
Send(new ServiceWorkerHostMsg_NotificationClickEventFinished(
GetRoutingID(), request_id, result));
}
void ServiceWorkerContextClient::didHandleNotificationCloseEvent(
int request_id,
blink::WebServiceWorkerEventResult result) {
Send(new ServiceWorkerHostMsg_NotificationCloseEventFinished(
GetRoutingID(), request_id, result));
}
void ServiceWorkerContextClient::didHandlePushEvent(
int request_id,
blink::WebServiceWorkerEventResult result) {
Send(new ServiceWorkerHostMsg_PushEventFinished(
GetRoutingID(), request_id, result));
}
void ServiceWorkerContextClient::didHandleSyncEvent(
int request_id,
blink::WebServiceWorkerEventResult result) {
const SyncCallback* callback =
context_->sync_event_callbacks.Lookup(request_id);
if (!callback)
return;
if (result == blink::WebServiceWorkerEventResultCompleted) {
callback->Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED);
} else {
callback->Run(blink::mojom::ServiceWorkerEventStatus::REJECTED);
}
context_->sync_event_callbacks.Remove(request_id);
}
blink::WebServiceWorkerNetworkProvider*
ServiceWorkerContextClient::createServiceWorkerNetworkProvider(
blink::WebDataSource* data_source) {
DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
// Create a content::ServiceWorkerNetworkProvider for this data source so
// we can observe its requests.
std::unique_ptr<ServiceWorkerNetworkProvider> provider(
new ServiceWorkerNetworkProvider(MSG_ROUTING_NONE,
SERVICE_WORKER_PROVIDER_FOR_CONTROLLER,
true /* is_parent_frame_secure */));
provider_context_ = provider->context();
// Tell the network provider about which version to load.
provider->SetServiceWorkerVersionId(service_worker_version_id_);
// The provider is kept around for the lifetime of the DataSource
// and ownership is transferred to the DataSource.
DataSourceExtraData* extra_data = new DataSourceExtraData();
data_source->setExtraData(extra_data);
ServiceWorkerNetworkProvider::AttachToDocumentState(extra_data,
std::move(provider));
// Blink is responsible for deleting the returned object.
return new WebServiceWorkerNetworkProviderImpl();
}
blink::WebServiceWorkerProvider*
ServiceWorkerContextClient::createServiceWorkerProvider() {
DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
DCHECK(provider_context_);
// Blink is responsible for deleting the returned object.
return new WebServiceWorkerProviderImpl(
sender_.get(), provider_context_.get());
}
void ServiceWorkerContextClient::postMessageToClient(
const blink::WebString& uuid,
const blink::WebString& message,
blink::WebMessagePortChannelArray* channels) {
// This may send channels for MessagePorts, and all internal book-keeping
// messages for MessagePort (e.g. QueueMessages) are sent from main thread
// (with thread hopping), so we need to do the same thread hopping here not
// to overtake those messages.
std::unique_ptr<blink::WebMessagePortChannelArray> channel_array(channels);
main_thread_task_runner_->PostTask(
FROM_HERE, base::Bind(&SendPostMessageToClientOnMainThread,
base::RetainedRef(sender_), GetRoutingID(),
base::UTF16ToUTF8(base::StringPiece16(uuid)),
static_cast<base::string16>(message),
base::Passed(&channel_array)));
}
void ServiceWorkerContextClient::postMessageToCrossOriginClient(
const blink::WebCrossOriginServiceWorkerClient&,
const blink::WebString&,
blink::WebMessagePortChannelArray*) {
NOTREACHED();
}
void ServiceWorkerContextClient::focus(
const blink::WebString& uuid,
blink::WebServiceWorkerClientCallbacks* callback) {
DCHECK(callback);
int request_id = context_->client_callbacks.Add(callback);
Send(new ServiceWorkerHostMsg_FocusClient(
GetRoutingID(), request_id,
base::UTF16ToUTF8(base::StringPiece16(uuid))));
}
void ServiceWorkerContextClient::navigate(
const blink::WebString& uuid,
const blink::WebURL& url,
blink::WebServiceWorkerClientCallbacks* callback) {
DCHECK(callback);
int request_id = context_->client_callbacks.Add(callback);
Send(new ServiceWorkerHostMsg_NavigateClient(
GetRoutingID(), request_id, base::UTF16ToUTF8(base::StringPiece16(uuid)),
url));
}
void ServiceWorkerContextClient::skipWaiting(
blink::WebServiceWorkerSkipWaitingCallbacks* callbacks) {
DCHECK(callbacks);
int request_id = context_->skip_waiting_callbacks.Add(callbacks);
Send(new ServiceWorkerHostMsg_SkipWaiting(GetRoutingID(), request_id));
}
void ServiceWorkerContextClient::claim(
blink::WebServiceWorkerClientsClaimCallbacks* callbacks) {
DCHECK(callbacks);
int request_id = context_->claim_clients_callbacks.Add(callbacks);
Send(new ServiceWorkerHostMsg_ClaimClients(GetRoutingID(), request_id));
}
void ServiceWorkerContextClient::registerForeignFetchScopes(
const blink::WebVector<blink::WebURL>& sub_scopes,
const blink::WebVector<blink::WebSecurityOrigin>& origins) {
Send(new ServiceWorkerHostMsg_RegisterForeignFetchScopes(
GetRoutingID(), 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::WebServiceWorkerContextProxy::LastChanceOption last_chance,
const SyncCallback& callback) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::DispatchSyncEvent");
int request_id =
context_->sync_event_callbacks.Add(new SyncCallback(callback));
// TODO(jkarlin): Make this blink::WebString::FromUTF8Lenient once
// https://crrev.com/1768063002/ lands.
proxy_->dispatchSyncEvent(request_id, blink::WebString::fromUTF8(tag),
last_chance);
}
void ServiceWorkerContextClient::Send(IPC::Message* message) {
sender_->Send(message);
}
void ServiceWorkerContextClient::SendWorkerStarted() {
DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
TRACE_EVENT_ASYNC_END0("ServiceWorker",
"ServiceWorkerContextClient::StartingWorkerContext",
this);
Send(new EmbeddedWorkerHostMsg_WorkerStarted(embedded_worker_id_));
}
void ServiceWorkerContextClient::SetRegistrationInServiceWorkerGlobalScope(
const ServiceWorkerRegistrationObjectInfo& info,
const ServiceWorkerVersionAttributes& attrs) {
DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
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::OnActivateEvent(int request_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnActivateEvent");
proxy_->dispatchActivateEvent(request_id);
}
void ServiceWorkerContextClient::OnExtendableMessageEvent(
int request_id,
const ServiceWorkerMsg_ExtendableMessageEvent_Params& params) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnExtendableMessageEvent");
blink::WebMessagePortChannelArray ports =
WebMessagePortChannelImpl::CreatePorts(params.message_ports,
params.new_routing_ids,
main_thread_task_runner_);
if (params.source.client_info.IsValid()) {
blink::WebServiceWorkerClientInfo web_client =
ToWebServiceWorkerClientInfo(params.source.client_info);
proxy_->dispatchExtendableMessageEvent(
request_id, params.message, params.source_origin, ports, web_client);
return;
}
DCHECK(params.source.service_worker_info.IsValid());
std::unique_ptr<ServiceWorkerHandleReference> handle =
ServiceWorkerHandleReference::Adopt(params.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, params.message, params.source_origin, ports,
WebServiceWorkerImpl::CreateHandle(worker));
}
void ServiceWorkerContextClient::OnInstallEvent(int request_id) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnInstallEvent");
proxy_->dispatchInstallEvent(request_id);
}
void ServiceWorkerContextClient::OnFetchEvent(
int request_id,
const ServiceWorkerFetchRequest& request) {
blink::WebServiceWorkerRequest webRequest;
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnFetchEvent");
webRequest.setURL(blink::WebURL(request.url));
webRequest.setMethod(blink::WebString::fromUTF8(request.method));
for (ServiceWorkerHeaderMap::const_iterator it = request.headers.begin();
it != request.headers.end();
++it) {
webRequest.setHeader(blink::WebString::fromUTF8(it->first),
blink::WebString::fromUTF8(it->second));
}
if (!request.blob_uuid.empty()) {
webRequest.setBlob(blink::WebString::fromUTF8(request.blob_uuid),
request.blob_size);
}
webRequest.setReferrer(
blink::WebString::fromUTF8(request.referrer.url.spec()),
request.referrer.policy);
webRequest.setMode(GetBlinkFetchRequestMode(request.mode));
webRequest.setIsMainResourceLoad(request.is_main_resource_load);
webRequest.setCredentialsMode(
GetBlinkFetchCredentialsMode(request.credentials_mode));
webRequest.setRedirectMode(GetBlinkFetchRedirectMode(request.redirect_mode));
webRequest.setRequestContext(
GetBlinkRequestContext(request.request_context_type));
webRequest.setFrameType(GetBlinkFrameType(request.frame_type));
webRequest.setClientId(blink::WebString::fromUTF8(request.client_id));
webRequest.setIsReload(request.is_reload);
if (request.fetch_type == ServiceWorkerFetchType::FOREIGN_FETCH) {
proxy_->dispatchForeignFetchEvent(request_id, webRequest);
} else {
proxy_->dispatchFetchEvent(request_id, webRequest);
}
}
void ServiceWorkerContextClient::OnNotificationClickEvent(
int request_id,
int64_t persistent_notification_id,
const PlatformNotificationData& notification_data,
int action_index) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnNotificationClickEvent");
proxy_->dispatchNotificationClickEvent(
request_id,
persistent_notification_id,
ToWebNotificationData(notification_data),
action_index);
}
void ServiceWorkerContextClient::OnNotificationCloseEvent(
int request_id,
int64_t persistent_notification_id,
const PlatformNotificationData& notification_data) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnNotificationCloseEvent");
proxy_->dispatchNotificationCloseEvent(
request_id, persistent_notification_id,
ToWebNotificationData(notification_data));
}
void ServiceWorkerContextClient::OnPushEvent(int request_id,
const PushEventPayload& payload) {
TRACE_EVENT0("ServiceWorker",
"ServiceWorkerContextClient::OnPushEvent");
// 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::ErrorTypeNavigation,
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::ErrorTypeNotFound,
"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::ErrorTypeNavigation,
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, message));
context_->claim_clients_callbacks.Remove(request_id);
}
void ServiceWorkerContextClient::OnPing() {
Send(new ServiceWorkerHostMsg_Pong(GetRoutingID()));
}
base::WeakPtr<ServiceWorkerContextClient>
ServiceWorkerContextClient::GetWeakPtr() {
DCHECK(worker_task_runner_->RunsTasksOnCurrentThread());
DCHECK(context_);
return context_->weak_factory.GetWeakPtr();
}
} // namespace content