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.
4
5 #include "content/renderer/service_worker/service_worker_script_context.h"
6
7 #include <map>
8
9 #include "base/debug/trace_event.h"
10 #include "base/logging.h"
11 #include "content/child/thread_safe_sender.h"
12 #include "content/child/webmessageportchannel_impl.h"
13 #include "content/common/service_worker/service_worker_messages.h"
14 #include "content/renderer/service_worker/embedded_worker_context_client.h"
15 #include "ipc/ipc_message.h"
16 #include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
17 #include "third_party/WebKit/public/platform/WebServiceWorkerRequest.h"
18 #include "third_party/WebKit/public/platform/WebString.h"
19 #include "third_party/WebKit/public/platform/WebURL.h"
20 #include "third_party/WebKit/public/web/WebServiceWorkerContextClient.h"
21 #include "third_party/WebKit/public/web/WebServiceWorkerContextProxy.h"
22
23 namespace content {
24
25 namespace {
26
SendPostMessageToDocumentOnMainThread(ThreadSafeSender * sender,int routing_id,int client_id,const base::string16 & message,scoped_ptr<blink::WebMessagePortChannelArray> channels)27 void SendPostMessageToDocumentOnMainThread(
28 ThreadSafeSender* sender,
29 int routing_id,
30 int client_id,
31 const base::string16& message,
32 scoped_ptr<blink::WebMessagePortChannelArray> channels) {
33 sender->Send(new ServiceWorkerHostMsg_PostMessageToDocument(
34 routing_id, client_id, message,
35 WebMessagePortChannelImpl::ExtractMessagePortIDs(channels.release())));
36 }
37
38 } // namespace
39
ServiceWorkerScriptContext(EmbeddedWorkerContextClient * embedded_context,blink::WebServiceWorkerContextProxy * proxy)40 ServiceWorkerScriptContext::ServiceWorkerScriptContext(
41 EmbeddedWorkerContextClient* embedded_context,
42 blink::WebServiceWorkerContextProxy* proxy)
43 : cache_storage_dispatcher_(new ServiceWorkerCacheStorageDispatcher(this)),
44 embedded_context_(embedded_context),
45 proxy_(proxy) {
46 }
47
~ServiceWorkerScriptContext()48 ServiceWorkerScriptContext::~ServiceWorkerScriptContext() {}
49
OnMessageReceived(const IPC::Message & message)50 void ServiceWorkerScriptContext::OnMessageReceived(
51 const IPC::Message& message) {
52 bool handled = true;
53 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerScriptContext, message)
54 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ActivateEvent, OnActivateEvent)
55 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FetchEvent, OnFetchEvent)
56 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_InstallEvent, OnInstallEvent)
57 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SyncEvent, OnSyncEvent)
58 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_PushEvent, OnPushEvent)
59 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToWorker, OnPostMessage)
60 IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetClientDocuments,
61 OnDidGetClientDocuments)
62 IPC_MESSAGE_UNHANDLED(handled = false)
63 IPC_END_MESSAGE_MAP()
64
65 // TODO(gavinp): Would it be preferable to put an AddListener() method to
66 // EmbeddedWorkerContextClient?
67 if (!handled)
68 handled = cache_storage_dispatcher_->OnMessageReceived(message);
69
70 DCHECK(handled);
71 }
72
DidHandleActivateEvent(int request_id,blink::WebServiceWorkerEventResult result)73 void ServiceWorkerScriptContext::DidHandleActivateEvent(
74 int request_id,
75 blink::WebServiceWorkerEventResult result) {
76 Send(new ServiceWorkerHostMsg_ActivateEventFinished(
77 GetRoutingID(), request_id, result));
78 }
79
DidHandleInstallEvent(int request_id,blink::WebServiceWorkerEventResult result)80 void ServiceWorkerScriptContext::DidHandleInstallEvent(
81 int request_id,
82 blink::WebServiceWorkerEventResult result) {
83 Send(new ServiceWorkerHostMsg_InstallEventFinished(
84 GetRoutingID(), request_id, result));
85 }
86
DidHandleFetchEvent(int request_id,ServiceWorkerFetchEventResult result,const ServiceWorkerResponse & response)87 void ServiceWorkerScriptContext::DidHandleFetchEvent(
88 int request_id,
89 ServiceWorkerFetchEventResult result,
90 const ServiceWorkerResponse& response) {
91 Send(new ServiceWorkerHostMsg_FetchEventFinished(
92 GetRoutingID(), request_id, result, response));
93 }
94
DidHandleSyncEvent(int request_id)95 void ServiceWorkerScriptContext::DidHandleSyncEvent(int request_id) {
96 Send(new ServiceWorkerHostMsg_SyncEventFinished(
97 GetRoutingID(), request_id));
98 }
99
GetClientDocuments(blink::WebServiceWorkerClientsCallbacks * callbacks)100 void ServiceWorkerScriptContext::GetClientDocuments(
101 blink::WebServiceWorkerClientsCallbacks* callbacks) {
102 DCHECK(callbacks);
103 int request_id = pending_clients_callbacks_.Add(callbacks);
104 Send(new ServiceWorkerHostMsg_GetClientDocuments(
105 GetRoutingID(), request_id));
106 }
107
PostMessageToDocument(int client_id,const base::string16 & message,scoped_ptr<blink::WebMessagePortChannelArray> channels)108 void ServiceWorkerScriptContext::PostMessageToDocument(
109 int client_id,
110 const base::string16& message,
111 scoped_ptr<blink::WebMessagePortChannelArray> channels) {
112 // This may send channels for MessagePorts, and all internal book-keeping
113 // messages for MessagePort (e.g. QueueMessages) are sent from main thread
114 // (with thread hopping), so we need to do the same thread hopping here not
115 // to overtake those messages.
116 embedded_context_->main_thread_proxy()->PostTask(
117 FROM_HERE,
118 base::Bind(&SendPostMessageToDocumentOnMainThread,
119 make_scoped_refptr(embedded_context_->thread_safe_sender()),
120 GetRoutingID(), client_id, message, base::Passed(&channels)));
121 }
122
Send(IPC::Message * message)123 void ServiceWorkerScriptContext::Send(IPC::Message* message) {
124 embedded_context_->Send(message);
125 }
126
GetRoutingID() const127 int ServiceWorkerScriptContext::GetRoutingID() const {
128 return embedded_context_->embedded_worker_id();
129 }
130
OnActivateEvent(int request_id)131 void ServiceWorkerScriptContext::OnActivateEvent(int request_id) {
132 TRACE_EVENT0("ServiceWorker",
133 "ServiceWorkerScriptContext::OnActivateEvent");
134 proxy_->dispatchActivateEvent(request_id);
135 }
136
OnInstallEvent(int request_id,int active_version_id)137 void ServiceWorkerScriptContext::OnInstallEvent(int request_id,
138 int active_version_id) {
139 TRACE_EVENT0("ServiceWorker",
140 "ServiceWorkerScriptContext::OnInstallEvent");
141 proxy_->dispatchInstallEvent(request_id);
142 }
143
OnFetchEvent(int request_id,const ServiceWorkerFetchRequest & request)144 void ServiceWorkerScriptContext::OnFetchEvent(
145 int request_id,
146 const ServiceWorkerFetchRequest& request) {
147 blink::WebServiceWorkerRequest webRequest;
148 TRACE_EVENT0("ServiceWorker",
149 "ServiceWorkerScriptContext::OnFetchEvent");
150 webRequest.setURL(blink::WebURL(request.url));
151 webRequest.setMethod(blink::WebString::fromUTF8(request.method));
152 for (ServiceWorkerHeaderMap::const_iterator it = request.headers.begin();
153 it != request.headers.end();
154 ++it) {
155 webRequest.setHeader(blink::WebString::fromUTF8(it->first),
156 blink::WebString::fromUTF8(it->second));
157 }
158 if (!request.blob_uuid.empty()) {
159 webRequest.setBlob(blink::WebString::fromUTF8(request.blob_uuid),
160 request.blob_size);
161 }
162 webRequest.setReferrer(blink::WebString::fromUTF8(request.referrer.spec()),
163 blink::WebReferrerPolicyDefault);
164 webRequest.setIsReload(request.is_reload);
165 proxy_->dispatchFetchEvent(request_id, webRequest);
166 }
167
OnSyncEvent(int request_id)168 void ServiceWorkerScriptContext::OnSyncEvent(int request_id) {
169 TRACE_EVENT0("ServiceWorker",
170 "ServiceWorkerScriptContext::OnSyncEvent");
171 proxy_->dispatchSyncEvent(request_id);
172 }
173
OnPushEvent(int request_id,const std::string & data)174 void ServiceWorkerScriptContext::OnPushEvent(int request_id,
175 const std::string& data) {
176 TRACE_EVENT0("ServiceWorker",
177 "ServiceWorkerScriptContext::OnPushEvent");
178 proxy_->dispatchPushEvent(request_id, blink::WebString::fromUTF8(data));
179 Send(new ServiceWorkerHostMsg_PushEventFinished(
180 GetRoutingID(), request_id));
181 }
182
OnPostMessage(const base::string16 & message,const std::vector<int> & sent_message_port_ids,const std::vector<int> & new_routing_ids)183 void ServiceWorkerScriptContext::OnPostMessage(
184 const base::string16& message,
185 const std::vector<int>& sent_message_port_ids,
186 const std::vector<int>& new_routing_ids) {
187 TRACE_EVENT0("ServiceWorker",
188 "ServiceWorkerScriptContext::OnPostEvent");
189 std::vector<WebMessagePortChannelImpl*> ports;
190 if (!sent_message_port_ids.empty()) {
191 base::MessageLoopProxy* loop_proxy = embedded_context_->main_thread_proxy();
192 ports.resize(sent_message_port_ids.size());
193 for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
194 ports[i] = new WebMessagePortChannelImpl(
195 new_routing_ids[i], sent_message_port_ids[i], loop_proxy);
196 }
197 }
198
199 proxy_->dispatchMessageEvent(message, ports);
200 }
201
OnDidGetClientDocuments(int request_id,const std::vector<int> & client_ids)202 void ServiceWorkerScriptContext::OnDidGetClientDocuments(
203 int request_id, const std::vector<int>& client_ids) {
204 TRACE_EVENT0("ServiceWorker",
205 "ServiceWorkerScriptContext::OnDidGetClientDocuments");
206 blink::WebServiceWorkerClientsCallbacks* callbacks =
207 pending_clients_callbacks_.Lookup(request_id);
208 if (!callbacks) {
209 NOTREACHED() << "Got stray response: " << request_id;
210 return;
211 }
212 scoped_ptr<blink::WebServiceWorkerClientsInfo> info(
213 new blink::WebServiceWorkerClientsInfo);
214 info->clientIDs = client_ids;
215 callbacks->onSuccess(info.release());
216 pending_clients_callbacks_.Remove(request_id);
217 }
218
219 } // namespace content
220