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
>(
48 blink::WebURLRequest::RequestContext
GetBlinkRequestContext(
49 RequestContextType request_context_type
) {
50 return static_cast<blink::WebURLRequest::RequestContext
>(
51 request_context_type
);
54 blink::WebURLRequest::FrameType
GetBlinkFrameType(
55 RequestContextFrameType frame_type
) {
56 return static_cast<blink::WebURLRequest::FrameType
>(frame_type
);
61 ServiceWorkerScriptContext::ServiceWorkerScriptContext(
62 EmbeddedWorkerContextClient
* embedded_context
,
63 blink::WebServiceWorkerContextProxy
* proxy
)
64 : cache_storage_dispatcher_(new ServiceWorkerCacheStorageDispatcher(this)),
65 embedded_context_(embedded_context
),
69 ServiceWorkerScriptContext::~ServiceWorkerScriptContext() {}
71 void ServiceWorkerScriptContext::OnMessageReceived(
72 const IPC::Message
& message
) {
74 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerScriptContext
, message
)
75 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ActivateEvent
, OnActivateEvent
)
76 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FetchEvent
, OnFetchEvent
)
77 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_InstallEvent
, OnInstallEvent
)
78 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SyncEvent
, OnSyncEvent
)
79 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_PushEvent
, OnPushEvent
)
80 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToWorker
, OnPostMessage
)
81 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetClientDocuments
,
82 OnDidGetClientDocuments
)
83 IPC_MESSAGE_UNHANDLED(handled
= false)
86 // TODO(gavinp): Would it be preferable to put an AddListener() method to
87 // EmbeddedWorkerContextClient?
89 handled
= cache_storage_dispatcher_
->OnMessageReceived(message
);
94 void ServiceWorkerScriptContext::DidHandleActivateEvent(
96 blink::WebServiceWorkerEventResult result
) {
98 "ServiceWorker.ActivateEventExecutionTime",
99 base::TimeTicks::Now() - activate_start_timings_
[request_id
]);
100 activate_start_timings_
.erase(request_id
);
102 Send(new ServiceWorkerHostMsg_ActivateEventFinished(
103 GetRoutingID(), request_id
, result
));
106 void ServiceWorkerScriptContext::DidHandleInstallEvent(
108 blink::WebServiceWorkerEventResult result
) {
110 "ServiceWorker.InstallEventExecutionTime",
111 base::TimeTicks::Now() - install_start_timings_
[request_id
]);
112 install_start_timings_
.erase(request_id
);
114 Send(new ServiceWorkerHostMsg_InstallEventFinished(
115 GetRoutingID(), request_id
, result
));
118 void ServiceWorkerScriptContext::DidHandleFetchEvent(
120 ServiceWorkerFetchEventResult result
,
121 const ServiceWorkerResponse
& response
) {
123 "ServiceWorker.FetchEventExecutionTime",
124 base::TimeTicks::Now() - fetch_start_timings_
[request_id
]);
125 fetch_start_timings_
.erase(request_id
);
127 Send(new ServiceWorkerHostMsg_FetchEventFinished(
128 GetRoutingID(), request_id
, result
, response
));
131 void ServiceWorkerScriptContext::DidHandleSyncEvent(int request_id
) {
132 Send(new ServiceWorkerHostMsg_SyncEventFinished(
133 GetRoutingID(), request_id
));
136 void ServiceWorkerScriptContext::GetClientDocuments(
137 blink::WebServiceWorkerClientsCallbacks
* callbacks
) {
139 int request_id
= pending_clients_callbacks_
.Add(callbacks
);
140 Send(new ServiceWorkerHostMsg_GetClientDocuments(
141 GetRoutingID(), request_id
));
144 void ServiceWorkerScriptContext::PostMessageToDocument(
146 const base::string16
& message
,
147 scoped_ptr
<blink::WebMessagePortChannelArray
> channels
) {
148 // This may send channels for MessagePorts, and all internal book-keeping
149 // messages for MessagePort (e.g. QueueMessages) are sent from main thread
150 // (with thread hopping), so we need to do the same thread hopping here not
151 // to overtake those messages.
152 embedded_context_
->main_thread_proxy()->PostTask(
154 base::Bind(&SendPostMessageToDocumentOnMainThread
,
155 make_scoped_refptr(embedded_context_
->thread_safe_sender()),
156 GetRoutingID(), client_id
, message
, base::Passed(&channels
)));
159 void ServiceWorkerScriptContext::Send(IPC::Message
* message
) {
160 embedded_context_
->Send(message
);
163 int ServiceWorkerScriptContext::GetRoutingID() const {
164 return embedded_context_
->embedded_worker_id();
167 void ServiceWorkerScriptContext::OnActivateEvent(int request_id
) {
168 TRACE_EVENT0("ServiceWorker",
169 "ServiceWorkerScriptContext::OnActivateEvent");
170 activate_start_timings_
[request_id
] = base::TimeTicks::Now();
171 proxy_
->dispatchActivateEvent(request_id
);
174 void ServiceWorkerScriptContext::OnInstallEvent(int request_id
,
175 int active_version_id
) {
176 TRACE_EVENT0("ServiceWorker",
177 "ServiceWorkerScriptContext::OnInstallEvent");
178 install_start_timings_
[request_id
] = base::TimeTicks::Now();
179 proxy_
->dispatchInstallEvent(request_id
);
182 void ServiceWorkerScriptContext::OnFetchEvent(
184 const ServiceWorkerFetchRequest
& request
) {
185 blink::WebServiceWorkerRequest webRequest
;
186 TRACE_EVENT0("ServiceWorker",
187 "ServiceWorkerScriptContext::OnFetchEvent");
188 webRequest
.setURL(blink::WebURL(request
.url
));
189 webRequest
.setMethod(blink::WebString::fromUTF8(request
.method
));
190 for (ServiceWorkerHeaderMap::const_iterator it
= request
.headers
.begin();
191 it
!= request
.headers
.end();
193 webRequest
.setHeader(blink::WebString::fromUTF8(it
->first
),
194 blink::WebString::fromUTF8(it
->second
));
196 if (!request
.blob_uuid
.empty()) {
197 webRequest
.setBlob(blink::WebString::fromUTF8(request
.blob_uuid
),
200 webRequest
.setReferrer(blink::WebString::fromUTF8(request
.referrer
.spec()),
201 blink::WebReferrerPolicyDefault
);
202 webRequest
.setMode(GetBlinkFetchRequestMode(request
.mode
));
203 webRequest
.setCredentialsMode(
204 GetBlinkFetchCredentialsMode(request
.credentials_mode
));
205 webRequest
.setRequestContext(
206 GetBlinkRequestContext(request
.request_context_type
));
207 webRequest
.setFrameType(GetBlinkFrameType(request
.frame_type
));
208 webRequest
.setIsReload(request
.is_reload
);
209 fetch_start_timings_
[request_id
] = base::TimeTicks::Now();
210 proxy_
->dispatchFetchEvent(request_id
, webRequest
);
213 void ServiceWorkerScriptContext::OnSyncEvent(int request_id
) {
214 TRACE_EVENT0("ServiceWorker",
215 "ServiceWorkerScriptContext::OnSyncEvent");
216 proxy_
->dispatchSyncEvent(request_id
);
219 void ServiceWorkerScriptContext::OnPushEvent(int request_id
,
220 const std::string
& data
) {
221 TRACE_EVENT0("ServiceWorker",
222 "ServiceWorkerScriptContext::OnPushEvent");
223 proxy_
->dispatchPushEvent(request_id
, blink::WebString::fromUTF8(data
));
224 Send(new ServiceWorkerHostMsg_PushEventFinished(
225 GetRoutingID(), request_id
));
228 void ServiceWorkerScriptContext::OnPostMessage(
229 const base::string16
& message
,
230 const std::vector
<int>& sent_message_port_ids
,
231 const std::vector
<int>& new_routing_ids
) {
232 TRACE_EVENT0("ServiceWorker",
233 "ServiceWorkerScriptContext::OnPostEvent");
234 std::vector
<WebMessagePortChannelImpl
*> ports
;
235 if (!sent_message_port_ids
.empty()) {
236 base::MessageLoopProxy
* loop_proxy
= embedded_context_
->main_thread_proxy();
237 ports
.resize(sent_message_port_ids
.size());
238 for (size_t i
= 0; i
< sent_message_port_ids
.size(); ++i
) {
239 ports
[i
] = new WebMessagePortChannelImpl(
240 new_routing_ids
[i
], sent_message_port_ids
[i
], loop_proxy
);
244 // dispatchMessageEvent is expected to execute onmessage function
246 base::TimeTicks before
= base::TimeTicks::Now();
247 proxy_
->dispatchMessageEvent(message
, ports
);
249 "ServiceWorker.MessageEventExecutionTime",
250 base::TimeTicks::Now() - before
);
253 void ServiceWorkerScriptContext::OnDidGetClientDocuments(
254 int request_id
, const std::vector
<int>& client_ids
) {
255 TRACE_EVENT0("ServiceWorker",
256 "ServiceWorkerScriptContext::OnDidGetClientDocuments");
257 blink::WebServiceWorkerClientsCallbacks
* callbacks
=
258 pending_clients_callbacks_
.Lookup(request_id
);
260 NOTREACHED() << "Got stray response: " << request_id
;
263 scoped_ptr
<blink::WebServiceWorkerClientsInfo
> info(
264 new blink::WebServiceWorkerClientsInfo
);
265 info
->clientIDs
= client_ids
;
266 callbacks
->onSuccess(info
.release());
267 pending_clients_callbacks_
.Remove(request_id
);
270 } // namespace content