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:
SharedWorkerWebApplicationCacheHostImpl(blink::WebApplicationCacheHostClient * client)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.
willStartMainResourceRequest(blink::WebURLRequest &,const blink::WebApplicationCacheHost *)38 virtual void willStartMainResourceRequest(
39 blink::WebURLRequest&,
40 const blink::WebApplicationCacheHost*) {}
didReceiveResponseForMainResource(const blink::WebURLResponse &)41 virtual void didReceiveResponseForMainResource(const blink::WebURLResponse&) {
42 }
didReceiveDataForMainResource(const char * data,int len)43 virtual void didReceiveDataForMainResource(const char* data, int len) {}
didFinishLoadingMainResource(bool success)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.
selectCacheWithoutManifest()49 virtual void selectCacheWithoutManifest() {}
selectCacheWithManifest(const blink::WebURL & manifestURL)50 virtual bool selectCacheWithManifest(const blink::WebURL& manifestURL) {
51 return true;
52 }
53 };
54 }
55
EmbeddedSharedWorkerStub(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)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
~EmbeddedSharedWorkerStub()77 EmbeddedSharedWorkerStub::~EmbeddedSharedWorkerStub() {
78 RenderThreadImpl::current()->RemoveEmbeddedWorkerRoute(route_id_);
79 }
80
OnMessageReceived(const IPC::Message & message)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
OnChannelError()95 void EmbeddedSharedWorkerStub::OnChannelError() {
96 OnTerminateWorkerContext();
97 }
98
workerReadyForInspection()99 void EmbeddedSharedWorkerStub::workerReadyForInspection() {
100 Send(new WorkerHostMsg_WorkerReadyForInspection(route_id_));
101 }
102
workerScriptLoaded()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
workerScriptLoadFailed()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
workerContextClosed()127 void EmbeddedSharedWorkerStub::workerContextClosed() {
128 Send(new WorkerHostMsg_WorkerContextClosed(route_id_));
129 }
130
workerContextDestroyed()131 void EmbeddedSharedWorkerStub::workerContextDestroyed() {
132 Send(new WorkerHostMsg_WorkerContextDestroyed(route_id_));
133 Shutdown();
134 }
135
selectAppCacheID(long long app_cache_id)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*
notificationPresenter()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*
createApplicationCacheHost(blink::WebApplicationCacheHostClient * client)153 EmbeddedSharedWorkerStub::createApplicationCacheHost(
154 blink::WebApplicationCacheHostClient* client) {
155 app_cache_host_ = new SharedWorkerWebApplicationCacheHostImpl(client);
156 return app_cache_host_;
157 }
158
159 blink::WebWorkerPermissionClientProxy*
createWorkerPermissionClientProxy(const blink::WebSecurityOrigin & origin)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
dispatchDevToolsMessage(const blink::WebString & message)169 void EmbeddedSharedWorkerStub::dispatchDevToolsMessage(
170 const blink::WebString& message) {
171 worker_devtools_agent_->SendDevToolsMessage(message);
172 }
173
saveDevToolsAgentState(const blink::WebString & state)174 void EmbeddedSharedWorkerStub::saveDevToolsAgentState(
175 const blink::WebString& state) {
176 worker_devtools_agent_->SaveDevToolsAgentState(state);
177 }
178
Shutdown()179 void EmbeddedSharedWorkerStub::Shutdown() {
180 delete this;
181 }
182
Send(IPC::Message * message)183 bool EmbeddedSharedWorkerStub::Send(IPC::Message* message) {
184 return RenderThreadImpl::current()->Send(message);
185 }
186
ConnectToChannel(WebMessagePortChannelImpl * channel)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
OnConnect(int sent_message_port_id,int routing_id)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
OnTerminateWorkerContext()211 void EmbeddedSharedWorkerStub::OnTerminateWorkerContext() {
212 runing_ = false;
213 impl_->terminateWorkerContext();
214 }
215
216 } // namespace content
217