2015-05-03 12:32:37 -07:00
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
2013-11-19 15:15:02 -08:00
/* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/. */
# include "ServiceWorkerManager.h"
2015-02-11 03:53:00 -08:00
# include "nsIAppsService.h"
2014-07-14 14:15:23 -07:00
# include "nsIDOMEventTarget.h"
2013-11-19 15:15:02 -08:00
# include "nsIDocument.h"
2014-07-02 17:48:50 -07:00
# include "nsIScriptSecurityManager.h"
2014-12-19 02:00:29 -08:00
# include "nsIStreamLoader.h"
# include "nsIHttpChannel.h"
# include "nsIHttpChannelInternal.h"
2015-02-18 17:34:29 -08:00
# include "nsIHttpHeaderVisitor.h"
2015-05-22 00:32:25 -07:00
# include "nsIJARChannel.h"
2015-02-18 17:34:29 -08:00
# include "nsINetworkInterceptController.h"
2015-04-10 01:50:06 -07:00
# include "nsIMutableArray.h"
2015-05-04 13:54:22 -07:00
# include "nsIUploadChannel2.h"
2013-11-19 15:15:02 -08:00
# include "nsPIDOMWindow.h"
2015-03-18 09:46:38 -07:00
# include "nsScriptLoader.h"
2015-02-18 17:34:29 -08:00
# include "nsDebug.h"
2013-11-19 15:15:02 -08:00
# include "jsapi.h"
2015-04-24 11:42:13 -07:00
# include "mozilla/ErrorNames.h"
2014-12-12 08:06:00 -08:00
# include "mozilla/LoadContext.h"
2013-11-19 15:15:02 -08:00
# include "mozilla/dom/BindingUtils.h"
2015-03-05 17:37:49 -08:00
# include "mozilla/dom/ContentParent.h"
2014-06-11 09:12:56 -07:00
# include "mozilla/dom/DOMError.h"
2014-07-02 17:48:35 -07:00
# include "mozilla/dom/ErrorEvent.h"
2015-02-18 17:34:29 -08:00
# include "mozilla/dom/Headers.h"
# include "mozilla/dom/InternalHeaders.h"
2014-10-28 13:11:31 -07:00
# include "mozilla/dom/Navigator.h"
2014-07-02 17:48:50 -07:00
# include "mozilla/dom/PromiseNativeHandler.h"
2015-02-18 17:34:29 -08:00
# include "mozilla/dom/Request.h"
# include "mozilla/dom/RootedDictionary.h"
2015-02-11 03:53:00 -08:00
# include "mozilla/ipc/BackgroundChild.h"
# include "mozilla/ipc/PBackgroundChild.h"
# include "mozilla/ipc/PBackgroundSharedTypes.h"
2015-04-13 10:36:06 -07:00
# include "mozilla/unused.h"
2014-06-11 09:12:56 -07:00
2013-11-19 15:15:02 -08:00
# include "nsContentUtils.h"
2014-10-28 13:11:31 -07:00
# include "nsGlobalWindow.h"
2013-11-19 15:15:02 -08:00
# include "nsNetUtil.h"
2014-06-11 09:12:56 -07:00
# include "nsProxyRelease.h"
2015-04-15 09:47:03 -07:00
# include "nsQueryObject.h"
2013-11-19 15:15:02 -08:00
# include "nsTArray.h"
# include "RuntimeService.h"
# include "ServiceWorker.h"
2014-10-27 04:03:00 -07:00
# include "ServiceWorkerClient.h"
2014-10-28 13:11:31 -07:00
# include "ServiceWorkerContainer.h"
2014-08-19 06:56:00 -07:00
# include "ServiceWorkerRegistration.h"
2015-03-18 09:46:38 -07:00
# include "ServiceWorkerScriptCache.h"
2014-07-02 17:48:50 -07:00
# include "ServiceWorkerEvents.h"
2013-11-19 15:15:02 -08:00
# include "WorkerInlines.h"
2014-06-11 09:12:56 -07:00
# include "WorkerPrivate.h"
# include "WorkerRunnable.h"
2014-07-02 17:48:50 -07:00
# include "WorkerScope.h"
2013-11-19 15:15:02 -08:00
2014-12-12 08:06:00 -08:00
# ifdef PostMessage
# undef PostMessage
# endif
2013-11-19 15:15:02 -08:00
using namespace mozilla ;
using namespace mozilla : : dom ;
2015-02-11 03:53:00 -08:00
using namespace mozilla : : ipc ;
2013-11-19 15:15:02 -08:00
BEGIN_WORKERS_NAMESPACE
2015-03-05 17:37:49 -08:00
# define PURGE_DOMAIN_DATA "browser:purge-domain-data"
# define PURGE_SESSION_HISTORY "browser:purge-session-history"
2015-03-17 08:47:02 -07:00
static_assert ( nsIHttpChannelInternal : : CORS_MODE_SAME_ORIGIN = = static_cast < uint32_t > ( RequestMode : : Same_origin ) ,
" RequestMode enumeration value should match Necko CORS mode value. " ) ;
static_assert ( nsIHttpChannelInternal : : CORS_MODE_NO_CORS = = static_cast < uint32_t > ( RequestMode : : No_cors ) ,
" RequestMode enumeration value should match Necko CORS mode value. " ) ;
static_assert ( nsIHttpChannelInternal : : CORS_MODE_CORS = = static_cast < uint32_t > ( RequestMode : : Cors ) ,
" RequestMode enumeration value should match Necko CORS mode value. " ) ;
static_assert ( nsIHttpChannelInternal : : CORS_MODE_CORS_WITH_FORCED_PREFLIGHT = = static_cast < uint32_t > ( RequestMode : : Cors_with_forced_preflight ) ,
" RequestMode enumeration value should match Necko CORS mode value. " ) ;
2015-02-11 03:53:00 -08:00
struct ServiceWorkerManager : : PendingOperation
{
nsCOMPtr < nsIRunnable > mRunnable ;
ServiceWorkerJobQueue * mQueue ;
nsRefPtr < ServiceWorkerJob > mJob ;
ServiceWorkerRegistrationData mRegistration ;
} ;
namespace {
nsresult
PopulateRegistrationData ( nsIPrincipal * aPrincipal ,
const ServiceWorkerRegistrationInfo * aRegistration ,
ServiceWorkerRegistrationData & aData )
{
MOZ_ASSERT ( aPrincipal ) ;
MOZ_ASSERT ( aRegistration ) ;
bool isNullPrincipal = true ;
nsresult rv = aPrincipal - > GetIsNullPrincipal ( & isNullPrincipal ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
// No null principals.
if ( NS_WARN_IF ( isNullPrincipal ) ) {
return NS_ERROR_FAILURE ;
}
rv = PrincipalToPrincipalInfo ( aPrincipal , & aData . principal ( ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
aData . scope ( ) = aRegistration - > mScope ;
aData . scriptSpec ( ) = aRegistration - > mScriptSpec ;
if ( aRegistration - > mActiveWorker ) {
aData . currentWorkerURL ( ) = aRegistration - > mActiveWorker - > ScriptSpec ( ) ;
2015-03-18 09:46:38 -07:00
aData . activeCacheName ( ) = aRegistration - > mActiveWorker - > CacheName ( ) ;
}
if ( aRegistration - > mWaitingWorker ) {
aData . waitingCacheName ( ) = aRegistration - > mWaitingWorker - > CacheName ( ) ;
2015-02-11 03:53:00 -08:00
}
return NS_OK ;
}
} // Anonymous namespace
2014-12-19 02:00:29 -08:00
NS_IMPL_ISUPPORTS0 ( ServiceWorkerJob )
2014-08-19 06:56:00 -07:00
NS_IMPL_ISUPPORTS0 ( ServiceWorkerRegistrationInfo )
2014-06-11 09:12:56 -07:00
void
2014-12-19 02:00:29 -08:00
ServiceWorkerJob : : Done ( nsresult aStatus )
2014-06-11 09:12:56 -07:00
{
2014-12-19 02:00:29 -08:00
if ( NS_WARN_IF ( NS_FAILED ( aStatus ) ) ) {
2015-04-24 11:42:13 -07:00
# ifdef DEBUG
nsAutoCString errorName ;
GetErrorName ( aStatus , errorName ) ;
# endif
NS_WARNING ( nsPrintfCString ( " ServiceWorkerJob failed with error: %s \n " ,
2015-04-24 11:55:06 -07:00
errorName . get ( ) ) . get ( ) ) ;
2014-06-11 09:12:56 -07:00
}
2014-07-02 17:48:35 -07:00
2014-12-19 02:00:29 -08:00
if ( mQueue ) {
mQueue - > Done ( this ) ;
2014-07-02 17:48:35 -07:00
}
}
2014-07-14 10:33:44 -07:00
void
ServiceWorkerRegistrationInfo : : Clear ( )
{
if ( mInstallingWorker ) {
// FIXME(nsm): Terminate installing worker.
2014-12-19 03:25:56 -08:00
mInstallingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2014-07-14 10:33:44 -07:00
mInstallingWorker = nullptr ;
// FIXME(nsm): Abort any inflight requests from installing worker.
}
if ( mWaitingWorker ) {
2014-12-19 03:25:56 -08:00
mWaitingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2015-03-18 09:46:38 -07:00
nsresult rv = serviceWorkerScriptCache : : PurgeCache ( mPrincipal ,
mWaitingWorker - > CacheName ( ) ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to purge the waiting cache. " ) ;
}
2014-07-14 10:33:44 -07:00
mWaitingWorker = nullptr ;
}
2014-12-19 02:00:29 -08:00
if ( mActiveWorker ) {
2014-12-19 03:25:56 -08:00
mActiveWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2015-03-18 09:46:38 -07:00
nsresult rv = serviceWorkerScriptCache : : PurgeCache ( mPrincipal ,
mActiveWorker - > CacheName ( ) ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to purge the active cache. " ) ;
}
2014-12-19 02:00:29 -08:00
mActiveWorker = nullptr ;
2014-07-14 10:33:44 -07:00
}
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
MOZ_ASSERT ( swm ) ;
swm - > InvalidateServiceWorkerRegistrationWorker ( this ,
WhichServiceWorker : : INSTALLING_WORKER |
WhichServiceWorker : : WAITING_WORKER |
WhichServiceWorker : : ACTIVE_WORKER ) ;
}
2015-02-11 03:53:00 -08:00
ServiceWorkerRegistrationInfo : : ServiceWorkerRegistrationInfo ( const nsACString & aScope ,
nsIPrincipal * aPrincipal )
: mControlledDocumentsCounter ( 0 )
, mScope ( aScope )
, mPrincipal ( aPrincipal )
, mPendingUninstall ( false )
2014-12-19 02:00:29 -08:00
{ }
2014-06-11 09:12:56 -07:00
2014-12-19 02:00:29 -08:00
ServiceWorkerRegistrationInfo : : ~ ServiceWorkerRegistrationInfo ( )
2014-06-11 09:12:56 -07:00
{
2014-12-19 02:00:29 -08:00
if ( IsControllingDocuments ( ) ) {
NS_WARNING ( " ServiceWorkerRegistrationInfo is still controlling documents. This can be a bug or a leak in ServiceWorker API or in any other API that takes the document alive. " ) ;
2014-06-11 09:12:56 -07:00
}
2014-12-19 02:00:29 -08:00
}
2014-06-11 09:12:56 -07:00
2013-11-19 15:15:02 -08:00
//////////////////////////
// ServiceWorkerManager //
//////////////////////////
NS_IMPL_ADDREF ( ServiceWorkerManager )
NS_IMPL_RELEASE ( ServiceWorkerManager )
NS_INTERFACE_MAP_BEGIN ( ServiceWorkerManager )
NS_INTERFACE_MAP_ENTRY ( nsIServiceWorkerManager )
2015-02-11 03:53:00 -08:00
NS_INTERFACE_MAP_ENTRY ( nsIIPCBackgroundChildCreateCallback )
2015-03-05 17:37:49 -08:00
NS_INTERFACE_MAP_ENTRY ( nsIObserver )
2013-11-19 15:15:02 -08:00
if ( aIID . Equals ( NS_GET_IID ( ServiceWorkerManager ) ) )
foundInterface = static_cast < nsIServiceWorkerManager * > ( this ) ;
else
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS ( nsISupports , nsIServiceWorkerManager )
NS_INTERFACE_MAP_END
ServiceWorkerManager : : ServiceWorkerManager ( )
2015-02-11 03:53:00 -08:00
: mActor ( nullptr )
2013-11-19 15:15:02 -08:00
{
2015-02-11 03:53:00 -08:00
// Register this component to PBackground.
MOZ_ALWAYS_TRUE ( BackgroundChild : : GetOrCreateForCurrentThread ( this ) ) ;
if ( XRE_GetProcessType ( ) = = GeckoProcessType_Default ) {
nsRefPtr < ServiceWorkerRegistrar > swr = ServiceWorkerRegistrar : : Get ( ) ;
MOZ_ASSERT ( swr ) ;
nsTArray < ServiceWorkerRegistrationData > data ;
swr - > GetRegistrations ( data ) ;
LoadRegistrations ( data ) ;
2015-03-05 17:37:49 -08:00
nsCOMPtr < nsIObserverService > obs = mozilla : : services : : GetObserverService ( ) ;
if ( obs ) {
DebugOnly < nsresult > rv ;
rv = obs - > AddObserver ( this , NS_XPCOM_SHUTDOWN_OBSERVER_ID , false /* ownsWeak */ ) ;
MOZ_ASSERT ( NS_SUCCEEDED ( rv ) ) ;
rv = obs - > AddObserver ( this , PURGE_SESSION_HISTORY , false /* ownsWeak */ ) ;
MOZ_ASSERT ( NS_SUCCEEDED ( rv ) ) ;
rv = obs - > AddObserver ( this , PURGE_DOMAIN_DATA , false /* ownsWeak */ ) ;
MOZ_ASSERT ( NS_SUCCEEDED ( rv ) ) ;
}
2015-02-11 03:53:00 -08:00
}
2013-11-19 15:15:02 -08:00
}
ServiceWorkerManager : : ~ ServiceWorkerManager ( )
{
// The map will assert if it is not empty when destroyed.
2015-05-19 12:20:15 -07:00
mServiceWorkerRegistrationInfos . Clear ( ) ;
2013-11-19 15:15:02 -08:00
}
2014-12-19 05:01:53 -08:00
class ContinueLifecycleTask : public nsISupports
2014-12-19 02:00:29 -08:00
{
2014-12-19 05:01:53 -08:00
NS_DECL_ISUPPORTS
protected :
virtual ~ ContinueLifecycleTask ( )
{ }
public :
virtual void ContinueAfterWorkerEvent ( bool aSuccess ,
bool aActivateImmediately ) = 0 ;
} ;
NS_IMPL_ISUPPORTS0 ( ContinueLifecycleTask ) ;
2015-02-10 14:33:23 -08:00
class ServiceWorkerRegisterJob ;
2015-03-21 09:28:04 -07:00
class ContinueInstallTask final : public ContinueLifecycleTask
2014-12-19 05:01:53 -08:00
{
nsRefPtr < ServiceWorkerRegisterJob > mJob ;
public :
explicit ContinueInstallTask ( ServiceWorkerRegisterJob * aJob )
: mJob ( aJob )
{ }
2015-03-21 09:28:04 -07:00
void ContinueAfterWorkerEvent ( bool aSuccess , bool aActivateImmediately ) override ;
2014-12-19 05:01:53 -08:00
} ;
2015-03-21 09:28:04 -07:00
class ContinueActivateTask final : public ContinueLifecycleTask
2014-12-19 05:01:53 -08:00
{
nsRefPtr < ServiceWorkerRegistrationInfo > mRegistration ;
public :
explicit ContinueActivateTask ( ServiceWorkerRegistrationInfo * aReg )
: mRegistration ( aReg )
{ }
void
2015-03-21 09:28:04 -07:00
ContinueAfterWorkerEvent ( bool aSuccess , bool aActivateImmediately /* unused */ ) override ;
2014-12-19 05:01:53 -08:00
} ;
2015-03-21 09:28:04 -07:00
class ContinueLifecycleRunnable final : public nsRunnable
2014-12-19 05:01:53 -08:00
{
nsMainThreadPtrHandle < ContinueLifecycleTask > mTask ;
2014-12-19 02:00:29 -08:00
bool mSuccess ;
bool mActivateImmediately ;
public :
2014-12-19 05:01:53 -08:00
ContinueLifecycleRunnable ( const nsMainThreadPtrHandle < ContinueLifecycleTask > & aTask ,
bool aSuccess ,
bool aActivateImmediately )
: mTask ( aTask )
2014-12-19 02:00:29 -08:00
, mSuccess ( aSuccess )
, mActivateImmediately ( aActivateImmediately )
{
MOZ_ASSERT ( ! NS_IsMainThread ( ) ) ;
}
NS_IMETHOD
2015-03-21 09:28:04 -07:00
Run ( ) override
2014-12-19 05:01:53 -08:00
{
AssertIsOnMainThread ( ) ;
mTask - > ContinueAfterWorkerEvent ( mSuccess , mActivateImmediately ) ;
return NS_OK ;
}
2014-12-19 02:00:29 -08:00
} ;
2013-11-19 15:15:02 -08:00
/*
2014-12-19 02:00:29 -08:00
* Fires ' install ' event on the ServiceWorkerGlobalScope . Modifies busy count
* since it fires the event . This is ok since there can ' t be nested
* ServiceWorkers , so the parent thread - > worker thread requirement for
* runnables is satisfied .
2013-11-19 15:15:02 -08:00
*/
2015-03-21 09:28:04 -07:00
class LifecycleEventWorkerRunnable final : public WorkerRunnable
2013-11-19 15:15:02 -08:00
{
2014-12-19 05:01:53 -08:00
nsString mEventName ;
2015-04-01 16:46:49 -07:00
const nsMainThreadPtrHandle < ServiceWorker > mServiceWorker ;
const nsMainThreadPtrHandle < ContinueLifecycleTask > mTask ;
2014-12-19 02:00:29 -08:00
2013-11-19 15:15:02 -08:00
public :
2015-04-01 16:46:49 -07:00
LifecycleEventWorkerRunnable ( nsMainThreadPtrHandle < ServiceWorker > & aServiceWorker ,
2014-12-19 05:01:53 -08:00
const nsString & aEventName ,
const nsMainThreadPtrHandle < ContinueLifecycleTask > & aTask )
2015-04-01 16:46:49 -07:00
: WorkerRunnable ( aServiceWorker - > GetWorkerPrivate ( ) , WorkerThreadModifyBusyCount )
2014-12-19 05:01:53 -08:00
, mEventName ( aEventName )
2015-04-01 16:46:49 -07:00
, mServiceWorker ( aServiceWorker )
2014-12-19 05:01:53 -08:00
, mTask ( aTask )
2014-12-19 02:00:29 -08:00
{
AssertIsOnMainThread ( ) ;
}
2013-11-19 15:15:02 -08:00
2014-12-19 02:00:29 -08:00
bool
2015-03-21 09:28:04 -07:00
WorkerRun ( JSContext * aCx , WorkerPrivate * aWorkerPrivate ) override
2013-11-19 15:15:02 -08:00
{
2014-12-19 02:00:29 -08:00
MOZ_ASSERT ( aWorkerPrivate ) ;
2014-12-19 05:01:53 -08:00
return DispatchLifecycleEvent ( aCx , aWorkerPrivate ) ;
2014-12-19 02:00:29 -08:00
}
2014-07-20 23:25:44 -07:00
2014-12-19 02:00:29 -08:00
private :
bool
2014-12-19 05:01:53 -08:00
DispatchLifecycleEvent ( JSContext * aCx , WorkerPrivate * aWorkerPrivate ) ;
2013-11-19 15:15:02 -08:00
2014-12-19 02:00:29 -08:00
} ;
2013-11-19 15:15:02 -08:00
2014-12-19 02:00:29 -08:00
class ServiceWorkerUpdateFinishCallback
{
protected :
virtual ~ ServiceWorkerUpdateFinishCallback ( )
{ }
2013-11-19 15:15:02 -08:00
2014-12-19 02:00:29 -08:00
public :
NS_INLINE_DECL_REFCOUNTING ( ServiceWorkerUpdateFinishCallback )
2013-11-19 15:15:02 -08:00
2014-12-19 02:00:29 -08:00
virtual
void UpdateSucceeded ( ServiceWorkerRegistrationInfo * aInfo )
{ }
2013-11-19 15:15:02 -08:00
2014-12-19 02:00:29 -08:00
virtual
void UpdateFailed ( nsresult aStatus )
{ }
2014-12-19 02:48:31 -08:00
virtual
void UpdateFailed ( const ErrorEventInit & aDesc )
{ }
2014-12-19 02:00:29 -08:00
} ;
2013-11-19 15:15:02 -08:00
2015-03-21 09:28:04 -07:00
class ServiceWorkerResolveWindowPromiseOnUpdateCallback final : public ServiceWorkerUpdateFinishCallback
2014-12-19 02:00:29 -08:00
{
nsRefPtr < nsPIDOMWindow > mWindow ;
// The promise "returned" by the call to Update up to
// navigator.serviceWorker.register().
nsRefPtr < Promise > mPromise ;
2014-06-11 09:12:56 -07:00
2014-12-19 02:00:29 -08:00
~ ServiceWorkerResolveWindowPromiseOnUpdateCallback ( )
{ }
2014-06-11 09:12:56 -07:00
2014-12-19 02:00:29 -08:00
public :
ServiceWorkerResolveWindowPromiseOnUpdateCallback ( nsPIDOMWindow * aWindow , Promise * aPromise )
: mWindow ( aWindow )
, mPromise ( aPromise )
{
}
void
2015-03-21 09:28:04 -07:00
UpdateSucceeded ( ServiceWorkerRegistrationInfo * aInfo ) override
2014-12-19 02:00:29 -08:00
{
2015-04-03 15:18:55 -07:00
nsRefPtr < ServiceWorkerRegistrationMainThread > swr =
new ServiceWorkerRegistrationMainThread ( mWindow ,
NS_ConvertUTF8toUTF16 ( aInfo - > mScope ) ) ;
2014-12-19 02:00:29 -08:00
mPromise - > MaybeResolve ( swr ) ;
}
void
2015-03-21 09:28:04 -07:00
UpdateFailed ( nsresult aStatus ) override
2014-12-19 02:00:29 -08:00
{
mPromise - > MaybeReject ( aStatus ) ;
2013-11-19 15:15:02 -08:00
}
2014-12-19 02:48:31 -08:00
void
2015-03-21 09:28:04 -07:00
UpdateFailed ( const ErrorEventInit & aErrorDesc ) override
2014-12-19 02:48:31 -08:00
{
AutoJSAPI jsapi ;
jsapi . Init ( mWindow ) ;
JSContext * cx = jsapi . cx ( ) ;
JS : : Rooted < JS : : Value > fnval ( cx ) ;
if ( ! ToJSValue ( cx , aErrorDesc . mFilename , & fnval ) ) {
JS_ClearPendingException ( cx ) ;
mPromise - > MaybeReject ( NS_ERROR_DOM_ABORT_ERR ) ;
return ;
}
JS : : Rooted < JSString * > fn ( cx , fnval . toString ( ) ) ;
JS : : Rooted < JS : : Value > msgval ( cx ) ;
if ( ! ToJSValue ( cx , aErrorDesc . mMessage , & msgval ) ) {
JS_ClearPendingException ( cx ) ;
mPromise - > MaybeReject ( NS_ERROR_DOM_ABORT_ERR ) ;
return ;
}
JS : : Rooted < JSString * > msg ( cx , msgval . toString ( ) ) ;
JS : : Rooted < JS : : Value > error ( cx ) ;
2015-05-13 14:07:34 -07:00
if ( ! JS : : CreateError ( cx , JSEXN_ERR , nullptr , fn , aErrorDesc . mLineno ,
2014-12-19 02:48:31 -08:00
aErrorDesc . mColno , nullptr , msg , & error ) ) {
JS_ClearPendingException ( cx ) ;
mPromise - > MaybeReject ( NS_ERROR_DOM_ABORT_ERR ) ;
return ;
}
mPromise - > MaybeReject ( cx , error ) ;
}
} ;
2015-03-21 09:28:04 -07:00
class ContinueUpdateRunnable final : public nsRunnable
2014-12-19 02:48:31 -08:00
{
nsMainThreadPtrHandle < nsISupports > mJob ;
public :
explicit ContinueUpdateRunnable ( const nsMainThreadPtrHandle < nsISupports > aJob )
: mJob ( aJob )
{
MOZ_ASSERT ( ! NS_IsMainThread ( ) ) ;
}
NS_IMETHOD Run ( ) ;
} ;
2015-03-21 09:28:04 -07:00
class CheckWorkerEvaluationAndContinueUpdateWorkerRunnable final : public WorkerRunnable
2014-12-19 02:48:31 -08:00
{
2015-04-01 16:46:49 -07:00
const nsMainThreadPtrHandle < ServiceWorker > mServiceWorker ;
2014-12-19 02:48:31 -08:00
const nsMainThreadPtrHandle < nsISupports > mJob ;
public :
2015-04-01 16:46:49 -07:00
CheckWorkerEvaluationAndContinueUpdateWorkerRunnable ( nsMainThreadPtrHandle < ServiceWorker > & aServiceWorker ,
2014-12-19 02:48:31 -08:00
const nsMainThreadPtrHandle < nsISupports > aJob )
2015-04-01 16:46:49 -07:00
: WorkerRunnable ( aServiceWorker - > GetWorkerPrivate ( ) , WorkerThreadUnchangedBusyCount )
, mServiceWorker ( aServiceWorker )
2014-12-19 02:48:31 -08:00
, mJob ( aJob )
2015-02-11 10:51:32 -08:00
{
2014-12-19 02:48:31 -08:00
AssertIsOnMainThread ( ) ;
}
bool
2015-03-21 09:28:04 -07:00
WorkerRun ( JSContext * aCx , WorkerPrivate * aWorkerPrivate ) override
2014-12-19 02:48:31 -08:00
{
aWorkerPrivate - > AssertIsOnWorkerThread ( ) ;
if ( aWorkerPrivate - > WorkerScriptExecutedSuccessfully ( ) ) {
nsRefPtr < ContinueUpdateRunnable > r = new ContinueUpdateRunnable ( mJob ) ;
nsresult rv = NS_DispatchToMainThread ( r ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to dispatch ContinueUpdateRunnable to main thread. " ) ;
}
}
return true ;
}
2013-11-19 15:15:02 -08:00
} ;
2015-03-09 18:57:06 -07:00
namespace {
2015-05-05 22:17:20 -07:00
/**
* The spec mandates slightly different behaviors for computing the scope
* prefix string in case a Service - Worker - Allowed header is specified versus
* when it ' s not available .
*
* With the header :
* " Set maxScopeString to " / " concatenated with the strings in maxScope's
* path ( including empty strings ) , separated from each other by " / " . "
* Without the header :
* " Set maxScopeString to " / " concatenated with the strings, except the last
* string that denotes the script ' s file name , in registration ' s registering
* script url ' s path ( including empty strings ) , separated from each other by
* " / " . "
*
* In simpler terms , if the header is not present , we should only use the
* " directory " part of the pathname , and otherwise the entire pathname should be
* used . ScopeStringPrefixMode allows the caller to specify the desired
* behavior .
*/
enum ScopeStringPrefixMode {
eUseDirectory ,
eUsePath
} ;
2015-03-09 18:57:06 -07:00
nsresult
2015-05-05 22:17:20 -07:00
GetRequiredScopeStringPrefix ( nsIURI * aScriptURI , nsACString & aPrefix ,
ScopeStringPrefixMode aPrefixMode )
2015-03-09 18:57:06 -07:00
{
2015-05-05 22:17:20 -07:00
nsresult rv = aScriptURI - > GetPrePath ( aPrefix ) ;
2015-03-09 18:57:06 -07:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-05-05 22:17:20 -07:00
if ( aPrefixMode = = eUseDirectory ) {
nsCOMPtr < nsIURL > scriptURL ( do_QueryInterface ( aScriptURI ) ) ;
if ( NS_WARN_IF ( ! scriptURL ) ) {
return NS_ERROR_FAILURE ;
}
2015-03-09 18:57:06 -07:00
2015-05-05 22:17:20 -07:00
nsAutoCString dir ;
rv = scriptURL - > GetDirectory ( dir ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-03-09 18:57:06 -07:00
2015-05-05 22:17:20 -07:00
aPrefix . Append ( dir ) ;
} else if ( aPrefixMode = = eUsePath ) {
nsAutoCString path ;
rv = aScriptURI - > GetPath ( path ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-03-09 18:57:06 -07:00
2015-05-05 22:17:20 -07:00
aPrefix . Append ( path ) ;
} else {
MOZ_ASSERT_UNREACHABLE ( " Invalid value for aPrefixMode " ) ;
}
2015-03-09 18:57:06 -07:00
return NS_OK ;
}
} // anonymous namespace
2015-03-21 09:28:04 -07:00
class ServiceWorkerRegisterJob final : public ServiceWorkerJob ,
2015-03-18 09:52:54 -07:00
public serviceWorkerScriptCache : : CompareCallback
2013-11-19 15:15:02 -08:00
{
2014-12-19 05:01:53 -08:00
friend class ContinueInstallTask ;
2013-11-19 15:15:02 -08:00
2014-12-19 02:00:29 -08:00
nsCString mScope ;
nsCString mScriptSpec ;
nsRefPtr < ServiceWorkerRegistrationInfo > mRegistration ;
nsRefPtr < ServiceWorkerUpdateFinishCallback > mCallback ;
2015-02-11 03:53:00 -08:00
nsCOMPtr < nsIPrincipal > mPrincipal ;
2015-03-18 14:02:51 -07:00
nsRefPtr < ServiceWorkerInfo > mUpdateAndInstallInfo ;
2013-11-19 15:15:02 -08:00
2014-12-19 02:00:29 -08:00
~ ServiceWorkerRegisterJob ( )
{ }
2013-11-19 15:15:02 -08:00
2014-12-19 02:00:29 -08:00
enum
{
REGISTER_JOB = 0 ,
UPDATE_JOB = 1 ,
} mJobType ;
2013-11-19 15:15:02 -08:00
2015-03-05 17:37:49 -08:00
bool mCanceled ;
2014-12-19 02:00:29 -08:00
public :
2015-03-18 09:46:38 -07:00
NS_DECL_ISUPPORTS_INHERITED
2013-11-19 15:15:02 -08:00
2014-12-19 02:00:29 -08:00
// [[Register]]
ServiceWorkerRegisterJob ( ServiceWorkerJobQueue * aQueue ,
const nsCString & aScope ,
const nsCString & aScriptSpec ,
2015-02-11 03:53:00 -08:00
ServiceWorkerUpdateFinishCallback * aCallback ,
nsIPrincipal * aPrincipal )
2014-12-19 02:00:29 -08:00
: ServiceWorkerJob ( aQueue )
, mScope ( aScope )
, mScriptSpec ( aScriptSpec )
, mCallback ( aCallback )
2015-02-11 03:53:00 -08:00
, mPrincipal ( aPrincipal )
2014-12-19 02:00:29 -08:00
, mJobType ( REGISTER_JOB )
2015-03-05 17:37:49 -08:00
, mCanceled ( false )
2014-12-19 02:00:29 -08:00
{ }
2014-08-21 16:31:12 -07:00
2014-12-19 02:00:29 -08:00
// [[Update]]
ServiceWorkerRegisterJob ( ServiceWorkerJobQueue * aQueue ,
ServiceWorkerRegistrationInfo * aRegistration ,
ServiceWorkerUpdateFinishCallback * aCallback )
: ServiceWorkerJob ( aQueue )
, mRegistration ( aRegistration )
, mCallback ( aCallback )
, mJobType ( UPDATE_JOB )
2015-03-05 17:37:49 -08:00
, mCanceled ( false )
2014-12-19 02:00:29 -08:00
{ }
2014-09-02 13:07:55 -07:00
2015-03-05 17:37:49 -08:00
bool
IsRegisterJob ( ) const override
{
return true ;
}
void
Cancel ( )
{
mQueue = nullptr ;
mCanceled = true ;
}
2014-12-19 02:00:29 -08:00
void
2015-03-21 09:28:04 -07:00
Start ( ) override
2014-12-19 02:00:29 -08:00
{
2015-02-11 03:53:00 -08:00
MOZ_ASSERT ( NS_IsMainThread ( ) ) ;
2015-03-05 17:37:49 -08:00
MOZ_ASSERT ( ! mCanceled ) ;
2015-02-11 03:53:00 -08:00
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
if ( ! swm - > HasBackgroundActor ( ) ) {
nsCOMPtr < nsIRunnable > runnable =
NS_NewRunnableMethod ( this , & ServiceWorkerRegisterJob : : Start ) ;
swm - > AppendPendingOperation ( runnable ) ;
return ;
}
2014-12-19 02:00:29 -08:00
if ( mJobType = = REGISTER_JOB ) {
2015-05-19 12:20:15 -07:00
mRegistration = swm - > GetRegistration ( mScope ) ;
2014-12-19 02:00:29 -08:00
if ( mRegistration ) {
nsRefPtr < ServiceWorkerInfo > newest = mRegistration - > Newest ( ) ;
2014-12-19 03:25:56 -08:00
if ( newest & & mScriptSpec . Equals ( newest - > ScriptSpec ( ) ) & &
2014-12-19 02:00:29 -08:00
mScriptSpec . Equals ( mRegistration - > mScriptSpec ) ) {
mRegistration - > mPendingUninstall = false ;
2015-04-30 07:32:47 -07:00
swm - > StoreRegistration ( mPrincipal , mRegistration ) ;
2014-12-19 02:00:29 -08:00
Succeed ( ) ;
Done ( NS_OK ) ;
return ;
}
} else {
2015-02-11 03:53:00 -08:00
mRegistration = swm - > CreateNewRegistration ( mScope , mPrincipal ) ;
2014-12-19 02:00:29 -08:00
}
2014-09-02 13:07:55 -07:00
2014-12-19 02:00:29 -08:00
mRegistration - > mScriptSpec = mScriptSpec ;
2015-02-11 03:53:00 -08:00
swm - > StoreRegistration ( mPrincipal , mRegistration ) ;
2014-12-19 02:00:29 -08:00
} else {
MOZ_ASSERT ( mJobType = = UPDATE_JOB ) ;
2014-09-02 13:07:55 -07:00
}
2014-12-19 02:00:29 -08:00
Update ( ) ;
2014-09-02 13:07:55 -07:00
}
2015-03-18 09:52:54 -07:00
void
2015-05-05 22:17:20 -07:00
ComparisonResult ( nsresult aStatus , bool aInCacheAndEqual ,
const nsAString & aNewCacheName ,
const nsACString & aMaxScope ) override
2014-12-19 02:00:29 -08:00
{
2015-03-05 17:37:49 -08:00
nsRefPtr < ServiceWorkerRegisterJob > kungFuDeathGrip = this ;
if ( mCanceled ) {
Fail ( NS_ERROR_DOM_TYPE_ERR ) ;
return ;
}
2014-12-19 02:00:29 -08:00
if ( NS_WARN_IF ( NS_FAILED ( aStatus ) ) ) {
2015-02-09 13:47:09 -08:00
Fail ( NS_ERROR_DOM_TYPE_ERR ) ;
2015-03-18 09:52:54 -07:00
return ;
2014-12-19 02:00:29 -08:00
}
2013-11-19 15:15:02 -08:00
2015-03-18 09:52:54 -07:00
if ( aInCacheAndEqual ) {
Succeed ( ) ;
2015-03-19 15:03:49 -07:00
Done ( NS_OK ) ;
2015-03-18 09:52:54 -07:00
return ;
2014-12-19 02:00:29 -08:00
}
2013-11-19 15:15:02 -08:00
2014-12-19 02:48:31 -08:00
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-02-08 20:33:39 -08:00
2015-05-05 22:17:20 -07:00
nsCOMPtr < nsIURI > scriptURI ;
nsresult rv = NS_NewURI ( getter_AddRefs ( scriptURI ) , mRegistration - > mScriptSpec ) ;
2015-03-09 18:57:06 -07:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
Fail ( NS_ERROR_DOM_SECURITY_ERR ) ;
2015-03-18 09:52:54 -07:00
return ;
2015-03-09 18:57:06 -07:00
}
2015-05-05 22:17:20 -07:00
nsCOMPtr < nsIURI > maxScopeURI ;
if ( ! aMaxScope . IsEmpty ( ) ) {
rv = NS_NewURI ( getter_AddRefs ( maxScopeURI ) , aMaxScope ,
nullptr , scriptURI ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
Fail ( NS_ERROR_DOM_SECURITY_ERR ) ;
return ;
}
}
nsAutoCString defaultAllowedPrefix ;
rv = GetRequiredScopeStringPrefix ( scriptURI , defaultAllowedPrefix ,
eUseDirectory ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
Fail ( NS_ERROR_DOM_SECURITY_ERR ) ;
return ;
}
nsAutoCString maxPrefix ( defaultAllowedPrefix ) ;
if ( maxScopeURI ) {
rv = GetRequiredScopeStringPrefix ( maxScopeURI , maxPrefix , eUsePath ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
Fail ( NS_ERROR_DOM_SECURITY_ERR ) ;
return ;
}
}
2015-03-09 18:57:06 -07:00
2015-05-05 22:17:20 -07:00
if ( ! StringBeginsWith ( mRegistration - > mScope , maxPrefix ) ) {
2015-03-09 18:57:06 -07:00
NS_WARNING ( " By default a service worker's scope is restricted to at or below it's script's location. " ) ;
Fail ( NS_ERROR_DOM_SECURITY_ERR ) ;
2015-03-18 09:52:54 -07:00
return ;
2015-03-09 18:57:06 -07:00
}
2015-03-18 09:46:38 -07:00
nsAutoString cacheName ;
2014-12-19 02:48:31 -08:00
// We have to create a ServiceWorker here simply to ensure there are no
// errors. Ideally we should just pass this worker on to ContinueInstall.
2015-02-08 20:33:39 -08:00
MOZ_ASSERT ( ! swm - > mSetOfScopesBeingUpdated . Contains ( mRegistration - > mScope ) ) ;
swm - > mSetOfScopesBeingUpdated . Put ( mRegistration - > mScope , true ) ;
2015-03-18 14:02:51 -07:00
MOZ_ASSERT ( ! mUpdateAndInstallInfo ) ;
mUpdateAndInstallInfo =
2015-03-19 11:41:42 -07:00
new ServiceWorkerInfo ( mRegistration , mRegistration - > mScriptSpec ,
2015-04-13 21:05:28 -07:00
aNewCacheName ) ;
2014-12-19 02:48:31 -08:00
nsRefPtr < ServiceWorker > serviceWorker ;
2015-02-17 04:36:09 -08:00
rv = swm - > CreateServiceWorker ( mRegistration - > mPrincipal ,
2015-03-18 14:02:51 -07:00
mUpdateAndInstallInfo ,
2014-12-19 02:48:31 -08:00
getter_AddRefs ( serviceWorker ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2015-02-11 13:24:57 -08:00
swm - > mSetOfScopesBeingUpdated . Remove ( mRegistration - > mScope ) ;
2014-12-19 02:48:31 -08:00
Fail ( NS_ERROR_DOM_ABORT_ERR ) ;
2015-03-18 09:52:54 -07:00
return ;
2014-12-19 02:48:31 -08:00
}
nsRefPtr < ServiceWorkerJob > upcasted = this ;
nsMainThreadPtrHandle < nsISupports > handle (
new nsMainThreadPtrHolder < nsISupports > ( upcasted ) ) ;
2015-04-01 16:46:49 -07:00
nsMainThreadPtrHandle < ServiceWorker > serviceWorkerHandle (
new nsMainThreadPtrHolder < ServiceWorker > ( serviceWorker ) ) ;
2014-12-19 02:48:31 -08:00
nsRefPtr < CheckWorkerEvaluationAndContinueUpdateWorkerRunnable > r =
2015-04-01 16:46:49 -07:00
new CheckWorkerEvaluationAndContinueUpdateWorkerRunnable ( serviceWorkerHandle , handle ) ;
2014-12-19 02:48:31 -08:00
AutoJSAPI jsapi ;
jsapi . Init ( ) ;
bool ok = r - > Dispatch ( jsapi . cx ( ) ) ;
if ( NS_WARN_IF ( ! ok ) ) {
2015-02-11 13:24:57 -08:00
swm - > mSetOfScopesBeingUpdated . Remove ( mRegistration - > mScope ) ;
2014-12-19 02:48:31 -08:00
Fail ( NS_ERROR_DOM_ABORT_ERR ) ;
2015-03-18 09:52:54 -07:00
return ;
2014-12-19 02:48:31 -08:00
}
2014-08-21 16:31:12 -07:00
}
2014-12-19 02:48:31 -08:00
// Public so our error handling code can use it.
2015-03-05 17:37:49 -08:00
// Callers MUST hold a strong ref before calling this!
2014-12-19 02:48:31 -08:00
void
Fail ( const ErrorEventInit & aError )
{
MOZ_ASSERT ( mCallback ) ;
2015-03-05 17:37:49 -08:00
nsRefPtr < ServiceWorkerUpdateFinishCallback > callback = mCallback . forget ( ) ;
// With cancellation support, we may only be running with one reference
// from another object like a stream loader or something.
// UpdateFailed may do something with that, so hold a ref to ourself since
// FailCommon relies on it.
// FailCommon does check for cancellation, but let's be safe here.
nsRefPtr < ServiceWorkerRegisterJob > kungFuDeathGrip = this ;
callback - > UpdateFailed ( aError ) ;
2014-11-05 14:43:51 -08:00
FailCommon ( NS_ERROR_DOM_JS_EXCEPTION ) ;
2014-12-19 02:48:31 -08:00
}
// Public so our error handling code can continue with a successful worker.
void
ContinueInstall ( )
{
2015-03-05 17:37:49 -08:00
// Even if we are canceled, ensure integrity of mSetOfScopesBeingUpdated
// first.
2014-12-19 02:48:31 -08:00
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-02-08 20:33:39 -08:00
MOZ_ASSERT ( swm - > mSetOfScopesBeingUpdated . Contains ( mRegistration - > mScope ) ) ;
swm - > mSetOfScopesBeingUpdated . Remove ( mRegistration - > mScope ) ;
2015-02-10 14:33:23 -08:00
// This is effectively the end of Step 4.3 of the [[Update]] algorithm.
// The invocation of [[Install]] is not part of the atomic block.
2015-03-05 17:37:49 -08:00
nsRefPtr < ServiceWorkerRegisterJob > kungFuDeathGrip = this ;
if ( mCanceled ) {
return Fail ( NS_ERROR_DOM_ABORT_ERR ) ;
}
2015-02-10 14:33:23 -08:00
// Begin [[Install]] atomic step 4.
2014-12-19 02:48:31 -08:00
if ( mRegistration - > mInstallingWorker ) {
// FIXME(nsm): Terminate and stuff
mRegistration - > mInstallingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
}
swm - > InvalidateServiceWorkerRegistrationWorker ( mRegistration ,
WhichServiceWorker : : INSTALLING_WORKER ) ;
2015-03-18 09:46:38 -07:00
2015-03-18 14:02:51 -07:00
mRegistration - > mInstallingWorker = mUpdateAndInstallInfo . forget ( ) ;
2014-12-19 02:48:31 -08:00
mRegistration - > mInstallingWorker - > UpdateState ( ServiceWorkerState : : Installing ) ;
Succeed ( ) ;
2015-03-05 17:37:49 -08:00
// The job should NOT call fail from this point on.
2014-12-19 02:48:31 -08:00
2015-02-10 14:33:23 -08:00
// Step 4.6 "Queue a task..." for updatefound.
2014-12-19 05:01:53 -08:00
nsCOMPtr < nsIRunnable > upr =
2015-04-08 13:13:32 -07:00
NS_NewRunnableMethodWithArg < ServiceWorkerRegistrationInfo * > (
swm ,
& ServiceWorkerManager : : FireUpdateFoundOnServiceWorkerRegistrations ,
mRegistration ) ;
2014-12-19 02:48:31 -08:00
NS_DispatchToMainThread ( upr ) ;
nsRefPtr < ServiceWorker > serviceWorker ;
2015-03-19 17:25:28 -07:00
nsresult rv = swm - > CreateServiceWorker ( mRegistration - > mPrincipal ,
mRegistration - > mInstallingWorker ,
getter_AddRefs ( serviceWorker ) ) ;
2014-12-19 02:48:31 -08:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2015-02-10 14:33:23 -08:00
ContinueAfterInstallEvent ( false /* aSuccess */ , false /* aActivateImmediately */ ) ;
2014-12-19 02:48:31 -08:00
return ;
}
2015-02-10 14:33:23 -08:00
nsMainThreadPtrHandle < ContinueLifecycleTask > handle (
new nsMainThreadPtrHolder < ContinueLifecycleTask > ( new ContinueInstallTask ( this ) ) ) ;
2015-04-01 16:46:49 -07:00
nsMainThreadPtrHandle < ServiceWorker > serviceWorkerHandle (
new nsMainThreadPtrHolder < ServiceWorker > ( serviceWorker ) ) ;
2014-12-19 05:01:53 -08:00
nsRefPtr < LifecycleEventWorkerRunnable > r =
2015-04-01 16:46:49 -07:00
new LifecycleEventWorkerRunnable ( serviceWorkerHandle , NS_LITERAL_STRING ( " install " ) , handle ) ;
2014-12-19 02:48:31 -08:00
AutoJSAPI jsapi ;
jsapi . Init ( ) ;
2015-02-10 14:33:23 -08:00
// This triggers Step 4.7 "Queue a task to run the following substeps..."
// which sends the install event to the worker.
2014-12-19 02:48:31 -08:00
r - > Dispatch ( jsapi . cx ( ) ) ;
}
2014-12-19 02:00:29 -08:00
private :
void
Update ( )
{
2015-03-05 17:37:49 -08:00
// Since Update() is called synchronously from Start(), we can assert this.
MOZ_ASSERT ( ! mCanceled ) ;
2014-12-19 02:00:29 -08:00
MOZ_ASSERT ( mRegistration ) ;
nsCOMPtr < nsIRunnable > r =
NS_NewRunnableMethod ( this , & ServiceWorkerRegisterJob : : ContinueUpdate ) ;
NS_DispatchToMainThread ( r ) ;
2013-11-19 15:15:02 -08:00
}
2014-12-19 02:00:29 -08:00
// Aspects of (actually the whole algorithm) of [[Update]] after
// "Run the following steps in parallel."
void
ContinueUpdate ( )
2014-08-20 08:40:00 -07:00
{
2014-12-19 02:00:29 -08:00
AssertIsOnMainThread ( ) ;
2015-03-05 17:37:49 -08:00
nsRefPtr < ServiceWorkerRegisterJob > kungFuDeathGrip = this ;
if ( mCanceled ) {
return Fail ( NS_ERROR_DOM_ABORT_ERR ) ;
}
2014-12-19 02:00:29 -08:00
if ( mRegistration - > mInstallingWorker ) {
// FIXME(nsm): "Terminate installing worker".
2014-12-19 03:25:56 -08:00
mRegistration - > mInstallingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2014-12-19 02:00:29 -08:00
mRegistration - > mInstallingWorker = nullptr ;
2014-08-20 08:40:00 -07:00
}
2015-03-18 09:52:54 -07:00
nsRefPtr < ServiceWorkerInfo > workerInfo = mRegistration - > Newest ( ) ;
nsAutoString cacheName ;
2014-08-20 08:40:00 -07:00
2015-03-18 09:52:54 -07:00
// 9.2.20 If newestWorker is not null, and newestWorker's script url is
// equal to registration's registering script url and response is a
// byte-for-byte match with the script resource of newestWorker...
if ( workerInfo & & workerInfo - > ScriptSpec ( ) . Equals ( mRegistration - > mScriptSpec ) ) {
cacheName = workerInfo - > CacheName ( ) ;
2014-08-20 08:40:00 -07:00
}
2015-03-18 09:52:54 -07:00
nsresult rv =
serviceWorkerScriptCache : : Compare ( mRegistration - > mPrincipal , cacheName ,
NS_ConvertUTF8toUTF16 ( mRegistration - > mScriptSpec ) ,
this ) ;
2014-12-19 02:00:29 -08:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return Fail ( rv ) ;
}
2014-08-20 08:40:00 -07:00
}
2014-12-19 02:00:29 -08:00
void
Succeed ( )
{
MOZ_ASSERT ( mCallback ) ;
mCallback - > UpdateSucceeded ( mRegistration ) ;
mCallback = nullptr ;
2014-08-20 08:40:00 -07:00
}
2014-11-05 14:43:51 -08:00
void
FailCommon ( nsresult aRv )
{
2015-03-18 14:02:51 -07:00
mUpdateAndInstallInfo = nullptr ;
2015-03-18 09:46:38 -07:00
if ( mRegistration - > mInstallingWorker ) {
nsresult rv = serviceWorkerScriptCache : : PurgeCache ( mRegistration - > mPrincipal ,
mRegistration - > mInstallingWorker - > CacheName ( ) ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to purge the installing worker cache. " ) ;
}
}
2015-02-10 14:33:23 -08:00
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
swm - > MaybeRemoveRegistration ( mRegistration ) ;
2014-11-05 14:43:51 -08:00
// Ensures that the job can't do anything useful from this point on.
mRegistration = nullptr ;
2015-04-24 11:42:13 -07:00
unused < < NS_WARN_IF ( NS_FAILED ( aRv ) ) ;
2014-11-05 14:43:51 -08:00
Done ( aRv ) ;
}
2014-12-19 02:00:29 -08:00
// This MUST only be called when the job is still performing actions related
// to registration or update. After the spec resolves the update promise, use
// Done() with the failure code instead.
2015-03-05 17:37:49 -08:00
// Callers MUST hold a strong ref before calling this!
2014-12-19 02:00:29 -08:00
void
2014-11-05 14:43:51 -08:00
Fail ( nsresult aRv )
2014-12-19 02:00:29 -08:00
{
MOZ_ASSERT ( mCallback ) ;
2015-03-05 17:37:49 -08:00
nsRefPtr < ServiceWorkerUpdateFinishCallback > callback = mCallback . forget ( ) ;
// With cancellation support, we may only be running with one reference
// from another object like a stream loader or something.
// UpdateFailed may do something with that, so hold a ref to ourself since
// FailCommon relies on it.
// FailCommon does check for cancellation, but let's be safe here.
nsRefPtr < ServiceWorkerRegisterJob > kungFuDeathGrip = this ;
callback - > UpdateFailed ( aRv ) ;
2014-11-05 14:43:51 -08:00
FailCommon ( aRv ) ;
}
void
2015-02-10 14:33:23 -08:00
ContinueAfterInstallEvent ( bool aInstallEventSuccess , bool aActivateImmediately )
2014-11-05 14:43:51 -08:00
{
2015-03-05 17:37:49 -08:00
if ( mCanceled ) {
return Done ( NS_ERROR_DOM_ABORT_ERR ) ;
}
if ( ! mRegistration - > mInstallingWorker ) {
NS_WARNING ( " mInstallingWorker was null. " ) ;
2014-12-19 02:00:29 -08:00
return Done ( NS_ERROR_DOM_ABORT_ERR ) ;
2014-08-20 08:40:00 -07:00
}
2014-12-19 02:00:29 -08:00
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-08-20 08:40:00 -07:00
2014-12-19 02:00:29 -08:00
// "If installFailed is true"
2015-04-24 11:42:13 -07:00
if ( NS_WARN_IF ( ! aInstallEventSuccess ) ) {
2014-12-19 02:00:29 -08:00
mRegistration - > mInstallingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
mRegistration - > mInstallingWorker = nullptr ;
swm - > InvalidateServiceWorkerRegistrationWorker ( mRegistration ,
WhichServiceWorker : : INSTALLING_WORKER ) ;
2015-02-10 14:33:23 -08:00
swm - > MaybeRemoveRegistration ( mRegistration ) ;
2014-12-19 02:00:29 -08:00
return Done ( NS_ERROR_DOM_ABORT_ERR ) ;
2014-08-20 08:40:00 -07:00
}
2014-12-19 02:00:29 -08:00
// "If registration's waiting worker is not null"
if ( mRegistration - > mWaitingWorker ) {
// FIXME(nsm): Terminate
mRegistration - > mWaitingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2015-03-18 09:46:38 -07:00
nsresult rv = serviceWorkerScriptCache : : PurgeCache ( mRegistration - > mPrincipal ,
mRegistration - > mWaitingWorker - > CacheName ( ) ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to purge the old waiting cache. " ) ;
}
2014-12-19 02:00:29 -08:00
}
2014-12-19 04:45:07 -08:00
2014-12-19 02:00:29 -08:00
mRegistration - > mWaitingWorker = mRegistration - > mInstallingWorker . forget ( ) ;
2015-02-19 08:40:21 -08:00
mRegistration - > mWaitingWorker - > UpdateState ( ServiceWorkerState : : Installed ) ;
2014-12-19 02:00:29 -08:00
swm - > InvalidateServiceWorkerRegistrationWorker ( mRegistration ,
WhichServiceWorker : : INSTALLING_WORKER | WhichServiceWorker : : WAITING_WORKER ) ;
2014-08-20 08:40:00 -07:00
2014-12-19 02:00:29 -08:00
// FIXME(nsm): Bug 982711 Deal with activateImmediately.
NS_WARN_IF_FALSE ( ! aActivateImmediately , " Immediate activation using replace() is not supported yet " ) ;
2015-02-17 00:35:27 -08:00
Done ( NS_OK ) ;
2015-02-10 14:33:23 -08:00
// Activate() is invoked out of band of atomic.
mRegistration - > TryToActivate ( ) ;
2014-08-20 08:40:00 -07:00
}
} ;
2015-03-18 09:46:38 -07:00
NS_IMPL_ISUPPORTS_INHERITED0 ( ServiceWorkerRegisterJob , ServiceWorkerJob ) ;
2014-12-19 02:48:31 -08:00
2015-03-05 17:37:49 -08:00
void
ServiceWorkerJobQueue : : CancelJobs ( )
{
if ( mJobs . IsEmpty ( ) ) {
return ;
}
// We have to treat the first job specially. It is the running job and needs
// to be notified correctly.
nsRefPtr < ServiceWorkerJob > runningJob = mJobs [ 0 ] ;
// We can just let an Unregister job run to completion.
if ( runningJob - > IsRegisterJob ( ) ) {
ServiceWorkerRegisterJob * job = static_cast < ServiceWorkerRegisterJob * > ( runningJob . get ( ) ) ;
job - > Cancel ( ) ;
}
// Get rid of everything. Non-main thread objects may still be holding a ref
// to the running register job. Since we called Cancel() on it, the job's
// main thread functions will just exit.
mJobs . Clear ( ) ;
}
2014-12-19 02:48:31 -08:00
NS_IMETHODIMP
ContinueUpdateRunnable : : Run ( )
{
AssertIsOnMainThread ( ) ;
nsRefPtr < ServiceWorkerJob > job = static_cast < ServiceWorkerJob * > ( mJob . get ( ) ) ;
nsRefPtr < ServiceWorkerRegisterJob > upjob = static_cast < ServiceWorkerRegisterJob * > ( job . get ( ) ) ;
upjob - > ContinueInstall ( ) ;
return NS_OK ;
}
2014-12-19 02:00:29 -08:00
2014-12-19 05:01:53 -08:00
void
ContinueInstallTask : : ContinueAfterWorkerEvent ( bool aSuccess , bool aActivateImmediately )
{
2015-02-10 14:33:23 -08:00
// This does not start the job immediately if there are other jobs in the
// queue, which captures the "atomic" behaviour we want.
2014-12-19 05:01:53 -08:00
mJob - > ContinueAfterInstallEvent ( aSuccess , aActivateImmediately ) ;
}
2014-08-20 08:40:00 -07:00
// If we return an error code here, the ServiceWorkerContainer will
// automatically reject the Promise.
NS_IMETHODIMP
2014-12-19 02:00:29 -08:00
ServiceWorkerManager : : Register ( nsIDOMWindow * aWindow ,
2015-03-09 18:57:06 -07:00
nsIURI * aScopeURI ,
nsIURI * aScriptURI ,
2014-12-19 02:00:29 -08:00
nsISupports * * aPromise )
2014-08-20 08:40:00 -07:00
{
AssertIsOnMainThread ( ) ;
// XXXnsm Don't allow chrome callers for now, we don't support chrome
// ServiceWorkers.
MOZ_ASSERT ( ! nsContentUtils : : IsCallerChrome ( ) ) ;
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
2014-12-19 02:00:29 -08:00
2015-03-24 11:15:00 -07:00
nsCOMPtr < nsPIDOMWindow > outerWindow = window - > GetOuterWindow ( ) ;
bool serviceWorkersTestingEnabled =
outerWindow - > GetServiceWorkersTestingEnabled ( ) ;
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsIDocument > doc = window - > GetExtantDoc ( ) ;
if ( ! doc ) {
2014-08-20 08:40:00 -07:00
return NS_ERROR_FAILURE ;
}
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsIURI > documentURI = doc - > GetBaseURI ( ) ;
2014-08-20 08:40:00 -07:00
2014-12-19 02:00:29 -08:00
bool authenticatedOrigin = false ;
2015-03-24 11:15:00 -07:00
if ( Preferences : : GetBool ( " dom.serviceWorkers.testing.enabled " ) | |
serviceWorkersTestingEnabled ) {
2014-12-19 02:00:29 -08:00
authenticatedOrigin = true ;
}
2014-08-20 08:40:00 -07:00
2014-12-19 02:00:29 -08:00
nsresult rv ;
if ( ! authenticatedOrigin ) {
nsAutoCString scheme ;
rv = documentURI - > GetScheme ( scheme ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2014-08-26 01:16:03 -07:00
2014-12-19 02:00:29 -08:00
if ( scheme . EqualsLiteral ( " https " ) | |
scheme . EqualsLiteral ( " file " ) | |
scheme . EqualsLiteral ( " app " ) ) {
authenticatedOrigin = true ;
}
}
2014-08-26 01:16:03 -07:00
2014-12-19 02:00:29 -08:00
if ( ! authenticatedOrigin ) {
nsAutoCString host ;
rv = documentURI - > GetHost ( host ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2014-08-26 01:16:03 -07:00
2014-12-19 02:00:29 -08:00
if ( host . Equals ( " 127.0.0.1 " ) | |
host . Equals ( " localhost " ) | |
host . Equals ( " ::1 " ) ) {
authenticatedOrigin = true ;
2014-08-26 01:16:03 -07:00
}
2014-12-19 02:00:29 -08:00
}
2014-08-26 01:16:03 -07:00
2014-12-19 02:00:29 -08:00
if ( ! authenticatedOrigin ) {
bool isFile ;
rv = documentURI - > SchemeIs ( " file " , & isFile ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
2014-08-26 01:16:03 -07:00
}
2014-12-19 02:00:29 -08:00
if ( ! isFile ) {
bool isHttps ;
rv = documentURI - > SchemeIs ( " https " , & isHttps ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) | | ! isHttps ) {
NS_WARNING ( " ServiceWorker registration from insecure websites is not allowed. " ) ;
return NS_ERROR_DOM_SECURITY_ERR ;
}
2014-08-26 01:16:03 -07:00
}
2014-12-19 02:00:29 -08:00
}
2014-08-26 01:16:03 -07:00
2014-12-19 02:00:29 -08:00
// Data URLs are not allowed.
nsCOMPtr < nsIPrincipal > documentPrincipal = doc - > NodePrincipal ( ) ;
2014-08-26 01:16:03 -07:00
2015-03-09 18:57:06 -07:00
rv = documentPrincipal - > CheckMayLoad ( aScriptURI , true /* report */ ,
2014-12-19 02:00:29 -08:00
false /* allowIfInheritsPrincipal */ ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
2014-08-26 01:16:03 -07:00
2015-03-09 18:57:06 -07:00
rv = documentPrincipal - > CheckMayLoad ( aScopeURI , true /* report */ ,
2014-12-19 02:00:29 -08:00
false /* allowIfInheritsPrinciple */ ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
nsCString cleanedScope ;
2015-03-09 18:57:06 -07:00
rv = aScopeURI - > GetSpecIgnoringRef ( cleanedScope ) ;
2014-12-19 02:00:29 -08:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2014-08-26 01:16:03 -07:00
return NS_ERROR_FAILURE ;
}
2014-12-19 02:00:29 -08:00
nsAutoCString spec ;
2015-03-09 18:57:06 -07:00
rv = aScriptURI - > GetSpec ( spec ) ;
2014-12-19 02:00:29 -08:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2014-08-26 01:16:03 -07:00
nsCOMPtr < nsIGlobalObject > sgo = do_QueryInterface ( window ) ;
ErrorResult result ;
nsRefPtr < Promise > promise = Promise : : Create ( sgo , result ) ;
if ( result . Failed ( ) ) {
2015-04-27 06:18:51 -07:00
return result . StealNSResult ( ) ;
2014-08-26 01:16:03 -07:00
}
2015-02-08 20:33:39 -08:00
ServiceWorkerJobQueue * queue = GetOrCreateJobQueue ( cleanedScope ) ;
2014-12-19 02:00:29 -08:00
MOZ_ASSERT ( queue ) ;
nsRefPtr < ServiceWorkerResolveWindowPromiseOnUpdateCallback > cb =
new ServiceWorkerResolveWindowPromiseOnUpdateCallback ( window , promise ) ;
nsRefPtr < ServiceWorkerRegisterJob > job =
2015-02-11 03:53:00 -08:00
new ServiceWorkerRegisterJob ( queue , cleanedScope , spec , cb , documentPrincipal ) ;
2014-12-19 02:00:29 -08:00
queue - > Append ( job ) ;
2014-08-26 01:16:03 -07:00
promise . forget ( aPromise ) ;
2014-12-19 02:00:29 -08:00
return NS_OK ;
2014-08-26 01:16:03 -07:00
}
2015-02-11 03:53:00 -08:00
void
ServiceWorkerManager : : AppendPendingOperation ( ServiceWorkerJobQueue * aQueue ,
ServiceWorkerJob * aJob )
{
MOZ_ASSERT ( ! mActor ) ;
MOZ_ASSERT ( aQueue ) ;
MOZ_ASSERT ( aJob ) ;
PendingOperation * opt = mPendingOperations . AppendElement ( ) ;
opt - > mQueue = aQueue ;
opt - > mJob = aJob ;
}
void
ServiceWorkerManager : : AppendPendingOperation ( nsIRunnable * aRunnable )
{
MOZ_ASSERT ( ! mActor ) ;
MOZ_ASSERT ( aRunnable ) ;
PendingOperation * opt = mPendingOperations . AppendElement ( ) ;
opt - > mRunnable = aRunnable ;
}
2014-12-19 02:00:29 -08:00
/*
2014-12-19 05:01:53 -08:00
* Used to handle ExtendableEvent : : waitUntil ( ) and proceed with
* installation / activation .
2014-12-19 02:00:29 -08:00
*/
2015-03-21 09:28:04 -07:00
class LifecycleEventPromiseHandler final : public PromiseNativeHandler
2014-08-26 01:16:03 -07:00
{
2014-12-19 05:01:53 -08:00
nsMainThreadPtrHandle < ContinueLifecycleTask > mTask ;
2015-05-01 08:14:42 -07:00
nsMainThreadPtrHandle < ServiceWorker > mServiceWorker ;
2014-12-19 02:00:29 -08:00
bool mActivateImmediately ;
2014-08-26 01:16:03 -07:00
2014-12-19 02:00:29 -08:00
virtual
2014-12-19 05:01:53 -08:00
~ LifecycleEventPromiseHandler ( )
2014-12-19 02:00:29 -08:00
{ }
2014-08-26 01:16:03 -07:00
2014-12-19 02:00:29 -08:00
public :
2014-12-19 05:01:53 -08:00
LifecycleEventPromiseHandler ( const nsMainThreadPtrHandle < ContinueLifecycleTask > & aTask ,
2015-05-01 08:14:42 -07:00
const nsMainThreadPtrHandle < ServiceWorker > & aServiceWorker ,
2014-12-19 05:01:53 -08:00
bool aActivateImmediately )
: mTask ( aTask )
2015-05-01 08:14:42 -07:00
, mServiceWorker ( aServiceWorker )
2014-12-19 02:00:29 -08:00
, mActivateImmediately ( aActivateImmediately )
{
MOZ_ASSERT ( ! NS_IsMainThread ( ) ) ;
}
2014-08-26 01:16:03 -07:00
2014-12-19 02:00:29 -08:00
void
2015-03-21 09:28:04 -07:00
ResolvedCallback ( JSContext * aCx , JS : : Handle < JS : : Value > aValue ) override
2014-12-19 02:00:29 -08:00
{
WorkerPrivate * workerPrivate = GetCurrentThreadWorkerPrivate ( ) ;
MOZ_ASSERT ( workerPrivate ) ;
workerPrivate - > AssertIsOnWorkerThread ( ) ;
2014-08-26 01:16:03 -07:00
2014-12-19 05:01:53 -08:00
nsRefPtr < ContinueLifecycleRunnable > r =
new ContinueLifecycleRunnable ( mTask , true /* success */ , mActivateImmediately ) ;
2014-12-19 02:00:29 -08:00
NS_DispatchToMainThread ( r ) ;
2014-08-26 01:16:03 -07:00
}
2014-12-19 02:00:29 -08:00
void
2015-03-21 09:28:04 -07:00
RejectedCallback ( JSContext * aCx , JS : : Handle < JS : : Value > aValue ) override
2014-12-19 02:00:29 -08:00
{
2014-12-19 05:01:53 -08:00
WorkerPrivate * workerPrivate = GetCurrentThreadWorkerPrivate ( ) ;
MOZ_ASSERT ( workerPrivate ) ;
workerPrivate - > AssertIsOnWorkerThread ( ) ;
nsRefPtr < ContinueLifecycleRunnable > r =
new ContinueLifecycleRunnable ( mTask , false /* success */ , mActivateImmediately ) ;
2014-12-19 02:00:29 -08:00
NS_DispatchToMainThread ( r ) ;
2015-04-08 16:04:12 -07:00
JS : : Rooted < JSObject * > obj ( aCx , workerPrivate - > GlobalScope ( ) - > GetWrapper ( ) ) ;
JS : : ExposeValueToActiveJS ( aValue ) ;
js : : ErrorReport report ( aCx ) ;
if ( NS_WARN_IF ( ! report . init ( aCx , aValue ) ) ) {
JS_ClearPendingException ( aCx ) ;
return ;
}
nsRefPtr < xpc : : ErrorReport > xpcReport = new xpc : : ErrorReport ( ) ;
xpcReport - > Init ( report . report ( ) , report . message ( ) , /* aIsChrome = */ false , /* aWindowID = */ 0 ) ;
nsRefPtr < AsyncErrorReporter > aer =
new AsyncErrorReporter ( CycleCollectedJSRuntime : : Get ( ) - > Runtime ( ) , xpcReport ) ;
NS_DispatchToMainThread ( aer ) ;
2014-12-19 02:00:29 -08:00
}
} ;
2014-08-26 01:16:03 -07:00
bool
2014-12-19 05:01:53 -08:00
LifecycleEventWorkerRunnable : : DispatchLifecycleEvent ( JSContext * aCx , WorkerPrivate * aWorkerPrivate )
2014-08-26 01:16:03 -07:00
{
2014-12-19 02:00:29 -08:00
aWorkerPrivate - > AssertIsOnWorkerThread ( ) ;
MOZ_ASSERT ( aWorkerPrivate - > IsServiceWorker ( ) ) ;
2014-12-19 05:01:53 -08:00
2014-12-19 05:01:53 -08:00
nsRefPtr < ExtendableEvent > event ;
2015-01-23 19:49:39 -08:00
nsRefPtr < EventTarget > target = aWorkerPrivate - > GlobalScope ( ) ;
2014-12-19 05:01:53 -08:00
2015-04-20 18:47:13 -07:00
if ( mEventName . EqualsASCII ( " install " ) | | mEventName . EqualsASCII ( " activate " ) ) {
2014-12-19 05:01:53 -08:00
// FIXME(nsm): Bug 982787 pass previous active worker.
ExtendableEventInit init ;
init . mBubbles = false ;
init . mCancelable = true ;
event = ExtendableEvent : : Constructor ( target , mEventName , init ) ;
} else {
MOZ_CRASH ( " Unexpected lifecycle event " ) ;
}
2014-12-19 02:00:29 -08:00
event - > SetTrusted ( true ) ;
nsRefPtr < Promise > waitUntilPromise ;
ErrorResult result ;
result = target - > DispatchDOMEvent ( nullptr , event , nullptr , nullptr ) ;
nsCOMPtr < nsIGlobalObject > sgo = aWorkerPrivate - > GlobalScope ( ) ;
2014-12-19 04:45:07 -08:00
WidgetEvent * internalEvent = event - > GetInternalNSEvent ( ) ;
if ( ! result . Failed ( ) & & ! internalEvent - > mFlags . mExceptionHasBeenRisen ) {
2014-12-19 02:00:29 -08:00
waitUntilPromise = event - > GetPromise ( ) ;
if ( ! waitUntilPromise ) {
ErrorResult result ;
waitUntilPromise =
Promise : : Resolve ( sgo , aCx , JS : : UndefinedHandleValue , result ) ;
2014-12-19 04:45:07 -08:00
if ( NS_WARN_IF ( result . Failed ( ) ) ) {
return true ;
}
2014-12-19 02:00:29 -08:00
}
} else {
// Continue with a canceled install.
2014-12-19 04:45:07 -08:00
// Although the spec has different routines to deal with popping stuff
// off it's internal queues, we can reuse the ContinueAfterInstallEvent()
// logic.
2015-04-08 16:04:12 -07:00
nsRefPtr < ContinueLifecycleRunnable > r =
new ContinueLifecycleRunnable ( mTask , false /* success */ , false /* activate immediately */ ) ;
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( NS_DispatchToMainThread ( r ) ) ) ;
return true ;
2014-12-19 02:00:29 -08:00
}
2014-08-26 01:16:03 -07:00
2014-12-19 05:01:53 -08:00
nsRefPtr < LifecycleEventPromiseHandler > handler =
2015-05-01 08:14:42 -07:00
new LifecycleEventPromiseHandler ( mTask , mServiceWorker , false /* activateImmediately */ ) ;
2014-12-19 05:01:53 -08:00
waitUntilPromise - > AppendNativeHandler ( handler ) ;
return true ;
}
2015-01-23 19:49:39 -08:00
2014-06-11 09:12:56 -07:00
void
2014-12-19 02:00:29 -08:00
ServiceWorkerRegistrationInfo : : TryToActivate ( )
2014-06-11 09:12:56 -07:00
{
2014-12-19 02:00:29 -08:00
if ( ! IsControllingDocuments ( ) ) {
Activate ( ) ;
2014-06-11 09:12:56 -07:00
}
}
2015-02-10 14:33:23 -08:00
void
2015-02-10 14:33:23 -08:00
ContinueActivateTask : : ContinueAfterWorkerEvent ( bool aSuccess , bool aActivateImmediately /* unused */ )
2015-02-10 14:33:23 -08:00
{
2015-02-10 14:33:23 -08:00
mRegistration - > FinishActivate ( aSuccess ) ;
}
2015-02-17 00:35:27 -08:00
2015-02-10 14:33:23 -08:00
void
ServiceWorkerRegistrationInfo : : Activate ( )
{
2014-12-19 02:00:29 -08:00
nsRefPtr < ServiceWorkerInfo > activatingWorker = mWaitingWorker ;
nsRefPtr < ServiceWorkerInfo > exitingWorker = mActiveWorker ;
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
swm - > InvalidateServiceWorkerRegistrationWorker ( this , WhichServiceWorker : : WAITING_WORKER | WhichServiceWorker : : ACTIVE_WORKER ) ;
if ( ! activatingWorker ) {
2014-06-11 09:12:56 -07:00
return ;
}
2014-12-19 02:00:29 -08:00
if ( exitingWorker ) {
// FIXME(nsm): Wait for worker.
// Terminate worker
exitingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2015-03-18 14:05:00 -07:00
nsresult rv = serviceWorkerScriptCache : : PurgeCache ( mPrincipal ,
exitingWorker - > CacheName ( ) ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to purge the activating cache. " ) ;
}
2014-06-11 09:12:56 -07:00
}
2014-12-19 02:00:29 -08:00
mActiveWorker = activatingWorker . forget ( ) ;
mWaitingWorker = nullptr ;
mActiveWorker - > UpdateState ( ServiceWorkerState : : Activating ) ;
2014-06-11 09:12:56 -07:00
2015-02-10 14:33:23 -08:00
// FIXME(nsm): Unlink appcache if there is one.
2014-12-19 02:00:29 -08:00
swm - > CheckPendingReadyPromises ( ) ;
2014-06-11 09:12:56 -07:00
2014-12-19 02:00:29 -08:00
// "Queue a task to fire a simple event named controllerchange..."
nsCOMPtr < nsIRunnable > controllerChangeRunnable =
2015-02-10 14:33:23 -08:00
NS_NewRunnableMethodWithArg < ServiceWorkerRegistrationInfo * > ( swm ,
& ServiceWorkerManager : : FireControllerChange ,
this ) ;
2014-12-19 02:00:29 -08:00
NS_DispatchToMainThread ( controllerChangeRunnable ) ;
2014-07-02 17:48:35 -07:00
2014-12-19 02:00:29 -08:00
MOZ_ASSERT ( mActiveWorker ) ;
nsRefPtr < ServiceWorker > serviceWorker ;
nsresult rv =
2015-02-17 04:36:09 -08:00
swm - > CreateServiceWorker ( mPrincipal ,
2015-02-19 08:40:21 -08:00
mActiveWorker ,
2014-12-19 02:00:29 -08:00
getter_AddRefs ( serviceWorker ) ) ;
2014-07-02 17:48:35 -07:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2015-02-10 14:33:23 -08:00
nsCOMPtr < nsIRunnable > r =
NS_NewRunnableMethodWithArg < bool > ( this ,
& ServiceWorkerRegistrationInfo : : FinishActivate ,
false /* success */ ) ;
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( NS_DispatchToMainThread ( r ) ) ) ;
2014-12-19 03:25:56 -08:00
return ;
2014-07-02 17:48:35 -07:00
}
2014-12-19 05:01:53 -08:00
nsMainThreadPtrHandle < ContinueLifecycleTask > handle (
new nsMainThreadPtrHolder < ContinueLifecycleTask > ( new ContinueActivateTask ( this ) ) ) ;
2014-07-02 17:48:35 -07:00
2015-04-01 16:46:49 -07:00
nsMainThreadPtrHandle < ServiceWorker > serviceWorkerHandle (
new nsMainThreadPtrHolder < ServiceWorker > ( serviceWorker ) ) ;
2014-12-19 05:01:53 -08:00
nsRefPtr < LifecycleEventWorkerRunnable > r =
2015-04-01 16:46:49 -07:00
new LifecycleEventWorkerRunnable ( serviceWorkerHandle , NS_LITERAL_STRING ( " activate " ) , handle ) ;
2014-07-02 17:48:35 -07:00
2014-12-19 02:00:29 -08:00
AutoJSAPI jsapi ;
jsapi . Init ( ) ;
r - > Dispatch ( jsapi . cx ( ) ) ;
2014-07-02 17:48:35 -07:00
}
2014-12-19 02:00:29 -08:00
/*
* Implements the async aspects of the getRegistrations algorithm .
*/
class GetRegistrationsRunnable : public nsRunnable
2014-07-02 17:48:50 -07:00
{
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsPIDOMWindow > mWindow ;
nsRefPtr < Promise > mPromise ;
2014-07-02 17:48:50 -07:00
public :
2014-12-19 02:00:29 -08:00
GetRegistrationsRunnable ( nsPIDOMWindow * aWindow , Promise * aPromise )
: mWindow ( aWindow ) , mPromise ( aPromise )
{ }
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
NS_IMETHODIMP
Run ( )
2014-07-02 17:48:50 -07:00
{
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-12-19 02:00:29 -08:00
nsIDocument * doc = mWindow - > GetExtantDoc ( ) ;
if ( ! doc ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsIURI > docURI = doc - > GetDocumentURI ( ) ;
if ( ! docURI ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsIPrincipal > principal = doc - > NodePrincipal ( ) ;
if ( ! principal ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-11 13:07:59 -07:00
2015-04-03 15:18:55 -07:00
nsTArray < nsRefPtr < ServiceWorkerRegistrationMainThread > > array ;
2014-12-19 02:00:29 -08:00
2015-02-16 14:22:17 -08:00
bool isNullPrincipal = true ;
nsresult rv = principal - > GetIsNullPrincipal ( & isNullPrincipal ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
if ( nsContentUtils : : IsSystemPrincipal ( principal ) | | isNullPrincipal ) {
mPromise - > MaybeResolve ( array ) ;
return NS_OK ;
}
2015-05-19 12:20:15 -07:00
for ( uint32_t i = 0 ; i < swm - > mOrderedScopes . Length ( ) ; + + i ) {
NS_ConvertUTF8toUTF16 scope ( swm - > mOrderedScopes [ i ] ) ;
2015-02-16 14:22:17 -08:00
nsCOMPtr < nsIURI > scopeURI ;
nsresult rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , scope , nullptr , nullptr ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
mPromise - > MaybeReject ( rv ) ;
break ;
}
rv = principal - > CheckMayLoad ( scopeURI , true /* report */ ,
false /* allowIfInheritsPrincipal */ ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
continue ;
}
2015-04-03 15:18:55 -07:00
nsRefPtr < ServiceWorkerRegistrationMainThread > swr =
new ServiceWorkerRegistrationMainThread ( mWindow , scope ) ;
2014-12-19 02:00:29 -08:00
array . AppendElement ( swr ) ;
}
mPromise - > MaybeResolve ( array ) ;
2014-07-11 13:07:59 -07:00
return NS_OK ;
}
} ;
2014-12-19 02:00:29 -08:00
// If we return an error code here, the ServiceWorkerContainer will
// automatically reject the Promise.
NS_IMETHODIMP
ServiceWorkerManager : : GetRegistrations ( nsIDOMWindow * aWindow ,
nsISupports * * aPromise )
2014-07-02 17:48:50 -07:00
{
2014-12-19 02:00:29 -08:00
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWindow ) ;
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
// XXXnsm Don't allow chrome callers for now, we don't support chrome
// ServiceWorkers.
MOZ_ASSERT ( ! nsContentUtils : : IsCallerChrome ( ) ) ;
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
if ( ! window ) {
return NS_ERROR_FAILURE ;
2014-07-02 17:48:50 -07:00
}
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsIGlobalObject > sgo = do_QueryInterface ( window ) ;
ErrorResult result ;
nsRefPtr < Promise > promise = Promise : : Create ( sgo , result ) ;
if ( result . Failed ( ) ) {
2015-04-27 06:18:51 -07:00
return result . StealNSResult ( ) ;
2014-07-02 17:48:50 -07:00
}
2014-12-19 02:00:29 -08:00
2015-03-17 09:29:17 -07:00
nsCOMPtr < nsIRunnable > runnable =
2014-12-19 02:00:29 -08:00
new GetRegistrationsRunnable ( window , promise ) ;
promise . forget ( aPromise ) ;
return NS_DispatchToCurrentThread ( runnable ) ;
}
2014-07-02 17:48:50 -07:00
/*
2014-12-19 02:00:29 -08:00
* Implements the async aspects of the getRegistration algorithm .
2014-07-02 17:48:50 -07:00
*/
2014-12-19 02:00:29 -08:00
class GetRegistrationRunnable : public nsRunnable
2014-07-02 17:48:50 -07:00
{
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsPIDOMWindow > mWindow ;
nsRefPtr < Promise > mPromise ;
nsString mDocumentURL ;
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
public :
GetRegistrationRunnable ( nsPIDOMWindow * aWindow , Promise * aPromise ,
const nsAString & aDocumentURL )
: mWindow ( aWindow ) , mPromise ( aPromise ) , mDocumentURL ( aDocumentURL )
2014-07-02 17:48:50 -07:00
{ }
2014-12-19 02:00:29 -08:00
NS_IMETHODIMP
Run ( )
2014-07-02 17:48:50 -07:00
{
2014-12-19 02:00:29 -08:00
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
nsIDocument * doc = mWindow - > GetExtantDoc ( ) ;
if ( ! doc ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsIURI > docURI = doc - > GetDocumentURI ( ) ;
if ( ! docURI ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsIURI > uri ;
nsresult rv = NS_NewURI ( getter_AddRefs ( uri ) , mDocumentURL , nullptr , docURI ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
mPromise - > MaybeReject ( rv ) ;
return NS_OK ;
}
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsIPrincipal > principal = doc - > NodePrincipal ( ) ;
if ( ! principal ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
rv = principal - > CheckMayLoad ( uri , true /* report */ ,
false /* allowIfInheritsPrinciple */ ) ;
if ( NS_FAILED ( rv ) ) {
mPromise - > MaybeReject ( NS_ERROR_DOM_SECURITY_ERR ) ;
return NS_OK ;
}
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration =
2015-05-19 12:20:15 -07:00
swm - > GetServiceWorkerRegistrationInfo ( uri ) ;
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
if ( ! registration ) {
mPromise - > MaybeResolve ( JS : : UndefinedHandleValue ) ;
return NS_OK ;
}
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
NS_ConvertUTF8toUTF16 scope ( registration - > mScope ) ;
2015-04-03 15:18:55 -07:00
nsRefPtr < ServiceWorkerRegistrationMainThread > swr =
new ServiceWorkerRegistrationMainThread ( mWindow , scope ) ;
2014-12-19 02:00:29 -08:00
mPromise - > MaybeResolve ( swr ) ;
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
return NS_OK ;
2014-07-11 13:07:59 -07:00
}
} ;
2014-12-19 02:00:29 -08:00
// If we return an error code here, the ServiceWorkerContainer will
// automatically reject the Promise.
NS_IMETHODIMP
ServiceWorkerManager : : GetRegistration ( nsIDOMWindow * aWindow ,
const nsAString & aDocumentURL ,
nsISupports * * aPromise )
2014-07-02 17:48:50 -07:00
{
2014-12-19 02:00:29 -08:00
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWindow ) ;
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
// XXXnsm Don't allow chrome callers for now, we don't support chrome
// ServiceWorkers.
MOZ_ASSERT ( ! nsContentUtils : : IsCallerChrome ( ) ) ;
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
if ( ! window ) {
return NS_ERROR_FAILURE ;
2014-07-02 17:48:50 -07:00
}
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsIGlobalObject > sgo = do_QueryInterface ( window ) ;
ErrorResult result ;
nsRefPtr < Promise > promise = Promise : : Create ( sgo , result ) ;
if ( result . Failed ( ) ) {
2015-04-27 06:18:51 -07:00
return result . StealNSResult ( ) ;
2014-07-02 17:48:50 -07:00
}
2015-03-17 09:29:17 -07:00
nsCOMPtr < nsIRunnable > runnable =
2014-12-19 02:00:29 -08:00
new GetRegistrationRunnable ( window , promise , aDocumentURL ) ;
promise . forget ( aPromise ) ;
return NS_DispatchToCurrentThread ( runnable ) ;
}
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
class GetReadyPromiseRunnable : public nsRunnable
{
nsCOMPtr < nsPIDOMWindow > mWindow ;
nsRefPtr < Promise > mPromise ;
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
public :
GetReadyPromiseRunnable ( nsPIDOMWindow * aWindow , Promise * aPromise )
: mWindow ( aWindow ) , mPromise ( aPromise )
{ }
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
NS_IMETHODIMP
Run ( )
{
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
nsIDocument * doc = mWindow - > GetExtantDoc ( ) ;
if ( ! doc ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsIURI > docURI = doc - > GetDocumentURI ( ) ;
if ( ! docURI ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
if ( ! swm - > CheckReadyPromise ( mWindow , docURI , mPromise ) ) {
swm - > StorePendingReadyPromise ( mWindow , docURI , mPromise ) ;
2014-07-02 17:48:50 -07:00
}
2014-12-19 02:00:29 -08:00
return NS_OK ;
}
} ;
2015-04-10 20:19:28 -07:00
# ifndef MOZ_SIMPLEPUSH
class SendPushEventRunnable final : public WorkerRunnable
{
nsString mData ;
nsMainThreadPtrHandle < ServiceWorker > mServiceWorker ;
public :
SendPushEventRunnable (
WorkerPrivate * aWorkerPrivate ,
const nsAString & aData ,
nsMainThreadPtrHandle < ServiceWorker > & aServiceWorker )
: WorkerRunnable ( aWorkerPrivate , WorkerThreadModifyBusyCount )
, mData ( aData )
, mServiceWorker ( aServiceWorker )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWorkerPrivate ) ;
MOZ_ASSERT ( aWorkerPrivate - > IsServiceWorker ( ) ) ;
}
bool
WorkerRun ( JSContext * aCx , WorkerPrivate * aWorkerPrivate ) override
{
MOZ_ASSERT ( aWorkerPrivate ) ;
GlobalObject globalObj ( aCx , aWorkerPrivate - > GlobalScope ( ) - > GetWrapper ( ) ) ;
PushEventInit pei ;
pei . mData . Construct ( mData ) ;
pei . mBubbles = false ;
pei . mCancelable = true ;
ErrorResult result ;
nsRefPtr < PushEvent > event =
PushEvent : : Constructor ( globalObj , NS_LITERAL_STRING ( " push " ) , pei , result ) ;
if ( NS_WARN_IF ( result . Failed ( ) ) ) {
return false ;
}
event - > SetTrusted ( true ) ;
event - > PostInit ( mServiceWorker ) ;
nsRefPtr < EventTarget > target = do_QueryObject ( aWorkerPrivate - > GlobalScope ( ) ) ;
target - > DispatchDOMEvent ( nullptr , event , nullptr , nullptr ) ;
return true ;
}
} ;
class SendPushSubscriptionChangeEventRunnable final : public WorkerRunnable
{
nsMainThreadPtrHandle < ServiceWorker > mServiceWorker ;
public :
SendPushSubscriptionChangeEventRunnable (
WorkerPrivate * aWorkerPrivate ,
nsMainThreadPtrHandle < ServiceWorker > & aServiceWorker )
: WorkerRunnable ( aWorkerPrivate , WorkerThreadModifyBusyCount )
, mServiceWorker ( aServiceWorker )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWorkerPrivate ) ;
MOZ_ASSERT ( aWorkerPrivate - > IsServiceWorker ( ) ) ;
}
bool
WorkerRun ( JSContext * aCx , WorkerPrivate * aWorkerPrivate ) override
{
MOZ_ASSERT ( aWorkerPrivate ) ;
2015-04-24 05:55:00 -07:00
WorkerGlobalScope * globalScope = aWorkerPrivate - > GlobalScope ( ) ;
nsCOMPtr < nsIDOMEvent > event ;
nsresult rv =
NS_NewDOMEvent ( getter_AddRefs ( event ) , globalScope , nullptr , nullptr ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return false ;
}
rv = event - > InitEvent ( NS_LITERAL_STRING ( " pushsubscriptionchange " ) , false , false ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return false ;
}
event - > SetTrusted ( true ) ;
2015-04-10 20:19:28 -07:00
2015-04-24 05:55:00 -07:00
globalScope - > DispatchDOMEvent ( nullptr , event , nullptr , nullptr ) ;
2015-04-10 20:19:28 -07:00
return true ;
}
} ;
# endif /* ! MOZ_SIMPLEPUSH */
NS_IMETHODIMP
2015-05-19 12:20:15 -07:00
ServiceWorkerManager : : SendPushEvent ( const nsACString & aScope , const nsAString & aData )
2015-04-10 20:19:28 -07:00
{
# ifdef MOZ_SIMPLEPUSH
return NS_ERROR_NOT_AVAILABLE ;
# else
2015-05-19 12:20:15 -07:00
nsRefPtr < ServiceWorker > serviceWorker = CreateServiceWorkerForScope ( aScope ) ;
2015-04-10 20:19:28 -07:00
if ( ! serviceWorker ) {
return NS_ERROR_FAILURE ;
}
nsMainThreadPtrHandle < ServiceWorker > serviceWorkerHandle (
new nsMainThreadPtrHolder < ServiceWorker > ( serviceWorker ) ) ;
nsRefPtr < SendPushEventRunnable > r =
2015-05-19 12:20:15 -07:00
new SendPushEventRunnable ( serviceWorker - > GetWorkerPrivate ( ) , aData , serviceWorkerHandle ) ;
2015-04-10 20:19:28 -07:00
AutoJSAPI jsapi ;
jsapi . Init ( ) ;
if ( NS_WARN_IF ( ! r - > Dispatch ( jsapi . cx ( ) ) ) ) {
return NS_ERROR_FAILURE ;
}
return NS_OK ;
# endif
}
NS_IMETHODIMP
2015-05-19 12:20:15 -07:00
ServiceWorkerManager : : SendPushSubscriptionChangeEvent ( const nsACString & aScope )
2015-04-10 20:19:28 -07:00
{
# ifdef MOZ_SIMPLEPUSH
return NS_ERROR_NOT_AVAILABLE ;
# else
2015-05-19 12:20:15 -07:00
nsRefPtr < ServiceWorker > serviceWorker = CreateServiceWorkerForScope ( aScope ) ;
2015-04-10 20:19:28 -07:00
if ( ! serviceWorker ) {
return NS_ERROR_FAILURE ;
}
nsMainThreadPtrHandle < ServiceWorker > serviceWorkerHandle (
new nsMainThreadPtrHolder < ServiceWorker > ( serviceWorker ) ) ;
nsRefPtr < SendPushSubscriptionChangeEventRunnable > r =
2015-05-19 12:20:15 -07:00
new SendPushSubscriptionChangeEventRunnable ( serviceWorker - > GetWorkerPrivate ( ) , serviceWorkerHandle ) ;
2015-04-10 20:19:28 -07:00
AutoJSAPI jsapi ;
jsapi . Init ( ) ;
if ( NS_WARN_IF ( ! r - > Dispatch ( jsapi . cx ( ) ) ) ) {
return NS_ERROR_FAILURE ;
}
return NS_OK ;
# endif
}
2014-12-19 02:00:29 -08:00
NS_IMETHODIMP
ServiceWorkerManager : : GetReadyPromise ( nsIDOMWindow * aWindow ,
nsISupports * * aPromise )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWindow ) ;
// XXXnsm Don't allow chrome callers for now, we don't support chrome
// ServiceWorkers.
MOZ_ASSERT ( ! nsContentUtils : : IsCallerChrome ( ) ) ;
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
if ( ! window ) {
return NS_ERROR_FAILURE ;
}
MOZ_ASSERT ( ! mPendingReadyPromises . Contains ( window ) ) ;
nsCOMPtr < nsIGlobalObject > sgo = do_QueryInterface ( window ) ;
ErrorResult result ;
nsRefPtr < Promise > promise = Promise : : Create ( sgo , result ) ;
if ( result . Failed ( ) ) {
2015-04-27 06:18:51 -07:00
return result . StealNSResult ( ) ;
2014-07-02 17:48:50 -07:00
}
2015-03-17 09:29:17 -07:00
nsCOMPtr < nsIRunnable > runnable =
2014-12-19 02:00:29 -08:00
new GetReadyPromiseRunnable ( window , promise ) ;
promise . forget ( aPromise ) ;
return NS_DispatchToCurrentThread ( runnable ) ;
}
NS_IMETHODIMP
ServiceWorkerManager : : RemoveReadyPromise ( nsIDOMWindow * aWindow )
2014-07-11 13:07:59 -07:00
{
2014-12-19 02:00:29 -08:00
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWindow ) ;
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
if ( ! window ) {
return NS_ERROR_FAILURE ;
2014-07-11 13:07:59 -07:00
}
2014-12-19 02:00:29 -08:00
mPendingReadyPromises . Remove ( aWindow ) ;
return NS_OK ;
}
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
void
ServiceWorkerManager : : StorePendingReadyPromise ( nsPIDOMWindow * aWindow ,
nsIURI * aURI ,
Promise * aPromise )
{
PendingReadyPromise * data ;
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
// We should not have 2 pending promises for the same window.
MOZ_ASSERT ( ! mPendingReadyPromises . Get ( aWindow , & data ) ) ;
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
data = new PendingReadyPromise ( aURI , aPromise ) ;
mPendingReadyPromises . Put ( aWindow , data ) ;
}
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
void
ServiceWorkerManager : : CheckPendingReadyPromises ( )
{
mPendingReadyPromises . Enumerate ( CheckPendingReadyPromisesEnumerator , this ) ;
}
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
PLDHashOperator
ServiceWorkerManager : : CheckPendingReadyPromisesEnumerator (
nsISupports * aSupports ,
nsAutoPtr < PendingReadyPromise > & aData ,
void * aPtr )
{
ServiceWorkerManager * aSwm = static_cast < ServiceWorkerManager * > ( aPtr ) ;
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aSupports ) ;
2014-07-11 13:07:59 -07:00
2014-12-19 02:00:29 -08:00
if ( aSwm - > CheckReadyPromise ( window , aData - > mURI , aData - > mPromise ) ) {
return PL_DHASH_REMOVE ;
}
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
return PL_DHASH_NEXT ;
}
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
bool
ServiceWorkerManager : : CheckReadyPromise ( nsPIDOMWindow * aWindow ,
nsIURI * aURI , Promise * aPromise )
{
nsRefPtr < ServiceWorkerRegistrationInfo > registration =
2015-05-19 12:20:15 -07:00
GetServiceWorkerRegistrationInfo ( aURI ) ;
2014-07-02 17:48:50 -07:00
2014-12-19 02:00:29 -08:00
if ( registration & & registration - > mActiveWorker ) {
NS_ConvertUTF8toUTF16 scope ( registration - > mScope ) ;
2015-04-03 15:18:55 -07:00
nsRefPtr < ServiceWorkerRegistrationMainThread > swr =
new ServiceWorkerRegistrationMainThread ( aWindow , scope ) ;
2014-12-19 02:00:29 -08:00
aPromise - > MaybeResolve ( swr ) ;
return true ;
2014-07-02 17:48:50 -07:00
}
2014-12-19 02:00:29 -08:00
return false ;
2014-07-02 17:48:50 -07:00
}
2015-04-10 20:19:28 -07:00
already_AddRefed < ServiceWorker >
2015-05-19 12:20:15 -07:00
ServiceWorkerManager : : CreateServiceWorkerForScope ( const nsACString & aScope )
2015-04-10 20:19:28 -07:00
{
AssertIsOnMainThread ( ) ;
nsCOMPtr < nsIURI > scopeURI ;
nsresult rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , aScope , nullptr , nullptr ) ;
if ( NS_FAILED ( rv ) ) {
return nullptr ;
}
2015-05-19 12:20:15 -07:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration = GetServiceWorkerRegistrationInfo ( scopeURI ) ;
2015-04-10 20:19:28 -07:00
if ( ! registration ) {
return nullptr ;
}
if ( ! registration - > mActiveWorker ) {
return nullptr ;
}
nsRefPtr < ServiceWorker > sw ;
rv = CreateServiceWorker ( registration - > mPrincipal ,
registration - > mActiveWorker ,
getter_AddRefs ( sw ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return nullptr ;
}
return sw . forget ( ) ;
}
2015-03-21 09:28:04 -07:00
class ServiceWorkerUnregisterJob final : public ServiceWorkerJob
2014-07-02 17:48:50 -07:00
{
2015-01-22 14:10:38 -08:00
nsRefPtr < ServiceWorkerRegistrationInfo > mRegistration ;
const nsCString mScope ;
nsCOMPtr < nsIServiceWorkerUnregisterCallback > mCallback ;
2015-05-19 12:20:15 -07:00
PrincipalInfo mPrincipalInfo ;
2014-12-19 02:00:29 -08:00
2015-01-22 14:10:38 -08:00
~ ServiceWorkerUnregisterJob ( )
{ }
public :
ServiceWorkerUnregisterJob ( ServiceWorkerJobQueue * aQueue ,
const nsACString & aScope ,
2015-02-11 03:53:00 -08:00
nsIServiceWorkerUnregisterCallback * aCallback ,
2015-05-19 12:20:15 -07:00
PrincipalInfo & aPrincipalInfo )
2015-01-22 14:10:38 -08:00
: ServiceWorkerJob ( aQueue )
, mScope ( aScope )
, mCallback ( aCallback )
2015-05-19 12:20:15 -07:00
, mPrincipalInfo ( aPrincipalInfo )
2015-01-22 14:10:38 -08:00
{
AssertIsOnMainThread ( ) ;
2014-07-11 13:07:59 -07:00
}
2015-01-22 14:10:38 -08:00
void
2015-03-21 09:28:04 -07:00
Start ( ) override
2014-07-11 13:07:59 -07:00
{
2015-01-22 14:10:38 -08:00
AssertIsOnMainThread ( ) ;
nsCOMPtr < nsIRunnable > r =
NS_NewRunnableMethod ( this , & ServiceWorkerUnregisterJob : : UnregisterAndDone ) ;
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( NS_DispatchToMainThread ( r ) ) ) ;
}
2014-07-11 13:07:59 -07:00
2015-01-22 14:10:38 -08:00
private :
// You probably want UnregisterAndDone().
nsresult
Unregister ( )
{
AssertIsOnMainThread ( ) ;
2014-07-11 13:07:59 -07:00
2015-01-22 14:10:38 -08:00
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-07-23 14:05:08 -07:00
2015-01-22 14:10:38 -08:00
// "Let registration be the result of running [[Get Registration]]
// algorithm passing scope as the argument."
nsRefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-05-19 12:20:15 -07:00
if ( ! swm - > mServiceWorkerRegistrationInfos . Get ( mScope , getter_AddRefs ( registration ) ) ) {
2015-01-22 14:10:38 -08:00
// "If registration is null, then, resolve promise with false."
2015-04-15 10:11:17 -07:00
return mCallback ? mCallback - > UnregisterSucceeded ( false ) : NS_OK ;
2015-01-22 14:10:38 -08:00
}
2014-07-11 13:07:59 -07:00
2015-01-22 14:10:38 -08:00
MOZ_ASSERT ( registration ) ;
2014-07-11 13:07:59 -07:00
2015-01-22 14:10:38 -08:00
// "Set registration's uninstalling flag."
registration - > mPendingUninstall = true ;
// "Resolve promise with true"
2015-05-19 12:20:15 -07:00
nsresult rv = mCallback ? mCallback - > UnregisterSucceeded ( true ) : NS_OK ;
2015-01-22 14:10:38 -08:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2014-12-19 02:00:29 -08:00
2015-01-22 14:10:38 -08:00
// "If no service worker client is using registration..."
if ( ! registration - > IsControllingDocuments ( ) ) {
// "If registration's uninstalling flag is set.."
if ( ! registration - > mPendingUninstall ) {
return NS_OK ;
2014-12-19 02:00:29 -08:00
}
2014-07-11 13:07:59 -07:00
2015-01-22 14:10:38 -08:00
// "Invoke [[Clear Registration]]..."
registration - > Clear ( ) ;
2015-02-08 20:33:39 -08:00
swm - > RemoveRegistration ( registration ) ;
2015-01-22 14:10:38 -08:00
}
2014-07-11 13:07:59 -07:00
2015-02-11 03:53:00 -08:00
MOZ_ASSERT ( swm - > mActor ) ;
2015-05-19 12:20:15 -07:00
swm - > mActor - > SendUnregisterServiceWorker ( mPrincipalInfo ,
2015-02-11 03:53:00 -08:00
NS_ConvertUTF8toUTF16 ( mScope ) ) ;
2015-03-18 09:46:38 -07:00
2015-01-22 14:10:38 -08:00
return NS_OK ;
}
2014-07-11 13:07:59 -07:00
2015-01-22 14:10:38 -08:00
// The unregister job is done irrespective of success or failure of any sort.
void
UnregisterAndDone ( )
{
2015-04-24 11:42:13 -07:00
nsresult rv = Unregister ( ) ;
unused < < NS_WARN_IF ( NS_FAILED ( rv ) ) ;
Done ( rv ) ;
2015-01-22 14:10:38 -08:00
}
} ;
2014-07-11 13:07:59 -07:00
2015-01-22 14:10:38 -08:00
NS_IMETHODIMP
2015-02-11 03:53:00 -08:00
ServiceWorkerManager : : Unregister ( nsIPrincipal * aPrincipal ,
nsIServiceWorkerUnregisterCallback * aCallback ,
2015-01-22 14:10:38 -08:00
const nsAString & aScope )
{
AssertIsOnMainThread ( ) ;
2015-04-15 10:11:17 -07:00
if ( ! aPrincipal ) {
return NS_ERROR_FAILURE ;
}
2015-01-22 14:10:38 -08:00
// This is not accessible by content, and callers should always ensure scope is
// a correct URI, so this is wrapped in DEBUG
# ifdef DEBUG
nsCOMPtr < nsIURI > scopeURI ;
nsresult rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , aScope , nullptr , nullptr ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
# endif
NS_ConvertUTF16toUTF8 scope ( aScope ) ;
2015-02-08 20:33:39 -08:00
ServiceWorkerJobQueue * queue = GetOrCreateJobQueue ( scope ) ;
2015-01-22 14:10:38 -08:00
MOZ_ASSERT ( queue ) ;
2015-05-19 12:20:15 -07:00
PrincipalInfo principalInfo ;
if ( NS_WARN_IF ( NS_FAILED ( PrincipalToPrincipalInfo ( aPrincipal ,
& principalInfo ) ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
2015-01-22 14:10:38 -08:00
nsRefPtr < ServiceWorkerUnregisterJob > job =
2015-05-19 12:20:15 -07:00
new ServiceWorkerUnregisterJob ( queue , scope , aCallback , principalInfo ) ;
2015-02-11 03:53:00 -08:00
if ( mActor ) {
queue - > Append ( job ) ;
return NS_OK ;
}
AppendPendingOperation ( queue , job ) ;
2015-01-22 14:10:38 -08:00
return NS_OK ;
2014-12-19 02:00:29 -08:00
}
/* static */
already_AddRefed < ServiceWorkerManager >
ServiceWorkerManager : : GetInstance ( )
{
nsCOMPtr < nsIServiceWorkerManager > swm = mozilla : : services : : GetServiceWorkerManager ( ) ;
nsRefPtr < ServiceWorkerManager > concrete = do_QueryObject ( swm ) ;
return concrete . forget ( ) ;
}
void
ServiceWorkerManager : : FinishFetch ( ServiceWorkerRegistrationInfo * aRegistration )
{
}
2014-07-02 17:48:50 -07:00
2014-12-19 02:48:31 -08:00
bool
2014-12-19 02:00:29 -08:00
ServiceWorkerManager : : HandleError ( JSContext * aCx ,
2014-12-19 02:48:31 -08:00
const nsCString & aScope ,
const nsString & aWorkerURL ,
2014-12-19 02:00:29 -08:00
nsString aMessage ,
nsString aFilename ,
nsString aLine ,
uint32_t aLineNumber ,
uint32_t aColumnNumber ,
uint32_t aFlags )
2014-07-02 17:48:50 -07:00
{
AssertIsOnMainThread ( ) ;
2015-02-08 20:33:39 -08:00
if ( ! mSetOfScopesBeingUpdated . Contains ( aScope ) ) {
2014-12-19 02:48:31 -08:00
return false ;
2014-07-22 18:18:48 -07:00
}
2015-02-08 20:33:39 -08:00
mSetOfScopesBeingUpdated . Remove ( aScope ) ;
2014-12-19 02:48:31 -08:00
2015-02-08 20:33:39 -08:00
ServiceWorkerJobQueue * queue = mJobQueues . Get ( aScope ) ;
2014-12-19 02:48:31 -08:00
MOZ_ASSERT ( queue ) ;
ServiceWorkerJob * job = queue - > Peek ( ) ;
2015-03-05 17:37:49 -08:00
if ( job ) {
MOZ_ASSERT ( job - > IsRegisterJob ( ) ) ;
nsRefPtr < ServiceWorkerRegisterJob > regJob = static_cast < ServiceWorkerRegisterJob * > ( job ) ;
2014-07-02 17:48:50 -07:00
2015-03-05 17:37:49 -08:00
RootedDictionary < ErrorEventInit > init ( aCx ) ;
init . mMessage = aMessage ;
init . mFilename = aFilename ;
init . mLineno = aLineNumber ;
init . mColno = aColumnNumber ;
2014-07-02 17:48:50 -07:00
2015-04-24 11:42:13 -07:00
NS_WARNING ( nsPrintfCString (
" Script error caused ServiceWorker registration to fail: %s:%u '%s' " ,
NS_ConvertUTF16toUTF8 ( aFilename ) . get ( ) , aLineNumber ,
NS_ConvertUTF16toUTF8 ( aMessage ) . get ( ) ) . get ( ) ) ;
2015-03-05 17:37:49 -08:00
regJob - > Fail ( init ) ;
}
2014-12-19 02:48:31 -08:00
return true ;
2014-06-11 09:12:56 -07:00
}
2014-07-11 13:07:59 -07:00
void
2014-12-19 02:00:29 -08:00
ServiceWorkerRegistrationInfo : : FinishActivate ( bool aSuccess )
2014-07-11 13:07:59 -07:00
{
2015-02-10 14:33:23 -08:00
if ( mPendingUninstall | | ! mActiveWorker ) {
return ;
}
2014-12-19 02:00:29 -08:00
if ( aSuccess ) {
mActiveWorker - > UpdateState ( ServiceWorkerState : : Activated ) ;
2015-02-10 18:08:58 -08:00
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
swm - > StoreRegistration ( mPrincipal , this ) ;
2014-12-19 02:00:29 -08:00
} else {
mActiveWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
mActiveWorker = nullptr ;
}
2014-07-11 13:07:59 -07:00
}
2013-11-19 15:15:02 -08:00
NS_IMETHODIMP
ServiceWorkerManager : : CreateServiceWorkerForWindow ( nsPIDOMWindow * aWindow ,
2015-02-19 08:40:21 -08:00
ServiceWorkerInfo * aInfo ,
2013-11-19 15:15:02 -08:00
ServiceWorker * * aServiceWorker )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWindow ) ;
2015-03-19 11:41:42 -07:00
MOZ_ASSERT ( aInfo ) ;
2013-11-19 15:15:02 -08:00
2014-12-19 02:00:29 -08:00
AutoJSAPI jsapi ;
jsapi . Init ( aWindow ) ;
JSContext * cx = jsapi . cx ( ) ;
2013-11-19 15:15:02 -08:00
2015-03-19 11:41:42 -07:00
WorkerLoadInfo loadInfo ;
nsresult rv = WorkerPrivate : : GetLoadInfo ( cx , aWindow , nullptr ,
NS_ConvertUTF8toUTF16 ( aInfo - > ScriptSpec ( ) ) ,
false ,
WorkerPrivate : : OverrideLoadGroup ,
& loadInfo ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-03-19 16:40:52 -07:00
MOZ_ASSERT ( ! aInfo - > CacheName ( ) . IsEmpty ( ) ) ;
2015-03-19 11:41:42 -07:00
loadInfo . mServiceWorkerCacheName = aInfo - > CacheName ( ) ;
2015-05-14 12:41:42 -07:00
loadInfo . mServiceWorkerID = aInfo - > ID ( ) ;
2015-03-19 11:41:42 -07:00
RuntimeService * rs = RuntimeService : : GetOrCreateService ( ) ;
if ( ! rs ) {
return NS_ERROR_FAILURE ;
}
2013-11-19 15:15:02 -08:00
2015-03-19 11:41:42 -07:00
nsRefPtr < SharedWorker > sharedWorker ;
rv = rs - > CreateSharedWorkerForServiceWorkerFromLoadInfo ( cx , & loadInfo ,
NS_ConvertUTF8toUTF16 ( aInfo - > ScriptSpec ( ) ) ,
aInfo - > Scope ( ) ,
getter_AddRefs ( sharedWorker ) ) ;
2013-11-19 15:15:02 -08:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-02-19 08:40:21 -08:00
nsRefPtr < ServiceWorker > serviceWorker =
new ServiceWorker ( aWindow , aInfo , sharedWorker ) ;
2013-11-19 15:15:02 -08:00
serviceWorker . forget ( aServiceWorker ) ;
return rv ;
}
2015-02-11 03:53:00 -08:00
void
ServiceWorkerManager : : LoadRegistrations (
const nsTArray < ServiceWorkerRegistrationData > & aRegistrations )
{
AssertIsOnMainThread ( ) ;
for ( uint32_t i = 0 , len = aRegistrations . Length ( ) ; i < len ; + + i ) {
nsCOMPtr < nsIPrincipal > principal =
PrincipalInfoToPrincipal ( aRegistrations [ i ] . principal ( ) ) ;
if ( ! principal ) {
continue ;
}
ServiceWorkerRegistrationInfo * registration =
CreateNewRegistration ( aRegistrations [ i ] . scope ( ) , principal ) ;
registration - > mScriptSpec = aRegistrations [ i ] . scriptSpec ( ) ;
2015-02-10 18:08:58 -08:00
const nsCString & currentWorkerURL = aRegistrations [ i ] . currentWorkerURL ( ) ;
if ( ! currentWorkerURL . IsEmpty ( ) ) {
registration - > mActiveWorker =
2015-03-18 09:46:38 -07:00
new ServiceWorkerInfo ( registration , currentWorkerURL , aRegistrations [ i ] . activeCacheName ( ) ) ;
2015-02-10 18:08:58 -08:00
registration - > mActiveWorker - > SetActivateStateUncheckedWithoutEvent ( ServiceWorkerState : : Activated ) ;
}
2015-02-11 03:53:00 -08:00
}
}
void
ServiceWorkerManager : : ActorFailed ( )
{
MOZ_CRASH ( " Failed to create a PBackgroundChild actor! " ) ;
}
void
ServiceWorkerManager : : ActorCreated ( mozilla : : ipc : : PBackgroundChild * aActor )
{
MOZ_ASSERT ( aActor ) ;
MOZ_ASSERT ( ! mActor ) ;
mActor = aActor ;
// Flush the pending requests.
for ( uint32_t i = 0 , len = mPendingOperations . Length ( ) ; i < len ; + + i ) {
MOZ_ASSERT ( mPendingOperations [ i ] . mRunnable | |
( mPendingOperations [ i ] . mJob & & mPendingOperations [ i ] . mQueue ) ) ;
if ( mPendingOperations [ i ] . mRunnable ) {
nsresult rv = NS_DispatchToCurrentThread ( mPendingOperations [ i ] . mRunnable ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to dispatch a runnable. " ) ;
return ;
}
} else {
mPendingOperations [ i ] . mQueue - > Append ( mPendingOperations [ i ] . mJob ) ;
}
}
mPendingOperations . Clear ( ) ;
}
void
ServiceWorkerManager : : StoreRegistration (
nsIPrincipal * aPrincipal ,
ServiceWorkerRegistrationInfo * aRegistration )
{
MOZ_ASSERT ( mActor ) ;
MOZ_ASSERT ( aPrincipal ) ;
MOZ_ASSERT ( aRegistration ) ;
ServiceWorkerRegistrationData data ;
nsresult rv = PopulateRegistrationData ( aPrincipal , aRegistration , data ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
PrincipalInfo principalInfo ;
if ( NS_WARN_IF ( NS_FAILED ( PrincipalToPrincipalInfo ( aPrincipal ,
& principalInfo ) ) ) ) {
return ;
}
mActor - > SendRegisterServiceWorker ( data ) ;
}
2014-08-19 06:56:00 -07:00
already_AddRefed < ServiceWorkerRegistrationInfo >
ServiceWorkerManager : : GetServiceWorkerRegistrationInfo ( nsPIDOMWindow * aWindow )
2014-07-11 11:52:19 -07:00
{
2014-07-20 23:25:44 -07:00
nsCOMPtr < nsIDocument > document = aWindow - > GetExtantDoc ( ) ;
2014-08-19 06:56:00 -07:00
return GetServiceWorkerRegistrationInfo ( document ) ;
2014-07-11 11:52:19 -07:00
}
2014-08-19 06:56:00 -07:00
already_AddRefed < ServiceWorkerRegistrationInfo >
ServiceWorkerManager : : GetServiceWorkerRegistrationInfo ( nsIDocument * aDoc )
2014-07-11 11:52:19 -07:00
{
nsCOMPtr < nsIURI > documentURI = aDoc - > GetDocumentURI ( ) ;
2015-05-19 12:20:15 -07:00
return GetServiceWorkerRegistrationInfo ( documentURI ) ;
2014-07-11 11:52:19 -07:00
}
2014-08-19 06:56:00 -07:00
already_AddRefed < ServiceWorkerRegistrationInfo >
2015-05-19 12:20:15 -07:00
ServiceWorkerManager : : GetServiceWorkerRegistrationInfo ( nsIURI * aURI )
2014-07-11 11:52:19 -07:00
{
2015-05-19 12:20:15 -07:00
nsCString spec ;
2014-07-14 14:15:23 -07:00
nsresult rv = aURI - > GetSpec ( spec ) ;
2014-07-11 11:52:19 -07:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return nullptr ;
}
2015-05-19 12:20:15 -07:00
nsCString scope = FindScopeForPath ( mOrderedScopes , spec ) ;
if ( scope . IsEmpty ( ) ) {
2014-07-11 11:52:19 -07:00
return nullptr ;
}
2014-08-19 06:56:00 -07:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-05-19 12:20:15 -07:00
mServiceWorkerRegistrationInfos . Get ( scope , getter_AddRefs ( registration ) ) ;
2014-07-11 11:52:19 -07:00
// ordered scopes and registrations better be in sync.
MOZ_ASSERT ( registration ) ;
2014-07-14 10:33:44 -07:00
if ( registration - > mPendingUninstall ) {
return nullptr ;
}
2014-07-28 06:57:31 -07:00
return registration . forget ( ) ;
2014-07-11 11:52:19 -07:00
}
/* static */ void
2015-05-19 12:20:15 -07:00
ServiceWorkerManager : : AddScope ( nsTArray < nsCString > & aList , const nsACString & aScope )
2014-07-11 11:52:19 -07:00
{
2015-05-19 12:20:15 -07:00
for ( uint32_t i = 0 ; i < aList . Length ( ) ; + + i ) {
const nsCString & current = aList [ i ] ;
2014-07-11 11:52:19 -07:00
// Perfect match!
if ( aScope . Equals ( current ) ) {
return ;
}
2014-08-21 16:38:40 -07:00
// Sort by length, with longest match first.
// /foo/bar should be before /foo/
// Similarly /foo/b is between the two.
if ( StringBeginsWith ( aScope , current ) ) {
2015-05-19 12:20:15 -07:00
aList . InsertElementAt ( i , aScope ) ;
2014-07-11 11:52:19 -07:00
return ;
}
}
2015-05-19 12:20:15 -07:00
aList . AppendElement ( aScope ) ;
2014-07-11 11:52:19 -07:00
}
2015-05-19 12:20:15 -07:00
/* static */ nsCString
ServiceWorkerManager : : FindScopeForPath ( nsTArray < nsCString > & aList , const nsACString & aPath )
2014-07-11 11:52:19 -07:00
{
2015-05-19 12:20:15 -07:00
nsCString match ;
2014-07-11 11:52:19 -07:00
2015-05-19 12:20:15 -07:00
for ( uint32_t i = 0 ; i < aList . Length ( ) ; + + i ) {
const nsCString & current = aList [ i ] ;
2014-08-21 16:38:40 -07:00
if ( StringBeginsWith ( aPath , current ) ) {
2015-05-19 12:20:15 -07:00
match = current ;
break ;
2014-07-11 11:52:19 -07:00
}
}
2015-05-19 12:20:15 -07:00
return match ;
2014-07-11 11:52:19 -07:00
}
/* static */ void
2015-05-19 12:20:15 -07:00
ServiceWorkerManager : : RemoveScope ( nsTArray < nsCString > & aList , const nsACString & aScope )
2014-07-11 11:52:19 -07:00
{
2015-05-19 12:20:15 -07:00
aList . RemoveElement ( aScope ) ;
2014-07-11 11:52:19 -07:00
}
2014-07-20 23:25:44 -07:00
void
ServiceWorkerManager : : MaybeStartControlling ( nsIDocument * aDoc )
{
AssertIsOnMainThread ( ) ;
2015-05-14 12:41:42 -07:00
// We keep a set of documents that service workers may choose to start
// controlling using claim().
MOZ_ASSERT ( ! mAllDocuments . Contains ( aDoc ) ) ;
mAllDocuments . PutEntry ( aDoc ) ;
2014-08-19 06:56:00 -07:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration =
GetServiceWorkerRegistrationInfo ( aDoc ) ;
2014-12-19 02:00:29 -08:00
if ( registration ) {
2015-02-08 20:33:39 -08:00
MOZ_ASSERT ( ! mControlledDocuments . Contains ( aDoc ) ) ;
2015-05-14 12:41:42 -07:00
StartControllingADocument ( registration , aDoc ) ;
2014-07-20 23:25:44 -07:00
}
}
void
ServiceWorkerManager : : MaybeStopControlling ( nsIDocument * aDoc )
{
MOZ_ASSERT ( aDoc ) ;
2014-08-19 06:56:00 -07:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-02-08 20:33:39 -08:00
mControlledDocuments . Remove ( aDoc , getter_AddRefs ( registration ) ) ;
2014-07-20 23:25:44 -07:00
// A document which was uncontrolled does not maintain that state itself, so
// it will always call MaybeStopControlling() even if there isn't an
// associated registration. So this check is required.
if ( registration ) {
2015-05-14 12:41:42 -07:00
StopControllingADocument ( registration ) ;
}
if ( mAllDocuments . Contains ( aDoc ) ) {
mAllDocuments . RemoveEntry ( aDoc ) ;
}
}
void
ServiceWorkerManager : : StartControllingADocument ( ServiceWorkerRegistrationInfo * aRegistration ,
nsIDocument * aDoc )
{
MOZ_ASSERT ( aRegistration ) ;
MOZ_ASSERT ( aDoc ) ;
aRegistration - > StartControllingADocument ( ) ;
mControlledDocuments . Put ( aDoc , aRegistration ) ;
}
void
ServiceWorkerManager : : StopControllingADocument ( ServiceWorkerRegistrationInfo * aRegistration )
{
aRegistration - > StopControllingADocument ( ) ;
if ( ! aRegistration - > IsControllingDocuments ( ) ) {
if ( aRegistration - > mPendingUninstall ) {
aRegistration - > Clear ( ) ;
RemoveRegistration ( aRegistration ) ;
} else {
aRegistration - > TryToActivate ( ) ;
2014-10-24 15:11:26 -07:00
}
2014-07-20 23:25:44 -07:00
}
}
2014-07-11 11:52:19 -07:00
NS_IMETHODIMP
2015-05-19 12:20:15 -07:00
ServiceWorkerManager : : GetScopeForUrl ( const nsAString & aUrl , nsAString & aScope )
2014-07-11 11:52:19 -07:00
{
nsCOMPtr < nsIURI > uri ;
nsresult rv = NS_NewURI ( getter_AddRefs ( uri ) , aUrl , nullptr , nullptr ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_FAILURE ;
}
2015-05-19 12:20:15 -07:00
nsRefPtr < ServiceWorkerRegistrationInfo > r = GetServiceWorkerRegistrationInfo ( uri ) ;
2014-07-11 11:52:19 -07:00
if ( ! r ) {
return NS_ERROR_FAILURE ;
}
aScope = NS_ConvertUTF8toUTF16 ( r - > mScope ) ;
return NS_OK ;
}
2014-07-11 13:07:59 -07:00
2014-07-14 14:15:23 -07:00
NS_IMETHODIMP
2015-04-08 13:13:32 -07:00
ServiceWorkerManager : : AddRegistrationEventListener ( const nsAString & aScope ,
ServiceWorkerRegistrationListener * aListener )
2014-07-14 14:15:23 -07:00
{
2014-08-27 13:33:20 -07:00
AssertIsOnMainThread ( ) ;
2015-04-08 13:13:32 -07:00
MOZ_ASSERT ( aListener ) ;
2014-10-27 11:52:57 -07:00
# ifdef DEBUG
// Ensure a registration is only listening for it's own scope.
nsAutoString regScope ;
2015-04-08 13:13:32 -07:00
aListener - > GetScope ( regScope ) ;
2014-10-27 11:52:57 -07:00
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
2015-04-08 13:13:32 -07:00
MOZ_ASSERT ( aScope . Equals ( regScope ) ) ;
2014-10-27 11:52:57 -07:00
# endif
2015-04-08 13:13:32 -07:00
MOZ_ASSERT ( ! mServiceWorkerRegistrationListeners . Contains ( aListener ) ) ;
mServiceWorkerRegistrationListeners . AppendElement ( aListener ) ;
2014-07-14 14:15:23 -07:00
return NS_OK ;
}
NS_IMETHODIMP
2015-04-08 13:13:32 -07:00
ServiceWorkerManager : : RemoveRegistrationEventListener ( const nsAString & aScope ,
ServiceWorkerRegistrationListener * aListener )
2014-07-14 14:15:23 -07:00
{
2014-08-27 13:33:20 -07:00
AssertIsOnMainThread ( ) ;
2015-04-08 13:13:32 -07:00
MOZ_ASSERT ( aListener ) ;
2014-10-27 11:52:57 -07:00
# ifdef DEBUG
// Ensure a registration is unregistering for it's own scope.
nsAutoString regScope ;
2015-04-08 13:13:32 -07:00
aListener - > GetScope ( regScope ) ;
2014-10-27 11:52:57 -07:00
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
2015-04-08 13:13:32 -07:00
MOZ_ASSERT ( aScope . Equals ( regScope ) ) ;
2014-10-27 11:52:57 -07:00
# endif
2015-04-08 13:13:32 -07:00
MOZ_ASSERT ( mServiceWorkerRegistrationListeners . Contains ( aListener ) ) ;
mServiceWorkerRegistrationListeners . RemoveElement ( aListener ) ;
2014-07-14 14:15:23 -07:00
return NS_OK ;
}
void
2015-04-08 13:13:32 -07:00
ServiceWorkerManager : : FireUpdateFoundOnServiceWorkerRegistrations (
ServiceWorkerRegistrationInfo * aRegistration )
2014-07-14 14:15:23 -07:00
{
AssertIsOnMainThread ( ) ;
2015-02-08 20:33:39 -08:00
2015-04-08 13:13:32 -07:00
nsTObserverArray < ServiceWorkerRegistrationListener * > : : ForwardIterator it ( mServiceWorkerRegistrationListeners ) ;
2015-02-08 20:33:39 -08:00
while ( it . HasMore ( ) ) {
2015-04-08 13:13:32 -07:00
nsRefPtr < ServiceWorkerRegistrationListener > target = it . GetNext ( ) ;
2015-02-08 20:33:39 -08:00
nsAutoString regScope ;
target - > GetScope ( regScope ) ;
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
NS_ConvertUTF16toUTF8 utf8Scope ( regScope ) ;
if ( utf8Scope . Equals ( aRegistration - > mScope ) ) {
2015-04-08 13:13:32 -07:00
target - > UpdateFound ( ) ;
2014-07-14 14:15:23 -07:00
}
}
}
2014-07-23 14:05:08 -07:00
/*
2014-08-24 22:35:03 -07:00
* This is used for installing , waiting and active .
2014-07-23 14:05:08 -07:00
*/
NS_IMETHODIMP
2014-08-24 22:35:03 -07:00
ServiceWorkerManager : : GetServiceWorkerForScope ( nsIDOMWindow * aWindow ,
const nsAString & aScope ,
WhichServiceWorker aWhichWorker ,
nsISupports * * aServiceWorker )
2014-07-23 14:05:08 -07:00
{
2014-08-24 22:35:03 -07:00
AssertIsOnMainThread ( ) ;
2014-07-23 14:05:08 -07:00
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
2015-02-19 08:40:21 -08:00
if ( NS_WARN_IF ( ! window ) ) {
2014-08-24 22:35:03 -07:00
return NS_ERROR_FAILURE ;
}
2014-07-23 14:05:08 -07:00
2014-08-24 22:35:03 -07:00
nsCOMPtr < nsIDocument > doc = window - > GetExtantDoc ( ) ;
MOZ_ASSERT ( doc ) ;
///////////////////////////////////////////
// Security check
2014-10-27 11:52:57 -07:00
nsAutoCString scope = NS_ConvertUTF16toUTF8 ( aScope ) ;
2014-08-24 22:35:03 -07:00
nsCOMPtr < nsIURI > scopeURI ;
// We pass nullptr as the base URI since scopes obtained from
// ServiceWorkerRegistrations MUST be fully qualified URIs.
nsresult rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , scope , nullptr , nullptr ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
nsCOMPtr < nsIPrincipal > documentPrincipal = doc - > NodePrincipal ( ) ;
rv = documentPrincipal - > CheckMayLoad ( scopeURI , true /* report */ ,
false /* allowIfInheritsPrinciple */ ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
////////////////////////////////////////////
2015-05-19 12:20:15 -07:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration = GetRegistration ( scope ) ;
2015-02-19 08:40:21 -08:00
if ( NS_WARN_IF ( ! registration ) ) {
2014-07-23 14:05:08 -07:00
return NS_ERROR_FAILURE ;
}
nsRefPtr < ServiceWorkerInfo > info ;
if ( aWhichWorker = = WhichServiceWorker : : INSTALLING_WORKER ) {
info = registration - > mInstallingWorker ;
} else if ( aWhichWorker = = WhichServiceWorker : : WAITING_WORKER ) {
info = registration - > mWaitingWorker ;
} else if ( aWhichWorker = = WhichServiceWorker : : ACTIVE_WORKER ) {
2014-12-19 02:00:29 -08:00
info = registration - > mActiveWorker ;
2014-07-23 14:05:08 -07:00
} else {
MOZ_CRASH ( " Invalid worker type " ) ;
}
2015-02-19 08:40:21 -08:00
if ( NS_WARN_IF ( ! info ) ) {
2014-07-23 14:05:08 -07:00
return NS_ERROR_DOM_NOT_FOUND_ERR ;
}
nsRefPtr < ServiceWorker > serviceWorker ;
2014-08-24 22:35:03 -07:00
rv = CreateServiceWorkerForWindow ( window ,
2015-02-19 08:40:21 -08:00
info ,
2014-08-24 22:35:03 -07:00
getter_AddRefs ( serviceWorker ) ) ;
2014-07-23 14:05:08 -07:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2014-12-19 03:25:56 -08:00
serviceWorker - > SetState ( info - > State ( ) ) ;
2014-07-23 14:05:08 -07:00
serviceWorker . forget ( aServiceWorker ) ;
return NS_OK ;
}
2015-02-18 17:34:29 -08:00
class FetchEventRunnable : public WorkerRunnable
, public nsIHttpHeaderVisitor {
nsMainThreadPtrHandle < nsIInterceptedChannel > mInterceptedChannel ;
nsMainThreadPtrHandle < ServiceWorker > mServiceWorker ;
nsTArray < nsCString > mHeaderNames ;
nsTArray < nsCString > mHeaderValues ;
2015-03-06 05:04:49 -08:00
nsAutoPtr < ServiceWorkerClientInfo > mClientInfo ;
2015-02-18 17:34:29 -08:00
nsCString mSpec ;
nsCString mMethod ;
bool mIsReload ;
2015-03-17 08:47:02 -07:00
RequestMode mRequestMode ;
RequestCredentials mRequestCredentials ;
2015-03-25 13:43:34 -07:00
nsContentPolicyType mContentPolicyType ;
2015-05-04 13:54:22 -07:00
nsCOMPtr < nsIInputStream > mUploadStream ;
2015-02-18 17:34:29 -08:00
public :
FetchEventRunnable ( WorkerPrivate * aWorkerPrivate ,
nsMainThreadPtrHandle < nsIInterceptedChannel > & aChannel ,
nsMainThreadPtrHandle < ServiceWorker > & aServiceWorker ,
2015-03-23 10:36:44 -07:00
nsAutoPtr < ServiceWorkerClientInfo > & aClientInfo ,
bool aIsReload )
2015-02-18 17:34:29 -08:00
: WorkerRunnable ( aWorkerPrivate , WorkerThreadModifyBusyCount )
, mInterceptedChannel ( aChannel )
, mServiceWorker ( aServiceWorker )
2015-03-06 05:04:49 -08:00
, mClientInfo ( aClientInfo )
2015-03-23 10:36:44 -07:00
, mIsReload ( aIsReload )
2015-03-17 08:47:02 -07:00
, mRequestMode ( RequestMode : : No_cors )
// By default we set it to same-origin since normal HTTP fetches always
// send credentials to same-origin websites unless explicitly forbidden.
, mRequestCredentials ( RequestCredentials : : Same_origin )
2015-03-25 13:43:34 -07:00
, mContentPolicyType ( nsIContentPolicy : : TYPE_INVALID )
2015-02-18 17:34:29 -08:00
{
MOZ_ASSERT ( aWorkerPrivate ) ;
}
NS_DECL_ISUPPORTS_INHERITED
NS_IMETHOD
2015-03-21 09:28:04 -07:00
VisitHeader ( const nsACString & aHeader , const nsACString & aValue ) override
2015-02-18 17:34:29 -08:00
{
mHeaderNames . AppendElement ( aHeader ) ;
mHeaderValues . AppendElement ( aValue ) ;
return NS_OK ;
}
nsresult
Init ( )
{
2015-03-17 08:47:02 -07:00
AssertIsOnMainThread ( ) ;
2015-02-18 17:34:29 -08:00
nsCOMPtr < nsIChannel > channel ;
nsresult rv = mInterceptedChannel - > GetChannel ( getter_AddRefs ( channel ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsCOMPtr < nsIURI > uri ;
rv = channel - > GetURI ( getter_AddRefs ( uri ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
rv = uri - > GetSpec ( mSpec ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2015-05-22 01:48:03 -07:00
uint32_t loadFlags ;
rv = channel - > GetLoadFlags ( & loadFlags ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2015-03-25 13:43:34 -07:00
2015-05-22 01:48:03 -07:00
nsCOMPtr < nsILoadInfo > loadInfo ;
rv = channel - > GetLoadInfo ( getter_AddRefs ( loadInfo ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2015-05-22 00:32:25 -07:00
2015-05-22 01:48:03 -07:00
mContentPolicyType = loadInfo - > GetContentPolicyType ( ) ;
2015-05-22 00:32:25 -07:00
2015-05-22 00:32:25 -07:00
nsCOMPtr < nsIHttpChannel > httpChannel = do_QueryInterface ( channel ) ;
if ( httpChannel ) {
rv = httpChannel - > GetRequestMethod ( mMethod ) ;
2015-05-22 01:48:03 -07:00
NS_ENSURE_SUCCESS ( rv , rv ) ;
2015-05-22 00:32:25 -07:00
nsCOMPtr < nsIHttpChannelInternal > internalChannel = do_QueryInterface ( httpChannel ) ;
NS_ENSURE_TRUE ( internalChannel , NS_ERROR_NOT_AVAILABLE ) ;
uint32_t mode ;
internalChannel - > GetCorsMode ( & mode ) ;
switch ( mode ) {
case nsIHttpChannelInternal : : CORS_MODE_SAME_ORIGIN :
mRequestMode = RequestMode : : Same_origin ;
break ;
case nsIHttpChannelInternal : : CORS_MODE_NO_CORS :
mRequestMode = RequestMode : : No_cors ;
break ;
case nsIHttpChannelInternal : : CORS_MODE_CORS :
case nsIHttpChannelInternal : : CORS_MODE_CORS_WITH_FORCED_PREFLIGHT :
mRequestMode = RequestMode : : Cors ;
break ;
default :
MOZ_CRASH ( " Unexpected CORS mode " ) ;
}
if ( loadFlags & nsIRequest : : LOAD_ANONYMOUS ) {
mRequestCredentials = RequestCredentials : : Omit ;
} else {
bool includeCrossOrigin ;
internalChannel - > GetCorsIncludeCredentials ( & includeCrossOrigin ) ;
if ( includeCrossOrigin ) {
mRequestCredentials = RequestCredentials : : Include ;
}
}
rv = httpChannel - > VisitRequestHeaders ( this ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsCOMPtr < nsIUploadChannel2 > uploadChannel = do_QueryInterface ( httpChannel ) ;
if ( uploadChannel ) {
MOZ_ASSERT ( ! mUploadStream ) ;
rv = uploadChannel - > CloneUploadStream ( getter_AddRefs ( mUploadStream ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
}
} else {
nsCOMPtr < nsIJARChannel > jarChannel = do_QueryInterface ( channel ) ;
// If it is not an HTTP channel it must be a JAR one.
NS_ENSURE_TRUE ( jarChannel , NS_ERROR_NOT_AVAILABLE ) ;
mMethod = " GET " ;
if ( loadFlags & nsIRequest : : LOAD_ANONYMOUS ) {
mRequestCredentials = RequestCredentials : : Omit ;
}
2015-05-04 13:54:22 -07:00
}
2015-02-18 17:34:29 -08:00
return NS_OK ;
}
bool
2015-03-21 09:28:04 -07:00
WorkerRun ( JSContext * aCx , WorkerPrivate * aWorkerPrivate ) override
2015-02-18 17:34:29 -08:00
{
MOZ_ASSERT ( aWorkerPrivate ) ;
return DispatchFetchEvent ( aCx , aWorkerPrivate ) ;
}
private :
~ FetchEventRunnable ( ) { }
2015-03-21 09:28:04 -07:00
class ResumeRequest final : public nsRunnable {
2015-02-18 17:34:29 -08:00
nsMainThreadPtrHandle < nsIInterceptedChannel > mChannel ;
public :
explicit ResumeRequest ( nsMainThreadPtrHandle < nsIInterceptedChannel > & aChannel )
: mChannel ( aChannel )
{
}
NS_IMETHOD Run ( )
{
AssertIsOnMainThread ( ) ;
nsresult rv = mChannel - > ResetInterception ( ) ;
NS_WARN_IF_FALSE ( NS_SUCCEEDED ( rv ) , " Failed to resume intercepted network request " ) ;
return rv ;
}
} ;
bool
DispatchFetchEvent ( JSContext * aCx , WorkerPrivate * aWorkerPrivate )
{
MOZ_ASSERT ( aCx ) ;
MOZ_ASSERT ( aWorkerPrivate ) ;
MOZ_ASSERT ( aWorkerPrivate - > IsServiceWorker ( ) ) ;
GlobalObject globalObj ( aCx , aWorkerPrivate - > GlobalScope ( ) - > GetWrapper ( ) ) ;
2015-02-26 12:40:00 -08:00
NS_ConvertUTF8toUTF16 local ( mSpec ) ;
2015-02-18 17:34:29 -08:00
RequestOrUSVString requestInfo ;
2015-02-26 12:40:00 -08:00
requestInfo . SetAsUSVString ( ) . Rebind ( local . Data ( ) , local . Length ( ) ) ;
2015-02-18 17:34:29 -08:00
RootedDictionary < RequestInit > reqInit ( aCx ) ;
reqInit . mMethod . Construct ( mMethod ) ;
nsRefPtr < InternalHeaders > internalHeaders = new InternalHeaders ( HeadersGuardEnum : : Request ) ;
MOZ_ASSERT ( mHeaderNames . Length ( ) = = mHeaderValues . Length ( ) ) ;
for ( uint32_t i = 0 ; i < mHeaderNames . Length ( ) ; i + + ) {
2015-04-10 20:19:28 -07:00
ErrorResult result ;
internalHeaders - > Set ( mHeaderNames [ i ] , mHeaderValues [ i ] , result ) ;
if ( NS_WARN_IF ( result . Failed ( ) ) ) {
2015-02-18 17:34:29 -08:00
return false ;
}
}
nsRefPtr < Headers > headers = new Headers ( globalObj . GetAsSupports ( ) , internalHeaders ) ;
reqInit . mHeaders . Construct ( ) ;
reqInit . mHeaders . Value ( ) . SetAsHeaders ( ) = headers ;
2015-03-17 08:47:02 -07:00
reqInit . mMode . Construct ( mRequestMode ) ;
reqInit . mCredentials . Construct ( mRequestCredentials ) ;
2015-02-18 17:34:29 -08:00
2015-04-10 20:19:28 -07:00
ErrorResult result ;
nsRefPtr < Request > request = Request : : Constructor ( globalObj , requestInfo , reqInit , result ) ;
if ( NS_WARN_IF ( result . Failed ( ) ) ) {
2015-02-18 17:34:29 -08:00
return false ;
}
2015-03-27 03:47:00 -07:00
// For Telemetry, note that this Request object was created by a Fetch event.
nsRefPtr < InternalRequest > internalReq = request - > GetInternalRequest ( ) ;
MOZ_ASSERT ( internalReq ) ;
internalReq - > SetCreatedByFetchEvent ( ) ;
2015-02-18 17:34:29 -08:00
2015-05-04 13:54:22 -07:00
internalReq - > SetBody ( mUploadStream ) ;
2015-03-25 13:43:34 -07:00
request - > SetContentPolicyType ( mContentPolicyType ) ;
2015-02-18 17:34:29 -08:00
RootedDictionary < FetchEventInit > init ( aCx ) ;
init . mRequest . Construct ( ) ;
init . mRequest . Value ( ) = request ;
init . mBubbles = false ;
init . mCancelable = true ;
init . mIsReload . Construct ( mIsReload ) ;
nsRefPtr < FetchEvent > event =
2015-04-10 20:19:28 -07:00
FetchEvent : : Constructor ( globalObj , NS_LITERAL_STRING ( " fetch " ) , init , result ) ;
if ( NS_WARN_IF ( result . Failed ( ) ) ) {
2015-02-18 17:34:29 -08:00
return false ;
}
2015-03-06 05:04:49 -08:00
event - > PostInit ( mInterceptedChannel , mServiceWorker , mClientInfo ) ;
2015-02-18 17:34:29 -08:00
event - > SetTrusted ( true ) ;
nsRefPtr < EventTarget > target = do_QueryObject ( aWorkerPrivate - > GlobalScope ( ) ) ;
nsresult rv2 = target - > DispatchDOMEvent ( nullptr , event , nullptr , nullptr ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv2 ) ) | | ! event - > WaitToRespond ( ) ) {
nsCOMPtr < nsIRunnable > runnable = new ResumeRequest ( mInterceptedChannel ) ;
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( NS_DispatchToMainThread ( runnable ) ) ) ;
}
return true ;
}
} ;
NS_IMPL_ISUPPORTS_INHERITED ( FetchEventRunnable , WorkerRunnable , nsIHttpHeaderVisitor )
NS_IMETHODIMP
2015-03-23 10:36:44 -07:00
ServiceWorkerManager : : DispatchFetchEvent ( nsIDocument * aDoc , nsIInterceptedChannel * aChannel ,
bool aIsReload )
2015-02-18 17:34:29 -08:00
{
MOZ_ASSERT ( aChannel ) ;
nsCOMPtr < nsISupports > serviceWorker ;
bool isNavigation = false ;
nsresult rv = aChannel - > GetIsNavigation ( & isNavigation ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
2015-03-06 05:04:49 -08:00
nsAutoPtr < ServiceWorkerClientInfo > clientInfo ;
2015-02-18 17:34:29 -08:00
if ( ! isNavigation ) {
MOZ_ASSERT ( aDoc ) ;
2015-02-26 12:14:51 -08:00
rv = GetDocumentController ( aDoc - > GetInnerWindow ( ) , getter_AddRefs ( serviceWorker ) ) ;
2015-03-06 05:04:49 -08:00
clientInfo = new ServiceWorkerClientInfo ( aDoc ) ;
2015-02-18 17:34:29 -08:00
} else {
nsCOMPtr < nsIChannel > internalChannel ;
rv = aChannel - > GetChannel ( getter_AddRefs ( internalChannel ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsCOMPtr < nsIURI > uri ;
rv = internalChannel - > GetURI ( getter_AddRefs ( uri ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
nsRefPtr < ServiceWorkerRegistrationInfo > registration =
2015-05-19 12:20:15 -07:00
GetServiceWorkerRegistrationInfo ( uri ) ;
2015-03-28 18:05:11 -07:00
if ( ! registration ) {
NS_WARNING ( " No registration found when dispatching the fetch event " ) ;
return NS_ERROR_FAILURE ;
}
2015-02-18 17:34:29 -08:00
// This should only happen if IsAvailableForURI() returned true.
MOZ_ASSERT ( registration - > mActiveWorker ) ;
nsRefPtr < ServiceWorker > sw ;
rv = CreateServiceWorker ( registration - > mPrincipal ,
2015-02-19 08:40:21 -08:00
registration - > mActiveWorker ,
2015-02-18 17:34:29 -08:00
getter_AddRefs ( sw ) ) ;
serviceWorker = sw . forget ( ) ;
}
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
nsMainThreadPtrHandle < nsIInterceptedChannel > handle (
new nsMainThreadPtrHolder < nsIInterceptedChannel > ( aChannel , false ) ) ;
nsRefPtr < ServiceWorker > sw = static_cast < ServiceWorker * > ( serviceWorker . get ( ) ) ;
nsMainThreadPtrHandle < ServiceWorker > serviceWorkerHandle (
new nsMainThreadPtrHolder < ServiceWorker > ( sw ) ) ;
2015-03-06 05:04:49 -08:00
// clientInfo is null if we don't have a controlled document
2015-02-18 17:34:29 -08:00
nsRefPtr < FetchEventRunnable > event =
2015-03-23 10:36:44 -07:00
new FetchEventRunnable ( sw - > GetWorkerPrivate ( ) , handle , serviceWorkerHandle , clientInfo , aIsReload ) ;
2015-02-18 17:34:29 -08:00
rv = event - > Init ( ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
AutoJSAPI api ;
api . Init ( ) ;
if ( NS_WARN_IF ( ! event - > Dispatch ( api . cx ( ) ) ) ) {
return NS_ERROR_FAILURE ;
}
return NS_OK ;
}
NS_IMETHODIMP
2015-05-19 12:20:15 -07:00
ServiceWorkerManager : : IsAvailableForURI ( nsIURI * aURI , bool * aIsAvailable )
2015-02-18 17:34:29 -08:00
{
MOZ_ASSERT ( aURI ) ;
MOZ_ASSERT ( aIsAvailable ) ;
nsRefPtr < ServiceWorkerRegistrationInfo > registration =
2015-05-19 12:20:15 -07:00
GetServiceWorkerRegistrationInfo ( aURI ) ;
2015-02-18 17:34:29 -08:00
* aIsAvailable = registration & & registration - > mActiveWorker ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerManager : : IsControlled ( nsIDocument * aDoc , bool * aIsControlled )
{
MOZ_ASSERT ( aDoc ) ;
MOZ_ASSERT ( aIsControlled ) ;
nsRefPtr < ServiceWorkerRegistrationInfo > registration ;
nsresult rv = GetDocumentRegistration ( aDoc , getter_AddRefs ( registration ) ) ;
2015-03-18 06:16:00 -07:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) & & rv ! = NS_ERROR_NOT_AVAILABLE ) ) {
// It's OK to ignore the case where we don't have a registration.
return rv ;
}
2015-02-18 17:34:29 -08:00
* aIsControlled = ! ! registration ;
return NS_OK ;
}
nsresult
ServiceWorkerManager : : GetDocumentRegistration ( nsIDocument * aDoc ,
ServiceWorkerRegistrationInfo * * aRegistrationInfo )
{
nsRefPtr < ServiceWorkerRegistrationInfo > registration ;
if ( ! mControlledDocuments . Get ( aDoc , getter_AddRefs ( registration ) ) ) {
2015-03-18 06:16:00 -07:00
return NS_ERROR_NOT_AVAILABLE ;
2015-02-18 17:34:29 -08:00
}
// If the document is controlled, the current worker MUST be non-null.
if ( ! registration - > mActiveWorker ) {
return NS_ERROR_NOT_AVAILABLE ;
}
registration . forget ( aRegistrationInfo ) ;
return NS_OK ;
}
2014-07-23 14:05:08 -07:00
/*
* The . controller is for the registration associated with the document when
* the document was loaded .
*/
NS_IMETHODIMP
ServiceWorkerManager : : GetDocumentController ( nsIDOMWindow * aWindow , nsISupports * * aServiceWorker )
{
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
MOZ_ASSERT ( window ) ;
if ( ! window | | ! window - > GetExtantDoc ( ) ) {
return NS_ERROR_FAILURE ;
}
nsCOMPtr < nsIDocument > doc = window - > GetExtantDoc ( ) ;
2014-08-19 06:56:00 -07:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-02-18 17:34:29 -08:00
nsresult rv = GetDocumentRegistration ( doc , getter_AddRefs ( registration ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
2015-02-18 13:00:33 -08:00
}
2014-07-23 14:05:08 -07:00
nsRefPtr < ServiceWorker > serviceWorker ;
2015-02-18 17:34:29 -08:00
rv = CreateServiceWorkerForWindow ( window ,
2015-02-19 08:40:21 -08:00
registration - > mActiveWorker ,
2015-02-18 17:34:29 -08:00
getter_AddRefs ( serviceWorker ) ) ;
2014-07-23 14:05:08 -07:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
serviceWorker . forget ( aServiceWorker ) ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerManager : : GetInstalling ( nsIDOMWindow * aWindow ,
2014-08-24 22:35:03 -07:00
const nsAString & aScope ,
2014-07-23 14:05:08 -07:00
nsISupports * * aServiceWorker )
{
2014-08-24 22:35:03 -07:00
return GetServiceWorkerForScope ( aWindow , aScope ,
WhichServiceWorker : : INSTALLING_WORKER ,
aServiceWorker ) ;
2014-07-23 14:05:08 -07:00
}
NS_IMETHODIMP
ServiceWorkerManager : : GetWaiting ( nsIDOMWindow * aWindow ,
2014-08-24 22:35:03 -07:00
const nsAString & aScope ,
2014-07-23 14:05:08 -07:00
nsISupports * * aServiceWorker )
{
2014-08-24 22:35:03 -07:00
return GetServiceWorkerForScope ( aWindow , aScope ,
WhichServiceWorker : : WAITING_WORKER ,
aServiceWorker ) ;
2014-07-23 14:05:08 -07:00
}
NS_IMETHODIMP
2014-08-24 22:35:03 -07:00
ServiceWorkerManager : : GetActive ( nsIDOMWindow * aWindow ,
const nsAString & aScope ,
nsISupports * * aServiceWorker )
2014-07-23 14:05:08 -07:00
{
2014-08-24 22:35:03 -07:00
return GetServiceWorkerForScope ( aWindow , aScope ,
WhichServiceWorker : : ACTIVE_WORKER ,
aServiceWorker ) ;
2014-07-23 14:05:08 -07:00
}
2014-07-02 17:48:50 -07:00
NS_IMETHODIMP
2015-02-17 04:36:09 -08:00
ServiceWorkerManager : : CreateServiceWorker ( nsIPrincipal * aPrincipal ,
2015-02-19 08:40:21 -08:00
ServiceWorkerInfo * aInfo ,
2014-07-02 17:48:50 -07:00
ServiceWorker * * aServiceWorker )
{
AssertIsOnMainThread ( ) ;
2015-02-17 04:36:09 -08:00
MOZ_ASSERT ( aPrincipal ) ;
2014-07-02 17:48:50 -07:00
2015-02-12 01:50:05 -08:00
WorkerLoadInfo info ;
2015-02-19 08:40:21 -08:00
nsresult rv = NS_NewURI ( getter_AddRefs ( info . mBaseURI ) , aInfo - > ScriptSpec ( ) ,
nullptr , nullptr ) ;
2014-07-02 17:48:50 -07:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
info . mResolvedScriptURI = info . mBaseURI ;
2015-03-19 16:40:52 -07:00
MOZ_ASSERT ( ! aInfo - > CacheName ( ) . IsEmpty ( ) ) ;
2015-03-19 11:41:42 -07:00
info . mServiceWorkerCacheName = aInfo - > CacheName ( ) ;
2015-05-14 12:41:42 -07:00
info . mServiceWorkerID = aInfo - > ID ( ) ;
2014-07-02 17:48:50 -07:00
rv = info . mBaseURI - > GetHost ( info . mDomain ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-02-17 04:36:09 -08:00
info . mPrincipal = aPrincipal ;
2014-12-12 08:06:00 -08:00
// NOTE: this defaults the SW load context to:
// - private browsing = false
// - content = true
// - use remote tabs = false
// Alternatively we could persist the original load group values and use
// them here.
2015-02-21 07:09:17 -08:00
WorkerPrivate : : OverrideLoadInfoLoadGroup ( info ) ;
2014-07-02 17:48:50 -07:00
2015-02-10 00:58:00 -08:00
RuntimeService * rs = RuntimeService : : GetOrCreateService ( ) ;
2014-07-02 17:48:50 -07:00
if ( ! rs ) {
return NS_ERROR_FAILURE ;
}
2014-12-19 02:00:29 -08:00
AutoJSAPI jsapi ;
jsapi . Init ( ) ;
2015-02-19 08:40:21 -08:00
nsRefPtr < SharedWorker > sharedWorker ;
rv = rs - > CreateSharedWorkerForServiceWorkerFromLoadInfo ( jsapi . cx ( ) , & info ,
NS_ConvertUTF8toUTF16 ( aInfo - > ScriptSpec ( ) ) ,
aInfo - > Scope ( ) ,
getter_AddRefs ( sharedWorker ) ) ;
2014-07-02 17:48:50 -07:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-02-19 08:40:21 -08:00
nsRefPtr < ServiceWorker > serviceWorker =
new ServiceWorker ( nullptr , aInfo , sharedWorker ) ;
2014-07-02 17:48:50 -07:00
serviceWorker . forget ( aServiceWorker ) ;
return NS_OK ;
}
2014-07-23 14:05:08 -07:00
void
2014-08-19 06:56:00 -07:00
ServiceWorkerManager : : InvalidateServiceWorkerRegistrationWorker ( ServiceWorkerRegistrationInfo * aRegistration ,
WhichServiceWorker aWhichOnes )
2014-07-23 14:05:08 -07:00
{
AssertIsOnMainThread ( ) ;
2015-04-08 13:13:32 -07:00
nsTObserverArray < ServiceWorkerRegistrationListener * > : : ForwardIterator it ( mServiceWorkerRegistrationListeners ) ;
2015-02-08 20:33:39 -08:00
while ( it . HasMore ( ) ) {
2015-04-08 13:13:32 -07:00
nsRefPtr < ServiceWorkerRegistrationListener > target = it . GetNext ( ) ;
2015-02-08 20:33:39 -08:00
nsAutoString regScope ;
target - > GetScope ( regScope ) ;
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
2014-07-23 14:05:08 -07:00
2015-02-08 20:33:39 -08:00
NS_ConvertUTF16toUTF8 utf8Scope ( regScope ) ;
2014-07-23 14:05:08 -07:00
2015-02-08 20:33:39 -08:00
if ( utf8Scope . Equals ( aRegistration - > mScope ) ) {
2015-04-08 13:13:32 -07:00
target - > InvalidateWorkers ( aWhichOnes ) ;
2014-07-23 14:05:08 -07:00
}
}
}
2014-10-06 08:45:14 -07:00
NS_IMETHODIMP
2015-05-19 12:20:15 -07:00
ServiceWorkerManager : : SoftUpdate ( const nsAString & aScope )
2014-10-06 08:45:14 -07:00
{
2015-03-19 18:09:10 -07:00
AssertIsOnMainThread ( ) ;
2014-10-06 08:45:14 -07:00
NS_ConvertUTF16toUTF8 scope ( aScope ) ;
2015-05-19 12:20:15 -07:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration ;
mServiceWorkerRegistrationInfos . Get ( scope , getter_AddRefs ( registration ) ) ;
2014-10-06 08:45:14 -07:00
if ( NS_WARN_IF ( ! registration ) ) {
return NS_OK ;
}
2015-03-19 18:09:10 -07:00
// "If registration's uninstalling flag is set, abort these steps."
2014-10-06 08:45:14 -07:00
if ( registration - > mPendingUninstall ) {
return NS_OK ;
}
2015-03-19 18:09:10 -07:00
// "If registration's installing worker is not null, abort these steps."
2014-10-06 08:45:14 -07:00
if ( registration - > mInstallingWorker ) {
return NS_OK ;
}
2015-03-19 18:09:10 -07:00
// "Let newestWorker be the result of running Get Newest Worker algorithm
// passing registration as its argument.
// If newestWorker is null, abort these steps."
nsRefPtr < ServiceWorkerInfo > newest = registration - > Newest ( ) ;
if ( ! newest ) {
return NS_OK ;
}
// "Set registration's registering script url to newestWorker's script url."
registration - > mScriptSpec = newest - > ScriptSpec ( ) ;
2015-02-08 20:33:39 -08:00
ServiceWorkerJobQueue * queue = GetOrCreateJobQueue ( scope ) ;
2014-12-19 02:00:29 -08:00
MOZ_ASSERT ( queue ) ;
nsRefPtr < ServiceWorkerUpdateFinishCallback > cb =
new ServiceWorkerUpdateFinishCallback ( ) ;
2015-03-19 18:09:10 -07:00
// "Invoke Update algorithm, or its equivalent, with client, registration as
// its argument."
2015-01-22 14:10:38 -08:00
nsRefPtr < ServiceWorkerRegisterJob > job =
new ServiceWorkerRegisterJob ( queue , registration , cb ) ;
2014-12-19 02:00:29 -08:00
queue - > Append ( job ) ;
2014-10-06 08:45:14 -07:00
return NS_OK ;
}
2014-10-27 04:03:00 -07:00
namespace {
class MOZ_STACK_CLASS FilterRegistrationData
{
public :
2015-03-06 05:04:49 -08:00
FilterRegistrationData ( nsTArray < ServiceWorkerClientInfo > & aDocuments ,
ServiceWorkerRegistrationInfo * aRegistration )
2014-10-27 04:03:00 -07:00
: mDocuments ( aDocuments ) ,
mRegistration ( aRegistration )
{
}
2015-03-06 05:04:49 -08:00
nsTArray < ServiceWorkerClientInfo > & mDocuments ;
2014-10-27 04:03:00 -07:00
nsRefPtr < ServiceWorkerRegistrationInfo > mRegistration ;
} ;
static PLDHashOperator
EnumControlledDocuments ( nsISupports * aKey ,
ServiceWorkerRegistrationInfo * aRegistration ,
void * aData )
{
FilterRegistrationData * data = static_cast < FilterRegistrationData * > ( aData ) ;
if ( data - > mRegistration ! = aRegistration ) {
return PL_DHASH_NEXT ;
}
2015-03-06 05:04:49 -08:00
2014-10-27 04:03:00 -07:00
nsCOMPtr < nsIDocument > document = do_QueryInterface ( aKey ) ;
2015-03-06 05:04:49 -08:00
if ( ! document | | ! document - > GetWindow ( ) ) {
2014-10-27 04:03:00 -07:00
return PL_DHASH_NEXT ;
}
2015-03-06 05:04:49 -08:00
ServiceWorkerClientInfo clientInfo ( document ) ;
data - > mDocuments . AppendElement ( clientInfo ) ;
2014-10-27 04:03:00 -07:00
return PL_DHASH_NEXT ;
}
2015-05-14 12:41:42 -07:00
static void
FireControllerChangeOnDocument ( nsIDocument * aDocument )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aDocument ) ;
nsCOMPtr < nsPIDOMWindow > w = aDocument - > GetWindow ( ) ;
MOZ_ASSERT ( w ) ;
auto * window = static_cast < nsGlobalWindow * > ( w . get ( ) ) ;
if ( NS_WARN_IF ( ! window ) ) {
NS_WARNING ( " No valid nsGlobalWindow " ) ;
return ;
}
ErrorResult result ;
dom : : Navigator * navigator = window - > GetNavigator ( result ) ;
if ( NS_WARN_IF ( result . Failed ( ) ) ) {
return ;
}
nsRefPtr < ServiceWorkerContainer > container = navigator - > ServiceWorker ( ) ;
container - > ControllerChanged ( result ) ;
if ( result . Failed ( ) ) {
NS_WARNING ( " Failed to dispatch controllerchange event " ) ;
}
}
2014-10-28 13:11:31 -07:00
static PLDHashOperator
FireControllerChangeOnMatchingDocument ( nsISupports * aKey ,
ServiceWorkerRegistrationInfo * aValue ,
void * aData )
{
AssertIsOnMainThread ( ) ;
ServiceWorkerRegistrationInfo * contextReg = static_cast < ServiceWorkerRegistrationInfo * > ( aData ) ;
if ( aValue ! = contextReg ) {
return PL_DHASH_NEXT ;
}
nsCOMPtr < nsIDocument > doc = do_QueryInterface ( aKey ) ;
if ( NS_WARN_IF ( ! doc ) ) {
return PL_DHASH_NEXT ;
}
2015-05-14 12:41:42 -07:00
FireControllerChangeOnDocument ( doc ) ;
2014-10-28 13:11:31 -07:00
2015-05-14 12:41:42 -07:00
return PL_DHASH_NEXT ;
}
2014-10-28 13:11:31 -07:00
2015-05-14 12:41:42 -07:00
static PLDHashOperator
ClaimMatchingClients ( nsISupportsHashKey * aKey , void * aData )
{
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
ServiceWorkerRegistrationInfo * workerRegistration =
static_cast < ServiceWorkerRegistrationInfo * > ( aData ) ;
nsCOMPtr < nsIDocument > document = do_QueryInterface ( aKey - > GetKey ( ) ) ;
swm - > MaybeClaimClient ( document , workerRegistration ) ;
2014-10-28 13:11:31 -07:00
return PL_DHASH_NEXT ;
}
2014-10-27 04:03:00 -07:00
} // anonymous namespace
void
2015-05-19 12:20:15 -07:00
ServiceWorkerManager : : GetAllClients ( const nsCString & aScope ,
2015-03-06 05:04:49 -08:00
nsTArray < ServiceWorkerClientInfo > & aControlledDocuments )
2014-10-27 04:03:00 -07:00
{
2015-05-19 12:20:15 -07:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration = GetRegistration ( aScope ) ;
2014-11-04 04:04:00 -08:00
if ( ! registration ) {
// The registration was removed, leave the array empty.
return ;
}
2014-10-27 04:03:00 -07:00
FilterRegistrationData data ( aControlledDocuments , registration ) ;
2015-02-08 20:33:39 -08:00
mControlledDocuments . EnumerateRead ( EnumControlledDocuments , & data ) ;
2014-10-27 04:03:00 -07:00
}
2015-05-14 12:41:42 -07:00
void
ServiceWorkerManager : : MaybeClaimClient ( nsIDocument * aDocument ,
ServiceWorkerRegistrationInfo * aWorkerRegistration )
{
MOZ_ASSERT ( aWorkerRegistration ) ;
MOZ_ASSERT ( aWorkerRegistration - > mActiveWorker ) ;
// Same origin check
if ( ! aWorkerRegistration - > mPrincipal - > Equals ( aDocument - > NodePrincipal ( ) ) ) {
return ;
}
// The registration that should be controlling the client
nsRefPtr < ServiceWorkerRegistrationInfo > matchingRegistration =
GetServiceWorkerRegistrationInfo ( aDocument ) ;
// The registration currently controlling the client
nsRefPtr < ServiceWorkerRegistrationInfo > controllingRegistration ;
GetDocumentRegistration ( aDocument , getter_AddRefs ( controllingRegistration ) ) ;
if ( aWorkerRegistration ! = matchingRegistration | |
aWorkerRegistration = = controllingRegistration ) {
return ;
}
if ( controllingRegistration ) {
StopControllingADocument ( controllingRegistration ) ;
}
StartControllingADocument ( aWorkerRegistration , aDocument ) ;
FireControllerChangeOnDocument ( aDocument ) ;
}
nsresult
2015-05-19 12:20:15 -07:00
ServiceWorkerManager : : ClaimClients ( const nsCString & aScope , uint64_t aId )
2015-05-14 12:41:42 -07:00
{
nsRefPtr < ServiceWorkerRegistrationInfo > registration =
2015-05-19 12:20:15 -07:00
GetRegistration ( aScope ) ;
2015-05-14 12:41:42 -07:00
if ( ! registration | | ! registration - > mActiveWorker | |
! ( registration - > mActiveWorker - > ID ( ) = = aId ) ) {
// The worker is not active.
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
mAllDocuments . EnumerateEntries ( ClaimMatchingClients , registration ) ;
return NS_OK ;
}
2014-12-19 02:00:29 -08:00
void
ServiceWorkerManager : : FireControllerChange ( ServiceWorkerRegistrationInfo * aRegistration )
{
2015-02-08 20:33:39 -08:00
mControlledDocuments . EnumerateRead ( FireControllerChangeOnMatchingDocument , aRegistration ) ;
2014-12-19 02:00:29 -08:00
}
2015-02-08 20:33:39 -08:00
ServiceWorkerRegistrationInfo *
2015-02-11 03:53:00 -08:00
ServiceWorkerManager : : CreateNewRegistration ( const nsCString & aScope ,
nsIPrincipal * aPrincipal )
2015-02-08 20:33:39 -08:00
{
# ifdef DEBUG
AssertIsOnMainThread ( ) ;
nsCOMPtr < nsIURI > scopeURI ;
nsresult rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , aScope , nullptr , nullptr ) ;
MOZ_ASSERT ( NS_SUCCEEDED ( rv ) ) ;
# endif
2015-02-11 03:53:00 -08:00
ServiceWorkerRegistrationInfo * registration = new ServiceWorkerRegistrationInfo ( aScope , aPrincipal ) ;
2015-02-08 20:33:39 -08:00
// From now on ownership of registration is with
// mServiceWorkerRegistrationInfos.
2015-05-19 12:20:15 -07:00
mServiceWorkerRegistrationInfos . Put ( aScope , registration ) ;
AddScope ( mOrderedScopes , aScope ) ;
2015-02-08 20:33:39 -08:00
return registration ;
}
2015-02-10 14:33:23 -08:00
void
ServiceWorkerManager : : MaybeRemoveRegistration ( ServiceWorkerRegistrationInfo * aRegistration )
{
MOZ_ASSERT ( aRegistration ) ;
nsRefPtr < ServiceWorkerInfo > newest = aRegistration - > Newest ( ) ;
if ( ! newest ) {
RemoveRegistration ( aRegistration ) ;
}
}
2015-02-11 10:51:32 -08:00
void
2015-03-05 17:37:49 -08:00
ServiceWorkerManager : : RemoveRegistrationInternal ( ServiceWorkerRegistrationInfo * aRegistration )
2015-02-11 10:51:32 -08:00
{
MOZ_ASSERT ( aRegistration ) ;
MOZ_ASSERT ( ! aRegistration - > IsControllingDocuments ( ) ) ;
2015-05-19 12:20:15 -07:00
MOZ_ASSERT ( mServiceWorkerRegistrationInfos . Contains ( aRegistration - > mScope ) ) ;
ServiceWorkerManager : : RemoveScope ( mOrderedScopes , aRegistration - > mScope ) ;
2015-02-11 10:51:32 -08:00
// All callers should be either from a job in which case the actor is
// available, or from MaybeStopControlling(), in which case, this will only be
// called if a valid registration is found. If a valid registration exists,
// it means the actor is available since the original map of registrations is
// populated by it, and any new registrations wait until the actor is
// available before proceeding (See ServiceWorkerRegisterJob::Start).
MOZ_ASSERT ( mActor ) ;
PrincipalInfo principalInfo ;
2015-03-05 17:37:49 -08:00
if ( NS_WARN_IF ( NS_FAILED ( PrincipalToPrincipalInfo ( aRegistration - > mPrincipal ,
2015-02-11 10:51:32 -08:00
& principalInfo ) ) ) ) {
//XXXnsm I can't think of any other reason a stored principal would fail to
//convert.
NS_WARNING ( " Unable to unregister serviceworker due to possible OOM " ) ;
return ;
}
2015-05-19 12:20:15 -07:00
mActor - > SendUnregisterServiceWorker ( principalInfo , NS_ConvertUTF8toUTF16 ( aRegistration - > mScope ) ) ;
2015-02-11 10:51:32 -08:00
}
2015-02-19 08:40:21 -08:00
2015-04-10 01:50:06 -07:00
class ServiceWorkerDataInfo final : public nsIServiceWorkerInfo
{
public :
NS_DECL_ISUPPORTS
NS_DECL_NSISERVICEWORKERINFO
static already_AddRefed < ServiceWorkerDataInfo >
Create ( const ServiceWorkerRegistrationData & aData ) ;
private :
ServiceWorkerDataInfo ( )
{ }
~ ServiceWorkerDataInfo ( )
{ }
nsCOMPtr < nsIPrincipal > mPrincipal ;
nsString mScope ;
nsString mScriptSpec ;
nsString mCurrentWorkerURL ;
nsString mActiveCacheName ;
nsString mWaitingCacheName ;
} ;
2015-03-05 17:37:49 -08:00
void
ServiceWorkerManager : : RemoveRegistration ( ServiceWorkerRegistrationInfo * aRegistration )
{
RemoveRegistrationInternal ( aRegistration ) ;
2015-05-19 12:20:15 -07:00
MOZ_ASSERT ( mServiceWorkerRegistrationInfos . Contains ( aRegistration - > mScope ) ) ;
mServiceWorkerRegistrationInfos . Remove ( aRegistration - > mScope ) ;
2015-03-05 17:37:49 -08:00
}
2015-04-10 01:50:06 -07:00
2015-03-05 17:37:49 -08:00
namespace {
/**
* See browser / components / sessionstore / Utils . jsm function hasRootDomain ( ) .
*
* Returns true if the | url | passed in is part of the given root | domain | .
* For example , if | url | is " www.mozilla.org " , and we pass in | domain | as
* " mozilla.org " , this will return true . It would return false the other way
* around .
*/
bool
HasRootDomain ( nsIURI * aURI , const nsACString & aDomain )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aURI ) ;
nsAutoCString host ;
nsresult rv = aURI - > GetHost ( host ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return false ;
}
nsACString : : const_iterator start , end ;
host . BeginReading ( start ) ;
host . EndReading ( end ) ;
if ( ! FindInReadable ( aDomain , start , end ) ) {
return false ;
}
if ( host . Equals ( aDomain ) ) {
return true ;
}
// Beginning of the string matches, can't look at the previous char.
if ( start . get ( ) = = host . BeginReading ( ) ) {
// Equals failed so this is fine.
return false ;
}
char prevChar = * ( - - start ) ;
return prevChar = = ' . ' ;
}
// If host/aData is null, unconditionally unregisters.
PLDHashOperator
UnregisterIfMatchesHost ( const nsACString & aScope ,
ServiceWorkerRegistrationInfo * aReg ,
void * aData )
{
// We avoid setting toRemove = aReg by default since there is a possibility
// of failure when aData is passed, in which case we don't want to remove the
// registration.
ServiceWorkerRegistrationInfo * toRemove = nullptr ;
if ( aData ) {
const nsACString & domain = * static_cast < nsACString * > ( aData ) ;
nsCOMPtr < nsIURI > scopeURI ;
nsresult rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , aScope , nullptr , nullptr ) ;
// This way subdomains are also cleared.
if ( NS_SUCCEEDED ( rv ) & & HasRootDomain ( scopeURI , domain ) ) {
toRemove = aReg ;
}
} else {
toRemove = aReg ;
}
if ( toRemove ) {
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
swm - > ForceUnregister ( toRemove ) ;
}
return PL_DHASH_NEXT ;
}
} // anonymous namespace
2015-04-10 01:50:06 -07:00
NS_IMPL_ISUPPORTS ( ServiceWorkerDataInfo , nsIServiceWorkerInfo )
/* static */ already_AddRefed < ServiceWorkerDataInfo >
ServiceWorkerDataInfo : : Create ( const ServiceWorkerRegistrationData & aData )
{
AssertIsOnMainThread ( ) ;
nsRefPtr < ServiceWorkerDataInfo > info = new ServiceWorkerDataInfo ( ) ;
info - > mPrincipal = PrincipalInfoToPrincipal ( aData . principal ( ) ) ;
if ( ! info - > mPrincipal ) {
return nullptr ;
}
CopyUTF8toUTF16 ( aData . scope ( ) , info - > mScope ) ;
CopyUTF8toUTF16 ( aData . scriptSpec ( ) , info - > mScriptSpec ) ;
CopyUTF8toUTF16 ( aData . currentWorkerURL ( ) , info - > mCurrentWorkerURL ) ;
info - > mActiveCacheName = aData . activeCacheName ( ) ;
info - > mWaitingCacheName = aData . waitingCacheName ( ) ;
return info . forget ( ) ;
}
NS_IMETHODIMP
ServiceWorkerDataInfo : : GetPrincipal ( nsIPrincipal * * aPrincipal )
{
AssertIsOnMainThread ( ) ;
NS_ADDREF ( * aPrincipal = mPrincipal ) ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerDataInfo : : GetScope ( nsAString & aScope )
{
AssertIsOnMainThread ( ) ;
aScope = mScope ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerDataInfo : : GetScriptSpec ( nsAString & aScriptSpec )
{
AssertIsOnMainThread ( ) ;
aScriptSpec = mScriptSpec ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerDataInfo : : GetCurrentWorkerURL ( nsAString & aCurrentWorkerURL )
{
AssertIsOnMainThread ( ) ;
aCurrentWorkerURL = mCurrentWorkerURL ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerDataInfo : : GetActiveCacheName ( nsAString & aActiveCacheName )
{
AssertIsOnMainThread ( ) ;
aActiveCacheName = mActiveCacheName ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerDataInfo : : GetWaitingCacheName ( nsAString & aWaitingCacheName )
{
AssertIsOnMainThread ( ) ;
aWaitingCacheName = mWaitingCacheName ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerManager : : GetAllRegistrations ( nsIArray * * aResult )
{
AssertIsOnMainThread ( ) ;
nsRefPtr < ServiceWorkerRegistrar > swr = ServiceWorkerRegistrar : : Get ( ) ;
MOZ_ASSERT ( swr ) ;
nsTArray < ServiceWorkerRegistrationData > data ;
swr - > GetRegistrations ( data ) ;
nsCOMPtr < nsIMutableArray > array ( do_CreateInstance ( NS_ARRAY_CONTRACTID ) ) ;
if ( ! array ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
for ( uint32_t i = 0 , len = data . Length ( ) ; i < len ; + + i ) {
nsCOMPtr < nsIServiceWorkerInfo > info = ServiceWorkerDataInfo : : Create ( data [ i ] ) ;
if ( ! info ) {
return NS_ERROR_FAILURE ;
}
array - > AppendElement ( info , false ) ;
}
array . forget ( aResult ) ;
return NS_OK ;
}
2015-03-05 17:37:49 -08:00
// MUST ONLY BE CALLED FROM UnregisterIfMatchesHost!
void
ServiceWorkerManager : : ForceUnregister ( ServiceWorkerRegistrationInfo * aRegistration )
{
MOZ_ASSERT ( aRegistration ) ;
ServiceWorkerJobQueue * mQueue ;
mJobQueues . Get ( aRegistration - > mScope , & mQueue ) ;
if ( mQueue ) {
mQueue - > CancelJobs ( ) ;
}
// Since Unregister is async, it is ok to call it in an enumeration.
Unregister ( aRegistration - > mPrincipal , nullptr , NS_ConvertUTF8toUTF16 ( aRegistration - > mScope ) ) ;
}
NS_IMETHODIMP
ServiceWorkerManager : : Remove ( const nsACString & aHost )
{
AssertIsOnMainThread ( ) ;
2015-05-19 12:20:15 -07:00
mServiceWorkerRegistrationInfos . EnumerateRead ( UnregisterIfMatchesHost , & const_cast < nsACString & > ( aHost ) ) ;
2015-03-05 17:37:49 -08:00
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerManager : : RemoveAll ( )
{
AssertIsOnMainThread ( ) ;
2015-05-19 12:20:15 -07:00
mServiceWorkerRegistrationInfos . EnumerateRead ( UnregisterIfMatchesHost , nullptr ) ;
2015-03-05 17:37:49 -08:00
return NS_OK ;
}
2015-04-13 10:36:06 -07:00
static PLDHashOperator
UpdateEachRegistration ( const nsACString & aKey ,
ServiceWorkerRegistrationInfo * aInfo ,
void * aUserArg ) {
auto This = static_cast < ServiceWorkerManager * > ( aUserArg ) ;
MOZ_ASSERT ( ! aInfo - > mScope . IsEmpty ( ) ) ;
2015-05-19 12:20:15 -07:00
nsresult res = This - > SoftUpdate ( NS_ConvertUTF8toUTF16 ( aInfo - > mScope ) ) ;
2015-04-13 10:36:06 -07:00
unused < < NS_WARN_IF ( NS_FAILED ( res ) ) ;
return PL_DHASH_NEXT ;
}
NS_IMETHODIMP
ServiceWorkerManager : : UpdateAllRegistrations ( )
{
AssertIsOnMainThread ( ) ;
2015-05-19 12:20:15 -07:00
mServiceWorkerRegistrationInfos . EnumerateRead ( UpdateEachRegistration , this ) ;
2015-04-13 10:36:06 -07:00
return NS_OK ;
}
2015-03-05 17:37:49 -08:00
NS_IMETHODIMP
ServiceWorkerManager : : Observe ( nsISupports * aSubject ,
const char * aTopic ,
const char16_t * aData )
{
MOZ_ASSERT ( XRE_GetProcessType ( ) = = GeckoProcessType_Default ) ;
nsAutoTArray < ContentParent * , 1 > children ;
ContentParent : : GetAll ( children ) ;
if ( strcmp ( aTopic , PURGE_SESSION_HISTORY ) = = 0 ) {
for ( uint32_t i = 0 ; i < children . Length ( ) ; i + + ) {
unused < < children [ i ] - > SendRemoveServiceWorkerRegistrations ( ) ;
}
RemoveAll ( ) ;
} else if ( strcmp ( aTopic , PURGE_DOMAIN_DATA ) = = 0 ) {
nsAutoString domain ( aData ) ;
for ( uint32_t i = 0 ; i < children . Length ( ) ; i + + ) {
unused < < children [ i ] - > SendRemoveServiceWorkerRegistrationsForDomain ( domain ) ;
}
Remove ( NS_ConvertUTF16toUTF8 ( domain ) ) ;
} else if ( strcmp ( aTopic , NS_XPCOM_SHUTDOWN_OBSERVER_ID ) = = 0 ) {
nsCOMPtr < nsIObserverService > obs = mozilla : : services : : GetObserverService ( ) ;
if ( obs ) {
obs - > RemoveObserver ( this , NS_XPCOM_SHUTDOWN_OBSERVER_ID ) ;
obs - > RemoveObserver ( this , PURGE_SESSION_HISTORY ) ;
obs - > RemoveObserver ( this , PURGE_DOMAIN_DATA ) ;
}
} else {
MOZ_CRASH ( " Received message we aren't supposed to be registered for! " ) ;
}
return NS_OK ;
}
2015-02-19 08:40:21 -08:00
void
ServiceWorkerInfo : : AppendWorker ( ServiceWorker * aWorker )
{
MOZ_ASSERT ( aWorker ) ;
# ifdef DEBUG
nsAutoString workerURL ;
aWorker - > GetScriptURL ( workerURL ) ;
MOZ_ASSERT ( workerURL . Equals ( NS_ConvertUTF8toUTF16 ( mScriptSpec ) ) ) ;
# endif
MOZ_ASSERT ( ! mInstances . Contains ( aWorker ) ) ;
mInstances . AppendElement ( aWorker ) ;
aWorker - > SetState ( State ( ) ) ;
}
void
ServiceWorkerInfo : : RemoveWorker ( ServiceWorker * aWorker )
{
MOZ_ASSERT ( aWorker ) ;
# ifdef DEBUG
nsAutoString workerURL ;
aWorker - > GetScriptURL ( workerURL ) ;
MOZ_ASSERT ( workerURL . Equals ( NS_ConvertUTF8toUTF16 ( mScriptSpec ) ) ) ;
# endif
MOZ_ASSERT ( mInstances . Contains ( aWorker ) ) ;
mInstances . RemoveElement ( aWorker ) ;
}
void
ServiceWorkerInfo : : UpdateState ( ServiceWorkerState aState )
{
# ifdef DEBUG
// Any state can directly transition to redundant, but everything else is
// ordered.
if ( aState ! = ServiceWorkerState : : Redundant ) {
MOZ_ASSERT_IF ( mState = = ServiceWorkerState : : EndGuard_ , aState = = ServiceWorkerState : : Installing ) ;
MOZ_ASSERT_IF ( mState = = ServiceWorkerState : : Installing , aState = = ServiceWorkerState : : Installed ) ;
MOZ_ASSERT_IF ( mState = = ServiceWorkerState : : Installed , aState = = ServiceWorkerState : : Activating ) ;
MOZ_ASSERT_IF ( mState = = ServiceWorkerState : : Activating , aState = = ServiceWorkerState : : Activated ) ;
}
// Activated can only go to redundant.
MOZ_ASSERT_IF ( mState = = ServiceWorkerState : : Activated , aState = = ServiceWorkerState : : Redundant ) ;
# endif
mState = aState ;
for ( uint32_t i = 0 ; i < mInstances . Length ( ) ; + + i ) {
mInstances [ i ] - > QueueStateChangeEvent ( mState ) ;
}
}
2015-05-14 12:41:42 -07:00
static uint64_t gServiceWorkerInfoCurrentID = 0 ;
uint64_t
ServiceWorkerInfo : : GetNextID ( ) const
{
return + + gServiceWorkerInfoCurrentID ;
}
2013-11-19 15:15:02 -08:00
END_WORKERS_NAMESPACE