LCOV - code coverage report
Current view: top level - dom/workers - ServiceWorkerContainer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 169 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "ServiceWorkerContainer.h"
       8             : 
       9             : #include "nsContentUtils.h"
      10             : #include "nsIDocument.h"
      11             : #include "nsIServiceWorkerManager.h"
      12             : #include "nsIURL.h"
      13             : #include "nsNetUtil.h"
      14             : #include "nsPIDOMWindow.h"
      15             : #include "mozilla/Preferences.h"
      16             : #include "mozilla/Services.h"
      17             : 
      18             : #include "nsCycleCollectionParticipant.h"
      19             : #include "nsServiceManagerUtils.h"
      20             : 
      21             : #include "mozilla/dom/Navigator.h"
      22             : #include "mozilla/dom/Promise.h"
      23             : #include "mozilla/dom/ServiceWorkerContainerBinding.h"
      24             : #include "mozilla/dom/workers/bindings/ServiceWorker.h"
      25             : 
      26             : #include "ServiceWorker.h"
      27             : 
      28             : namespace mozilla {
      29             : namespace dom {
      30             : 
      31           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorkerContainer)
      32           0 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
      33             : 
      34           0 : NS_IMPL_ADDREF_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
      35           0 : NS_IMPL_RELEASE_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
      36             : 
      37           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper,
      38             :                                    mControllerWorker, mReadyPromise)
      39             : 
      40             : /* static */ bool
      41           0 : ServiceWorkerContainer::IsEnabled(JSContext* aCx, JSObject* aGlobal)
      42             : {
      43           0 :   MOZ_ASSERT(NS_IsMainThread());
      44             : 
      45           0 :   JS::Rooted<JSObject*> global(aCx, aGlobal);
      46           0 :   nsCOMPtr<nsPIDOMWindowInner> window = Navigator::GetWindowFromGlobal(global);
      47           0 :   if (!window) {
      48           0 :     return false;
      49             :   }
      50             : 
      51           0 :   nsIDocument* doc = window->GetExtantDoc();
      52           0 :   if (!doc || nsContentUtils::IsInPrivateBrowsing(doc)) {
      53           0 :     return false;
      54             :   }
      55             : 
      56           0 :   return Preferences::GetBool("dom.serviceWorkers.enabled", false);
      57             : }
      58             : 
      59           0 : ServiceWorkerContainer::ServiceWorkerContainer(nsPIDOMWindowInner* aWindow)
      60           0 :   : DOMEventTargetHelper(aWindow)
      61             : {
      62           0 : }
      63             : 
      64           0 : ServiceWorkerContainer::~ServiceWorkerContainer()
      65             : {
      66           0 :   RemoveReadyPromise();
      67           0 : }
      68             : 
      69             : void
      70           0 : ServiceWorkerContainer::DisconnectFromOwner()
      71             : {
      72           0 :   mControllerWorker = nullptr;
      73           0 :   RemoveReadyPromise();
      74           0 :   DOMEventTargetHelper::DisconnectFromOwner();
      75           0 : }
      76             : 
      77             : void
      78           0 : ServiceWorkerContainer::ControllerChanged(ErrorResult& aRv)
      79             : {
      80           0 :   mControllerWorker = nullptr;
      81           0 :   aRv = DispatchTrustedEvent(NS_LITERAL_STRING("controllerchange"));
      82           0 : }
      83             : 
      84             : void
      85           0 : ServiceWorkerContainer::RemoveReadyPromise()
      86             : {
      87           0 :   if (nsCOMPtr<nsPIDOMWindowInner> window = GetOwner()) {
      88             :     nsCOMPtr<nsIServiceWorkerManager> swm =
      89           0 :       mozilla::services::GetServiceWorkerManager();
      90           0 :     if (!swm) {
      91             :       // If the browser is shutting down, we don't need to remove the promise.
      92           0 :       return;
      93             :     }
      94             : 
      95           0 :     swm->RemoveReadyPromise(window);
      96             :   }
      97             : }
      98             : 
      99             : JSObject*
     100           0 : ServiceWorkerContainer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     101             : {
     102           0 :   return ServiceWorkerContainerBinding::Wrap(aCx, this, aGivenProto);
     103             : }
     104             : 
     105             : static nsresult
     106           0 : CheckForSlashEscapedCharsInPath(nsIURI* aURI)
     107             : {
     108           0 :   MOZ_ASSERT(aURI);
     109             : 
     110             :   // A URL that can't be downcast to a standard URL is an invalid URL and should
     111             :   // be treated as such and fail with SecurityError.
     112           0 :   nsCOMPtr<nsIURL> url(do_QueryInterface(aURI));
     113           0 :   if (NS_WARN_IF(!url)) {
     114           0 :     return NS_ERROR_DOM_SECURITY_ERR;
     115             :   }
     116             : 
     117           0 :   nsAutoCString path;
     118           0 :   nsresult rv = url->GetFilePath(path);
     119           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     120           0 :     return rv;
     121             :   }
     122             : 
     123           0 :   ToLowerCase(path);
     124           0 :   if (path.Find("%2f") != kNotFound ||
     125           0 :       path.Find("%5c") != kNotFound) {
     126           0 :     return NS_ERROR_DOM_TYPE_ERR;
     127             :   }
     128             : 
     129           0 :   return NS_OK;
     130             : }
     131             : 
     132             : already_AddRefed<Promise>
     133           0 : ServiceWorkerContainer::Register(const nsAString& aScriptURL,
     134             :                                  const RegistrationOptions& aOptions,
     135             :                                  ErrorResult& aRv)
     136             : {
     137           0 :   nsCOMPtr<nsISupports> promise;
     138             : 
     139           0 :   nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
     140           0 :   if (!swm) {
     141           0 :     aRv.Throw(NS_ERROR_FAILURE);
     142           0 :     return nullptr;
     143             :   }
     144             : 
     145           0 :   nsCOMPtr<nsIURI> baseURI;
     146             : 
     147           0 :   nsIDocument* doc = GetEntryDocument();
     148           0 :   if (doc) {
     149           0 :     baseURI = doc->GetBaseURI();
     150             :   } else {
     151             :     // XXXnsm. One of our devtools browser test calls register() from a content
     152             :     // script where there is no valid entry document. Use the window to resolve
     153             :     // the uri in that case.
     154           0 :     nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
     155           0 :     nsCOMPtr<nsPIDOMWindowOuter> outerWindow;
     156           0 :     if (window && (outerWindow = window->GetOuterWindow()) &&
     157           0 :         outerWindow->GetServiceWorkersTestingEnabled()) {
     158           0 :       baseURI = window->GetDocBaseURI();
     159             :     }
     160             :   }
     161             : 
     162             :   nsresult rv;
     163           0 :   nsCOMPtr<nsIURI> scriptURI;
     164           0 :   rv = NS_NewURI(getter_AddRefs(scriptURI), aScriptURL, nullptr, baseURI);
     165           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     166           0 :     aRv.ThrowTypeError<MSG_INVALID_URL>(aScriptURL);
     167           0 :     return nullptr;
     168             :   }
     169             : 
     170           0 :   aRv = CheckForSlashEscapedCharsInPath(scriptURI);
     171           0 :   if (NS_WARN_IF(aRv.Failed())) {
     172           0 :     return nullptr;
     173             :   }
     174             : 
     175             :   // In ServiceWorkerContainer.register() the scope argument is parsed against
     176             :   // different base URLs depending on whether it was passed or not.
     177           0 :   nsCOMPtr<nsIURI> scopeURI;
     178             : 
     179             :   // Step 4. If none passed, parse against script's URL
     180           0 :   if (!aOptions.mScope.WasPassed()) {
     181           0 :     NS_NAMED_LITERAL_STRING(defaultScope, "./");
     182           0 :     rv = NS_NewURI(getter_AddRefs(scopeURI), defaultScope,
     183           0 :                    nullptr, scriptURI);
     184           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     185           0 :       nsAutoCString spec;
     186           0 :       scriptURI->GetSpec(spec);
     187           0 :       NS_ConvertUTF8toUTF16 wSpec(spec);
     188           0 :       aRv.ThrowTypeError<MSG_INVALID_SCOPE>(defaultScope, wSpec);
     189           0 :       return nullptr;
     190             :     }
     191             :   } else {
     192             :     // Step 5. Parse against entry settings object's base URL.
     193           0 :     rv = NS_NewURI(getter_AddRefs(scopeURI), aOptions.mScope.Value(),
     194           0 :                    nullptr, baseURI);
     195           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     196           0 :       nsIURI* uri = baseURI ? baseURI : scriptURI;
     197           0 :       nsAutoCString spec;
     198           0 :       uri->GetSpec(spec);
     199           0 :       NS_ConvertUTF8toUTF16 wSpec(spec);
     200           0 :       aRv.ThrowTypeError<MSG_INVALID_SCOPE>(aOptions.mScope.Value(), wSpec);
     201           0 :       return nullptr;
     202             :     }
     203             : 
     204           0 :     aRv = CheckForSlashEscapedCharsInPath(scopeURI);
     205           0 :     if (NS_WARN_IF(aRv.Failed())) {
     206           0 :       return nullptr;
     207             :     }
     208             :   }
     209             : 
     210             :   // This is a quick fix for temporarily turning off script loading setting when
     211             :   // registering a service worker. This should be removed in Bug 1353636.
     212           0 :   nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
     213             : 
     214             :   // The spec says that the "client" passed to Register() must be the global
     215             :   // where the ServiceWorkerContainer was retrieved from.
     216           0 :   aRv = swm->Register(GetOwner(), scopeURI, scriptURI, loadFlags,
     217           0 :                       getter_AddRefs(promise));
     218           0 :   if (NS_WARN_IF(aRv.Failed())) {
     219           0 :     return nullptr;
     220             :   }
     221             : 
     222           0 :   RefPtr<Promise> ret = static_cast<Promise*>(promise.get());
     223           0 :   MOZ_ASSERT(ret);
     224           0 :   return ret.forget();
     225             : }
     226             : 
     227             : already_AddRefed<workers::ServiceWorker>
     228           0 : ServiceWorkerContainer::GetController()
     229             : {
     230           0 :   if (!mControllerWorker) {
     231           0 :     nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
     232           0 :     if (!swm) {
     233           0 :       return nullptr;
     234             :     }
     235             : 
     236             :     // TODO: What should we do here if the ServiceWorker script fails to load?
     237             :     //       In theory the DOM ServiceWorker object can exist without the worker
     238             :     //       thread running, but it seems our design does not expect that.
     239           0 :     nsCOMPtr<nsISupports> serviceWorker;
     240           0 :     nsresult rv = swm->GetDocumentController(GetOwner(),
     241           0 :                                              getter_AddRefs(serviceWorker));
     242           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     243           0 :       return nullptr;
     244             :     }
     245             : 
     246             :     mControllerWorker =
     247           0 :       static_cast<workers::ServiceWorker*>(serviceWorker.get());
     248             :   }
     249             : 
     250           0 :   RefPtr<workers::ServiceWorker> ref = mControllerWorker;
     251           0 :   return ref.forget();
     252             : }
     253             : 
     254             : already_AddRefed<Promise>
     255           0 : ServiceWorkerContainer::GetRegistrations(ErrorResult& aRv)
     256             : {
     257             :   nsresult rv;
     258           0 :   nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
     259           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     260           0 :     aRv.Throw(rv);
     261           0 :     return nullptr;
     262             :   }
     263             : 
     264           0 :   nsCOMPtr<nsISupports> promise;
     265           0 :   aRv = swm->GetRegistrations(GetOwner(), getter_AddRefs(promise));
     266           0 :   if (aRv.Failed()) {
     267           0 :     return nullptr;
     268             :   }
     269             : 
     270           0 :   RefPtr<Promise> ret = static_cast<Promise*>(promise.get());
     271           0 :   MOZ_ASSERT(ret);
     272           0 :   return ret.forget();
     273             : }
     274             : 
     275             : already_AddRefed<Promise>
     276           0 : ServiceWorkerContainer::GetRegistration(const nsAString& aDocumentURL,
     277             :                                         ErrorResult& aRv)
     278             : {
     279             :   nsresult rv;
     280           0 :   nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
     281           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     282           0 :     aRv.Throw(rv);
     283           0 :     return nullptr;
     284             :   }
     285             : 
     286           0 :   nsCOMPtr<nsISupports> promise;
     287           0 :   aRv = swm->GetRegistration(GetOwner(), aDocumentURL, getter_AddRefs(promise));
     288           0 :   if (aRv.Failed()) {
     289           0 :     return nullptr;
     290             :   }
     291             : 
     292           0 :   RefPtr<Promise> ret = static_cast<Promise*>(promise.get());
     293           0 :   MOZ_ASSERT(ret);
     294           0 :   return ret.forget();
     295             : }
     296             : 
     297             : Promise*
     298           0 : ServiceWorkerContainer::GetReady(ErrorResult& aRv)
     299             : {
     300           0 :   if (mReadyPromise) {
     301           0 :     return mReadyPromise;
     302             :   }
     303             : 
     304           0 :   nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
     305           0 :   if (!swm) {
     306           0 :     aRv.Throw(NS_ERROR_FAILURE);
     307           0 :     return nullptr;
     308             :   }
     309             : 
     310           0 :   nsCOMPtr<nsISupports> promise;
     311           0 :   aRv = swm->GetReadyPromise(GetOwner(), getter_AddRefs(promise));
     312             : 
     313           0 :   mReadyPromise = static_cast<Promise*>(promise.get());
     314           0 :   return mReadyPromise;
     315             : }
     316             : 
     317             : // Testing only.
     318             : void
     319           0 : ServiceWorkerContainer::GetScopeForUrl(const nsAString& aUrl,
     320             :                                        nsString& aScope,
     321             :                                        ErrorResult& aRv)
     322             : {
     323           0 :   nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
     324           0 :   if (!swm) {
     325           0 :     aRv.Throw(NS_ERROR_FAILURE);
     326           0 :     return;
     327             :   }
     328             : 
     329           0 :   nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
     330           0 :   if (NS_WARN_IF(!window)) {
     331           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     332           0 :     return;
     333             :   }
     334             : 
     335           0 :   nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
     336           0 :   if (NS_WARN_IF(!doc)) {
     337           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     338           0 :     return;
     339             :   }
     340             : 
     341           0 :   aRv = swm->GetScopeForUrl(doc->NodePrincipal(),
     342           0 :                             aUrl, aScope);
     343             : }
     344             : 
     345             : } // namespace dom
     346             : } // namespace mozilla

Generated by: LCOV version 1.13