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_dispatcher_host.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "content/browser/message_port_message_filter.h"
     10 #include "content/browser/message_port_service.h"
     11 #include "content/browser/service_worker/embedded_worker_registry.h"
     12 #include "content/browser/service_worker/service_worker_context_core.h"
     13 #include "content/browser/service_worker/service_worker_context_wrapper.h"
     14 #include "content/browser/service_worker/service_worker_handle.h"
     15 #include "content/browser/service_worker/service_worker_registration.h"
     16 #include "content/browser/service_worker/service_worker_utils.h"
     17 #include "content/common/service_worker/embedded_worker_messages.h"
     18 #include "content/common/service_worker/service_worker_messages.h"
     19 #include "ipc/ipc_message_macros.h"
     20 #include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
     21 #include "url/gurl.h"
     22 
     23 using blink::WebServiceWorkerError;
     24 
     25 namespace content {
     26 
     27 namespace {
     28 
     29 const char kDisabledErrorMessage[] =
     30     "ServiceWorker is disabled";
     31 const char kDomainMismatchErrorMessage[] =
     32     "Scope and scripts do not have the same origin";
     33 
     34 const uint32 kFilteredMessageClasses[] = {
     35   ServiceWorkerMsgStart,
     36   EmbeddedWorkerMsgStart,
     37 };
     38 
     39 bool CanRegisterServiceWorker(const GURL& document_url,
     40                               const GURL& pattern,
     41                               const GURL& script_url) {
     42   // TODO: Respect Chrome's content settings, if we add a setting for
     43   // controlling whether Service Worker is allowed.
     44   return document_url.GetOrigin() == pattern.GetOrigin() &&
     45          document_url.GetOrigin() == script_url.GetOrigin();
     46 }
     47 
     48 bool CanUnregisterServiceWorker(const GURL& document_url,
     49                                 const GURL& pattern) {
     50   // TODO: Respect Chrome's content settings, if we add a setting for
     51   // controlling whether Service Worker is allowed.
     52   return document_url.GetOrigin() == pattern.GetOrigin();
     53 }
     54 
     55 }  // namespace
     56 
     57 ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost(
     58     int render_process_id,
     59     MessagePortMessageFilter* message_port_message_filter)
     60     : BrowserMessageFilter(kFilteredMessageClasses,
     61                            arraysize(kFilteredMessageClasses)),
     62       render_process_id_(render_process_id),
     63       message_port_message_filter_(message_port_message_filter),
     64       channel_ready_(false) {
     65 }
     66 
     67 ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
     68   if (GetContext()) {
     69     GetContext()->RemoveAllProviderHostsForProcess(render_process_id_);
     70     GetContext()->embedded_worker_registry()->RemoveChildProcessSender(
     71         render_process_id_);
     72   }
     73 }
     74 
     75 void ServiceWorkerDispatcherHost::Init(
     76     ServiceWorkerContextWrapper* context_wrapper) {
     77   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
     78     BrowserThread::PostTask(
     79         BrowserThread::IO, FROM_HERE,
     80         base::Bind(&ServiceWorkerDispatcherHost::Init,
     81                    this, make_scoped_refptr(context_wrapper)));
     82     return;
     83   }
     84   context_wrapper_ = context_wrapper;
     85   GetContext()->embedded_worker_registry()->AddChildProcessSender(
     86       render_process_id_, this);
     87 }
     88 
     89 void ServiceWorkerDispatcherHost::OnFilterAdded(IPC::Sender* sender) {
     90   BrowserMessageFilter::OnFilterAdded(sender);
     91   channel_ready_ = true;
     92   std::vector<IPC::Message*> messages;
     93   pending_messages_.release(&messages);
     94   for (size_t i = 0; i < messages.size(); ++i) {
     95     BrowserMessageFilter::Send(messages[i]);
     96   }
     97 }
     98 
     99 void ServiceWorkerDispatcherHost::OnDestruct() const {
    100   BrowserThread::DeleteOnIOThread::Destruct(this);
    101 }
    102 
    103 bool ServiceWorkerDispatcherHost::OnMessageReceived(
    104     const IPC::Message& message) {
    105   bool handled = true;
    106   IPC_BEGIN_MESSAGE_MAP(ServiceWorkerDispatcherHost, message)
    107     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_RegisterServiceWorker,
    108                         OnRegisterServiceWorker)
    109     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_UnregisterServiceWorker,
    110                         OnUnregisterServiceWorker)
    111     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderCreated,
    112                         OnProviderCreated)
    113     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed,
    114                         OnProviderDestroyed)
    115     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetVersionId,
    116                         OnSetHostedVersionId)
    117     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToWorker,
    118                         OnPostMessageToWorker)
    119     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoaded,
    120                         OnWorkerScriptLoaded)
    121     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerScriptLoadFailed,
    122                         OnWorkerScriptLoadFailed)
    123     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStarted,
    124                         OnWorkerStarted)
    125     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStopped,
    126                         OnWorkerStopped)
    127     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportException,
    128                         OnReportException)
    129     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportConsoleMessage,
    130                         OnReportConsoleMessage)
    131     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount,
    132                         OnIncrementServiceWorkerRefCount)
    133     IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount,
    134                         OnDecrementServiceWorkerRefCount)
    135     IPC_MESSAGE_UNHANDLED(handled = false)
    136   IPC_END_MESSAGE_MAP()
    137 
    138   if (!handled && GetContext()) {
    139     handled =
    140         GetContext()->embedded_worker_registry()->OnMessageReceived(message);
    141     if (!handled)
    142       BadMessageReceived();
    143   }
    144 
    145   return handled;
    146 }
    147 
    148 bool ServiceWorkerDispatcherHost::Send(IPC::Message* message) {
    149   if (channel_ready_) {
    150     BrowserMessageFilter::Send(message);
    151     // Don't bother passing through Send()'s result: it's not reliable.
    152     return true;
    153   }
    154 
    155   pending_messages_.push_back(message);
    156   return true;
    157 }
    158 
    159 void ServiceWorkerDispatcherHost::RegisterServiceWorkerHandle(
    160     scoped_ptr<ServiceWorkerHandle> handle) {
    161   int handle_id = handle->handle_id();
    162   handles_.AddWithID(handle.release(), handle_id);
    163 }
    164 
    165 void ServiceWorkerDispatcherHost::OnRegisterServiceWorker(
    166     int thread_id,
    167     int request_id,
    168     int provider_id,
    169     const GURL& pattern,
    170     const GURL& script_url) {
    171   if (!GetContext() || !ServiceWorkerUtils::IsFeatureEnabled()) {
    172     Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
    173         thread_id,
    174         request_id,
    175         WebServiceWorkerError::ErrorTypeDisabled,
    176         base::ASCIIToUTF16(kDisabledErrorMessage)));
    177     return;
    178   }
    179 
    180   ServiceWorkerProviderHost* provider_host = GetContext()->GetProviderHost(
    181       render_process_id_, provider_id);
    182   if (!provider_host) {
    183     BadMessageReceived();
    184     return;
    185   }
    186   if (!provider_host->IsContextAlive()) {
    187     Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
    188         thread_id,
    189         request_id,
    190         WebServiceWorkerError::ErrorTypeDisabled,
    191         base::ASCIIToUTF16(kDisabledErrorMessage)));
    192     return;
    193   }
    194 
    195   if (!CanRegisterServiceWorker(
    196       provider_host->document_url(), pattern, script_url)) {
    197     Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
    198         thread_id,
    199         request_id,
    200         WebServiceWorkerError::ErrorTypeSecurity,
    201         base::ASCIIToUTF16(kDomainMismatchErrorMessage)));
    202     return;
    203   }
    204   GetContext()->RegisterServiceWorker(
    205       pattern,
    206       script_url,
    207       render_process_id_,
    208       provider_host,
    209       base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete,
    210                  this,
    211                  thread_id,
    212                  request_id));
    213 }
    214 
    215 void ServiceWorkerDispatcherHost::OnUnregisterServiceWorker(
    216     int thread_id,
    217     int request_id,
    218     int provider_id,
    219     const GURL& pattern) {
    220   if (!GetContext() || !ServiceWorkerUtils::IsFeatureEnabled()) {
    221     Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
    222         thread_id,
    223         request_id,
    224         blink::WebServiceWorkerError::ErrorTypeDisabled,
    225         base::ASCIIToUTF16(kDisabledErrorMessage)));
    226     return;
    227   }
    228 
    229   ServiceWorkerProviderHost* provider_host = GetContext()->GetProviderHost(
    230       render_process_id_, provider_id);
    231   if (!provider_host) {
    232     BadMessageReceived();
    233     return;
    234   }
    235   if (!provider_host->IsContextAlive()) {
    236     Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
    237         thread_id,
    238         request_id,
    239         blink::WebServiceWorkerError::ErrorTypeDisabled,
    240         base::ASCIIToUTF16(kDisabledErrorMessage)));
    241     return;
    242   }
    243 
    244   if (!CanUnregisterServiceWorker(provider_host->document_url(), pattern)) {
    245     Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
    246         thread_id,
    247         request_id,
    248         WebServiceWorkerError::ErrorTypeSecurity,
    249         base::ASCIIToUTF16(kDomainMismatchErrorMessage)));
    250     return;
    251   }
    252 
    253   GetContext()->UnregisterServiceWorker(
    254       pattern,
    255       base::Bind(&ServiceWorkerDispatcherHost::UnregistrationComplete,
    256                  this,
    257                  thread_id,
    258                  request_id));
    259 }
    260 
    261 void ServiceWorkerDispatcherHost::OnPostMessageToWorker(
    262     int handle_id,
    263     const base::string16& message,
    264     const std::vector<int>& sent_message_port_ids) {
    265   if (!GetContext() || !ServiceWorkerUtils::IsFeatureEnabled())
    266     return;
    267 
    268   ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
    269   if (!handle) {
    270     BadMessageReceived();
    271     return;
    272   }
    273 
    274   std::vector<int> new_routing_ids;
    275   message_port_message_filter_->UpdateMessagePortsWithNewRoutes(
    276       sent_message_port_ids, &new_routing_ids);
    277   handle->version()->SendMessage(
    278       ServiceWorkerMsg_MessageToWorker(message,
    279                                        sent_message_port_ids,
    280                                        new_routing_ids),
    281       base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
    282 }
    283 
    284 void ServiceWorkerDispatcherHost::OnProviderCreated(int provider_id) {
    285   if (!GetContext())
    286     return;
    287   if (GetContext()->GetProviderHost(render_process_id_, provider_id)) {
    288     BadMessageReceived();
    289     return;
    290   }
    291   scoped_ptr<ServiceWorkerProviderHost> provider_host(
    292       new ServiceWorkerProviderHost(
    293           render_process_id_, provider_id, GetContext()->AsWeakPtr(), this));
    294   GetContext()->AddProviderHost(provider_host.Pass());
    295 }
    296 
    297 void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) {
    298   if (!GetContext())
    299     return;
    300   if (!GetContext()->GetProviderHost(render_process_id_, provider_id)) {
    301     BadMessageReceived();
    302     return;
    303   }
    304   GetContext()->RemoveProviderHost(render_process_id_, provider_id);
    305 }
    306 
    307 void ServiceWorkerDispatcherHost::OnSetHostedVersionId(
    308     int provider_id, int64 version_id) {
    309   if (!GetContext())
    310     return;
    311   ServiceWorkerProviderHost* provider_host =
    312       GetContext()->GetProviderHost(render_process_id_, provider_id);
    313   if (!provider_host) {
    314     BadMessageReceived();
    315     return;
    316   }
    317   if (!provider_host->IsContextAlive())
    318     return;
    319   if (!provider_host->SetHostedVersionId(version_id))
    320     BadMessageReceived();
    321 }
    322 
    323 void ServiceWorkerDispatcherHost::RegistrationComplete(
    324     int thread_id,
    325     int request_id,
    326     ServiceWorkerStatusCode status,
    327     int64 registration_id,
    328     int64 version_id) {
    329   if (!GetContext())
    330     return;
    331 
    332   if (status != SERVICE_WORKER_OK) {
    333     SendRegistrationError(thread_id, request_id, status);
    334     return;
    335   }
    336 
    337   ServiceWorkerVersion* version = GetContext()->GetLiveVersion(version_id);
    338   DCHECK(version);
    339   DCHECK_EQ(registration_id, version->registration_id());
    340   scoped_ptr<ServiceWorkerHandle> handle =
    341       ServiceWorkerHandle::Create(GetContext()->AsWeakPtr(),
    342                                   this, thread_id, version);
    343   Send(new ServiceWorkerMsg_ServiceWorkerRegistered(
    344       thread_id, request_id, handle->GetObjectInfo()));
    345   RegisterServiceWorkerHandle(handle.Pass());
    346 }
    347 
    348 // TODO(nhiroki): These message handlers that take |embedded_worker_id| as an
    349 // input should check if the worker refers to the live context. If the context
    350 // was deleted, handle the messege gracefully (http://crbug.com/371675).
    351 void ServiceWorkerDispatcherHost::OnWorkerScriptLoaded(int embedded_worker_id) {
    352   if (!GetContext())
    353     return;
    354   GetContext()->embedded_worker_registry()->OnWorkerScriptLoaded(
    355       render_process_id_, embedded_worker_id);
    356 }
    357 
    358 void ServiceWorkerDispatcherHost::OnWorkerScriptLoadFailed(
    359     int embedded_worker_id) {
    360   if (!GetContext())
    361     return;
    362   GetContext()->embedded_worker_registry()->OnWorkerScriptLoadFailed(
    363       render_process_id_, embedded_worker_id);
    364 }
    365 
    366 void ServiceWorkerDispatcherHost::OnWorkerStarted(
    367     int thread_id, int embedded_worker_id) {
    368   if (!GetContext())
    369     return;
    370   GetContext()->embedded_worker_registry()->OnWorkerStarted(
    371       render_process_id_, thread_id, embedded_worker_id);
    372 }
    373 
    374 void ServiceWorkerDispatcherHost::OnWorkerStopped(int embedded_worker_id) {
    375   if (!GetContext())
    376     return;
    377   GetContext()->embedded_worker_registry()->OnWorkerStopped(
    378       render_process_id_, embedded_worker_id);
    379 }
    380 
    381 void ServiceWorkerDispatcherHost::OnReportException(
    382     int embedded_worker_id,
    383     const base::string16& error_message,
    384     int line_number,
    385     int column_number,
    386     const GURL& source_url) {
    387   if (!GetContext())
    388     return;
    389   GetContext()->embedded_worker_registry()->OnReportException(
    390       embedded_worker_id,
    391       error_message,
    392       line_number,
    393       column_number,
    394       source_url);
    395 }
    396 
    397 void ServiceWorkerDispatcherHost::OnReportConsoleMessage(
    398     int embedded_worker_id,
    399     const EmbeddedWorkerHostMsg_ReportConsoleMessage_Params& params) {
    400   if (!GetContext())
    401     return;
    402   GetContext()->embedded_worker_registry()->OnReportConsoleMessage(
    403       embedded_worker_id,
    404       params.source_identifier,
    405       params.message_level,
    406       params.message,
    407       params.line_number,
    408       params.source_url);
    409 }
    410 
    411 void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount(
    412     int handle_id) {
    413   ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
    414   if (!handle) {
    415     BadMessageReceived();
    416     return;
    417   }
    418   handle->IncrementRefCount();
    419 }
    420 
    421 void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount(
    422     int handle_id) {
    423   ServiceWorkerHandle* handle = handles_.Lookup(handle_id);
    424   if (!handle) {
    425     BadMessageReceived();
    426     return;
    427   }
    428   handle->DecrementRefCount();
    429   if (handle->HasNoRefCount())
    430     handles_.Remove(handle_id);
    431 }
    432 
    433 void ServiceWorkerDispatcherHost::UnregistrationComplete(
    434     int thread_id,
    435     int request_id,
    436     ServiceWorkerStatusCode status) {
    437   if (status != SERVICE_WORKER_OK) {
    438     SendRegistrationError(thread_id, request_id, status);
    439     return;
    440   }
    441 
    442   Send(new ServiceWorkerMsg_ServiceWorkerUnregistered(thread_id, request_id));
    443 }
    444 
    445 void ServiceWorkerDispatcherHost::SendRegistrationError(
    446     int thread_id,
    447     int request_id,
    448     ServiceWorkerStatusCode status) {
    449   base::string16 error_message;
    450   blink::WebServiceWorkerError::ErrorType error_type;
    451   GetServiceWorkerRegistrationStatusResponse(
    452       status, &error_type, &error_message);
    453   Send(new ServiceWorkerMsg_ServiceWorkerRegistrationError(
    454       thread_id, request_id, error_type, error_message));
    455 }
    456 
    457 ServiceWorkerContextCore* ServiceWorkerDispatcherHost::GetContext() {
    458   return context_wrapper_->context();
    459 }
    460 
    461 }  // namespace content
    462