Home | History | Annotate | Download | only in worker
      1 // Copyright (c) 2012 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/worker/websharedworker_stub.h"
      6 
      7 #include "base/compiler_specific.h"
      8 #include "content/child/child_process.h"
      9 #include "content/child/child_thread.h"
     10 #include "content/child/fileapi/file_system_dispatcher.h"
     11 #include "content/child/webmessageportchannel_impl.h"
     12 #include "content/common/worker_messages.h"
     13 #include "content/worker/shared_worker_devtools_agent.h"
     14 #include "content/worker/worker_thread.h"
     15 #include "third_party/WebKit/public/web/WebSharedWorker.h"
     16 #include "third_party/WebKit/public/platform/WebString.h"
     17 #include "third_party/WebKit/public/platform/WebURL.h"
     18 
     19 namespace content {
     20 
     21 WebSharedWorkerStub::WebSharedWorkerStub(
     22     const string16& name,
     23     int route_id,
     24     const WorkerAppCacheInitInfo& appcache_init_info)
     25     : route_id_(route_id),
     26       appcache_init_info_(appcache_init_info),
     27       client_(route_id, this),
     28       name_(name),
     29       started_(false) {
     30 
     31   WorkerThread* worker_thread = WorkerThread::current();
     32   DCHECK(worker_thread);
     33   worker_thread->AddWorkerStub(this);
     34   // Start processing incoming IPCs for this worker.
     35   worker_thread->AddRoute(route_id_, this);
     36   ChildProcess::current()->AddRefProcess();
     37 
     38   // TODO(atwilson): Add support for NaCl when they support MessagePorts.
     39   impl_ = WebKit::WebSharedWorker::create(client());
     40   worker_devtools_agent_.reset(new SharedWorkerDevToolsAgent(route_id, impl_));
     41   client()->set_devtools_agent(worker_devtools_agent_.get());
     42 }
     43 
     44 WebSharedWorkerStub::~WebSharedWorkerStub() {
     45   impl_->clientDestroyed();
     46   WorkerThread* worker_thread = WorkerThread::current();
     47   DCHECK(worker_thread);
     48   worker_thread->RemoveWorkerStub(this);
     49   worker_thread->RemoveRoute(route_id_);
     50   ChildProcess::current()->ReleaseProcess();
     51 }
     52 
     53 void WebSharedWorkerStub::Shutdown() {
     54   // The worker has exited - free ourselves and the client.
     55   delete this;
     56 }
     57 
     58 void WebSharedWorkerStub::EnsureWorkerContextTerminates() {
     59   client_.EnsureWorkerContextTerminates();
     60 }
     61 
     62 bool WebSharedWorkerStub::OnMessageReceived(const IPC::Message& message) {
     63   if (worker_devtools_agent_->OnMessageReceived(message))
     64     return true;
     65 
     66   bool handled = true;
     67   IPC_BEGIN_MESSAGE_MAP(WebSharedWorkerStub, message)
     68     IPC_MESSAGE_HANDLER(WorkerMsg_StartWorkerContext, OnStartWorkerContext)
     69     IPC_MESSAGE_HANDLER(WorkerMsg_TerminateWorkerContext,
     70                         OnTerminateWorkerContext)
     71     IPC_MESSAGE_HANDLER(WorkerMsg_Connect, OnConnect)
     72     IPC_MESSAGE_UNHANDLED(handled = false)
     73   IPC_END_MESSAGE_MAP()
     74   return handled;
     75 }
     76 
     77 void WebSharedWorkerStub::OnChannelError() {
     78     OnTerminateWorkerContext();
     79 }
     80 
     81 const GURL& WebSharedWorkerStub::url() {
     82   return url_;
     83 }
     84 
     85 void WebSharedWorkerStub::OnStartWorkerContext(
     86     const GURL& url, const string16& user_agent, const string16& source_code,
     87     const string16& content_security_policy,
     88     WebKit::WebContentSecurityPolicyType policy_type) {
     89   // Ignore multiple attempts to start this worker (can happen if two pages
     90   // try to start it simultaneously).
     91   if (started_)
     92     return;
     93 
     94   impl_->startWorkerContext(url, name_, user_agent, source_code,
     95                             content_security_policy, policy_type, 0);
     96   started_ = true;
     97   url_ = url;
     98 
     99   // Process any pending connections.
    100   for (PendingConnectInfoList::const_iterator iter = pending_connects_.begin();
    101        iter != pending_connects_.end();
    102        ++iter) {
    103     OnConnect(iter->first, iter->second);
    104   }
    105   pending_connects_.clear();
    106 }
    107 
    108 void WebSharedWorkerStub::OnConnect(int sent_message_port_id, int routing_id) {
    109   if (started_) {
    110     WebKit::WebMessagePortChannel* channel =
    111         new WebMessagePortChannelImpl(routing_id,
    112                                       sent_message_port_id,
    113                                       base::MessageLoopProxy::current().get());
    114     impl_->connect(channel, NULL);
    115   } else {
    116     // If two documents try to load a SharedWorker at the same time, the
    117     // WorkerMsg_Connect for one of the documents can come in before the
    118     // worker is started. Just queue up the connect and deliver it once the
    119     // worker starts.
    120     PendingConnectInfo pending_connect(sent_message_port_id, routing_id);
    121     pending_connects_.push_back(pending_connect);
    122   }
    123 }
    124 
    125 void WebSharedWorkerStub::OnTerminateWorkerContext() {
    126   impl_->terminateWorkerContext();
    127 
    128   // Call the client to make sure context exits.
    129   EnsureWorkerContextTerminates();
    130   started_ = false;
    131 }
    132 
    133 }  // namespace content
    134