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