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