Home | History | Annotate | Download | only in worker_host
      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:
     70   WorkerSandboxedProcessLauncherDelegate() {}
     71   virtual ~WorkerSandboxedProcessLauncherDelegate() {}
     72 
     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.
     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 
     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 
    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 
    122 bool WorkerProcessHost::Send(IPC::Message* message) {
    123   return process_->Send(message);
    124 }
    125 
    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 
    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 
    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 
    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 
    312 void WorkerProcessHost::OnProcessLaunched() {
    313   process_launched_ = true;
    314 
    315   WorkerServiceImpl::GetInstance()->NotifyWorkerProcessCreated();
    316 }
    317 
    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.
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    476 bool WorkerProcessHost::CanShutdown() {
    477   return instances_.empty();
    478 }
    479 
    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 
    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 
    530 void WorkerProcessHost::TerminateWorker(int worker_route_id) {
    531   Send(new WorkerMsg_TerminateWorkerContext(worker_route_id));
    532 }
    533 
    534 void WorkerProcessHost::SetBackgrounded(bool backgrounded) {
    535   process_->SetBackgrounded(backgrounded);
    536 }
    537 
    538 const ChildProcessData& WorkerProcessHost::GetData() {
    539   return process_->GetData();
    540 }
    541 
    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 
    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 
    568 net::URLRequestContext* WorkerProcessHost::GetRequestContext(
    569     ResourceType::Type resource_type) {
    570   return partition_.url_request_context()->GetURLRequestContext();
    571 }
    572 
    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 
    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 
    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
    619 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 
    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 
    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 
    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 
    678 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 
    688 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
    704 WorkerProcessHost::WorkerInstance::GetFilter() const {
    705   DCHECK(NumFilters() == 1);
    706   return *filters_.begin();
    707 }
    708 
    709 }  // namespace content
    710