[content shell] implement testRunner.overridePreference
[chromium-blink-merge.git] / content / browser / worker_host / worker_process_host.cc
blob953e868ae1fd5e9e29ad1058e10d3ecabfc70d0c
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.h"
17 #include "base/string_util.h"
18 #include "base/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/debugger/worker_devtools_manager.h"
24 #include "content/browser/debugger/worker_devtools_message_filter.h"
25 #include "content/browser/fileapi/fileapi_message_filter.h"
26 #include "content/browser/in_process_webkit/indexed_db_dispatcher_host.h"
27 #include "content/browser/mime_registry_message_filter.h"
28 #include "content/browser/renderer_host/database_message_filter.h"
29 #include "content/browser/renderer_host/file_utilities_message_filter.h"
30 #include "content/browser/renderer_host/render_view_host_delegate.h"
31 #include "content/browser/renderer_host/render_view_host_impl.h"
32 #include "content/browser/renderer_host/socket_stream_dispatcher_host.h"
33 #include "content/browser/resource_context_impl.h"
34 #include "content/browser/worker_host/message_port_service.h"
35 #include "content/browser/worker_host/worker_message_filter.h"
36 #include "content/browser/worker_host/worker_service_impl.h"
37 #include "content/common/child_process_host_impl.h"
38 #include "content/common/debug_flags.h"
39 #include "content/common/view_messages.h"
40 #include "content/common/worker_messages.h"
41 #include "content/public/browser/browser_thread.h"
42 #include "content/public/browser/content_browser_client.h"
43 #include "content/public/browser/user_metrics.h"
44 #include "content/public/common/content_switches.h"
45 #include "content/public/common/result_codes.h"
46 #include "ipc/ipc_switches.h"
47 #include "net/base/mime_util.h"
48 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
49 #include "net/url_request/url_request_context_getter.h"
50 #include "ui/base/ui_base_switches.h"
51 #include "webkit/fileapi/file_system_context.h"
52 #include "webkit/fileapi/sandbox_mount_point_provider.h"
53 #include "webkit/glue/resource_type.h"
55 namespace content {
56 namespace {
58 // Helper class that we pass to SocketStreamDispatcherHost so that it can find
59 // the right net::URLRequestContext for a request.
60 class URLRequestContextSelector
61 : public ResourceMessageFilter::URLRequestContextSelector {
62 public:
63 explicit URLRequestContextSelector(
64 net::URLRequestContextGetter* url_request_context,
65 net::URLRequestContextGetter* media_url_request_context)
66 : url_request_context_(url_request_context),
67 media_url_request_context_(media_url_request_context) {
69 virtual ~URLRequestContextSelector() {}
71 virtual net::URLRequestContext* GetRequestContext(
72 ResourceType::Type resource_type) {
73 if (resource_type == ResourceType::MEDIA)
74 return media_url_request_context_->GetURLRequestContext();
75 return url_request_context_->GetURLRequestContext();
78 private:
79 net::URLRequestContextGetter* url_request_context_;
80 net::URLRequestContextGetter* media_url_request_context_;
83 } // namespace
85 // Notifies RenderViewHost that one or more worker objects crashed.
86 void WorkerCrashCallback(int render_process_unique_id, int render_view_id) {
87 RenderViewHostImpl* host =
88 RenderViewHostImpl::FromID(render_process_unique_id, render_view_id);
89 if (host)
90 host->GetDelegate()->WorkerCrashed();
93 WorkerProcessHost::WorkerProcessHost(
94 ResourceContext* resource_context,
95 const WorkerStoragePartition& partition)
96 : resource_context_(resource_context),
97 partition_(partition) {
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_view_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 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::kDisableWebSockets,
158 #if defined(OS_MACOSX)
159 switches::kEnableSandboxLogging,
160 #endif
162 cmd_line->CopySwitchesFrom(*CommandLine::ForCurrentProcess(), kSwitchNames,
163 arraysize(kSwitchNames));
165 #if defined(OS_POSIX)
166 bool use_zygote = true;
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;
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;
190 #endif
192 process_->Launch(
193 #if defined(OS_WIN)
194 FilePath(),
195 #elif defined(OS_POSIX)
196 use_zygote,
197 base::EnvironmentVector(),
198 #endif
199 cmd_line);
201 ChildProcessSecurityPolicyImpl::GetInstance()->AddWorker(
202 process_->GetData().id, render_process_id);
203 CreateMessageFilters(render_process_id);
205 return true;
208 void WorkerProcessHost::CreateMessageFilters(int render_process_id) {
209 ChromeBlobStorageContext* blob_storage_context =
210 GetChromeBlobStorageContextForResourceContext(resource_context_);
212 net::URLRequestContextGetter* url_request_context =
213 partition_.url_request_context();
214 net::URLRequestContextGetter* media_url_request_context =
215 partition_.url_request_context();
217 ResourceMessageFilter* resource_message_filter = new ResourceMessageFilter(
218 process_->GetData().id, PROCESS_TYPE_WORKER, resource_context_,
219 partition_.appcache_service(),
220 blob_storage_context,
221 new URLRequestContextSelector(url_request_context,
222 media_url_request_context));
223 process_->GetHost()->AddFilter(resource_message_filter);
225 worker_message_filter_ = new WorkerMessageFilter(
226 render_process_id, resource_context_, partition_,
227 base::Bind(&WorkerServiceImpl::next_worker_route_id,
228 base::Unretained(WorkerServiceImpl::GetInstance())));
229 process_->GetHost()->AddFilter(worker_message_filter_);
230 process_->GetHost()->AddFilter(new AppCacheDispatcherHost(
231 partition_.appcache_service(),
232 process_->GetData().id));
233 process_->GetHost()->AddFilter(new FileAPIMessageFilter(
234 process_->GetData().id,
235 url_request_context,
236 partition_.filesystem_context(),
237 blob_storage_context));
238 process_->GetHost()->AddFilter(new FileUtilitiesMessageFilter(
239 process_->GetData().id));
240 process_->GetHost()->AddFilter(new MimeRegistryMessageFilter());
241 process_->GetHost()->AddFilter(
242 new DatabaseMessageFilter(partition_.database_tracker()));
244 SocketStreamDispatcherHost* socket_stream_dispatcher_host =
245 new SocketStreamDispatcherHost(
246 render_process_id,
247 new URLRequestContextSelector(url_request_context,
248 media_url_request_context),
249 resource_context_);
250 process_->GetHost()->AddFilter(socket_stream_dispatcher_host);
251 process_->GetHost()->AddFilter(
252 new WorkerDevToolsMessageFilter(process_->GetData().id));
253 process_->GetHost()->AddFilter(new IndexedDBDispatcherHost(
254 process_->GetData().id, partition_.indexed_db_context()));
257 void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) {
258 ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL(
259 process_->GetData().id, instance.url());
261 instances_.push_back(instance);
263 WorkerProcessMsg_CreateWorker_Params params;
264 params.url = instance.url();
265 params.name = instance.name();
266 params.route_id = instance.worker_route_id();
267 params.creator_process_id = instance.parent_process_id();
268 params.shared_worker_appcache_id = instance.main_resource_appcache_id();
269 Send(new WorkerProcessMsg_CreateWorker(params));
271 UpdateTitle();
273 // Walk all pending filters and let them know the worker has been created
274 // (could be more than one in the case where we had to queue up worker
275 // creation because the worker process limit was reached).
276 for (WorkerInstance::FilterList::const_iterator i =
277 instance.filters().begin();
278 i != instance.filters().end(); ++i) {
279 CHECK(i->first);
280 i->first->Send(new ViewMsg_WorkerCreated(i->second));
284 bool WorkerProcessHost::FilterMessage(const IPC::Message& message,
285 WorkerMessageFilter* filter) {
286 for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
287 if (!i->closed() && i->HasFilter(filter, message.routing_id())) {
288 RelayMessage(message, worker_message_filter_, i->worker_route_id());
289 return true;
293 return false;
296 void WorkerProcessHost::OnProcessLaunched() {
299 bool WorkerProcessHost::OnMessageReceived(const IPC::Message& message) {
300 bool msg_is_ok = true;
301 bool handled = true;
302 IPC_BEGIN_MESSAGE_MAP_EX(WorkerProcessHost, message, msg_is_ok)
303 IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerContextClosed,
304 OnWorkerContextClosed)
305 IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowDatabase, OnAllowDatabase)
306 IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowFileSystem, OnAllowFileSystem)
307 IPC_MESSAGE_HANDLER(WorkerProcessHostMsg_AllowIndexedDB, OnAllowIndexedDB)
308 IPC_MESSAGE_UNHANDLED(handled = false)
309 IPC_END_MESSAGE_MAP_EX()
311 if (!msg_is_ok) {
312 NOTREACHED();
313 RecordAction(UserMetricsAction("BadMessageTerminate_WPH"));
314 base::KillProcess(
315 process_->GetData().handle, RESULT_CODE_KILLED_BAD_MESSAGE, false);
318 if (handled)
319 return true;
321 if (message.type() == WorkerHostMsg_WorkerContextDestroyed::ID) {
322 WorkerServiceImpl::GetInstance()->NotifyWorkerDestroyed(
323 this, message.routing_id());
326 for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
327 if (i->worker_route_id() == message.routing_id()) {
328 if (message.type() == WorkerHostMsg_WorkerContextDestroyed::ID) {
329 instances_.erase(i);
330 UpdateTitle();
332 return true;
335 return false;
338 // Sent to notify the browser process when a worker context invokes close(), so
339 // no new connections are sent to shared workers.
340 void WorkerProcessHost::OnWorkerContextClosed(int worker_route_id) {
341 for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
342 if (i->worker_route_id() == worker_route_id) {
343 // Set the closed flag - this will stop any further messages from
344 // being sent to the worker (messages can still be sent from the worker,
345 // for exception reporting, etc).
346 i->set_closed(true);
347 break;
352 void WorkerProcessHost::OnAllowDatabase(int worker_route_id,
353 const GURL& url,
354 const string16& name,
355 const string16& display_name,
356 unsigned long estimated_size,
357 bool* result) {
358 *result = GetContentClient()->browser()->AllowWorkerDatabase(
359 url, name, display_name, estimated_size, resource_context_,
360 GetRenderViewIDsForWorker(worker_route_id));
363 void WorkerProcessHost::OnAllowFileSystem(int worker_route_id,
364 const GURL& url,
365 bool* result) {
366 *result = GetContentClient()->browser()->AllowWorkerFileSystem(
367 url, resource_context_, GetRenderViewIDsForWorker(worker_route_id));
370 void WorkerProcessHost::OnAllowIndexedDB(int worker_route_id,
371 const GURL& url,
372 const string16& name,
373 bool* result) {
374 *result = GetContentClient()->browser()->AllowWorkerIndexedDB(
375 url, name, resource_context_, GetRenderViewIDsForWorker(worker_route_id));
378 void WorkerProcessHost::RelayMessage(
379 const IPC::Message& message,
380 WorkerMessageFilter* filter,
381 int route_id) {
382 if (message.type() == WorkerMsg_PostMessage::ID) {
383 // We want to send the receiver a routing id for the new channel, so
384 // crack the message first.
385 string16 msg;
386 std::vector<int> sent_message_port_ids;
387 std::vector<int> new_routing_ids;
388 if (!WorkerMsg_PostMessage::Read(
389 &message, &msg, &sent_message_port_ids, &new_routing_ids)) {
390 return;
392 if (sent_message_port_ids.size() != new_routing_ids.size())
393 return;
395 for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
396 new_routing_ids[i] = filter->GetNextRoutingID();
397 MessagePortService::GetInstance()->UpdateMessagePort(
398 sent_message_port_ids[i], filter, new_routing_ids[i]);
401 filter->Send(new WorkerMsg_PostMessage(
402 route_id, msg, sent_message_port_ids, new_routing_ids));
404 // Send any queued messages to the sent message ports. We can only do this
405 // after sending the above message, since it's the one that sets up the
406 // message port route which the queued messages are sent to.
407 for (size_t i = 0; i < sent_message_port_ids.size(); ++i) {
408 MessagePortService::GetInstance()->
409 SendQueuedMessagesIfPossible(sent_message_port_ids[i]);
411 } else 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;
419 new_routing_id = filter->GetNextRoutingID();
420 MessagePortService::GetInstance()->UpdateMessagePort(
421 sent_message_port_id, filter, new_routing_id);
423 // Resend the message with the new routing id.
424 filter->Send(new WorkerMsg_Connect(
425 route_id, sent_message_port_id, new_routing_id));
427 // Send any queued messages for the sent port.
428 MessagePortService::GetInstance()->SendQueuedMessagesIfPossible(
429 sent_message_port_id);
430 } else {
431 IPC::Message* new_message = new IPC::Message(message);
432 new_message->set_routing_id(route_id);
433 filter->Send(new_message);
434 if (message.type() == WorkerMsg_StartWorkerContext::ID) {
435 WorkerDevToolsManager::GetInstance()->WorkerContextStarted(
436 this, route_id);
438 return;
442 void WorkerProcessHost::FilterShutdown(WorkerMessageFilter* filter) {
443 for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
444 bool shutdown = false;
445 i->RemoveFilters(filter);
447 i->worker_document_set()->RemoveAll(filter);
448 if (i->worker_document_set()->IsEmpty()) {
449 shutdown = true;
451 if (shutdown) {
452 Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id()));
453 i = instances_.erase(i);
454 } else {
455 ++i;
460 bool WorkerProcessHost::CanShutdown() {
461 return instances_.empty();
464 void WorkerProcessHost::UpdateTitle() {
465 std::set<std::string> titles;
466 for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) {
467 // Allow the embedder first crack at special casing the title.
468 std::string title = GetContentClient()->browser()->
469 GetWorkerProcessTitle(i->url(), resource_context_);
471 if (title.empty()) {
472 title = net::RegistryControlledDomainService::GetDomainAndRegistry(
473 i->url());
476 // Use the host name if the domain is empty, i.e. localhost or IP address.
477 if (title.empty())
478 title = i->url().host();
480 // If the host name is empty, i.e. file url, use the path.
481 if (title.empty())
482 title = i->url().path();
483 titles.insert(title);
486 std::string display_title;
487 for (std::set<std::string>::iterator i = titles.begin();
488 i != titles.end(); ++i) {
489 if (!display_title.empty())
490 display_title += ", ";
491 display_title += *i;
494 process_->SetName(ASCIIToUTF16(display_title));
497 void WorkerProcessHost::DocumentDetached(WorkerMessageFilter* filter,
498 unsigned long long document_id) {
499 // Walk all instances and remove the document from their document set.
500 for (Instances::iterator i = instances_.begin(); i != instances_.end();) {
501 i->worker_document_set()->Remove(filter, document_id);
502 if (i->worker_document_set()->IsEmpty()) {
503 // This worker has no more associated documents - shut it down.
504 Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id()));
505 i = instances_.erase(i);
506 } else {
507 ++i;
512 void WorkerProcessHost::TerminateWorker(int worker_route_id) {
513 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id));
516 const ChildProcessData& WorkerProcessHost::GetData() {
517 return process_->GetData();
520 std::vector<std::pair<int, int> > WorkerProcessHost::GetRenderViewIDsForWorker(
521 int worker_route_id) {
522 std::vector<std::pair<int, int> > result;
523 WorkerProcessHost::Instances::const_iterator i;
524 for (i = instances_.begin(); i != instances_.end(); ++i) {
525 if (i->worker_route_id() != worker_route_id)
526 continue;
527 const WorkerDocumentSet::DocumentInfoSet& documents =
528 i->worker_document_set()->documents();
529 for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
530 documents.begin(); doc != documents.end(); ++doc) {
531 result.push_back(
532 std::make_pair(doc->render_process_id(), doc->render_view_id()));
534 break;
536 return result;
539 WorkerProcessHost::WorkerInstance::WorkerInstance(
540 const GURL& url,
541 const string16& name,
542 int worker_route_id,
543 int parent_process_id,
544 int64 main_resource_appcache_id,
545 ResourceContext* resource_context,
546 const WorkerStoragePartition& partition)
547 : url_(url),
548 closed_(false),
549 name_(name),
550 worker_route_id_(worker_route_id),
551 parent_process_id_(parent_process_id),
552 main_resource_appcache_id_(main_resource_appcache_id),
553 worker_document_set_(new WorkerDocumentSet()),
554 resource_context_(resource_context),
555 partition_(partition) {
556 DCHECK(resource_context_);
559 WorkerProcessHost::WorkerInstance::WorkerInstance(
560 const GURL& url,
561 bool shared,
562 const string16& name,
563 ResourceContext* resource_context,
564 const WorkerStoragePartition& partition)
565 : url_(url),
566 closed_(false),
567 name_(name),
568 worker_route_id_(MSG_ROUTING_NONE),
569 parent_process_id_(0),
570 main_resource_appcache_id_(0),
571 worker_document_set_(new WorkerDocumentSet()),
572 resource_context_(resource_context),
573 partition_(partition) {
574 DCHECK(resource_context_);
577 WorkerProcessHost::WorkerInstance::~WorkerInstance() {
580 // Compares an instance based on the algorithm in the WebWorkers spec - an
581 // instance matches if the origins of the URLs match, and:
582 // a) the names are non-empty and equal
583 // -or-
584 // b) the names are both empty, and the urls are equal
585 bool WorkerProcessHost::WorkerInstance::Matches(
586 const GURL& match_url,
587 const string16& match_name,
588 const WorkerStoragePartition& partition,
589 ResourceContext* resource_context) const {
590 // Only match open shared workers.
591 if (closed_)
592 return false;
594 // ResourceContext equivalence is being used as a proxy to ensure we only
595 // matched shared workers within the same BrowserContext.
596 if (resource_context_ != resource_context)
597 return false;
599 // We must be in the same storage partition otherwise sharing will violate
600 // isolation.
601 if (!partition_.Equals(partition))
602 return false;
604 if (url_.GetOrigin() != match_url.GetOrigin())
605 return false;
607 if (name_.empty() && match_name.empty())
608 return url_ == match_url;
610 return name_ == match_name;
613 void WorkerProcessHost::WorkerInstance::AddFilter(WorkerMessageFilter* filter,
614 int route_id) {
615 CHECK(filter);
616 if (!HasFilter(filter, route_id)) {
617 FilterInfo info(filter, route_id);
618 filters_.push_back(info);
622 void WorkerProcessHost::WorkerInstance::RemoveFilter(
623 WorkerMessageFilter* filter, int route_id) {
624 for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
625 if (i->first == filter && i->second == route_id)
626 i = filters_.erase(i);
627 else
628 ++i;
630 // Should not be duplicate copies in the filter set.
631 DCHECK(!HasFilter(filter, route_id));
634 void WorkerProcessHost::WorkerInstance::RemoveFilters(
635 WorkerMessageFilter* filter) {
636 for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
637 if (i->first == filter)
638 i = filters_.erase(i);
639 else
640 ++i;
644 bool WorkerProcessHost::WorkerInstance::HasFilter(
645 WorkerMessageFilter* filter, int route_id) const {
646 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
647 ++i) {
648 if (i->first == filter && i->second == route_id)
649 return true;
651 return false;
654 bool WorkerProcessHost::WorkerInstance::RendererIsParent(
655 int render_process_id, int render_view_id) const {
656 const WorkerDocumentSet::DocumentInfoSet& parents =
657 worker_document_set()->documents();
658 for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
659 parents.begin();
660 parent_iter != parents.end(); ++parent_iter) {
661 if (parent_iter->render_process_id() == render_process_id &&
662 parent_iter->render_view_id() == render_view_id) {
663 return true;
666 return false;
669 WorkerProcessHost::WorkerInstance::FilterInfo
670 WorkerProcessHost::WorkerInstance::GetFilter() const {
671 DCHECK(NumFilters() == 1);
672 return *filters_.begin();
675 } // namespace content