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