1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/service_worker/service_worker_script_context.h"
7 #include "base/debug/trace_event.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "content/child/thread_safe_sender.h"
11 #include "content/child/webmessageportchannel_impl.h"
12 #include "content/common/service_worker/service_worker_messages.h"
13 #include "content/renderer/service_worker/embedded_worker_context_client.h"
14 #include "ipc/ipc_message.h"
15 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
16 #include "third_party/WebKit/public/platform/WebServiceWorkerRequest.h"
17 #include "third_party/WebKit/public/platform/WebString.h"
18 #include "third_party/WebKit/public/platform/WebURL.h"
19 #include "third_party/WebKit/public/web/WebServiceWorkerContextClient.h"
20 #include "third_party/WebKit/public/web/WebServiceWorkerContextProxy.h"
26 void SendPostMessageToDocumentOnMainThread(
27 ThreadSafeSender
* sender
,
30 const base::string16
& message
,
31 scoped_ptr
<blink::WebMessagePortChannelArray
> channels
) {
32 sender
->Send(new ServiceWorkerHostMsg_PostMessageToDocument(
33 routing_id
, client_id
, message
,
34 WebMessagePortChannelImpl::ExtractMessagePortIDs(channels
.release())));
37 blink::WebURLRequest::FetchRequestMode
GetBlinkFetchRequestMode(
38 FetchRequestMode mode
) {
39 return static_cast<blink::WebURLRequest::FetchRequestMode
>(mode
);
42 blink::WebURLRequest::FetchCredentialsMode
GetBlinkFetchCredentialsMode(
43 FetchCredentialsMode credentials_mode
) {
44 return static_cast<blink::WebURLRequest::FetchCredentialsMode
>(
50 ServiceWorkerScriptContext::ServiceWorkerScriptContext(
51 EmbeddedWorkerContextClient
* embedded_context
,
52 blink::WebServiceWorkerContextProxy
* proxy
)
53 : cache_storage_dispatcher_(new ServiceWorkerCacheStorageDispatcher(this)),
54 embedded_context_(embedded_context
),
58 ServiceWorkerScriptContext::~ServiceWorkerScriptContext() {}
60 void ServiceWorkerScriptContext::OnMessageReceived(
61 const IPC::Message
& message
) {
63 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerScriptContext
, message
)
64 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ActivateEvent
, OnActivateEvent
)
65 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FetchEvent
, OnFetchEvent
)
66 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_InstallEvent
, OnInstallEvent
)
67 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SyncEvent
, OnSyncEvent
)
68 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_PushEvent
, OnPushEvent
)
69 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToWorker
, OnPostMessage
)
70 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetClientDocuments
,
71 OnDidGetClientDocuments
)
72 IPC_MESSAGE_UNHANDLED(handled
= false)
75 // TODO(gavinp): Would it be preferable to put an AddListener() method to
76 // EmbeddedWorkerContextClient?
78 handled
= cache_storage_dispatcher_
->OnMessageReceived(message
);
83 void ServiceWorkerScriptContext::DidHandleActivateEvent(
85 blink::WebServiceWorkerEventResult result
) {
87 "ServiceWorker.ActivateEventExecutionTime",
88 base::TimeTicks::Now() - activate_start_timings_
[request_id
]);
89 activate_start_timings_
.erase(request_id
);
91 Send(new ServiceWorkerHostMsg_ActivateEventFinished(
92 GetRoutingID(), request_id
, result
));
95 void ServiceWorkerScriptContext::DidHandleInstallEvent(
97 blink::WebServiceWorkerEventResult result
) {
99 "ServiceWorker.InstallEventExecutionTime",
100 base::TimeTicks::Now() - install_start_timings_
[request_id
]);
101 install_start_timings_
.erase(request_id
);
103 Send(new ServiceWorkerHostMsg_InstallEventFinished(
104 GetRoutingID(), request_id
, result
));
107 void ServiceWorkerScriptContext::DidHandleFetchEvent(
109 ServiceWorkerFetchEventResult result
,
110 const ServiceWorkerResponse
& response
) {
112 "ServiceWorker.FetchEventExecutionTime",
113 base::TimeTicks::Now() - fetch_start_timings_
[request_id
]);
114 fetch_start_timings_
.erase(request_id
);
116 Send(new ServiceWorkerHostMsg_FetchEventFinished(
117 GetRoutingID(), request_id
, result
, response
));
120 void ServiceWorkerScriptContext::DidHandleSyncEvent(int request_id
) {
121 Send(new ServiceWorkerHostMsg_SyncEventFinished(
122 GetRoutingID(), request_id
));
125 void ServiceWorkerScriptContext::GetClientDocuments(
126 blink::WebServiceWorkerClientsCallbacks
* callbacks
) {
128 int request_id
= pending_clients_callbacks_
.Add(callbacks
);
129 Send(new ServiceWorkerHostMsg_GetClientDocuments(
130 GetRoutingID(), request_id
));
133 void ServiceWorkerScriptContext::PostMessageToDocument(
135 const base::string16
& message
,
136 scoped_ptr
<blink::WebMessagePortChannelArray
> channels
) {
137 // This may send channels for MessagePorts, and all internal book-keeping
138 // messages for MessagePort (e.g. QueueMessages) are sent from main thread
139 // (with thread hopping), so we need to do the same thread hopping here not
140 // to overtake those messages.
141 embedded_context_
->main_thread_proxy()->PostTask(
143 base::Bind(&SendPostMessageToDocumentOnMainThread
,
144 make_scoped_refptr(embedded_context_
->thread_safe_sender()),
145 GetRoutingID(), client_id
, message
, base::Passed(&channels
)));
148 void ServiceWorkerScriptContext::Send(IPC::Message
* message
) {
149 embedded_context_
->Send(message
);
152 int ServiceWorkerScriptContext::GetRoutingID() const {
153 return embedded_context_
->embedded_worker_id();
156 void ServiceWorkerScriptContext::OnActivateEvent(int request_id
) {
157 TRACE_EVENT0("ServiceWorker",
158 "ServiceWorkerScriptContext::OnActivateEvent");
159 activate_start_timings_
[request_id
] = base::TimeTicks::Now();
160 proxy_
->dispatchActivateEvent(request_id
);
163 void ServiceWorkerScriptContext::OnInstallEvent(int request_id
,
164 int active_version_id
) {
165 TRACE_EVENT0("ServiceWorker",
166 "ServiceWorkerScriptContext::OnInstallEvent");
167 install_start_timings_
[request_id
] = base::TimeTicks::Now();
168 proxy_
->dispatchInstallEvent(request_id
);
171 void ServiceWorkerScriptContext::OnFetchEvent(
173 const ServiceWorkerFetchRequest
& request
) {
174 blink::WebServiceWorkerRequest webRequest
;
175 TRACE_EVENT0("ServiceWorker",
176 "ServiceWorkerScriptContext::OnFetchEvent");
177 webRequest
.setURL(blink::WebURL(request
.url
));
178 webRequest
.setMethod(blink::WebString::fromUTF8(request
.method
));
179 for (ServiceWorkerHeaderMap::const_iterator it
= request
.headers
.begin();
180 it
!= request
.headers
.end();
182 webRequest
.setHeader(blink::WebString::fromUTF8(it
->first
),
183 blink::WebString::fromUTF8(it
->second
));
185 if (!request
.blob_uuid
.empty()) {
186 webRequest
.setBlob(blink::WebString::fromUTF8(request
.blob_uuid
),
189 webRequest
.setReferrer(blink::WebString::fromUTF8(request
.referrer
.spec()),
190 blink::WebReferrerPolicyDefault
);
191 webRequest
.setMode(GetBlinkFetchRequestMode(request
.mode
));
192 webRequest
.setCredentialsMode(
193 GetBlinkFetchCredentialsMode(request
.credentials_mode
));
194 webRequest
.setIsReload(request
.is_reload
);
195 fetch_start_timings_
[request_id
] = base::TimeTicks::Now();
196 proxy_
->dispatchFetchEvent(request_id
, webRequest
);
199 void ServiceWorkerScriptContext::OnSyncEvent(int request_id
) {
200 TRACE_EVENT0("ServiceWorker",
201 "ServiceWorkerScriptContext::OnSyncEvent");
202 proxy_
->dispatchSyncEvent(request_id
);
205 void ServiceWorkerScriptContext::OnPushEvent(int request_id
,
206 const std::string
& data
) {
207 TRACE_EVENT0("ServiceWorker",
208 "ServiceWorkerScriptContext::OnPushEvent");
209 proxy_
->dispatchPushEvent(request_id
, blink::WebString::fromUTF8(data
));
210 Send(new ServiceWorkerHostMsg_PushEventFinished(
211 GetRoutingID(), request_id
));
214 void ServiceWorkerScriptContext::OnPostMessage(
215 const base::string16
& message
,
216 const std::vector
<int>& sent_message_port_ids
,
217 const std::vector
<int>& new_routing_ids
) {
218 TRACE_EVENT0("ServiceWorker",
219 "ServiceWorkerScriptContext::OnPostEvent");
220 std::vector
<WebMessagePortChannelImpl
*> ports
;
221 if (!sent_message_port_ids
.empty()) {
222 base::MessageLoopProxy
* loop_proxy
= embedded_context_
->main_thread_proxy();
223 ports
.resize(sent_message_port_ids
.size());
224 for (size_t i
= 0; i
< sent_message_port_ids
.size(); ++i
) {
225 ports
[i
] = new WebMessagePortChannelImpl(
226 new_routing_ids
[i
], sent_message_port_ids
[i
], loop_proxy
);
230 // dispatchMessageEvent is expected to execute onmessage function
232 base::TimeTicks before
= base::TimeTicks::Now();
233 proxy_
->dispatchMessageEvent(message
, ports
);
235 "ServiceWorker.MessageEventExecutionTime",
236 base::TimeTicks::Now() - before
);
239 void ServiceWorkerScriptContext::OnDidGetClientDocuments(
240 int request_id
, const std::vector
<int>& client_ids
) {
241 TRACE_EVENT0("ServiceWorker",
242 "ServiceWorkerScriptContext::OnDidGetClientDocuments");
243 blink::WebServiceWorkerClientsCallbacks
* callbacks
=
244 pending_clients_callbacks_
.Lookup(request_id
);
246 NOTREACHED() << "Got stray response: " << request_id
;
249 scoped_ptr
<blink::WebServiceWorkerClientsInfo
> info(
250 new blink::WebServiceWorkerClientsInfo
);
251 info
->clientIDs
= client_ids
;
252 callbacks
->onSuccess(info
.release());
253 pending_clients_callbacks_
.Remove(request_id
);
256 } // namespace content