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::workerScriptLoaded() { 100 Send(new WorkerHostMsg_WorkerScriptLoaded(route_id_)); 101 runing_ = true; 102 // Process any pending connections. 103 for (PendingChannelList::const_iterator iter = pending_channels_.begin(); 104 iter != pending_channels_.end(); 105 ++iter) { 106 ConnectToChannel(*iter); 107 } 108 pending_channels_.clear(); 109 } 110 111 void EmbeddedSharedWorkerStub::workerScriptLoadFailed() { 112 Send(new WorkerHostMsg_WorkerScriptLoadFailed(route_id_)); 113 for (PendingChannelList::const_iterator iter = pending_channels_.begin(); 114 iter != pending_channels_.end(); 115 ++iter) { 116 blink::WebMessagePortChannel* channel = *iter; 117 channel->destroy(); 118 } 119 pending_channels_.clear(); 120 Shutdown(); 121 } 122 123 void EmbeddedSharedWorkerStub::workerContextClosed() { 124 Send(new WorkerHostMsg_WorkerContextClosed(route_id_)); 125 } 126 127 void EmbeddedSharedWorkerStub::workerContextDestroyed() { 128 Send(new WorkerHostMsg_WorkerContextDestroyed(route_id_)); 129 Shutdown(); 130 } 131 132 void EmbeddedSharedWorkerStub::selectAppCacheID(long long app_cache_id) { 133 if (app_cache_host_) { 134 // app_cache_host_ could become stale as it's owned by blink's 135 // DocumentLoader. This method is assumed to be called while it's valid. 136 app_cache_host_->backend()->SelectCacheForSharedWorker( 137 app_cache_host_->host_id(), app_cache_id); 138 } 139 } 140 141 blink::WebNotificationPresenter* 142 EmbeddedSharedWorkerStub::notificationPresenter() { 143 // TODO(horo): delete this method if we have no plan to implement this. 144 NOTREACHED(); 145 return NULL; 146 } 147 148 blink::WebApplicationCacheHost* 149 EmbeddedSharedWorkerStub::createApplicationCacheHost( 150 blink::WebApplicationCacheHostClient* client) { 151 app_cache_host_ = new SharedWorkerWebApplicationCacheHostImpl(client); 152 return app_cache_host_; 153 } 154 155 blink::WebWorkerPermissionClientProxy* 156 EmbeddedSharedWorkerStub::createWorkerPermissionClientProxy( 157 const blink::WebSecurityOrigin& origin) { 158 return new EmbeddedSharedWorkerPermissionClientProxy( 159 GURL(origin.toString()), 160 origin.isUnique(), 161 route_id_, 162 ChildThread::current()->thread_safe_sender()); 163 } 164 165 void EmbeddedSharedWorkerStub::dispatchDevToolsMessage( 166 const blink::WebString& message) { 167 worker_devtools_agent_->SendDevToolsMessage(message); 168 } 169 170 void EmbeddedSharedWorkerStub::saveDevToolsAgentState( 171 const blink::WebString& state) { 172 worker_devtools_agent_->SaveDevToolsAgentState(state); 173 } 174 175 void EmbeddedSharedWorkerStub::Shutdown() { 176 delete this; 177 } 178 179 bool EmbeddedSharedWorkerStub::Send(IPC::Message* message) { 180 return RenderThreadImpl::current()->Send(message); 181 } 182 183 void EmbeddedSharedWorkerStub::ConnectToChannel( 184 WebMessagePortChannelImpl* channel) { 185 impl_->connect(channel); 186 Send( 187 new WorkerHostMsg_WorkerConnected(channel->message_port_id(), route_id_)); 188 } 189 190 void EmbeddedSharedWorkerStub::OnConnect(int sent_message_port_id, 191 int routing_id) { 192 WebMessagePortChannelImpl* channel = 193 new WebMessagePortChannelImpl(routing_id, 194 sent_message_port_id, 195 base::MessageLoopProxy::current().get()); 196 if (runing_) { 197 ConnectToChannel(channel); 198 } else { 199 // If two documents try to load a SharedWorker at the same time, the 200 // WorkerMsg_Connect for one of the documents can come in before the 201 // worker is started. Just queue up the connect and deliver it once the 202 // worker starts. 203 pending_channels_.push_back(channel); 204 } 205 } 206 207 void EmbeddedSharedWorkerStub::OnTerminateWorkerContext() { 208 runing_ = false; 209 impl_->terminateWorkerContext(); 210 } 211 212 } // namespace content 213