• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/command_line.h"
8 #include "base/compiler_specific.h"
9 #include "content/child/child_process.h"
10 #include "content/child/child_thread.h"
11 #include "content/child/fileapi/file_system_dispatcher.h"
12 #include "content/child/shared_worker_devtools_agent.h"
13 #include "content/child/webmessageportchannel_impl.h"
14 #include "content/common/worker_messages.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/worker/worker_thread.h"
17 #include "third_party/WebKit/public/platform/WebString.h"
18 #include "third_party/WebKit/public/platform/WebURL.h"
19 #include "third_party/WebKit/public/web/WebSharedWorker.h"
20 
21 namespace content {
22 
WebSharedWorkerStub(const GURL & url,const base::string16 & name,const base::string16 & content_security_policy,blink::WebContentSecurityPolicyType security_policy_type,bool pause_on_start,int route_id)23 WebSharedWorkerStub::WebSharedWorkerStub(
24     const GURL& url,
25     const base::string16& name,
26     const base::string16& content_security_policy,
27     blink::WebContentSecurityPolicyType security_policy_type,
28     bool pause_on_start,
29     int route_id)
30     : route_id_(route_id),
31       client_(route_id, this),
32       running_(false),
33       url_(url) {
34 
35   WorkerThread* worker_thread = WorkerThread::current();
36   DCHECK(worker_thread);
37   worker_thread->AddWorkerStub(this);
38   // Start processing incoming IPCs for this worker.
39   worker_thread->GetRouter()->AddRoute(route_id_, this);
40 
41   // TODO(atwilson): Add support for NaCl when they support MessagePorts.
42   impl_ = blink::WebSharedWorker::create(client());
43   if (pause_on_start) {
44     // Pause worker context when it starts and wait until either DevTools client
45     // is attached or explicit resume notification is received.
46     impl_->pauseWorkerContextOnStart();
47   }
48 
49   worker_devtools_agent_.reset(new SharedWorkerDevToolsAgent(route_id, impl_));
50   client()->set_devtools_agent(worker_devtools_agent_.get());
51   impl_->startWorkerContext(url_, name,
52                             content_security_policy, security_policy_type);
53 }
54 
~WebSharedWorkerStub()55 WebSharedWorkerStub::~WebSharedWorkerStub() {
56   impl_->clientDestroyed();
57   WorkerThread* worker_thread = WorkerThread::current();
58   DCHECK(worker_thread);
59   worker_thread->RemoveWorkerStub(this);
60   worker_thread->GetRouter()->RemoveRoute(route_id_);
61 }
62 
Shutdown()63 void WebSharedWorkerStub::Shutdown() {
64   // The worker has exited - free ourselves and the client.
65   delete this;
66 }
67 
EnsureWorkerContextTerminates()68 void WebSharedWorkerStub::EnsureWorkerContextTerminates() {
69   client_.EnsureWorkerContextTerminates();
70 }
71 
OnMessageReceived(const IPC::Message & message)72 bool WebSharedWorkerStub::OnMessageReceived(const IPC::Message& message) {
73   if (worker_devtools_agent_->OnMessageReceived(message))
74     return true;
75 
76   bool handled = true;
77   IPC_BEGIN_MESSAGE_MAP(WebSharedWorkerStub, message)
78     IPC_MESSAGE_HANDLER(WorkerMsg_TerminateWorkerContext,
79                         OnTerminateWorkerContext)
80     IPC_MESSAGE_HANDLER(WorkerMsg_Connect, OnConnect)
81     IPC_MESSAGE_UNHANDLED(handled = false)
82   IPC_END_MESSAGE_MAP()
83   return handled;
84 }
85 
OnChannelError()86 void WebSharedWorkerStub::OnChannelError() {
87     OnTerminateWorkerContext();
88 }
89 
url()90 const GURL& WebSharedWorkerStub::url() {
91   return url_;
92 }
93 
OnConnect(int sent_message_port_id,int routing_id)94 void WebSharedWorkerStub::OnConnect(int sent_message_port_id, int routing_id) {
95   WebMessagePortChannelImpl* channel =
96       new WebMessagePortChannelImpl(routing_id,
97                                     sent_message_port_id,
98                                     base::MessageLoopProxy::current().get());
99   if (running_) {
100     impl_->connect(channel);
101     WorkerThread::current()->Send(
102         new WorkerHostMsg_WorkerConnected(channel->message_port_id(),
103                                           route_id_));
104   } else {
105     // If two documents try to load a SharedWorker at the same time, the
106     // WorkerMsg_Connect for one of the documents can come in before the
107     // worker is started. Just queue up the connect and deliver it once the
108     // worker starts.
109     pending_channels_.push_back(channel);
110   }
111 }
112 
OnTerminateWorkerContext()113 void WebSharedWorkerStub::OnTerminateWorkerContext() {
114   running_ = false;
115   // Call the client to make sure context exits.
116   EnsureWorkerContextTerminates();
117   // This may call "delete this" via WorkerScriptLoadFailed and Shutdown.
118   impl_->terminateWorkerContext();
119 }
120 
WorkerScriptLoaded()121 void WebSharedWorkerStub::WorkerScriptLoaded() {
122   running_ = true;
123   // Process any pending connections.
124   for (PendingChannelList::const_iterator iter = pending_channels_.begin();
125        iter != pending_channels_.end();
126        ++iter) {
127     impl_->connect(*iter);
128     WorkerThread::current()->Send(
129         new WorkerHostMsg_WorkerConnected((*iter)->message_port_id(),
130                                           route_id_));
131   }
132   pending_channels_.clear();
133 }
134 
WorkerScriptLoadFailed()135 void WebSharedWorkerStub::WorkerScriptLoadFailed() {
136   for (PendingChannelList::const_iterator iter = pending_channels_.begin();
137        iter != pending_channels_.end();
138        ++iter) {
139     blink::WebMessagePortChannel* channel = *iter;
140     channel->destroy();
141   }
142   pending_channels_.clear();
143   Shutdown();
144 }
145 
146 }  // namespace content
147