Home | History | Annotate | Download | only in shared_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/shared_worker/embedded_shared_worker_stub.h"
      6 
      7 #include "base/message_loop/message_loop_proxy.h"
      8 #include "content/child/appcache/appcache_dispatcher.h"
      9 #include "content/child/appcache/web_application_cache_host_impl.h"
     10 #include "content/child/scoped_child_process_reference.h"
     11 #include "content/child/shared_worker_devtools_agent.h"
     12 #include "content/child/webmessageportchannel_impl.h"
     13 #include "content/common/worker_messages.h"
     14 #include "content/renderer/render_thread_impl.h"
     15 #include "content/renderer/shared_worker/embedded_shared_worker_permission_client_proxy.h"
     16 #include "ipc/ipc_message_macros.h"
     17 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
     18 #include "third_party/WebKit/public/web/WebSharedWorker.h"
     19 #include "third_party/WebKit/public/web/WebSharedWorkerClient.h"
     20 
     21 namespace content {
     22 
     23 namespace {
     24 
     25 class SharedWorkerWebApplicationCacheHostImpl
     26     : public WebApplicationCacheHostImpl {
     27  public:
     28   SharedWorkerWebApplicationCacheHostImpl(
     29       blink::WebApplicationCacheHostClient* client)
     30       : WebApplicationCacheHostImpl(client,
     31                                     RenderThreadImpl::current()
     32                                         ->appcache_dispatcher()
     33                                         ->backend_proxy()) {}
     34 
     35   // Main resource loading is different for workers. The main resource is
     36   // loaded by the worker using WorkerScriptLoader.
     37   // These overrides are stubbed out.
     38   virtual void willStartMainResourceRequest(
     39       blink::WebURLRequest&,
     40       const blink::WebApplicationCacheHost*) {}
     41   virtual void didReceiveResponseForMainResource(const blink::WebURLResponse&) {
     42   }
     43   virtual void didReceiveDataForMainResource(const char* data, int len) {}
     44   virtual void didFinishLoadingMainResource(bool success) {}
     45 
     46   // Cache selection is also different for workers. We know at construction
     47   // time what cache to select and do so then.
     48   // These overrides are stubbed out.
     49   virtual void selectCacheWithoutManifest() {}
     50   virtual bool selectCacheWithManifest(const blink::WebURL& manifestURL) {
     51     return true;
     52   }
     53 };
     54 }
     55 
     56 EmbeddedSharedWorkerStub::EmbeddedSharedWorkerStub(
     57     const GURL& url,
     58     const base::string16& name,
     59     const base::string16& content_security_policy,
     60     blink::WebContentSecurityPolicyType security_policy_type,
     61     bool pause_on_start,
     62     int route_id)
     63     : route_id_(route_id), name_(name), runing_(false), url_(url) {
     64   RenderThreadImpl::current()->AddEmbeddedWorkerRoute(route_id_, this);
     65   impl_ = blink::WebSharedWorker::create(this);
     66   if (pause_on_start) {
     67     // Pause worker context when it starts and wait until either DevTools client
     68     // is attached or explicit resume notification is received.
     69     impl_->pauseWorkerContextOnStart();
     70   }
     71   worker_devtools_agent_.reset(
     72       new SharedWorkerDevToolsAgent(route_id, impl_));
     73   impl_->startWorkerContext(url, name_,
     74                             content_security_policy, security_policy_type);
     75 }
     76 
     77 EmbeddedSharedWorkerStub::~EmbeddedSharedWorkerStub() {
     78   RenderThreadImpl::current()->RemoveEmbeddedWorkerRoute(route_id_);
     79 }
     80 
     81 bool EmbeddedSharedWorkerStub::OnMessageReceived(
     82     const IPC::Message& message) {
     83   if (worker_devtools_agent_->OnMessageReceived(message))
     84     return true;
     85   bool handled = true;
     86   IPC_BEGIN_MESSAGE_MAP(EmbeddedSharedWorkerStub, message)
     87     IPC_MESSAGE_HANDLER(WorkerMsg_TerminateWorkerContext,
     88                         OnTerminateWorkerContext)
     89     IPC_MESSAGE_HANDLER(WorkerMsg_Connect, OnConnect)
     90     IPC_MESSAGE_UNHANDLED(handled = false)
     91   IPC_END_MESSAGE_MAP()
     92   return handled;
     93 }
     94 
     95 void EmbeddedSharedWorkerStub::OnChannelError() {
     96   OnTerminateWorkerContext();
     97 }
     98 
     99 void EmbeddedSharedWorkerStub::workerReadyForInspection() {
    100   Send(new WorkerHostMsg_WorkerReadyForInspection(route_id_));
    101 }
    102 
    103 void EmbeddedSharedWorkerStub::workerScriptLoaded() {
    104   Send(new WorkerHostMsg_WorkerScriptLoaded(route_id_));
    105   runing_ = true;
    106   // Process any pending connections.
    107   for (PendingChannelList::const_iterator iter = pending_channels_.begin();
    108        iter != pending_channels_.end();
    109        ++iter) {
    110     ConnectToChannel(*iter);
    111   }
    112   pending_channels_.clear();
    113 }
    114 
    115 void EmbeddedSharedWorkerStub::workerScriptLoadFailed() {
    116   Send(new WorkerHostMsg_WorkerScriptLoadFailed(route_id_));
    117   for (PendingChannelList::const_iterator iter = pending_channels_.begin();
    118        iter != pending_channels_.end();
    119        ++iter) {
    120     blink::WebMessagePortChannel* channel = *iter;
    121     channel->destroy();
    122   }
    123   pending_channels_.clear();
    124   Shutdown();
    125 }
    126 
    127 void EmbeddedSharedWorkerStub::workerContextClosed() {
    128   Send(new WorkerHostMsg_WorkerContextClosed(route_id_));
    129 }
    130 
    131 void EmbeddedSharedWorkerStub::workerContextDestroyed() {
    132   Send(new WorkerHostMsg_WorkerContextDestroyed(route_id_));
    133   Shutdown();
    134 }
    135 
    136 void EmbeddedSharedWorkerStub::selectAppCacheID(long long app_cache_id) {
    137   if (app_cache_host_) {
    138     // app_cache_host_ could become stale as it's owned by blink's
    139     // DocumentLoader. This method is assumed to be called while it's valid.
    140     app_cache_host_->backend()->SelectCacheForSharedWorker(
    141         app_cache_host_->host_id(), app_cache_id);
    142   }
    143 }
    144 
    145 blink::WebNotificationPresenter*
    146 EmbeddedSharedWorkerStub::notificationPresenter() {
    147   // TODO(horo): delete this method if we have no plan to implement this.
    148   NOTREACHED();
    149   return NULL;
    150 }
    151 
    152 blink::WebApplicationCacheHost*
    153 EmbeddedSharedWorkerStub::createApplicationCacheHost(
    154     blink::WebApplicationCacheHostClient* client) {
    155   app_cache_host_ = new SharedWorkerWebApplicationCacheHostImpl(client);
    156   return app_cache_host_;
    157 }
    158 
    159 blink::WebWorkerPermissionClientProxy*
    160     EmbeddedSharedWorkerStub::createWorkerPermissionClientProxy(
    161     const blink::WebSecurityOrigin& origin) {
    162   return new EmbeddedSharedWorkerPermissionClientProxy(
    163       GURL(origin.toString()),
    164       origin.isUnique(),
    165       route_id_,
    166       ChildThread::current()->thread_safe_sender());
    167 }
    168 
    169 void EmbeddedSharedWorkerStub::dispatchDevToolsMessage(
    170       const blink::WebString& message) {
    171   worker_devtools_agent_->SendDevToolsMessage(message);
    172 }
    173 
    174 void EmbeddedSharedWorkerStub::saveDevToolsAgentState(
    175       const blink::WebString& state) {
    176   worker_devtools_agent_->SaveDevToolsAgentState(state);
    177 }
    178 
    179 void EmbeddedSharedWorkerStub::Shutdown() {
    180   delete this;
    181 }
    182 
    183 bool EmbeddedSharedWorkerStub::Send(IPC::Message* message) {
    184   return RenderThreadImpl::current()->Send(message);
    185 }
    186 
    187 void EmbeddedSharedWorkerStub::ConnectToChannel(
    188     WebMessagePortChannelImpl* channel) {
    189   impl_->connect(channel);
    190   Send(
    191       new WorkerHostMsg_WorkerConnected(channel->message_port_id(), route_id_));
    192 }
    193 
    194 void EmbeddedSharedWorkerStub::OnConnect(int sent_message_port_id,
    195                                          int routing_id) {
    196   WebMessagePortChannelImpl* channel =
    197       new WebMessagePortChannelImpl(routing_id,
    198                                     sent_message_port_id,
    199                                     base::MessageLoopProxy::current().get());
    200   if (runing_) {
    201     ConnectToChannel(channel);
    202   } else {
    203     // If two documents try to load a SharedWorker at the same time, the
    204     // WorkerMsg_Connect for one of the documents can come in before the
    205     // worker is started. Just queue up the connect and deliver it once the
    206     // worker starts.
    207     pending_channels_.push_back(channel);
    208   }
    209 }
    210 
    211 void EmbeddedSharedWorkerStub::OnTerminateWorkerContext() {
    212   runing_ = false;
    213   impl_->terminateWorkerContext();
    214 }
    215 
    216 }  // namespace content
    217