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 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 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 48 ServiceWorkerScriptContext::~ServiceWorkerScriptContext() {} 49 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 73 void ServiceWorkerScriptContext::DidHandleActivateEvent( 74 int request_id, 75 blink::WebServiceWorkerEventResult result) { 76 Send(new ServiceWorkerHostMsg_ActivateEventFinished( 77 GetRoutingID(), request_id, result)); 78 } 79 80 void ServiceWorkerScriptContext::DidHandleInstallEvent( 81 int request_id, 82 blink::WebServiceWorkerEventResult result) { 83 Send(new ServiceWorkerHostMsg_InstallEventFinished( 84 GetRoutingID(), request_id, result)); 85 } 86 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 95 void ServiceWorkerScriptContext::DidHandleSyncEvent(int request_id) { 96 Send(new ServiceWorkerHostMsg_SyncEventFinished( 97 GetRoutingID(), request_id)); 98 } 99 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 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 123 void ServiceWorkerScriptContext::Send(IPC::Message* message) { 124 embedded_context_->Send(message); 125 } 126 127 int ServiceWorkerScriptContext::GetRoutingID() const { 128 return embedded_context_->embedded_worker_id(); 129 } 130 131 void ServiceWorkerScriptContext::OnActivateEvent(int request_id) { 132 TRACE_EVENT0("ServiceWorker", 133 "ServiceWorkerScriptContext::OnActivateEvent"); 134 proxy_->dispatchActivateEvent(request_id); 135 } 136 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 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 168 void ServiceWorkerScriptContext::OnSyncEvent(int request_id) { 169 TRACE_EVENT0("ServiceWorker", 170 "ServiceWorkerScriptContext::OnSyncEvent"); 171 proxy_->dispatchSyncEvent(request_id); 172 } 173 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 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 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