2015-05-03 19:32:37 +00:00
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
2013-11-19 23:15:02 +00: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-06-11 17:42:38 +00:00
# include "mozIApplication.h"
2015-02-11 11:53:00 +00:00
# include "nsIAppsService.h"
2015-11-16 16:04:11 +00:00
# include "nsIConsoleService.h"
2014-07-14 21:15:23 +00:00
# include "nsIDOMEventTarget.h"
2013-11-19 23:15:02 +00:00
# include "nsIDocument.h"
2014-07-03 00:48:50 +00:00
# include "nsIScriptSecurityManager.h"
2014-12-19 10:00:29 +00:00
# include "nsIStreamLoader.h"
# include "nsIHttpChannel.h"
# include "nsIHttpChannelInternal.h"
2015-02-19 01:34:29 +00:00
# include "nsIHttpHeaderVisitor.h"
2015-05-22 07:32:25 +00:00
# include "nsIJARChannel.h"
2015-02-19 01:34:29 +00:00
# include "nsINetworkInterceptController.h"
2015-04-10 08:50:06 +00:00
# include "nsIMutableArray.h"
2015-11-16 16:04:11 +00:00
# include "nsIScriptError.h"
2015-11-30 19:29:51 +00:00
# include "nsISimpleEnumerator.h"
2015-12-11 19:53:10 +00:00
# include "nsITimer.h"
2015-05-04 20:54:22 +00:00
# include "nsIUploadChannel2.h"
2013-11-19 23:15:02 +00:00
# include "nsPIDOMWindow.h"
2015-03-18 16:46:38 +00:00
# include "nsScriptLoader.h"
2015-11-16 16:04:11 +00:00
# include "nsServiceManagerUtils.h"
2015-02-19 01:34:29 +00:00
# include "nsDebug.h"
2015-11-27 22:27:53 +00:00
# include "nsISupportsPrimitives.h"
2013-11-19 23:15:02 +00:00
# include "jsapi.h"
2015-06-03 08:43:43 +00:00
# include "mozilla/BasePrincipal.h"
2015-06-04 17:21:52 +00:00
# include "mozilla/ClearOnShutdown.h"
2015-04-24 18:42:13 +00:00
# include "mozilla/ErrorNames.h"
2014-12-12 16:06:00 +00:00
# include "mozilla/LoadContext.h"
2015-06-05 06:11:18 +00:00
# include "mozilla/Telemetry.h"
2013-11-19 23:15:02 +00:00
# include "mozilla/dom/BindingUtils.h"
2015-03-06 01:37:49 +00:00
# include "mozilla/dom/ContentParent.h"
2014-06-11 16:12:56 +00:00
# include "mozilla/dom/DOMError.h"
2014-07-03 00:48:35 +00:00
# include "mozilla/dom/ErrorEvent.h"
2015-02-19 01:34:29 +00:00
# include "mozilla/dom/Headers.h"
2015-09-02 16:20:30 +00:00
# include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
2015-06-11 13:32:54 +00:00
# include "mozilla/dom/indexedDB/IDBFactory.h"
2015-02-19 01:34:29 +00:00
# include "mozilla/dom/InternalHeaders.h"
2014-10-28 20:11:31 +00:00
# include "mozilla/dom/Navigator.h"
2015-06-26 01:50:25 +00:00
# include "mozilla/dom/NotificationEvent.h"
2014-07-03 00:48:50 +00:00
# include "mozilla/dom/PromiseNativeHandler.h"
2015-02-19 01:34:29 +00:00
# include "mozilla/dom/Request.h"
# include "mozilla/dom/RootedDictionary.h"
2015-02-11 11:53:00 +00:00
# include "mozilla/ipc/BackgroundChild.h"
# include "mozilla/ipc/PBackgroundChild.h"
# include "mozilla/ipc/PBackgroundSharedTypes.h"
2015-04-13 17:36:06 +00:00
# include "mozilla/unused.h"
2015-07-15 21:01:02 +00:00
# include "mozilla/EnumSet.h"
2014-06-11 16:12:56 +00:00
2015-10-19 02:38:06 +00:00
# include "nsContentPolicyUtils.h"
2015-11-06 19:10:17 +00:00
# include "nsContentSecurityManager.h"
2013-11-19 23:15:02 +00:00
# include "nsContentUtils.h"
2014-10-28 20:11:31 +00:00
# include "nsGlobalWindow.h"
2013-11-19 23:15:02 +00:00
# include "nsNetUtil.h"
2015-07-07 02:17:00 +00:00
# include "nsIURL.h"
2014-06-11 16:12:56 +00:00
# include "nsProxyRelease.h"
2015-04-15 16:47:03 +00:00
# include "nsQueryObject.h"
2013-11-19 23:15:02 +00:00
# include "nsTArray.h"
# include "RuntimeService.h"
# include "ServiceWorker.h"
2014-10-27 11:03:00 +00:00
# include "ServiceWorkerClient.h"
2014-10-28 20:11:31 +00:00
# include "ServiceWorkerContainer.h"
2015-06-04 18:51:57 +00:00
# include "ServiceWorkerManagerChild.h"
2015-09-30 23:11:03 +00:00
# include "ServiceWorkerPrivate.h"
2015-06-03 08:43:43 +00:00
# include "ServiceWorkerRegistrar.h"
2014-08-19 13:56:00 +00:00
# include "ServiceWorkerRegistration.h"
2015-03-18 16:46:38 +00:00
# include "ServiceWorkerScriptCache.h"
2014-07-03 00:48:50 +00:00
# include "ServiceWorkerEvents.h"
2015-07-02 12:54:00 +00:00
# include "SharedWorker.h"
2013-11-19 23:15:02 +00:00
# include "WorkerInlines.h"
2014-06-11 16:12:56 +00:00
# include "WorkerPrivate.h"
# include "WorkerRunnable.h"
2014-07-03 00:48:50 +00:00
# include "WorkerScope.h"
2013-11-19 23:15:02 +00:00
2015-09-17 12:10:42 +00:00
# ifndef MOZ_SIMPLEPUSH
# include "mozilla/dom/TypedArray.h"
# endif
2014-12-12 16:06:00 +00:00
# ifdef PostMessage
# undef PostMessage
# endif
2013-11-19 23:15:02 +00:00
using namespace mozilla ;
using namespace mozilla : : dom ;
2015-02-11 11:53:00 +00:00
using namespace mozilla : : ipc ;
2013-11-19 23:15:02 +00:00
BEGIN_WORKERS_NAMESPACE
2015-03-06 01:37:49 +00:00
# define PURGE_DOMAIN_DATA "browser:purge-domain-data"
# define PURGE_SESSION_HISTORY "browser:purge-session-history"
2015-08-19 06:46:53 +00:00
# define CLEAR_ORIGIN_DATA "clear-origin-data"
2015-03-06 01:37:49 +00:00
2015-03-17 15:47:02 +00:00
static_assert ( nsIHttpChannelInternal : : CORS_MODE_SAME_ORIGIN = = static_cast < uint32_t > ( RequestMode : : Same_origin ) ,
" RequestMode enumeration value should match Necko CORS mode value. " ) ;
static_assert ( nsIHttpChannelInternal : : CORS_MODE_NO_CORS = = static_cast < uint32_t > ( RequestMode : : No_cors ) ,
" RequestMode enumeration value should match Necko CORS mode value. " ) ;
static_assert ( nsIHttpChannelInternal : : CORS_MODE_CORS = = static_cast < uint32_t > ( RequestMode : : Cors ) ,
" RequestMode enumeration value should match Necko CORS mode value. " ) ;
2015-08-31 21:26:29 +00:00
static_assert ( nsIHttpChannelInternal : : REDIRECT_MODE_FOLLOW = = static_cast < uint32_t > ( RequestRedirect : : Follow ) ,
" RequestRedirect enumeration value should make Necko Redirect mode value. " ) ;
static_assert ( nsIHttpChannelInternal : : REDIRECT_MODE_ERROR = = static_cast < uint32_t > ( RequestRedirect : : Error ) ,
" RequestRedirect enumeration value should make Necko Redirect mode value. " ) ;
static_assert ( nsIHttpChannelInternal : : REDIRECT_MODE_MANUAL = = static_cast < uint32_t > ( RequestRedirect : : Manual ) ,
" RequestRedirect enumeration value should make Necko Redirect mode value. " ) ;
static_assert ( 3 = = static_cast < uint32_t > ( RequestRedirect : : EndGuard_ ) ,
" RequestRedirect enumeration value should make Necko Redirect mode value. " ) ;
2015-06-04 17:21:52 +00:00
static StaticRefPtr < ServiceWorkerManager > gInstance ;
2015-11-23 13:47:53 +00:00
struct ServiceWorkerManager : : RegistrationDataPerPrincipal final
2015-06-03 08:43:43 +00:00
{
// Ordered list of scopes for glob matching.
// Each entry is an absolute URL representing the scope.
// Each value of the hash table is an array of an absolute URLs representing
// the scopes.
//
// An array is used for now since the number of controlled scopes per
// domain is expected to be relatively low. If that assumption was proved
// wrong this should be replaced with a better structure to avoid the
// memmoves associated with inserting stuff in the middle of the array.
nsTArray < nsCString > mOrderedScopes ;
// Scope to registration.
// The scope should be a fully qualified valid URL.
nsRefPtrHashtable < nsCStringHashKey , ServiceWorkerRegistrationInfo > mInfos ;
// Maps scopes to job queues.
nsClassHashtable < nsCStringHashKey , ServiceWorkerJobQueue > mJobQueues ;
2015-12-11 19:53:10 +00:00
// Map scopes to scheduled update timers.
nsInterfaceHashtable < nsCStringHashKey , nsITimer > mUpdateTimers ;
2015-06-03 08:43:43 +00:00
} ;
2015-11-23 13:47:53 +00:00
struct ServiceWorkerManager : : PendingOperation final
2015-02-11 11:53:00 +00:00
{
nsCOMPtr < nsIRunnable > mRunnable ;
ServiceWorkerJobQueue * mQueue ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerJob > mJob ;
2015-02-11 11:53:00 +00:00
ServiceWorkerRegistrationData mRegistration ;
} ;
2015-06-03 08:43:43 +00:00
class ServiceWorkerJob : public nsISupports
{
2015-11-26 17:03:10 +00:00
friend class ServiceWorkerJobQueue ;
2015-06-03 08:43:43 +00:00
public :
NS_DECL_ISUPPORTS
2015-11-26 17:03:10 +00:00
enum Type
{
RegisterJob ,
UpdateJob ,
InstallJob ,
UnregisterJob
} ;
2015-06-03 08:43:43 +00:00
virtual void Start ( ) = 0 ;
2015-11-26 17:03:10 +00:00
bool
IsRegisterOrInstallJob ( ) const
{
return mJobType = = RegisterJob | | mJobType = = UpdateJob | |
mJobType = = InstallJob ;
}
2015-06-03 08:43:43 +00:00
protected :
2015-11-26 17:03:10 +00:00
// The queue keeps the jobs alive, so they can hold a rawptr back to the
// queue.
ServiceWorkerJobQueue * mQueue ;
Type mJobType ;
explicit ServiceWorkerJob ( ServiceWorkerJobQueue * aQueue , Type aJobType )
2015-06-03 08:43:43 +00:00
: mQueue ( aQueue )
2015-11-26 17:03:10 +00:00
, mJobType ( aJobType )
2015-11-23 13:47:53 +00:00
{ }
2015-06-03 08:43:43 +00:00
virtual ~ ServiceWorkerJob ( )
2015-11-23 13:47:53 +00:00
{ }
2015-06-03 08:43:43 +00:00
void
Done ( nsresult aStatus ) ;
} ;
class ServiceWorkerJobQueue final
{
friend class ServiceWorkerJob ;
2015-11-26 17:03:10 +00:00
struct QueueData final
{
QueueData ( )
: mPopping ( false )
{ }
~ QueueData ( )
{
if ( ! mJobs . IsEmpty ( ) ) {
NS_WARNING ( " Pending/running jobs still around on shutdown! " ) ;
}
}
nsTArray < RefPtr < ServiceWorkerJob > > mJobs ;
bool mPopping ;
} ;
2015-06-03 08:43:43 +00:00
const nsCString mOriginAttributesSuffix ;
2015-11-26 17:03:10 +00:00
QueueData mRegistrationJobQueue ;
QueueData mInstallationJobQueue ;
2015-06-03 08:43:43 +00:00
public :
explicit ServiceWorkerJobQueue ( const nsACString & aScopeKey )
: mOriginAttributesSuffix ( aScopeKey )
{ }
~ ServiceWorkerJobQueue ( )
2015-11-26 17:03:10 +00:00
{ }
2015-06-03 08:43:43 +00:00
void
Append ( ServiceWorkerJob * aJob )
{
MOZ_ASSERT ( aJob ) ;
2015-11-26 17:03:10 +00:00
QueueData & queue = GetQueue ( aJob - > mJobType ) ;
MOZ_ASSERT ( ! queue . mJobs . Contains ( aJob ) ) ;
bool wasEmpty = queue . mJobs . IsEmpty ( ) ;
queue . mJobs . AppendElement ( aJob ) ;
2015-06-03 08:43:43 +00:00
if ( wasEmpty ) {
aJob - > Start ( ) ;
}
}
void
CancelJobs ( ) ;
2015-11-26 17:03:10 +00:00
private :
void
CancelJobs ( QueueData & aQueue ) ;
// Internal helper function used to assign jobs to the correct queue.
QueueData &
GetQueue ( ServiceWorkerJob : : Type aType )
2015-06-03 08:43:43 +00:00
{
2015-11-26 17:03:10 +00:00
switch ( aType ) {
case ServiceWorkerJob : : Type : : RegisterJob :
case ServiceWorkerJob : : Type : : UpdateJob :
case ServiceWorkerJob : : Type : : UnregisterJob :
return mRegistrationJobQueue ;
case ServiceWorkerJob : : Type : : InstallJob :
return mInstallationJobQueue ;
default :
MOZ_CRASH ( " Invalid job queue type. " ) ;
return mRegistrationJobQueue ;
2015-06-03 08:43:43 +00:00
}
}
2015-11-26 17:03:10 +00:00
bool
IsEmpty ( )
{
return mRegistrationJobQueue . mJobs . IsEmpty ( ) & &
mInstallationJobQueue . mJobs . IsEmpty ( ) ;
}
2015-06-03 08:43:43 +00:00
void
2015-11-26 17:03:10 +00:00
Pop ( QueueData & aQueue )
2015-06-03 08:43:43 +00:00
{
2015-11-26 17:03:10 +00:00
MOZ_ASSERT ( ! aQueue . mPopping ,
2015-06-03 08:43:43 +00:00
" Pop() called recursively, did you write a job which calls Done() synchronously from Start()? " ) ;
2015-11-26 17:03:10 +00:00
AutoRestore < bool > savePopping ( aQueue . mPopping ) ;
aQueue . mPopping = true ;
MOZ_ASSERT ( ! aQueue . mJobs . IsEmpty ( ) ) ;
aQueue . mJobs . RemoveElementAt ( 0 ) ;
if ( ! aQueue . mJobs . IsEmpty ( ) ) {
aQueue . mJobs [ 0 ] - > Start ( ) ;
} else if ( IsEmpty ( ) ) {
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( swm ) ;
swm - > MaybeRemoveRegistrationInfo ( mOriginAttributesSuffix ) ;
}
}
void
Done ( ServiceWorkerJob * aJob )
{
2015-11-26 17:03:10 +00:00
MOZ_ASSERT ( aJob ) ;
QueueData & queue = GetQueue ( aJob - > mJobType ) ;
MOZ_ASSERT ( ! queue . mJobs . IsEmpty ( ) ) ;
MOZ_ASSERT ( queue . mJobs [ 0 ] = = aJob ) ;
Pop ( queue ) ;
2015-06-03 08:43:43 +00:00
}
} ;
2015-02-11 11:53:00 +00:00
namespace {
nsresult
PopulateRegistrationData ( nsIPrincipal * aPrincipal ,
const ServiceWorkerRegistrationInfo * aRegistration ,
ServiceWorkerRegistrationData & aData )
{
MOZ_ASSERT ( aPrincipal ) ;
MOZ_ASSERT ( aRegistration ) ;
2015-06-03 20:40:46 +00:00
if ( NS_WARN_IF ( ! BasePrincipal : : Cast ( aPrincipal ) - > IsCodebasePrincipal ( ) ) ) {
2015-02-11 11:53:00 +00:00
return NS_ERROR_FAILURE ;
}
2015-06-03 08:43:43 +00:00
nsresult rv = PrincipalToPrincipalInfo ( aPrincipal , & aData . principal ( ) ) ;
2015-02-11 11:53:00 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
aData . scope ( ) = aRegistration - > mScope ;
2015-12-11 19:53:10 +00:00
RefPtr < ServiceWorkerInfo > newest = aRegistration - > Newest ( ) ;
if ( NS_WARN_IF ( ! newest ) ) {
return NS_ERROR_FAILURE ;
}
aData . scriptSpec ( ) = newest - > ScriptSpec ( ) ;
2015-02-11 11:53:00 +00:00
if ( aRegistration - > mActiveWorker ) {
aData . currentWorkerURL ( ) = aRegistration - > mActiveWorker - > ScriptSpec ( ) ;
2015-03-18 16:46:38 +00:00
aData . activeCacheName ( ) = aRegistration - > mActiveWorker - > CacheName ( ) ;
}
if ( aRegistration - > mWaitingWorker ) {
aData . waitingCacheName ( ) = aRegistration - > mWaitingWorker - > CacheName ( ) ;
2015-02-11 11:53:00 +00:00
}
return NS_OK ;
}
2015-06-04 18:51:57 +00:00
class TeardownRunnable final : public nsRunnable
{
public :
explicit TeardownRunnable ( ServiceWorkerManagerChild * aActor )
: mActor ( aActor )
{
MOZ_ASSERT ( mActor ) ;
}
NS_IMETHODIMP Run ( ) override
{
MOZ_ASSERT ( mActor ) ;
mActor - > SendShutdown ( ) ;
return NS_OK ;
}
private :
~ TeardownRunnable ( ) { }
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManagerChild > mActor ;
2015-06-04 18:51:57 +00:00
} ;
2015-07-13 15:25:42 +00:00
} // namespace
2015-02-11 11:53:00 +00:00
2014-12-19 10:00:29 +00:00
NS_IMPL_ISUPPORTS0 ( ServiceWorkerJob )
2014-06-11 16:12:56 +00:00
void
2014-12-19 10:00:29 +00:00
ServiceWorkerJob : : Done ( nsresult aStatus )
2014-06-11 16:12:56 +00:00
{
2014-12-19 10:00:29 +00:00
if ( NS_WARN_IF ( NS_FAILED ( aStatus ) ) ) {
2015-04-24 18:42:13 +00:00
# ifdef DEBUG
nsAutoCString errorName ;
GetErrorName ( aStatus , errorName ) ;
# endif
2015-11-04 16:26:46 +00:00
NS_WARNING ( nsPrintfCString ( " ServiceWorkerJob failed with error: %s " ,
2015-04-24 18:55:06 +00:00
errorName . get ( ) ) . get ( ) ) ;
2014-06-11 16:12:56 +00:00
}
2014-07-03 00:48:35 +00:00
2014-12-19 10:00:29 +00:00
if ( mQueue ) {
mQueue - > Done ( this ) ;
2014-07-03 00:48:35 +00:00
}
}
2014-07-14 17:33:44 +00:00
void
ServiceWorkerRegistrationInfo : : Clear ( )
{
if ( mInstallingWorker ) {
2014-12-19 11:25:56 +00:00
mInstallingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2015-09-30 23:11:03 +00:00
mInstallingWorker - > WorkerPrivate ( ) - > NoteDeadServiceWorkerInfo ( ) ;
2014-07-14 17:33:44 +00:00
mInstallingWorker = nullptr ;
// FIXME(nsm): Abort any inflight requests from installing worker.
}
if ( mWaitingWorker ) {
2014-12-19 11:25:56 +00:00
mWaitingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2015-03-18 16:46:38 +00:00
nsresult rv = serviceWorkerScriptCache : : PurgeCache ( mPrincipal ,
mWaitingWorker - > CacheName ( ) ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to purge the waiting cache. " ) ;
}
2015-09-30 23:11:03 +00:00
mWaitingWorker - > WorkerPrivate ( ) - > NoteDeadServiceWorkerInfo ( ) ;
2014-07-14 17:33:44 +00:00
mWaitingWorker = nullptr ;
}
2014-12-19 10:00:29 +00:00
if ( mActiveWorker ) {
2014-12-19 11:25:56 +00:00
mActiveWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2015-03-18 16:46:38 +00:00
nsresult rv = serviceWorkerScriptCache : : PurgeCache ( mPrincipal ,
mActiveWorker - > CacheName ( ) ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to purge the active cache. " ) ;
}
2015-09-30 23:11:03 +00:00
mActiveWorker - > WorkerPrivate ( ) - > NoteDeadServiceWorkerInfo ( ) ;
2014-12-19 10:00:29 +00:00
mActiveWorker = nullptr ;
2014-07-14 17:33:44 +00:00
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-07-14 17:33:44 +00:00
MOZ_ASSERT ( swm ) ;
swm - > InvalidateServiceWorkerRegistrationWorker ( this ,
WhichServiceWorker : : INSTALLING_WORKER |
WhichServiceWorker : : WAITING_WORKER |
WhichServiceWorker : : ACTIVE_WORKER ) ;
}
2015-02-11 11:53:00 +00:00
ServiceWorkerRegistrationInfo : : ServiceWorkerRegistrationInfo ( const nsACString & aScope ,
nsIPrincipal * aPrincipal )
: mControlledDocumentsCounter ( 0 )
2015-12-11 19:53:10 +00:00
, mUpdateState ( NoUpdate )
, mLastUpdateCheckTime ( 0 )
2015-02-11 11:53:00 +00:00
, mScope ( aScope )
, mPrincipal ( aPrincipal )
2015-11-26 17:03:10 +00:00
, mUpdating ( false )
2015-02-11 11:53:00 +00:00
, mPendingUninstall ( false )
2015-11-23 13:47:53 +00:00
{ }
2014-06-11 16:12:56 +00:00
2014-12-19 10:00:29 +00:00
ServiceWorkerRegistrationInfo : : ~ ServiceWorkerRegistrationInfo ( )
2014-06-11 16:12:56 +00:00
{
2014-12-19 10:00:29 +00: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 16:12:56 +00:00
}
2014-12-19 10:00:29 +00:00
}
2014-06-11 16:12:56 +00:00
2015-11-02 14:04:41 +00:00
NS_IMPL_ISUPPORTS ( ServiceWorkerRegistrationInfo , nsIServiceWorkerRegistrationInfo )
NS_IMETHODIMP
ServiceWorkerRegistrationInfo : : GetPrincipal ( nsIPrincipal * * aPrincipal )
{
AssertIsOnMainThread ( ) ;
NS_ADDREF ( * aPrincipal = mPrincipal ) ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerRegistrationInfo : : GetScope ( nsAString & aScope )
{
AssertIsOnMainThread ( ) ;
CopyUTF8toUTF16 ( mScope , aScope ) ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerRegistrationInfo : : GetScriptSpec ( nsAString & aScriptSpec )
{
AssertIsOnMainThread ( ) ;
2015-12-11 19:53:10 +00:00
RefPtr < ServiceWorkerInfo > newest = Newest ( ) ;
if ( newest ) {
CopyUTF8toUTF16 ( newest - > ScriptSpec ( ) , aScriptSpec ) ;
}
2015-11-02 14:04:41 +00:00
return NS_OK ;
}
NS_IMETHODIMP
2015-11-05 06:15:49 +00:00
ServiceWorkerRegistrationInfo : : GetInstallingWorker ( nsIServiceWorkerInfo * * aResult )
2015-11-02 14:04:41 +00:00
{
AssertIsOnMainThread ( ) ;
2015-11-05 06:15:49 +00:00
nsCOMPtr < nsIServiceWorkerInfo > info = do_QueryInterface ( mInstallingWorker ) ;
info . forget ( aResult ) ;
2015-11-02 14:04:41 +00:00
return NS_OK ;
}
NS_IMETHODIMP
2015-11-05 06:15:49 +00:00
ServiceWorkerRegistrationInfo : : GetWaitingWorker ( nsIServiceWorkerInfo * * aResult )
2015-11-02 14:04:41 +00:00
{
AssertIsOnMainThread ( ) ;
2015-11-05 06:15:49 +00:00
nsCOMPtr < nsIServiceWorkerInfo > info = do_QueryInterface ( mWaitingWorker ) ;
info . forget ( aResult ) ;
2015-11-02 14:04:41 +00:00
return NS_OK ;
}
NS_IMETHODIMP
2015-11-05 06:15:49 +00:00
ServiceWorkerRegistrationInfo : : GetActiveWorker ( nsIServiceWorkerInfo * * aResult )
2015-11-02 14:04:41 +00:00
{
AssertIsOnMainThread ( ) ;
2015-11-05 06:15:49 +00:00
nsCOMPtr < nsIServiceWorkerInfo > info = do_QueryInterface ( mActiveWorker ) ;
info . forget ( aResult ) ;
2015-11-02 14:04:41 +00:00
return NS_OK ;
}
2015-12-15 11:10:53 +00:00
NS_IMETHODIMP
ServiceWorkerRegistrationInfo : : GetWorkerByID ( uint64_t aID , nsIServiceWorkerInfo * * aResult )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aResult ) ;
RefPtr < ServiceWorkerInfo > info = GetServiceWorkerInfoById ( aID ) ;
if ( NS_WARN_IF ( ! info ) ) {
return NS_ERROR_FAILURE ;
}
info . forget ( aResult ) ;
return NS_OK ;
}
2015-11-13 20:54:45 +00:00
NS_IMETHODIMP
ServiceWorkerRegistrationInfo : : AddListener (
nsIServiceWorkerRegistrationInfoListener * aListener )
{
AssertIsOnMainThread ( ) ;
if ( ! aListener | | mListeners . Contains ( aListener ) ) {
return NS_ERROR_INVALID_ARG ;
}
mListeners . AppendElement ( aListener ) ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerRegistrationInfo : : RemoveListener (
nsIServiceWorkerRegistrationInfoListener * aListener )
{
AssertIsOnMainThread ( ) ;
if ( ! aListener | | ! mListeners . Contains ( aListener ) ) {
return NS_ERROR_INVALID_ARG ;
}
mListeners . RemoveElement ( aListener ) ;
return NS_OK ;
}
2015-10-24 12:16:23 +00:00
already_AddRefed < ServiceWorkerInfo >
ServiceWorkerRegistrationInfo : : GetServiceWorkerInfoById ( uint64_t aId )
{
RefPtr < ServiceWorkerInfo > serviceWorker ;
if ( mInstallingWorker & & mInstallingWorker - > ID ( ) = = aId ) {
serviceWorker = mInstallingWorker ;
} else if ( mWaitingWorker & & mWaitingWorker - > ID ( ) = = aId ) {
serviceWorker = mWaitingWorker ;
} else if ( mActiveWorker & & mActiveWorker - > ID ( ) = = aId ) {
serviceWorker = mActiveWorker ;
}
return serviceWorker . forget ( ) ;
}
2013-11-19 23:15:02 +00:00
//////////////////////////
// ServiceWorkerManager //
//////////////////////////
NS_IMPL_ADDREF ( ServiceWorkerManager )
NS_IMPL_RELEASE ( ServiceWorkerManager )
NS_INTERFACE_MAP_BEGIN ( ServiceWorkerManager )
NS_INTERFACE_MAP_ENTRY ( nsIServiceWorkerManager )
2015-02-11 11:53:00 +00:00
NS_INTERFACE_MAP_ENTRY ( nsIIPCBackgroundChildCreateCallback )
2015-03-06 01:37:49 +00:00
NS_INTERFACE_MAP_ENTRY ( nsIObserver )
2013-11-19 23:15:02 +00:00
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS ( nsISupports , nsIServiceWorkerManager )
NS_INTERFACE_MAP_END
ServiceWorkerManager : : ServiceWorkerManager ( )
2015-02-11 11:53:00 +00:00
: mActor ( nullptr )
2015-06-23 12:56:29 +00:00
, mShuttingDown ( false )
2013-11-19 23:15:02 +00:00
{
2015-02-11 11:53:00 +00:00
// Register this component to PBackground.
MOZ_ALWAYS_TRUE ( BackgroundChild : : GetOrCreateForCurrentThread ( this ) ) ;
2015-06-04 17:21:52 +00:00
}
ServiceWorkerManager : : ~ ServiceWorkerManager ( )
{
// The map will assert if it is not empty when destroyed.
mRegistrationInfos . Clear ( ) ;
2015-06-23 12:56:29 +00:00
MOZ_ASSERT ( ! mActor ) ;
2015-06-04 17:21:52 +00:00
}
2015-02-11 11:53:00 +00:00
2015-06-04 17:21:52 +00:00
void
ServiceWorkerManager : : Init ( )
{
2015-06-23 12:56:29 +00:00
nsCOMPtr < nsIObserverService > obs = mozilla : : services : : GetObserverService ( ) ;
if ( obs ) {
DebugOnly < nsresult > rv ;
rv = obs - > AddObserver ( this , NS_XPCOM_SHUTDOWN_OBSERVER_ID , false /* ownsWeak */ ) ;
MOZ_ASSERT ( NS_SUCCEEDED ( rv ) ) ;
}
2015-07-04 01:29:00 +00:00
if ( XRE_IsParentProcess ( ) ) {
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrar > swr = ServiceWorkerRegistrar : : Get ( ) ;
2015-02-11 11:53:00 +00:00
MOZ_ASSERT ( swr ) ;
nsTArray < ServiceWorkerRegistrationData > data ;
swr - > GetRegistrations ( data ) ;
LoadRegistrations ( data ) ;
2015-03-06 01:37:49 +00:00
if ( obs ) {
DebugOnly < nsresult > rv ;
rv = obs - > AddObserver ( this , PURGE_SESSION_HISTORY , false /* ownsWeak */ ) ;
MOZ_ASSERT ( NS_SUCCEEDED ( rv ) ) ;
rv = obs - > AddObserver ( this , PURGE_DOMAIN_DATA , false /* ownsWeak */ ) ;
MOZ_ASSERT ( NS_SUCCEEDED ( rv ) ) ;
2015-08-19 06:46:53 +00:00
rv = obs - > AddObserver ( this , CLEAR_ORIGIN_DATA , false /* ownsWeak */ ) ;
2015-06-11 17:42:38 +00:00
MOZ_ASSERT ( NS_SUCCEEDED ( rv ) ) ;
2015-03-06 01:37:49 +00:00
}
2015-02-11 11:53:00 +00:00
}
2013-11-19 23:15:02 +00:00
}
2014-12-19 13:01:53 +00:00
class ContinueLifecycleTask : public nsISupports
2014-12-19 10:00:29 +00:00
{
2014-12-19 13:01:53 +00:00
NS_DECL_ISUPPORTS
protected :
virtual ~ ContinueLifecycleTask ( )
2015-11-23 13:47:53 +00:00
{ }
2014-12-19 13:01:53 +00:00
public :
2015-09-30 23:11:03 +00:00
virtual void ContinueAfterWorkerEvent ( bool aSuccess ) = 0 ;
2014-12-19 13:01:53 +00:00
} ;
NS_IMPL_ISUPPORTS0 ( ContinueLifecycleTask ) ;
2015-11-26 17:03:10 +00:00
class ServiceWorkerInstallJob ;
2015-02-10 22:33:23 +00:00
2015-03-21 16:28:04 +00:00
class ContinueInstallTask final : public ContinueLifecycleTask
2014-12-19 13:01:53 +00:00
{
2015-11-26 17:03:10 +00:00
RefPtr < ServiceWorkerInstallJob > mJob ;
2014-12-19 13:01:53 +00:00
public :
2015-11-26 17:03:10 +00:00
explicit ContinueInstallTask ( ServiceWorkerInstallJob * aJob )
2014-12-19 13:01:53 +00:00
: mJob ( aJob )
2015-11-23 13:47:53 +00:00
{ }
2014-12-19 13:01:53 +00:00
2015-09-30 23:11:03 +00:00
void ContinueAfterWorkerEvent ( bool aSuccess ) override ;
2014-12-19 13:01:53 +00:00
} ;
2015-03-21 16:28:04 +00:00
class ContinueActivateTask final : public ContinueLifecycleTask
2014-12-19 13:01:53 +00:00
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > mRegistration ;
2014-12-19 13:01:53 +00:00
public :
explicit ContinueActivateTask ( ServiceWorkerRegistrationInfo * aReg )
: mRegistration ( aReg )
2015-11-23 13:47:53 +00:00
{ }
2014-12-19 13:01:53 +00:00
void
2015-09-30 23:11:03 +00:00
ContinueAfterWorkerEvent ( bool aSuccess ) override ;
2014-12-19 13:01:53 +00:00
} ;
2015-09-30 23:11:03 +00:00
class ContinueLifecycleRunnable final : public LifeCycleEventCallback
2014-12-19 13:01:53 +00:00
{
nsMainThreadPtrHandle < ContinueLifecycleTask > mTask ;
2014-12-19 10:00:29 +00:00
bool mSuccess ;
public :
2015-09-30 23:11:03 +00:00
explicit ContinueLifecycleRunnable ( const nsMainThreadPtrHandle < ContinueLifecycleTask > & aTask )
2014-12-19 13:01:53 +00:00
: mTask ( aTask )
2015-09-30 23:11:03 +00:00
, mSuccess ( false )
2013-11-19 23:15:02 +00:00
{
2015-09-30 14:14:33 +00:00
AssertIsOnMainThread ( ) ;
2014-12-19 10:00:29 +00:00
}
2015-09-30 18:11:47 +00:00
2015-09-30 23:11:03 +00:00
void
SetResult ( bool aResult ) override
2015-09-30 18:11:47 +00:00
{
2015-09-30 23:11:03 +00:00
mSuccess = aResult ;
2015-09-30 18:11:47 +00:00
}
2015-09-30 23:11:03 +00:00
NS_IMETHOD
Run ( ) override
2015-09-30 18:11:47 +00:00
{
2015-09-30 23:11:03 +00:00
AssertIsOnMainThread ( ) ;
mTask - > ContinueAfterWorkerEvent ( mSuccess ) ;
return NS_OK ;
2015-09-30 18:11:47 +00:00
}
} ;
2015-03-21 16:28:04 +00:00
class ServiceWorkerResolveWindowPromiseOnUpdateCallback final : public ServiceWorkerUpdateFinishCallback
2014-12-19 10:00:29 +00:00
{
2015-10-18 05:24:48 +00:00
RefPtr < nsPIDOMWindow > mWindow ;
2014-12-19 10:00:29 +00:00
// The promise "returned" by the call to Update up to
// navigator.serviceWorker.register().
2015-10-18 05:24:48 +00:00
RefPtr < Promise > mPromise ;
2014-06-11 16:12:56 +00:00
2014-12-19 10:00:29 +00:00
~ ServiceWorkerResolveWindowPromiseOnUpdateCallback ( )
2015-11-23 13:47:53 +00:00
{ }
2014-06-11 16:12:56 +00:00
2014-12-19 10:00:29 +00:00
public :
ServiceWorkerResolveWindowPromiseOnUpdateCallback ( nsPIDOMWindow * aWindow , Promise * aPromise )
: mWindow ( aWindow )
, mPromise ( aPromise )
2015-11-23 13:47:53 +00:00
{ }
2014-12-19 10:00:29 +00:00
void
2015-03-21 16:28:04 +00:00
UpdateSucceeded ( ServiceWorkerRegistrationInfo * aInfo ) override
2014-12-19 10:00:29 +00:00
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationMainThread > swr =
2015-11-23 18:38:08 +00:00
mWindow - > GetServiceWorkerRegistration ( NS_ConvertUTF8toUTF16 ( aInfo - > mScope ) ) ;
2014-12-19 10:00:29 +00:00
mPromise - > MaybeResolve ( swr ) ;
}
void
2015-11-16 16:04:11 +00:00
UpdateFailed ( ErrorResult & aStatus ) override
2014-12-19 10:00:29 +00:00
{
mPromise - > MaybeReject ( aStatus ) ;
2013-11-19 23:15:02 +00:00
}
2014-12-19 10:48:31 +00:00
} ;
2015-11-26 17:03:10 +00:00
class ContinueUpdateRunnable final : public LifeCycleEventCallback
2014-12-19 10:48:31 +00:00
{
nsMainThreadPtrHandle < nsISupports > mJob ;
2015-11-26 17:03:10 +00:00
bool mScriptEvaluationResult ;
2014-12-19 10:48:31 +00:00
public :
explicit ContinueUpdateRunnable ( const nsMainThreadPtrHandle < nsISupports > aJob )
: mJob ( aJob )
2015-11-26 17:03:10 +00:00
, mScriptEvaluationResult ( false )
2015-09-30 18:11:47 +00:00
{
AssertIsOnMainThread ( ) ;
}
2015-11-26 17:03:10 +00:00
void
SetResult ( bool aResult )
{
mScriptEvaluationResult = aResult ;
}
2015-09-30 23:11:03 +00:00
NS_IMETHOD Run ( ) ;
2015-09-30 18:11:47 +00:00
} ;
2015-03-10 01:57:06 +00:00
namespace {
2015-05-06 05:17:20 +00:00
/**
* The spec mandates slightly different behaviors for computing the scope
* prefix string in case a Service - Worker - Allowed header is specified versus
* when it ' s not available .
*
* With the header :
* " Set maxScopeString to " / " concatenated with the strings in maxScope's
* path ( including empty strings ) , separated from each other by " / " . "
* Without the header :
* " Set maxScopeString to " / " concatenated with the strings, except the last
* string that denotes the script ' s file name , in registration ' s registering
* script url ' s path ( including empty strings ) , separated from each other by
* " / " . "
*
* In simpler terms , if the header is not present , we should only use the
* " directory " part of the pathname , and otherwise the entire pathname should be
* used . ScopeStringPrefixMode allows the caller to specify the desired
* behavior .
*/
enum ScopeStringPrefixMode {
eUseDirectory ,
eUsePath
} ;
2015-03-10 01:57:06 +00:00
nsresult
2015-05-06 05:17:20 +00:00
GetRequiredScopeStringPrefix ( nsIURI * aScriptURI , nsACString & aPrefix ,
ScopeStringPrefixMode aPrefixMode )
2015-03-10 01:57:06 +00:00
{
2015-05-06 05:17:20 +00:00
nsresult rv = aScriptURI - > GetPrePath ( aPrefix ) ;
2015-03-10 01:57:06 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-05-06 05:17:20 +00:00
if ( aPrefixMode = = eUseDirectory ) {
nsCOMPtr < nsIURL > scriptURL ( do_QueryInterface ( aScriptURI ) ) ;
if ( NS_WARN_IF ( ! scriptURL ) ) {
return NS_ERROR_FAILURE ;
}
2015-03-10 01:57:06 +00:00
2015-05-06 05:17:20 +00:00
nsAutoCString dir ;
rv = scriptURL - > GetDirectory ( dir ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-03-10 01:57:06 +00:00
2015-05-06 05:17:20 +00:00
aPrefix . Append ( dir ) ;
} else if ( aPrefixMode = = eUsePath ) {
nsAutoCString path ;
rv = aScriptURI - > GetPath ( path ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-03-10 01:57:06 +00:00
2015-05-06 05:17:20 +00:00
aPrefix . Append ( path ) ;
} else {
MOZ_ASSERT_UNREACHABLE ( " Invalid value for aPrefixMode " ) ;
}
2015-03-10 01:57:06 +00:00
return NS_OK ;
}
2015-06-04 18:51:57 +00:00
class PropagateSoftUpdateRunnable final : public nsRunnable
{
public :
2015-11-03 01:50:54 +00:00
PropagateSoftUpdateRunnable ( const PrincipalOriginAttributes & aOriginAttributes ,
2015-06-04 18:51:57 +00:00
const nsAString & aScope )
: mOriginAttributes ( aOriginAttributes )
, mScope ( aScope )
{ }
NS_IMETHOD Run ( ) override
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-06-04 18:51:57 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-06-04 18:51:57 +00:00
MOZ_ASSERT ( swm ) ;
2015-06-21 11:17:58 +00:00
swm - > PropagateSoftUpdate ( mOriginAttributes , mScope ) ;
2015-06-04 18:51:57 +00:00
return NS_OK ;
}
private :
~ PropagateSoftUpdateRunnable ( )
{ }
2015-11-03 01:50:54 +00:00
const PrincipalOriginAttributes mOriginAttributes ;
2015-06-04 18:51:57 +00:00
const nsString mScope ;
} ;
class PropagateUnregisterRunnable final : public nsRunnable
{
public :
PropagateUnregisterRunnable ( nsIPrincipal * aPrincipal ,
nsIServiceWorkerUnregisterCallback * aCallback ,
const nsAString & aScope )
: mPrincipal ( aPrincipal )
, mCallback ( aCallback )
, mScope ( aScope )
{
MOZ_ASSERT ( aPrincipal ) ;
}
NS_IMETHOD Run ( ) override
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-06-04 18:51:57 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-06-04 18:51:57 +00:00
MOZ_ASSERT ( swm ) ;
nsresult rv = swm - > PropagateUnregister ( mPrincipal , mCallback , mScope ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
return NS_OK ;
}
private :
~ PropagateUnregisterRunnable ( )
{ }
nsCOMPtr < nsIPrincipal > mPrincipal ;
nsCOMPtr < nsIServiceWorkerUnregisterCallback > mCallback ;
const nsString mScope ;
} ;
2015-06-21 11:19:07 +00:00
class RemoveRunnable final : public nsRunnable
{
public :
explicit RemoveRunnable ( const nsACString & aHost )
{ }
NS_IMETHOD Run ( ) override
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-06-21 11:19:07 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-06-21 11:19:07 +00:00
MOZ_ASSERT ( swm ) ;
swm - > Remove ( mHost ) ;
return NS_OK ;
}
private :
~ RemoveRunnable ( )
{ }
const nsCString mHost ;
} ;
class PropagateRemoveRunnable final : public nsRunnable
{
public :
explicit PropagateRemoveRunnable ( const nsACString & aHost )
{ }
NS_IMETHOD Run ( ) override
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-06-21 11:19:07 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-06-21 11:19:07 +00:00
MOZ_ASSERT ( swm ) ;
swm - > PropagateRemove ( mHost ) ;
return NS_OK ;
}
private :
~ PropagateRemoveRunnable ( )
{ }
const nsCString mHost ;
} ;
2015-06-21 11:17:58 +00:00
class PropagateRemoveAllRunnable final : public nsRunnable
{
public :
PropagateRemoveAllRunnable ( )
{ }
NS_IMETHOD Run ( ) override
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-06-21 11:17:58 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-06-21 11:17:58 +00:00
MOZ_ASSERT ( swm ) ;
swm - > PropagateRemoveAll ( ) ;
return NS_OK ;
}
private :
~ PropagateRemoveAllRunnable ( )
{ }
} ;
2015-07-13 15:25:42 +00:00
} // namespace
2015-03-10 01:57:06 +00:00
2015-11-26 17:03:10 +00:00
class ServiceWorkerJobBase : public ServiceWorkerJob
{
public :
ServiceWorkerJobBase ( ServiceWorkerJobQueue * aQueue ,
ServiceWorkerJob : : Type aJobType ,
ServiceWorkerUpdateFinishCallback * aCallback )
: ServiceWorkerJobBase ( aQueue , aJobType , aCallback , nullptr , nullptr )
{ }
ServiceWorkerJobBase ( ServiceWorkerJobQueue * aQueue ,
ServiceWorkerJob : : Type aJobType ,
ServiceWorkerUpdateFinishCallback * aCallback ,
ServiceWorkerRegistrationInfo * aRegistration ,
ServiceWorkerInfo * aServiceWorkerInfo )
: ServiceWorkerJob ( aQueue , aJobType )
, mCallback ( aCallback )
, mCanceled ( false )
, mRegistration ( aRegistration )
, mUpdateAndInstallInfo ( aServiceWorkerInfo )
{
AssertIsOnMainThread ( ) ;
}
void
Cancel ( )
{
mQueue = nullptr ;
mCanceled = true ;
}
protected :
RefPtr < ServiceWorkerUpdateFinishCallback > mCallback ;
bool mCanceled ;
RefPtr < ServiceWorkerRegistrationInfo > mRegistration ;
RefPtr < ServiceWorkerInfo > mUpdateAndInstallInfo ;
~ ServiceWorkerJobBase ( )
{ }
2015-12-11 19:53:10 +00:00
void
Succeed ( )
{
AssertIsOnMainThread ( ) ;
// We don't have a callback for soft updates.
if ( mCallback ) {
mCallback - > UpdateSucceeded ( mRegistration ) ;
mCallback = nullptr ;
}
}
} ;
// Base type for jobs that work with a specific service worker script.
class ServiceWorkerScriptJobBase : public ServiceWorkerJobBase
{
protected :
2015-12-11 19:53:10 +00:00
const nsCString mScriptSpec ;
2015-12-11 19:53:10 +00:00
ServiceWorkerScriptJobBase ( ServiceWorkerJobQueue * aQueue ,
ServiceWorkerJob : : Type aJobType ,
ServiceWorkerUpdateFinishCallback * aCallback ,
ServiceWorkerRegistrationInfo * aRegistration ,
2015-12-11 19:53:10 +00:00
ServiceWorkerInfo * aServiceWorkerInfo ,
const nsACString & aScriptSpec )
2015-12-11 19:53:10 +00:00
: ServiceWorkerJobBase ( aQueue , aJobType , aCallback , aRegistration ,
aServiceWorkerInfo )
2015-12-11 19:53:10 +00:00
, mScriptSpec ( aScriptSpec )
2015-12-11 19:53:10 +00:00
{
}
2015-11-26 17:03:10 +00: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.
// Callers MUST hold a strong ref before calling this!
void
2015-12-11 19:53:10 +00:00
FailWithErrorResult ( ErrorResult & aRv )
2015-11-26 17:03:10 +00:00
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( mRegistration ) ;
// With cancellation support, we may only be running with one reference
// from another object like a stream loader or something.
RefPtr < ServiceWorkerJob > kungFuDeathGrip = this ;
// Save off the plain error code to pass to Done() where its logged to
// stderr as a warning.
nsresult origStatus = static_cast < nsresult > ( aRv . ErrorCodeAsInt ( ) ) ;
// Ensure that we only surface SecurityErr or TypeErr to script.
if ( aRv . Failed ( ) & & ! aRv . ErrorCodeIs ( NS_ERROR_DOM_SECURITY_ERR ) & &
! aRv . ErrorCodeIs ( NS_ERROR_DOM_TYPE_ERR ) ) {
// Remove the old error code so we can replace it with a TypeError.
aRv . SuppressException ( ) ;
2015-12-11 19:53:10 +00:00
NS_ConvertUTF8toUTF16 scriptSpec ( mScriptSpec ) ;
2015-11-26 17:03:10 +00:00
NS_ConvertUTF8toUTF16 scope ( mRegistration - > mScope ) ;
// Throw the type error with a generic error message.
aRv . ThrowTypeError < MSG_SW_INSTALL_ERROR > ( scriptSpec , scope ) ;
}
if ( mCallback ) {
mCallback - > UpdateFailed ( aRv ) ;
mCallback = nullptr ;
}
// In case the callback does not consume the exception
aRv . SuppressException ( ) ;
mUpdateAndInstallInfo = nullptr ;
if ( mRegistration - > mInstallingWorker ) {
nsresult rv = serviceWorkerScriptCache : : PurgeCache ( mRegistration - > mPrincipal ,
mRegistration - > mInstallingWorker - > CacheName ( ) ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to purge the installing worker cache. " ) ;
}
}
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
swm - > MaybeRemoveRegistration ( mRegistration ) ;
// Ensures that the job can't do anything useful from this point on.
mRegistration = nullptr ;
Done ( origStatus ) ;
}
void
Fail ( nsresult aRv )
{
ErrorResult rv ( aRv ) ;
2015-12-11 19:53:10 +00:00
FailWithErrorResult ( rv ) ;
2015-12-11 02:49:48 +00:00
}
2015-11-26 17:03:10 +00:00
} ;
2015-12-11 19:53:10 +00:00
class ServiceWorkerInstallJob final : public ServiceWorkerScriptJobBase
2013-11-19 23:15:02 +00:00
{
2014-12-19 13:01:53 +00:00
friend class ContinueInstallTask ;
2013-11-19 23:15:02 +00:00
2015-11-26 17:03:10 +00:00
public :
ServiceWorkerInstallJob ( ServiceWorkerJobQueue * aQueue ,
ServiceWorkerUpdateFinishCallback * aCallback ,
ServiceWorkerRegistrationInfo * aRegistration ,
2015-12-11 19:53:10 +00:00
ServiceWorkerInfo * aServiceWorkerInfo ,
const nsACString & aScriptSpec )
2015-12-11 19:53:10 +00:00
: ServiceWorkerScriptJobBase ( aQueue , Type : : InstallJob , aCallback ,
2015-12-11 19:53:10 +00:00
aRegistration , aServiceWorkerInfo ,
2015-12-11 19:53:10 +00:00
aScriptSpec )
2015-11-26 17:03:10 +00:00
{
MOZ_ASSERT ( aRegistration ) ;
}
void
Start ( )
{
AssertIsOnMainThread ( ) ;
nsCOMPtr < nsIRunnable > r =
NS_NewRunnableMethod ( this , & ServiceWorkerInstallJob : : Install ) ;
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( NS_DispatchToMainThread ( r ) ) ) ;
}
void
Install ( )
{
RefPtr < ServiceWorkerJob > kungFuDeathGrip = this ;
if ( mCanceled ) {
return Fail ( NS_ERROR_DOM_ABORT_ERR ) ;
}
MOZ_ASSERT ( mRegistration ) ;
// Begin [[Install]] atomic step 3.
if ( mRegistration - > mInstallingWorker ) {
mRegistration - > mInstallingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
mRegistration - > mInstallingWorker - > WorkerPrivate ( ) - > TerminateWorker ( ) ;
}
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
swm - > InvalidateServiceWorkerRegistrationWorker ( mRegistration ,
WhichServiceWorker : : INSTALLING_WORKER ) ;
mRegistration - > mInstallingWorker = mUpdateAndInstallInfo . forget ( ) ;
mRegistration - > mInstallingWorker - > UpdateState ( ServiceWorkerState : : Installing ) ;
mRegistration - > NotifyListenersOnChange ( ) ;
Succeed ( ) ;
// The job should NOT call fail from this point on.
// Step 8 "Queue a task..." for updatefound.
nsCOMPtr < nsIRunnable > upr =
2015-12-05 02:03:47 +00:00
NS_NewRunnableMethodWithArg < RefPtr < ServiceWorkerRegistrationInfo > > (
2015-11-26 17:03:10 +00:00
swm ,
& ServiceWorkerManager : : FireUpdateFoundOnServiceWorkerRegistrations ,
mRegistration ) ;
NS_DispatchToMainThread ( upr ) ;
// Call ContinueAfterInstallEvent(false) on main thread if the SW
// script fails to load.
nsCOMPtr < nsIRunnable > failRunnable = NS_NewRunnableMethodWithArgs < bool >
( this , & ServiceWorkerInstallJob : : ContinueAfterInstallEvent , false ) ;
nsMainThreadPtrHandle < ContinueLifecycleTask > installTask (
new nsMainThreadPtrHolder < ContinueLifecycleTask > ( new ContinueInstallTask ( this ) ) ) ;
RefPtr < LifeCycleEventCallback > callback = new ContinueLifecycleRunnable ( installTask ) ;
// This triggers Step 4.7 "Queue a task to run the following substeps..."
// which sends the install event to the worker.
ServiceWorkerPrivate * workerPrivate =
mRegistration - > mInstallingWorker - > WorkerPrivate ( ) ;
nsresult rv = workerPrivate - > SendLifeCycleEvent ( NS_LITERAL_STRING ( " install " ) ,
callback , failRunnable ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
ContinueAfterInstallEvent ( false /* aSuccess */ ) ;
}
}
void
ContinueAfterInstallEvent ( bool aInstallEventSuccess )
{
if ( mCanceled ) {
return Done ( NS_ERROR_DOM_ABORT_ERR ) ;
}
if ( ! mRegistration - > mInstallingWorker ) {
NS_WARNING ( " mInstallingWorker was null. " ) ;
return Done ( NS_ERROR_DOM_ABORT_ERR ) ;
}
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
// "If installFailed is true"
if ( NS_WARN_IF ( ! aInstallEventSuccess ) ) {
mRegistration - > mInstallingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
mRegistration - > mInstallingWorker = nullptr ;
swm - > InvalidateServiceWorkerRegistrationWorker ( mRegistration ,
WhichServiceWorker : : INSTALLING_WORKER ) ;
swm - > MaybeRemoveRegistration ( mRegistration ) ;
return Done ( NS_ERROR_DOM_ABORT_ERR ) ;
}
// "If registration's waiting worker is not null"
if ( mRegistration - > mWaitingWorker ) {
mRegistration - > mWaitingWorker - > WorkerPrivate ( ) - > TerminateWorker ( ) ;
mRegistration - > mWaitingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
nsresult rv =
serviceWorkerScriptCache : : PurgeCache ( mRegistration - > mPrincipal ,
mRegistration - > mWaitingWorker - > CacheName ( ) ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to purge the old waiting cache. " ) ;
}
}
mRegistration - > mWaitingWorker = mRegistration - > mInstallingWorker . forget ( ) ;
mRegistration - > mWaitingWorker - > UpdateState ( ServiceWorkerState : : Installed ) ;
mRegistration - > NotifyListenersOnChange ( ) ;
swm - > InvalidateServiceWorkerRegistrationWorker ( mRegistration ,
WhichServiceWorker : : INSTALLING_WORKER | WhichServiceWorker : : WAITING_WORKER ) ;
// "If registration's waiting worker's skip waiting flag is set"
if ( mRegistration - > mWaitingWorker - > SkipWaitingFlag ( ) ) {
mRegistration - > PurgeActiveWorker ( ) ;
}
Done ( NS_OK ) ;
// Activate() is invoked out of band of atomic.
mRegistration - > TryToActivate ( ) ;
}
} ;
2015-12-11 19:53:10 +00:00
class ServiceWorkerRegisterJob final : public ServiceWorkerScriptJobBase ,
2015-11-26 17:03:10 +00:00
public serviceWorkerScriptCache : : CompareCallback
{
friend class ContinueUpdateRunnable ;
2014-12-19 10:00:29 +00:00
nsCString mScope ;
2015-02-11 11:53:00 +00:00
nsCOMPtr < nsIPrincipal > mPrincipal ;
2015-06-23 17:50:04 +00:00
nsCOMPtr < nsILoadGroup > mLoadGroup ;
2013-11-19 23:15:02 +00:00
2014-12-19 10:00:29 +00:00
~ ServiceWorkerRegisterJob ( )
2015-11-26 17:03:10 +00:00
{ }
2015-03-06 01:37:49 +00:00
2014-12-19 10:00:29 +00:00
public :
2015-03-18 16:46:38 +00:00
NS_DECL_ISUPPORTS_INHERITED
2013-11-19 23:15:02 +00:00
2014-12-19 10:00:29 +00:00
// [[Register]]
ServiceWorkerRegisterJob ( ServiceWorkerJobQueue * aQueue ,
const nsCString & aScope ,
const nsCString & aScriptSpec ,
2015-02-11 11:53:00 +00:00
ServiceWorkerUpdateFinishCallback * aCallback ,
2015-06-23 17:50:04 +00:00
nsIPrincipal * aPrincipal ,
nsILoadGroup * aLoadGroup )
2015-12-11 19:53:10 +00:00
: ServiceWorkerScriptJobBase ( aQueue , Type : : RegisterJob , aCallback , nullptr ,
2015-12-11 19:53:10 +00:00
nullptr , aScriptSpec )
2014-12-19 10:00:29 +00:00
, mScope ( aScope )
2015-02-11 11:53:00 +00:00
, mPrincipal ( aPrincipal )
2015-06-23 17:50:04 +00:00
, mLoadGroup ( aLoadGroup )
{
2015-11-20 08:43:07 +00:00
AssertIsOnMainThread ( ) ;
2015-06-23 17:50:04 +00:00
MOZ_ASSERT ( mLoadGroup ) ;
2015-11-20 08:43:07 +00:00
MOZ_ASSERT ( aCallback ) ;
2015-06-23 17:50:04 +00:00
}
2014-08-21 23:31:12 +00:00
2014-12-19 10:00:29 +00:00
// [[Update]]
ServiceWorkerRegisterJob ( ServiceWorkerJobQueue * aQueue ,
ServiceWorkerRegistrationInfo * aRegistration ,
2015-12-11 19:53:10 +00:00
ServiceWorkerUpdateFinishCallback * aCallback ,
const nsACString & aScriptSpec )
2015-12-11 19:53:10 +00:00
: ServiceWorkerScriptJobBase ( aQueue , Type : : UpdateJob , aCallback ,
2015-12-11 19:53:10 +00:00
aRegistration , nullptr , aScriptSpec )
2015-11-20 08:43:07 +00:00
{
AssertIsOnMainThread ( ) ;
}
2014-09-02 20:07:55 +00:00
2014-12-19 10:00:29 +00:00
void
2015-03-21 16:28:04 +00:00
Start ( ) override
2014-12-19 10:00:29 +00:00
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-03-06 01:37:49 +00:00
MOZ_ASSERT ( ! mCanceled ) ;
2015-02-11 11:53:00 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-02-11 11:53:00 +00:00
if ( ! swm - > HasBackgroundActor ( ) ) {
nsCOMPtr < nsIRunnable > runnable =
NS_NewRunnableMethod ( this , & ServiceWorkerRegisterJob : : Start ) ;
swm - > AppendPendingOperation ( runnable ) ;
return ;
}
2015-11-26 17:03:10 +00:00
if ( mJobType = = RegisterJob ) {
2015-06-03 08:43:43 +00:00
mRegistration = swm - > GetRegistration ( mPrincipal , mScope ) ;
2014-12-19 10:00:29 +00:00
if ( mRegistration ) {
2015-11-20 01:42:09 +00:00
mRegistration - > mPendingUninstall = false ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerInfo > newest = mRegistration - > Newest ( ) ;
2015-12-11 19:53:10 +00:00
if ( newest & & mScriptSpec . Equals ( newest - > ScriptSpec ( ) ) ) {
2015-04-30 14:32:47 +00:00
swm - > StoreRegistration ( mPrincipal , mRegistration ) ;
2014-12-19 10:00:29 +00:00
Succeed ( ) ;
2015-06-10 20:39:42 +00:00
// Done() must always be called async from Start()
nsCOMPtr < nsIRunnable > runnable =
NS_NewRunnableMethodWithArg < nsresult > (
this ,
& ServiceWorkerRegisterJob : : Done ,
NS_OK ) ;
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( NS_DispatchToCurrentThread ( runnable ) ) ) ;
2014-12-19 10:00:29 +00:00
return ;
}
} else {
2015-02-11 11:53:00 +00:00
mRegistration = swm - > CreateNewRegistration ( mScope , mPrincipal ) ;
2014-12-19 10:00:29 +00:00
}
2014-09-02 20:07:55 +00:00
2015-02-11 11:53:00 +00:00
swm - > StoreRegistration ( mPrincipal , mRegistration ) ;
2014-12-19 10:00:29 +00:00
} else {
2015-11-26 17:03:10 +00:00
MOZ_ASSERT ( mJobType = = UpdateJob ) ;
2015-12-11 19:53:10 +00:00
// If a different script spec has been registered between when this update
// was scheduled and it running now, then simply abort.
RefPtr < ServiceWorkerInfo > newest = mRegistration - > Newest ( ) ;
if ( newest & & ! mScriptSpec . Equals ( newest - > ScriptSpec ( ) ) ) {
// Done() must always be called async from Start()
nsCOMPtr < nsIRunnable > runnable =
NS_NewRunnableMethodWithArg < nsresult > (
this ,
& ServiceWorkerRegisterJob : : Fail ,
NS_ERROR_DOM_ABORT_ERR ) ;
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( NS_DispatchToCurrentThread ( runnable ) ) ) ;
return ;
}
2014-09-02 20:07:55 +00:00
}
2014-12-19 10:00:29 +00:00
Update ( ) ;
2014-09-02 20:07:55 +00:00
}
2015-03-18 16:52:54 +00:00
void
2015-05-06 05:17:20 +00:00
ComparisonResult ( nsresult aStatus , bool aInCacheAndEqual ,
const nsAString & aNewCacheName ,
const nsACString & aMaxScope ) override
2014-12-19 10:00:29 +00:00
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegisterJob > kungFuDeathGrip = this ;
2015-08-19 23:21:25 +00:00
if ( NS_WARN_IF ( mCanceled ) ) {
2015-11-16 16:04:11 +00:00
Fail ( NS_ERROR_DOM_ABORT_ERR ) ;
2015-03-06 01:37:49 +00:00
return ;
}
2014-12-19 10:00:29 +00:00
if ( NS_WARN_IF ( NS_FAILED ( aStatus ) ) ) {
2015-11-16 16:04:11 +00:00
Fail ( aStatus ) ;
2015-03-18 16:52:54 +00:00
return ;
2014-12-19 10:00:29 +00:00
}
2013-11-19 23:15:02 +00:00
2015-03-18 16:52:54 +00:00
if ( aInCacheAndEqual ) {
Succeed ( ) ;
2015-03-19 22:03:49 +00:00
Done ( NS_OK ) ;
2015-03-18 16:52:54 +00:00
return ;
2014-12-19 10:00:29 +00:00
}
2013-11-19 23:15:02 +00:00
2015-06-05 06:11:18 +00:00
AssertIsOnMainThread ( ) ;
Telemetry : : Accumulate ( Telemetry : : SERVICE_WORKER_UPDATED , 1 ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-02-09 04:33:39 +00:00
2015-05-06 05:17:20 +00:00
nsCOMPtr < nsIURI > scriptURI ;
2015-12-11 19:53:10 +00:00
nsresult rv = NS_NewURI ( getter_AddRefs ( scriptURI ) , mScriptSpec ) ;
2015-03-10 01:57:06 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
Fail ( NS_ERROR_DOM_SECURITY_ERR ) ;
2015-03-18 16:52:54 +00:00
return ;
2015-03-10 01:57:06 +00:00
}
2015-05-06 05:17:20 +00:00
nsCOMPtr < nsIURI > maxScopeURI ;
if ( ! aMaxScope . IsEmpty ( ) ) {
rv = NS_NewURI ( getter_AddRefs ( maxScopeURI ) , aMaxScope ,
nullptr , scriptURI ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
Fail ( NS_ERROR_DOM_SECURITY_ERR ) ;
return ;
}
}
nsAutoCString defaultAllowedPrefix ;
rv = GetRequiredScopeStringPrefix ( scriptURI , defaultAllowedPrefix ,
eUseDirectory ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
Fail ( NS_ERROR_DOM_SECURITY_ERR ) ;
return ;
}
nsAutoCString maxPrefix ( defaultAllowedPrefix ) ;
if ( maxScopeURI ) {
rv = GetRequiredScopeStringPrefix ( maxScopeURI , maxPrefix , eUsePath ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
Fail ( NS_ERROR_DOM_SECURITY_ERR ) ;
return ;
}
}
2015-03-10 01:57:06 +00:00
2015-05-06 05:17:20 +00:00
if ( ! StringBeginsWith ( mRegistration - > mScope , maxPrefix ) ) {
2015-03-10 01:57:06 +00:00
NS_WARNING ( " By default a service worker's scope is restricted to at or below it's script's location. " ) ;
Fail ( NS_ERROR_DOM_SECURITY_ERR ) ;
2015-03-18 16:52:54 +00:00
return ;
2015-03-10 01:57:06 +00:00
}
2015-06-03 08:43:43 +00:00
nsAutoCString scopeKey ;
rv = swm - > PrincipalToScopeKey ( mRegistration - > mPrincipal , scopeKey ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return Fail ( NS_ERROR_FAILURE ) ;
}
ServiceWorkerManager : : RegistrationDataPerPrincipal * data ;
if ( ! swm - > mRegistrationInfos . Get ( scopeKey , & data ) ) {
return Fail ( NS_ERROR_FAILURE ) ;
}
2015-03-18 21:02:51 +00:00
MOZ_ASSERT ( ! mUpdateAndInstallInfo ) ;
mUpdateAndInstallInfo =
2015-12-11 19:53:10 +00:00
new ServiceWorkerInfo ( mRegistration , mScriptSpec , aNewCacheName ) ;
2014-12-19 10:48:31 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerJob > upcasted = this ;
2014-12-19 10:48:31 +00:00
nsMainThreadPtrHandle < nsISupports > handle (
new nsMainThreadPtrHolder < nsISupports > ( upcasted ) ) ;
2015-11-26 17:03:10 +00:00
RefPtr < LifeCycleEventCallback > callback = new ContinueUpdateRunnable ( handle ) ;
2014-12-19 10:48:31 +00:00
2015-09-30 23:11:03 +00:00
ServiceWorkerPrivate * workerPrivate =
mUpdateAndInstallInfo - > WorkerPrivate ( ) ;
2015-11-26 17:03:10 +00:00
rv = workerPrivate - > CheckScriptEvaluation ( callback ) ;
2015-09-30 23:11:03 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2015-11-26 17:03:10 +00:00
Fail ( NS_ERROR_DOM_ABORT_ERR ) ;
2015-07-15 19:21:40 +00:00
}
}
2015-11-26 17:03:10 +00:00
private :
2015-11-26 17:03:10 +00:00
// This will perform steps 27 and 28 from [[Update]]
// Remove the job from the registration queue and invoke [[Install]]
2014-12-19 10:48:31 +00:00
void
2015-11-26 17:03:10 +00:00
ContinueInstall ( bool aScriptEvaluationResult )
2014-12-19 10:48:31 +00:00
{
2015-11-26 17:03:10 +00:00
AssertIsOnMainThread ( ) ;
2015-11-26 17:03:10 +00:00
MOZ_ASSERT ( mRegistration ) ;
2015-11-26 17:03:10 +00:00
mRegistration - > mUpdating = false ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegisterJob > kungFuDeathGrip = this ;
2015-03-06 01:37:49 +00:00
if ( mCanceled ) {
return Fail ( NS_ERROR_DOM_ABORT_ERR ) ;
}
2015-11-26 17:03:10 +00:00
if ( NS_WARN_IF ( ! aScriptEvaluationResult ) ) {
ErrorResult error ;
2015-12-11 19:53:10 +00:00
NS_ConvertUTF8toUTF16 scriptSpec ( mScriptSpec ) ;
2015-11-26 17:03:10 +00:00
NS_ConvertUTF8toUTF16 scope ( mRegistration - > mScope ) ;
error . ThrowTypeError < MSG_SW_SCRIPT_THREW > ( scriptSpec , scope ) ;
2015-12-11 19:53:10 +00:00
return FailWithErrorResult ( error ) ;
2015-11-26 17:03:10 +00:00
}
2015-11-26 17:03:10 +00:00
RefPtr < ServiceWorkerInstallJob > job =
2015-12-11 19:53:10 +00:00
new ServiceWorkerInstallJob ( mQueue , mCallback , mRegistration ,
mUpdateAndInstallInfo , mScriptSpec ) ;
2015-11-26 17:03:10 +00:00
mQueue - > Append ( job ) ;
Done ( NS_OK ) ;
2014-12-19 10:48:31 +00:00
}
2014-12-19 10:00:29 +00:00
void
Update ( )
{
2015-11-26 17:03:10 +00:00
AssertIsOnMainThread ( ) ;
2015-03-06 01:37:49 +00:00
// Since Update() is called synchronously from Start(), we can assert this.
MOZ_ASSERT ( ! mCanceled ) ;
2014-12-19 10:00:29 +00:00
MOZ_ASSERT ( mRegistration ) ;
nsCOMPtr < nsIRunnable > r =
NS_NewRunnableMethod ( this , & ServiceWorkerRegisterJob : : ContinueUpdate ) ;
NS_DispatchToMainThread ( r ) ;
2015-11-26 17:03:10 +00:00
mRegistration - > mUpdating = true ;
2013-11-19 23:15:02 +00:00
}
2014-12-19 10:00:29 +00:00
// Aspects of (actually the whole algorithm) of [[Update]] after
// "Run the following steps in parallel."
void
ContinueUpdate ( )
2014-08-20 15:40:00 +00:00
{
2014-12-19 10:00:29 +00:00
AssertIsOnMainThread ( ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegisterJob > kungFuDeathGrip = this ;
2015-03-06 01:37:49 +00:00
if ( mCanceled ) {
return Fail ( NS_ERROR_DOM_ABORT_ERR ) ;
}
2014-12-19 10:00:29 +00:00
if ( mRegistration - > mInstallingWorker ) {
2014-12-19 11:25:56 +00:00
mRegistration - > mInstallingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
2015-11-26 17:03:10 +00:00
mRegistration - > mInstallingWorker - > WorkerPrivate ( ) - > TerminateWorker ( ) ;
2014-12-19 10:00:29 +00:00
mRegistration - > mInstallingWorker = nullptr ;
2014-08-20 15:40:00 +00:00
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerInfo > workerInfo = mRegistration - > Newest ( ) ;
2015-03-18 16:52:54 +00:00
nsAutoString cacheName ;
2014-08-20 15:40:00 +00:00
2015-03-18 16:52:54 +00:00
// 9.2.20 If newestWorker is not null, and newestWorker's script url is
// equal to registration's registering script url and response is a
// byte-for-byte match with the script resource of newestWorker...
2015-12-11 19:53:10 +00:00
if ( workerInfo & & workerInfo - > ScriptSpec ( ) . Equals ( mScriptSpec ) ) {
2015-03-18 16:52:54 +00:00
cacheName = workerInfo - > CacheName ( ) ;
2014-08-20 15:40:00 +00:00
}
2015-03-18 16:52:54 +00:00
nsresult rv =
2015-10-26 02:59:48 +00:00
serviceWorkerScriptCache : : Compare ( mRegistration , mRegistration - > mPrincipal , cacheName ,
2015-12-11 19:53:10 +00:00
NS_ConvertUTF8toUTF16 ( mScriptSpec ) , this ,
mLoadGroup ) ;
2014-12-19 10:00:29 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return Fail ( rv ) ;
}
2014-08-20 15:40:00 +00:00
}
2015-11-20 08:43:07 +00:00
void
Done ( nsresult aStatus )
{
2015-11-26 17:03:10 +00:00
AssertIsOnMainThread ( ) ;
2015-11-20 08:43:07 +00:00
2015-11-26 17:03:10 +00:00
if ( mRegistration ) {
mRegistration - > mUpdating = false ;
2015-11-20 08:43:07 +00:00
}
2015-11-26 17:03:10 +00:00
ServiceWorkerJob : : Done ( aStatus ) ;
2015-11-20 08:43:07 +00:00
}
2014-08-20 15:40:00 +00:00
} ;
2015-03-18 16:46:38 +00:00
NS_IMPL_ISUPPORTS_INHERITED0 ( ServiceWorkerRegisterJob , ServiceWorkerJob ) ;
2014-12-19 10:48:31 +00:00
2015-03-06 01:37:49 +00:00
void
ServiceWorkerJobQueue : : CancelJobs ( )
{
2015-11-26 17:03:10 +00:00
// The order doesn't matter. Cancel() just sets a flag on these jobs.
CancelJobs ( mRegistrationJobQueue ) ;
CancelJobs ( mInstallationJobQueue ) ;
}
void
ServiceWorkerJobQueue : : CancelJobs ( QueueData & aQueue )
{
if ( aQueue . mJobs . IsEmpty ( ) ) {
2015-03-06 01:37:49 +00:00
return ;
}
// We have to treat the first job specially. It is the running job and needs
// to be notified correctly.
2015-11-26 17:03:10 +00:00
RefPtr < ServiceWorkerJob > runningJob = aQueue . mJobs [ 0 ] ;
2015-03-06 01:37:49 +00:00
// We can just let an Unregister job run to completion.
2015-11-26 17:03:10 +00:00
if ( runningJob - > IsRegisterOrInstallJob ( ) ) {
ServiceWorkerJobBase * job = static_cast < ServiceWorkerJobBase * > ( runningJob . get ( ) ) ;
2015-03-06 01:37:49 +00:00
job - > Cancel ( ) ;
}
// Get rid of everything. Non-main thread objects may still be holding a ref
// to the running register job. Since we called Cancel() on it, the job's
// main thread functions will just exit.
2015-11-26 17:03:10 +00:00
aQueue . mJobs . Clear ( ) ;
2015-03-06 01:37:49 +00:00
}
2014-12-19 10:48:31 +00:00
NS_IMETHODIMP
ContinueUpdateRunnable : : Run ( )
{
AssertIsOnMainThread ( ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerJob > job = static_cast < ServiceWorkerJob * > ( mJob . get ( ) ) ;
RefPtr < ServiceWorkerRegisterJob > upjob = static_cast < ServiceWorkerRegisterJob * > ( job . get ( ) ) ;
2015-11-26 17:03:10 +00:00
upjob - > ContinueInstall ( mScriptEvaluationResult ) ;
2014-12-19 10:48:31 +00:00
return NS_OK ;
}
2014-12-19 10:00:29 +00:00
2014-12-19 13:01:53 +00:00
void
2015-09-30 23:11:03 +00:00
ContinueInstallTask : : ContinueAfterWorkerEvent ( bool aSuccess )
2014-12-19 13:01:53 +00:00
{
2015-02-10 22:33:23 +00:00
// This does not start the job immediately if there are other jobs in the
// queue, which captures the "atomic" behaviour we want.
2015-09-30 23:11:03 +00:00
mJob - > ContinueAfterInstallEvent ( aSuccess ) ;
2014-12-19 13:01:53 +00:00
}
2015-06-10 22:57:10 +00:00
// This function implements parts of the step 3 of the following algorithm:
// https://w3c.github.io/webappsec/specs/powerfulfeatures/#settings-secure
static bool
IsFromAuthenticatedOrigin ( nsIDocument * aDoc )
{
MOZ_ASSERT ( aDoc ) ;
nsCOMPtr < nsIDocument > doc ( aDoc ) ;
2015-11-06 19:10:17 +00:00
nsCOMPtr < nsIContentSecurityManager > csm = do_GetService ( NS_CONTENTSECURITYMANAGER_CONTRACTID ) ;
if ( NS_WARN_IF ( ! csm ) ) {
return false ;
}
2015-06-10 22:57:10 +00:00
while ( doc & & ! nsContentUtils : : IsChromeDoc ( doc ) ) {
2015-11-06 19:10:17 +00:00
bool trustworthyURI = false ;
2015-11-10 21:51:22 +00:00
// The origin of the document may be different from the document URI
// itself. Check the principal, not the document URI itself.
nsCOMPtr < nsIPrincipal > documentPrincipal = doc - > NodePrincipal ( ) ;
// The check for IsChromeDoc() above should mean we never see a system
// principal inside the loop.
MOZ_ASSERT ( ! nsContentUtils : : IsSystemPrincipal ( documentPrincipal ) ) ;
// Pass the principal as a URI to the security manager
nsCOMPtr < nsIURI > uri ;
documentPrincipal - > GetURI ( getter_AddRefs ( uri ) ) ;
if ( NS_WARN_IF ( ! uri ) ) {
return false ;
}
csm - > IsURIPotentiallyTrustworthy ( uri , & trustworthyURI ) ;
2015-11-06 19:10:17 +00:00
if ( ! trustworthyURI ) {
2015-06-10 22:57:10 +00:00
return false ;
}
doc = doc - > GetParentDocument ( ) ;
}
return true ;
}
2015-06-10 22:33:40 +00:00
// If we return an error code here, the ServiceWorkerContainer will
// automatically reject the Promise.
NS_IMETHODIMP
ServiceWorkerManager : : Register ( nsIDOMWindow * aWindow ,
nsIURI * aScopeURI ,
nsIURI * aScriptURI ,
nsISupports * * aPromise )
{
AssertIsOnMainThread ( ) ;
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
2015-11-05 17:33:33 +00:00
if ( NS_WARN_IF ( ! window ) ) {
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
2015-06-10 22:33:40 +00:00
nsCOMPtr < nsIDocument > doc = window - > GetExtantDoc ( ) ;
if ( ! doc ) {
return NS_ERROR_FAILURE ;
}
2015-11-10 21:51:22 +00:00
// Don't allow service workers to register when the *document* is chrome.
if ( NS_WARN_IF ( nsContentUtils : : IsSystemPrincipal ( doc - > NodePrincipal ( ) ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
2015-06-10 22:33:40 +00:00
nsCOMPtr < nsPIDOMWindow > outerWindow = window - > GetOuterWindow ( ) ;
bool serviceWorkersTestingEnabled =
outerWindow - > GetServiceWorkersTestingEnabled ( ) ;
bool authenticatedOrigin ;
if ( Preferences : : GetBool ( " dom.serviceWorkers.testing.enabled " ) | |
serviceWorkersTestingEnabled ) {
authenticatedOrigin = true ;
} else {
authenticatedOrigin = IsFromAuthenticatedOrigin ( doc ) ;
}
if ( ! authenticatedOrigin ) {
NS_WARNING ( " ServiceWorker registration from insecure websites is not allowed. " ) ;
return NS_ERROR_DOM_SECURITY_ERR ;
}
2014-12-19 10:00:29 +00:00
// Data URLs are not allowed.
nsCOMPtr < nsIPrincipal > documentPrincipal = doc - > NodePrincipal ( ) ;
2014-08-26 08:16:03 +00:00
2015-06-10 22:33:40 +00:00
nsresult rv = documentPrincipal - > CheckMayLoad ( aScriptURI , true /* report */ ,
false /* allowIfInheritsPrincipal */ ) ;
2014-12-19 10:00:29 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
2014-08-26 08:16:03 +00:00
2015-10-19 02:38:06 +00:00
// Check content policy.
int16_t decision = nsIContentPolicy : : ACCEPT ;
rv = NS_CheckContentLoadPolicy ( nsIContentPolicy : : TYPE_INTERNAL_SERVICE_WORKER ,
aScriptURI ,
documentPrincipal ,
doc ,
EmptyCString ( ) ,
nullptr ,
& decision ) ;
NS_ENSURE_SUCCESS ( rv , rv ) ;
if ( NS_WARN_IF ( decision ! = nsIContentPolicy : : ACCEPT ) ) {
return NS_ERROR_CONTENT_BLOCKED ;
}
2015-03-10 01:57:06 +00:00
rv = documentPrincipal - > CheckMayLoad ( aScopeURI , true /* report */ ,
2014-12-19 10:00:29 +00:00
false /* allowIfInheritsPrinciple */ ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
2015-11-10 21:51:22 +00:00
// The IsURIPotentiallyTrustworthy() check allows file:// and possibly other
// URI schemes. We need to explicitly only allows http and https schemes.
// Note, we just use the aScriptURI here for the check since its already
// been verified as same origin with the document principal. This also
// is a good block against accidentally allowing blob: script URIs which
// might inherit the origin.
bool isHttp = false ;
bool isHttps = false ;
aScriptURI - > SchemeIs ( " http " , & isHttp ) ;
aScriptURI - > SchemeIs ( " https " , & isHttps ) ;
if ( NS_WARN_IF ( ! isHttp & & ! isHttps ) ) {
# ifdef RELEASE_BUILD
return NS_ERROR_DOM_SECURITY_ERR ;
# else
bool isApp = false ;
aScriptURI - > SchemeIs ( " app " , & isApp ) ;
if ( NS_WARN_IF ( ! isApp ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
# endif
}
2014-12-19 10:00:29 +00:00
nsCString cleanedScope ;
2015-03-10 01:57:06 +00:00
rv = aScopeURI - > GetSpecIgnoringRef ( cleanedScope ) ;
2014-12-19 10:00:29 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2014-08-26 08:16:03 +00:00
return NS_ERROR_FAILURE ;
}
2014-12-19 10:00:29 +00:00
nsAutoCString spec ;
2015-11-11 10:46:29 +00:00
rv = aScriptURI - > GetSpecIgnoringRef ( spec ) ;
2014-12-19 10:00:29 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2014-08-26 08:16:03 +00:00
nsCOMPtr < nsIGlobalObject > sgo = do_QueryInterface ( window ) ;
ErrorResult result ;
2015-10-18 05:24:48 +00:00
RefPtr < Promise > promise = Promise : : Create ( sgo , result ) ;
2014-08-26 08:16:03 +00:00
if ( result . Failed ( ) ) {
2015-04-27 13:18:51 +00:00
return result . StealNSResult ( ) ;
2014-08-26 08:16:03 +00:00
}
2015-06-03 08:43:43 +00:00
nsAutoCString originSuffix ;
rv = PrincipalToScopeKey ( documentPrincipal , originSuffix ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-11-16 16:04:11 +00:00
AddRegisteringDocument ( cleanedScope , doc ) ;
2015-06-03 08:43:43 +00:00
ServiceWorkerJobQueue * queue = GetOrCreateJobQueue ( originSuffix , cleanedScope ) ;
2014-12-19 10:00:29 +00:00
MOZ_ASSERT ( queue ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerResolveWindowPromiseOnUpdateCallback > cb =
2014-12-19 10:00:29 +00:00
new ServiceWorkerResolveWindowPromiseOnUpdateCallback ( window , promise ) ;
2015-06-23 17:50:04 +00:00
nsCOMPtr < nsILoadGroup > docLoadGroup = doc - > GetDocumentLoadGroup ( ) ;
2015-10-18 05:24:48 +00:00
RefPtr < WorkerLoadInfo : : InterfaceRequestor > ir =
2015-06-23 17:50:04 +00:00
new WorkerLoadInfo : : InterfaceRequestor ( documentPrincipal , docLoadGroup ) ;
ir - > MaybeAddTabChild ( docLoadGroup ) ;
// Create a load group that is separate from, yet related to, the document's load group.
// This allows checks for interfaces like nsILoadContext to yield the values used by the
// the document, yet will not cancel the update job if the document's load group is cancelled.
nsCOMPtr < nsILoadGroup > loadGroup = do_CreateInstance ( NS_LOADGROUP_CONTRACTID ) ;
rv = loadGroup - > SetNotificationCallbacks ( ir ) ;
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( rv ) ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegisterJob > job =
2015-06-23 17:50:04 +00:00
new ServiceWorkerRegisterJob ( queue , cleanedScope , spec , cb , documentPrincipal , loadGroup ) ;
2014-12-19 10:00:29 +00:00
queue - > Append ( job ) ;
2015-06-05 06:11:18 +00:00
AssertIsOnMainThread ( ) ;
Telemetry : : Accumulate ( Telemetry : : SERVICE_WORKER_REGISTRATIONS , 1 ) ;
2014-08-26 08:16:03 +00:00
promise . forget ( aPromise ) ;
2014-12-19 10:00:29 +00:00
return NS_OK ;
2014-08-26 08:16:03 +00:00
}
2015-02-11 11:53:00 +00:00
void
ServiceWorkerManager : : AppendPendingOperation ( ServiceWorkerJobQueue * aQueue ,
ServiceWorkerJob * aJob )
{
MOZ_ASSERT ( ! mActor ) ;
MOZ_ASSERT ( aQueue ) ;
MOZ_ASSERT ( aJob ) ;
2015-06-23 12:56:29 +00:00
if ( ! mShuttingDown ) {
PendingOperation * opt = mPendingOperations . AppendElement ( ) ;
opt - > mQueue = aQueue ;
opt - > mJob = aJob ;
}
2015-02-11 11:53:00 +00:00
}
void
ServiceWorkerManager : : AppendPendingOperation ( nsIRunnable * aRunnable )
{
MOZ_ASSERT ( ! mActor ) ;
MOZ_ASSERT ( aRunnable ) ;
2015-06-23 12:56:29 +00:00
if ( ! mShuttingDown ) {
PendingOperation * opt = mPendingOperations . AppendElement ( ) ;
opt - > mRunnable = aRunnable ;
}
2015-02-11 11:53:00 +00:00
}
2014-06-11 16:12:56 +00:00
void
2014-12-19 10:00:29 +00:00
ServiceWorkerRegistrationInfo : : TryToActivate ( )
2014-06-11 16:12:56 +00:00
{
2015-06-02 11:12:00 +00:00
if ( ! IsControllingDocuments ( ) | | mWaitingWorker - > SkipWaitingFlag ( ) ) {
2014-12-19 10:00:29 +00:00
Activate ( ) ;
2014-06-11 16:12:56 +00:00
}
}
2015-02-10 22:33:23 +00:00
void
2015-09-30 23:11:03 +00:00
ContinueActivateTask : : ContinueAfterWorkerEvent ( bool aSuccess )
2015-02-10 22:33:23 +00:00
{
2015-02-10 22:33:23 +00:00
mRegistration - > FinishActivate ( aSuccess ) ;
}
2015-02-17 08:35:27 +00:00
2015-02-10 22:33:23 +00:00
void
2015-06-02 11:12:00 +00:00
ServiceWorkerRegistrationInfo : : PurgeActiveWorker ( )
2015-02-10 22:33:23 +00:00
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerInfo > exitingWorker = mActiveWorker . forget ( ) ;
2015-06-02 11:12:00 +00:00
if ( ! exitingWorker )
return ;
2014-12-19 10:00:29 +00:00
2015-06-02 11:12:00 +00:00
// FIXME(jaoo): Bug 1170543 - Wait for exitingWorker to finish and terminate it.
exitingWorker - > UpdateState ( ServiceWorkerState : : Redundant ) ;
nsresult rv = serviceWorkerScriptCache : : PurgeCache ( mPrincipal ,
exitingWorker - > CacheName ( ) ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to purge the activating cache. " ) ;
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-06-02 11:12:00 +00:00
swm - > InvalidateServiceWorkerRegistrationWorker ( this , WhichServiceWorker : : ACTIVE_WORKER ) ;
}
void
ServiceWorkerRegistrationInfo : : Activate ( )
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerInfo > activatingWorker = mWaitingWorker ;
2014-12-19 10:00:29 +00:00
if ( ! activatingWorker ) {
2014-06-11 16:12:56 +00:00
return ;
}
2015-06-02 11:12:00 +00:00
PurgeActiveWorker ( ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-06-02 11:12:00 +00:00
swm - > InvalidateServiceWorkerRegistrationWorker ( this , WhichServiceWorker : : WAITING_WORKER ) ;
2014-06-11 16:12:56 +00:00
2014-12-19 10:00:29 +00:00
mActiveWorker = activatingWorker . forget ( ) ;
mWaitingWorker = nullptr ;
mActiveWorker - > UpdateState ( ServiceWorkerState : : Activating ) ;
2015-11-13 20:54:54 +00:00
NotifyListenersOnChange ( ) ;
2014-06-11 16:12:56 +00:00
2015-02-10 22:33:23 +00:00
// FIXME(nsm): Unlink appcache if there is one.
2014-12-19 10:00:29 +00:00
swm - > CheckPendingReadyPromises ( ) ;
2014-06-11 16:12:56 +00:00
2014-12-19 10:00:29 +00:00
// "Queue a task to fire a simple event named controllerchange..."
nsCOMPtr < nsIRunnable > controllerChangeRunnable =
2015-12-05 02:03:47 +00:00
NS_NewRunnableMethodWithArg < RefPtr < ServiceWorkerRegistrationInfo > > (
swm , & ServiceWorkerManager : : FireControllerChange , this ) ;
2014-12-19 10:00:29 +00:00
NS_DispatchToMainThread ( controllerChangeRunnable ) ;
2014-07-03 00:48:35 +00:00
2015-07-15 19:21:40 +00:00
nsCOMPtr < nsIRunnable > failRunnable =
NS_NewRunnableMethodWithArg < bool > ( this ,
& ServiceWorkerRegistrationInfo : : FinishActivate ,
false /* success */ ) ;
2015-09-30 23:11:03 +00:00
nsMainThreadPtrHandle < ContinueLifecycleTask > continueActivateTask (
new nsMainThreadPtrHolder < ContinueLifecycleTask > ( new ContinueActivateTask ( this ) ) ) ;
2015-10-18 05:24:48 +00:00
RefPtr < LifeCycleEventCallback > callback =
2015-09-30 23:11:03 +00:00
new ContinueLifecycleRunnable ( continueActivateTask ) ;
ServiceWorkerPrivate * workerPrivate = mActiveWorker - > WorkerPrivate ( ) ;
nsresult rv = workerPrivate - > SendLifeCycleEvent ( NS_LITERAL_STRING ( " activate " ) ,
callback , failRunnable ) ;
2014-07-03 00:48:35 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2015-07-15 19:21:40 +00:00
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( NS_DispatchToMainThread ( failRunnable ) ) ) ;
2014-12-19 11:25:56 +00:00
return ;
2014-07-03 00:48:35 +00:00
}
}
2014-12-19 10:00:29 +00:00
/*
* Implements the async aspects of the getRegistrations algorithm .
*/
2015-11-23 13:47:53 +00:00
class GetRegistrationsRunnable final : public nsRunnable
2014-07-03 00:48:50 +00:00
{
2014-12-19 10:00:29 +00:00
nsCOMPtr < nsPIDOMWindow > mWindow ;
2015-10-18 05:24:48 +00:00
RefPtr < Promise > mPromise ;
2014-07-03 00:48:50 +00:00
public :
2014-12-19 10:00:29 +00:00
GetRegistrationsRunnable ( nsPIDOMWindow * aWindow , Promise * aPromise )
: mWindow ( aWindow ) , mPromise ( aPromise )
2015-11-23 13:47:53 +00:00
{ }
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
NS_IMETHODIMP
Run ( )
2014-07-03 00:48:50 +00:00
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
nsIDocument * doc = mWindow - > GetExtantDoc ( ) ;
if ( ! doc ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-11 20:07:59 +00:00
2014-12-19 10:00:29 +00:00
nsCOMPtr < nsIURI > docURI = doc - > GetDocumentURI ( ) ;
if ( ! docURI ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-11 20:07:59 +00:00
2014-12-19 10:00:29 +00:00
nsCOMPtr < nsIPrincipal > principal = doc - > NodePrincipal ( ) ;
if ( ! principal ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-11 20:07:59 +00:00
2015-10-18 05:24:48 +00:00
nsTArray < RefPtr < ServiceWorkerRegistrationMainThread > > array ;
2014-12-19 10:00:29 +00:00
2015-06-03 20:40:46 +00:00
if ( NS_WARN_IF ( ! BasePrincipal : : Cast ( principal ) - > IsCodebasePrincipal ( ) ) ) {
2015-06-03 08:43:43 +00:00
return NS_OK ;
}
nsAutoCString scopeKey ;
nsresult rv = swm - > PrincipalToScopeKey ( principal , scopeKey ) ;
2015-02-16 22:22:17 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-06-03 08:43:43 +00:00
ServiceWorkerManager : : RegistrationDataPerPrincipal * data ;
if ( ! swm - > mRegistrationInfos . Get ( scopeKey , & data ) ) {
2015-02-16 22:22:17 +00:00
mPromise - > MaybeResolve ( array ) ;
return NS_OK ;
}
2015-06-03 08:43:43 +00:00
for ( uint32_t i = 0 ; i < data - > mOrderedScopes . Length ( ) ; + + i ) {
NS_ConvertUTF8toUTF16 scope ( data - > mOrderedScopes [ i ] ) ;
2015-02-16 22:22:17 +00:00
nsCOMPtr < nsIURI > scopeURI ;
nsresult rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , scope , nullptr , nullptr ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
mPromise - > MaybeReject ( rv ) ;
break ;
}
rv = principal - > CheckMayLoad ( scopeURI , true /* report */ ,
false /* allowIfInheritsPrincipal */ ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
continue ;
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationMainThread > swr =
2015-11-23 18:38:08 +00:00
mWindow - > GetServiceWorkerRegistration ( scope ) ;
2014-12-19 10:00:29 +00:00
array . AppendElement ( swr ) ;
}
mPromise - > MaybeResolve ( array ) ;
2014-07-11 20:07:59 +00:00
return NS_OK ;
}
} ;
2014-12-19 10:00:29 +00: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 00:48:50 +00:00
{
2014-12-19 10:00:29 +00:00
AssertIsOnMainThread ( ) ;
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
2015-11-05 17:33:33 +00:00
if ( NS_WARN_IF ( ! window ) ) {
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
2015-05-29 16:17:33 +00:00
nsCOMPtr < nsIDocument > doc = window - > GetExtantDoc ( ) ;
2015-11-05 17:33:33 +00:00
if ( NS_WARN_IF ( ! doc ) ) {
return NS_ERROR_DOM_INVALID_STATE_ERR ;
2014-07-03 00:48:50 +00:00
}
2015-05-29 16:17:33 +00:00
// Don't allow service workers to register when the *document* is chrome for
// now.
MOZ_ASSERT ( ! nsContentUtils : : IsSystemPrincipal ( doc - > NodePrincipal ( ) ) ) ;
2014-12-19 10:00:29 +00:00
nsCOMPtr < nsIGlobalObject > sgo = do_QueryInterface ( window ) ;
ErrorResult result ;
2015-10-18 05:24:48 +00:00
RefPtr < Promise > promise = Promise : : Create ( sgo , result ) ;
2014-12-19 10:00:29 +00:00
if ( result . Failed ( ) ) {
2015-04-27 13:18:51 +00:00
return result . StealNSResult ( ) ;
2014-07-03 00:48:50 +00:00
}
2014-12-19 10:00:29 +00:00
2015-03-17 16:29:17 +00:00
nsCOMPtr < nsIRunnable > runnable =
2014-12-19 10:00:29 +00:00
new GetRegistrationsRunnable ( window , promise ) ;
promise . forget ( aPromise ) ;
return NS_DispatchToCurrentThread ( runnable ) ;
}
2014-07-03 00:48:50 +00:00
/*
2014-12-19 10:00:29 +00:00
* Implements the async aspects of the getRegistration algorithm .
2014-07-03 00:48:50 +00:00
*/
2015-11-23 13:47:53 +00:00
class GetRegistrationRunnable final : public nsRunnable
2014-07-03 00:48:50 +00:00
{
2014-12-19 10:00:29 +00:00
nsCOMPtr < nsPIDOMWindow > mWindow ;
2015-10-18 05:24:48 +00:00
RefPtr < Promise > mPromise ;
2014-12-19 10:00:29 +00:00
nsString mDocumentURL ;
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
public :
GetRegistrationRunnable ( nsPIDOMWindow * aWindow , Promise * aPromise ,
const nsAString & aDocumentURL )
: mWindow ( aWindow ) , mPromise ( aPromise ) , mDocumentURL ( aDocumentURL )
2015-11-23 13:47:53 +00:00
{ }
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
NS_IMETHODIMP
Run ( )
2014-07-03 00:48:50 +00:00
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
nsIDocument * doc = mWindow - > GetExtantDoc ( ) ;
if ( ! doc ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
nsCOMPtr < nsIURI > docURI = doc - > GetDocumentURI ( ) ;
if ( ! docURI ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00: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 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
nsCOMPtr < nsIPrincipal > principal = doc - > NodePrincipal ( ) ;
if ( ! principal ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-11 20:07:59 +00:00
2014-12-19 10:00:29 +00:00
rv = principal - > CheckMayLoad ( uri , true /* report */ ,
false /* allowIfInheritsPrinciple */ ) ;
if ( NS_FAILED ( rv ) ) {
mPromise - > MaybeReject ( NS_ERROR_DOM_SECURITY_ERR ) ;
return NS_OK ;
}
2014-07-11 20:07:59 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2015-06-03 08:43:43 +00:00
swm - > GetServiceWorkerRegistrationInfo ( principal , uri ) ;
2014-07-11 20:07:59 +00:00
2014-12-19 10:00:29 +00:00
if ( ! registration ) {
mPromise - > MaybeResolve ( JS : : UndefinedHandleValue ) ;
return NS_OK ;
}
2014-07-11 20:07:59 +00:00
2014-12-19 10:00:29 +00:00
NS_ConvertUTF8toUTF16 scope ( registration - > mScope ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationMainThread > swr =
2015-11-23 18:38:08 +00:00
mWindow - > GetServiceWorkerRegistration ( scope ) ;
2014-12-19 10:00:29 +00:00
mPromise - > MaybeResolve ( swr ) ;
2014-07-11 20:07:59 +00:00
2014-12-19 10:00:29 +00:00
return NS_OK ;
2014-07-11 20:07:59 +00:00
}
} ;
2014-12-19 10:00:29 +00: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 00:48:50 +00:00
{
2014-12-19 10:00:29 +00:00
AssertIsOnMainThread ( ) ;
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
2015-11-05 17:33:33 +00:00
if ( NS_WARN_IF ( ! window ) ) {
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
2015-05-29 16:17:33 +00:00
nsCOMPtr < nsIDocument > doc = window - > GetExtantDoc ( ) ;
2015-11-05 17:33:33 +00:00
if ( NS_WARN_IF ( ! doc ) ) {
return NS_ERROR_DOM_INVALID_STATE_ERR ;
2014-07-03 00:48:50 +00:00
}
2015-05-29 16:17:33 +00:00
// Don't allow service workers to register when the *document* is chrome for
// now.
MOZ_ASSERT ( ! nsContentUtils : : IsSystemPrincipal ( doc - > NodePrincipal ( ) ) ) ;
2014-12-19 10:00:29 +00:00
nsCOMPtr < nsIGlobalObject > sgo = do_QueryInterface ( window ) ;
ErrorResult result ;
2015-10-18 05:24:48 +00:00
RefPtr < Promise > promise = Promise : : Create ( sgo , result ) ;
2014-12-19 10:00:29 +00:00
if ( result . Failed ( ) ) {
2015-04-27 13:18:51 +00:00
return result . StealNSResult ( ) ;
2014-07-03 00:48:50 +00:00
}
2015-03-17 16:29:17 +00:00
nsCOMPtr < nsIRunnable > runnable =
2014-12-19 10:00:29 +00:00
new GetRegistrationRunnable ( window , promise , aDocumentURL ) ;
promise . forget ( aPromise ) ;
return NS_DispatchToCurrentThread ( runnable ) ;
}
2014-07-03 00:48:50 +00:00
2015-11-23 13:47:53 +00:00
class GetReadyPromiseRunnable final : public nsRunnable
2014-12-19 10:00:29 +00:00
{
nsCOMPtr < nsPIDOMWindow > mWindow ;
2015-10-18 05:24:48 +00:00
RefPtr < Promise > mPromise ;
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
public :
GetReadyPromiseRunnable ( nsPIDOMWindow * aWindow , Promise * aPromise )
: mWindow ( aWindow ) , mPromise ( aPromise )
2015-11-23 13:47:53 +00:00
{ }
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
NS_IMETHODIMP
Run ( )
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
nsIDocument * doc = mWindow - > GetExtantDoc ( ) ;
if ( ! doc ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
nsCOMPtr < nsIURI > docURI = doc - > GetDocumentURI ( ) ;
if ( ! docURI ) {
mPromise - > MaybeReject ( NS_ERROR_UNEXPECTED ) ;
return NS_OK ;
}
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
if ( ! swm - > CheckReadyPromise ( mWindow , docURI , mPromise ) ) {
swm - > StorePendingReadyPromise ( mWindow , docURI , mPromise ) ;
2014-07-03 00:48:50 +00:00
}
2014-12-19 10:00:29 +00:00
return NS_OK ;
}
} ;
2015-04-11 03:19:28 +00:00
NS_IMETHODIMP
2015-06-24 20:34:54 +00:00
ServiceWorkerManager : : SendPushEvent ( const nsACString & aOriginAttributes ,
2015-06-03 08:43:43 +00:00
const nsACString & aScope ,
2015-09-17 12:10:42 +00:00
uint32_t aDataLength ,
2015-09-17 12:13:04 +00:00
uint8_t * aDataBytes ,
uint8_t optional_argc )
2015-04-11 03:19:28 +00:00
{
# ifdef MOZ_SIMPLEPUSH
return NS_ERROR_NOT_AVAILABLE ;
# else
2015-11-03 01:50:54 +00:00
PrincipalOriginAttributes attrs ;
2015-06-24 20:34:54 +00:00
if ( ! attrs . PopulateFromSuffix ( aOriginAttributes ) ) {
2015-06-03 08:43:43 +00:00
return NS_ERROR_INVALID_ARG ;
}
2015-09-30 23:11:03 +00:00
ServiceWorkerInfo * serviceWorker = GetActiveWorkerInfoForScope ( attrs , aScope ) ;
2015-07-17 21:54:38 +00:00
if ( NS_WARN_IF ( ! serviceWorker ) ) {
2015-04-11 03:19:28 +00:00
return NS_ERROR_FAILURE ;
}
2015-10-26 02:59:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
GetRegistration ( serviceWorker - > GetPrincipal ( ) , aScope ) ;
2015-09-17 12:13:04 +00:00
if ( optional_argc = = 2 ) {
nsTArray < uint8_t > data ;
if ( ! data . InsertElementsAt ( 0 , aDataBytes , aDataLength , fallible ) ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
2015-10-26 02:59:48 +00:00
return serviceWorker - > WorkerPrivate ( ) - > SendPushEvent ( Some ( data ) , registration ) ;
2015-09-17 12:13:04 +00:00
} else {
MOZ_ASSERT ( optional_argc = = 0 ) ;
2015-10-26 02:59:48 +00:00
return serviceWorker - > WorkerPrivate ( ) - > SendPushEvent ( Nothing ( ) , registration ) ;
2015-09-30 18:11:47 +00:00
}
2015-09-30 23:11:03 +00:00
# endif // MOZ_SIMPLEPUSH
2015-04-11 03:19:28 +00:00
}
NS_IMETHODIMP
2015-06-24 20:34:54 +00:00
ServiceWorkerManager : : SendPushSubscriptionChangeEvent ( const nsACString & aOriginAttributes ,
const nsACString & aScope )
2015-04-11 03:19:28 +00:00
{
# ifdef MOZ_SIMPLEPUSH
return NS_ERROR_NOT_AVAILABLE ;
# else
2015-11-03 01:50:54 +00:00
PrincipalOriginAttributes attrs ;
2015-06-24 20:34:54 +00:00
if ( ! attrs . PopulateFromSuffix ( aOriginAttributes ) ) {
2015-06-03 08:43:43 +00:00
return NS_ERROR_INVALID_ARG ;
}
2015-09-30 23:11:03 +00:00
ServiceWorkerInfo * info = GetActiveWorkerInfoForScope ( attrs , aScope ) ;
if ( ! info ) {
2015-04-11 03:19:28 +00:00
return NS_ERROR_FAILURE ;
}
2015-09-30 23:11:03 +00:00
return info - > WorkerPrivate ( ) - > SendPushSubscriptionChangeEvent ( ) ;
2015-04-11 03:19:28 +00:00
# endif
}
2015-06-26 01:50:25 +00:00
NS_IMETHODIMP
ServiceWorkerManager : : SendNotificationClickEvent ( const nsACString & aOriginSuffix ,
const nsACString & aScope ,
const nsAString & aID ,
const nsAString & aTitle ,
const nsAString & aDir ,
const nsAString & aLang ,
const nsAString & aBody ,
const nsAString & aTag ,
const nsAString & aIcon ,
const nsAString & aData ,
const nsAString & aBehavior )
{
2015-11-03 01:50:54 +00:00
PrincipalOriginAttributes attrs ;
2015-06-26 01:50:25 +00:00
if ( ! attrs . PopulateFromSuffix ( aOriginSuffix ) ) {
return NS_ERROR_INVALID_ARG ;
}
2015-09-30 23:11:03 +00:00
ServiceWorkerInfo * info = GetActiveWorkerInfoForScope ( attrs , aScope ) ;
if ( ! info ) {
2015-06-26 01:50:25 +00:00
return NS_ERROR_FAILURE ;
}
2015-09-30 23:11:03 +00:00
ServiceWorkerPrivate * workerPrivate = info - > WorkerPrivate ( ) ;
return workerPrivate - > SendNotificationClickEvent ( aID , aTitle , aDir ,
aLang , aBody , aTag ,
aIcon , aData , aBehavior ,
NS_ConvertUTF8toUTF16 ( aScope ) ) ;
2015-06-26 01:50:25 +00:00
}
2014-12-19 10:00:29 +00:00
NS_IMETHODIMP
ServiceWorkerManager : : GetReadyPromise ( nsIDOMWindow * aWindow ,
nsISupports * * aPromise )
{
AssertIsOnMainThread ( ) ;
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
2015-11-05 17:33:33 +00:00
if ( NS_WARN_IF ( ! window ) ) {
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
2015-05-29 16:17:33 +00:00
nsCOMPtr < nsIDocument > doc = window - > GetExtantDoc ( ) ;
2015-11-05 17:33:33 +00:00
if ( NS_WARN_IF ( ! doc ) ) {
2014-12-19 10:00:29 +00:00
return NS_ERROR_FAILURE ;
}
2015-05-29 16:17:33 +00:00
// Don't allow service workers to register when the *document* is chrome for
// now.
MOZ_ASSERT ( ! nsContentUtils : : IsSystemPrincipal ( doc - > NodePrincipal ( ) ) ) ;
2014-12-19 10:00:29 +00:00
MOZ_ASSERT ( ! mPendingReadyPromises . Contains ( window ) ) ;
nsCOMPtr < nsIGlobalObject > sgo = do_QueryInterface ( window ) ;
ErrorResult result ;
2015-10-18 05:24:48 +00:00
RefPtr < Promise > promise = Promise : : Create ( sgo , result ) ;
2014-12-19 10:00:29 +00:00
if ( result . Failed ( ) ) {
2015-04-27 13:18:51 +00:00
return result . StealNSResult ( ) ;
2014-07-03 00:48:50 +00:00
}
2015-03-17 16:29:17 +00:00
nsCOMPtr < nsIRunnable > runnable =
2014-12-19 10:00:29 +00:00
new GetReadyPromiseRunnable ( window , promise ) ;
promise . forget ( aPromise ) ;
return NS_DispatchToCurrentThread ( runnable ) ;
}
NS_IMETHODIMP
ServiceWorkerManager : : RemoveReadyPromise ( nsIDOMWindow * aWindow )
2014-07-11 20:07:59 +00:00
{
2014-12-19 10:00:29 +00:00
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWindow ) ;
2014-07-11 20:07:59 +00:00
2014-12-19 10:00:29 +00:00
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
if ( ! window ) {
return NS_ERROR_FAILURE ;
2014-07-11 20:07:59 +00:00
}
2014-12-19 10:00:29 +00:00
mPendingReadyPromises . Remove ( aWindow ) ;
return NS_OK ;
}
2014-07-11 20:07:59 +00:00
2014-12-19 10:00:29 +00:00
void
ServiceWorkerManager : : StorePendingReadyPromise ( nsPIDOMWindow * aWindow ,
nsIURI * aURI ,
Promise * aPromise )
{
PendingReadyPromise * data ;
2014-07-11 20:07:59 +00:00
2014-12-19 10:00:29 +00:00
// We should not have 2 pending promises for the same window.
MOZ_ASSERT ( ! mPendingReadyPromises . Get ( aWindow , & data ) ) ;
2014-07-11 20:07:59 +00:00
2014-12-19 10:00:29 +00:00
data = new PendingReadyPromise ( aURI , aPromise ) ;
mPendingReadyPromises . Put ( aWindow , data ) ;
}
2014-07-11 20:07:59 +00:00
2014-12-19 10:00:29 +00:00
void
ServiceWorkerManager : : CheckPendingReadyPromises ( )
{
2015-11-19 08:03:29 +00:00
for ( auto iter = mPendingReadyPromises . Iter ( ) ; ! iter . Done ( ) ; iter . Next ( ) ) {
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( iter . Key ( ) ) ;
MOZ_ASSERT ( window ) ;
2014-07-11 20:07:59 +00:00
2015-11-19 08:03:29 +00:00
nsAutoPtr < PendingReadyPromise > & pendingReadyPromise = iter . Data ( ) ;
if ( CheckReadyPromise ( window , pendingReadyPromise - > mURI ,
pendingReadyPromise - > mPromise ) ) {
iter . Remove ( ) ;
2015-11-23 13:47:53 +00:00
}
2014-12-19 10:00:29 +00:00
}
}
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
bool
ServiceWorkerManager : : CheckReadyPromise ( nsPIDOMWindow * aWindow ,
nsIURI * aURI , Promise * aPromise )
{
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( aWindow ) ;
MOZ_ASSERT ( aURI ) ;
nsCOMPtr < nsIDocument > doc = aWindow - > GetExtantDoc ( ) ;
MOZ_ASSERT ( doc ) ;
nsCOMPtr < nsIPrincipal > principal = doc - > NodePrincipal ( ) ;
MOZ_ASSERT ( principal ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2015-06-03 08:43:43 +00:00
GetServiceWorkerRegistrationInfo ( principal , aURI ) ;
2014-07-03 00:48:50 +00:00
2014-12-19 10:00:29 +00:00
if ( registration & & registration - > mActiveWorker ) {
NS_ConvertUTF8toUTF16 scope ( registration - > mScope ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationMainThread > swr =
2015-11-23 18:38:08 +00:00
aWindow - > GetServiceWorkerRegistration ( scope ) ;
2014-12-19 10:00:29 +00:00
aPromise - > MaybeResolve ( swr ) ;
return true ;
2014-07-03 00:48:50 +00:00
}
2014-12-19 10:00:29 +00:00
return false ;
2014-07-03 00:48:50 +00:00
}
2015-09-30 23:11:03 +00:00
ServiceWorkerInfo *
2015-11-03 01:50:54 +00:00
ServiceWorkerManager : : GetActiveWorkerInfoForScope ( const PrincipalOriginAttributes & aOriginAttributes ,
2015-11-23 13:47:53 +00:00
const nsACString & aScope )
2015-04-11 03:19:28 +00:00
{
AssertIsOnMainThread ( ) ;
nsCOMPtr < nsIURI > scopeURI ;
nsresult rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , aScope , nullptr , nullptr ) ;
if ( NS_FAILED ( rv ) ) {
return nullptr ;
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2015-06-03 08:43:43 +00:00
GetServiceWorkerRegistrationInfo ( aOriginAttributes , scopeURI ) ;
2015-04-11 03:19:28 +00:00
if ( ! registration ) {
return nullptr ;
}
2015-09-30 23:11:03 +00:00
return registration - > mActiveWorker ;
}
2015-04-11 03:19:28 +00:00
2015-09-30 23:11:03 +00:00
ServiceWorkerInfo *
ServiceWorkerManager : : GetActiveWorkerInfoForDocument ( nsIDocument * aDocument )
{
AssertIsOnMainThread ( ) ;
2015-09-30 14:14:33 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-09-30 23:11:03 +00:00
GetDocumentRegistration ( aDocument , getter_AddRefs ( registration ) ) ;
if ( ! registration ) {
2015-04-11 03:19:28 +00:00
return nullptr ;
}
2015-09-30 23:11:03 +00:00
return registration - > mActiveWorker ;
2015-04-11 03:19:28 +00:00
}
2015-03-21 16:28:04 +00:00
class ServiceWorkerUnregisterJob final : public ServiceWorkerJob
2014-07-03 00:48:50 +00:00
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > mRegistration ;
2015-01-22 22:10:38 +00:00
const nsCString mScope ;
nsCOMPtr < nsIServiceWorkerUnregisterCallback > mCallback ;
2015-06-03 08:43:43 +00:00
nsCOMPtr < nsIPrincipal > mPrincipal ;
2014-12-19 10:00:29 +00:00
2015-01-22 22:10:38 +00:00
~ ServiceWorkerUnregisterJob ( )
2015-11-23 13:47:53 +00:00
{ }
2015-01-22 22:10:38 +00:00
public :
ServiceWorkerUnregisterJob ( ServiceWorkerJobQueue * aQueue ,
const nsACString & aScope ,
2015-02-11 11:53:00 +00:00
nsIServiceWorkerUnregisterCallback * aCallback ,
2015-06-03 08:43:43 +00:00
nsIPrincipal * aPrincipal )
2015-11-26 17:03:10 +00:00
: ServiceWorkerJob ( aQueue , Type : : UnregisterJob )
2015-01-22 22:10:38 +00:00
, mScope ( aScope )
, mCallback ( aCallback )
2015-06-03 08:43:43 +00:00
, mPrincipal ( aPrincipal )
2015-01-22 22:10:38 +00:00
{
AssertIsOnMainThread ( ) ;
2014-07-11 20:07:59 +00:00
}
2015-01-22 22:10:38 +00:00
void
2015-03-21 16:28:04 +00:00
Start ( ) override
2014-07-11 20:07:59 +00:00
{
2015-01-22 22:10:38 +00:00
AssertIsOnMainThread ( ) ;
nsCOMPtr < nsIRunnable > r =
NS_NewRunnableMethod ( this , & ServiceWorkerUnregisterJob : : UnregisterAndDone ) ;
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( NS_DispatchToMainThread ( r ) ) ) ;
}
2014-07-11 20:07:59 +00:00
2015-01-22 22:10:38 +00:00
private :
// You probably want UnregisterAndDone().
nsresult
Unregister ( )
{
AssertIsOnMainThread ( ) ;
2014-07-11 20:07:59 +00:00
2015-06-03 08:43:43 +00:00
PrincipalInfo principalInfo ;
if ( NS_WARN_IF ( NS_FAILED ( PrincipalToPrincipalInfo ( mPrincipal ,
& principalInfo ) ) ) ) {
return mCallback ? mCallback - > UnregisterSucceeded ( false ) : NS_OK ;
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2014-07-23 21:05:08 +00:00
2015-06-23 12:56:29 +00:00
// Could it be that we are shutting down.
if ( swm - > mActor ) {
swm - > mActor - > SendUnregister ( principalInfo , NS_ConvertUTF8toUTF16 ( mScope ) ) ;
}
2015-06-21 11:19:07 +00:00
2015-06-03 08:43:43 +00:00
nsAutoCString scopeKey ;
nsresult rv = swm - > PrincipalToScopeKey ( mPrincipal , scopeKey ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return mCallback ? mCallback - > UnregisterSucceeded ( false ) : NS_OK ;
}
2015-01-22 22:10:38 +00:00
// "Let registration be the result of running [[Get Registration]]
// algorithm passing scope as the argument."
2015-06-03 08:43:43 +00:00
ServiceWorkerManager : : RegistrationDataPerPrincipal * data ;
if ( ! swm - > mRegistrationInfos . Get ( scopeKey , & data ) ) {
// "If registration is null, then, resolve promise with false."
return mCallback ? mCallback - > UnregisterSucceeded ( false ) : NS_OK ;
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-06-03 08:43:43 +00:00
if ( ! data - > mInfos . Get ( mScope , getter_AddRefs ( registration ) ) ) {
2015-01-22 22:10:38 +00:00
// "If registration is null, then, resolve promise with false."
2015-04-15 17:11:17 +00:00
return mCallback ? mCallback - > UnregisterSucceeded ( false ) : NS_OK ;
2015-01-22 22:10:38 +00:00
}
2014-07-11 20:07:59 +00:00
2015-01-22 22:10:38 +00:00
MOZ_ASSERT ( registration ) ;
2014-07-11 20:07:59 +00:00
2015-01-22 22:10:38 +00:00
// "Set registration's uninstalling flag."
registration - > mPendingUninstall = true ;
// "Resolve promise with true"
2015-06-03 08:43:43 +00:00
rv = mCallback ? mCallback - > UnregisterSucceeded ( true ) : NS_OK ;
2015-01-22 22:10:38 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2014-12-19 10:00:29 +00:00
2015-01-22 22:10:38 +00: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 10:00:29 +00:00
}
2014-07-11 20:07:59 +00:00
2015-01-22 22:10:38 +00:00
// "Invoke [[Clear Registration]]..."
registration - > Clear ( ) ;
2015-02-09 04:33:39 +00:00
swm - > RemoveRegistration ( registration ) ;
2015-01-22 22:10:38 +00:00
}
2014-07-11 20:07:59 +00:00
2015-01-22 22:10:38 +00:00
return NS_OK ;
}
2014-07-11 20:07:59 +00:00
2015-01-22 22:10:38 +00:00
// The unregister job is done irrespective of success or failure of any sort.
void
UnregisterAndDone ( )
{
2015-04-24 18:42:13 +00:00
nsresult rv = Unregister ( ) ;
2015-11-02 05:53:26 +00:00
Unused < < NS_WARN_IF ( NS_FAILED ( rv ) ) ;
2015-04-24 18:42:13 +00:00
Done ( rv ) ;
2015-01-22 22:10:38 +00:00
}
} ;
2014-07-11 20:07:59 +00:00
2015-01-22 22:10:38 +00:00
NS_IMETHODIMP
2015-02-11 11:53:00 +00:00
ServiceWorkerManager : : Unregister ( nsIPrincipal * aPrincipal ,
nsIServiceWorkerUnregisterCallback * aCallback ,
2015-01-22 22:10:38 +00:00
const nsAString & aScope )
{
AssertIsOnMainThread ( ) ;
2015-04-15 17:11:17 +00:00
if ( ! aPrincipal ) {
return NS_ERROR_FAILURE ;
}
2015-01-22 22:10:38 +00:00
2015-06-03 08:43:43 +00:00
nsresult rv ;
2015-01-22 22:10:38 +00:00
// This is not accessible by content, and callers should always ensure scope is
// a correct URI, so this is wrapped in DEBUG
# ifdef DEBUG
nsCOMPtr < nsIURI > scopeURI ;
2015-06-03 08:43:43 +00:00
rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , aScope , nullptr , nullptr ) ;
2015-01-22 22:10:38 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
# endif
2015-06-03 08:43:43 +00:00
nsAutoCString originSuffix ;
rv = PrincipalToScopeKey ( aPrincipal , originSuffix ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-01-22 22:10:38 +00:00
NS_ConvertUTF16toUTF8 scope ( aScope ) ;
2015-06-03 08:43:43 +00:00
ServiceWorkerJobQueue * queue = GetOrCreateJobQueue ( originSuffix , scope ) ;
2015-01-22 22:10:38 +00:00
MOZ_ASSERT ( queue ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerUnregisterJob > job =
2015-06-03 08:43:43 +00:00
new ServiceWorkerUnregisterJob ( queue , scope , aCallback , aPrincipal ) ;
2015-02-11 11:53:00 +00:00
if ( mActor ) {
queue - > Append ( job ) ;
return NS_OK ;
}
AppendPendingOperation ( queue , job ) ;
2015-01-22 22:10:38 +00:00
return NS_OK ;
2014-12-19 10:00:29 +00:00
}
2015-06-03 08:43:43 +00:00
ServiceWorkerJobQueue *
ServiceWorkerManager : : GetOrCreateJobQueue ( const nsACString & aKey ,
const nsACString & aScope )
{
ServiceWorkerManager : : RegistrationDataPerPrincipal * data ;
if ( ! mRegistrationInfos . Get ( aKey , & data ) ) {
data = new RegistrationDataPerPrincipal ( ) ;
mRegistrationInfos . Put ( aKey , data ) ;
}
ServiceWorkerJobQueue * queue ;
if ( ! data - > mJobQueues . Get ( aScope , & queue ) ) {
queue = new ServiceWorkerJobQueue ( aKey ) ;
data - > mJobQueues . Put ( aScope , queue ) ;
}
return queue ;
}
2014-12-19 10:00:29 +00:00
/* static */
already_AddRefed < ServiceWorkerManager >
ServiceWorkerManager : : GetInstance ( )
{
2015-06-04 17:21:52 +00:00
// Note: We don't simply check gInstance for null-ness here, since otherwise
// this can resurrect the ServiceWorkerManager pretty late during shutdown.
static bool firstTime = true ;
if ( firstTime ) {
2015-06-02 22:01:26 +00:00
firstTime = false ;
2015-06-04 17:21:52 +00:00
AssertIsOnMainThread ( ) ;
gInstance = new ServiceWorkerManager ( ) ;
gInstance - > Init ( ) ;
ClearOnShutdown ( & gInstance ) ;
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > copy = gInstance . get ( ) ;
2015-06-04 17:21:52 +00:00
return copy . forget ( ) ;
2014-12-19 10:00:29 +00:00
}
void
ServiceWorkerManager : : FinishFetch ( ServiceWorkerRegistrationInfo * aRegistration )
{
}
2014-07-03 00:48:50 +00:00
2015-11-16 16:04:11 +00:00
void
ServiceWorkerManager : : ReportToAllClients ( const nsCString & aScope ,
const nsString & aMessage ,
const nsString & aFilename ,
const nsString & aLine ,
uint32_t aLineNumber ,
uint32_t aColumnNumber ,
uint32_t aFlags )
{
nsCOMPtr < nsIURI > uri ;
nsresult rv = NS_NewURI ( getter_AddRefs ( uri ) , aFilename ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
2015-11-16 16:04:11 +00:00
nsAutoTArray < uint64_t , 16 > windows ;
// Report errors to every controlled document.
2015-11-16 16:04:11 +00:00
for ( auto iter = mControlledDocuments . Iter ( ) ; ! iter . Done ( ) ; iter . Next ( ) ) {
ServiceWorkerRegistrationInfo * reg = iter . UserData ( ) ;
MOZ_ASSERT ( reg ) ;
if ( ! reg - > mScope . Equals ( aScope ) ) {
continue ;
}
nsCOMPtr < nsIDocument > doc = do_QueryInterface ( iter . Key ( ) ) ;
2015-11-16 16:04:11 +00:00
if ( ! doc | | ! doc - > IsCurrentActiveDocument ( ) | | ! doc - > GetWindow ( ) ) {
2015-11-16 16:04:11 +00:00
continue ;
}
2015-11-16 16:04:11 +00:00
windows . AppendElement ( doc - > InnerWindowID ( ) ) ;
2015-11-16 16:04:11 +00:00
nsContentUtils : : ReportToConsoleNonLocalized ( aMessage ,
aFlags ,
NS_LITERAL_CSTRING ( " Service Workers " ) ,
doc ,
uri ,
aLine ,
aLineNumber ,
aColumnNumber ) ;
}
2015-11-16 16:04:11 +00:00
// Report to any documents that have called .register() for this scope. They
// may not be controlled, but will still want to see error reports.
2015-11-16 16:04:11 +00:00
WeakDocumentList * regList = mRegisteringDocuments . Get ( aScope ) ;
if ( regList ) {
for ( int32_t i = regList - > Length ( ) - 1 ; i > = 0 ; - - i ) {
nsCOMPtr < nsIDocument > doc = do_QueryReferent ( regList - > ElementAt ( i ) ) ;
2015-11-16 16:04:11 +00:00
if ( ! doc ) {
2015-11-16 16:04:11 +00:00
regList - > RemoveElementAt ( i ) ;
2015-11-16 16:04:11 +00:00
continue ;
}
2015-11-16 16:04:11 +00:00
if ( ! doc - > IsCurrentActiveDocument ( ) ) {
continue ;
}
2015-11-16 16:04:11 +00:00
uint64_t innerWindowId = doc - > InnerWindowID ( ) ;
if ( windows . Contains ( innerWindowId ) ) {
continue ;
}
windows . AppendElement ( innerWindowId ) ;
nsContentUtils : : ReportToConsoleNonLocalized ( aMessage ,
aFlags ,
NS_LITERAL_CSTRING ( " Service Workers " ) ,
doc ,
uri ,
aLine ,
aLineNumber ,
aColumnNumber ) ;
}
2015-11-16 16:04:11 +00:00
if ( regList - > IsEmpty ( ) ) {
regList = nullptr ;
nsAutoPtr < WeakDocumentList > doomed ;
mRegisteringDocuments . RemoveAndForget ( aScope , doomed ) ;
}
2015-11-16 16:04:11 +00:00
}
2015-11-16 16:04:11 +00:00
InterceptionList * intList = mNavigationInterceptions . Get ( aScope ) ;
if ( intList ) {
nsIConsoleService * consoleService = nullptr ;
for ( uint32_t i = 0 ; i < intList - > Length ( ) ; + + i ) {
nsCOMPtr < nsIInterceptedChannel > channel = intList - > ElementAt ( i ) ;
nsCOMPtr < nsIChannel > inner ;
rv = channel - > GetChannel ( getter_AddRefs ( inner ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
continue ;
}
uint64_t innerWindowId = nsContentUtils : : GetInnerWindowID ( inner ) ;
if ( innerWindowId = = 0 | | windows . Contains ( innerWindowId ) ) {
continue ;
}
windows . AppendElement ( innerWindowId ) ;
// Unfortunately the nsContentUtils helpers don't provide a convenient
// way to log to a window ID without a document. Use console service
// directly.
nsCOMPtr < nsIScriptError > errorObject =
do_CreateInstance ( NS_SCRIPTERROR_CONTRACTID , & rv ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
rv = errorObject - > InitWithWindowID ( aMessage ,
aFilename ,
aLine ,
aLineNumber ,
aColumnNumber ,
aFlags ,
NS_LITERAL_CSTRING ( " Service Workers " ) ,
innerWindowId ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
if ( ! consoleService ) {
rv = CallGetService ( NS_CONSOLESERVICE_CONTRACTID , & consoleService ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
}
consoleService - > LogMessage ( errorObject ) ;
}
}
2015-11-16 16:04:11 +00:00
// If there are no documents to report to, at least report something to the
// browser console.
if ( windows . IsEmpty ( ) ) {
nsContentUtils : : ReportToConsoleNonLocalized ( aMessage ,
aFlags ,
NS_LITERAL_CSTRING ( " Service Workers " ) ,
nullptr , // document
uri ,
aLine ,
aLineNumber ,
aColumnNumber ) ;
return ;
}
2015-11-16 16:04:11 +00:00
}
void
2014-12-19 10:00:29 +00:00
ServiceWorkerManager : : HandleError ( JSContext * aCx ,
2015-06-03 08:43:43 +00:00
nsIPrincipal * aPrincipal ,
2014-12-19 10:48:31 +00:00
const nsCString & aScope ,
const nsString & aWorkerURL ,
2015-11-16 16:04:11 +00:00
const nsString & aMessage ,
const nsString & aFilename ,
const nsString & aLine ,
2014-12-19 10:00:29 +00:00
uint32_t aLineNumber ,
uint32_t aColumnNumber ,
2015-08-19 23:21:25 +00:00
uint32_t aFlags ,
JSExnType aExnType )
2014-07-03 00:48:50 +00:00
{
AssertIsOnMainThread ( ) ;
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( aPrincipal ) ;
nsAutoCString scopeKey ;
nsresult rv = PrincipalToScopeKey ( aPrincipal , scopeKey ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
2015-11-16 16:04:11 +00:00
return ;
2015-06-03 08:43:43 +00:00
}
2014-07-03 00:48:50 +00:00
2015-06-03 08:43:43 +00:00
ServiceWorkerManager : : RegistrationDataPerPrincipal * data ;
2015-11-16 16:04:11 +00:00
if ( NS_WARN_IF ( ! mRegistrationInfos . Get ( scopeKey , & data ) ) ) {
return ;
2014-07-23 01:18:48 +00:00
}
2015-11-16 16:04:11 +00:00
// Always report any uncaught exceptions or errors to the console of
// each client.
2015-11-16 16:04:11 +00:00
ReportToAllClients ( aScope , aMessage , aFilename , aLine , aLineNumber ,
aColumnNumber , aFlags ) ;
2014-06-11 16:12:56 +00:00
}
2014-07-11 20:07:59 +00:00
void
2014-12-19 10:00:29 +00:00
ServiceWorkerRegistrationInfo : : FinishActivate ( bool aSuccess )
2014-07-11 20:07:59 +00:00
{
2015-12-04 21:32:37 +00:00
if ( mPendingUninstall | | ! mActiveWorker | |
mActiveWorker - > State ( ) ! = ServiceWorkerState : : Activating ) {
2015-02-10 22:33:23 +00:00
return ;
}
2015-08-24 21:42:14 +00:00
// Activation never fails, so aSuccess is ignored.
mActiveWorker - > UpdateState ( ServiceWorkerState : : Activated ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-08-24 21:42:14 +00:00
swm - > StoreRegistration ( mPrincipal , this ) ;
2014-07-11 20:07:59 +00:00
}
2015-10-26 02:59:48 +00:00
void
ServiceWorkerRegistrationInfo : : RefreshLastUpdateCheckTime ( )
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-10-26 02:59:48 +00:00
mLastUpdateCheckTime = PR_IntervalNow ( ) / PR_MSEC_PER_SEC ;
}
bool
ServiceWorkerRegistrationInfo : : IsLastUpdateCheckTimeOverOneDay ( ) const
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-10-26 02:59:48 +00:00
// For testing.
if ( Preferences : : GetBool ( " dom.serviceWorkers.testUpdateOverOneDay " ) ) {
return true ;
}
const uint64_t kSecondsPerDay = 86400 ;
const uint64_t now = PR_IntervalNow ( ) / PR_MSEC_PER_SEC ;
if ( ( mLastUpdateCheckTime ! = 0 ) & &
( now - mLastUpdateCheckTime > kSecondsPerDay ) ) {
return true ;
}
return false ;
}
2015-11-13 20:54:45 +00:00
void
ServiceWorkerRegistrationInfo : : NotifyListenersOnChange ( )
{
nsTArray < nsCOMPtr < nsIServiceWorkerRegistrationInfoListener > > listeners ( mListeners ) ;
for ( size_t index = 0 ; index < listeners . Length ( ) ; + + index ) {
listeners [ index ] - > OnChange ( ) ;
}
}
2015-12-11 19:53:10 +00:00
void
ServiceWorkerRegistrationInfo : : MaybeScheduleTimeCheckAndUpdate ( )
{
AssertIsOnMainThread ( ) ;
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
if ( ! swm ) {
// shutting down, do nothing
return ;
}
if ( mUpdateState = = NoUpdate ) {
mUpdateState = NeedTimeCheckAndUpdate ;
}
swm - > ScheduleUpdateTimer ( mPrincipal , mScope ) ;
}
void
ServiceWorkerRegistrationInfo : : MaybeScheduleUpdate ( )
{
AssertIsOnMainThread ( ) ;
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
if ( ! swm ) {
// shutting down, do nothing
return ;
}
mUpdateState = NeedUpdate ;
swm - > ScheduleUpdateTimer ( mPrincipal , mScope ) ;
}
bool
ServiceWorkerRegistrationInfo : : CheckAndClearIfUpdateNeeded ( )
{
AssertIsOnMainThread ( ) ;
bool result = mUpdateState = = NeedUpdate | |
( mUpdateState = = NeedTimeCheckAndUpdate & &
IsLastUpdateCheckTimeOverOneDay ( ) ) ;
mUpdateState = NoUpdate ;
return result ;
}
2015-06-04 18:51:57 +00:00
void
2015-06-04 18:51:57 +00:00
ServiceWorkerManager : : LoadRegistration (
const ServiceWorkerRegistrationData & aRegistration )
2015-06-04 18:51:57 +00:00
{
AssertIsOnMainThread ( ) ;
2015-06-04 18:51:57 +00:00
nsCOMPtr < nsIPrincipal > principal =
PrincipalInfoToPrincipal ( aRegistration . principal ( ) ) ;
if ( ! principal ) {
return ;
}
2015-06-05 11:07:51 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2015-06-04 18:51:57 +00:00
GetRegistration ( principal , aRegistration . scope ( ) ) ;
if ( ! registration ) {
registration = CreateNewRegistration ( aRegistration . scope ( ) , principal ) ;
2015-12-11 19:53:10 +00:00
} else {
RefPtr < ServiceWorkerInfo > newest = registration - > Newest ( ) ;
if ( newest & & newest - > ScriptSpec ( ) = = aRegistration . scriptSpec ( ) & &
! ! registration - > mActiveWorker = = aRegistration . currentWorkerURL ( ) . IsEmpty ( ) ) {
// No needs for updates.
return ;
}
2015-06-04 18:51:57 +00:00
}
2015-06-05 11:07:51 +00:00
2015-06-04 18:51:57 +00:00
const nsCString & currentWorkerURL = aRegistration . currentWorkerURL ( ) ;
if ( ! currentWorkerURL . IsEmpty ( ) ) {
registration - > mActiveWorker =
new ServiceWorkerInfo ( registration , currentWorkerURL ,
aRegistration . activeCacheName ( ) ) ;
registration - > mActiveWorker - > SetActivateStateUncheckedWithoutEvent ( ServiceWorkerState : : Activated ) ;
}
}
void
ServiceWorkerManager : : LoadRegistrations (
const nsTArray < ServiceWorkerRegistrationData > & aRegistrations )
{
AssertIsOnMainThread ( ) ;
for ( uint32_t i = 0 , len = aRegistrations . Length ( ) ; i < len ; + + i ) {
LoadRegistration ( aRegistrations [ i ] ) ;
2015-02-11 11:53:00 +00:00
}
}
void
ServiceWorkerManager : : ActorFailed ( )
{
MOZ_CRASH ( " Failed to create a PBackgroundChild actor! " ) ;
}
void
ServiceWorkerManager : : ActorCreated ( mozilla : : ipc : : PBackgroundChild * aActor )
{
MOZ_ASSERT ( aActor ) ;
MOZ_ASSERT ( ! mActor ) ;
2015-06-04 18:51:57 +00:00
PServiceWorkerManagerChild * actor =
aActor - > SendPServiceWorkerManagerConstructor ( ) ;
mActor = static_cast < ServiceWorkerManagerChild * > ( actor ) ;
2015-02-11 11:53:00 +00:00
// 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 ( aPrincipal ) ;
MOZ_ASSERT ( aRegistration ) ;
2015-06-23 12:56:29 +00:00
if ( mShuttingDown ) {
return ;
}
MOZ_ASSERT ( mActor ) ;
2015-02-11 11:53:00 +00:00
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 ;
}
2015-06-04 18:51:57 +00:00
mActor - > SendRegister ( data ) ;
2015-02-11 11:53:00 +00:00
}
2014-08-19 13:56:00 +00:00
already_AddRefed < ServiceWorkerRegistrationInfo >
ServiceWorkerManager : : GetServiceWorkerRegistrationInfo ( nsPIDOMWindow * aWindow )
2014-07-11 18:52:19 +00:00
{
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( aWindow ) ;
2014-07-21 06:25:44 +00:00
nsCOMPtr < nsIDocument > document = aWindow - > GetExtantDoc ( ) ;
2014-08-19 13:56:00 +00:00
return GetServiceWorkerRegistrationInfo ( document ) ;
2014-07-11 18:52:19 +00:00
}
2014-08-19 13:56:00 +00:00
already_AddRefed < ServiceWorkerRegistrationInfo >
ServiceWorkerManager : : GetServiceWorkerRegistrationInfo ( nsIDocument * aDoc )
2014-07-11 18:52:19 +00:00
{
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( aDoc ) ;
2014-07-11 18:52:19 +00:00
nsCOMPtr < nsIURI > documentURI = aDoc - > GetDocumentURI ( ) ;
2015-06-03 08:43:43 +00:00
nsCOMPtr < nsIPrincipal > principal = aDoc - > NodePrincipal ( ) ;
return GetServiceWorkerRegistrationInfo ( principal , documentURI ) ;
2014-07-11 18:52:19 +00:00
}
2014-08-19 13:56:00 +00:00
already_AddRefed < ServiceWorkerRegistrationInfo >
2015-06-03 08:43:43 +00:00
ServiceWorkerManager : : GetServiceWorkerRegistrationInfo ( nsIPrincipal * aPrincipal ,
nsIURI * aURI )
2014-07-11 18:52:19 +00:00
{
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( aPrincipal ) ;
MOZ_ASSERT ( aURI ) ;
2015-06-08 23:18:09 +00:00
//XXXnsm Temporary fix until Bug 1171432 is fixed.
if ( NS_WARN_IF ( BasePrincipal : : Cast ( aPrincipal ) - > AppId ( ) = = nsIScriptSecurityManager : : UNKNOWN_APP_ID ) ) {
return nullptr ;
}
2015-06-03 08:43:43 +00:00
nsAutoCString originAttributesSuffix ;
nsresult rv = PrincipalToScopeKey ( aPrincipal , originAttributesSuffix ) ;
2015-06-11 16:47:46 +00:00
if ( NS_FAILED ( rv ) ) {
2015-06-03 08:43:43 +00:00
return nullptr ;
}
return GetServiceWorkerRegistrationInfo ( originAttributesSuffix , aURI ) ;
}
already_AddRefed < ServiceWorkerRegistrationInfo >
2015-11-03 01:50:54 +00:00
ServiceWorkerManager : : GetServiceWorkerRegistrationInfo ( const PrincipalOriginAttributes & aOriginAttributes ,
2015-06-03 08:43:43 +00:00
nsIURI * aURI )
{
MOZ_ASSERT ( aURI ) ;
nsAutoCString originAttributesSuffix ;
aOriginAttributes . CreateSuffix ( originAttributesSuffix ) ;
return GetServiceWorkerRegistrationInfo ( originAttributesSuffix , aURI ) ;
}
already_AddRefed < ServiceWorkerRegistrationInfo >
ServiceWorkerManager : : GetServiceWorkerRegistrationInfo ( const nsACString & aScopeKey ,
nsIURI * aURI )
{
MOZ_ASSERT ( aURI ) ;
nsAutoCString spec ;
2014-07-14 21:15:23 +00:00
nsresult rv = aURI - > GetSpec ( spec ) ;
2014-07-11 18:52:19 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return nullptr ;
}
2015-06-03 08:43:43 +00:00
nsAutoCString scope ;
RegistrationDataPerPrincipal * data ;
if ( ! FindScopeForPath ( aScopeKey , spec , & data , scope ) ) {
2014-07-11 18:52:19 +00:00
return nullptr ;
}
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( data ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-06-03 08:43:43 +00:00
data - > mInfos . Get ( scope , getter_AddRefs ( registration ) ) ;
2014-07-11 18:52:19 +00:00
// ordered scopes and registrations better be in sync.
MOZ_ASSERT ( registration ) ;
2015-06-03 08:43:43 +00:00
# ifdef DEBUG
nsAutoCString originSuffix ;
rv = registration - > mPrincipal - > GetOriginSuffix ( originSuffix ) ;
MOZ_ASSERT ( NS_SUCCEEDED ( rv ) ) ;
MOZ_ASSERT ( originSuffix . Equals ( aScopeKey ) ) ;
# endif
2014-07-14 17:33:44 +00:00
if ( registration - > mPendingUninstall ) {
return nullptr ;
}
2014-07-28 13:57:31 +00:00
return registration . forget ( ) ;
2014-07-11 18:52:19 +00:00
}
2015-06-03 08:43:43 +00:00
/* static */ nsresult
ServiceWorkerManager : : PrincipalToScopeKey ( nsIPrincipal * aPrincipal ,
nsACString & aKey )
{
MOZ_ASSERT ( aPrincipal ) ;
2015-06-11 16:47:46 +00:00
if ( ! BasePrincipal : : Cast ( aPrincipal ) - > IsCodebasePrincipal ( ) ) {
2015-06-03 08:43:43 +00:00
return NS_ERROR_FAILURE ;
}
nsresult rv = aPrincipal - > GetOriginSuffix ( aKey ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
return NS_OK ;
}
2014-07-11 18:52:19 +00:00
/* static */ void
2015-06-03 08:43:43 +00:00
ServiceWorkerManager : : AddScopeAndRegistration ( const nsACString & aScope ,
ServiceWorkerRegistrationInfo * aInfo )
2014-07-11 18:52:19 +00:00
{
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( aInfo ) ;
MOZ_ASSERT ( aInfo - > mPrincipal ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( swm ) ;
nsAutoCString scopeKey ;
nsresult rv = swm - > PrincipalToScopeKey ( aInfo - > mPrincipal , scopeKey ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
RegistrationDataPerPrincipal * data ;
if ( ! swm - > mRegistrationInfos . Get ( scopeKey , & data ) ) {
data = new RegistrationDataPerPrincipal ( ) ;
swm - > mRegistrationInfos . Put ( scopeKey , data ) ;
}
for ( uint32_t i = 0 ; i < data - > mOrderedScopes . Length ( ) ; + + i ) {
const nsCString & current = data - > mOrderedScopes [ i ] ;
2014-07-11 18:52:19 +00:00
// Perfect match!
if ( aScope . Equals ( current ) ) {
2015-06-03 08:43:43 +00:00
data - > mInfos . Put ( aScope , aInfo ) ;
2015-11-04 14:17:02 +00:00
swm - > NotifyListenersOnRegister ( aInfo ) ;
2014-07-11 18:52:19 +00:00
return ;
}
2014-08-21 23:38:40 +00:00
// Sort by length, with longest match first.
// /foo/bar should be before /foo/
// Similarly /foo/b is between the two.
if ( StringBeginsWith ( aScope , current ) ) {
2015-06-03 08:43:43 +00:00
data - > mOrderedScopes . InsertElementAt ( i , aScope ) ;
data - > mInfos . Put ( aScope , aInfo ) ;
2015-11-04 14:17:02 +00:00
swm - > NotifyListenersOnRegister ( aInfo ) ;
2014-07-11 18:52:19 +00:00
return ;
}
}
2015-06-03 08:43:43 +00:00
data - > mOrderedScopes . AppendElement ( aScope ) ;
data - > mInfos . Put ( aScope , aInfo ) ;
2015-11-04 14:17:02 +00:00
swm - > NotifyListenersOnRegister ( aInfo ) ;
2014-07-11 18:52:19 +00:00
}
2015-06-03 08:43:43 +00:00
/* static */ bool
ServiceWorkerManager : : FindScopeForPath ( const nsACString & aScopeKey ,
const nsACString & aPath ,
RegistrationDataPerPrincipal * * aData ,
nsACString & aMatch )
2014-07-11 18:52:19 +00:00
{
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( aData ) ;
2014-07-11 18:52:19 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( swm ) ;
if ( ! swm - > mRegistrationInfos . Get ( aScopeKey , aData ) ) {
return false ;
}
for ( uint32_t i = 0 ; i < ( * aData ) - > mOrderedScopes . Length ( ) ; + + i ) {
const nsCString & current = ( * aData ) - > mOrderedScopes [ i ] ;
2014-08-21 23:38:40 +00:00
if ( StringBeginsWith ( aPath , current ) ) {
2015-06-03 08:43:43 +00:00
aMatch = current ;
return true ;
2014-07-11 18:52:19 +00:00
}
}
2015-06-03 08:43:43 +00:00
return false ;
}
/* static */ bool
ServiceWorkerManager : : HasScope ( nsIPrincipal * aPrincipal ,
const nsACString & aScope )
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( swm ) ;
nsAutoCString scopeKey ;
nsresult rv = PrincipalToScopeKey ( aPrincipal , scopeKey ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return false ;
}
RegistrationDataPerPrincipal * data ;
if ( ! swm - > mRegistrationInfos . Get ( scopeKey , & data ) ) {
return false ;
}
return data - > mOrderedScopes . Contains ( aScope ) ;
2014-07-11 18:52:19 +00:00
}
/* static */ void
2015-06-03 08:43:43 +00:00
ServiceWorkerManager : : RemoveScopeAndRegistration ( ServiceWorkerRegistrationInfo * aRegistration )
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( swm ) ;
nsAutoCString scopeKey ;
nsresult rv = swm - > PrincipalToScopeKey ( aRegistration - > mPrincipal , scopeKey ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
RegistrationDataPerPrincipal * data ;
if ( ! swm - > mRegistrationInfos . Get ( scopeKey , & data ) ) {
return ;
}
2015-12-11 19:53:10 +00:00
nsCOMPtr < nsITimer > timer = data - > mUpdateTimers . Get ( aRegistration - > mScope ) ;
if ( timer ) {
timer - > Cancel ( ) ;
data - > mUpdateTimers . Remove ( aRegistration - > mScope ) ;
}
2015-11-04 14:17:02 +00:00
RefPtr < ServiceWorkerRegistrationInfo > info ;
data - > mInfos . Get ( aRegistration - > mScope , getter_AddRefs ( info ) ) ;
2015-06-03 08:43:43 +00:00
data - > mInfos . Remove ( aRegistration - > mScope ) ;
data - > mOrderedScopes . RemoveElement ( aRegistration - > mScope ) ;
2015-11-04 14:17:02 +00:00
swm - > NotifyListenersOnUnregister ( info ) ;
2015-06-03 08:43:43 +00:00
swm - > MaybeRemoveRegistrationInfo ( scopeKey ) ;
2015-11-23 18:38:08 +00:00
swm - > NotifyServiceWorkerRegistrationRemoved ( aRegistration ) ;
2015-06-03 08:43:43 +00:00
}
void
ServiceWorkerManager : : MaybeRemoveRegistrationInfo ( const nsACString & aScopeKey )
2014-07-11 18:52:19 +00:00
{
2015-06-03 08:43:43 +00:00
RegistrationDataPerPrincipal * data ;
if ( ! mRegistrationInfos . Get ( aScopeKey , & data ) ) {
return ;
}
if ( data - > mOrderedScopes . IsEmpty ( ) & & data - > mJobQueues . Count ( ) = = 0 ) {
mRegistrationInfos . Remove ( aScopeKey ) ;
}
2014-07-11 18:52:19 +00:00
}
2014-07-21 06:25:44 +00:00
void
2015-11-25 23:03:59 +00:00
ServiceWorkerManager : : MaybeStartControlling ( nsIDocument * aDoc ,
const nsAString & aDocumentId )
2014-07-21 06:25:44 +00:00
{
AssertIsOnMainThread ( ) ;
2015-05-14 19:41:42 +00:00
// We keep a set of documents that service workers may choose to start
// controlling using claim().
MOZ_ASSERT ( ! mAllDocuments . Contains ( aDoc ) ) ;
mAllDocuments . PutEntry ( aDoc ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2014-08-19 13:56:00 +00:00
GetServiceWorkerRegistrationInfo ( aDoc ) ;
2014-12-19 10:00:29 +00:00
if ( registration ) {
2015-02-09 04:33:39 +00:00
MOZ_ASSERT ( ! mControlledDocuments . Contains ( aDoc ) ) ;
2015-11-25 23:03:59 +00:00
StartControllingADocument ( registration , aDoc , aDocumentId ) ;
2014-07-21 06:25:44 +00:00
}
}
void
ServiceWorkerManager : : MaybeStopControlling ( nsIDocument * aDoc )
{
MOZ_ASSERT ( aDoc ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-02-09 04:33:39 +00:00
mControlledDocuments . Remove ( aDoc , getter_AddRefs ( registration ) ) ;
2014-07-21 06:25:44 +00:00
// A document which was uncontrolled does not maintain that state itself, so
// it will always call MaybeStopControlling() even if there isn't an
// associated registration. So this check is required.
if ( registration ) {
2015-05-14 19:41:42 +00:00
StopControllingADocument ( registration ) ;
}
2015-09-25 02:05:16 +00:00
mAllDocuments . RemoveEntry ( aDoc ) ;
2015-05-14 19:41:42 +00:00
}
2015-12-11 19:53:11 +00:00
void
ServiceWorkerManager : : MaybeCheckNavigationUpdate ( nsIDocument * aDoc )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aDoc ) ;
// We perform these success path navigation update steps when the
// document tells us its more or less done loading. This avoids
// slowing down page load and also lets pages consistently get
// updatefound events when they fire.
//
// 9.8.20 If respondWithEntered is false, then:
// 9.8.22 Else: (respondWith was entered and succeeded)
// If request is a non-subresource request, then: Invoke Soft Update
// algorithm.
RefPtr < ServiceWorkerRegistrationInfo > registration ;
mControlledDocuments . Get ( aDoc , getter_AddRefs ( registration ) ) ;
if ( registration ) {
registration - > MaybeScheduleUpdate ( ) ;
}
}
2015-05-14 19:41:42 +00:00
void
ServiceWorkerManager : : StartControllingADocument ( ServiceWorkerRegistrationInfo * aRegistration ,
2015-11-25 23:03:59 +00:00
nsIDocument * aDoc ,
const nsAString & aDocumentId )
2015-05-14 19:41:42 +00:00
{
MOZ_ASSERT ( aRegistration ) ;
MOZ_ASSERT ( aDoc ) ;
aRegistration - > StartControllingADocument ( ) ;
mControlledDocuments . Put ( aDoc , aRegistration ) ;
2015-11-25 23:03:59 +00:00
if ( ! aDocumentId . IsEmpty ( ) ) {
aDoc - > SetId ( aDocumentId ) ;
}
2015-06-05 06:11:18 +00:00
Telemetry : : Accumulate ( Telemetry : : SERVICE_WORKER_CONTROLLED_DOCUMENTS , 1 ) ;
2015-05-14 19:41:42 +00:00
}
void
ServiceWorkerManager : : StopControllingADocument ( ServiceWorkerRegistrationInfo * aRegistration )
{
aRegistration - > StopControllingADocument ( ) ;
if ( ! aRegistration - > IsControllingDocuments ( ) ) {
if ( aRegistration - > mPendingUninstall ) {
aRegistration - > Clear ( ) ;
RemoveRegistration ( aRegistration ) ;
} else {
2015-09-30 23:11:03 +00:00
// If the registration has an active worker that is running
// this might be a good time to stop it.
if ( aRegistration - > mActiveWorker ) {
ServiceWorkerPrivate * serviceWorkerPrivate =
aRegistration - > mActiveWorker - > WorkerPrivate ( ) ;
serviceWorkerPrivate - > NoteStoppedControllingDocuments ( ) ;
}
2015-05-14 19:41:42 +00:00
aRegistration - > TryToActivate ( ) ;
2014-10-24 22:11:26 +00:00
}
2014-07-21 06:25:44 +00:00
}
}
2014-07-11 18:52:19 +00:00
NS_IMETHODIMP
2015-06-03 08:43:43 +00:00
ServiceWorkerManager : : GetScopeForUrl ( nsIPrincipal * aPrincipal ,
const nsAString & aUrl , nsAString & aScope )
2014-07-11 18:52:19 +00:00
{
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( aPrincipal ) ;
2014-07-11 18:52:19 +00:00
nsCOMPtr < nsIURI > uri ;
nsresult rv = NS_NewURI ( getter_AddRefs ( uri ) , aUrl , nullptr , nullptr ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return NS_ERROR_FAILURE ;
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > r =
2015-06-03 08:43:43 +00:00
GetServiceWorkerRegistrationInfo ( aPrincipal , uri ) ;
2014-07-11 18:52:19 +00:00
if ( ! r ) {
return NS_ERROR_FAILURE ;
}
aScope = NS_ConvertUTF8toUTF16 ( r - > mScope ) ;
return NS_OK ;
}
2014-07-11 20:07:59 +00:00
2014-07-14 21:15:23 +00:00
NS_IMETHODIMP
2015-04-08 20:13:32 +00:00
ServiceWorkerManager : : AddRegistrationEventListener ( const nsAString & aScope ,
ServiceWorkerRegistrationListener * aListener )
2014-07-14 21:15:23 +00:00
{
2014-08-27 20:33:20 +00:00
AssertIsOnMainThread ( ) ;
2015-04-08 20:13:32 +00:00
MOZ_ASSERT ( aListener ) ;
2014-10-27 18:52:57 +00:00
# ifdef DEBUG
// Ensure a registration is only listening for it's own scope.
nsAutoString regScope ;
2015-04-08 20:13:32 +00:00
aListener - > GetScope ( regScope ) ;
2014-10-27 18:52:57 +00:00
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
2015-04-08 20:13:32 +00:00
MOZ_ASSERT ( aScope . Equals ( regScope ) ) ;
2014-10-27 18:52:57 +00:00
# endif
2015-04-08 20:13:32 +00:00
MOZ_ASSERT ( ! mServiceWorkerRegistrationListeners . Contains ( aListener ) ) ;
mServiceWorkerRegistrationListeners . AppendElement ( aListener ) ;
2014-07-14 21:15:23 +00:00
return NS_OK ;
}
NS_IMETHODIMP
2015-04-08 20:13:32 +00:00
ServiceWorkerManager : : RemoveRegistrationEventListener ( const nsAString & aScope ,
ServiceWorkerRegistrationListener * aListener )
2014-07-14 21:15:23 +00:00
{
2014-08-27 20:33:20 +00:00
AssertIsOnMainThread ( ) ;
2015-04-08 20:13:32 +00:00
MOZ_ASSERT ( aListener ) ;
2014-10-27 18:52:57 +00:00
# ifdef DEBUG
// Ensure a registration is unregistering for it's own scope.
nsAutoString regScope ;
2015-04-08 20:13:32 +00:00
aListener - > GetScope ( regScope ) ;
2014-10-27 18:52:57 +00:00
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
2015-04-08 20:13:32 +00:00
MOZ_ASSERT ( aScope . Equals ( regScope ) ) ;
2014-10-27 18:52:57 +00:00
# endif
2015-04-08 20:13:32 +00:00
MOZ_ASSERT ( mServiceWorkerRegistrationListeners . Contains ( aListener ) ) ;
mServiceWorkerRegistrationListeners . RemoveElement ( aListener ) ;
2014-07-14 21:15:23 +00:00
return NS_OK ;
}
void
2015-04-08 20:13:32 +00:00
ServiceWorkerManager : : FireUpdateFoundOnServiceWorkerRegistrations (
ServiceWorkerRegistrationInfo * aRegistration )
2014-07-14 21:15:23 +00:00
{
AssertIsOnMainThread ( ) ;
2015-02-09 04:33:39 +00:00
2015-04-08 20:13:32 +00:00
nsTObserverArray < ServiceWorkerRegistrationListener * > : : ForwardIterator it ( mServiceWorkerRegistrationListeners ) ;
2015-02-09 04:33:39 +00:00
while ( it . HasMore ( ) ) {
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationListener > target = it . GetNext ( ) ;
2015-02-09 04:33:39 +00:00
nsAutoString regScope ;
target - > GetScope ( regScope ) ;
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
NS_ConvertUTF16toUTF8 utf8Scope ( regScope ) ;
if ( utf8Scope . Equals ( aRegistration - > mScope ) ) {
2015-04-08 20:13:32 +00:00
target - > UpdateFound ( ) ;
2014-07-14 21:15:23 +00:00
}
}
}
2014-07-23 21:05:08 +00:00
/*
2014-08-25 05:35:03 +00:00
* This is used for installing , waiting and active .
2014-07-23 21:05:08 +00:00
*/
NS_IMETHODIMP
2014-08-25 05:35:03 +00:00
ServiceWorkerManager : : GetServiceWorkerForScope ( nsIDOMWindow * aWindow ,
const nsAString & aScope ,
WhichServiceWorker aWhichWorker ,
nsISupports * * aServiceWorker )
2014-07-23 21:05:08 +00:00
{
2014-08-25 05:35:03 +00:00
AssertIsOnMainThread ( ) ;
2014-07-23 21:05:08 +00:00
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
2015-02-19 16:40:21 +00:00
if ( NS_WARN_IF ( ! window ) ) {
2015-11-05 17:33:33 +00:00
return NS_ERROR_DOM_INVALID_STATE_ERR ;
2014-08-25 05:35:03 +00:00
}
2014-07-23 21:05:08 +00:00
2014-08-25 05:35:03 +00:00
nsCOMPtr < nsIDocument > doc = window - > GetExtantDoc ( ) ;
MOZ_ASSERT ( doc ) ;
///////////////////////////////////////////
// Security check
2014-10-27 18:52:57 +00:00
nsAutoCString scope = NS_ConvertUTF16toUTF8 ( aScope ) ;
2014-08-25 05:35:03 +00: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-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2015-06-03 08:43:43 +00:00
GetRegistration ( documentPrincipal , scope ) ;
2015-02-19 16:40:21 +00:00
if ( NS_WARN_IF ( ! registration ) ) {
2014-07-23 21:05:08 +00:00
return NS_ERROR_FAILURE ;
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerInfo > info ;
2014-07-23 21:05:08 +00:00
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 10:00:29 +00:00
info = registration - > mActiveWorker ;
2014-07-23 21:05:08 +00:00
} else {
MOZ_CRASH ( " Invalid worker type " ) ;
}
2015-02-19 16:40:21 +00:00
if ( NS_WARN_IF ( ! info ) ) {
2014-07-23 21:05:08 +00:00
return NS_ERROR_DOM_NOT_FOUND_ERR ;
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorker > serviceWorker = new ServiceWorker ( window , info ) ;
2014-07-23 21:05:08 +00:00
2014-12-19 11:25:56 +00:00
serviceWorker - > SetState ( info - > State ( ) ) ;
2014-07-23 21:05:08 +00:00
serviceWorker . forget ( aServiceWorker ) ;
return NS_OK ;
}
2015-09-15 17:15:45 +00:00
namespace {
class ContinueDispatchFetchEventRunnable : public nsRunnable
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerPrivate > mServiceWorkerPrivate ;
2015-09-30 23:11:03 +00:00
nsCOMPtr < nsIInterceptedChannel > mChannel ;
nsCOMPtr < nsILoadGroup > mLoadGroup ;
2015-11-25 23:05:34 +00:00
nsString mDocumentId ;
2015-09-15 17:15:45 +00:00
bool mIsReload ;
public :
2015-09-30 23:11:03 +00:00
ContinueDispatchFetchEventRunnable ( ServiceWorkerPrivate * aServiceWorkerPrivate ,
nsIInterceptedChannel * aChannel ,
nsILoadGroup * aLoadGroup ,
2015-11-25 23:05:34 +00:00
const nsAString & aDocumentId ,
2015-09-15 17:15:45 +00:00
bool aIsReload )
2015-09-30 23:11:03 +00:00
: mServiceWorkerPrivate ( aServiceWorkerPrivate )
2015-09-15 17:15:45 +00:00
, mChannel ( aChannel )
2015-09-30 23:11:03 +00:00
, mLoadGroup ( aLoadGroup )
2015-11-25 23:05:34 +00:00
, mDocumentId ( aDocumentId )
2015-09-15 17:15:45 +00:00
, mIsReload ( aIsReload )
{
2015-09-30 23:11:03 +00:00
MOZ_ASSERT ( aServiceWorkerPrivate ) ;
MOZ_ASSERT ( aChannel ) ;
2015-09-15 17:15:45 +00:00
}
void
HandleError ( )
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-09-15 17:15:45 +00:00
NS_WARNING ( " Unexpected error while dispatching fetch event! " ) ;
DebugOnly < nsresult > rv = mChannel - > ResetInterception ( ) ;
NS_WARN_IF_FALSE ( NS_SUCCEEDED ( rv ) , " Failed to resume intercepted network request " ) ;
}
NS_IMETHOD
Run ( ) override
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-09-15 17:15:45 +00:00
nsCOMPtr < nsIChannel > channel ;
nsresult rv = mChannel - > GetChannel ( getter_AddRefs ( channel ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
HandleError ( ) ;
return NS_OK ;
}
// The channel might have encountered an unexpected error while ensuring
// the upload stream is cloneable. Check here and reset the interception
// if that happens.
nsresult status ;
rv = channel - > GetStatus ( & status ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) | | NS_FAILED ( status ) ) ) {
HandleError ( ) ;
return NS_OK ;
}
2015-09-30 23:11:03 +00:00
rv = mServiceWorkerPrivate - > SendFetchEvent ( mChannel , mLoadGroup ,
2015-11-25 23:05:34 +00:00
mDocumentId , mIsReload ) ;
2015-09-15 17:15:45 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
HandleError ( ) ;
}
return NS_OK ;
}
} ;
} // anonymous namespace
2015-09-21 21:10:37 +00:00
already_AddRefed < nsIRunnable >
2015-11-03 01:50:54 +00:00
ServiceWorkerManager : : PrepareFetchEvent ( const PrincipalOriginAttributes & aOriginAttributes ,
2015-09-21 21:10:37 +00:00
nsIDocument * aDoc ,
2015-11-25 23:05:34 +00:00
const nsAString & aDocumentIdForTopLevelNavigation ,
2015-09-21 21:10:37 +00:00
nsIInterceptedChannel * aChannel ,
bool aIsReload ,
2015-09-17 18:56:41 +00:00
bool aIsSubresourceLoad ,
2015-09-21 21:10:37 +00:00
ErrorResult & aRv )
2015-02-19 01:34:29 +00:00
{
MOZ_ASSERT ( aChannel ) ;
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-09-21 21:10:37 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerInfo > serviceWorker ;
2015-09-30 23:11:03 +00:00
nsCOMPtr < nsILoadGroup > loadGroup ;
2015-11-25 23:05:34 +00:00
nsAutoString documentId ;
2015-03-06 13:04:49 +00:00
2015-09-17 18:56:41 +00:00
if ( aIsSubresourceLoad ) {
2015-02-19 01:34:29 +00:00
MOZ_ASSERT ( aDoc ) ;
2015-09-30 23:11:03 +00:00
serviceWorker = GetActiveWorkerInfoForDocument ( aDoc ) ;
loadGroup = aDoc - > GetDocumentLoadGroup ( ) ;
2015-11-25 23:05:34 +00:00
nsresult rv = aDoc - > GetOrCreateId ( documentId ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return nullptr ;
}
2015-02-19 01:34:29 +00:00
} else {
nsCOMPtr < nsIChannel > internalChannel ;
2015-06-03 08:43:43 +00:00
aRv = aChannel - > GetChannel ( getter_AddRefs ( internalChannel ) ) ;
if ( NS_WARN_IF ( aRv . Failed ( ) ) ) {
2015-09-21 21:10:37 +00:00
return nullptr ;
2015-06-03 08:43:43 +00:00
}
2015-02-19 01:34:29 +00:00
2015-09-30 23:11:03 +00:00
internalChannel - > GetLoadGroup ( getter_AddRefs ( loadGroup ) ) ;
2015-11-25 23:05:34 +00:00
documentId = aDocumentIdForTopLevelNavigation ;
2015-02-19 01:34:29 +00:00
nsCOMPtr < nsIURI > uri ;
2015-11-14 18:09:58 +00:00
aRv = internalChannel - > GetURI ( getter_AddRefs ( uri ) ) ;
2015-06-03 08:43:43 +00:00
if ( NS_WARN_IF ( aRv . Failed ( ) ) ) {
2015-09-21 21:10:37 +00:00
return nullptr ;
2015-06-03 08:43:43 +00:00
}
2015-02-19 01:34:29 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2015-06-03 08:43:43 +00:00
GetServiceWorkerRegistrationInfo ( aOriginAttributes , uri ) ;
2015-03-29 01:05:11 +00:00
if ( ! registration ) {
NS_WARNING ( " No registration found when dispatching the fetch event " ) ;
2015-06-03 08:43:43 +00:00
aRv . Throw ( NS_ERROR_FAILURE ) ;
2015-09-21 21:10:37 +00:00
return nullptr ;
2015-03-29 01:05:11 +00:00
}
2015-06-03 08:43:43 +00:00
// This should only happen if IsAvailable() returned true.
2015-02-19 01:34:29 +00:00
MOZ_ASSERT ( registration - > mActiveWorker ) ;
2015-09-30 23:11:03 +00:00
serviceWorker = registration - > mActiveWorker ;
2015-11-16 16:04:11 +00:00
AddNavigationInterception ( serviceWorker - > Scope ( ) , aChannel ) ;
2015-02-19 01:34:29 +00:00
}
2015-09-30 23:11:03 +00:00
if ( NS_WARN_IF ( aRv . Failed ( ) ) | | ! serviceWorker ) {
2015-09-21 21:10:37 +00:00
return nullptr ;
2015-02-19 01:34:29 +00:00
}
2015-09-15 17:15:45 +00:00
nsCOMPtr < nsIRunnable > continueRunnable =
2015-09-30 23:11:03 +00:00
new ContinueDispatchFetchEventRunnable ( serviceWorker - > WorkerPrivate ( ) ,
aChannel , loadGroup ,
2015-11-25 23:05:34 +00:00
documentId , aIsReload ) ;
2015-09-15 17:15:45 +00:00
2015-09-21 21:10:37 +00:00
return continueRunnable . forget ( ) ;
}
void
ServiceWorkerManager : : DispatchPreparedFetchEvent ( nsIInterceptedChannel * aChannel ,
nsIRunnable * aPreparedRunnable ,
ErrorResult & aRv )
{
MOZ_ASSERT ( aChannel ) ;
MOZ_ASSERT ( aPreparedRunnable ) ;
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-09-21 21:10:37 +00:00
2015-09-15 17:15:45 +00:00
nsCOMPtr < nsIChannel > innerChannel ;
aRv = aChannel - > GetChannel ( getter_AddRefs ( innerChannel ) ) ;
2015-06-03 08:43:43 +00:00
if ( NS_WARN_IF ( aRv . Failed ( ) ) ) {
return ;
}
2015-02-19 01:34:29 +00:00
2015-09-15 17:15:45 +00:00
nsCOMPtr < nsIUploadChannel2 > uploadChannel = do_QueryInterface ( innerChannel ) ;
// If there is no upload stream, then continue immediately
if ( ! uploadChannel ) {
2015-09-21 21:10:37 +00:00
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( aPreparedRunnable - > Run ( ) ) ) ;
2015-06-03 08:43:43 +00:00
return ;
2015-02-19 01:34:29 +00:00
}
2015-09-15 17:15:45 +00:00
// Otherwise, ensure the upload stream can be cloned directly. This may
// require some async copying, so provide a callback.
2015-09-21 21:10:37 +00:00
aRv = uploadChannel - > EnsureUploadStreamIsCloneable ( aPreparedRunnable ) ;
2015-02-19 01:34:29 +00:00
}
2015-06-03 08:43:43 +00:00
bool
2015-11-03 01:50:54 +00:00
ServiceWorkerManager : : IsAvailable ( const PrincipalOriginAttributes & aOriginAttributes ,
2015-06-26 18:18:18 +00:00
nsIURI * aURI )
2015-02-19 01:34:29 +00:00
{
MOZ_ASSERT ( aURI ) ;
2015-06-03 08:43:43 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2015-06-03 08:43:43 +00:00
GetServiceWorkerRegistrationInfo ( aOriginAttributes , aURI ) ;
return registration & & registration - > mActiveWorker ;
2015-02-19 01:34:29 +00:00
}
2015-06-03 08:43:43 +00:00
bool
ServiceWorkerManager : : IsControlled ( nsIDocument * aDoc , ErrorResult & aRv )
2015-02-19 01:34:29 +00:00
{
MOZ_ASSERT ( aDoc ) ;
2015-06-03 08:43:43 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-02-19 01:34:29 +00:00
nsresult rv = GetDocumentRegistration ( aDoc , getter_AddRefs ( registration ) ) ;
2015-03-18 13:16:00 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) & & rv ! = NS_ERROR_NOT_AVAILABLE ) ) {
// It's OK to ignore the case where we don't have a registration.
2015-06-03 08:43:43 +00:00
aRv . Throw ( rv ) ;
return false ;
2015-03-18 13:16:00 +00:00
}
2015-06-03 08:43:43 +00:00
2015-10-27 18:10:39 +00:00
MOZ_ASSERT_IF ( ! ! registration , ! nsContentUtils : : IsInPrivateBrowsing ( aDoc ) ) ;
2015-06-03 08:43:43 +00:00
return ! ! registration ;
2015-02-19 01:34:29 +00:00
}
nsresult
ServiceWorkerManager : : GetDocumentRegistration ( nsIDocument * aDoc ,
ServiceWorkerRegistrationInfo * * aRegistrationInfo )
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-02-19 01:34:29 +00:00
if ( ! mControlledDocuments . Get ( aDoc , getter_AddRefs ( registration ) ) ) {
2015-03-18 13:16:00 +00:00
return NS_ERROR_NOT_AVAILABLE ;
2015-02-19 01:34:29 +00:00
}
// If the document is controlled, the current worker MUST be non-null.
if ( ! registration - > mActiveWorker ) {
return NS_ERROR_NOT_AVAILABLE ;
}
registration . forget ( aRegistrationInfo ) ;
return NS_OK ;
}
2014-07-23 21:05:08 +00:00
/*
* The . controller is for the registration associated with the document when
* the document was loaded .
*/
NS_IMETHODIMP
2015-07-15 19:21:40 +00:00
ServiceWorkerManager : : GetDocumentController ( nsIDOMWindow * aWindow ,
nsISupports * * aServiceWorker )
2014-07-23 21:05:08 +00:00
{
nsCOMPtr < nsPIDOMWindow > window = do_QueryInterface ( aWindow ) ;
MOZ_ASSERT ( window ) ;
if ( ! window | | ! window - > GetExtantDoc ( ) ) {
2015-11-05 17:33:33 +00:00
return NS_ERROR_DOM_INVALID_STATE_ERR ;
2014-07-23 21:05:08 +00:00
}
nsCOMPtr < nsIDocument > doc = window - > GetExtantDoc ( ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration ;
2015-02-19 01:34:29 +00:00
nsresult rv = GetDocumentRegistration ( doc , getter_AddRefs ( registration ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
2015-02-18 21:00:33 +00:00
}
2015-09-30 23:11:03 +00:00
MOZ_ASSERT ( registration - > mActiveWorker ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorker > serviceWorker =
2015-09-30 23:11:03 +00:00
new ServiceWorker ( window , registration - > mActiveWorker ) ;
2014-07-23 21:05:08 +00:00
serviceWorker . forget ( aServiceWorker ) ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerManager : : GetInstalling ( nsIDOMWindow * aWindow ,
2014-08-25 05:35:03 +00:00
const nsAString & aScope ,
2014-07-23 21:05:08 +00:00
nsISupports * * aServiceWorker )
{
2014-08-25 05:35:03 +00:00
return GetServiceWorkerForScope ( aWindow , aScope ,
WhichServiceWorker : : INSTALLING_WORKER ,
aServiceWorker ) ;
2014-07-23 21:05:08 +00:00
}
NS_IMETHODIMP
ServiceWorkerManager : : GetWaiting ( nsIDOMWindow * aWindow ,
2014-08-25 05:35:03 +00:00
const nsAString & aScope ,
2014-07-23 21:05:08 +00:00
nsISupports * * aServiceWorker )
{
2014-08-25 05:35:03 +00:00
return GetServiceWorkerForScope ( aWindow , aScope ,
WhichServiceWorker : : WAITING_WORKER ,
aServiceWorker ) ;
2014-07-23 21:05:08 +00:00
}
NS_IMETHODIMP
2014-08-25 05:35:03 +00:00
ServiceWorkerManager : : GetActive ( nsIDOMWindow * aWindow ,
const nsAString & aScope ,
nsISupports * * aServiceWorker )
2014-07-23 21:05:08 +00:00
{
2014-08-25 05:35:03 +00:00
return GetServiceWorkerForScope ( aWindow , aScope ,
WhichServiceWorker : : ACTIVE_WORKER ,
aServiceWorker ) ;
2014-07-23 21:05:08 +00:00
}
void
2014-08-19 13:56:00 +00:00
ServiceWorkerManager : : InvalidateServiceWorkerRegistrationWorker ( ServiceWorkerRegistrationInfo * aRegistration ,
WhichServiceWorker aWhichOnes )
2014-07-23 21:05:08 +00:00
{
AssertIsOnMainThread ( ) ;
2015-04-08 20:13:32 +00:00
nsTObserverArray < ServiceWorkerRegistrationListener * > : : ForwardIterator it ( mServiceWorkerRegistrationListeners ) ;
2015-02-09 04:33:39 +00:00
while ( it . HasMore ( ) ) {
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationListener > target = it . GetNext ( ) ;
2015-02-09 04:33:39 +00:00
nsAutoString regScope ;
target - > GetScope ( regScope ) ;
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
2014-07-23 21:05:08 +00:00
2015-02-09 04:33:39 +00:00
NS_ConvertUTF16toUTF8 utf8Scope ( regScope ) ;
2014-07-23 21:05:08 +00:00
2015-02-09 04:33:39 +00:00
if ( utf8Scope . Equals ( aRegistration - > mScope ) ) {
2015-04-08 20:13:32 +00:00
target - > InvalidateWorkers ( aWhichOnes ) ;
2014-07-23 21:05:08 +00:00
}
}
}
2015-11-23 18:38:08 +00:00
void
ServiceWorkerManager : : NotifyServiceWorkerRegistrationRemoved ( ServiceWorkerRegistrationInfo * aRegistration )
{
AssertIsOnMainThread ( ) ;
nsTObserverArray < ServiceWorkerRegistrationListener * > : : ForwardIterator it ( mServiceWorkerRegistrationListeners ) ;
while ( it . HasMore ( ) ) {
RefPtr < ServiceWorkerRegistrationListener > target = it . GetNext ( ) ;
nsAutoString regScope ;
target - > GetScope ( regScope ) ;
MOZ_ASSERT ( ! regScope . IsEmpty ( ) ) ;
NS_ConvertUTF16toUTF8 utf8Scope ( regScope ) ;
if ( utf8Scope . Equals ( aRegistration - > mScope ) ) {
target - > RegistrationRemoved ( ) ;
}
}
}
2015-06-03 08:43:43 +00:00
void
2015-11-26 17:03:10 +00:00
ServiceWorkerManager : : SoftUpdate ( const OriginAttributes & aOriginAttributes ,
const nsACString & aScope )
2015-06-03 08:43:43 +00:00
{
2015-11-26 17:03:10 +00:00
AssertIsOnMainThread ( ) ;
2015-06-03 08:43:43 +00:00
nsAutoCString scopeKey ;
2015-11-26 17:03:10 +00:00
aOriginAttributes . CreateSuffix ( scopeKey ) ;
RefPtr < ServiceWorkerRegistrationInfo > registration =
GetRegistration ( scopeKey , aScope ) ;
if ( NS_WARN_IF ( ! registration ) ) {
2015-06-03 08:43:43 +00:00
return ;
}
2015-11-26 17:03:10 +00:00
// "If registration's uninstalling flag is set, abort these steps."
if ( registration - > mPendingUninstall ) {
return ;
}
2015-06-03 08:43:43 +00:00
2015-11-26 17:03:10 +00:00
// "If registration's installing worker is not null, abort these steps."
if ( registration - > mInstallingWorker ) {
return ;
}
2015-06-04 18:51:57 +00:00
2015-11-26 17:03:10 +00:00
// "Let newestWorker be the result of running Get Newest Worker algorithm
// passing registration as its argument.
// If newestWorker is null, abort these steps."
RefPtr < ServiceWorkerInfo > newest = registration - > Newest ( ) ;
if ( ! newest ) {
return ;
}
2015-11-16 16:04:11 +00:00
2015-11-26 17:03:10 +00:00
// "If the registration queue for registration is empty, invoke Update algorithm,
// or its equivalent, with client, registration as its argument."
// TODO(catalinb): We don't implement the force bypass cache flag.
// See: https://github.com/slightlyoff/ServiceWorker/issues/759
if ( ! registration - > mUpdating ) {
ServiceWorkerJobQueue * queue = GetOrCreateJobQueue ( scopeKey , aScope ) ;
MOZ_ASSERT ( queue ) ;
2015-11-16 16:04:11 +00:00
2015-11-26 17:03:10 +00:00
RefPtr < ServiceWorkerRegisterJob > job =
2015-12-11 19:53:10 +00:00
new ServiceWorkerRegisterJob ( queue , registration , nullptr ,
newest - > ScriptSpec ( ) ) ;
2015-11-26 17:03:10 +00:00
queue - > Append ( job ) ;
}
}
2015-11-16 16:04:11 +00:00
2015-06-03 08:43:43 +00:00
void
2015-11-26 17:03:10 +00:00
ServiceWorkerManager : : Update ( nsIPrincipal * aPrincipal ,
const nsACString & aScope ,
ServiceWorkerUpdateFinishCallback * aCallback )
2015-06-03 08:43:43 +00:00
{
2015-11-26 17:03:10 +00:00
MOZ_ASSERT ( aPrincipal ) ;
MOZ_ASSERT ( aCallback ) ;
nsAutoCString scopeKey ;
nsresult rv = PrincipalToScopeKey ( aPrincipal , scopeKey ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2015-11-26 17:03:10 +00:00
GetRegistration ( scopeKey , aScope ) ;
2014-10-06 15:45:14 +00:00
if ( NS_WARN_IF ( ! registration ) ) {
2015-06-03 08:43:43 +00:00
return ;
2014-10-06 15:45:14 +00:00
}
2015-03-20 01:09:10 +00:00
// "If registration's uninstalling flag is set, abort these steps."
2014-10-06 15:45:14 +00:00
if ( registration - > mPendingUninstall ) {
2015-06-03 08:43:43 +00:00
return ;
2014-10-06 15:45:14 +00:00
}
2015-03-20 01:09:10 +00:00
// "Let newestWorker be the result of running Get Newest Worker algorithm
// passing registration as its argument.
2015-11-26 17:03:10 +00:00
// If newestWorker is null, return a promise rejected with "InvalidStateError"
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerInfo > newest = registration - > Newest ( ) ;
2015-03-20 01:09:10 +00:00
if ( ! newest ) {
2015-11-26 17:03:10 +00:00
ErrorResult error ( NS_ERROR_DOM_INVALID_STATE_ERR ) ;
aCallback - > UpdateFailed ( error ) ;
// In case the callback does not consume the exception
error . SuppressException ( ) ;
2015-06-03 08:43:43 +00:00
return ;
2015-03-20 01:09:10 +00:00
}
2015-06-03 08:43:43 +00:00
ServiceWorkerJobQueue * queue =
2015-11-26 17:03:10 +00:00
GetOrCreateJobQueue ( scopeKey , aScope ) ;
2014-12-19 10:00:29 +00:00
MOZ_ASSERT ( queue ) ;
2015-03-20 01:09:10 +00:00
// "Invoke Update algorithm, or its equivalent, with client, registration as
// its argument."
2015-11-26 17:03:10 +00:00
RefPtr < ServiceWorkerRegisterJob > job =
2015-12-11 19:53:10 +00:00
new ServiceWorkerRegisterJob ( queue , registration , aCallback ,
newest - > ScriptSpec ( ) ) ;
2015-11-26 17:03:10 +00:00
queue - > Append ( job ) ;
2014-10-06 15:45:14 +00:00
}
2014-10-27 11:03:00 +00:00
namespace {
2015-05-14 19:41:42 +00:00
static void
FireControllerChangeOnDocument ( nsIDocument * aDocument )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aDocument ) ;
nsCOMPtr < nsPIDOMWindow > w = aDocument - > GetWindow ( ) ;
2015-11-16 16:41:57 +00:00
if ( ! w ) {
NS_WARNING ( " Failed to dispatch controllerchange event " ) ;
return ;
}
2015-07-17 05:10:35 +00:00
w = w - > GetCurrentInnerWindow ( ) ;
2015-11-16 16:41:57 +00:00
if ( ! w ) {
NS_WARNING ( " Failed to dispatch controllerchange event " ) ;
return ;
}
2015-05-14 19:41:42 +00:00
auto * window = static_cast < nsGlobalWindow * > ( w . get ( ) ) ;
ErrorResult result ;
dom : : Navigator * navigator = window - > GetNavigator ( result ) ;
if ( NS_WARN_IF ( result . Failed ( ) ) ) {
2015-07-10 20:56:06 +00:00
result . SuppressException ( ) ;
2015-05-14 19:41:42 +00:00
return ;
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerContainer > container = navigator - > ServiceWorker ( ) ;
2015-05-14 19:41:42 +00:00
container - > ControllerChanged ( result ) ;
if ( result . Failed ( ) ) {
NS_WARNING ( " Failed to dispatch controllerchange event " ) ;
}
}
2015-07-13 15:37:28 +00:00
} // anonymous namespace
2014-10-27 11:03:00 +00:00
2015-11-27 22:27:53 +00:00
UniquePtr < ServiceWorkerClientInfo >
ServiceWorkerManager : : GetClient ( nsIPrincipal * aPrincipal ,
const nsAString & aClientId ,
ErrorResult & aRv )
{
UniquePtr < ServiceWorkerClientInfo > clientInfo ;
nsCOMPtr < nsISupportsInterfacePointer > ifptr =
do_CreateInstance ( NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID ) ;
if ( NS_WARN_IF ( ! ifptr ) ) {
return clientInfo ;
}
nsCOMPtr < nsIObserverService > obs = mozilla : : services : : GetObserverService ( ) ;
if ( NS_WARN_IF ( ! obs ) ) {
return clientInfo ;
}
nsresult rv = obs - > NotifyObservers ( ifptr , " service-worker-get-client " ,
PromiseFlatString ( aClientId ) . get ( ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return clientInfo ;
}
nsCOMPtr < nsISupports > ptr ;
ifptr - > GetData ( getter_AddRefs ( ptr ) ) ;
nsCOMPtr < nsIDocument > doc = do_QueryInterface ( ptr ) ;
if ( NS_WARN_IF ( ! doc ) ) {
return clientInfo ;
}
bool equals = false ;
aPrincipal - > Equals ( doc - > NodePrincipal ( ) , & equals ) ;
if ( ! equals ) {
return clientInfo ;
}
if ( ! IsFromAuthenticatedOrigin ( doc ) ) {
aRv . Throw ( NS_ERROR_DOM_SECURITY_ERR ) ;
return clientInfo ;
}
clientInfo . reset ( new ServiceWorkerClientInfo ( doc ) ) ;
return clientInfo ;
}
2014-10-27 11:03:00 +00:00
void
2015-06-03 08:43:43 +00:00
ServiceWorkerManager : : GetAllClients ( nsIPrincipal * aPrincipal ,
const nsCString & aScope ,
2015-11-30 19:29:51 +00:00
bool aIncludeUncontrolled ,
nsTArray < ServiceWorkerClientInfo > & aDocuments )
2014-10-27 11:03:00 +00:00
{
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( aPrincipal ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2015-06-03 08:43:43 +00:00
GetRegistration ( aPrincipal , aScope ) ;
2014-11-04 12:04:00 +00:00
if ( ! registration ) {
// The registration was removed, leave the array empty.
return ;
}
2015-11-30 19:29:51 +00:00
nsCOMPtr < nsIObserverService > obs = mozilla : : services : : GetObserverService ( ) ;
if ( NS_WARN_IF ( ! obs ) ) {
return ;
}
nsCOMPtr < nsISimpleEnumerator > enumerator ;
nsresult rv = obs - > EnumerateObservers ( " service-worker-get-client " ,
getter_AddRefs ( enumerator ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
auto ProcessDocument = [ & aDocuments ] ( nsIPrincipal * aPrincipal , nsIDocument * aDoc ) {
if ( ! aDoc | | ! aDoc - > GetWindow ( ) ) {
return ;
}
bool equals = false ;
aPrincipal - > Equals ( aDoc - > NodePrincipal ( ) , & equals ) ;
if ( ! equals ) {
return ;
2015-10-26 04:08:54 +00:00
}
2015-11-30 19:29:51 +00:00
if ( ! Preferences : : GetBool ( " dom.serviceWorkers.testing.enabled " ) & &
! IsFromAuthenticatedOrigin ( aDoc ) ) {
return ;
}
2014-10-27 11:03:00 +00:00
2015-11-30 19:29:51 +00:00
ServiceWorkerClientInfo clientInfo ( aDoc ) ;
aDocuments . AppendElement ( aDoc ) ;
} ;
// Since it's not simple to check whether a document is in
// mControlledDocuments, we take different code paths depending on whether we
// need to look at all documents. The common parts of the two loops are
// factored out into the ProcessDocument lambda.
if ( aIncludeUncontrolled ) {
bool loop = true ;
while ( NS_SUCCEEDED ( enumerator - > HasMoreElements ( & loop ) ) & & loop ) {
nsCOMPtr < nsISupports > ptr ;
rv = enumerator - > GetNext ( getter_AddRefs ( ptr ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
continue ;
}
nsCOMPtr < nsIDocument > doc = do_QueryInterface ( ptr ) ;
ProcessDocument ( aPrincipal , doc ) ;
2015-10-26 04:08:54 +00:00
}
2015-11-30 19:29:51 +00:00
} else {
for ( auto iter = mControlledDocuments . Iter ( ) ; ! iter . Done ( ) ; iter . Next ( ) ) {
ServiceWorkerRegistrationInfo * thisRegistration = iter . UserData ( ) ;
MOZ_ASSERT ( thisRegistration ) ;
if ( ! registration - > mScope . Equals ( thisRegistration - > mScope ) ) {
continue ;
}
2015-10-26 04:08:54 +00:00
2015-11-30 19:29:51 +00:00
nsCOMPtr < nsIDocument > doc = do_QueryInterface ( iter . Key ( ) ) ;
ProcessDocument ( aPrincipal , doc ) ;
}
2015-10-26 04:08:54 +00:00
}
2014-10-27 11:03:00 +00:00
}
2015-05-14 19:41:42 +00:00
void
ServiceWorkerManager : : MaybeClaimClient ( nsIDocument * aDocument ,
ServiceWorkerRegistrationInfo * aWorkerRegistration )
{
MOZ_ASSERT ( aWorkerRegistration ) ;
MOZ_ASSERT ( aWorkerRegistration - > mActiveWorker ) ;
// Same origin check
if ( ! aWorkerRegistration - > mPrincipal - > Equals ( aDocument - > NodePrincipal ( ) ) ) {
return ;
}
// The registration that should be controlling the client
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > matchingRegistration =
2015-05-14 19:41:42 +00:00
GetServiceWorkerRegistrationInfo ( aDocument ) ;
// The registration currently controlling the client
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > controllingRegistration ;
2015-05-14 19:41:42 +00:00
GetDocumentRegistration ( aDocument , getter_AddRefs ( controllingRegistration ) ) ;
if ( aWorkerRegistration ! = matchingRegistration | |
aWorkerRegistration = = controllingRegistration ) {
return ;
}
if ( controllingRegistration ) {
StopControllingADocument ( controllingRegistration ) ;
}
2015-11-25 23:03:59 +00:00
StartControllingADocument ( aWorkerRegistration , aDocument , NS_LITERAL_STRING ( " " ) ) ;
2015-05-14 19:41:42 +00:00
FireControllerChangeOnDocument ( aDocument ) ;
}
nsresult
2015-06-03 08:43:43 +00:00
ServiceWorkerManager : : ClaimClients ( nsIPrincipal * aPrincipal ,
const nsCString & aScope , uint64_t aId )
2015-05-14 19:41:42 +00:00
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2015-06-03 08:43:43 +00:00
GetRegistration ( aPrincipal , aScope ) ;
2015-05-14 19:41:42 +00:00
if ( ! registration | | ! registration - > mActiveWorker | |
! ( registration - > mActiveWorker - > ID ( ) = = aId ) ) {
// The worker is not active.
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
2015-07-13 15:37:28 +00:00
for ( auto iter = mAllDocuments . Iter ( ) ; ! iter . Done ( ) ; iter . Next ( ) ) {
nsCOMPtr < nsIDocument > document = do_QueryInterface ( iter . Get ( ) - > GetKey ( ) ) ;
swm - > MaybeClaimClient ( document , registration ) ;
}
2015-05-14 19:41:42 +00:00
return NS_OK ;
}
2015-06-02 11:12:00 +00:00
nsresult
2015-06-03 14:20:52 +00:00
ServiceWorkerManager : : SetSkipWaitingFlag ( nsIPrincipal * aPrincipal ,
const nsCString & aScope ,
2015-06-02 11:12:00 +00:00
uint64_t aServiceWorkerID )
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2015-06-03 14:20:52 +00:00
GetRegistration ( aPrincipal , aScope ) ;
2015-11-26 17:03:10 +00:00
if ( NS_WARN_IF ( ! registration ) ) {
2015-06-02 11:12:00 +00:00
return NS_ERROR_FAILURE ;
}
if ( registration - > mInstallingWorker & &
( registration - > mInstallingWorker - > ID ( ) = = aServiceWorkerID ) ) {
registration - > mInstallingWorker - > SetSkipWaitingFlag ( ) ;
} else if ( registration - > mWaitingWorker & &
( registration - > mWaitingWorker - > ID ( ) = = aServiceWorkerID ) ) {
registration - > mWaitingWorker - > SetSkipWaitingFlag ( ) ;
if ( registration - > mWaitingWorker - > State ( ) = = ServiceWorkerState : : Installed ) {
registration - > TryToActivate ( ) ;
}
} else {
2015-11-26 17:03:10 +00:00
NS_WARNING ( " Failed to set skipWaiting flag, no matching worker. " ) ;
2015-06-02 11:12:00 +00:00
return NS_ERROR_FAILURE ;
}
return NS_OK ;
}
2014-12-19 10:00:29 +00:00
void
ServiceWorkerManager : : FireControllerChange ( ServiceWorkerRegistrationInfo * aRegistration )
{
2015-10-26 04:09:05 +00:00
AssertIsOnMainThread ( ) ;
for ( auto iter = mControlledDocuments . Iter ( ) ; ! iter . Done ( ) ; iter . Next ( ) ) {
if ( iter . UserData ( ) ! = aRegistration ) {
continue ;
}
nsCOMPtr < nsIDocument > doc = do_QueryInterface ( iter . Key ( ) ) ;
if ( NS_WARN_IF ( ! doc ) ) {
continue ;
}
FireControllerChangeOnDocument ( doc ) ;
}
2014-12-19 10:00:29 +00:00
}
2015-02-09 04:33:39 +00:00
2015-06-03 08:43:43 +00:00
already_AddRefed < ServiceWorkerRegistrationInfo >
ServiceWorkerManager : : GetRegistration ( nsIPrincipal * aPrincipal ,
const nsACString & aScope ) const
{
MOZ_ASSERT ( aPrincipal ) ;
nsAutoCString scopeKey ;
nsresult rv = PrincipalToScopeKey ( aPrincipal , scopeKey ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return nullptr ;
}
return GetRegistration ( scopeKey , aScope ) ;
}
2015-12-15 11:10:53 +00:00
NS_IMETHODIMP
ServiceWorkerManager : : GetRegistrationByPrincipal ( nsIPrincipal * aPrincipal ,
const nsAString & aScope ,
nsIServiceWorkerRegistrationInfo * * aInfo )
{
MOZ_ASSERT ( aPrincipal ) ;
MOZ_ASSERT ( aInfo ) ;
nsCOMPtr < nsIURI > scopeURI ;
nsresult rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , aScope , nullptr , nullptr ) ;
if ( NS_FAILED ( rv ) ) {
return NS_ERROR_FAILURE ;
}
RefPtr < ServiceWorkerRegistrationInfo > info =
GetServiceWorkerRegistrationInfo ( aPrincipal , scopeURI ) ;
if ( ! info ) {
return NS_ERROR_FAILURE ;
}
info . forget ( aInfo ) ;
return NS_OK ;
}
2015-06-03 08:43:43 +00:00
already_AddRefed < ServiceWorkerRegistrationInfo >
ServiceWorkerManager : : GetRegistration ( const nsACString & aScopeKey ,
const nsACString & aScope ) const
{
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > reg ;
2015-06-03 08:43:43 +00:00
RegistrationDataPerPrincipal * data ;
if ( ! mRegistrationInfos . Get ( aScopeKey , & data ) ) {
return reg . forget ( ) ;
}
data - > mInfos . Get ( aScope , getter_AddRefs ( reg ) ) ;
return reg . forget ( ) ;
}
2015-02-09 04:33:39 +00:00
ServiceWorkerRegistrationInfo *
2015-02-11 11:53:00 +00:00
ServiceWorkerManager : : CreateNewRegistration ( const nsCString & aScope ,
nsIPrincipal * aPrincipal )
2015-02-09 04:33:39 +00:00
{
# ifdef DEBUG
AssertIsOnMainThread ( ) ;
nsCOMPtr < nsIURI > scopeURI ;
nsresult rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , aScope , nullptr , nullptr ) ;
MOZ_ASSERT ( NS_SUCCEEDED ( rv ) ) ;
2015-06-04 18:51:57 +00:00
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > tmp =
2015-06-04 18:51:57 +00:00
GetRegistration ( aPrincipal , aScope ) ;
MOZ_ASSERT ( ! tmp ) ;
2015-02-09 04:33:39 +00:00
# endif
2015-06-03 08:43:43 +00:00
2015-02-11 11:53:00 +00:00
ServiceWorkerRegistrationInfo * registration = new ServiceWorkerRegistrationInfo ( aScope , aPrincipal ) ;
2015-02-09 04:33:39 +00:00
// From now on ownership of registration is with
// mServiceWorkerRegistrationInfos.
2015-06-03 08:43:43 +00:00
AddScopeAndRegistration ( aScope , registration ) ;
2015-02-09 04:33:39 +00:00
return registration ;
}
2015-02-10 22:33:23 +00:00
void
ServiceWorkerManager : : MaybeRemoveRegistration ( ServiceWorkerRegistrationInfo * aRegistration )
{
MOZ_ASSERT ( aRegistration ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerInfo > newest = aRegistration - > Newest ( ) ;
2015-09-23 18:40:51 +00:00
if ( ! newest & & HasScope ( aRegistration - > mPrincipal , aRegistration - > mScope ) ) {
aRegistration - > Clear ( ) ;
2015-02-10 22:33:23 +00:00
RemoveRegistration ( aRegistration ) ;
}
}
2015-02-11 18:51:32 +00:00
void
2015-03-06 01:37:49 +00:00
ServiceWorkerManager : : RemoveRegistrationInternal ( ServiceWorkerRegistrationInfo * aRegistration )
2015-02-11 18:51:32 +00:00
{
MOZ_ASSERT ( aRegistration ) ;
MOZ_ASSERT ( ! aRegistration - > IsControllingDocuments ( ) ) ;
2015-06-23 12:56:29 +00:00
if ( mShuttingDown ) {
return ;
}
2015-02-11 18:51:32 +00:00
// All callers should be either from a job in which case the actor is
// available, or from MaybeStopControlling(), in which case, this will only be
// called if a valid registration is found. If a valid registration exists,
// it means the actor is available since the original map of registrations is
// populated by it, and any new registrations wait until the actor is
// available before proceeding (See ServiceWorkerRegisterJob::Start).
MOZ_ASSERT ( mActor ) ;
PrincipalInfo principalInfo ;
2015-03-06 01:37:49 +00:00
if ( NS_WARN_IF ( NS_FAILED ( PrincipalToPrincipalInfo ( aRegistration - > mPrincipal ,
2015-02-11 18:51:32 +00:00
& principalInfo ) ) ) ) {
//XXXnsm I can't think of any other reason a stored principal would fail to
//convert.
NS_WARNING ( " Unable to unregister serviceworker due to possible OOM " ) ;
return ;
}
2015-06-03 08:43:43 +00:00
2015-06-04 18:51:57 +00:00
mActor - > SendUnregister ( principalInfo , NS_ConvertUTF8toUTF16 ( aRegistration - > mScope ) ) ;
2015-02-11 18:51:32 +00:00
}
2015-02-19 16:40:21 +00:00
2015-03-06 01:37:49 +00:00
void
ServiceWorkerManager : : RemoveRegistration ( ServiceWorkerRegistrationInfo * aRegistration )
{
RemoveRegistrationInternal ( aRegistration ) ;
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( HasScope ( aRegistration - > mPrincipal , aRegistration - > mScope ) ) ;
RemoveScopeAndRegistration ( aRegistration ) ;
2015-03-06 01:37:49 +00:00
}
2015-04-10 08:50:06 +00:00
2015-03-06 01:37:49 +00:00
namespace {
/**
* See browser / components / sessionstore / Utils . jsm function hasRootDomain ( ) .
*
* Returns true if the | url | passed in is part of the given root | domain | .
* For example , if | url | is " www.mozilla.org " , and we pass in | domain | as
* " mozilla.org " , this will return true . It would return false the other way
* around .
*/
bool
HasRootDomain ( nsIURI * aURI , const nsACString & aDomain )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aURI ) ;
nsAutoCString host ;
nsresult rv = aURI - > GetHost ( host ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return false ;
}
nsACString : : const_iterator start , end ;
host . BeginReading ( start ) ;
host . EndReading ( end ) ;
if ( ! FindInReadable ( aDomain , start , end ) ) {
return false ;
}
if ( host . Equals ( aDomain ) ) {
return true ;
}
// Beginning of the string matches, can't look at the previous char.
if ( start . get ( ) = = host . BeginReading ( ) ) {
// Equals failed so this is fine.
return false ;
}
char prevChar = * ( - - start ) ;
return prevChar = = ' . ' ;
}
2015-07-13 15:25:42 +00:00
} // namespace
2015-06-04 18:51:57 +00:00
2015-04-10 08:50:06 +00:00
NS_IMETHODIMP
ServiceWorkerManager : : GetAllRegistrations ( nsIArray * * aResult )
{
AssertIsOnMainThread ( ) ;
nsCOMPtr < nsIMutableArray > array ( do_CreateInstance ( NS_ARRAY_CONTRACTID ) ) ;
if ( ! array ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
2015-10-26 04:08:54 +00:00
for ( auto it1 = mRegistrationInfos . Iter ( ) ; ! it1 . Done ( ) ; it1 . Next ( ) ) {
for ( auto it2 = it1 . UserData ( ) - > mInfos . Iter ( ) ; ! it2 . Done ( ) ; it2 . Next ( ) ) {
ServiceWorkerRegistrationInfo * reg = it2 . UserData ( ) ;
MOZ_ASSERT ( reg ) ;
if ( reg - > mPendingUninstall ) {
continue ;
}
2015-11-02 14:04:41 +00:00
array - > AppendElement ( reg , false ) ;
2015-10-26 04:08:54 +00:00
}
}
2015-04-10 08:50:06 +00:00
array . forget ( aResult ) ;
return NS_OK ;
}
2015-10-26 04:35:44 +00:00
// MUST ONLY BE CALLED FROM Remove(), RemoveAll() and RemoveAllRegistrations()!
2015-03-06 01:37:49 +00:00
void
2015-06-03 08:43:43 +00:00
ServiceWorkerManager : : ForceUnregister ( RegistrationDataPerPrincipal * aRegistrationData ,
ServiceWorkerRegistrationInfo * aRegistration )
2015-03-06 01:37:49 +00:00
{
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( aRegistrationData ) ;
2015-03-06 01:37:49 +00:00
MOZ_ASSERT ( aRegistration ) ;
2015-06-03 08:43:43 +00:00
ServiceWorkerJobQueue * queue ;
aRegistrationData - > mJobQueues . Get ( aRegistration - > mScope , & queue ) ;
if ( queue ) {
queue - > CancelJobs ( ) ;
2015-03-06 01:37:49 +00:00
}
2015-12-11 19:53:10 +00:00
nsCOMPtr < nsITimer > timer =
aRegistrationData - > mUpdateTimers . Get ( aRegistration - > mScope ) ;
if ( timer ) {
timer - > Cancel ( ) ;
aRegistrationData - > mUpdateTimers . Remove ( aRegistration - > mScope ) ;
}
2015-03-06 01:37:49 +00:00
// Since Unregister is async, it is ok to call it in an enumeration.
Unregister ( aRegistration - > mPrincipal , nullptr , NS_ConvertUTF8toUTF16 ( aRegistration - > mScope ) ) ;
}
NS_IMETHODIMP
2015-06-21 11:19:07 +00:00
ServiceWorkerManager : : RemoveAndPropagate ( const nsACString & aHost )
{
Remove ( aHost ) ;
PropagateRemove ( aHost ) ;
return NS_OK ;
}
void
2015-03-06 01:37:49 +00:00
ServiceWorkerManager : : Remove ( const nsACString & aHost )
{
AssertIsOnMainThread ( ) ;
2015-06-21 11:19:07 +00:00
// We need to postpone this operation in case we don't have an actor because
// this is needed by the ForceUnregister.
if ( ! mActor ) {
2015-10-18 05:24:48 +00:00
RefPtr < nsIRunnable > runnable = new RemoveRunnable ( aHost ) ;
2015-06-21 11:19:07 +00:00
AppendPendingOperation ( runnable ) ;
return ;
}
2015-10-26 04:35:30 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
for ( auto it1 = mRegistrationInfos . Iter ( ) ; ! it1 . Done ( ) ; it1 . Next ( ) ) {
ServiceWorkerManager : : RegistrationDataPerPrincipal * data = it1 . UserData ( ) ;
for ( auto it2 = data - > mInfos . Iter ( ) ; ! it2 . Done ( ) ; it2 . Next ( ) ) {
ServiceWorkerRegistrationInfo * reg = it2 . UserData ( ) ;
nsCOMPtr < nsIURI > scopeURI ;
nsresult rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , it2 . Key ( ) ,
nullptr , nullptr ) ;
// This way subdomains are also cleared.
if ( NS_SUCCEEDED ( rv ) & & HasRootDomain ( scopeURI , aHost ) ) {
swm - > ForceUnregister ( data , reg ) ;
}
}
}
2015-06-21 11:19:07 +00:00
}
void
ServiceWorkerManager : : PropagateRemove ( const nsACString & aHost )
{
AssertIsOnMainThread ( ) ;
if ( ! mActor ) {
2015-10-18 05:24:48 +00:00
RefPtr < nsIRunnable > runnable = new PropagateRemoveRunnable ( aHost ) ;
2015-06-21 11:19:07 +00:00
AppendPendingOperation ( runnable ) ;
return ;
}
mActor - > SendPropagateRemove ( nsCString ( aHost ) ) ;
2015-03-06 01:37:49 +00:00
}
2015-06-21 11:17:58 +00:00
void
2015-03-06 01:37:49 +00:00
ServiceWorkerManager : : RemoveAll ( )
{
AssertIsOnMainThread ( ) ;
2015-10-26 04:35:30 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
for ( auto it1 = mRegistrationInfos . Iter ( ) ; ! it1 . Done ( ) ; it1 . Next ( ) ) {
ServiceWorkerManager : : RegistrationDataPerPrincipal * data = it1 . UserData ( ) ;
for ( auto it2 = data - > mInfos . Iter ( ) ; ! it2 . Done ( ) ; it2 . Next ( ) ) {
ServiceWorkerRegistrationInfo * reg = it2 . UserData ( ) ;
swm - > ForceUnregister ( data , reg ) ;
}
}
2015-06-21 11:17:58 +00:00
}
void
ServiceWorkerManager : : PropagateRemoveAll ( )
{
AssertIsOnMainThread ( ) ;
2015-07-04 01:29:00 +00:00
MOZ_ASSERT ( XRE_IsParentProcess ( ) ) ;
2015-06-21 11:17:58 +00:00
if ( ! mActor ) {
2015-10-18 05:24:48 +00:00
RefPtr < nsIRunnable > runnable = new PropagateRemoveAllRunnable ( ) ;
2015-06-21 11:17:58 +00:00
AppendPendingOperation ( runnable ) ;
return ;
}
mActor - > SendPropagateRemoveAll ( ) ;
2015-03-06 01:37:49 +00:00
}
2015-06-11 17:42:38 +00:00
void
2015-11-03 01:50:54 +00:00
ServiceWorkerManager : : RemoveAllRegistrations ( PrincipalOriginAttributes * aParams )
2015-06-11 17:42:38 +00:00
{
AssertIsOnMainThread ( ) ;
2015-08-03 20:51:07 +00:00
MOZ_ASSERT ( aParams ) ;
2015-06-11 17:42:38 +00:00
2015-10-26 04:35:44 +00:00
for ( auto it1 = mRegistrationInfos . Iter ( ) ; ! it1 . Done ( ) ; it1 . Next ( ) ) {
ServiceWorkerManager : : RegistrationDataPerPrincipal * data = it1 . UserData ( ) ;
// We can use iteration because ForceUnregister (and Unregister) are
// async. Otherwise doing some R/W operations on an hashtable during
// iteration will crash.
for ( auto it2 = data - > mInfos . Iter ( ) ; ! it2 . Done ( ) ; it2 . Next ( ) ) {
ServiceWorkerRegistrationInfo * reg = it2 . UserData ( ) ;
MOZ_ASSERT ( reg ) ;
MOZ_ASSERT ( reg - > mPrincipal ) ;
bool equals = false ;
if ( aParams - > mInBrowser ) {
// When we do a system wide "clear cookies and stored data" on B2G we
// get the "clear-origin-data" notification with the System app appID
// and the browserOnly flag set to true. Web sites registering a
// service worker on B2G have a principal with the following
// information: web site origin + System app appId + inBrowser=1 So
// we need to check if the service worker registration info contains
// the System app appID and the enabled inBrowser flag and in that
// case remove it from the registry.
OriginAttributes attrs =
mozilla : : BasePrincipal : : Cast ( reg - > mPrincipal ) - > OriginAttributesRef ( ) ;
equals = attrs = = * aParams ;
} else {
// If we get the "clear-origin-data" notification because of an app
// uninstallation, we need to check the full principal to get the
// match in the service workers registry. If we find a match, we
// unregister the worker.
nsCOMPtr < nsIAppsService > appsService = do_GetService ( APPS_SERVICE_CONTRACTID ) ;
if ( NS_WARN_IF ( ! appsService ) ) {
continue ;
}
nsCOMPtr < mozIApplication > app ;
appsService - > GetAppByLocalId ( aParams - > mAppId , getter_AddRefs ( app ) ) ;
if ( NS_WARN_IF ( ! app ) ) {
continue ;
}
nsCOMPtr < nsIPrincipal > principal ;
app - > GetPrincipal ( getter_AddRefs ( principal ) ) ;
if ( NS_WARN_IF ( ! principal ) ) {
continue ;
}
reg - > mPrincipal - > Equals ( principal , & equals ) ;
}
if ( equals ) {
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
swm - > ForceUnregister ( data , reg ) ;
}
}
}
2015-06-11 17:42:38 +00:00
}
2015-11-04 14:17:02 +00:00
NS_IMETHODIMP
ServiceWorkerManager : : AddListener ( nsIServiceWorkerManagerListener * aListener )
{
AssertIsOnMainThread ( ) ;
2015-11-13 20:54:45 +00:00
if ( ! aListener | | mListeners . Contains ( aListener ) ) {
2015-11-04 14:17:02 +00:00
return NS_ERROR_INVALID_ARG ;
}
mListeners . AppendElement ( aListener ) ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerManager : : RemoveListener ( nsIServiceWorkerManagerListener * aListener )
{
AssertIsOnMainThread ( ) ;
2015-11-13 20:54:45 +00:00
if ( ! aListener | | ! mListeners . Contains ( aListener ) ) {
2015-11-04 14:17:02 +00:00
return NS_ERROR_INVALID_ARG ;
}
mListeners . RemoveElement ( aListener ) ;
return NS_OK ;
}
2015-11-16 16:04:11 +00:00
NS_IMETHODIMP
ServiceWorkerManager : : ShouldReportToWindow ( nsIDOMWindow * aWindow ,
const nsACString & aScope ,
bool * aResult )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aResult ) ;
* aResult = false ;
// Get the inner window ID to compare to our document windows below.
nsCOMPtr < nsPIDOMWindow > targetWin = do_QueryInterface ( aWindow ) ;
if ( NS_WARN_IF ( ! targetWin ) ) {
return NS_OK ;
}
targetWin = targetWin - > GetScriptableTop ( ) ;
uint64_t winId = targetWin - > WindowID ( ) ;
// Check our weak registering document references first. This way we clear
// out as many dead weak references as possible when this method is called.
WeakDocumentList * list = mRegisteringDocuments . Get ( aScope ) ;
if ( list ) {
for ( int32_t i = list - > Length ( ) - 1 ; i > = 0 ; - - i ) {
nsCOMPtr < nsIDocument > doc = do_QueryReferent ( list - > ElementAt ( i ) ) ;
if ( ! doc ) {
list - > RemoveElementAt ( i ) ;
continue ;
}
if ( ! doc - > IsCurrentActiveDocument ( ) ) {
continue ;
}
nsCOMPtr < nsPIDOMWindow > win = doc - > GetWindow ( ) ;
if ( ! win ) {
continue ;
}
win = win - > GetScriptableTop ( ) ;
// Match. We should report to this window.
if ( win & & winId = = win - > WindowID ( ) ) {
* aResult = true ;
return NS_OK ;
}
}
if ( list - > IsEmpty ( ) ) {
list = nullptr ;
nsAutoPtr < WeakDocumentList > doomed ;
mRegisteringDocuments . RemoveAndForget ( aScope , doomed ) ;
}
}
// Examine any windows performing a navigation that we are currently
// intercepting.
InterceptionList * intList = mNavigationInterceptions . Get ( aScope ) ;
if ( intList ) {
for ( uint32_t i = 0 ; i < intList - > Length ( ) ; + + i ) {
nsCOMPtr < nsIInterceptedChannel > channel = intList - > ElementAt ( i ) ;
nsCOMPtr < nsIChannel > inner ;
nsresult rv = channel - > GetChannel ( getter_AddRefs ( inner ) ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
continue ;
}
uint64_t id = nsContentUtils : : GetInnerWindowID ( inner ) ;
if ( id = = 0 ) {
continue ;
}
nsCOMPtr < nsPIDOMWindow > win = nsGlobalWindow : : GetInnerWindowWithId ( id ) ;
if ( ! win ) {
continue ;
}
win = win - > GetScriptableTop ( ) ;
// Match. We should report to this window.
if ( win & & winId = = win - > WindowID ( ) ) {
* aResult = true ;
return NS_OK ;
}
}
}
// Next examine controlled documents to see if the windows match.
for ( auto iter = mControlledDocuments . Iter ( ) ; ! iter . Done ( ) ; iter . Next ( ) ) {
ServiceWorkerRegistrationInfo * reg = iter . UserData ( ) ;
MOZ_ASSERT ( reg ) ;
if ( ! reg - > mScope . Equals ( aScope ) ) {
continue ;
}
nsCOMPtr < nsIDocument > doc = do_QueryInterface ( iter . Key ( ) ) ;
if ( ! doc | | ! doc - > IsCurrentActiveDocument ( ) ) {
continue ;
}
nsCOMPtr < nsPIDOMWindow > win = doc - > GetWindow ( ) ;
if ( ! win ) {
continue ;
}
win = win - > GetScriptableTop ( ) ;
// Match. We should report to this window.
if ( win & & winId = = win - > WindowID ( ) ) {
* aResult = true ;
return NS_OK ;
}
}
// No match. We should not report to this window.
return NS_OK ;
}
2015-03-06 01:37:49 +00:00
NS_IMETHODIMP
ServiceWorkerManager : : Observe ( nsISupports * aSubject ,
const char * aTopic ,
const char16_t * aData )
{
2015-06-21 11:17:58 +00:00
if ( strcmp ( aTopic , PURGE_SESSION_HISTORY ) = = 0 ) {
2015-07-04 01:29:00 +00:00
MOZ_ASSERT ( XRE_IsParentProcess ( ) ) ;
2015-06-21 11:17:58 +00:00
RemoveAll ( ) ;
PropagateRemoveAll ( ) ;
return NS_OK ;
}
if ( strcmp ( aTopic , PURGE_DOMAIN_DATA ) = = 0 ) {
2015-07-04 01:29:00 +00:00
MOZ_ASSERT ( XRE_IsParentProcess ( ) ) ;
2015-03-06 01:37:49 +00:00
nsAutoString domain ( aData ) ;
2015-06-21 11:19:07 +00:00
RemoveAndPropagate ( NS_ConvertUTF16toUTF8 ( domain ) ) ;
return NS_OK ;
}
2015-03-06 01:37:49 +00:00
2015-08-19 06:46:53 +00:00
if ( strcmp ( aTopic , CLEAR_ORIGIN_DATA ) = = 0 ) {
2015-07-04 01:29:00 +00:00
MOZ_ASSERT ( XRE_IsParentProcess ( ) ) ;
2015-11-03 01:50:54 +00:00
PrincipalOriginAttributes attrs ;
2015-08-19 06:46:53 +00:00
MOZ_ALWAYS_TRUE ( attrs . Init ( nsAutoString ( aData ) ) ) ;
2015-06-11 17:42:38 +00:00
2015-08-19 06:46:53 +00:00
RemoveAllRegistrations ( & attrs ) ;
2015-06-23 12:56:29 +00:00
return NS_OK ;
}
if ( strcmp ( aTopic , NS_XPCOM_SHUTDOWN_OBSERVER_ID ) = = 0 ) {
mShuttingDown = true ;
2015-12-11 19:53:10 +00:00
for ( auto it1 = mRegistrationInfos . Iter ( ) ; ! it1 . Done ( ) ; it1 . Next ( ) ) {
for ( auto it2 = it1 . UserData ( ) - > mUpdateTimers . Iter ( ) ; ! it2 . Done ( ) ; it2 . Next ( ) ) {
nsCOMPtr < nsITimer > timer = it2 . UserData ( ) ;
timer - > Cancel ( ) ;
}
it1 . UserData ( ) - > mUpdateTimers . Clear ( ) ;
}
2015-03-06 01:37:49 +00:00
nsCOMPtr < nsIObserverService > obs = mozilla : : services : : GetObserverService ( ) ;
if ( obs ) {
obs - > RemoveObserver ( this , NS_XPCOM_SHUTDOWN_OBSERVER_ID ) ;
2015-06-23 12:56:29 +00:00
2015-07-04 01:29:00 +00:00
if ( XRE_IsParentProcess ( ) ) {
2015-06-23 12:56:29 +00:00
obs - > RemoveObserver ( this , PURGE_SESSION_HISTORY ) ;
obs - > RemoveObserver ( this , PURGE_DOMAIN_DATA ) ;
2015-08-19 06:46:53 +00:00
obs - > RemoveObserver ( this , CLEAR_ORIGIN_DATA ) ;
2015-06-23 12:56:29 +00:00
}
2015-03-06 01:37:49 +00:00
}
2015-06-23 12:56:29 +00:00
if ( mActor ) {
mActor - > ManagerShuttingDown ( ) ;
2015-10-18 05:24:48 +00:00
RefPtr < TeardownRunnable > runnable = new TeardownRunnable ( mActor ) ;
2015-06-23 12:56:29 +00:00
nsresult rv = NS_DispatchToMainThread ( runnable ) ;
2015-11-02 05:53:26 +00:00
Unused < < NS_WARN_IF ( NS_FAILED ( rv ) ) ;
2015-06-23 12:56:29 +00:00
mActor = nullptr ;
}
return NS_OK ;
2015-03-06 01:37:49 +00:00
}
2015-06-23 12:56:29 +00:00
MOZ_CRASH ( " Received message we aren't supposed to be registered for! " ) ;
2015-03-06 01:37:49 +00:00
return NS_OK ;
}
2015-06-04 18:51:57 +00:00
NS_IMETHODIMP
ServiceWorkerManager : : PropagateSoftUpdate ( JS : : Handle < JS : : Value > aOriginAttributes ,
const nsAString & aScope ,
JSContext * aCx )
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-06-04 18:51:57 +00:00
2015-11-03 01:50:54 +00:00
PrincipalOriginAttributes attrs ;
2015-06-04 18:51:57 +00:00
if ( ! aOriginAttributes . isObject ( ) | | ! attrs . Init ( aCx , aOriginAttributes ) ) {
return NS_ERROR_INVALID_ARG ;
}
PropagateSoftUpdate ( attrs , aScope ) ;
return NS_OK ;
}
void
2015-11-03 01:50:54 +00:00
ServiceWorkerManager : : PropagateSoftUpdate ( const PrincipalOriginAttributes & aOriginAttributes ,
2015-06-04 18:51:57 +00:00
const nsAString & aScope )
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-06-04 18:51:57 +00:00
if ( ! mActor ) {
2015-10-18 05:24:48 +00:00
RefPtr < nsIRunnable > runnable =
2015-06-04 18:51:57 +00:00
new PropagateSoftUpdateRunnable ( aOriginAttributes , aScope ) ;
AppendPendingOperation ( runnable ) ;
return ;
}
mActor - > SendPropagateSoftUpdate ( aOriginAttributes , nsString ( aScope ) ) ;
}
NS_IMETHODIMP
ServiceWorkerManager : : PropagateUnregister ( nsIPrincipal * aPrincipal ,
nsIServiceWorkerUnregisterCallback * aCallback ,
const nsAString & aScope )
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-06-04 18:51:57 +00:00
MOZ_ASSERT ( aPrincipal ) ;
if ( ! mActor ) {
2015-10-18 05:24:48 +00:00
RefPtr < nsIRunnable > runnable =
2015-06-04 18:51:57 +00:00
new PropagateUnregisterRunnable ( aPrincipal , aCallback , aScope ) ;
AppendPendingOperation ( runnable ) ;
return NS_OK ;
}
PrincipalInfo principalInfo ;
if ( NS_WARN_IF ( NS_FAILED ( PrincipalToPrincipalInfo ( aPrincipal ,
& principalInfo ) ) ) ) {
return NS_ERROR_FAILURE ;
}
mActor - > SendPropagateUnregister ( principalInfo , nsString ( aScope ) ) ;
nsresult rv = Unregister ( aPrincipal , aCallback , aScope ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
return NS_OK ;
}
2015-11-04 14:17:02 +00:00
void
ServiceWorkerManager : : NotifyListenersOnRegister (
nsIServiceWorkerRegistrationInfo * aInfo )
{
nsTArray < nsCOMPtr < nsIServiceWorkerManagerListener > > listeners ( mListeners ) ;
for ( size_t index = 0 ; index < listeners . Length ( ) ; + + index ) {
listeners [ index ] - > OnRegister ( aInfo ) ;
}
}
void
ServiceWorkerManager : : NotifyListenersOnUnregister (
nsIServiceWorkerRegistrationInfo * aInfo )
{
nsTArray < nsCOMPtr < nsIServiceWorkerManagerListener > > listeners ( mListeners ) ;
for ( size_t index = 0 ; index < listeners . Length ( ) ; + + index ) {
listeners [ index ] - > OnUnregister ( aInfo ) ;
}
}
2015-11-16 16:04:11 +00:00
void
ServiceWorkerManager : : AddRegisteringDocument ( const nsACString & aScope ,
nsIDocument * aDoc )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( ! aScope . IsEmpty ( ) ) ;
MOZ_ASSERT ( aDoc ) ;
WeakDocumentList * list = mRegisteringDocuments . LookupOrAdd ( aScope ) ;
MOZ_ASSERT ( list ) ;
for ( int32_t i = list - > Length ( ) - 1 ; i > = 0 ; - - i ) {
nsCOMPtr < nsIDocument > existing = do_QueryReferent ( list - > ElementAt ( i ) ) ;
if ( ! existing ) {
list - > RemoveElementAt ( i ) ;
continue ;
}
if ( existing = = aDoc ) {
return ;
}
}
list - > AppendElement ( do_GetWeakReference ( aDoc ) ) ;
}
2015-11-16 16:04:11 +00:00
class ServiceWorkerManager : : InterceptionReleaseHandle final : public nsISupports
{
const nsCString mScope ;
// Weak reference to channel is safe, because the channel holds a
// reference to this object. Also, the pointer is only used for
// comparison purposes.
nsIInterceptedChannel * mChannel ;
~ InterceptionReleaseHandle ( )
{
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
swm - > RemoveNavigationInterception ( mScope , mChannel ) ;
}
public :
InterceptionReleaseHandle ( const nsACString & aScope ,
nsIInterceptedChannel * aChannel )
: mScope ( aScope )
, mChannel ( aChannel )
{
2015-11-23 13:47:53 +00:00
AssertIsOnMainThread ( ) ;
2015-11-16 16:04:11 +00:00
MOZ_ASSERT ( ! aScope . IsEmpty ( ) ) ;
MOZ_ASSERT ( mChannel ) ;
}
NS_DECL_ISUPPORTS
} ;
NS_IMPL_ISUPPORTS0 ( ServiceWorkerManager : : InterceptionReleaseHandle ) ;
void
ServiceWorkerManager : : AddNavigationInterception ( const nsACString & aScope ,
nsIInterceptedChannel * aChannel )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( ! aScope . IsEmpty ( ) ) ;
MOZ_ASSERT ( aChannel ) ;
InterceptionList * list =
mNavigationInterceptions . LookupOrAdd ( aScope ) ;
MOZ_ASSERT ( list ) ;
MOZ_ASSERT ( ! list - > Contains ( aChannel ) ) ;
nsCOMPtr < nsISupports > releaseHandle =
new InterceptionReleaseHandle ( aScope , aChannel ) ;
aChannel - > SetReleaseHandle ( releaseHandle ) ;
list - > AppendElement ( aChannel ) ;
}
void
ServiceWorkerManager : : RemoveNavigationInterception ( const nsACString & aScope ,
nsIInterceptedChannel * aChannel )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aChannel ) ;
InterceptionList * list =
mNavigationInterceptions . Get ( aScope ) ;
if ( list ) {
MOZ_ALWAYS_TRUE ( list - > RemoveElement ( aChannel ) ) ;
MOZ_ASSERT ( ! list - > Contains ( aChannel ) ) ;
if ( list - > IsEmpty ( ) ) {
list = nullptr ;
nsAutoPtr < InterceptionList > doomed ;
mNavigationInterceptions . RemoveAndForget ( aScope , doomed ) ;
}
}
}
2015-12-11 19:53:10 +00:00
class UpdateTimerCallback final : public nsITimerCallback
{
nsCOMPtr < nsIPrincipal > mPrincipal ;
const nsCString mScope ;
~ UpdateTimerCallback ( )
{
}
public :
UpdateTimerCallback ( nsIPrincipal * aPrincipal , const nsACString & aScope )
: mPrincipal ( aPrincipal )
, mScope ( aScope )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( mPrincipal ) ;
MOZ_ASSERT ( ! mScope . IsEmpty ( ) ) ;
}
NS_IMETHOD
Notify ( nsITimer * aTimer ) override
{
AssertIsOnMainThread ( ) ;
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
if ( ! swm ) {
// shutting down, do nothing
return NS_OK ;
}
swm - > UpdateTimerFired ( mPrincipal , mScope ) ;
return NS_OK ;
}
NS_DECL_ISUPPORTS
} ;
NS_IMPL_ISUPPORTS ( UpdateTimerCallback , nsITimerCallback )
void
ServiceWorkerManager : : ScheduleUpdateTimer ( nsIPrincipal * aPrincipal ,
const nsACString & aScope )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aPrincipal ) ;
MOZ_ASSERT ( ! aScope . IsEmpty ( ) ) ;
if ( mShuttingDown ) {
return ;
}
nsAutoCString scopeKey ;
nsresult rv = PrincipalToScopeKey ( aPrincipal , scopeKey ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
RegistrationDataPerPrincipal * data ;
if ( ! mRegistrationInfos . Get ( scopeKey , & data ) ) {
return ;
}
nsCOMPtr < nsITimer > timer = data - > mUpdateTimers . Get ( aScope ) ;
if ( timer ) {
2015-12-11 19:53:11 +00:00
// There is already a timer scheduled. In this case just use the original
// schedule time. We don't want to push it out to a later time since that
// could allow updates to be starved forever if events are continuously
// fired.
return ;
}
timer = do_CreateInstance ( " @mozilla.org/timer;1 " , & rv ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
2015-12-11 19:53:10 +00:00
}
nsCOMPtr < nsITimerCallback > callback = new UpdateTimerCallback ( aPrincipal ,
aScope ) ;
const uint32_t UPDATE_DELAY_MS = 1000 ;
rv = timer - > InitWithCallback ( callback , UPDATE_DELAY_MS ,
nsITimer : : TYPE_ONE_SHOT ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
data - > mUpdateTimers . Put ( aScope , timer ) ;
}
void
ServiceWorkerManager : : UpdateTimerFired ( nsIPrincipal * aPrincipal ,
const nsACString & aScope )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aPrincipal ) ;
MOZ_ASSERT ( ! aScope . IsEmpty ( ) ) ;
if ( mShuttingDown ) {
return ;
}
// First cleanup the timer.
nsAutoCString scopeKey ;
nsresult rv = PrincipalToScopeKey ( aPrincipal , scopeKey ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
RegistrationDataPerPrincipal * data ;
if ( ! mRegistrationInfos . Get ( scopeKey , & data ) ) {
return ;
}
nsCOMPtr < nsITimer > timer = data - > mUpdateTimers . Get ( aScope ) ;
if ( timer ) {
timer - > Cancel ( ) ;
data - > mUpdateTimers . Remove ( aScope ) ;
}
RefPtr < ServiceWorkerRegistrationInfo > registration ;
data - > mInfos . Get ( aScope , getter_AddRefs ( registration ) ) ;
if ( ! registration ) {
return ;
}
if ( ! registration - > CheckAndClearIfUpdateNeeded ( ) ) {
return ;
}
PrincipalOriginAttributes attrs =
mozilla : : BasePrincipal : : Cast ( aPrincipal ) - > OriginAttributesRef ( ) ;
// Then trigger an update to fire asynchronously now.
PropagateSoftUpdate ( attrs , NS_ConvertUTF8toUTF16 ( aScope ) ) ;
}
2015-11-05 06:15:49 +00:00
NS_IMPL_ISUPPORTS ( ServiceWorkerInfo , nsIServiceWorkerInfo )
NS_IMETHODIMP
ServiceWorkerInfo : : GetScriptSpec ( nsAString & aScriptSpec )
{
AssertIsOnMainThread ( ) ;
CopyUTF8toUTF16 ( mScriptSpec , aScriptSpec ) ;
return NS_OK ;
}
NS_IMETHODIMP
ServiceWorkerInfo : : GetCacheName ( nsAString & aCacheName )
{
AssertIsOnMainThread ( ) ;
aCacheName = mCacheName ;
return NS_OK ;
}
2015-11-26 11:18:56 +00:00
NS_IMETHODIMP
ServiceWorkerInfo : : GetDebugger ( nsIWorkerDebugger * * aResult )
{
if ( NS_WARN_IF ( ! aResult ) ) {
return NS_ERROR_FAILURE ;
}
return mServiceWorkerPrivate - > GetDebugger ( aResult ) ;
}
NS_IMETHODIMP
ServiceWorkerInfo : : AttachDebugger ( )
{
return mServiceWorkerPrivate - > AttachDebugger ( ) ;
}
NS_IMETHODIMP
ServiceWorkerInfo : : DetachDebugger ( )
{
return mServiceWorkerPrivate - > DetachDebugger ( ) ;
}
2015-02-19 16:40:21 +00:00
void
ServiceWorkerInfo : : AppendWorker ( ServiceWorker * aWorker )
{
MOZ_ASSERT ( aWorker ) ;
# ifdef DEBUG
nsAutoString workerURL ;
aWorker - > GetScriptURL ( workerURL ) ;
MOZ_ASSERT ( workerURL . Equals ( NS_ConvertUTF8toUTF16 ( mScriptSpec ) ) ) ;
# endif
MOZ_ASSERT ( ! mInstances . Contains ( aWorker ) ) ;
mInstances . AppendElement ( aWorker ) ;
aWorker - > SetState ( State ( ) ) ;
}
void
ServiceWorkerInfo : : RemoveWorker ( ServiceWorker * aWorker )
{
MOZ_ASSERT ( aWorker ) ;
# ifdef DEBUG
nsAutoString workerURL ;
aWorker - > GetScriptURL ( workerURL ) ;
MOZ_ASSERT ( workerURL . Equals ( NS_ConvertUTF8toUTF16 ( mScriptSpec ) ) ) ;
# endif
MOZ_ASSERT ( mInstances . Contains ( aWorker ) ) ;
mInstances . RemoveElement ( aWorker ) ;
}
2015-10-25 23:30:16 +00:00
namespace {
class ChangeStateUpdater final : public nsRunnable
{
public :
ChangeStateUpdater ( const nsTArray < ServiceWorker * > & aInstances ,
ServiceWorkerState aState )
: mState ( aState )
{
for ( size_t i = 0 ; i < aInstances . Length ( ) ; + + i ) {
mInstances . AppendElement ( aInstances [ i ] ) ;
}
}
NS_IMETHODIMP Run ( )
{
// We need to update the state of all instances atomically before notifying
// them to make sure that the observed state for all instances inside
// statechange event handlers is correct.
for ( size_t i = 0 ; i < mInstances . Length ( ) ; + + i ) {
mInstances [ i ] - > SetState ( mState ) ;
}
for ( size_t i = 0 ; i < mInstances . Length ( ) ; + + i ) {
mInstances [ i ] - > DispatchStateChange ( mState ) ;
}
return NS_OK ;
}
private :
nsAutoTArray < RefPtr < ServiceWorker > , 1 > mInstances ;
ServiceWorkerState mState ;
} ;
}
2015-02-19 16:40:21 +00:00
void
ServiceWorkerInfo : : UpdateState ( ServiceWorkerState aState )
{
2015-11-24 15:47:59 +00:00
AssertIsOnMainThread ( ) ;
2015-02-19 16:40:21 +00:00
# ifdef DEBUG
// Any state can directly transition to redundant, but everything else is
// ordered.
if ( aState ! = ServiceWorkerState : : Redundant ) {
MOZ_ASSERT_IF ( mState = = ServiceWorkerState : : EndGuard_ , aState = = ServiceWorkerState : : Installing ) ;
MOZ_ASSERT_IF ( mState = = ServiceWorkerState : : Installing , aState = = ServiceWorkerState : : Installed ) ;
MOZ_ASSERT_IF ( mState = = ServiceWorkerState : : Installed , aState = = ServiceWorkerState : : Activating ) ;
MOZ_ASSERT_IF ( mState = = ServiceWorkerState : : Activating , aState = = ServiceWorkerState : : Activated ) ;
}
// Activated can only go to redundant.
MOZ_ASSERT_IF ( mState = = ServiceWorkerState : : Activated , aState = = ServiceWorkerState : : Redundant ) ;
# endif
2015-11-24 15:47:59 +00:00
// Flush any pending functional events to the worker when it transitions to the
// activated state.
// TODO: Do we care that these events will race with the propagation of the
// state change?
if ( aState = = ServiceWorkerState : : Activated & & mState ! = aState ) {
mServiceWorkerPrivate - > Activated ( ) ;
}
2015-02-19 16:40:21 +00:00
mState = aState ;
2015-10-25 23:30:16 +00:00
nsCOMPtr < nsIRunnable > r = new ChangeStateUpdater ( mInstances , mState ) ;
MOZ_ALWAYS_TRUE ( NS_SUCCEEDED ( NS_DispatchToMainThread ( r . forget ( ) ) ) ) ;
2015-02-19 16:40:21 +00:00
}
2015-05-14 19:41:42 +00:00
2015-09-30 23:11:03 +00:00
ServiceWorkerInfo : : ServiceWorkerInfo ( ServiceWorkerRegistrationInfo * aReg ,
const nsACString & aScriptSpec ,
const nsAString & aCacheName )
: mRegistration ( aReg )
, mScriptSpec ( aScriptSpec )
, mCacheName ( aCacheName )
, mState ( ServiceWorkerState : : EndGuard_ )
, mServiceWorkerID ( GetNextID ( ) )
2015-11-23 13:47:53 +00:00
, mServiceWorkerPrivate ( new ServiceWorkerPrivate ( this ) )
2015-09-30 23:11:03 +00:00
, mSkipWaitingFlag ( false )
{
MOZ_ASSERT ( mRegistration ) ;
MOZ_ASSERT ( ! aCacheName . IsEmpty ( ) ) ;
}
ServiceWorkerInfo : : ~ ServiceWorkerInfo ( )
{
MOZ_ASSERT ( mServiceWorkerPrivate ) ;
2015-09-30 23:11:03 +00:00
mServiceWorkerPrivate - > NoteDeadServiceWorkerInfo ( ) ;
2015-09-30 23:11:03 +00:00
}
2015-05-14 19:41:42 +00:00
static uint64_t gServiceWorkerInfoCurrentID = 0 ;
uint64_t
ServiceWorkerInfo : : GetNextID ( ) const
{
return + + gServiceWorkerInfoCurrentID ;
}
2013-11-19 23:15:02 +00:00
END_WORKERS_NAMESPACE