Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / shared_worker / shared_worker_host.cc
blob99c369de2d6c8cf2a719749d7899afe2df4064e9
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.
5 #include "content/browser/shared_worker/shared_worker_host.h"
7 #include "base/metrics/histogram.h"
8 #include "content/browser/devtools/shared_worker_devtools_manager.h"
9 #include "content/browser/message_port_message_filter.h"
10 #include "content/browser/message_port_service.h"
11 #include "content/browser/shared_worker/shared_worker_instance.h"
12 #include "content/browser/shared_worker/shared_worker_message_filter.h"
13 #include "content/browser/shared_worker/shared_worker_service_impl.h"
14 #include "content/browser/shared_worker/worker_document_set.h"
15 #include "content/common/view_messages.h"
16 #include "content/common/worker_messages.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/content_browser_client.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "content/public/common/content_client.h"
22 namespace content {
23 namespace {
25 void NotifyWorkerReadyForInspection(int worker_process_id,
26 int worker_route_id) {
27 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
28 BrowserThread::PostTask(BrowserThread::UI,
29 FROM_HERE,
30 base::Bind(NotifyWorkerReadyForInspection,
31 worker_process_id,
32 worker_route_id));
33 return;
35 SharedWorkerDevToolsManager::GetInstance()->WorkerReadyForInspection(
36 worker_process_id, worker_route_id);
39 void NotifyWorkerDestroyed(int worker_process_id, int worker_route_id) {
40 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
41 BrowserThread::PostTask(
42 BrowserThread::UI,
43 FROM_HERE,
44 base::Bind(NotifyWorkerDestroyed, worker_process_id, worker_route_id));
45 return;
47 SharedWorkerDevToolsManager::GetInstance()->WorkerDestroyed(
48 worker_process_id, worker_route_id);
51 } // namespace
53 SharedWorkerHost::SharedWorkerHost(SharedWorkerInstance* instance,
54 SharedWorkerMessageFilter* filter,
55 int worker_route_id)
56 : instance_(instance),
57 worker_document_set_(new WorkerDocumentSet()),
58 container_render_filter_(filter),
59 worker_process_id_(filter->render_process_id()),
60 worker_route_id_(worker_route_id),
61 closed_(false),
62 creation_time_(base::TimeTicks::Now()),
63 weak_factory_(this) {
64 DCHECK_CURRENTLY_ON(BrowserThread::IO);
67 SharedWorkerHost::~SharedWorkerHost() {
68 DCHECK_CURRENTLY_ON(BrowserThread::IO);
69 UMA_HISTOGRAM_LONG_TIMES("SharedWorker.TimeToDeleted",
70 base::TimeTicks::Now() - creation_time_);
71 if (!closed_)
72 NotifyWorkerDestroyed(worker_process_id_, worker_route_id_);
73 SharedWorkerServiceImpl::GetInstance()->NotifyWorkerDestroyed(
74 worker_process_id_, worker_route_id_);
77 bool SharedWorkerHost::Send(IPC::Message* message) {
78 if (!container_render_filter_) {
79 delete message;
80 return false;
82 return container_render_filter_->Send(message);
85 void SharedWorkerHost::Start(bool pause_on_start) {
86 WorkerProcessMsg_CreateWorker_Params params;
87 params.url = instance_->url();
88 params.name = instance_->name();
89 params.content_security_policy = instance_->content_security_policy();
90 params.security_policy_type = instance_->security_policy_type();
91 params.pause_on_start = pause_on_start;
92 params.route_id = worker_route_id_;
93 Send(new WorkerProcessMsg_CreateWorker(params));
95 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
96 ++i) {
97 i->filter()->Send(new ViewMsg_WorkerCreated(i->route_id()));
101 bool SharedWorkerHost::FilterMessage(const IPC::Message& message,
102 SharedWorkerMessageFilter* filter) {
103 if (!instance_)
104 return false;
106 if (!closed_ && HasFilter(filter, message.routing_id())) {
107 RelayMessage(message, filter);
108 return true;
111 return false;
114 void SharedWorkerHost::FilterShutdown(SharedWorkerMessageFilter* filter) {
115 if (!instance_)
116 return;
117 RemoveFilters(filter);
118 worker_document_set_->RemoveAll(filter);
119 if (worker_document_set_->IsEmpty()) {
120 // This worker has no more associated documents - shut it down.
121 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id_));
125 void SharedWorkerHost::DocumentDetached(SharedWorkerMessageFilter* filter,
126 unsigned long long document_id) {
127 if (!instance_)
128 return;
129 // Walk all instances and remove the document from their document set.
130 worker_document_set_->Remove(filter, document_id);
131 if (worker_document_set_->IsEmpty()) {
132 // This worker has no more associated documents - shut it down.
133 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id_));
137 void SharedWorkerHost::WorkerContextClosed() {
138 if (!instance_)
139 return;
140 // Set the closed flag - this will stop any further messages from
141 // being sent to the worker (messages can still be sent from the worker,
142 // for exception reporting, etc).
143 closed_ = true;
144 NotifyWorkerDestroyed(worker_process_id_, worker_route_id_);
147 void SharedWorkerHost::WorkerContextDestroyed() {
148 if (!instance_)
149 return;
150 instance_.reset();
151 worker_document_set_ = NULL;
154 void SharedWorkerHost::WorkerReadyForInspection() {
155 NotifyWorkerReadyForInspection(worker_process_id_, worker_route_id_);
158 void SharedWorkerHost::WorkerScriptLoaded() {
159 UMA_HISTOGRAM_TIMES("SharedWorker.TimeToScriptLoaded",
160 base::TimeTicks::Now() - creation_time_);
163 void SharedWorkerHost::WorkerScriptLoadFailed() {
164 UMA_HISTOGRAM_TIMES("SharedWorker.TimeToScriptLoadFailed",
165 base::TimeTicks::Now() - creation_time_);
166 if (!instance_)
167 return;
168 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
169 ++i) {
170 i->filter()->Send(new ViewMsg_WorkerScriptLoadFailed(i->route_id()));
174 void SharedWorkerHost::WorkerConnected(int message_port_id) {
175 if (!instance_)
176 return;
177 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
178 ++i) {
179 if (i->message_port_id() != message_port_id)
180 continue;
181 i->filter()->Send(new ViewMsg_WorkerConnected(i->route_id()));
182 return;
186 void SharedWorkerHost::AllowDatabase(const GURL& url,
187 const base::string16& name,
188 const base::string16& display_name,
189 unsigned long estimated_size,
190 bool* result) {
191 if (!instance_)
192 return;
193 *result = GetContentClient()->browser()->AllowWorkerDatabase(
194 url,
195 name,
196 display_name,
197 estimated_size,
198 instance_->resource_context(),
199 GetRenderFrameIDsForWorker());
202 void SharedWorkerHost::AllowFileSystem(const GURL& url,
203 scoped_ptr<IPC::Message> reply_msg) {
204 if (!instance_)
205 return;
206 GetContentClient()->browser()->AllowWorkerFileSystem(
207 url,
208 instance_->resource_context(),
209 GetRenderFrameIDsForWorker(),
210 base::Bind(&SharedWorkerHost::AllowFileSystemResponse,
211 weak_factory_.GetWeakPtr(),
212 base::Passed(&reply_msg)));
215 void SharedWorkerHost::AllowFileSystemResponse(
216 scoped_ptr<IPC::Message> reply_msg,
217 bool allowed) {
218 WorkerProcessHostMsg_RequestFileSystemAccessSync::WriteReplyParams(
219 reply_msg.get(),
220 allowed);
221 Send(reply_msg.release());
224 void SharedWorkerHost::AllowIndexedDB(const GURL& url,
225 const base::string16& name,
226 bool* result) {
227 if (!instance_)
228 return;
229 *result = GetContentClient()->browser()->AllowWorkerIndexedDB(
230 url, name, instance_->resource_context(), GetRenderFrameIDsForWorker());
233 void SharedWorkerHost::RelayMessage(
234 const IPC::Message& message,
235 SharedWorkerMessageFilter* incoming_filter) {
236 if (!instance_)
237 return;
238 if (message.type() == WorkerMsg_Connect::ID) {
239 // Crack the SharedWorker Connect message to setup routing for the port.
240 WorkerMsg_Connect::Param param;
241 if (!WorkerMsg_Connect::Read(&message, &param))
242 return;
243 int sent_message_port_id = base::get<0>(param);
244 int new_routing_id = base::get<1>(param);
246 DCHECK(container_render_filter_);
247 new_routing_id = container_render_filter_->GetNextRoutingID();
248 MessagePortService::GetInstance()->UpdateMessagePort(
249 sent_message_port_id,
250 container_render_filter_->message_port_message_filter(),
251 new_routing_id);
252 SetMessagePortID(
253 incoming_filter, message.routing_id(), sent_message_port_id);
254 // Resend the message with the new routing id.
255 Send(new WorkerMsg_Connect(
256 worker_route_id_, sent_message_port_id, new_routing_id));
258 // Send any queued messages for the sent port.
259 MessagePortService::GetInstance()->SendQueuedMessagesIfPossible(
260 sent_message_port_id);
261 } else {
262 IPC::Message* new_message = new IPC::Message(message);
263 new_message->set_routing_id(worker_route_id_);
264 Send(new_message);
265 return;
269 void SharedWorkerHost::TerminateWorker() {
270 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id_));
273 std::vector<std::pair<int, int> >
274 SharedWorkerHost::GetRenderFrameIDsForWorker() {
275 std::vector<std::pair<int, int> > result;
276 if (!instance_)
277 return result;
278 const WorkerDocumentSet::DocumentInfoSet& documents =
279 worker_document_set_->documents();
280 for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
281 documents.begin();
282 doc != documents.end();
283 ++doc) {
284 result.push_back(
285 std::make_pair(doc->render_process_id(), doc->render_frame_id()));
287 return result;
290 void SharedWorkerHost::AddFilter(SharedWorkerMessageFilter* filter,
291 int route_id) {
292 CHECK(filter);
293 if (!HasFilter(filter, route_id)) {
294 FilterInfo info(filter, route_id);
295 filters_.push_back(info);
299 void SharedWorkerHost::RemoveFilters(SharedWorkerMessageFilter* filter) {
300 for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
301 if (i->filter() == filter)
302 i = filters_.erase(i);
303 else
304 ++i;
308 bool SharedWorkerHost::HasFilter(SharedWorkerMessageFilter* filter,
309 int route_id) const {
310 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
311 ++i) {
312 if (i->filter() == filter && i->route_id() == route_id)
313 return true;
315 return false;
318 void SharedWorkerHost::SetMessagePortID(SharedWorkerMessageFilter* filter,
319 int route_id,
320 int message_port_id) {
321 for (FilterList::iterator i = filters_.begin(); i != filters_.end(); ++i) {
322 if (i->filter() == filter && i->route_id() == route_id) {
323 i->set_message_port_id(message_port_id);
324 return;
329 } // namespace content