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.
5 #include "content/browser/worker_host/worker_process_host.h"
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"
60 #include "content/common/sandbox_win.h"
61 #include "content/public/common/sandboxed_process_launcher_delegate.h"
68 // NOTE: changes to this class need to be reviewed by the security team.
69 class WorkerSandboxedProcessLauncherDelegate
70 : public content::SandboxedProcessLauncherDelegate {
72 WorkerSandboxedProcessLauncherDelegate() {}
73 virtual ~WorkerSandboxedProcessLauncherDelegate() {}
75 virtual void PreSpawnTarget(sandbox::TargetPolicy* policy,
77 AddBaseHandleClosePolicy(policy);
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);
87 host->delegate()->WorkerCrashed(host);
90 void WorkerCreatedCallback(int render_process_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)
98 SiteInstance* site_instance = render_frame_host->GetSiteInstance();
99 GetContentClient()->browser()->WorkerProcessCreated(site_instance,
103 void WorkerTerminatedCallback(int render_process_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)
111 SiteInstance* site_instance = render_frame_host->GetSiteInstance();
112 GetContentClient()->browser()->WorkerProcessTerminated(site_instance,
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_);
127 new BrowserChildProcessHostImpl(PROCESS_TYPE_WORKER, this));
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()));
144 WorkerServiceImpl::GetInstance()->NotifyWorkerDestroyed(
145 this, i->worker_route_id());
148 ChildProcessSecurityPolicyImpl::GetInstance()->Remove(
149 process_->GetData().id);
152 bool WorkerProcessHost::Send(IPC::Message* message) {
153 return process_->Send(message);
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())
161 #if defined(OS_LINUX)
162 int flags = ChildProcessHost::CHILD_ALLOW_SELF;
164 int flags = ChildProcessHost::CHILD_NORMAL;
167 base::FilePath exe_path = ChildProcessHost::GetChildPath(flags);
168 if (exe_path.empty())
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);
177 static const char* const kSwitchNames[] = {
178 switches::kDisableApplicationCache,
179 switches::kDisableDatabases,
181 switches::kDisableDesktopNotifications,
183 switches::kDisableFileSystem,
184 switches::kDisableSeccompFilterSandbox,
185 switches::kEnableExperimentalWebPlatformFeatures,
186 switches::kEnableServiceWorker,
187 #if defined(OS_MACOSX)
188 switches::kEnableSandboxLogging,
190 switches::kJavaScriptFlags,
193 cmd_line->CopySwitchesFrom(*CommandLine::ForCurrentProcess(), kSwitchNames,
194 arraysize(kSwitchNames));
196 #if defined(OS_POSIX)
197 bool use_zygote = true;
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);
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");
225 new WorkerSandboxedProcessLauncherDelegate,
227 #elif defined(OS_POSIX)
229 base::EnvironmentMap(),
233 ChildProcessSecurityPolicyImpl::GetInstance()->AddWorker(
234 process_->GetData().id, render_process_id);
235 CreateMessageFilters(render_process_id);
237 BrowserThread::PostTask(
238 BrowserThread::UI, FROM_HERE,
239 base::Bind(&WorkerCreatedCallback,
242 process_->GetData().id));
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_);
252 net::URLRequestContextGetter* url_request_context =
253 partition_.url_request_context();
255 ResourceMessageFilter::GetContextsCallback get_contexts_callback(
256 base::Bind(&WorkerProcessHost::GetContexts,
257 base::Unretained(this)));
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);
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,
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,
282 partition_.filesystem_context(),
283 blob_storage_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()));
294 SocketStreamDispatcherHost::GetRequestContextCallback
295 request_context_callback(
296 base::Bind(&WorkerProcessHost::GetRequestContext,
297 base::Unretained(this)));
299 SocketStreamDispatcherHost* socket_stream_dispatcher_host =
300 new SocketStreamDispatcherHost(
302 request_context_callback,
304 socket_stream_dispatcher_host_ = socket_stream_dispatcher_host;
305 process_->AddFilter(socket_stream_dispatcher_host);
306 process_->AddFilter(new WorkerDevToolsMessageFilter(process_->GetData().id));
308 new IndexedDBDispatcherHost(partition_.indexed_db_context()));
311 void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) {
312 ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL(
313 process_->GetData().id, instance.url());
315 instances_.push_back(instance);
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));
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()));
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));
349 void WorkerProcessHost::OnProcessLaunched() {
350 process_launched_ = true;
352 WorkerServiceImpl::GetInstance()->NotifyWorkerProcessCreated();
355 bool WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
356 bool msg_is_ok = 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,
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()
379 RecordAction(base::UserMetricsAction("BadMessageTerminate_WPH"));
381 process_->GetData().handle, RESULT_CODE_KILLED_BAD_MESSAGE, false);
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).
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) {
413 void WorkerProcessHost::OnWorkerScriptLoaded(int worker_route_id) {
414 WorkerDevToolsManager::GetInstance()->WorkerContextStarted(this,
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) {
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()));
433 process_->GetData().handle, RESULT_CODE_NORMAL_EXIT, false);
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)
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)
446 j->filter()->Send(new ViewMsg_WorkerConnected(j->route_id()));
452 void WorkerProcessHost::OnAllowDatabase(int worker_route_id,
454 const base::string16& name,
455 const base::string16& display_name,
456 unsigned long estimated_size,
458 *result = GetContentClient()->browser()->AllowWorkerDatabase(
459 url, name, display_name, estimated_size, resource_context_,
460 GetRenderFrameIDsForWorker(worker_route_id));
463 void WorkerProcessHost::OnAllowFileSystem(int worker_route_id,
466 *result = GetContentClient()->browser()->AllowWorkerFileSystem(
467 url, resource_context_, GetRenderFrameIDsForWorker(worker_route_id));
470 void WorkerProcessHost::OnAllowIndexedDB(int worker_route_id,
472 const base::string16& name,
474 *result = GetContentClient()->browser()->AllowWorkerIndexedDB(
475 url, name, resource_context_,
476 GetRenderFrameIDsForWorker(worker_route_id));
479 void WorkerProcessHost::OnForceKillWorkerProcess() {
480 if (process_ && process_launched_)
482 process_->GetData().handle, RESULT_CODE_NORMAL_EXIT, false);
484 RecordAction(base::UserMetricsAction("WorkerProcess_BadProcessToKill"));
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;
495 if (!WorkerMsg_Connect::Read(
496 &message, &sent_message_port_id, &new_routing_id)) {
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(),
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));
512 // Send any queued messages for the sent port.
513 MessagePortService::GetInstance()->SendQueuedMessagesIfPossible(
514 sent_message_port_id);
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);
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.
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;
536 void WorkerProcessHost::FilterShutdown(WorkerMessageFilter* filter) {
537 for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
538 bool shutdown = false;
539 i->RemoveFilters(filter);
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();
551 i->worker_document_set()->RemoveAll(filter);
552 if (i->worker_document_set()->IsEmpty()) {
556 BrowserThread::PostTask(
557 BrowserThread::UI, FROM_HERE,
558 base::Bind(&WorkerTerminatedCallback,
559 filter->render_process_id(),
561 process_->GetData().id));
562 Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id()));
563 i = instances_.erase(i);
568 ShutdownSocketStreamDispatcherHostIfNecessary();
571 bool WorkerProcessHost::CanShutdown() {
572 return instances_.empty();
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_);
583 title = net::registry_controlled_domains::GetDomainAndRegistry(
585 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
588 // Use the host name if the domain is empty, i.e. localhost or IP address.
590 title = i->url().host();
592 // If the host name is empty, i.e. file url, use the path.
594 title = i->url().path();
595 titles.insert(title);
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 += ", ";
606 process_->SetName(base::UTF8ToUTF16(display_title));
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();
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(),
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);
638 ShutdownSocketStreamDispatcherHostIfNecessary();
641 void WorkerProcessHost::TerminateWorker(int worker_route_id) {
642 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id));
645 void WorkerProcessHost::SetBackgrounded(bool backgrounded) {
646 process_->SetBackgrounded(backgrounded);
649 const ChildProcessData& WorkerProcessHost::GetData() {
650 return process_->GetData();
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)
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) {
665 std::make_pair(doc->render_process_id(), doc->render_frame_id()));
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();
679 net::URLRequestContext* WorkerProcessHost::GetRequestContext(
680 ResourceType::Type resource_type) {
681 return partition_.url_request_context()->GetURLRequestContext();
684 WorkerProcessHost::WorkerInstance::WorkerInstance(
686 const base::string16& name,
687 const base::string16& content_security_policy,
688 blink::WebContentSecurityPolicyType security_policy_type,
691 ResourceContext* resource_context,
692 const WorkerStoragePartition& partition)
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_);
707 WorkerProcessHost::WorkerInstance::~WorkerInstance() {
710 void WorkerProcessHost::WorkerInstance::SetMessagePortID(
711 WorkerMessageFilter* filter,
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);
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
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.
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)
741 // We must be in the same storage partition otherwise sharing will violate
743 if (!partition_.Equals(partition))
746 if (url_.GetOrigin() != match_url.GetOrigin())
749 if (name_.empty() && match_name.empty())
750 return url_ == match_url;
752 return name_ == match_name;
755 void WorkerProcessHost::WorkerInstance::AddFilter(WorkerMessageFilter* filter,
758 if (!HasFilter(filter, route_id)) {
759 FilterInfo info(filter, route_id);
760 filters_.push_back(info);
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);
772 // Should not be duplicate copies in the filter set.
773 DCHECK(!HasFilter(filter, route_id));
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);
786 bool WorkerProcessHost::WorkerInstance::HasFilter(
787 WorkerMessageFilter* filter, int route_id) const {
788 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
790 if (i->filter() == filter && i->route_id() == route_id)
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 =
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) {
811 WorkerProcessHost::WorkerInstance::FilterInfo
812 WorkerProcessHost::WorkerInstance::GetFilter() const {
813 DCHECK(NumFilters() == 1);
814 return *filters_.begin();
817 } // namespace content