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