Home | History | Annotate | Download | only in service_worker
      1 // Copyright 2013 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/service_worker/service_worker_provider_host.h"
      6 
      7 #include "base/stl_util.h"
      8 #include "content/browser/message_port_message_filter.h"
      9 #include "content/browser/service_worker/service_worker_context_core.h"
     10 #include "content/browser/service_worker/service_worker_context_request_handler.h"
     11 #include "content/browser/service_worker/service_worker_controllee_request_handler.h"
     12 #include "content/browser/service_worker/service_worker_dispatcher_host.h"
     13 #include "content/browser/service_worker/service_worker_handle.h"
     14 #include "content/browser/service_worker/service_worker_utils.h"
     15 #include "content/browser/service_worker/service_worker_version.h"
     16 #include "content/common/service_worker/service_worker_messages.h"
     17 
     18 namespace content {
     19 
     20 static const int kDocumentMainThreadId = 0;
     21 
     22 ServiceWorkerProviderHost::ServiceWorkerProviderHost(
     23     int process_id, int provider_id,
     24     base::WeakPtr<ServiceWorkerContextCore> context,
     25     ServiceWorkerDispatcherHost* dispatcher_host)
     26     : process_id_(process_id),
     27       provider_id_(provider_id),
     28       context_(context),
     29       dispatcher_host_(dispatcher_host) {
     30 }
     31 
     32 ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
     33   if (active_version_)
     34     active_version_->RemoveControllee(this);
     35   if (waiting_version_)
     36     waiting_version_->RemoveWaitingControllee(this);
     37 }
     38 
     39 void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
     40   DCHECK(!url.has_ref());
     41   document_url_ = url;
     42 }
     43 
     44 void ServiceWorkerProviderHost::SetActiveVersion(
     45     ServiceWorkerVersion* version) {
     46   if (version == active_version_)
     47     return;
     48   scoped_refptr<ServiceWorkerVersion> previous_version = active_version_;
     49   active_version_ = version;
     50   if (version)
     51     version->AddControllee(this);
     52   if (previous_version)
     53     previous_version->RemoveControllee(this);
     54 
     55   if (!dispatcher_host_)
     56     return;  // Could be NULL in some tests.
     57 
     58   dispatcher_host_->Send(new ServiceWorkerMsg_SetCurrentServiceWorker(
     59       kDocumentMainThreadId, provider_id(), CreateHandleAndPass(version)));
     60 }
     61 
     62 void ServiceWorkerProviderHost::SetWaitingVersion(
     63     ServiceWorkerVersion* version) {
     64   DCHECK(ValidateVersionForAssociation(version));
     65   if (version == waiting_version_)
     66     return;
     67   scoped_refptr<ServiceWorkerVersion> previous_version = waiting_version_;
     68   waiting_version_ = version;
     69   if (version)
     70     version->AddWaitingControllee(this);
     71   if (previous_version)
     72     previous_version->RemoveWaitingControllee(this);
     73 
     74   if (!dispatcher_host_)
     75     return;  // Could be NULL in some tests.
     76 
     77   dispatcher_host_->Send(new ServiceWorkerMsg_SetWaitingServiceWorker(
     78       kDocumentMainThreadId, provider_id(), CreateHandleAndPass(version)));
     79 }
     80 
     81 bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id) {
     82   if (!context_)
     83     return true;  // System is shutting down.
     84   if (active_version_)
     85     return false;  // Unexpected bad message.
     86 
     87   ServiceWorkerVersion* live_version = context_->GetLiveVersion(version_id);
     88   if (!live_version)
     89     return true;  // Was deleted before it got started.
     90 
     91   ServiceWorkerVersionInfo info = live_version->GetInfo();
     92   if (info.running_status != ServiceWorkerVersion::STARTING ||
     93       info.process_id != process_id_) {
     94     // If we aren't trying to start this version in our process
     95     // something is amiss.
     96     return false;
     97   }
     98 
     99   running_hosted_version_ = live_version;
    100   return true;
    101 }
    102 
    103 scoped_ptr<ServiceWorkerRequestHandler>
    104 ServiceWorkerProviderHost::CreateRequestHandler(
    105     ResourceType::Type resource_type,
    106     base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context) {
    107   if (IsHostToRunningServiceWorker()) {
    108     return scoped_ptr<ServiceWorkerRequestHandler>(
    109         new ServiceWorkerContextRequestHandler(
    110             context_, AsWeakPtr(), blob_storage_context, resource_type));
    111   }
    112   if (ServiceWorkerUtils::IsMainResourceType(resource_type) ||
    113       active_version()) {
    114     return scoped_ptr<ServiceWorkerRequestHandler>(
    115         new ServiceWorkerControlleeRequestHandler(
    116             context_, AsWeakPtr(), blob_storage_context, resource_type));
    117   }
    118   return scoped_ptr<ServiceWorkerRequestHandler>();
    119 }
    120 
    121 bool ServiceWorkerProviderHost::ValidateVersionForAssociation(
    122     ServiceWorkerVersion* version) {
    123   if (running_hosted_version_)
    124     return false;
    125   if (!version)
    126     return true;
    127 
    128   // A version to be associated with this provider should have the same
    129   // registration (scope) as current active/waiting versions.
    130   if (active_version_) {
    131     if (active_version_->registration_id() != version->registration_id())
    132       return false;
    133     DCHECK_EQ(active_version_->scope(), version->scope());
    134   }
    135   if (waiting_version_) {
    136     if (waiting_version_->registration_id() != version->registration_id())
    137       return false;
    138     DCHECK_EQ(waiting_version_->scope(), version->scope());
    139   }
    140   return true;
    141 }
    142 
    143 void ServiceWorkerProviderHost::PostMessage(
    144     const base::string16& message,
    145     const std::vector<int>& sent_message_port_ids) {
    146   if (!dispatcher_host_)
    147     return;  // Could be NULL in some tests.
    148 
    149   std::vector<int> new_routing_ids;
    150   dispatcher_host_->message_port_message_filter()->
    151       UpdateMessagePortsWithNewRoutes(sent_message_port_ids,
    152                                       &new_routing_ids);
    153 
    154   dispatcher_host_->Send(
    155       new ServiceWorkerMsg_MessageToDocument(
    156           kDocumentMainThreadId, provider_id(),
    157           message,
    158           sent_message_port_ids,
    159           new_routing_ids));
    160 }
    161 
    162 ServiceWorkerObjectInfo ServiceWorkerProviderHost::CreateHandleAndPass(
    163     ServiceWorkerVersion* version) {
    164   DCHECK(ValidateVersionForAssociation(version));
    165   ServiceWorkerObjectInfo info;
    166   if (context_ && version) {
    167     scoped_ptr<ServiceWorkerHandle> handle =
    168         ServiceWorkerHandle::Create(context_, dispatcher_host_,
    169                                     kDocumentMainThreadId, version);
    170     info = handle->GetObjectInfo();
    171     dispatcher_host_->RegisterServiceWorkerHandle(handle.Pass());
    172   }
    173   return info;
    174 }
    175 
    176 bool ServiceWorkerProviderHost::IsContextAlive() {
    177   return context_ != NULL;
    178 }
    179 
    180 }  // namespace content
    181