DevTools: cut host and port from webSocketDebuggerUrl in addition to ws:// prefix
[chromium-blink-merge.git] / content / browser / shared_worker / shared_worker_host.cc
blobe28687ed9350fa4de8c2f9ece8f39aaf866fd713
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/frame_host/render_frame_host_delegate.h"
10 #include "content/browser/frame_host/render_frame_host_impl.h"
11 #include "content/browser/message_port_message_filter.h"
12 #include "content/browser/message_port_service.h"
13 #include "content/browser/shared_worker/shared_worker_instance.h"
14 #include "content/browser/shared_worker/shared_worker_message_filter.h"
15 #include "content/browser/shared_worker/shared_worker_service_impl.h"
16 #include "content/browser/shared_worker/worker_document_set.h"
17 #include "content/common/view_messages.h"
18 #include "content/common/worker_messages.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/content_browser_client.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/common/content_client.h"
24 namespace content {
25 namespace {
27 // Notifies RenderViewHost that one or more worker objects crashed.
28 void WorkerCrashCallback(int render_process_unique_id, int render_frame_id) {
29 RenderFrameHostImpl* host =
30 RenderFrameHostImpl::FromID(render_process_unique_id, render_frame_id);
31 if (host)
32 host->delegate()->WorkerCrashed(host);
35 void NotifyWorkerReadyForInspection(int worker_process_id,
36 int worker_route_id) {
37 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
38 BrowserThread::PostTask(BrowserThread::UI,
39 FROM_HERE,
40 base::Bind(NotifyWorkerReadyForInspection,
41 worker_process_id,
42 worker_route_id));
43 return;
45 SharedWorkerDevToolsManager::GetInstance()->WorkerReadyForInspection(
46 worker_process_id, worker_route_id);
49 void NotifyWorkerDestroyed(int worker_process_id, int worker_route_id) {
50 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
51 BrowserThread::PostTask(
52 BrowserThread::UI,
53 FROM_HERE,
54 base::Bind(NotifyWorkerDestroyed, worker_process_id, worker_route_id));
55 return;
57 SharedWorkerDevToolsManager::GetInstance()->WorkerDestroyed(
58 worker_process_id, worker_route_id);
61 } // namespace
63 SharedWorkerHost::SharedWorkerHost(SharedWorkerInstance* instance,
64 SharedWorkerMessageFilter* filter,
65 int worker_route_id)
66 : instance_(instance),
67 worker_document_set_(new WorkerDocumentSet()),
68 container_render_filter_(filter),
69 worker_process_id_(filter->render_process_id()),
70 worker_route_id_(worker_route_id),
71 load_failed_(false),
72 closed_(false),
73 creation_time_(base::TimeTicks::Now()),
74 weak_factory_(this) {
75 DCHECK_CURRENTLY_ON(BrowserThread::IO);
78 SharedWorkerHost::~SharedWorkerHost() {
79 DCHECK_CURRENTLY_ON(BrowserThread::IO);
80 UMA_HISTOGRAM_LONG_TIMES("SharedWorker.TimeToDeleted",
81 base::TimeTicks::Now() - creation_time_);
82 // If we crashed, tell the RenderViewHosts.
83 if (instance_ && !load_failed_) {
84 const WorkerDocumentSet::DocumentInfoSet& parents =
85 worker_document_set_->documents();
86 for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
87 parents.begin();
88 parent_iter != parents.end();
89 ++parent_iter) {
90 BrowserThread::PostTask(BrowserThread::UI,
91 FROM_HERE,
92 base::Bind(&WorkerCrashCallback,
93 parent_iter->render_process_id(),
94 parent_iter->render_frame_id()));
97 if (!closed_)
98 NotifyWorkerDestroyed(worker_process_id_, worker_route_id_);
99 SharedWorkerServiceImpl::GetInstance()->NotifyWorkerDestroyed(
100 worker_process_id_, worker_route_id_);
103 bool SharedWorkerHost::Send(IPC::Message* message) {
104 if (!container_render_filter_) {
105 delete message;
106 return false;
108 return container_render_filter_->Send(message);
111 void SharedWorkerHost::Start(bool pause_on_start) {
112 WorkerProcessMsg_CreateWorker_Params params;
113 params.url = instance_->url();
114 params.name = instance_->name();
115 params.content_security_policy = instance_->content_security_policy();
116 params.security_policy_type = instance_->security_policy_type();
117 params.pause_on_start = pause_on_start;
118 params.route_id = worker_route_id_;
119 Send(new WorkerProcessMsg_CreateWorker(params));
121 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
122 ++i) {
123 i->filter()->Send(new ViewMsg_WorkerCreated(i->route_id()));
127 bool SharedWorkerHost::FilterMessage(const IPC::Message& message,
128 SharedWorkerMessageFilter* filter) {
129 if (!instance_)
130 return false;
132 if (!closed_ && HasFilter(filter, message.routing_id())) {
133 RelayMessage(message, filter);
134 return true;
137 return false;
140 void SharedWorkerHost::FilterShutdown(SharedWorkerMessageFilter* filter) {
141 if (!instance_)
142 return;
143 RemoveFilters(filter);
144 worker_document_set_->RemoveAll(filter);
145 if (worker_document_set_->IsEmpty()) {
146 // This worker has no more associated documents - shut it down.
147 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id_));
151 void SharedWorkerHost::DocumentDetached(SharedWorkerMessageFilter* filter,
152 unsigned long long document_id) {
153 if (!instance_)
154 return;
155 // Walk all instances and remove the document from their document set.
156 worker_document_set_->Remove(filter, document_id);
157 if (worker_document_set_->IsEmpty()) {
158 // This worker has no more associated documents - shut it down.
159 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id_));
163 void SharedWorkerHost::WorkerContextClosed() {
164 if (!instance_)
165 return;
166 // Set the closed flag - this will stop any further messages from
167 // being sent to the worker (messages can still be sent from the worker,
168 // for exception reporting, etc).
169 closed_ = true;
170 NotifyWorkerDestroyed(worker_process_id_, worker_route_id_);
173 void SharedWorkerHost::WorkerContextDestroyed() {
174 if (!instance_)
175 return;
176 instance_.reset();
177 worker_document_set_ = NULL;
180 void SharedWorkerHost::WorkerReadyForInspection() {
181 NotifyWorkerReadyForInspection(worker_process_id_, worker_route_id_);
184 void SharedWorkerHost::WorkerScriptLoaded() {
185 UMA_HISTOGRAM_TIMES("SharedWorker.TimeToScriptLoaded",
186 base::TimeTicks::Now() - creation_time_);
189 void SharedWorkerHost::WorkerScriptLoadFailed() {
190 UMA_HISTOGRAM_TIMES("SharedWorker.TimeToScriptLoadFailed",
191 base::TimeTicks::Now() - creation_time_);
192 if (!instance_)
193 return;
194 load_failed_ = true;
195 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
196 ++i) {
197 i->filter()->Send(new ViewMsg_WorkerScriptLoadFailed(i->route_id()));
201 void SharedWorkerHost::WorkerConnected(int message_port_id) {
202 if (!instance_)
203 return;
204 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
205 ++i) {
206 if (i->message_port_id() != message_port_id)
207 continue;
208 i->filter()->Send(new ViewMsg_WorkerConnected(i->route_id()));
209 return;
213 void SharedWorkerHost::AllowDatabase(const GURL& url,
214 const base::string16& name,
215 const base::string16& display_name,
216 unsigned long estimated_size,
217 bool* result) {
218 if (!instance_)
219 return;
220 *result = GetContentClient()->browser()->AllowWorkerDatabase(
221 url,
222 name,
223 display_name,
224 estimated_size,
225 instance_->resource_context(),
226 GetRenderFrameIDsForWorker());
229 void SharedWorkerHost::AllowFileSystem(const GURL& url,
230 scoped_ptr<IPC::Message> reply_msg) {
231 if (!instance_)
232 return;
233 GetContentClient()->browser()->AllowWorkerFileSystem(
234 url,
235 instance_->resource_context(),
236 GetRenderFrameIDsForWorker(),
237 base::Bind(&SharedWorkerHost::AllowFileSystemResponse,
238 weak_factory_.GetWeakPtr(),
239 base::Passed(&reply_msg)));
242 void SharedWorkerHost::AllowFileSystemResponse(
243 scoped_ptr<IPC::Message> reply_msg,
244 bool allowed) {
245 WorkerProcessHostMsg_RequestFileSystemAccessSync::WriteReplyParams(
246 reply_msg.get(),
247 allowed);
248 Send(reply_msg.release());
251 void SharedWorkerHost::AllowIndexedDB(const GURL& url,
252 const base::string16& name,
253 bool* result) {
254 if (!instance_)
255 return;
256 *result = GetContentClient()->browser()->AllowWorkerIndexedDB(
257 url, name, instance_->resource_context(), GetRenderFrameIDsForWorker());
260 void SharedWorkerHost::RelayMessage(
261 const IPC::Message& message,
262 SharedWorkerMessageFilter* incoming_filter) {
263 if (!instance_)
264 return;
265 if (message.type() == WorkerMsg_Connect::ID) {
266 // Crack the SharedWorker Connect message to setup routing for the port.
267 WorkerMsg_Connect::Param param;
268 if (!WorkerMsg_Connect::Read(&message, &param))
269 return;
270 int sent_message_port_id = base::get<0>(param);
271 int new_routing_id = base::get<1>(param);
273 DCHECK(container_render_filter_);
274 new_routing_id = container_render_filter_->GetNextRoutingID();
275 MessagePortService::GetInstance()->UpdateMessagePort(
276 sent_message_port_id,
277 container_render_filter_->message_port_message_filter(),
278 new_routing_id);
279 SetMessagePortID(
280 incoming_filter, message.routing_id(), sent_message_port_id);
281 // Resend the message with the new routing id.
282 Send(new WorkerMsg_Connect(
283 worker_route_id_, sent_message_port_id, new_routing_id));
285 // Send any queued messages for the sent port.
286 MessagePortService::GetInstance()->SendQueuedMessagesIfPossible(
287 sent_message_port_id);
288 } else {
289 IPC::Message* new_message = new IPC::Message(message);
290 new_message->set_routing_id(worker_route_id_);
291 Send(new_message);
292 return;
296 void SharedWorkerHost::TerminateWorker() {
297 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id_));
300 std::vector<std::pair<int, int> >
301 SharedWorkerHost::GetRenderFrameIDsForWorker() {
302 std::vector<std::pair<int, int> > result;
303 if (!instance_)
304 return result;
305 const WorkerDocumentSet::DocumentInfoSet& documents =
306 worker_document_set_->documents();
307 for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
308 documents.begin();
309 doc != documents.end();
310 ++doc) {
311 result.push_back(
312 std::make_pair(doc->render_process_id(), doc->render_frame_id()));
314 return result;
317 void SharedWorkerHost::AddFilter(SharedWorkerMessageFilter* filter,
318 int route_id) {
319 CHECK(filter);
320 if (!HasFilter(filter, route_id)) {
321 FilterInfo info(filter, route_id);
322 filters_.push_back(info);
326 void SharedWorkerHost::RemoveFilters(SharedWorkerMessageFilter* filter) {
327 for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
328 if (i->filter() == filter)
329 i = filters_.erase(i);
330 else
331 ++i;
335 bool SharedWorkerHost::HasFilter(SharedWorkerMessageFilter* filter,
336 int route_id) const {
337 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
338 ++i) {
339 if (i->filter() == filter && i->route_id() == route_id)
340 return true;
342 return false;
345 void SharedWorkerHost::SetMessagePortID(SharedWorkerMessageFilter* filter,
346 int route_id,
347 int message_port_id) {
348 for (FilterList::iterator i = filters_.begin(); i != filters_.end(); ++i) {
349 if (i->filter() == filter && i->route_id() == route_id) {
350 i->set_message_port_id(message_port_id);
351 return;
356 } // namespace content