IndexedDBFactory now ForceCloses databases.
[chromium-blink-merge.git] / content / browser / worker_host / worker_process_host.cc
blob9b95d4dd09e78cb6eed6de0940242ddbfc83ed3b
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"
7 #include <set>
8 #include <string>
9 #include <vector>
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"
59 #if defined(OS_WIN)
60 #include "content/common/sandbox_win.h"
61 #include "content/public/common/sandboxed_process_launcher_delegate.h"
62 #endif
64 namespace content {
65 namespace {
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() {}
75 virtual void PreSpawnTarget(sandbox::TargetPolicy* policy,
76 bool* success) {
77 AddBaseHandleClosePolicy(policy);
80 #endif // OS_WIN
82 } // namespace
84 // Notifies RenderViewHost that one or more worker objects crashed.
85 void WorkerCrashCallback(int render_process_unique_id, int render_frame_id) {
86 RenderFrameHostImpl* host =
87 RenderFrameHostImpl::FromID(render_process_unique_id, render_frame_id);
88 if (host)
89 host->delegate()->WorkerCrashed();
92 WorkerProcessHost::WorkerProcessHost(
93 ResourceContext* resource_context,
94 const WorkerStoragePartition& partition)
95 : resource_context_(resource_context),
96 partition_(partition),
97 process_launched_(false) {
98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
99 DCHECK(resource_context_);
100 process_.reset(
101 new BrowserChildProcessHostImpl(PROCESS_TYPE_WORKER, this));
104 WorkerProcessHost::~WorkerProcessHost() {
105 // If we crashed, tell the RenderViewHosts.
106 for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
107 const WorkerDocumentSet::DocumentInfoSet& parents =
108 i->worker_document_set()->documents();
109 for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
110 parents.begin(); parent_iter != parents.end(); ++parent_iter) {
111 BrowserThread::PostTask(
112 BrowserThread::UI, FROM_HERE,
113 base::Bind(&WorkerCrashCallback, parent_iter->render_process_id(),
114 parent_iter->render_frame_id()));
116 WorkerServiceImpl::GetInstance()->NotifyWorkerDestroyed(
117 this, i->worker_route_id());
120 ChildProcessSecurityPolicyImpl::GetInstance()->Remove(
121 process_->GetData().id);
124 bool WorkerProcessHost::Send(IPC::Message* message) {
125 return process_->Send(message);
128 bool WorkerProcessHost::Init(int render_process_id) {
129 std::string channel_id = process_->GetHost()->CreateChannel();
130 if (channel_id.empty())
131 return false;
133 #if defined(OS_LINUX)
134 int flags = ChildProcessHost::CHILD_ALLOW_SELF;
135 #else
136 int flags = ChildProcessHost::CHILD_NORMAL;
137 #endif
139 base::FilePath exe_path = ChildProcessHost::GetChildPath(flags);
140 if (exe_path.empty())
141 return false;
143 CommandLine* cmd_line = new CommandLine(exe_path);
144 cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kWorkerProcess);
145 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
146 std::string locale = GetContentClient()->browser()->GetApplicationLocale();
147 cmd_line->AppendSwitchASCII(switches::kLang, locale);
149 static const char* const kSwitchNames[] = {
150 switches::kDisableApplicationCache,
151 switches::kDisableDatabases,
152 #if defined(OS_WIN)
153 switches::kDisableDesktopNotifications,
154 #endif
155 switches::kDisableFileSystem,
156 switches::kDisableSeccompFilterSandbox,
157 switches::kEnableExperimentalWebPlatformFeatures,
158 switches::kEnableServiceWorker,
159 #if defined(OS_MACOSX)
160 switches::kEnableSandboxLogging,
161 #endif
162 switches::kJavaScriptFlags,
163 switches::kNoSandbox
165 cmd_line->CopySwitchesFrom(*CommandLine::ForCurrentProcess(), kSwitchNames,
166 arraysize(kSwitchNames));
168 #if defined(OS_POSIX)
169 bool use_zygote = true;
171 if (CommandLine::ForCurrentProcess()->HasSwitch(
172 switches::kWaitForDebuggerChildren)) {
173 // Look to pass-on the kWaitForDebugger flag.
174 std::string value = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
175 switches::kWaitForDebuggerChildren);
176 if (value.empty() || value == switches::kWorkerProcess) {
177 cmd_line->AppendSwitch(switches::kWaitForDebugger);
178 use_zygote = false;
182 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren)) {
183 // Look to pass-on the kDebugOnStart flag.
184 std::string value = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
185 switches::kDebugChildren);
186 if (value.empty() || value == switches::kWorkerProcess) {
187 // launches a new xterm, and runs the worker process in gdb, reading
188 // optional commands from gdb_chrome file in the working directory.
189 cmd_line->PrependWrapper("xterm -e gdb -x gdb_chrome --args");
190 use_zygote = false;
193 #endif
195 process_->Launch(
196 #if defined(OS_WIN)
197 new WorkerSandboxedProcessLauncherDelegate,
198 #elif defined(OS_POSIX)
199 use_zygote,
200 base::EnvironmentMap(),
201 #endif
202 cmd_line);
204 ChildProcessSecurityPolicyImpl::GetInstance()->AddWorker(
205 process_->GetData().id, render_process_id);
206 CreateMessageFilters(render_process_id);
208 return true;
211 void WorkerProcessHost::CreateMessageFilters(int render_process_id) {
212 ChromeBlobStorageContext* blob_storage_context =
213 GetChromeBlobStorageContextForResourceContext(resource_context_);
214 StreamContext* stream_context =
215 GetStreamContextForResourceContext(resource_context_);
217 net::URLRequestContextGetter* url_request_context =
218 partition_.url_request_context();
220 ResourceMessageFilter::GetContextsCallback get_contexts_callback(
221 base::Bind(&WorkerProcessHost::GetContexts,
222 base::Unretained(this)));
224 ResourceMessageFilter* resource_message_filter = new ResourceMessageFilter(
225 process_->GetData().id, PROCESS_TYPE_WORKER,
226 partition_.appcache_service(),
227 blob_storage_context,
228 partition_.filesystem_context(),
229 get_contexts_callback);
230 process_->AddFilter(resource_message_filter);
232 MessagePortMessageFilter* message_port_message_filter =
233 new MessagePortMessageFilter(
234 base::Bind(&WorkerServiceImpl::next_worker_route_id,
235 base::Unretained(WorkerServiceImpl::GetInstance())));
236 process_->AddFilter(message_port_message_filter);
237 worker_message_filter_ = new WorkerMessageFilter(render_process_id,
238 resource_context_,
239 partition_,
240 message_port_message_filter);
241 process_->AddFilter(worker_message_filter_.get());
242 process_->AddFilter(new AppCacheDispatcherHost(
243 partition_.appcache_service(), process_->GetData().id));
244 process_->AddFilter(new FileAPIMessageFilter(
245 process_->GetData().id,
246 url_request_context,
247 partition_.filesystem_context(),
248 blob_storage_context,
249 stream_context));
250 process_->AddFilter(new FileUtilitiesMessageFilter(
251 process_->GetData().id));
252 process_->AddFilter(new MimeRegistryMessageFilter());
253 process_->AddFilter(new DatabaseMessageFilter(partition_.database_tracker()));
254 process_->AddFilter(new QuotaDispatcherHost(
255 process_->GetData().id,
256 partition_.quota_manager(),
257 GetContentClient()->browser()->CreateQuotaPermissionContext()));
259 SocketStreamDispatcherHost::GetRequestContextCallback
260 request_context_callback(
261 base::Bind(&WorkerProcessHost::GetRequestContext,
262 base::Unretained(this)));
264 SocketStreamDispatcherHost* socket_stream_dispatcher_host =
265 new SocketStreamDispatcherHost(
266 render_process_id,
267 request_context_callback,
268 resource_context_);
269 socket_stream_dispatcher_host_ = socket_stream_dispatcher_host;
270 process_->AddFilter(socket_stream_dispatcher_host);
271 process_->AddFilter(new WorkerDevToolsMessageFilter(process_->GetData().id));
272 process_->AddFilter(
273 new IndexedDBDispatcherHost(partition_.indexed_db_context()));
276 void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) {
277 ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL(
278 process_->GetData().id, instance.url());
280 instances_.push_back(instance);
282 WorkerProcessMsg_CreateWorker_Params params;
283 params.url = instance.url();
284 params.name = instance.name();
285 params.content_security_policy = instance.content_security_policy();
286 params.security_policy_type = instance.security_policy_type();
287 params.route_id = instance.worker_route_id();
288 params.creator_process_id = instance.parent_process_id();
289 params.shared_worker_appcache_id = instance.main_resource_appcache_id();
290 Send(new WorkerProcessMsg_CreateWorker(params));
292 UpdateTitle();
294 // Walk all pending filters and let them know the worker has been created
295 // (could be more than one in the case where we had to queue up worker
296 // creation because the worker process limit was reached).
297 for (WorkerInstance::FilterList::const_iterator i =
298 instance.filters().begin();
299 i != instance.filters().end(); ++i) {
300 CHECK(i->first);
301 i->first->Send(new ViewMsg_WorkerCreated(i->second));
305 bool WorkerProcessHost::FilterMessage(const IPC::Message& message,
306 WorkerMessageFilter* filter) {
307 for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
308 if (!i->closed() && i->HasFilter(filter, message.routing_id())) {
309 RelayMessage(message, worker_message_filter_.get(), i->worker_route_id());
310 return true;
314 return false;
317 void WorkerProcessHost::OnProcessLaunched() {
318 process_launched_ = true;
320 WorkerServiceImpl::GetInstance()->NotifyWorkerProcessCreated();
323 bool WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
324 bool msg_is_ok = true;
325 bool handled = true;
326 IPC_BEGIN_MESSAGE_MAP_EX(WorkerProcessHost, message, msg_is_ok)
327 IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerContextClosed,
328 OnWorkerContextClosed)
329 IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowDatabase, OnAllowDatabase)
330 IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowFileSystem, OnAllowFileSystem)
331 IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowIndexedDB, OnAllowIndexedDB)
332 IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_ForceKillWorker,
333 OnForceKillWorkerProcess)
334 IPC_MESSAGE_UNHANDLED(handled = false)
335 IPC_END_MESSAGE_MAP_EX()
337 if (!msg_is_ok) {
338 NOTREACHED();
339 RecordAction(UserMetricsAction("BadMessageTerminate_WPH"));
340 base::KillProcess(
341 process_->GetData().handle, RESULT_CODE_KILLED_BAD_MESSAGE, false);
344 if (handled)
345 return true;
347 if (message.type() == WorkerHostMsg_WorkerContextDestroyed::ID) {
348 WorkerServiceImpl::GetInstance()->NotifyWorkerDestroyed(
349 this, message.routing_id());
352 for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
353 if (i->worker_route_id() == message.routing_id()) {
354 if (message.type() == WorkerHostMsg_WorkerContextDestroyed::ID) {
355 instances_.erase(i);
356 UpdateTitle();
358 return true;
361 return false;
364 // Sent to notify the browser process when a worker context invokes close(), so
365 // no new connections are sent to shared workers.
366 void WorkerProcessHost::OnWorkerContextClosed(int worker_route_id) {
367 for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
368 if (i->worker_route_id() == worker_route_id) {
369 // Set the closed flag - this will stop any further messages from
370 // being sent to the worker (messages can still be sent from the worker,
371 // for exception reporting, etc).
372 i->set_closed(true);
373 break;
378 void WorkerProcessHost::OnAllowDatabase(int worker_route_id,
379 const GURL& url,
380 const base::string16& name,
381 const base::string16& display_name,
382 unsigned long estimated_size,
383 bool* result) {
384 *result = GetContentClient()->browser()->AllowWorkerDatabase(
385 url, name, display_name, estimated_size, resource_context_,
386 GetRenderFrameIDsForWorker(worker_route_id));
389 void WorkerProcessHost::OnAllowFileSystem(int worker_route_id,
390 const GURL& url,
391 bool* result) {
392 *result = GetContentClient()->browser()->AllowWorkerFileSystem(
393 url, resource_context_, GetRenderFrameIDsForWorker(worker_route_id));
396 void WorkerProcessHost::OnAllowIndexedDB(int worker_route_id,
397 const GURL& url,
398 const base::string16& name,
399 bool* result) {
400 *result = GetContentClient()->browser()->AllowWorkerIndexedDB(
401 url, name, resource_context_,
402 GetRenderFrameIDsForWorker(worker_route_id));
405 void WorkerProcessHost::OnForceKillWorkerProcess() {
406 if (process_ && process_launched_)
407 base::KillProcess(
408 process_->GetData().handle, RESULT_CODE_NORMAL_EXIT, false);
409 else
410 RecordAction(UserMetricsAction("WorkerProcess_BadProcessToKill"));
413 void WorkerProcessHost::RelayMessage(
414 const IPC::Message& message,
415 WorkerMessageFilter* filter,
416 int route_id) {
417 if (message.type() == WorkerMsg_Connect::ID) {
418 // Crack the SharedWorker Connect message to setup routing for the port.
419 int sent_message_port_id;
420 int new_routing_id;
421 if (!WorkerMsg_Connect::Read(
422 &message, &sent_message_port_id, &new_routing_id)) {
423 return;
425 new_routing_id = filter->GetNextRoutingID();
426 MessagePortService::GetInstance()->UpdateMessagePort(
427 sent_message_port_id,
428 filter->message_port_message_filter(),
429 new_routing_id);
431 // Resend the message with the new routing id.
432 filter->Send(new WorkerMsg_Connect(
433 route_id, sent_message_port_id, new_routing_id));
435 // Send any queued messages for the sent port.
436 MessagePortService::GetInstance()->SendQueuedMessagesIfPossible(
437 sent_message_port_id);
438 } else {
439 IPC::Message* new_message = new IPC::Message(message);
440 new_message->set_routing_id(route_id);
441 filter->Send(new_message);
442 if (message.type() == WorkerMsg_StartWorkerContext::ID) {
443 WorkerDevToolsManager::GetInstance()->WorkerContextStarted(
444 this, route_id);
446 return;
450 void WorkerProcessHost::ShutdownSocketStreamDispatcherHostIfNecessary() {
451 if (!instances_.size() && socket_stream_dispatcher_host_.get()) {
452 // We can assume that this object is going to delete, because
453 // currently a WorkerInstance will never be added to a WorkerProcessHost
454 // once it is initialized.
456 // SocketStreamDispatcherHost should be notified now that the worker
457 // process will shutdown soon.
458 socket_stream_dispatcher_host_->Shutdown();
459 socket_stream_dispatcher_host_ = NULL;
463 void WorkerProcessHost::FilterShutdown(WorkerMessageFilter* filter) {
464 for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
465 bool shutdown = false;
466 i->RemoveFilters(filter);
468 i->worker_document_set()->RemoveAll(filter);
469 if (i->worker_document_set()->IsEmpty()) {
470 shutdown = true;
472 if (shutdown) {
473 Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id()));
474 i = instances_.erase(i);
475 } else {
476 ++i;
479 ShutdownSocketStreamDispatcherHostIfNecessary();
482 bool WorkerProcessHost::CanShutdown() {
483 return instances_.empty();
486 void WorkerProcessHost::UpdateTitle() {
487 std::set<std::string> titles;
488 for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
489 // Allow the embedder first crack at special casing the title.
490 std::string title = GetContentClient()->browser()->
491 GetWorkerProcessTitle(i->url(), resource_context_);
493 if (title.empty()) {
494 title = net::registry_controlled_domains::GetDomainAndRegistry(
495 i->url(),
496 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
499 // Use the host name if the domain is empty, i.e. localhost or IP address.
500 if (title.empty())
501 title = i->url().host();
503 // If the host name is empty, i.e. file url, use the path.
504 if (title.empty())
505 title = i->url().path();
506 titles.insert(title);
509 std::string display_title;
510 for (std::set<std::string>::iterator i = titles.begin();
511 i != titles.end(); ++i) {
512 if (!display_title.empty())
513 display_title += ", ";
514 display_title += *i;
517 process_->SetName(base::UTF8ToUTF16(display_title));
520 void WorkerProcessHost::DocumentDetached(WorkerMessageFilter* filter,
521 unsigned long long document_id) {
522 // Walk all instances and remove the document from their document set.
523 for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
524 i->worker_document_set()->Remove(filter, document_id);
525 if (i->worker_document_set()->IsEmpty()) {
526 // This worker has no more associated documents - shut it down.
527 Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id()));
528 i = instances_.erase(i);
529 } else {
530 ++i;
533 ShutdownSocketStreamDispatcherHostIfNecessary();
536 void WorkerProcessHost::TerminateWorker(int worker_route_id) {
537 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id));
540 void WorkerProcessHost::SetBackgrounded(bool backgrounded) {
541 process_->SetBackgrounded(backgrounded);
544 const ChildProcessData& WorkerProcessHost::GetData() {
545 return process_->GetData();
548 std::vector<std::pair<int, int> > WorkerProcessHost::GetRenderFrameIDsForWorker(
549 int worker_route_id) {
550 std::vector<std::pair<int, int> > result;
551 WorkerProcessHost::Instances::const_iterator i;
552 for (i = instances_.begin(); i != instances_.end(); ++i) {
553 if (i->worker_route_id() != worker_route_id)
554 continue;
555 const WorkerDocumentSet::DocumentInfoSet& documents =
556 i->worker_document_set()->documents();
557 for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
558 documents.begin(); doc != documents.end(); ++doc) {
559 result.push_back(
560 std::make_pair(doc->render_process_id(), doc->render_frame_id()));
562 break;
564 return result;
567 void WorkerProcessHost::GetContexts(const ResourceHostMsg_Request& request,
568 ResourceContext** resource_context,
569 net::URLRequestContext** request_context) {
570 *resource_context = resource_context_;
571 *request_context = partition_.url_request_context()->GetURLRequestContext();
574 net::URLRequestContext* WorkerProcessHost::GetRequestContext(
575 ResourceType::Type resource_type) {
576 return partition_.url_request_context()->GetURLRequestContext();
579 WorkerProcessHost::WorkerInstance::WorkerInstance(
580 const GURL& url,
581 const base::string16& name,
582 const base::string16& content_security_policy,
583 blink::WebContentSecurityPolicyType security_policy_type,
584 int worker_route_id,
585 int parent_process_id,
586 int64 main_resource_appcache_id,
587 ResourceContext* resource_context,
588 const WorkerStoragePartition& partition)
589 : url_(url),
590 closed_(false),
591 name_(name),
592 content_security_policy_(content_security_policy),
593 security_policy_type_(security_policy_type),
594 worker_route_id_(worker_route_id),
595 parent_process_id_(parent_process_id),
596 main_resource_appcache_id_(main_resource_appcache_id),
597 worker_document_set_(new WorkerDocumentSet()),
598 resource_context_(resource_context),
599 partition_(partition) {
600 DCHECK(resource_context_);
603 WorkerProcessHost::WorkerInstance::WorkerInstance(
604 const GURL& url,
605 bool shared,
606 const base::string16& name,
607 ResourceContext* resource_context,
608 const WorkerStoragePartition& partition)
609 : url_(url),
610 closed_(false),
611 name_(name),
612 worker_route_id_(MSG_ROUTING_NONE),
613 parent_process_id_(0),
614 main_resource_appcache_id_(0),
615 worker_document_set_(new WorkerDocumentSet()),
616 resource_context_(resource_context),
617 partition_(partition) {
618 DCHECK(resource_context_);
621 WorkerProcessHost::WorkerInstance::~WorkerInstance() {
624 // Compares an instance based on the algorithm in the WebWorkers spec - an
625 // instance matches if the origins of the URLs match, and:
626 // a) the names are non-empty and equal
627 // -or-
628 // b) the names are both empty, and the urls are equal
629 bool WorkerProcessHost::WorkerInstance::Matches(
630 const GURL& match_url,
631 const base::string16& match_name,
632 const WorkerStoragePartition& partition,
633 ResourceContext* resource_context) const {
634 // Only match open shared workers.
635 if (closed_)
636 return false;
638 // ResourceContext equivalence is being used as a proxy to ensure we only
639 // matched shared workers within the same BrowserContext.
640 if (resource_context_ != resource_context)
641 return false;
643 // We must be in the same storage partition otherwise sharing will violate
644 // isolation.
645 if (!partition_.Equals(partition))
646 return false;
648 if (url_.GetOrigin() != match_url.GetOrigin())
649 return false;
651 if (name_.empty() && match_name.empty())
652 return url_ == match_url;
654 return name_ == match_name;
657 void WorkerProcessHost::WorkerInstance::AddFilter(WorkerMessageFilter* filter,
658 int route_id) {
659 CHECK(filter);
660 if (!HasFilter(filter, route_id)) {
661 FilterInfo info(filter, route_id);
662 filters_.push_back(info);
666 void WorkerProcessHost::WorkerInstance::RemoveFilter(
667 WorkerMessageFilter* filter, int route_id) {
668 for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
669 if (i->first == filter && i->second == route_id)
670 i = filters_.erase(i);
671 else
672 ++i;
674 // Should not be duplicate copies in the filter set.
675 DCHECK(!HasFilter(filter, route_id));
678 void WorkerProcessHost::WorkerInstance::RemoveFilters(
679 WorkerMessageFilter* filter) {
680 for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
681 if (i->first == filter)
682 i = filters_.erase(i);
683 else
684 ++i;
688 bool WorkerProcessHost::WorkerInstance::HasFilter(
689 WorkerMessageFilter* filter, int route_id) const {
690 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
691 ++i) {
692 if (i->first == filter && i->second == route_id)
693 return true;
695 return false;
698 bool WorkerProcessHost::WorkerInstance::FrameIsParent(
699 int render_process_id, int render_frame_id) const {
700 const WorkerDocumentSet::DocumentInfoSet& parents =
701 worker_document_set()->documents();
702 for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
703 parents.begin();
704 parent_iter != parents.end(); ++parent_iter) {
705 if (parent_iter->render_process_id() == render_process_id &&
706 parent_iter->render_frame_id() == render_frame_id) {
707 return true;
710 return false;
713 WorkerProcessHost::WorkerInstance::FilterInfo
714 WorkerProcessHost::WorkerInstance::GetFilter() const {
715 DCHECK(NumFilters() == 1);
716 return *filters_.begin();
719 } // namespace content