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