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 21namespace content { 22 23WebSharedWorkerStub::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 55WebSharedWorkerStub::~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 63void WebSharedWorkerStub::Shutdown() { 64 // The worker has exited - free ourselves and the client. 65 delete this; 66} 67 68void WebSharedWorkerStub::EnsureWorkerContextTerminates() { 69 client_.EnsureWorkerContextTerminates(); 70} 71 72bool 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 86void WebSharedWorkerStub::OnChannelError() { 87 OnTerminateWorkerContext(); 88} 89 90const GURL& WebSharedWorkerStub::url() { 91 return url_; 92} 93 94void 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 113void 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 121void 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 135void 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