Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / browser / worker_host / worker_process_host.cc
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/browser/worker_host/worker_process_host.h"
6
7 #include <set>
8 #include <string>
9 #include <vector>
10
11 #include "base/base_switches.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/command_line.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "content/browser/appcache/appcache_dispatcher_host.h"
20 #include "content/browser/appcache/chrome_appcache_service.h"
21 #include "content/browser/browser_child_process_host_impl.h"
22 #include "content/browser/child_process_security_policy_impl.h"
23 #include "content/browser/devtools/worker_devtools_manager.h"
24 #include "content/browser/devtools/worker_devtools_message_filter.h"
25 #include "content/browser/fileapi/fileapi_message_filter.h"
26 #include "content/browser/frame_host/render_frame_host_delegate.h"
27 #include "content/browser/frame_host/render_frame_host_impl.h"
28 #include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
29 #include "content/browser/loader/resource_message_filter.h"
30 #include "content/browser/message_port_message_filter.h"
31 #include "content/browser/message_port_service.h"
32 #include "content/browser/mime_registry_message_filter.h"
33 #include "content/browser/quota_dispatcher_host.h"
34 #include "content/browser/renderer_host/database_message_filter.h"
35 #include "content/browser/renderer_host/file_utilities_message_filter.h"
36 #include "content/browser/renderer_host/render_view_host_delegate.h"
37 #include "content/browser/renderer_host/render_view_host_impl.h"
38 #include "content/browser/renderer_host/socket_stream_dispatcher_host.h"
39 #include "content/browser/resource_context_impl.h"
40 #include "content/browser/worker_host/worker_message_filter.h"
41 #include "content/browser/worker_host/worker_service_impl.h"
42 #include "content/common/child_process_host_impl.h"
43 #include "content/common/view_messages.h"
44 #include "content/common/worker_messages.h"
45 #include "content/public/browser/browser_thread.h"
46 #include "content/public/browser/content_browser_client.h"
47 #include "content/public/browser/user_metrics.h"
48 #include "content/public/common/content_switches.h"
49 #include "content/public/common/result_codes.h"
50 #include "ipc/ipc_switches.h"
51 #include "net/base/mime_util.h"
52 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
53 #include "net/url_request/url_request_context_getter.h"
54 #include "ui/base/ui_base_switches.h"
55 #include "webkit/browser/fileapi/file_system_context.h"
56 #include "webkit/browser/fileapi/sandbox_file_system_backend.h"
57 #include "webkit/common/resource_type.h"
58
59 #if defined(OS_WIN)
60 #include "content/common/sandbox_win.h"
61 #include "content/public/common/sandboxed_process_launcher_delegate.h"
62 #endif
63
64 namespace content {
65 namespace {
66
67 #if defined(OS_WIN)
68 // NOTE: changes to this class need to be reviewed by the security team.
69 class WorkerSandboxedProcessLauncherDelegate
70     : public content::SandboxedProcessLauncherDelegate {
71  public:
72   WorkerSandboxedProcessLauncherDelegate() {}
73   virtual ~WorkerSandboxedProcessLauncherDelegate() {}
74
75   virtual void PreSpawnTarget(sandbox::TargetPolicy* policy,
76                               bool* success) {
77     AddBaseHandleClosePolicy(policy);
78   }
79 };
80 #endif  // OS_WIN
81
82 // Notifies RenderViewHost that one or more worker objects crashed.
83 void WorkerCrashCallback(int render_process_unique_id, int render_frame_id) {
84   RenderFrameHostImpl* host =
85       RenderFrameHostImpl::FromID(render_process_unique_id, render_frame_id);
86   if (host)
87     host->delegate()->WorkerCrashed(host);
88 }
89
90 void WorkerCreatedCallback(int render_process_id,
91                            int render_frame_id,
92                            int worker_process_id) {
93   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
94   RenderFrameHost* render_frame_host =
95       RenderFrameHost::FromID(render_process_id, render_frame_id);
96   if (!render_frame_host)
97     return;
98   SiteInstance* site_instance = render_frame_host->GetSiteInstance();
99   GetContentClient()->browser()->WorkerProcessCreated(site_instance,
100                                                       worker_process_id);
101 }
102
103 void WorkerTerminatedCallback(int render_process_id,
104                               int render_frame_id,
105                               int worker_process_id) {
106   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
107   RenderFrameHost* render_frame_host =
108       RenderFrameHost::FromID(render_process_id, render_frame_id);
109   if (!render_frame_host)
110     return;
111   SiteInstance* site_instance = render_frame_host->GetSiteInstance();
112   GetContentClient()->browser()->WorkerProcessTerminated(site_instance,
113                                                          worker_process_id);
114 }
115
116 }  // namespace
117
118 WorkerProcessHost::WorkerProcessHost(
119     ResourceContext* resource_context,
120     const WorkerStoragePartition& partition)
121     : resource_context_(resource_context),
122       partition_(partition),
123       process_launched_(false) {
124   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
125   DCHECK(resource_context_);
126   process_.reset(
127       new BrowserChildProcessHostImpl(PROCESS_TYPE_WORKER, this));
128 }
129
130 WorkerProcessHost::~WorkerProcessHost() {
131   // If we crashed, tell the RenderViewHosts.
132   for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
133     if (!i->load_failed()) {
134       const WorkerDocumentSet::DocumentInfoSet& parents =
135           i->worker_document_set()->documents();
136       for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
137                parents.begin(); parent_iter != parents.end(); ++parent_iter) {
138         BrowserThread::PostTask(
139             BrowserThread::UI, FROM_HERE,
140             base::Bind(&WorkerCrashCallback, parent_iter->render_process_id(),
141                        parent_iter->render_frame_id()));
142       }
143     }
144     WorkerServiceImpl::GetInstance()->NotifyWorkerDestroyed(
145         this, i->worker_route_id());
146   }
147
148   ChildProcessSecurityPolicyImpl::GetInstance()->Remove(
149       process_->GetData().id);
150 }
151
152 bool WorkerProcessHost::Send(IPC::Message* message) {
153   return process_->Send(message);
154 }
155
156 bool WorkerProcessHost::Init(int render_process_id, int render_frame_id) {
157   std::string channel_id = process_->GetHost()->CreateChannel();
158   if (channel_id.empty())
159     return false;
160
161 #if defined(OS_LINUX)
162   int flags = ChildProcessHost::CHILD_ALLOW_SELF;
163 #else
164   int flags = ChildProcessHost::CHILD_NORMAL;
165 #endif
166
167   base::FilePath exe_path = ChildProcessHost::GetChildPath(flags);
168   if (exe_path.empty())
169     return false;
170
171   CommandLine* cmd_line = new CommandLine(exe_path);
172   cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kWorkerProcess);
173   cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
174   std::string locale = GetContentClient()->browser()->GetApplicationLocale();
175   cmd_line->AppendSwitchASCII(switches::kLang, locale);
176
177   static const char* const kSwitchNames[] = {
178     switches::kDisableApplicationCache,
179     switches::kDisableDatabases,
180 #if defined(OS_WIN)
181     switches::kDisableDesktopNotifications,
182 #endif
183     switches::kDisableFileSystem,
184     switches::kDisableSeccompFilterSandbox,
185     switches::kEnableExperimentalWebPlatformFeatures,
186     switches::kEnableServiceWorker,
187 #if defined(OS_MACOSX)
188     switches::kEnableSandboxLogging,
189 #endif
190     switches::kJavaScriptFlags,
191     switches::kNoSandbox
192   };
193   cmd_line->CopySwitchesFrom(*CommandLine::ForCurrentProcess(), kSwitchNames,
194                              arraysize(kSwitchNames));
195
196 #if defined(OS_POSIX)
197   bool use_zygote = true;
198
199   if (CommandLine::ForCurrentProcess()->HasSwitch(
200           switches::kWaitForDebuggerChildren)) {
201     // Look to pass-on the kWaitForDebugger flag.
202     std::string value = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
203         switches::kWaitForDebuggerChildren);
204     if (value.empty() || value == switches::kWorkerProcess) {
205       cmd_line->AppendSwitch(switches::kWaitForDebugger);
206       use_zygote = false;
207     }
208   }
209
210   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren)) {
211     // Look to pass-on the kDebugOnStart flag.
212     std::string value = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
213         switches::kDebugChildren);
214     if (value.empty() || value == switches::kWorkerProcess) {
215       // launches a new xterm, and runs the worker process in gdb, reading
216       // optional commands from gdb_chrome file in the working directory.
217       cmd_line->PrependWrapper("xterm -e gdb -x gdb_chrome --args");
218       use_zygote = false;
219     }
220   }
221 #endif
222
223   process_->Launch(
224 #if defined(OS_WIN)
225       new WorkerSandboxedProcessLauncherDelegate,
226       false,
227 #elif defined(OS_POSIX)
228       use_zygote,
229       base::EnvironmentMap(),
230 #endif
231       cmd_line);
232
233   ChildProcessSecurityPolicyImpl::GetInstance()->AddWorker(
234       process_->GetData().id, render_process_id);
235   CreateMessageFilters(render_process_id);
236
237   BrowserThread::PostTask(
238       BrowserThread::UI, FROM_HERE,
239       base::Bind(&WorkerCreatedCallback,
240                  render_process_id,
241                  render_frame_id,
242                  process_->GetData().id));
243   return true;
244 }
245
246 void WorkerProcessHost::CreateMessageFilters(int render_process_id) {
247   ChromeBlobStorageContext* blob_storage_context =
248       GetChromeBlobStorageContextForResourceContext(resource_context_);
249   StreamContext* stream_context =
250       GetStreamContextForResourceContext(resource_context_);
251
252   net::URLRequestContextGetter* url_request_context =
253       partition_.url_request_context();
254
255   ResourceMessageFilter::GetContextsCallback get_contexts_callback(
256       base::Bind(&WorkerProcessHost::GetContexts,
257       base::Unretained(this)));
258
259   ResourceMessageFilter* resource_message_filter = new ResourceMessageFilter(
260       process_->GetData().id, PROCESS_TYPE_WORKER,
261       partition_.appcache_service(),
262       blob_storage_context,
263       partition_.filesystem_context(),
264       get_contexts_callback);
265   process_->AddFilter(resource_message_filter);
266
267   MessagePortMessageFilter* message_port_message_filter =
268       new MessagePortMessageFilter(
269           base::Bind(&WorkerServiceImpl::next_worker_route_id,
270                      base::Unretained(WorkerServiceImpl::GetInstance())));
271   process_->AddFilter(message_port_message_filter);
272   worker_message_filter_ = new WorkerMessageFilter(render_process_id,
273                                                    resource_context_,
274                                                    partition_,
275                                                    message_port_message_filter);
276   process_->AddFilter(worker_message_filter_.get());
277   process_->AddFilter(new AppCacheDispatcherHost(
278       partition_.appcache_service(), process_->GetData().id));
279   process_->AddFilter(new FileAPIMessageFilter(
280       process_->GetData().id,
281       url_request_context,
282       partition_.filesystem_context(),
283       blob_storage_context,
284       stream_context));
285   process_->AddFilter(new FileUtilitiesMessageFilter(
286       process_->GetData().id));
287   process_->AddFilter(new MimeRegistryMessageFilter());
288   process_->AddFilter(new DatabaseMessageFilter(partition_.database_tracker()));
289   process_->AddFilter(new QuotaDispatcherHost(
290       process_->GetData().id,
291       partition_.quota_manager(),
292       GetContentClient()->browser()->CreateQuotaPermissionContext()));
293
294   SocketStreamDispatcherHost::GetRequestContextCallback
295       request_context_callback(
296           base::Bind(&WorkerProcessHost::GetRequestContext,
297           base::Unretained(this)));
298
299   SocketStreamDispatcherHost* socket_stream_dispatcher_host =
300       new SocketStreamDispatcherHost(
301           render_process_id,
302           request_context_callback,
303           resource_context_);
304   socket_stream_dispatcher_host_ = socket_stream_dispatcher_host;
305   process_->AddFilter(socket_stream_dispatcher_host);
306   process_->AddFilter(new WorkerDevToolsMessageFilter(process_->GetData().id));
307   process_->AddFilter(
308       new IndexedDBDispatcherHost(partition_.indexed_db_context()));
309 }
310
311 void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) {
312   ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL(
313       process_->GetData().id, instance.url());
314
315   instances_.push_back(instance);
316
317   WorkerProcessMsg_CreateWorker_Params params;
318   params.url = instance.url();
319   params.name = instance.name();
320   params.content_security_policy = instance.content_security_policy();
321   params.security_policy_type = instance.security_policy_type();
322   params.route_id = instance.worker_route_id();
323   Send(new WorkerProcessMsg_CreateWorker(params));
324
325   UpdateTitle();
326
327   // Walk all pending filters and let them know the worker has been created
328   // (could be more than one in the case where we had to queue up worker
329   // creation because the worker process limit was reached).
330   for (WorkerInstance::FilterList::const_iterator i =
331            instance.filters().begin();
332        i != instance.filters().end(); ++i) {
333     i->filter()->Send(new ViewMsg_WorkerCreated(i->route_id()));
334   }
335 }
336
337 bool WorkerProcessHost::FilterMessage(const IPC::Message& message,
338                                       WorkerMessageFilter* filter) {
339   for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
340     if (!i->closed() && i->HasFilter(filter, message.routing_id())) {
341       RelayMessage(message, filter, &(*i));
342       return true;
343     }
344   }
345
346   return false;
347 }
348
349 void WorkerProcessHost::OnProcessLaunched() {
350   process_launched_ = true;
351
352   WorkerServiceImpl::GetInstance()->NotifyWorkerProcessCreated();
353 }
354
355 bool WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
356   bool msg_is_ok = true;
357   bool handled = true;
358   IPC_BEGIN_MESSAGE_MAP_EX(WorkerProcessHost, message, msg_is_ok)
359     IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerContextClosed,
360                         OnWorkerContextClosed)
361     IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerContextDestroyed,
362                         OnWorkerContextDestroyed)
363     IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerScriptLoaded,
364                         OnWorkerScriptLoaded)
365     IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerScriptLoadFailed,
366                         OnWorkerScriptLoadFailed)
367     IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerConnected,
368                         OnWorkerConnected)
369     IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowDatabase, OnAllowDatabase)
370     IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowFileSystem, OnAllowFileSystem)
371     IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowIndexedDB, OnAllowIndexedDB)
372     IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_ForceKillWorker,
373                         OnForceKillWorkerProcess)
374     IPC_MESSAGE_UNHANDLED(handled = false)
375   IPC_END_MESSAGE_MAP_EX()
376
377   if (!msg_is_ok) {
378     NOTREACHED();
379     RecordAction(base::UserMetricsAction("BadMessageTerminate_WPH"));
380     base::KillProcess(
381         process_->GetData().handle, RESULT_CODE_KILLED_BAD_MESSAGE, false);
382   }
383
384   return handled;
385 }
386
387 // Sent to notify the browser process when a worker context invokes close(), so
388 // no new connections are sent to shared workers.
389 void WorkerProcessHost::OnWorkerContextClosed(int worker_route_id) {
390   for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
391     if (i->worker_route_id() == worker_route_id) {
392       // Set the closed flag - this will stop any further messages from
393       // being sent to the worker (messages can still be sent from the worker,
394       // for exception reporting, etc).
395       i->set_closed(true);
396       break;
397     }
398   }
399 }
400
401 void WorkerProcessHost::OnWorkerContextDestroyed(int worker_route_id) {
402   WorkerServiceImpl::GetInstance()->NotifyWorkerDestroyed(
403       this, worker_route_id);
404   for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
405     if (i->worker_route_id() == worker_route_id) {
406       instances_.erase(i);
407       UpdateTitle();
408       return;
409     }
410   }
411 }
412
413 void WorkerProcessHost::OnWorkerScriptLoaded(int worker_route_id) {
414   WorkerDevToolsManager::GetInstance()->WorkerContextStarted(this,
415                                                              worker_route_id);
416 }
417
418 void WorkerProcessHost::OnWorkerScriptLoadFailed(int worker_route_id) {
419   bool shutdown = true;
420   for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
421     if (i->worker_route_id() != worker_route_id) {
422       shutdown = false;
423       continue;
424     }
425     i->set_load_failed(true);
426     for (WorkerInstance::FilterList::const_iterator j = i->filters().begin();
427           j != i->filters().end(); ++j) {
428       j->filter()->Send(new ViewMsg_WorkerScriptLoadFailed(j->route_id()));
429     }
430   }
431   if (shutdown) {
432     base::KillProcess(
433           process_->GetData().handle, RESULT_CODE_NORMAL_EXIT, false);
434   }
435 }
436
437 void WorkerProcessHost::OnWorkerConnected(int message_port_id,
438                                           int worker_route_id) {
439   for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
440     if (i->worker_route_id() != worker_route_id)
441       continue;
442     for (WorkerInstance::FilterList::const_iterator j = i->filters().begin();
443           j != i->filters().end(); ++j) {
444       if (j->message_port_id() != message_port_id)
445         continue;
446       j->filter()->Send(new ViewMsg_WorkerConnected(j->route_id()));
447       return;
448     }
449   }
450 }
451
452 void WorkerProcessHost::OnAllowDatabase(int worker_route_id,
453                                         const GURL& url,
454                                         const base::string16& name,
455                                         const base::string16& display_name,
456                                         unsigned long estimated_size,
457                                         bool* result) {
458   *result = GetContentClient()->browser()->AllowWorkerDatabase(
459       url, name, display_name, estimated_size, resource_context_,
460       GetRenderFrameIDsForWorker(worker_route_id));
461 }
462
463 void WorkerProcessHost::OnAllowFileSystem(int worker_route_id,
464                                           const GURL& url,
465                                           bool* result) {
466   *result = GetContentClient()->browser()->AllowWorkerFileSystem(
467       url, resource_context_, GetRenderFrameIDsForWorker(worker_route_id));
468 }
469
470 void WorkerProcessHost::OnAllowIndexedDB(int worker_route_id,
471                                          const GURL& url,
472                                          const base::string16& name,
473                                          bool* result) {
474   *result = GetContentClient()->browser()->AllowWorkerIndexedDB(
475       url, name, resource_context_,
476       GetRenderFrameIDsForWorker(worker_route_id));
477 }
478
479 void WorkerProcessHost::OnForceKillWorkerProcess() {
480   if (process_ && process_launched_)
481     base::KillProcess(
482           process_->GetData().handle, RESULT_CODE_NORMAL_EXIT, false);
483   else
484     RecordAction(base::UserMetricsAction("WorkerProcess_BadProcessToKill"));
485 }
486
487 void WorkerProcessHost::RelayMessage(
488     const IPC::Message& message,
489     WorkerMessageFilter* incoming_filter,
490     WorkerInstance* instance) {
491   if (message.type() == WorkerMsg_Connect::ID) {
492     // Crack the SharedWorker Connect message to setup routing for the port.
493     int sent_message_port_id;
494     int new_routing_id;
495     if (!WorkerMsg_Connect::Read(
496             &message, &sent_message_port_id, &new_routing_id)) {
497       return;
498     }
499     new_routing_id = worker_message_filter_->GetNextRoutingID();
500     MessagePortService::GetInstance()->UpdateMessagePort(
501         sent_message_port_id,
502         worker_message_filter_->message_port_message_filter(),
503         new_routing_id);
504
505     instance->SetMessagePortID(incoming_filter,
506                                message.routing_id(),
507                                sent_message_port_id);
508     // Resend the message with the new routing id.
509     worker_message_filter_->Send(new WorkerMsg_Connect(
510         instance->worker_route_id(), sent_message_port_id, new_routing_id));
511
512     // Send any queued messages for the sent port.
513     MessagePortService::GetInstance()->SendQueuedMessagesIfPossible(
514         sent_message_port_id);
515   } else {
516     IPC::Message* new_message = new IPC::Message(message);
517     new_message->set_routing_id(instance->worker_route_id());
518     worker_message_filter_->Send(new_message);
519     return;
520   }
521 }
522
523 void WorkerProcessHost::ShutdownSocketStreamDispatcherHostIfNecessary() {
524   if (!instances_.size() && socket_stream_dispatcher_host_.get()) {
525     // We can assume that this object is going to delete, because
526     // currently a WorkerInstance will never be added to a WorkerProcessHost
527     // once it is initialized.
528
529     // SocketStreamDispatcherHost should be notified now that the worker
530     // process will shutdown soon.
531     socket_stream_dispatcher_host_->Shutdown();
532     socket_stream_dispatcher_host_ = NULL;
533   }
534 }
535
536 void WorkerProcessHost::FilterShutdown(WorkerMessageFilter* filter) {
537   for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
538     bool shutdown = false;
539     i->RemoveFilters(filter);
540
541     int render_frame_id = 0;
542     const WorkerDocumentSet::DocumentInfoSet& documents =
543         i->worker_document_set()->documents();
544     for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
545          documents.begin(); doc != documents.end(); ++doc) {
546       if (doc->filter() == filter) {
547         render_frame_id = doc->render_frame_id();
548         break;
549       }
550     }
551     i->worker_document_set()->RemoveAll(filter);
552     if (i->worker_document_set()->IsEmpty()) {
553       shutdown = true;
554     }
555     if (shutdown) {
556       BrowserThread::PostTask(
557           BrowserThread::UI, FROM_HERE,
558           base::Bind(&WorkerTerminatedCallback,
559                      filter->render_process_id(),
560                      render_frame_id,
561                      process_->GetData().id));
562       Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id()));
563       i = instances_.erase(i);
564     } else {
565       ++i;
566     }
567   }
568   ShutdownSocketStreamDispatcherHostIfNecessary();
569 }
570
571 bool WorkerProcessHost::CanShutdown() {
572   return instances_.empty();
573 }
574
575 void WorkerProcessHost::UpdateTitle() {
576   std::set<std::string> titles;
577   for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
578     // Allow the embedder first crack at special casing the title.
579     std::string title = GetContentClient()->browser()->
580         GetWorkerProcessTitle(i->url(), resource_context_);
581
582     if (title.empty()) {
583       title = net::registry_controlled_domains::GetDomainAndRegistry(
584           i->url(),
585           net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
586     }
587
588     // Use the host name if the domain is empty, i.e. localhost or IP address.
589     if (title.empty())
590       title = i->url().host();
591
592     // If the host name is empty, i.e. file url, use the path.
593     if (title.empty())
594       title = i->url().path();
595     titles.insert(title);
596   }
597
598   std::string display_title;
599   for (std::set<std::string>::iterator i = titles.begin();
600        i != titles.end(); ++i) {
601     if (!display_title.empty())
602       display_title += ", ";
603     display_title += *i;
604   }
605
606   process_->SetName(base::UTF8ToUTF16(display_title));
607 }
608
609 void WorkerProcessHost::DocumentDetached(WorkerMessageFilter* filter,
610                                          unsigned long long document_id) {
611   // Walk all instances and remove the document from their document set.
612   for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
613     int render_frame_id = 0;
614     const WorkerDocumentSet::DocumentInfoSet& documents =
615         i->worker_document_set()->documents();
616     for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
617          documents.begin(); doc != documents.end(); ++doc) {
618       if (doc->filter() == filter && doc->document_id() == document_id) {
619         render_frame_id = doc->render_frame_id();
620         break;
621       }
622     }
623     i->worker_document_set()->Remove(filter, document_id);
624     if (i->worker_document_set()->IsEmpty()) {
625       BrowserThread::PostTask(
626           BrowserThread::UI, FROM_HERE,
627           base::Bind(&WorkerTerminatedCallback,
628                      filter->render_process_id(),
629                      render_frame_id,
630                      process_->GetData().id));
631       // This worker has no more associated documents - shut it down.
632       Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id()));
633       i = instances_.erase(i);
634     } else {
635       ++i;
636     }
637   }
638   ShutdownSocketStreamDispatcherHostIfNecessary();
639 }
640
641 void WorkerProcessHost::TerminateWorker(int worker_route_id) {
642   Send(new WorkerMsg_TerminateWorkerContext(worker_route_id));
643 }
644
645 void WorkerProcessHost::SetBackgrounded(bool backgrounded) {
646   process_->SetBackgrounded(backgrounded);
647 }
648
649 const ChildProcessData& WorkerProcessHost::GetData() {
650   return process_->GetData();
651 }
652
653 std::vector<std::pair<int, int> > WorkerProcessHost::GetRenderFrameIDsForWorker(
654     int worker_route_id) {
655   std::vector<std::pair<int, int> > result;
656   WorkerProcessHost::Instances::const_iterator i;
657   for (i = instances_.begin(); i != instances_.end(); ++i) {
658     if (i->worker_route_id() != worker_route_id)
659       continue;
660     const WorkerDocumentSet::DocumentInfoSet& documents =
661         i->worker_document_set()->documents();
662     for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
663          documents.begin(); doc != documents.end(); ++doc) {
664       result.push_back(
665           std::make_pair(doc->render_process_id(), doc->render_frame_id()));
666     }
667     break;
668   }
669   return result;
670 }
671
672 void WorkerProcessHost::GetContexts(const ResourceHostMsg_Request& request,
673                                     ResourceContext** resource_context,
674                                     net::URLRequestContext** request_context) {
675   *resource_context = resource_context_;
676   *request_context = partition_.url_request_context()->GetURLRequestContext();
677 }
678
679 net::URLRequestContext* WorkerProcessHost::GetRequestContext(
680     ResourceType::Type resource_type) {
681   return partition_.url_request_context()->GetURLRequestContext();
682 }
683
684 WorkerProcessHost::WorkerInstance::WorkerInstance(
685     const GURL& url,
686     const base::string16& name,
687     const base::string16& content_security_policy,
688     blink::WebContentSecurityPolicyType security_policy_type,
689     int worker_route_id,
690     int render_frame_id,
691     ResourceContext* resource_context,
692     const WorkerStoragePartition& partition)
693     : url_(url),
694       closed_(false),
695       name_(name),
696       content_security_policy_(content_security_policy),
697       security_policy_type_(security_policy_type),
698       worker_route_id_(worker_route_id),
699       render_frame_id_(render_frame_id),
700       worker_document_set_(new WorkerDocumentSet()),
701       resource_context_(resource_context),
702       partition_(partition),
703       load_failed_(false) {
704   DCHECK(resource_context_);
705 }
706
707 WorkerProcessHost::WorkerInstance::~WorkerInstance() {
708 }
709
710 void WorkerProcessHost::WorkerInstance::SetMessagePortID(
711     WorkerMessageFilter* filter,
712     int route_id,
713     int message_port_id) {
714   for (FilterList::iterator i = filters_.begin(); i != filters_.end(); ++i) {
715     if (i->filter() == filter && i->route_id() == route_id) {
716       i->set_message_port_id(message_port_id);
717       return;
718     }
719   }
720 }
721
722 // Compares an instance based on the algorithm in the WebWorkers spec - an
723 // instance matches if the origins of the URLs match, and:
724 // a) the names are non-empty and equal
725 // -or-
726 // b) the names are both empty, and the urls are equal
727 bool WorkerProcessHost::WorkerInstance::Matches(
728     const GURL& match_url,
729     const base::string16& match_name,
730     const WorkerStoragePartition& partition,
731     ResourceContext* resource_context) const {
732   // Only match open shared workers.
733   if (closed_)
734     return false;
735
736   // ResourceContext equivalence is being used as a proxy to ensure we only
737   // matched shared workers within the same BrowserContext.
738   if (resource_context_ != resource_context)
739     return false;
740
741   // We must be in the same storage partition otherwise sharing will violate
742   // isolation.
743   if (!partition_.Equals(partition))
744     return false;
745
746   if (url_.GetOrigin() != match_url.GetOrigin())
747     return false;
748
749   if (name_.empty() && match_name.empty())
750     return url_ == match_url;
751
752   return name_ == match_name;
753 }
754
755 void WorkerProcessHost::WorkerInstance::AddFilter(WorkerMessageFilter* filter,
756                                                   int route_id) {
757   CHECK(filter);
758   if (!HasFilter(filter, route_id)) {
759     FilterInfo info(filter, route_id);
760     filters_.push_back(info);
761   }
762 }
763
764 void WorkerProcessHost::WorkerInstance::RemoveFilter(
765     WorkerMessageFilter* filter, int route_id) {
766   for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
767     if (i->filter() == filter && i->route_id() == route_id)
768       i = filters_.erase(i);
769     else
770       ++i;
771   }
772   // Should not be duplicate copies in the filter set.
773   DCHECK(!HasFilter(filter, route_id));
774 }
775
776 void WorkerProcessHost::WorkerInstance::RemoveFilters(
777     WorkerMessageFilter* filter) {
778   for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
779     if (i->filter() == filter)
780       i = filters_.erase(i);
781     else
782       ++i;
783   }
784 }
785
786 bool WorkerProcessHost::WorkerInstance::HasFilter(
787     WorkerMessageFilter* filter, int route_id) const {
788   for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
789        ++i) {
790     if (i->filter() == filter && i->route_id() == route_id)
791       return true;
792   }
793   return false;
794 }
795
796 bool WorkerProcessHost::WorkerInstance::FrameIsParent(
797     int render_process_id, int render_frame_id) const {
798   const WorkerDocumentSet::DocumentInfoSet& parents =
799       worker_document_set()->documents();
800   for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
801            parents.begin();
802        parent_iter != parents.end(); ++parent_iter) {
803     if (parent_iter->render_process_id() == render_process_id &&
804         parent_iter->render_frame_id() == render_frame_id) {
805       return true;
806     }
807   }
808   return false;
809 }
810
811 WorkerProcessHost::WorkerInstance::FilterInfo
812 WorkerProcessHost::WorkerInstance::GetFilter() const {
813   DCHECK(NumFilters() == 1);
814   return *filters_.begin();
815 }
816
817 }  // namespace content