2013-11-20 03:15:02 +04: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 14:53:00 +03:00
# include "nsIAppsService.h"
2014-07-15 01:15:23 +04:00
# include "nsIDOMEventTarget.h"
2013-11-20 03:15:02 +04:00
# include "nsIDocument.h"
2014-07-03 04:48:50 +04:00
# include "nsIScriptSecurityManager.h"
2014-12-19 13:00:29 +03:00
# include "nsIStreamLoader.h"
# include "nsIHttpChannel.h"
# include "nsIHttpChannelInternal.h"
2015-02-19 04:34:29 +03:00
# include "nsIHttpHeaderVisitor.h"
# include "nsINetworkInterceptController.h"
2013-11-20 03:15:02 +04:00
# include "nsPIDOMWindow.h"
2015-02-19 04:34:29 +03:00
# include "nsDebug.h"
2013-11-20 03:15:02 +04:00
# include "jsapi.h"
2014-12-12 19:06:00 +03:00
# include "mozilla/LoadContext.h"
2013-11-20 03:15:02 +04:00
# include "mozilla/dom/BindingUtils.h"
2014-06-11 20:12:56 +04:00
# include "mozilla/dom/DOMError.h"
2014-07-03 04:48:35 +04:00
# include "mozilla/dom/ErrorEvent.h"
2015-02-19 04:34:29 +03:00
# include "mozilla/dom/Headers.h"
2014-07-03 04:48:50 +04:00
# include "mozilla/dom/InstallEventBinding.h"
2015-02-19 04:34:29 +03:00
# include "mozilla/dom/InternalHeaders.h"
2014-10-28 23:11:31 +03:00
# include "mozilla/dom/Navigator.h"
2014-07-03 04:48:50 +04:00
# include "mozilla/dom/PromiseNativeHandler.h"
2015-02-19 04:34:29 +03:00
# include "mozilla/dom/Request.h"
# include "mozilla/dom/RootedDictionary.h"
2015-02-11 14:53:00 +03:00
# include "mozilla/ipc/BackgroundChild.h"
# include "mozilla/ipc/PBackgroundChild.h"
# include "mozilla/ipc/PBackgroundSharedTypes.h"
2014-06-11 20:12:56 +04:00
2013-11-20 03:15:02 +04:00
# include "nsContentUtils.h"
2014-10-28 23:11:31 +03:00
# include "nsGlobalWindow.h"
2013-11-20 03:15:02 +04:00
# include "nsNetUtil.h"
2014-06-11 20:12:56 +04:00
# include "nsProxyRelease.h"
2013-11-20 03:15:02 +04:00
# include "nsTArray.h"
# include "RuntimeService.h"
# include "ServiceWorker.h"
2014-10-27 14:03:00 +03:00
# include "ServiceWorkerClient.h"
2014-10-28 23:11:31 +03:00
# include "ServiceWorkerContainer.h"
2014-08-19 17:56:00 +04:00
# include "ServiceWorkerRegistration.h"
2014-07-03 04:48:50 +04:00
# include "ServiceWorkerEvents.h"
2013-11-20 03:15:02 +04:00
# include "WorkerInlines.h"
2014-06-11 20:12:56 +04:00
# include "WorkerPrivate.h"
# include "WorkerRunnable.h"
2014-07-03 04:48:50 +04:00
# include "WorkerScope.h"
2013-11-20 03:15:02 +04:00
2014-12-12 19:06:00 +03:00
# ifdef PostMessage
# undef PostMessage
# endif
2013-11-20 03:15:02 +04:00
using namespace mozilla ;
using namespace mozilla : : dom ;
2015-02-11 14:53:00 +03:00
using namespace mozilla : : ipc ;
2013-11-20 03:15:02 +04:00
BEGIN_WORKERS_NAMESPACE
2015-02-11 14:53:00 +03: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 ( ) ;
}
return NS_OK ;
}
} // Anonymous namespace
2014-12-19 13:00:29 +03:00
NS_IMPL_ISUPPORTS0 ( ServiceWorkerJob )
2014-08-19 17:56:00 +04:00
NS_IMPL_ISUPPORTS0 ( ServiceWorkerRegistrationInfo )
2014-06-11 20:12:56 +04:00
void
2014-12-19 13:00:29 +03:00
ServiceWorkerJob : : Done ( nsresult aStatus )
2014-06-11 20:12:56 +04:00
{
2014-12-19 13:00:29 +03:00
if ( NS_WARN_IF ( NS_FAILED ( aStatus ) ) ) {
// Windows builds complain if the return value of NS_WARN_IF isn't used.
2014-06-11 20:12:56 +04:00
}
2014-07-03 04:48:35 +04:00
2014-12-19 13:00:29 +03:00
if ( mQueue ) {
mQueue - > Done ( this ) ;
2014-07-03 04:48:35 +04:00
}
}
2014-07-14 21:33:44 +04:00
void
ServiceWorkerRegistrationInfo : : Clear ( )
{
if ( mInstallingWorker ) {
// FIXME(nsm): Terminate installing worker.
2014-12-19 14:25:56 +03:00
mInstallingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2014-07-14 21:33:44 +04:00
mInstallingWorker = nullptr ;
// FIXME(nsm): Abort any inflight requests from installing worker.
}
if ( mWaitingWorker ) {
2014-12-19 14:25:56 +03:00
mWaitingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2014-07-14 21:33:44 +04:00
// Fire statechange.
mWaitingWorker = nullptr ;
}
2014-12-19 13:00:29 +03:00
if ( mActiveWorker ) {
2014-12-19 14:25:56 +03:00
mActiveWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2014-12-19 13:00:29 +03:00
mActiveWorker = nullptr ;
2014-07-14 21:33:44 +04:00
}
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
MOZ_ASSERT ( swm ) ;
swm - > InvalidateServiceWorkerRegistrationWorker ( this ,
WhichServiceWorker : : INSTALLING_WORKER |
WhichServiceWorker : : WAITING_WORKER |
WhichServiceWorker : : ACTIVE_WORKER ) ;
}
2015-02-11 14:53:00 +03:00
ServiceWorkerRegistrationInfo : : ServiceWorkerRegistrationInfo ( const nsACString & aScope ,
nsIPrincipal * aPrincipal )
: mControlledDocumentsCounter ( 0 )
, mScope ( aScope )
, mPrincipal ( aPrincipal )
, mPendingUninstall ( false )
2014-12-19 13:00:29 +03:00
{ }
2014-06-11 20:12:56 +04:00
2014-12-19 13:00:29 +03:00
ServiceWorkerRegistrationInfo : : ~ ServiceWorkerRegistrationInfo ( )
2014-06-11 20:12:56 +04:00
{
2014-12-19 13:00:29 +03: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 20:12:56 +04:00
}
2014-12-19 13:00:29 +03:00
}
2014-06-11 20:12:56 +04:00
2013-11-20 03:15:02 +04:00
//////////////////////////
// ServiceWorkerManager //
//////////////////////////
NS_IMPL_ADDREF ( ServiceWorkerManager )
NS_IMPL_RELEASE ( ServiceWorkerManager )
NS_INTERFACE_MAP_BEGIN ( ServiceWorkerManager )
NS_INTERFACE_MAP_ENTRY ( nsIServiceWorkerManager )
2015-02-11 14:53:00 +03:00
NS_INTERFACE_MAP_ENTRY ( nsIIPCBackgroundChildCreateCallback )
2013-11-20 03:15:02 +04: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 14:53:00 +03:00
: mActor ( nullptr )
2013-11-20 03:15:02 +04:00
{
2015-02-11 14:53:00 +03: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 ) ;
}
2013-11-20 03:15:02 +04:00
}
ServiceWorkerManager : : ~ ServiceWorkerManager ( )
{
// The map will assert if it is not empty when destroyed.
2015-02-09 07:33:39 +03:00
mServiceWorkerRegistrationInfos . Clear ( ) ;
2013-11-20 03:15:02 +04:00
}
2014-12-19 16:01:53 +03:00
class ContinueLifecycleTask : public nsISupports
2014-12-19 13:00:29 +03:00
{
2014-12-19 16:01:53 +03:00
NS_DECL_ISUPPORTS
protected :
virtual ~ ContinueLifecycleTask ( )
{ }
public :
virtual void ContinueAfterWorkerEvent ( bool aSuccess ,
bool aActivateImmediately ) = 0 ;
} ;
NS_IMPL_ISUPPORTS0 ( ContinueLifecycleTask ) ;
2015-02-11 01:33:23 +03:00
class ServiceWorkerRegisterJob ;
2014-12-19 16:01:53 +03:00
class ContinueInstallTask MOZ_FINAL : public ContinueLifecycleTask
{
nsRefPtr < ServiceWorkerRegisterJob > mJob ;
public :
explicit ContinueInstallTask ( ServiceWorkerRegisterJob * aJob )
: mJob ( aJob )
{ }
void ContinueAfterWorkerEvent ( bool aSuccess , bool aActivateImmediately ) MOZ_OVERRIDE ;
} ;
class ContinueActivateTask MOZ_FINAL : public ContinueLifecycleTask
{
nsRefPtr < ServiceWorkerRegistrationInfo > mRegistration ;
public :
explicit ContinueActivateTask ( ServiceWorkerRegistrationInfo * aReg )
: mRegistration ( aReg )
{ }
void
2015-02-11 01:33:23 +03:00
ContinueAfterWorkerEvent ( bool aSuccess , bool aActivateImmediately /* unused */ ) MOZ_OVERRIDE ;
2014-12-19 16:01:53 +03:00
} ;
class ContinueLifecycleRunnable MOZ_FINAL : public nsRunnable
{
nsMainThreadPtrHandle < ContinueLifecycleTask > mTask ;
2014-12-19 13:00:29 +03:00
bool mSuccess ;
bool mActivateImmediately ;
public :
2014-12-19 16:01:53 +03:00
ContinueLifecycleRunnable ( const nsMainThreadPtrHandle < ContinueLifecycleTask > & aTask ,
bool aSuccess ,
bool aActivateImmediately )
: mTask ( aTask )
2014-12-19 13:00:29 +03:00
, mSuccess ( aSuccess )
, mActivateImmediately ( aActivateImmediately )
{
MOZ_ASSERT ( ! NS_IsMainThread ( ) ) ;
}
NS_IMETHOD
2014-12-19 16:01:53 +03:00
Run ( ) MOZ_OVERRIDE
{
AssertIsOnMainThread ( ) ;
mTask - > ContinueAfterWorkerEvent ( mSuccess , mActivateImmediately ) ;
return NS_OK ;
}
2014-12-19 13:00:29 +03:00
} ;
2013-11-20 03:15:02 +04:00
/*
2014-12-19 13:00:29 +03: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-20 03:15:02 +04:00
*/
2014-12-19 16:01:53 +03:00
class LifecycleEventWorkerRunnable MOZ_FINAL : public WorkerRunnable
2013-11-20 03:15:02 +04:00
{
2014-12-19 16:01:53 +03:00
nsString mEventName ;
nsMainThreadPtrHandle < ContinueLifecycleTask > mTask ;
2014-12-19 13:00:29 +03:00
2013-11-20 03:15:02 +04:00
public :
2014-12-19 16:01:53 +03:00
LifecycleEventWorkerRunnable ( WorkerPrivate * aWorkerPrivate ,
const nsString & aEventName ,
const nsMainThreadPtrHandle < ContinueLifecycleTask > & aTask )
: WorkerRunnable ( aWorkerPrivate , WorkerThreadModifyBusyCount )
, mEventName ( aEventName )
, mTask ( aTask )
2014-12-19 13:00:29 +03:00
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWorkerPrivate ) ;
}
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
bool
2014-12-19 16:01:53 +03:00
WorkerRun ( JSContext * aCx , WorkerPrivate * aWorkerPrivate ) MOZ_OVERRIDE
2013-11-20 03:15:02 +04:00
{
2014-12-19 13:00:29 +03:00
MOZ_ASSERT ( aWorkerPrivate ) ;
2014-12-19 16:01:53 +03:00
return DispatchLifecycleEvent ( aCx , aWorkerPrivate ) ;
2014-12-19 13:00:29 +03:00
}
2014-07-21 10:25:44 +04:00
2014-12-19 13:00:29 +03:00
private :
bool
2014-12-19 16:01:53 +03:00
DispatchLifecycleEvent ( JSContext * aCx , WorkerPrivate * aWorkerPrivate ) ;
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
} ;
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
class ServiceWorkerUpdateFinishCallback
{
protected :
virtual ~ ServiceWorkerUpdateFinishCallback ( )
{ }
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
public :
NS_INLINE_DECL_REFCOUNTING ( ServiceWorkerUpdateFinishCallback )
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
virtual
void UpdateSucceeded ( ServiceWorkerRegistrationInfo * aInfo )
{ }
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
virtual
void UpdateFailed ( nsresult aStatus )
{ }
2014-12-19 13:48:31 +03:00
virtual
void UpdateFailed ( const ErrorEventInit & aDesc )
{ }
2014-12-19 13:00:29 +03:00
} ;
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
class ServiceWorkerResolveWindowPromiseOnUpdateCallback MOZ_FINAL : public ServiceWorkerUpdateFinishCallback
{
nsRefPtr < nsPIDOMWindow > mWindow ;
// The promise "returned" by the call to Update up to
// navigator.serviceWorker.register().
nsRefPtr < Promise > mPromise ;
2014-06-11 20:12:56 +04:00
2014-12-19 13:00:29 +03:00
~ ServiceWorkerResolveWindowPromiseOnUpdateCallback ( )
{ }
2014-06-11 20:12:56 +04:00
2014-12-19 13:00:29 +03:00
public :
ServiceWorkerResolveWindowPromiseOnUpdateCallback ( nsPIDOMWindow * aWindow , Promise * aPromise )
: mWindow ( aWindow )
, mPromise ( aPromise )
{
}
void
UpdateSucceeded ( ServiceWorkerRegistrationInfo * aInfo ) MOZ_OVERRIDE
{
nsRefPtr < ServiceWorkerRegistration > swr =
new ServiceWorkerRegistration ( mWindow ,
NS_ConvertUTF8toUTF16 ( aInfo - > mScope ) ) ;
mPromise - > MaybeResolve ( swr ) ;
}
void
UpdateFailed ( nsresult aStatus ) MOZ_OVERRIDE
{
mPromise - > MaybeReject ( aStatus ) ;
2013-11-20 03:15:02 +04:00
}
2014-12-19 13:48:31 +03:00
void
UpdateFailed ( const ErrorEventInit & aErrorDesc ) MOZ_OVERRIDE
{
AutoJSAPI jsapi ;
jsapi . Init ( mWindow ) ;
JSContext * cx = jsapi . cx ( ) ;
JS : : Rooted < JSString * > stack ( cx , JS_GetEmptyString ( JS_GetRuntime ( 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 ) ;
if ( ! JS : : CreateError ( cx , JSEXN_ERR , stack , fn , aErrorDesc . mLineno ,
aErrorDesc . mColno , nullptr , msg , & error ) ) {
JS_ClearPendingException ( cx ) ;
mPromise - > MaybeReject ( NS_ERROR_DOM_ABORT_ERR ) ;
return ;
}
mPromise - > MaybeReject ( cx , error ) ;
}
} ;
class ContinueUpdateRunnable MOZ_FINAL : public nsRunnable
{
nsMainThreadPtrHandle < nsISupports > mJob ;
public :
explicit ContinueUpdateRunnable ( const nsMainThreadPtrHandle < nsISupports > aJob )
: mJob ( aJob )
{
MOZ_ASSERT ( ! NS_IsMainThread ( ) ) ;
}
NS_IMETHOD Run ( ) ;
} ;
class CheckWorkerEvaluationAndContinueUpdateWorkerRunnable MOZ_FINAL : public WorkerRunnable
{
const nsMainThreadPtrHandle < nsISupports > mJob ;
public :
CheckWorkerEvaluationAndContinueUpdateWorkerRunnable ( WorkerPrivate * aWorkerPrivate ,
const nsMainThreadPtrHandle < nsISupports > aJob )
: WorkerRunnable ( aWorkerPrivate , WorkerThreadUnchangedBusyCount )
, mJob ( aJob )
{
AssertIsOnMainThread ( ) ;
}
bool
WorkerRun ( JSContext * aCx , WorkerPrivate * aWorkerPrivate )
{
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-20 03:15:02 +04:00
} ;
2014-12-19 13:00:29 +03:00
class ServiceWorkerRegisterJob MOZ_FINAL : public ServiceWorkerJob ,
public nsIStreamLoaderObserver
2013-11-20 03:15:02 +04:00
{
2014-12-19 16:01:53 +03:00
friend class ContinueInstallTask ;
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
nsCString mScope ;
nsCString mScriptSpec ;
nsRefPtr < ServiceWorkerRegistrationInfo > mRegistration ;
nsRefPtr < ServiceWorkerUpdateFinishCallback > mCallback ;
2015-02-11 14:53:00 +03:00
nsCOMPtr < nsIPrincipal > mPrincipal ;
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
~ ServiceWorkerRegisterJob ( )
{ }
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
enum
{
REGISTER_JOB = 0 ,
UPDATE_JOB = 1 ,
} mJobType ;
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
public :
NS_DECL_ISUPPORTS
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
// [[Register]]
ServiceWorkerRegisterJob ( ServiceWorkerJobQueue * aQueue ,
const nsCString & aScope ,
const nsCString & aScriptSpec ,
2015-02-11 14:53:00 +03:00
ServiceWorkerUpdateFinishCallback * aCallback ,
nsIPrincipal * aPrincipal )
2014-12-19 13:00:29 +03:00
: ServiceWorkerJob ( aQueue )
, mScope ( aScope )
, mScriptSpec ( aScriptSpec )
, mCallback ( aCallback )
2015-02-11 14:53:00 +03:00
, mPrincipal ( aPrincipal )
2014-12-19 13:00:29 +03:00
, mJobType ( REGISTER_JOB )
{ }
2014-08-22 03:31:12 +04:00
2014-12-19 13:00:29 +03:00
// [[Update]]
ServiceWorkerRegisterJob ( ServiceWorkerJobQueue * aQueue ,
ServiceWorkerRegistrationInfo * aRegistration ,
ServiceWorkerUpdateFinishCallback * aCallback )
: ServiceWorkerJob ( aQueue )
, mRegistration ( aRegistration )
, mCallback ( aCallback )
, mJobType ( UPDATE_JOB )
{ }
2014-09-03 00:07:55 +04:00
2014-12-19 13:00:29 +03:00
void
Start ( ) MOZ_OVERRIDE
{
2015-02-11 14:53:00 +03:00
MOZ_ASSERT ( NS_IsMainThread ( ) ) ;
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
if ( ! swm - > HasBackgroundActor ( ) ) {
nsCOMPtr < nsIRunnable > runnable =
NS_NewRunnableMethod ( this , & ServiceWorkerRegisterJob : : Start ) ;
swm - > AppendPendingOperation ( runnable ) ;
return ;
}
2014-12-19 13:00:29 +03:00
if ( mJobType = = REGISTER_JOB ) {
2015-02-09 07:33:39 +03:00
mRegistration = swm - > GetRegistration ( mScope ) ;
2014-12-19 13:00:29 +03:00
if ( mRegistration ) {
nsRefPtr < ServiceWorkerInfo > newest = mRegistration - > Newest ( ) ;
2014-12-19 14:25:56 +03:00
if ( newest & & mScriptSpec . Equals ( newest - > ScriptSpec ( ) ) & &
2014-12-19 13:00:29 +03:00
mScriptSpec . Equals ( mRegistration - > mScriptSpec ) ) {
mRegistration - > mPendingUninstall = false ;
Succeed ( ) ;
Done ( NS_OK ) ;
return ;
}
} else {
2015-02-11 14:53:00 +03:00
mRegistration = swm - > CreateNewRegistration ( mScope , mPrincipal ) ;
2014-12-19 13:00:29 +03:00
}
2014-09-03 00:07:55 +04:00
2014-12-19 13:00:29 +03:00
mRegistration - > mScriptSpec = mScriptSpec ;
2015-02-11 14:53:00 +03:00
swm - > StoreRegistration ( mPrincipal , mRegistration ) ;
2014-12-19 13:00:29 +03:00
} else {
MOZ_ASSERT ( mJobType = = UPDATE_JOB ) ;
2014-09-03 00:07:55 +04:00
}
2014-12-19 13:00:29 +03:00
Update ( ) ;
2014-09-03 00:07:55 +04:00
}
2014-12-19 13:00:29 +03:00
NS_IMETHOD
OnStreamComplete ( nsIStreamLoader * aLoader , nsISupports * aContext ,
nsresult aStatus , uint32_t aLen ,
const uint8_t * aString ) MOZ_OVERRIDE
{
if ( NS_WARN_IF ( NS_FAILED ( aStatus ) ) ) {
Fail ( NS_ERROR_DOM_NETWORK_ERR ) ;
return aStatus ;
}
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIRequest > request ;
nsresult rv = aLoader - > GetRequest ( getter_AddRefs ( request ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
Fail ( NS_ERROR_DOM_NETWORK_ERR ) ;
return rv ;
}
2014-08-22 03:31:12 +04:00
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIHttpChannel > httpChannel = do_QueryInterface ( request ) ;
if ( ! httpChannel ) {
Fail ( NS_ERROR_DOM_NETWORK_ERR ) ;
return NS_ERROR_FAILURE ;
}
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
bool requestSucceeded ;
rv = httpChannel - > GetRequestSucceeded ( & requestSucceeded ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) | | ! requestSucceeded ) ) {
Fail ( NS_ERROR_DOM_NETWORK_ERR ) ;
return rv ;
}
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
// FIXME(nsm): "Extract mime type..."
// FIXME(nsm): Byte match to aString.
NS_WARNING ( " Byte wise check is disabled, just using new one " ) ;
2014-12-19 13:48:31 +03:00
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-02-09 07:33:39 +03:00
2014-12-19 13:48:31 +03: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-09 07:33:39 +03:00
MOZ_ASSERT ( ! swm - > mSetOfScopesBeingUpdated . Contains ( mRegistration - > mScope ) ) ;
swm - > mSetOfScopesBeingUpdated . Put ( mRegistration - > mScope , true ) ;
2014-12-19 13:48:31 +03:00
nsRefPtr < ServiceWorker > serviceWorker ;
2015-02-17 15:36:09 +03:00
rv = swm - > CreateServiceWorker ( mRegistration - > mPrincipal ,
mRegistration - > mScriptSpec ,
2014-12-19 13:48:31 +03:00
mRegistration - > mScope ,
getter_AddRefs ( serviceWorker ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2015-02-12 00:24:57 +03:00
swm - > mSetOfScopesBeingUpdated . Remove ( mRegistration - > mScope ) ;
2014-12-19 13:48:31 +03:00
Fail ( NS_ERROR_DOM_ABORT_ERR ) ;
return rv ;
}
nsRefPtr < ServiceWorkerJob > upcasted = this ;
nsMainThreadPtrHandle < nsISupports > handle (
new nsMainThreadPtrHolder < nsISupports > ( upcasted ) ) ;
nsRefPtr < CheckWorkerEvaluationAndContinueUpdateWorkerRunnable > r =
new CheckWorkerEvaluationAndContinueUpdateWorkerRunnable ( serviceWorker - > GetWorkerPrivate ( ) , handle ) ;
AutoJSAPI jsapi ;
jsapi . Init ( ) ;
bool ok = r - > Dispatch ( jsapi . cx ( ) ) ;
if ( NS_WARN_IF ( ! ok ) ) {
2015-02-12 00:24:57 +03:00
swm - > mSetOfScopesBeingUpdated . Remove ( mRegistration - > mScope ) ;
2014-12-19 13:48:31 +03:00
Fail ( NS_ERROR_DOM_ABORT_ERR ) ;
return rv ;
}
2014-12-19 13:00:29 +03:00
return NS_OK ;
2014-08-22 03:31:12 +04:00
}
2014-12-19 13:48:31 +03:00
// Public so our error handling code can use it.
void
Fail ( const ErrorEventInit & aError )
{
MOZ_ASSERT ( mCallback ) ;
mCallback - > UpdateFailed ( aError ) ;
2014-11-06 01:43:51 +03:00
FailCommon ( NS_ERROR_DOM_JS_EXCEPTION ) ;
2014-12-19 13:48:31 +03:00
}
// Public so our error handling code can continue with a successful worker.
void
ContinueInstall ( )
{
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-02-09 07:33:39 +03:00
MOZ_ASSERT ( swm - > mSetOfScopesBeingUpdated . Contains ( mRegistration - > mScope ) ) ;
swm - > mSetOfScopesBeingUpdated . Remove ( mRegistration - > mScope ) ;
2015-02-11 01:33:23 +03: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.
// Begin [[Install]] atomic step 4.
2014-12-19 13:48:31 +03:00
if ( mRegistration - > mInstallingWorker ) {
// FIXME(nsm): Terminate and stuff
mRegistration - > mInstallingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
}
swm - > InvalidateServiceWorkerRegistrationWorker ( mRegistration ,
WhichServiceWorker : : INSTALLING_WORKER ) ;
mRegistration - > mInstallingWorker = new ServiceWorkerInfo ( mRegistration , mRegistration - > mScriptSpec ) ;
mRegistration - > mInstallingWorker - > UpdateState ( ServiceWorkerState : : Installing ) ;
Succeed ( ) ;
2015-02-11 01:33:23 +03:00
// Step 4.6 "Queue a task..." for updatefound.
2014-12-19 16:01:53 +03:00
nsCOMPtr < nsIRunnable > upr =
NS_NewRunnableMethodWithArg < ServiceWorkerRegistrationInfo * > ( swm ,
& ServiceWorkerManager : : FireUpdateFound ,
mRegistration ) ;
2014-12-19 13:48:31 +03:00
NS_DispatchToMainThread ( upr ) ;
nsRefPtr < ServiceWorker > serviceWorker ;
nsresult rv =
2015-02-17 15:36:09 +03:00
swm - > CreateServiceWorker ( mRegistration - > mPrincipal ,
mRegistration - > mInstallingWorker - > ScriptSpec ( ) ,
2014-12-19 13:48:31 +03:00
mRegistration - > mScope ,
getter_AddRefs ( serviceWorker ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2015-02-11 01:33:23 +03:00
ContinueAfterInstallEvent ( false /* aSuccess */ , false /* aActivateImmediately */ ) ;
2014-12-19 13:48:31 +03:00
return ;
}
2015-02-11 01:33:23 +03:00
nsMainThreadPtrHandle < ContinueLifecycleTask > handle (
new nsMainThreadPtrHolder < ContinueLifecycleTask > ( new ContinueInstallTask ( this ) ) ) ;
2014-12-19 16:01:53 +03:00
nsRefPtr < LifecycleEventWorkerRunnable > r =
new LifecycleEventWorkerRunnable ( serviceWorker - > GetWorkerPrivate ( ) , NS_LITERAL_STRING ( " install " ) , handle ) ;
2014-12-19 13:48:31 +03:00
AutoJSAPI jsapi ;
jsapi . Init ( ) ;
2015-02-11 01:33:23 +03: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 13:48:31 +03:00
r - > Dispatch ( jsapi . cx ( ) ) ;
}
2014-12-19 13:00:29 +03:00
private :
void
Update ( )
{
MOZ_ASSERT ( mRegistration ) ;
nsCOMPtr < nsIRunnable > r =
NS_NewRunnableMethod ( this , & ServiceWorkerRegisterJob : : ContinueUpdate ) ;
NS_DispatchToMainThread ( r ) ;
2013-11-20 03:15:02 +04:00
}
2014-12-19 13:00:29 +03:00
// Aspects of (actually the whole algorithm) of [[Update]] after
// "Run the following steps in parallel."
void
ContinueUpdate ( )
2014-08-20 19:40:00 +04:00
{
2014-12-19 13:00:29 +03:00
AssertIsOnMainThread ( ) ;
if ( mRegistration - > mInstallingWorker ) {
// FIXME(nsm): "Terminate installing worker".
2014-12-19 14:25:56 +03:00
mRegistration - > mInstallingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2014-12-19 13:00:29 +03:00
mRegistration - > mInstallingWorker = nullptr ;
2014-08-20 19:40:00 +04:00
}
2014-12-19 13:00:29 +03:00
// FIXME(nsm): Plug in FetchDriver when it is ready.
nsCOMPtr < nsIURI > uri ;
nsresult rv = NS_NewURI ( getter_AddRefs ( uri ) , mRegistration - > mScriptSpec , nullptr , nullptr ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return Fail ( rv ) ;
2014-08-20 19:40:00 +04:00
}
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIPrincipal > principal ;
nsIScriptSecurityManager * ssm = nsContentUtils : : GetSecurityManager ( ) ;
rv = ssm - > GetNoAppCodebasePrincipal ( uri , getter_AddRefs ( principal ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return Fail ( rv ) ;
2014-08-20 19:40:00 +04:00
}
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIChannel > channel ;
rv = NS_NewChannel ( getter_AddRefs ( channel ) ,
uri ,
principal ,
nsILoadInfo : : SEC_NORMAL ,
nsIContentPolicy : : TYPE_SCRIPT ) ; // FIXME(nsm): TYPE_SERVICEWORKER
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return Fail ( rv ) ;
2014-08-20 19:40:00 +04:00
}
2014-12-19 13:00:29 +03:00
// FIXME(nsm): Set redirect limit.
2014-08-20 19:40:00 +04:00
2014-12-19 13:00:29 +03:00
// Don't let serviceworker intercept.
nsCOMPtr < nsIHttpChannelInternal > internalChannel = do_QueryInterface ( channel ) ;
if ( internalChannel ) {
internalChannel - > ForceNoIntercept ( ) ;
}
2014-08-20 19:40:00 +04:00
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIStreamLoader > loader ;
rv = NS_NewStreamLoader ( getter_AddRefs ( loader ) , this ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return Fail ( rv ) ;
2014-08-20 19:40:00 +04:00
}
2014-12-19 13:00:29 +03:00
rv = channel - > AsyncOpen ( loader , nullptr ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return Fail ( rv ) ;
}
2014-08-20 19:40:00 +04:00
}
2014-12-19 13:00:29 +03:00
void
Succeed ( )
{
MOZ_ASSERT ( mCallback ) ;
mCallback - > UpdateSucceeded ( mRegistration ) ;
mCallback = nullptr ;
2014-08-20 19:40:00 +04:00
}
2014-11-06 01:43:51 +03:00
void
FailCommon ( nsresult aRv )
{
mCallback = nullptr ;
2015-02-11 01:33:23 +03:00
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
swm - > MaybeRemoveRegistration ( mRegistration ) ;
2014-11-06 01:43:51 +03:00
// Ensures that the job can't do anything useful from this point on.
mRegistration = nullptr ;
Done ( aRv ) ;
}
2014-12-19 13:00:29 +03: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.
void
2014-11-06 01:43:51 +03:00
Fail ( nsresult aRv )
2014-12-19 13:00:29 +03:00
{
MOZ_ASSERT ( mCallback ) ;
2014-11-06 01:43:51 +03:00
mCallback - > UpdateFailed ( aRv ) ;
FailCommon ( aRv ) ;
}
void
2015-02-11 01:33:23 +03:00
ContinueAfterInstallEvent ( bool aInstallEventSuccess , bool aActivateImmediately )
2014-11-06 01:43:51 +03:00
{
2014-12-19 13:00:29 +03:00
if ( ! mRegistration - > mInstallingWorker ) {
NS_WARNING ( " mInstallingWorker was null. " ) ;
return Done ( NS_ERROR_DOM_ABORT_ERR ) ;
2014-08-20 19:40:00 +04:00
}
2014-12-19 13:00:29 +03:00
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-08-20 19:40:00 +04:00
2014-12-19 13:00:29 +03:00
// "If installFailed is true"
2015-02-11 01:33:23 +03:00
if ( ! aInstallEventSuccess ) {
2014-12-19 13:00:29 +03:00
mRegistration - > mInstallingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
mRegistration - > mInstallingWorker = nullptr ;
swm - > InvalidateServiceWorkerRegistrationWorker ( mRegistration ,
WhichServiceWorker : : INSTALLING_WORKER ) ;
2015-02-11 01:33:23 +03:00
swm - > MaybeRemoveRegistration ( mRegistration ) ;
2014-12-19 13:00:29 +03:00
return Done ( NS_ERROR_DOM_ABORT_ERR ) ;
2014-08-20 19:40:00 +04:00
}
2014-12-19 13:00:29 +03:00
// "If registration's waiting worker is not null"
if ( mRegistration - > mWaitingWorker ) {
// FIXME(nsm): Terminate
mRegistration - > mWaitingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
}
2014-12-19 15:45:07 +03:00
// Although the spec first sets waiting worker and then updates its state,
// our ServiceWorkerInfo does not hold a list of associated ServiceWorker
// objects in content JS. This means if we want to fire an event on
// ServiceWorkerRegistration.installing, we need to do it first, before
// swapping it with waiting worker.
mRegistration - > mInstallingWorker - > UpdateState ( ServiceWorkerState : : Installed ) ;
2014-12-19 13:00:29 +03:00
mRegistration - > mWaitingWorker = mRegistration - > mInstallingWorker . forget ( ) ;
swm - > InvalidateServiceWorkerRegistrationWorker ( mRegistration ,
WhichServiceWorker : : INSTALLING_WORKER | WhichServiceWorker : : WAITING_WORKER ) ;
2014-08-20 19:40:00 +04:00
2014-12-19 13:00:29 +03:00
// FIXME(nsm): Bug 982711 Deal with activateImmediately.
NS_WARN_IF_FALSE ( ! aActivateImmediately , " Immediate activation using replace() is not supported yet " ) ;
2015-02-17 11:35:27 +03:00
Done ( NS_OK ) ;
2015-02-11 01:33:23 +03:00
// Activate() is invoked out of band of atomic.
mRegistration - > TryToActivate ( ) ;
2014-08-20 19:40:00 +04:00
}
} ;
2014-12-19 13:48:31 +03:00
NS_IMPL_ISUPPORTS_INHERITED ( ServiceWorkerRegisterJob , ServiceWorkerJob , nsIStreamLoaderObserver ) ;
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 13:00:29 +03:00
2014-12-19 16:01:53 +03:00
void
ContinueInstallTask : : ContinueAfterWorkerEvent ( bool aSuccess , bool aActivateImmediately )
{
2015-02-11 01:33:23 +03: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 16:01:53 +03:00
mJob - > ContinueAfterInstallEvent ( aSuccess , aActivateImmediately ) ;
}
2014-08-20 19:40:00 +04:00
// If we return an error code here, the ServiceWorkerContainer will
// automatically reject the Promise.
NS_IMETHODIMP
2014-12-19 13:00:29 +03:00
ServiceWorkerManager : : Register ( nsIDOMWindow * aWindow ,
const nsAString & aScope ,
const nsAString & aScriptURL ,
nsISupports * * aPromise )
2014-08-20 19:40:00 +04: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 13:00:29 +03:00
nsCOMPtr < nsIDocument > doc = window - > GetExtantDoc ( ) ;
if ( ! doc ) {
2014-08-20 19:40:00 +04:00
return NS_ERROR_FAILURE ;
}
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIURI > documentURI = doc - > GetBaseURI ( ) ;
2014-08-20 19:40:00 +04:00
2014-12-19 13:00:29 +03:00
bool authenticatedOrigin = false ;
// FIXME(nsm): Bug 1003991. Disable check when devtools are open.
if ( Preferences : : GetBool ( " dom.serviceWorkers.testing.enabled " ) ) {
authenticatedOrigin = true ;
}
2014-08-20 19:40:00 +04:00
2014-12-19 13:00:29 +03:00
nsresult rv ;
if ( ! authenticatedOrigin ) {
nsAutoCString scheme ;
rv = documentURI - > GetScheme ( scheme ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2014-08-26 12:16:03 +04:00
2014-12-19 13:00:29 +03:00
if ( scheme . EqualsLiteral ( " https " ) | |
scheme . EqualsLiteral ( " file " ) | |
scheme . EqualsLiteral ( " app " ) ) {
authenticatedOrigin = true ;
}
}
2014-08-26 12:16:03 +04:00
2014-12-19 13:00:29 +03:00
if ( ! authenticatedOrigin ) {
nsAutoCString host ;
rv = documentURI - > GetHost ( host ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2014-08-26 12:16:03 +04:00
2014-12-19 13:00:29 +03:00
if ( host . Equals ( " 127.0.0.1 " ) | |
host . Equals ( " localhost " ) | |
host . Equals ( " ::1 " ) ) {
authenticatedOrigin = true ;
2014-08-26 12:16:03 +04:00
}
2014-12-19 13:00:29 +03:00
}
2014-08-26 12:16:03 +04:00
2014-12-19 13:00:29 +03:00
if ( ! authenticatedOrigin ) {
bool isFile ;
rv = documentURI - > SchemeIs ( " file " , & isFile ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
2014-08-26 12:16:03 +04:00
}
2014-12-19 13:00:29 +03: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 12:16:03 +04:00
}
2014-12-19 13:00:29 +03:00
}
2014-08-26 12:16:03 +04:00
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIURI > scriptURI ;
rv = NS_NewURI ( getter_AddRefs ( scriptURI ) , aScriptURL , nullptr , documentURI ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
2014-08-26 12:16:03 +04:00
}
2014-12-19 13:00:29 +03:00
// Data URLs are not allowed.
nsCOMPtr < nsIPrincipal > documentPrincipal = doc - > NodePrincipal ( ) ;
2014-08-26 12:16:03 +04:00
2014-12-19 13:00:29 +03:00
rv = documentPrincipal - > CheckMayLoad ( scriptURI , true /* report */ ,
false /* allowIfInheritsPrincipal */ ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
2014-08-26 12:16:03 +04:00
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIURI > scopeURI ;
rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , aScope , nullptr , documentURI ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
rv = documentPrincipal - > CheckMayLoad ( scopeURI , true /* report */ ,
false /* allowIfInheritsPrinciple */ ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
nsCString cleanedScope ;
rv = scopeURI - > GetSpecIgnoringRef ( cleanedScope ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2014-08-26 12:16:03 +04:00
return NS_ERROR_FAILURE ;
}
2014-12-19 13:00:29 +03:00
nsAutoCString spec ;
rv = scriptURI - > GetSpec ( spec ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2014-08-26 12:16:03 +04:00
nsCOMPtr < nsIGlobalObject > sgo = do_QueryInterface ( window ) ;
ErrorResult result ;
nsRefPtr < Promise > promise = Promise : : Create ( sgo , result ) ;
if ( result . Failed ( ) ) {
return result . ErrorCode ( ) ;
}
2015-02-09 07:33:39 +03:00
ServiceWorkerJobQueue * queue = GetOrCreateJobQueue ( cleanedScope ) ;
2014-12-19 13:00:29 +03:00
MOZ_ASSERT ( queue ) ;
nsRefPtr < ServiceWorkerResolveWindowPromiseOnUpdateCallback > cb =
new ServiceWorkerResolveWindowPromiseOnUpdateCallback ( window , promise ) ;
nsRefPtr < ServiceWorkerRegisterJob > job =
2015-02-11 14:53:00 +03:00
new ServiceWorkerRegisterJob ( queue , cleanedScope , spec , cb , documentPrincipal ) ;
2014-12-19 13:00:29 +03:00
queue - > Append ( job ) ;
2014-08-26 12:16:03 +04:00
promise . forget ( aPromise ) ;
2014-12-19 13:00:29 +03:00
return NS_OK ;
2014-08-26 12:16:03 +04:00
}
2015-02-11 14:53:00 +03: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 13:00:29 +03:00
/*
2014-12-19 16:01:53 +03:00
* Used to handle ExtendableEvent : : waitUntil ( ) and proceed with
* installation / activation .
2014-12-19 13:00:29 +03:00
*/
2014-12-19 16:01:53 +03:00
class LifecycleEventPromiseHandler MOZ_FINAL : public PromiseNativeHandler
2014-08-26 12:16:03 +04:00
{
2014-12-19 16:01:53 +03:00
nsMainThreadPtrHandle < ContinueLifecycleTask > mTask ;
2014-12-19 13:00:29 +03:00
bool mActivateImmediately ;
2014-08-26 12:16:03 +04:00
2014-12-19 13:00:29 +03:00
virtual
2014-12-19 16:01:53 +03:00
~ LifecycleEventPromiseHandler ( )
2014-12-19 13:00:29 +03:00
{ }
2014-08-26 12:16:03 +04:00
2014-12-19 13:00:29 +03:00
public :
2014-12-19 16:01:53 +03:00
LifecycleEventPromiseHandler ( const nsMainThreadPtrHandle < ContinueLifecycleTask > & aTask ,
bool aActivateImmediately )
: mTask ( aTask )
2014-12-19 13:00:29 +03:00
, mActivateImmediately ( aActivateImmediately )
{
MOZ_ASSERT ( ! NS_IsMainThread ( ) ) ;
}
2014-08-26 12:16:03 +04:00
2014-12-19 13:00:29 +03:00
void
ResolvedCallback ( JSContext * aCx , JS : : Handle < JS : : Value > aValue ) MOZ_OVERRIDE
{
WorkerPrivate * workerPrivate = GetCurrentThreadWorkerPrivate ( ) ;
MOZ_ASSERT ( workerPrivate ) ;
workerPrivate - > AssertIsOnWorkerThread ( ) ;
2014-08-26 12:16:03 +04:00
2014-12-19 16:01:53 +03:00
nsRefPtr < ContinueLifecycleRunnable > r =
new ContinueLifecycleRunnable ( mTask , true /* success */ , mActivateImmediately ) ;
2014-12-19 13:00:29 +03:00
NS_DispatchToMainThread ( r ) ;
2014-08-26 12:16:03 +04:00
}
2014-12-19 13:00:29 +03:00
void
RejectedCallback ( JSContext * aCx , JS : : Handle < JS : : Value > aValue ) MOZ_OVERRIDE
{
2014-12-19 16:01:53 +03:00
WorkerPrivate * workerPrivate = GetCurrentThreadWorkerPrivate ( ) ;
MOZ_ASSERT ( workerPrivate ) ;
workerPrivate - > AssertIsOnWorkerThread ( ) ;
nsRefPtr < ContinueLifecycleRunnable > r =
new ContinueLifecycleRunnable ( mTask , false /* success */ , mActivateImmediately ) ;
2014-12-19 13:00:29 +03:00
NS_DispatchToMainThread ( r ) ;
}
} ;
2014-08-26 12:16:03 +04:00
bool
2014-12-19 16:01:53 +03:00
LifecycleEventWorkerRunnable : : DispatchLifecycleEvent ( JSContext * aCx , WorkerPrivate * aWorkerPrivate )
2014-08-26 12:16:03 +04:00
{
2014-12-19 13:00:29 +03:00
aWorkerPrivate - > AssertIsOnWorkerThread ( ) ;
MOZ_ASSERT ( aWorkerPrivate - > IsServiceWorker ( ) ) ;
2014-12-19 16:01:53 +03:00
2014-12-19 16:01:53 +03:00
nsRefPtr < ExtendableEvent > event ;
2015-01-24 06:49:39 +03:00
nsRefPtr < EventTarget > target = aWorkerPrivate - > GlobalScope ( ) ;
2014-12-19 16:01:53 +03:00
if ( mEventName . EqualsASCII ( " install " ) ) {
// FIXME(nsm): Bug 982787 pass previous active worker.
InstallEventInit init ;
init . mBubbles = false ;
init . mCancelable = true ;
event = InstallEvent : : Constructor ( target , mEventName , init ) ;
} else if ( mEventName . EqualsASCII ( " activate " ) ) {
ExtendableEventInit init ;
init . mBubbles = false ;
init . mCancelable = true ;
event = ExtendableEvent : : Constructor ( target , mEventName , init ) ;
} else {
MOZ_CRASH ( " Unexpected lifecycle event " ) ;
}
2014-12-19 13:00:29 +03:00
event - > SetTrusted ( true ) ;
nsRefPtr < Promise > waitUntilPromise ;
ErrorResult result ;
result = target - > DispatchDOMEvent ( nullptr , event , nullptr , nullptr ) ;
nsCOMPtr < nsIGlobalObject > sgo = aWorkerPrivate - > GlobalScope ( ) ;
2014-12-19 15:45:07 +03:00
WidgetEvent * internalEvent = event - > GetInternalNSEvent ( ) ;
if ( ! result . Failed ( ) & & ! internalEvent - > mFlags . mExceptionHasBeenRisen ) {
2014-12-19 13:00:29 +03:00
waitUntilPromise = event - > GetPromise ( ) ;
if ( ! waitUntilPromise ) {
ErrorResult result ;
waitUntilPromise =
Promise : : Resolve ( sgo , aCx , JS : : UndefinedHandleValue , result ) ;
2014-12-19 15:45:07 +03:00
if ( NS_WARN_IF ( result . Failed ( ) ) ) {
return true ;
}
2014-12-19 13:00:29 +03:00
}
} else {
// Continue with a canceled install.
2014-12-19 15:45:07 +03:00
// Although the spec has different routines to deal with popping stuff
// off it's internal queues, we can reuse the ContinueAfterInstallEvent()
// logic.
2014-12-19 13:00:29 +03:00
waitUntilPromise = Promise : : Reject ( sgo , aCx ,
JS : : UndefinedHandleValue , result ) ;
2014-08-26 12:16:03 +04:00
}
2014-12-19 13:00:29 +03:00
if ( result . Failed ( ) ) {
return false ;
}
2014-08-26 12:16:03 +04:00
2014-12-19 16:01:53 +03:00
// activateimmediately is only relevant to "install" event.
bool activateImmediately = false ;
InstallEvent * installEvent = event - > AsInstallEvent ( ) ;
if ( installEvent ) {
activateImmediately = installEvent - > ActivateImmediately ( ) ;
2015-01-24 06:49:39 +03:00
// FIXME(nsm): Set activeWorker to the correct thing.
// FIXME(nsm): Install error handler for any listener errors.
}
2014-12-19 16:01:53 +03:00
nsRefPtr < LifecycleEventPromiseHandler > handler =
new LifecycleEventPromiseHandler ( mTask , activateImmediately ) ;
waitUntilPromise - > AppendNativeHandler ( handler ) ;
return true ;
}
2015-01-24 06:49:39 +03:00
2014-06-11 20:12:56 +04:00
void
2014-12-19 13:00:29 +03:00
ServiceWorkerRegistrationInfo : : TryToActivate ( )
2014-06-11 20:12:56 +04:00
{
2014-12-19 13:00:29 +03:00
if ( ! IsControllingDocuments ( ) ) {
Activate ( ) ;
2014-06-11 20:12:56 +04:00
}
}
2015-02-11 01:33:23 +03:00
void
2015-02-11 01:33:23 +03:00
ContinueActivateTask : : ContinueAfterWorkerEvent ( bool aSuccess , bool aActivateImmediately /* unused */ )
2015-02-11 01:33:23 +03:00
{
2015-02-11 01:33:23 +03:00
mRegistration - > FinishActivate ( aSuccess ) ;
}
2015-02-17 11:35:27 +03:00
2015-02-11 01:33:23 +03:00
void
ServiceWorkerRegistrationInfo : : Activate ( )
{
2014-12-19 13:00:29 +03: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 ) {
NS_WARNING ( " No activatingWorker! " ) ;
2014-06-11 20:12:56 +04:00
return ;
}
2014-12-19 13:00:29 +03:00
if ( exitingWorker ) {
// FIXME(nsm): Wait for worker.
// Terminate worker
exitingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2014-06-11 20:12:56 +04:00
}
2014-12-19 13:00:29 +03:00
mActiveWorker = activatingWorker . forget ( ) ;
mWaitingWorker = nullptr ;
mActiveWorker - > UpdateState ( ServiceWorkerState : : Activating ) ;
2014-06-11 20:12:56 +04:00
2015-02-11 01:33:23 +03:00
// FIXME(nsm): Unlink appcache if there is one.
2014-12-19 13:00:29 +03:00
swm - > CheckPendingReadyPromises ( ) ;
2015-02-11 14:53:00 +03:00
swm - > StoreRegistration ( mPrincipal , this ) ;
2014-06-11 20:12:56 +04:00
2014-12-19 13:00:29 +03:00
// "Queue a task to fire a simple event named controllerchange..."
nsCOMPtr < nsIRunnable > controllerChangeRunnable =
2015-02-11 01:33:23 +03:00
NS_NewRunnableMethodWithArg < ServiceWorkerRegistrationInfo * > ( swm ,
& ServiceWorkerManager : : FireControllerChange ,
this ) ;
2014-12-19 13:00:29 +03:00
NS_DispatchToMainThread ( controllerChangeRunnable ) ;
2014-07-03 04:48:35 +04:00
2014-12-19 13:00:29 +03:00
MOZ_ASSERT ( mActiveWorker ) ;
nsRefPtr < ServiceWorker > serviceWorker ;
nsresult rv =
2015-02-17 15:36:09 +03:00
swm - > CreateServiceWorker ( mPrincipal ,
mActiveWorker - > ScriptSpec ( ) ,
2014-12-19 13:00:29 +03:00
mScope ,
getter_AddRefs ( serviceWorker ) ) ;
2014-07-03 04:48:35 +04:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2015-02-11 01:33:23 +03:00
nsCOMPtr < nsIRunnable > r =
NS_NewRunnableMethodWithArg < bool > ( this ,
& ServiceWorkerRegistrationInfo : : FinishActivate ,
false /* success */ ) ;
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( NS_DispatchToMainThread ( r ) ) ) ;
2014-12-19 14:25:56 +03:00
return ;
2014-07-03 04:48:35 +04:00
}
2014-12-19 16:01:53 +03:00
nsMainThreadPtrHandle < ContinueLifecycleTask > handle (
new nsMainThreadPtrHolder < ContinueLifecycleTask > ( new ContinueActivateTask ( this ) ) ) ;
2014-07-03 04:48:35 +04:00
2014-12-19 16:01:53 +03:00
nsRefPtr < LifecycleEventWorkerRunnable > r =
new LifecycleEventWorkerRunnable ( serviceWorker - > GetWorkerPrivate ( ) , NS_LITERAL_STRING ( " activate " ) , handle ) ;
2014-07-03 04:48:35 +04:00
2014-12-19 13:00:29 +03:00
AutoJSAPI jsapi ;
jsapi . Init ( ) ;
r - > Dispatch ( jsapi . cx ( ) ) ;
2014-07-03 04:48:35 +04:00
}
2014-12-19 13:00:29 +03:00
/*
* Implements the async aspects of the getRegistrations algorithm .
*/
class GetRegistrationsRunnable : public nsRunnable
2014-07-03 04:48:50 +04:00
{
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsPIDOMWindow > mWindow ;
nsRefPtr < Promise > mPromise ;
2014-07-03 04:48:50 +04:00
public :
2014-12-19 13:00:29 +03:00
GetRegistrationsRunnable ( nsPIDOMWindow * aWindow , Promise * aPromise )
: mWindow ( aWindow ) , mPromise ( aPromise )
{ }
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
NS_IMETHODIMP
Run ( )
2014-07-03 04:48:50 +04:00
{
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-12-19 13:00:29 +03:00
nsIDocument * doc = mWindow - > GetExtantDoc ( ) ;
if ( ! doc ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIURI > docURI = doc - > GetDocumentURI ( ) ;
if ( ! docURI ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIPrincipal > principal = doc - > NodePrincipal ( ) ;
if ( ! principal ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
nsTArray < nsRefPtr < ServiceWorkerRegistration > > array ;
2015-02-17 01:22:17 +03: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-02-09 07:33:39 +03:00
for ( uint32_t i = 0 ; i < swm - > mOrderedScopes . Length ( ) ; + + i ) {
NS_ConvertUTF8toUTF16 scope ( swm - > mOrderedScopes [ i ] ) ;
2015-02-17 01:22:17 +03: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 ;
}
2014-12-19 13:00:29 +03:00
nsRefPtr < ServiceWorkerRegistration > swr =
new ServiceWorkerRegistration ( mWindow , scope ) ;
array . AppendElement ( swr ) ;
}
mPromise - > MaybeResolve ( array ) ;
2014-07-12 00:07:59 +04:00
return NS_OK ;
}
} ;
2014-12-19 13:00:29 +03: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-03 04:48:50 +04:00
{
2014-12-19 13:00:29 +03:00
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWindow ) ;
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03: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-03 04:48:50 +04:00
}
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIGlobalObject > sgo = do_QueryInterface ( window ) ;
ErrorResult result ;
nsRefPtr < Promise > promise = Promise : : Create ( sgo , result ) ;
if ( result . Failed ( ) ) {
return result . ErrorCode ( ) ;
2014-07-03 04:48:50 +04:00
}
2014-12-19 13:00:29 +03:00
nsRefPtr < nsIRunnable > runnable =
new GetRegistrationsRunnable ( window , promise ) ;
promise . forget ( aPromise ) ;
return NS_DispatchToCurrentThread ( runnable ) ;
}
2014-07-03 04:48:50 +04:00
/*
2014-12-19 13:00:29 +03:00
* Implements the async aspects of the getRegistration algorithm .
2014-07-03 04:48:50 +04:00
*/
2014-12-19 13:00:29 +03:00
class GetRegistrationRunnable : public nsRunnable
2014-07-03 04:48:50 +04:00
{
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsPIDOMWindow > mWindow ;
nsRefPtr < Promise > mPromise ;
nsString mDocumentURL ;
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
public :
GetRegistrationRunnable ( nsPIDOMWindow * aWindow , Promise * aPromise ,
const nsAString & aDocumentURL )
: mWindow ( aWindow ) , mPromise ( aPromise ) , mDocumentURL ( aDocumentURL )
2014-07-03 04:48:50 +04:00
{ }
2014-12-19 13:00:29 +03:00
NS_IMETHODIMP
Run ( )
2014-07-03 04:48:50 +04:00
{
2014-12-19 13:00:29 +03:00
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
nsIDocument * doc = mWindow - > GetExtantDoc ( ) ;
if ( ! doc ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIURI > docURI = doc - > GetDocumentURI ( ) ;
if ( ! docURI ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03: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-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIPrincipal > principal = doc - > NodePrincipal ( ) ;
if ( ! principal ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03: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-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration =
swm - > GetServiceWorkerRegistrationInfo ( uri ) ;
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
if ( ! registration ) {
mPromise - > MaybeResolve ( JS : : UndefinedHandleValue ) ;
return NS_OK ;
}
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
NS_ConvertUTF8toUTF16 scope ( registration - > mScope ) ;
nsRefPtr < ServiceWorkerRegistration > swr =
new ServiceWorkerRegistration ( mWindow , scope ) ;
mPromise - > MaybeResolve ( swr ) ;
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
return NS_OK ;
2014-07-12 00:07:59 +04:00
}
} ;
2014-12-19 13:00:29 +03: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-03 04:48:50 +04:00
{
2014-12-19 13:00:29 +03:00
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWindow ) ;
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03: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-03 04:48:50 +04:00
}
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIGlobalObject > sgo = do_QueryInterface ( window ) ;
ErrorResult result ;
nsRefPtr < Promise > promise = Promise : : Create ( sgo , result ) ;
if ( result . Failed ( ) ) {
return result . ErrorCode ( ) ;
2014-07-03 04:48:50 +04:00
}
2014-12-19 13:00:29 +03:00
nsRefPtr < nsIRunnable > runnable =
new GetRegistrationRunnable ( window , promise , aDocumentURL ) ;
promise . forget ( aPromise ) ;
return NS_DispatchToCurrentThread ( runnable ) ;
}
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
class GetReadyPromiseRunnable : public nsRunnable
{
nsCOMPtr < nsPIDOMWindow > mWindow ;
nsRefPtr < Promise > mPromise ;
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
public :
GetReadyPromiseRunnable ( nsPIDOMWindow * aWindow , Promise * aPromise )
: mWindow ( aWindow ) , mPromise ( aPromise )
{ }
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
NS_IMETHODIMP
Run ( )
{
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
nsIDocument * doc = mWindow - > GetExtantDoc ( ) ;
if ( ! doc ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIURI > docURI = doc - > GetDocumentURI ( ) ;
if ( ! docURI ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
if ( ! swm - > CheckReadyPromise ( mWindow , docURI , mPromise ) ) {
swm - > StorePendingReadyPromise ( mWindow , docURI , mPromise ) ;
2014-07-03 04:48:50 +04:00
}
2014-12-19 13:00:29 +03:00
return NS_OK ;
}
} ;
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 ( ) ) {
return result . ErrorCode ( ) ;
2014-07-03 04:48:50 +04:00
}
2014-12-19 13:00:29 +03:00
nsRefPtr < nsIRunnable > runnable =
new GetReadyPromiseRunnable ( window , promise ) ;
promise . forget ( aPromise ) ;
return NS_DispatchToCurrentThread ( runnable ) ;
}
NS_IMETHODIMP
ServiceWorkerManager : : RemoveReadyPromise ( nsIDOMWindow * aWindow )
2014-07-12 00:07:59 +04:00
{
2014-12-19 13:00:29 +03:00
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWindow ) ;
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
if ( ! window ) {
return NS_ERROR_FAILURE ;
2014-07-12 00:07:59 +04:00
}
2014-12-19 13:00:29 +03:00
mPendingReadyPromises . Remove ( aWindow ) ;
return NS_OK ;
}
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
void
ServiceWorkerManager : : StorePendingReadyPromise ( nsPIDOMWindow * aWindow ,
nsIURI * aURI ,
Promise * aPromise )
{
PendingReadyPromise * data ;
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
// We should not have 2 pending promises for the same window.
MOZ_ASSERT ( ! mPendingReadyPromises . Get ( aWindow , & data ) ) ;
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
data = new PendingReadyPromise ( aURI , aPromise ) ;
mPendingReadyPromises . Put ( aWindow , data ) ;
}
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
void
ServiceWorkerManager : : CheckPendingReadyPromises ( )
{
mPendingReadyPromises . Enumerate ( CheckPendingReadyPromisesEnumerator , this ) ;
}
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
PLDHashOperator
ServiceWorkerManager : : CheckPendingReadyPromisesEnumerator (
nsISupports * aSupports ,
nsAutoPtr < PendingReadyPromise > & aData ,
void * aPtr )
{
ServiceWorkerManager * aSwm = static_cast < ServiceWorkerManager * > ( aPtr ) ;
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aSupports ) ;
2014-07-12 00:07:59 +04:00
2014-12-19 13:00:29 +03:00
if ( aSwm - > CheckReadyPromise ( window , aData - > mURI , aData - > mPromise ) ) {
return PL_DHASH_REMOVE ;
}
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
return PL_DHASH_NEXT ;
}
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
bool
ServiceWorkerManager : : CheckReadyPromise ( nsPIDOMWindow * aWindow ,
nsIURI * aURI , Promise * aPromise )
{
nsRefPtr < ServiceWorkerRegistrationInfo > registration =
GetServiceWorkerRegistrationInfo ( aURI ) ;
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
if ( registration & & registration - > mActiveWorker ) {
NS_ConvertUTF8toUTF16 scope ( registration - > mScope ) ;
nsRefPtr < ServiceWorkerRegistration > swr =
new ServiceWorkerRegistration ( aWindow , scope ) ;
aPromise - > MaybeResolve ( swr ) ;
return true ;
2014-07-03 04:48:50 +04:00
}
2014-12-19 13:00:29 +03:00
return false ;
2014-07-03 04:48:50 +04:00
}
2015-01-23 01:10:38 +03:00
class ServiceWorkerUnregisterJob MOZ_FINAL : public ServiceWorkerJob
2014-07-03 04:48:50 +04:00
{
2015-01-23 01:10:38 +03:00
nsRefPtr < ServiceWorkerRegistrationInfo > mRegistration ;
const nsCString mScope ;
nsCOMPtr < nsIServiceWorkerUnregisterCallback > mCallback ;
2015-02-11 14:53:00 +03:00
PrincipalInfo mPrincipalInfo ;
2014-12-19 13:00:29 +03:00
2015-01-23 01:10:38 +03:00
~ ServiceWorkerUnregisterJob ( )
{ }
public :
ServiceWorkerUnregisterJob ( ServiceWorkerJobQueue * aQueue ,
const nsACString & aScope ,
2015-02-11 14:53:00 +03:00
nsIServiceWorkerUnregisterCallback * aCallback ,
PrincipalInfo & aPrincipalInfo )
2015-01-23 01:10:38 +03:00
: ServiceWorkerJob ( aQueue )
, mScope ( aScope )
, mCallback ( aCallback )
2015-02-11 14:53:00 +03:00
, mPrincipalInfo ( aPrincipalInfo )
2015-01-23 01:10:38 +03:00
{
AssertIsOnMainThread ( ) ;
2014-07-12 00:07:59 +04:00
}
2015-01-23 01:10:38 +03:00
void
Start ( ) MOZ_OVERRIDE
2014-07-12 00:07:59 +04:00
{
2015-01-23 01:10:38 +03:00
AssertIsOnMainThread ( ) ;
nsCOMPtr < nsIRunnable > r =
NS_NewRunnableMethod ( this , & ServiceWorkerUnregisterJob : : UnregisterAndDone ) ;
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( NS_DispatchToMainThread ( r ) ) ) ;
}
2014-07-12 00:07:59 +04:00
2015-01-23 01:10:38 +03:00
private :
// You probably want UnregisterAndDone().
nsresult
Unregister ( )
{
AssertIsOnMainThread ( ) ;
2014-07-12 00:07:59 +04:00
2015-01-23 01:10:38 +03:00
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-07-24 01:05:08 +04:00
2015-01-23 01:10:38 +03:00
// "Let registration be the result of running [[Get Registration]]
// algorithm passing scope as the argument."
nsRefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-02-09 07:33:39 +03:00
if ( ! swm - > mServiceWorkerRegistrationInfos . Get ( mScope , getter_AddRefs ( registration ) ) ) {
2015-01-23 01:10:38 +03:00
// "If registration is null, then, resolve promise with false."
return mCallback - > UnregisterSucceeded ( false ) ;
}
2014-07-12 00:07:59 +04:00
2015-01-23 01:10:38 +03:00
MOZ_ASSERT ( registration ) ;
2014-07-12 00:07:59 +04:00
2015-01-23 01:10:38 +03:00
// "Set registration's uninstalling flag."
registration - > mPendingUninstall = true ;
// "Resolve promise with true"
nsresult rv = mCallback - > UnregisterSucceeded ( true ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2014-12-19 13:00:29 +03:00
2015-01-23 01:10:38 +03: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 13:00:29 +03:00
}
2014-07-12 00:07:59 +04:00
2015-01-23 01:10:38 +03:00
// "Invoke [[Clear Registration]]..."
registration - > Clear ( ) ;
2015-02-09 07:33:39 +03:00
swm - > RemoveRegistration ( registration ) ;
2015-01-23 01:10:38 +03:00
}
2014-07-12 00:07:59 +04:00
2015-02-11 14:53:00 +03:00
MOZ_ASSERT ( swm - > mActor ) ;
swm - > mActor - > SendUnregisterServiceWorker ( mPrincipalInfo ,
NS_ConvertUTF8toUTF16 ( mScope ) ) ;
2015-01-23 01:10:38 +03:00
return NS_OK ;
}
2014-07-12 00:07:59 +04:00
2015-01-23 01:10:38 +03:00
// The unregister job is done irrespective of success or failure of any sort.
void
UnregisterAndDone ( )
{
Done ( Unregister ( ) ) ;
}
} ;
2014-07-12 00:07:59 +04:00
2015-01-23 01:10:38 +03:00
NS_IMETHODIMP
2015-02-11 14:53:00 +03:00
ServiceWorkerManager : : Unregister ( nsIPrincipal * aPrincipal ,
nsIServiceWorkerUnregisterCallback * aCallback ,
2015-01-23 01:10:38 +03:00
const nsAString & aScope )
{
AssertIsOnMainThread ( ) ;
2015-02-11 14:53:00 +03:00
MOZ_ASSERT ( aPrincipal ) ;
2015-01-23 01:10:38 +03:00
MOZ_ASSERT ( aCallback ) ;
// 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-09 07:33:39 +03:00
ServiceWorkerJobQueue * queue = GetOrCreateJobQueue ( scope ) ;
2015-01-23 01:10:38 +03:00
MOZ_ASSERT ( queue ) ;
2015-02-11 14:53:00 +03:00
PrincipalInfo principalInfo ;
if ( NS_WARN_IF ( NS_FAILED ( PrincipalToPrincipalInfo ( aPrincipal ,
& principalInfo ) ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
2015-01-23 01:10:38 +03:00
nsRefPtr < ServiceWorkerUnregisterJob > job =
2015-02-11 14:53:00 +03:00
new ServiceWorkerUnregisterJob ( queue , scope , aCallback , principalInfo ) ;
if ( mActor ) {
queue - > Append ( job ) ;
return NS_OK ;
}
AppendPendingOperation ( queue , job ) ;
2015-01-23 01:10:38 +03:00
return NS_OK ;
2014-12-19 13:00:29 +03: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-03 04:48:50 +04:00
2014-12-19 13:48:31 +03:00
bool
2014-12-19 13:00:29 +03:00
ServiceWorkerManager : : HandleError ( JSContext * aCx ,
2014-12-19 13:48:31 +03:00
const nsCString & aScope ,
const nsString & aWorkerURL ,
2014-12-19 13:00:29 +03:00
nsString aMessage ,
nsString aFilename ,
nsString aLine ,
uint32_t aLineNumber ,
uint32_t aColumnNumber ,
uint32_t aFlags )
2014-07-03 04:48:50 +04:00
{
AssertIsOnMainThread ( ) ;
2015-02-09 07:33:39 +03:00
if ( ! mSetOfScopesBeingUpdated . Contains ( aScope ) ) {
2014-12-19 13:48:31 +03:00
return false ;
2014-07-23 05:18:48 +04:00
}
2015-02-09 07:33:39 +03:00
mSetOfScopesBeingUpdated . Remove ( aScope ) ;
2014-12-19 13:48:31 +03:00
2015-02-09 07:33:39 +03:00
ServiceWorkerJobQueue * queue = mJobQueues . Get ( aScope ) ;
2014-12-19 13:48:31 +03:00
MOZ_ASSERT ( queue ) ;
ServiceWorkerJob * job = queue - > Peek ( ) ;
ServiceWorkerRegisterJob * regJob = static_cast < ServiceWorkerRegisterJob * > ( job ) ;
MOZ_ASSERT ( regJob ) ;
2014-07-03 04:48:50 +04:00
2014-12-19 13:00:29 +03:00
RootedDictionary < ErrorEventInit > init ( aCx ) ;
init . mMessage = aMessage ;
init . mFilename = aFilename ;
init . mLineno = aLineNumber ;
init . mColno = aColumnNumber ;
2014-07-03 04:48:50 +04:00
2014-12-19 13:48:31 +03:00
regJob - > Fail ( init ) ;
return true ;
2014-06-11 20:12:56 +04:00
}
2014-07-12 00:07:59 +04:00
void
2014-12-19 13:00:29 +03:00
ServiceWorkerRegistrationInfo : : FinishActivate ( bool aSuccess )
2014-07-12 00:07:59 +04:00
{
2015-02-11 01:33:23 +03:00
if ( mPendingUninstall | | ! mActiveWorker ) {
return ;
}
2014-12-19 13:00:29 +03:00
if ( aSuccess ) {
mActiveWorker - > UpdateState ( ServiceWorkerState : : Activated ) ;
} else {
mActiveWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
mActiveWorker = nullptr ;
}
2014-07-12 00:07:59 +04:00
}
2014-12-19 14:25:56 +03:00
void
ServiceWorkerRegistrationInfo : : QueueStateChangeEvent ( ServiceWorkerInfo * aInfo ,
ServiceWorkerState aState ) const
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aInfo ) ;
MOZ_ASSERT ( aInfo = = mInstallingWorker | |
aInfo = = mWaitingWorker | |
aInfo = = mActiveWorker ) ;
nsRefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-02-09 07:33:39 +03:00
WhichServiceWorker whichOne ;
if ( aInfo = = mInstallingWorker ) {
whichOne = WhichServiceWorker : : INSTALLING_WORKER ;
} else if ( aInfo = = mWaitingWorker ) {
whichOne = WhichServiceWorker : : WAITING_WORKER ;
} else if ( aInfo = = mActiveWorker ) {
whichOne = WhichServiceWorker : : ACTIVE_WORKER ;
} else {
MOZ_CRASH ( " Hit unexpected case " ) ;
}
2014-12-19 14:25:56 +03:00
2015-02-09 07:33:39 +03:00
// Refactor this iteration pattern across this and 2 other call-sites.
nsTObserverArray < ServiceWorkerRegistration * > : : ForwardIterator it ( swm - > mServiceWorkerRegistrations ) ;
while ( it . HasMore ( ) ) {
nsRefPtr < ServiceWorkerRegistration > target = it . GetNext ( ) ;
nsAutoString regScope ;
target - > GetScope ( regScope ) ;
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
NS_ConvertUTF16toUTF8 utf8Scope ( regScope ) ;
if ( utf8Scope . Equals ( mScope ) ) {
target - > QueueStateChangeEvent ( whichOne , aState ) ;
2014-12-19 14:25:56 +03:00
}
}
}
2013-11-20 03:15:02 +04:00
NS_IMETHODIMP
ServiceWorkerManager : : CreateServiceWorkerForWindow ( nsPIDOMWindow * aWindow ,
const nsACString & aScriptSpec ,
const nsACString & aScope ,
ServiceWorker * * aServiceWorker )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWindow ) ;
RuntimeService * rs = RuntimeService : : GetOrCreateService ( ) ;
nsRefPtr < ServiceWorker > serviceWorker ;
2014-12-19 13:00:29 +03:00
AutoJSAPI jsapi ;
jsapi . Init ( aWindow ) ;
JSContext * cx = jsapi . cx ( ) ;
2013-11-20 03:15:02 +04:00
2014-12-19 13:00:29 +03:00
nsCOMPtr < nsIGlobalObject > sgo = do_QueryInterface ( aWindow ) ;
2013-11-20 03:15:02 +04:00
JS : : Rooted < JSObject * > jsGlobal ( cx , sgo - > GetGlobalJSObject ( ) ) ;
GlobalObject global ( cx , jsGlobal ) ;
nsresult rv = rs - > CreateServiceWorker ( global ,
NS_ConvertUTF8toUTF16 ( aScriptSpec ) ,
aScope ,
getter_AddRefs ( serviceWorker ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
serviceWorker . forget ( aServiceWorker ) ;
return rv ;
}
2015-02-11 14:53:00 +03: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 ( ) ;
registration - > mActiveWorker =
new ServiceWorkerInfo ( registration , aRegistrations [ i ] . currentWorkerURL ( ) ) ;
}
}
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 17:56:00 +04:00
already_AddRefed < ServiceWorkerRegistrationInfo >
ServiceWorkerManager : : GetServiceWorkerRegistrationInfo ( nsPIDOMWindow * aWindow )
2014-07-11 22:52:19 +04:00
{
2014-07-21 10:25:44 +04:00
nsCOMPtr < nsIDocument > document = aWindow - > GetExtantDoc ( ) ;
2014-08-19 17:56:00 +04:00
return GetServiceWorkerRegistrationInfo ( document ) ;
2014-07-11 22:52:19 +04:00
}
2014-08-19 17:56:00 +04:00
already_AddRefed < ServiceWorkerRegistrationInfo >
ServiceWorkerManager : : GetServiceWorkerRegistrationInfo ( nsIDocument * aDoc )
2014-07-11 22:52:19 +04:00
{
nsCOMPtr < nsIURI > documentURI = aDoc - > GetDocumentURI ( ) ;
2014-08-19 17:56:00 +04:00
return GetServiceWorkerRegistrationInfo ( documentURI ) ;
2014-07-11 22:52:19 +04:00
}
2014-08-19 17:56:00 +04:00
already_AddRefed < ServiceWorkerRegistrationInfo >
ServiceWorkerManager : : GetServiceWorkerRegistrationInfo ( nsIURI * aURI )
2014-07-11 22:52:19 +04:00
{
nsCString spec ;
2014-07-15 01:15:23 +04:00
nsresult rv = aURI - > GetSpec ( spec ) ;
2014-07-11 22:52:19 +04:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return nullptr ;
}
2015-02-09 07:33:39 +03:00
nsCString scope = FindScopeForPath ( mOrderedScopes , spec ) ;
2014-07-11 22:52:19 +04:00
if ( scope . IsEmpty ( ) ) {
return nullptr ;
}
2014-08-19 17:56:00 +04:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-02-09 07:33:39 +03:00
mServiceWorkerRegistrationInfos . Get ( scope , getter_AddRefs ( registration ) ) ;
2014-07-11 22:52:19 +04:00
// ordered scopes and registrations better be in sync.
MOZ_ASSERT ( registration ) ;
2014-07-14 21:33:44 +04:00
if ( registration - > mPendingUninstall ) {
return nullptr ;
}
2014-07-28 17:57:31 +04:00
return registration . forget ( ) ;
2014-07-11 22:52:19 +04:00
}
/* static */ void
ServiceWorkerManager : : AddScope ( nsTArray < nsCString > & aList , const nsACString & aScope )
{
for ( uint32_t i = 0 ; i < aList . Length ( ) ; + + i ) {
const nsCString & current = aList [ i ] ;
// Perfect match!
if ( aScope . Equals ( current ) ) {
return ;
}
2014-08-22 03:38:40 +04: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 ) ) {
2014-07-11 22:52:19 +04:00
aList . InsertElementAt ( i , aScope ) ;
return ;
}
}
aList . AppendElement ( aScope ) ;
}
/* static */ nsCString
ServiceWorkerManager : : FindScopeForPath ( nsTArray < nsCString > & aList , const nsACString & aPath )
{
nsCString match ;
for ( uint32_t i = 0 ; i < aList . Length ( ) ; + + i ) {
const nsCString & current = aList [ i ] ;
2014-08-22 03:38:40 +04:00
if ( StringBeginsWith ( aPath , current ) ) {
match = current ;
break ;
2014-07-11 22:52:19 +04:00
}
}
return match ;
}
/* static */ void
ServiceWorkerManager : : RemoveScope ( nsTArray < nsCString > & aList , const nsACString & aScope )
{
aList . RemoveElement ( aScope ) ;
}
2014-07-21 10:25:44 +04:00
void
ServiceWorkerManager : : MaybeStartControlling ( nsIDocument * aDoc )
{
AssertIsOnMainThread ( ) ;
2014-08-19 17:56:00 +04:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration =
GetServiceWorkerRegistrationInfo ( aDoc ) ;
2014-12-19 13:00:29 +03:00
if ( registration ) {
2015-02-09 07:33:39 +03:00
MOZ_ASSERT ( ! mControlledDocuments . Contains ( aDoc ) ) ;
2014-07-21 10:25:44 +04:00
registration - > StartControllingADocument ( ) ;
// Use the already_AddRefed<> form of Put to avoid the addref-deref since
// we don't need the registration pointer in this function anymore.
2015-02-09 07:33:39 +03:00
mControlledDocuments . Put ( aDoc , registration . forget ( ) ) ;
2014-07-21 10:25:44 +04:00
}
}
void
ServiceWorkerManager : : MaybeStopControlling ( nsIDocument * aDoc )
{
MOZ_ASSERT ( aDoc ) ;
2014-08-19 17:56:00 +04:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-02-09 07:33:39 +03:00
mControlledDocuments . Remove ( aDoc , getter_AddRefs ( registration ) ) ;
2014-07-21 10:25:44 +04: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 ) {
registration - > StopControllingADocument ( ) ;
2014-10-25 02:11:26 +04:00
if ( ! registration - > IsControllingDocuments ( ) ) {
2015-02-11 01:33:23 +03:00
if ( registration - > mPendingUninstall ) {
registration - > Clear ( ) ;
RemoveRegistration ( registration ) ;
} else {
registration - > TryToActivate ( ) ;
}
2014-10-25 02:11:26 +04:00
}
2014-07-21 10:25:44 +04:00
}
}
2014-07-11 22:52:19 +04:00
NS_IMETHODIMP
ServiceWorkerManager : : GetScopeForUrl ( const nsAString & aUrl , nsAString & aScope )
{
nsCOMPtr < nsIURI > uri ;
nsresult rv = NS_NewURI ( getter_AddRefs ( uri ) , aUrl , nullptr , nullptr ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_FAILURE ;
}
2014-08-19 17:56:00 +04:00
nsRefPtr < ServiceWorkerRegistrationInfo > r = GetServiceWorkerRegistrationInfo ( uri ) ;
2014-07-11 22:52:19 +04:00
if ( ! r ) {
return NS_ERROR_FAILURE ;
}
aScope = NS_ConvertUTF8toUTF16 ( r - > mScope ) ;
return NS_OK ;
}
2014-07-12 00:07:59 +04:00
2014-07-15 01:15:23 +04:00
NS_IMETHODIMP
2014-10-27 21:52:57 +03:00
ServiceWorkerManager : : AddRegistrationEventListener ( const nsAString & aScope , nsIDOMEventTarget * aListener )
2014-07-15 01:15:23 +04:00
{
2014-08-28 00:33:20 +04:00
AssertIsOnMainThread ( ) ;
2014-10-27 21:52:57 +03:00
nsAutoCString scope = NS_ConvertUTF16toUTF8 ( aScope ) ;
2014-07-15 01:15:23 +04:00
2014-08-19 17:56:00 +04:00
// TODO: this is very very bad:
ServiceWorkerRegistration * registration = static_cast < ServiceWorkerRegistration * > ( aListener ) ;
2015-02-09 07:33:39 +03:00
MOZ_ASSERT ( ! mServiceWorkerRegistrations . Contains ( registration ) ) ;
2014-10-27 21:52:57 +03:00
# ifdef DEBUG
// Ensure a registration is only listening for it's own scope.
nsAutoString regScope ;
registration - > GetScope ( regScope ) ;
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
MOZ_ASSERT ( scope . Equals ( NS_ConvertUTF16toUTF8 ( regScope ) ) ) ;
# endif
2015-02-09 07:33:39 +03:00
mServiceWorkerRegistrations . AppendElement ( registration ) ;
2014-07-15 01:15:23 +04:00
return NS_OK ;
}
NS_IMETHODIMP
2014-10-27 21:52:57 +03:00
ServiceWorkerManager : : RemoveRegistrationEventListener ( const nsAString & aScope , nsIDOMEventTarget * aListener )
2014-07-15 01:15:23 +04:00
{
2014-08-28 00:33:20 +04:00
AssertIsOnMainThread ( ) ;
2014-10-27 21:52:57 +03:00
nsCString scope = NS_ConvertUTF16toUTF8 ( aScope ) ;
2014-08-19 17:56:00 +04:00
ServiceWorkerRegistration * registration = static_cast < ServiceWorkerRegistration * > ( aListener ) ;
2015-02-09 07:33:39 +03:00
MOZ_ASSERT ( mServiceWorkerRegistrations . Contains ( registration ) ) ;
2014-10-27 21:52:57 +03:00
# ifdef DEBUG
// Ensure a registration is unregistering for it's own scope.
nsAutoString regScope ;
registration - > GetScope ( regScope ) ;
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
MOZ_ASSERT ( scope . Equals ( NS_ConvertUTF16toUTF8 ( regScope ) ) ) ;
# endif
2015-02-09 07:33:39 +03:00
mServiceWorkerRegistrations . RemoveElement ( registration ) ;
2014-07-15 01:15:23 +04:00
return NS_OK ;
}
void
2014-08-19 17:56:00 +04:00
ServiceWorkerManager : : FireEventOnServiceWorkerRegistrations (
ServiceWorkerRegistrationInfo * aRegistration ,
2014-07-15 01:15:23 +04:00
const nsAString & aName )
{
AssertIsOnMainThread ( ) ;
2015-02-09 07:33:39 +03:00
nsTObserverArray < ServiceWorkerRegistration * > : : ForwardIterator it ( mServiceWorkerRegistrations ) ;
while ( it . HasMore ( ) ) {
nsRefPtr < ServiceWorkerRegistration > target = it . GetNext ( ) ;
nsAutoString regScope ;
target - > GetScope ( regScope ) ;
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
NS_ConvertUTF16toUTF8 utf8Scope ( regScope ) ;
if ( utf8Scope . Equals ( aRegistration - > mScope ) ) {
nsresult rv = target - > DispatchTrustedEvent ( aName ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
// Warn only.
2014-07-15 01:15:23 +04:00
}
}
}
}
2014-07-24 01:05:08 +04:00
/*
2014-08-25 09:35:03 +04:00
* This is used for installing , waiting and active .
2014-07-24 01:05:08 +04:00
*/
NS_IMETHODIMP
2014-08-25 09:35:03 +04:00
ServiceWorkerManager : : GetServiceWorkerForScope ( nsIDOMWindow * aWindow ,
const nsAString & aScope ,
WhichServiceWorker aWhichWorker ,
nsISupports * * aServiceWorker )
2014-07-24 01:05:08 +04:00
{
2014-08-25 09:35:03 +04:00
AssertIsOnMainThread ( ) ;
2014-07-24 01:05:08 +04:00
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
2014-08-25 09:35:03 +04:00
if ( ! window ) {
return NS_ERROR_FAILURE ;
}
2014-07-24 01:05:08 +04:00
2014-08-25 09:35:03 +04:00
nsCOMPtr < nsIDocument > doc = window - > GetExtantDoc ( ) ;
MOZ_ASSERT ( doc ) ;
///////////////////////////////////////////
// Security check
2014-10-27 21:52:57 +03:00
nsAutoCString scope = NS_ConvertUTF16toUTF8 ( aScope ) ;
2014-08-25 09:35:03 +04: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-02-09 07:33:39 +03:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration = GetRegistration ( scope ) ;
2014-07-24 01:05:08 +04:00
if ( ! registration ) {
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 13:00:29 +03:00
info = registration - > mActiveWorker ;
2014-07-24 01:05:08 +04:00
} else {
MOZ_CRASH ( " Invalid worker type " ) ;
}
if ( ! info ) {
return NS_ERROR_DOM_NOT_FOUND_ERR ;
}
nsRefPtr < ServiceWorker > serviceWorker ;
2014-08-25 09:35:03 +04:00
rv = CreateServiceWorkerForWindow ( window ,
2014-12-19 14:25:56 +03:00
info - > ScriptSpec ( ) ,
2014-08-25 09:35:03 +04:00
registration - > mScope ,
getter_AddRefs ( serviceWorker ) ) ;
2014-07-24 01:05:08 +04:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2014-12-19 14:25:56 +03:00
serviceWorker - > SetState ( info - > State ( ) ) ;
2014-07-24 01:05:08 +04:00
serviceWorker . forget ( aServiceWorker ) ;
return NS_OK ;
}
2015-02-19 04:34:29 +03:00
class FetchEventRunnable : public WorkerRunnable
, public nsIHttpHeaderVisitor {
nsMainThreadPtrHandle < nsIInterceptedChannel > mInterceptedChannel ;
nsMainThreadPtrHandle < ServiceWorker > mServiceWorker ;
nsTArray < nsCString > mHeaderNames ;
nsTArray < nsCString > mHeaderValues ;
uint64_t mWindowId ;
nsCString mSpec ;
nsCString mMethod ;
bool mIsReload ;
public :
FetchEventRunnable ( WorkerPrivate * aWorkerPrivate ,
nsMainThreadPtrHandle < nsIInterceptedChannel > & aChannel ,
nsMainThreadPtrHandle < ServiceWorker > & aServiceWorker ,
uint64_t aWindowId )
: WorkerRunnable ( aWorkerPrivate , WorkerThreadModifyBusyCount )
, mInterceptedChannel ( aChannel )
, mServiceWorker ( aServiceWorker )
, mWindowId ( aWindowId )
{
MOZ_ASSERT ( aWorkerPrivate ) ;
}
NS_DECL_ISUPPORTS_INHERITED
NS_IMETHOD
VisitHeader ( const nsACString & aHeader , const nsACString & aValue )
{
mHeaderNames . AppendElement ( aHeader ) ;
mHeaderValues . AppendElement ( aValue ) ;
return NS_OK ;
}
nsresult
Init ( )
{
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 ) ;
nsCOMPtr < nsIHttpChannel > httpChannel = do_QueryInterface ( channel ) ;
NS_ENSURE_TRUE ( httpChannel , NS_ERROR_NOT_AVAILABLE ) ;
rv = httpChannel - > GetRequestMethod ( mMethod ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
uint32_t loadFlags ;
rv = channel - > GetLoadFlags ( & loadFlags ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
//TODO(jdm): we should probably include reload-ness in the loadinfo or as a separate load flag
mIsReload = false ;
rv = httpChannel - > VisitRequestHeaders ( this ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
return NS_OK ;
}
bool
WorkerRun ( JSContext * aCx , WorkerPrivate * aWorkerPrivate )
{
MOZ_ASSERT ( aWorkerPrivate ) ;
return DispatchFetchEvent ( aCx , aWorkerPrivate ) ;
}
private :
~ FetchEventRunnable ( ) { }
class ResumeRequest MOZ_FINAL : public nsRunnable {
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 ( ) ) ;
RequestOrUSVString requestInfo ;
* requestInfo . SetAsUSVString ( ) . ToAStringPtr ( ) = NS_ConvertUTF8toUTF16 ( mSpec ) ;
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 + + ) {
ErrorResult rv ;
internalHeaders - > Set ( mHeaderNames [ i ] , mHeaderValues [ i ] , rv ) ;
if ( NS_WARN_IF ( rv . Failed ( ) ) ) {
return false ;
}
}
nsRefPtr < Headers > headers = new Headers ( globalObj . GetAsSupports ( ) , internalHeaders ) ;
reqInit . mHeaders . Construct ( ) ;
reqInit . mHeaders . Value ( ) . SetAsHeaders ( ) = headers ;
//TODO(jdm): set request body
//TODO(jdm): set request same-origin mode and credentials
ErrorResult rv ;
nsRefPtr < Request > request = Request : : Constructor ( globalObj , requestInfo , reqInit , rv ) ;
if ( NS_WARN_IF ( rv . Failed ( ) ) ) {
return false ;
}
RootedDictionary < FetchEventInit > init ( aCx ) ;
init . mRequest . Construct ( ) ;
init . mRequest . Value ( ) = request ;
init . mBubbles = false ;
init . mCancelable = true ;
init . mIsReload . Construct ( mIsReload ) ;
nsRefPtr < FetchEvent > event =
FetchEvent : : Constructor ( globalObj , NS_LITERAL_STRING ( " fetch " ) , init , rv ) ;
if ( NS_WARN_IF ( rv . Failed ( ) ) ) {
return false ;
}
event - > PostInit ( mInterceptedChannel , mServiceWorker , mWindowId ) ;
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
ServiceWorkerManager : : DispatchFetchEvent ( nsIDocument * aDoc , nsIInterceptedChannel * aChannel )
{
MOZ_ASSERT ( aChannel ) ;
nsCOMPtr < nsISupports > serviceWorker ;
bool isNavigation = false ;
nsresult rv = aChannel - > GetIsNavigation ( & isNavigation ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
if ( ! isNavigation ) {
MOZ_ASSERT ( aDoc ) ;
rv = GetDocumentController ( aDoc - > GetWindow ( ) , getter_AddRefs ( serviceWorker ) ) ;
} 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 =
GetServiceWorkerRegistrationInfo ( uri ) ;
// This should only happen if IsAvailableForURI() returned true.
MOZ_ASSERT ( registration ) ;
MOZ_ASSERT ( registration - > mActiveWorker ) ;
nsRefPtr < ServiceWorker > sw ;
rv = CreateServiceWorker ( registration - > mPrincipal ,
registration - > mActiveWorker - > ScriptSpec ( ) ,
registration - > mScope ,
getter_AddRefs ( sw ) ) ;
serviceWorker = sw . forget ( ) ;
}
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
nsMainThreadPtrHandle < nsIInterceptedChannel > handle (
new nsMainThreadPtrHolder < nsIInterceptedChannel > ( aChannel , false ) ) ;
uint64_t windowId = aDoc ? aDoc - > GetInnerWindow ( ) - > WindowID ( ) : 0 ;
nsRefPtr < ServiceWorker > sw = static_cast < ServiceWorker * > ( serviceWorker . get ( ) ) ;
nsMainThreadPtrHandle < ServiceWorker > serviceWorkerHandle (
new nsMainThreadPtrHolder < ServiceWorker > ( sw ) ) ;
nsRefPtr < FetchEventRunnable > event =
new FetchEventRunnable ( sw - > GetWorkerPrivate ( ) , handle , serviceWorkerHandle , windowId ) ;
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
ServiceWorkerManager : : IsAvailableForURI ( nsIURI * aURI , bool * aIsAvailable )
{
MOZ_ASSERT ( aURI ) ;
MOZ_ASSERT ( aIsAvailable ) ;
nsRefPtr < ServiceWorkerRegistrationInfo > registration =
GetServiceWorkerRegistrationInfo ( aURI ) ;
* 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 ) ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
* aIsControlled = ! ! registration ;
return NS_OK ;
}
nsresult
ServiceWorkerManager : : GetDocumentRegistration ( nsIDocument * aDoc ,
ServiceWorkerRegistrationInfo * * aRegistrationInfo )
{
nsRefPtr < ServiceWorkerRegistrationInfo > registration ;
if ( ! mControlledDocuments . Get ( aDoc , getter_AddRefs ( registration ) ) ) {
return NS_ERROR_FAILURE ;
}
// 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-24 01:05:08 +04: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 17:56:00 +04:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-02-19 04:34:29 +03:00
nsresult rv = GetDocumentRegistration ( doc , getter_AddRefs ( registration ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
2015-02-19 00:00:33 +03:00
}
2014-07-24 01:05:08 +04:00
nsRefPtr < ServiceWorker > serviceWorker ;
2015-02-19 04:34:29 +03:00
rv = CreateServiceWorkerForWindow ( window ,
registration - > mActiveWorker - > ScriptSpec ( ) ,
registration - > mScope ,
getter_AddRefs ( serviceWorker ) ) ;
2014-07-24 01:05:08 +04:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
serviceWorker . forget ( aServiceWorker ) ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerManager : : GetInstalling ( nsIDOMWindow * aWindow ,
2014-08-25 09:35:03 +04:00
const nsAString & aScope ,
2014-07-24 01:05:08 +04:00
nsISupports * * aServiceWorker )
{
2014-08-25 09:35:03 +04:00
return GetServiceWorkerForScope ( aWindow , aScope ,
WhichServiceWorker : : INSTALLING_WORKER ,
aServiceWorker ) ;
2014-07-24 01:05:08 +04:00
}
NS_IMETHODIMP
ServiceWorkerManager : : GetWaiting ( nsIDOMWindow * aWindow ,
2014-08-25 09:35:03 +04:00
const nsAString & aScope ,
2014-07-24 01:05:08 +04:00
nsISupports * * aServiceWorker )
{
2014-08-25 09:35:03 +04:00
return GetServiceWorkerForScope ( aWindow , aScope ,
WhichServiceWorker : : WAITING_WORKER ,
aServiceWorker ) ;
2014-07-24 01:05:08 +04:00
}
NS_IMETHODIMP
2014-08-25 09:35:03 +04:00
ServiceWorkerManager : : GetActive ( nsIDOMWindow * aWindow ,
const nsAString & aScope ,
nsISupports * * aServiceWorker )
2014-07-24 01:05:08 +04:00
{
2014-08-25 09:35:03 +04:00
return GetServiceWorkerForScope ( aWindow , aScope ,
WhichServiceWorker : : ACTIVE_WORKER ,
aServiceWorker ) ;
2014-07-24 01:05:08 +04:00
}
2014-07-03 04:48:50 +04:00
NS_IMETHODIMP
2015-02-17 15:36:09 +03:00
ServiceWorkerManager : : CreateServiceWorker ( nsIPrincipal * aPrincipal ,
const nsACString & aScriptSpec ,
2014-07-03 04:48:50 +04:00
const nsACString & aScope ,
ServiceWorker * * aServiceWorker )
{
AssertIsOnMainThread ( ) ;
2015-02-17 15:36:09 +03:00
MOZ_ASSERT ( aPrincipal ) ;
2014-07-03 04:48:50 +04:00
WorkerPrivate : : LoadInfo info ;
nsresult rv = NS_NewURI ( getter_AddRefs ( info . mBaseURI ) , aScriptSpec , nullptr , nullptr ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
info . mResolvedScriptURI = info . mBaseURI ;
rv = info . mBaseURI - > GetHost ( info . mDomain ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-02-17 15:36:09 +03:00
info . mPrincipal = aPrincipal ;
2014-12-12 19:06:00 +03: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.
rv = NS_NewLoadGroup ( getter_AddRefs ( info . mLoadGroup ) , info . mPrincipal ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2014-07-03 04:48:50 +04:00
return rv ;
}
nsRefPtr < ServiceWorker > serviceWorker ;
2015-02-10 11:58:00 +03:00
RuntimeService * rs = RuntimeService : : GetOrCreateService ( ) ;
2014-07-03 04:48:50 +04:00
if ( ! rs ) {
return NS_ERROR_FAILURE ;
}
2014-12-19 13:00:29 +03:00
AutoJSAPI jsapi ;
jsapi . Init ( ) ;
rv = rs - > CreateServiceWorkerFromLoadInfo ( jsapi . cx ( ) , & info ,
NS_ConvertUTF8toUTF16 ( aScriptSpec ) ,
aScope ,
2014-07-03 04:48:50 +04:00
getter_AddRefs ( serviceWorker ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
serviceWorker . forget ( aServiceWorker ) ;
return NS_OK ;
}
2014-07-24 01:05:08 +04:00
void
2014-08-19 17:56:00 +04:00
ServiceWorkerManager : : InvalidateServiceWorkerRegistrationWorker ( ServiceWorkerRegistrationInfo * aRegistration ,
WhichServiceWorker aWhichOnes )
2014-07-24 01:05:08 +04:00
{
AssertIsOnMainThread ( ) ;
2015-02-09 07:33:39 +03:00
nsTObserverArray < ServiceWorkerRegistration * > : : ForwardIterator it ( mServiceWorkerRegistrations ) ;
while ( it . HasMore ( ) ) {
nsRefPtr < ServiceWorkerRegistration > target = it . GetNext ( ) ;
nsAutoString regScope ;
target - > GetScope ( regScope ) ;
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
2014-07-24 01:05:08 +04:00
2015-02-09 07:33:39 +03:00
NS_ConvertUTF16toUTF8 utf8Scope ( regScope ) ;
2014-07-24 01:05:08 +04:00
2015-02-09 07:33:39 +03:00
if ( utf8Scope . Equals ( aRegistration - > mScope ) ) {
target - > InvalidateWorkerReference ( aWhichOnes ) ;
2014-07-24 01:05:08 +04:00
}
}
}
2014-10-06 19:45:14 +04:00
NS_IMETHODIMP
ServiceWorkerManager : : Update ( const nsAString & aScope )
{
NS_ConvertUTF16toUTF8 scope ( aScope ) ;
nsRefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-02-09 07:33:39 +03:00
mServiceWorkerRegistrationInfos . Get ( scope , getter_AddRefs ( registration ) ) ;
2014-10-06 19:45:14 +04:00
if ( NS_WARN_IF ( ! registration ) ) {
return NS_OK ;
}
2014-12-19 13:00:29 +03:00
// FIXME(nsm): Bug 1089889 Refactor this into SoftUpdate.
2014-10-06 19:45:14 +04:00
if ( registration - > mPendingUninstall ) {
return NS_OK ;
}
if ( registration - > mInstallingWorker ) {
return NS_OK ;
}
2015-02-09 07:33:39 +03:00
ServiceWorkerJobQueue * queue = GetOrCreateJobQueue ( scope ) ;
2014-12-19 13:00:29 +03:00
MOZ_ASSERT ( queue ) ;
nsRefPtr < ServiceWorkerUpdateFinishCallback > cb =
new ServiceWorkerUpdateFinishCallback ( ) ;
2015-01-23 01:10:38 +03:00
nsRefPtr < ServiceWorkerRegisterJob > job =
new ServiceWorkerRegisterJob ( queue , registration , cb ) ;
2014-12-19 13:00:29 +03:00
queue - > Append ( job ) ;
2014-10-06 19:45:14 +04:00
return NS_OK ;
}
2014-10-27 14:03:00 +03:00
namespace {
class MOZ_STACK_CLASS FilterRegistrationData
{
public :
FilterRegistrationData ( nsTArray < uint64_t > * aDocuments ,
ServiceWorkerRegistrationInfo * aRegistration )
: mDocuments ( aDocuments ) ,
mRegistration ( aRegistration )
{
}
nsTArray < uint64_t > * mDocuments ;
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 ;
}
nsCOMPtr < nsIDocument > document = do_QueryInterface ( aKey ) ;
if ( ! document | | ! document - > GetInnerWindow ( ) ) {
return PL_DHASH_NEXT ;
}
data - > mDocuments - > AppendElement ( document - > GetInnerWindow ( ) - > WindowID ( ) ) ;
return PL_DHASH_NEXT ;
}
2014-10-28 23:11:31 +03: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 ;
}
nsCOMPtr < nsPIDOMWindow > w = doc - > GetWindow ( ) ;
MOZ_ASSERT ( w ) ;
auto * window = static_cast < nsGlobalWindow * > ( w . get ( ) ) ;
if ( NS_WARN_IF ( ! window ) ) {
NS_WARNING ( " No valid nsGlobalWindow " ) ;
return PL_DHASH_NEXT ;
}
ErrorResult result ;
dom : : Navigator * navigator = window - > GetNavigator ( result ) ;
if ( NS_WARN_IF ( result . Failed ( ) ) ) {
return PL_DHASH_NEXT ;
}
nsRefPtr < ServiceWorkerContainer > container = navigator - > ServiceWorker ( ) ;
result = container - > DispatchTrustedEvent ( NS_LITERAL_STRING ( " controllerchange " ) ) ;
if ( result . Failed ( ) ) {
NS_WARNING ( " Failed to dispatch controllerchange event " ) ;
}
return PL_DHASH_NEXT ;
}
2014-10-27 14:03:00 +03:00
} // anonymous namespace
void
2015-02-20 18:16:17 +03:00
ServiceWorkerManager : : GetAllClients ( const nsCString & aScope ,
nsTArray < uint64_t > * aControlledDocuments )
2014-10-27 14:03:00 +03:00
{
2015-02-09 07:33:39 +03:00
nsRefPtr < ServiceWorkerRegistrationInfo > registration = GetRegistration ( aScope ) ;
2014-11-04 15:04:00 +03:00
if ( ! registration ) {
// The registration was removed, leave the array empty.
return ;
}
2014-10-27 14:03:00 +03:00
FilterRegistrationData data ( aControlledDocuments , registration ) ;
2015-02-09 07:33:39 +03:00
mControlledDocuments . EnumerateRead ( EnumControlledDocuments , & data ) ;
2014-10-27 14:03:00 +03:00
}
2014-12-19 13:00:29 +03:00
void
ServiceWorkerManager : : FireControllerChange ( ServiceWorkerRegistrationInfo * aRegistration )
{
2015-02-09 07:33:39 +03:00
mControlledDocuments . EnumerateRead ( FireControllerChangeOnMatchingDocument , aRegistration ) ;
2014-12-19 13:00:29 +03:00
}
2015-02-09 07:33:39 +03:00
ServiceWorkerRegistrationInfo *
2015-02-11 14:53:00 +03:00
ServiceWorkerManager : : CreateNewRegistration ( const nsCString & aScope ,
nsIPrincipal * aPrincipal )
2015-02-09 07:33:39 +03: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 14:53:00 +03:00
ServiceWorkerRegistrationInfo * registration = new ServiceWorkerRegistrationInfo ( aScope , aPrincipal ) ;
2015-02-09 07:33:39 +03:00
// From now on ownership of registration is with
// mServiceWorkerRegistrationInfos.
mServiceWorkerRegistrationInfos . Put ( aScope , registration ) ;
AddScope ( mOrderedScopes , aScope ) ;
return registration ;
}
2015-02-11 01:33:23 +03:00
void
ServiceWorkerManager : : MaybeRemoveRegistration ( ServiceWorkerRegistrationInfo * aRegistration )
{
MOZ_ASSERT ( aRegistration ) ;
nsRefPtr < ServiceWorkerInfo > newest = aRegistration - > Newest ( ) ;
if ( ! newest ) {
RemoveRegistration ( aRegistration ) ;
}
}
2013-11-20 03:15:02 +04:00
END_WORKERS_NAMESPACE