Home | History | Annotate | Download | only in service_worker
      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