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-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"
# 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"
# 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"
2016-04-06 20:27:22 +00:00
# include "ServiceWorkerJobQueue.h"
2015-06-04 18:51:57 +00:00
# include "ServiceWorkerManagerChild.h"
2015-09-30 23:11:03 +00:00
# include "ServiceWorkerPrivate.h"
2016-04-06 20:27:22 +00:00
# include "ServiceWorkerRegisterJob.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"
2016-04-06 20:27:22 +00:00
# include "ServiceWorkerUnregisterJob.h"
# include "ServiceWorkerUpdateJob.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. " ) ;
2016-01-13 23:15:37 +00:00
static_assert ( nsIHttpChannelInternal : : CORS_MODE_NAVIGATE = = static_cast < uint32_t > ( RequestMode : : Navigate ) ,
" RequestMode enumeration value should match Necko CORS mode value. " ) ;
2015-03-17 15:47:02 +00:00
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. " ) ;
2016-02-28 21:34:01 +00:00
static_assert ( nsIHttpChannelInternal : : FETCH_CACHE_MODE_DEFAULT = = static_cast < uint32_t > ( RequestCache : : Default ) ,
" RequestCache enumeration value should match Necko Cache mode value. " ) ;
static_assert ( nsIHttpChannelInternal : : FETCH_CACHE_MODE_NO_STORE = = static_cast < uint32_t > ( RequestCache : : No_store ) ,
" RequestCache enumeration value should match Necko Cache mode value. " ) ;
static_assert ( nsIHttpChannelInternal : : FETCH_CACHE_MODE_RELOAD = = static_cast < uint32_t > ( RequestCache : : Reload ) ,
" RequestCache enumeration value should match Necko Cache mode value. " ) ;
static_assert ( nsIHttpChannelInternal : : FETCH_CACHE_MODE_NO_CACHE = = static_cast < uint32_t > ( RequestCache : : No_cache ) ,
" RequestCache enumeration value should match Necko Cache mode value. " ) ;
static_assert ( nsIHttpChannelInternal : : FETCH_CACHE_MODE_FORCE_CACHE = = static_cast < uint32_t > ( RequestCache : : Force_cache ) ,
" RequestCache enumeration value should match Necko Cache mode value. " ) ;
static_assert ( 5 = = static_cast < uint32_t > ( RequestCache : : EndGuard_ ) ,
" RequestCache enumeration value should match Necko Cache 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.
2016-04-06 20:27:22 +00:00
nsRefPtrHashtable < nsCStringHashKey , ServiceWorkerJobQueue2 > 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-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 ;
}
2015-02-11 11:53:00 +00:00
if ( aRegistration - > mActiveWorker ) {
aData . currentWorkerURL ( ) = aRegistration - > mActiveWorker - > ScriptSpec ( ) ;
2016-01-13 01:31:23 +00:00
aData . cacheName ( ) = aRegistration - > mActiveWorker - > 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-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 ) ;
2016-01-15 17:37:34 +00:00
// It is ok to return null for a missing service worker info.
2015-12-15 11:10:53 +00:00
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
}
2016-04-06 20:27:22 +00:00
class ContinueActivateRunnable final : public LifeCycleEventCallback
2014-12-19 13:01:53 +00:00
{
2016-04-06 20:27:22 +00:00
nsMainThreadPtrHandle < ServiceWorkerRegistrationInfo > mRegistration ;
2014-12-19 10:00:29 +00:00
bool mSuccess ;
public :
2016-04-06 20:27:22 +00:00
explicit ContinueActivateRunnable ( const nsMainThreadPtrHandle < ServiceWorkerRegistrationInfo > & aRegistration )
: mRegistration ( aRegistration )
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 ( ) ;
2016-04-06 20:27:22 +00:00
mRegistration - > FinishActivate ( mSuccess ) ;
mRegistration = nullptr ;
2015-09-30 23:11:03 +00:00
return NS_OK ;
2015-09-30 18:11:47 +00:00
}
} ;
2016-04-06 20:27:22 +00:00
class ServiceWorkerResolveWindowPromiseOnRegisterCallback final : public ServiceWorkerJob2 : : Callback
2014-12-19 10:00:29 +00:00
{
2016-01-30 17:05:36 +00:00
RefPtr < nsPIDOMWindowInner > 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
2016-04-06 20:27:22 +00:00
~ ServiceWorkerResolveWindowPromiseOnRegisterCallback ( )
2015-11-23 13:47:53 +00:00
{ }
2014-06-11 16:12:56 +00:00
2016-04-06 20:27:22 +00:00
virtual void
JobFinished ( ServiceWorkerJob2 * aJob , ErrorResult & aStatus ) override
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aJob ) ;
if ( aStatus . Failed ( ) ) {
mPromise - > MaybeReject ( aStatus ) ;
return ;
}
2016-04-06 20:27:22 +00:00
MOZ_ASSERT ( aJob - > GetType ( ) = = ServiceWorkerJob2 : : Type : : Register ) ;
RefPtr < ServiceWorkerRegisterJob2 > registerJob =
static_cast < ServiceWorkerRegisterJob2 * > ( aJob ) ;
RefPtr < ServiceWorkerRegistrationInfo > reg = registerJob - > GetRegistration ( ) ;
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerRegistrationMainThread > swr =
2016-04-06 20:27:22 +00:00
mWindow - > GetServiceWorkerRegistration ( NS_ConvertUTF8toUTF16 ( reg - > mScope ) ) ;
2016-04-06 20:27:22 +00:00
mPromise - > MaybeResolve ( swr ) ;
}
2014-12-19 10:00:29 +00:00
public :
2016-04-06 20:27:22 +00:00
ServiceWorkerResolveWindowPromiseOnRegisterCallback ( nsPIDOMWindowInner * aWindow ,
Promise * aPromise )
2014-12-19 10:00:29 +00:00
: mWindow ( aWindow )
, mPromise ( aPromise )
2015-11-23 13:47:53 +00:00
{ }
2014-12-19 10:00:29 +00:00
2016-04-06 20:27:22 +00:00
NS_INLINE_DECL_REFCOUNTING ( ServiceWorkerResolveWindowPromiseOnRegisterCallback , override )
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-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
2016-01-30 17:05:36 +00:00
ServiceWorkerManager : : Register ( mozIDOMWindow * aWindow ,
2015-06-10 22:33:40 +00:00
nsIURI * aScopeURI ,
nsIURI * aScriptURI ,
nsISupports * * aPromise )
{
AssertIsOnMainThread ( ) ;
2016-01-30 17:05:36 +00:00
if ( NS_WARN_IF ( ! aWindow ) ) {
2015-11-05 17:33:33 +00:00
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
2015-06-10 22:33:40 +00:00
2016-01-30 17:05:36 +00:00
auto * window = nsPIDOMWindowInner : : From ( aWindow ) ;
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
2016-01-30 17:05:36 +00:00
nsCOMPtr < nsPIDOMWindowOuter > outerWindow = window - > GetOuterWindow ( ) ;
2015-06-10 22:33:40 +00:00
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 ) ) {
return NS_ERROR_DOM_SECURITY_ERR ;
}
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
}
2016-03-08 14:55:41 +00:00
nsAutoCString scopeKey ;
rv = PrincipalToScopeKey ( documentPrincipal , scopeKey ) ;
2015-06-03 08:43:43 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-11-16 16:04:11 +00:00
AddRegisteringDocument ( cleanedScope , doc ) ;
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerJobQueue2 > queue = GetOrCreateJobQueue ( scopeKey ,
cleanedScope ) ;
2014-12-19 10:00:29 +00:00
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerResolveWindowPromiseOnRegisterCallback > cb =
new ServiceWorkerResolveWindowPromiseOnRegisterCallback ( window , promise ) ;
2014-12-19 10:00:29 +00:00
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 ) ;
2016-03-28 17:28:15 +00:00
MOZ_ALWAYS_SUCCEEDS ( loadGroup - > SetNotificationCallbacks ( ir ) ) ;
2015-06-23 17:50:04 +00:00
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerRegisterJob2 > job =
new ServiceWorkerRegisterJob2 ( documentPrincipal , cleanedScope , spec ,
loadGroup ) ;
job - > AppendResultCallback ( cb ) ;
queue - > ScheduleJob ( job ) ;
2014-12-19 10:00:29 +00:00
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 ( nsIRunnable * aRunnable )
{
MOZ_ASSERT ( ! mActor ) ;
MOZ_ASSERT ( aRunnable ) ;
2015-06-23 12:56:29 +00:00
if ( ! mShuttingDown ) {
2016-04-06 20:27:22 +00:00
mPendingOperations . AppendElement ( aRunnable ) ;
2015-06-23 12:56:29 +00:00
}
2015-02-11 11:53:00 +00:00
}
2016-02-25 01:03:28 +00:00
void
ServiceWorkerRegistrationInfo : : TryToActivateAsync ( )
{
nsCOMPtr < nsIRunnable > r =
NS_NewRunnableMethod ( this ,
& ServiceWorkerRegistrationInfo : : TryToActivate ) ;
2016-03-28 17:28:15 +00:00
MOZ_ALWAYS_SUCCEEDS ( NS_DispatchToMainThread ( r ) ) ;
2016-02-25 01:03:28 +00:00
}
/*
* TryToActivate should not be called directly , use TryToACtivateAsync instead .
*/
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
{
2016-02-25 01:03:28 +00:00
if ( ! IsControllingDocuments ( ) | |
// Waiting worker will be removed if the registration is removed
( mWaitingWorker & & 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-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 */ ) ;
2016-04-06 20:27:22 +00:00
nsMainThreadPtrHandle < ServiceWorkerRegistrationInfo > handle (
new nsMainThreadPtrHolder < ServiceWorkerRegistrationInfo > ( this ) ) ;
RefPtr < LifeCycleEventCallback > callback = new ContinueActivateRunnable ( handle ) ;
2015-09-30 23:11:03 +00:00
ServiceWorkerPrivate * workerPrivate = mActiveWorker - > WorkerPrivate ( ) ;
2016-04-06 20:27:22 +00:00
MOZ_ASSERT ( workerPrivate ) ;
2015-09-30 23:11:03 +00:00
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 ) ) ) {
2016-03-28 17:28:15 +00:00
MOZ_ALWAYS_SUCCEEDS ( 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
{
2016-01-30 17:05:36 +00:00
nsCOMPtr < nsPIDOMWindowInner > mWindow ;
2015-10-18 05:24:48 +00:00
RefPtr < Promise > mPromise ;
2014-07-03 00:48:50 +00:00
public :
2016-01-30 17:05:36 +00:00
GetRegistrationsRunnable ( nsPIDOMWindowInner * aWindow , Promise * aPromise )
2014-12-19 10:00:29 +00:00
: 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
2016-01-30 17:05:36 +00:00
ServiceWorkerManager : : GetRegistrations ( mozIDOMWindow * aWindow ,
2014-12-19 10:00:29 +00:00
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
2016-01-30 17:05:36 +00:00
if ( NS_WARN_IF ( ! aWindow ) ) {
2015-11-05 17:33:33 +00:00
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
2015-05-29 16:17:33 +00:00
2016-01-30 17:05:36 +00:00
auto * window = nsPIDOMWindowInner : : From ( aWindow ) ;
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
{
2016-01-30 17:05:36 +00:00
nsCOMPtr < nsPIDOMWindowInner > 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 :
2016-01-30 17:05:36 +00:00
GetRegistrationRunnable ( nsPIDOMWindowInner * aWindow , Promise * aPromise ,
2014-12-19 10:00:29 +00:00
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
2016-01-30 17:05:36 +00:00
ServiceWorkerManager : : GetRegistration ( mozIDOMWindow * aWindow ,
2014-12-19 10:00:29 +00:00
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
2016-01-30 17:05:36 +00:00
if ( NS_WARN_IF ( ! aWindow ) ) {
2015-11-05 17:33:33 +00:00
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
2015-05-29 16:17:33 +00:00
2016-01-30 17:05:36 +00:00
auto * window = nsPIDOMWindowInner : : From ( aWindow ) ;
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
{
2016-01-30 17:05:36 +00:00
nsCOMPtr < nsPIDOMWindowInner > 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 :
2016-01-30 17:05:36 +00:00
GetReadyPromiseRunnable ( nsPIDOMWindowInner * aWindow , Promise * aPromise )
2014-12-19 10:00:29 +00:00
: 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 )
2016-01-14 05:19:51 +00:00
{
if ( optional_argc = = 2 ) {
nsTArray < uint8_t > data ;
if ( ! data . InsertElementsAt ( 0 , aDataBytes , aDataLength , fallible ) ) {
return NS_ERROR_OUT_OF_MEMORY ;
}
2016-03-28 18:50:39 +00:00
return SendPushEvent ( aOriginAttributes , aScope , EmptyString ( ) , Some ( data ) ) ;
2016-01-14 05:19:51 +00:00
}
MOZ_ASSERT ( optional_argc = = 0 ) ;
2016-03-28 18:50:39 +00:00
return SendPushEvent ( aOriginAttributes , aScope , EmptyString ( ) , Nothing ( ) ) ;
2016-01-14 05:19:51 +00:00
}
nsresult
ServiceWorkerManager : : SendPushEvent ( const nsACString & aOriginAttributes ,
const nsACString & aScope ,
2016-03-28 18:50:39 +00:00
const nsAString & aMessageId ,
const Maybe < nsTArray < uint8_t > > & aData )
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 ) ;
2016-03-28 18:50:39 +00:00
return serviceWorker - > WorkerPrivate ( ) - > SendPushEvent ( aMessageId , aData ,
registration ) ;
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
2016-01-30 17:05:36 +00:00
ServiceWorkerManager : : GetReadyPromise ( mozIDOMWindow * aWindow ,
2014-12-19 10:00:29 +00:00
nsISupports * * aPromise )
{
AssertIsOnMainThread ( ) ;
2016-01-30 17:05:36 +00:00
if ( NS_WARN_IF ( ! aWindow ) ) {
2015-11-05 17:33:33 +00:00
return NS_ERROR_DOM_INVALID_STATE_ERR ;
}
2015-05-29 16:17:33 +00:00
2016-01-30 17:05:36 +00:00
auto * window = nsPIDOMWindowInner : : From ( aWindow ) ;
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
2016-01-30 17:05:36 +00:00
ServiceWorkerManager : : RemoveReadyPromise ( mozIDOMWindow * 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
2016-01-30 17:05:36 +00:00
if ( ! aWindow ) {
2014-12-19 10:00:29 +00:00
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
2016-01-30 17:05:36 +00:00
ServiceWorkerManager : : StorePendingReadyPromise ( nsPIDOMWindowInner * aWindow ,
2014-12-19 10:00:29 +00:00
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 ( ) ) {
2016-01-30 17:05:36 +00:00
nsCOMPtr < nsPIDOMWindowInner > window = do_QueryInterface ( iter . Key ( ) ) ;
2015-11-19 08:03:29 +00:00
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
2016-01-30 17:05:36 +00:00
ServiceWorkerManager : : CheckReadyPromise ( nsPIDOMWindowInner * aWindow ,
2014-12-19 10:00:29 +00:00
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 ;
}
2016-03-08 14:55:41 +00:00
nsCOMPtr < nsIPrincipal > principal =
BasePrincipal : : CreateCodebasePrincipal ( scopeURI , aOriginAttributes ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2016-03-08 14:55:41 +00:00
GetServiceWorkerRegistrationInfo ( principal , 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
}
2016-04-06 20:27:22 +00:00
namespace {
class UnregisterJobCallback final : public ServiceWorkerJob2 : : Callback
{
nsCOMPtr < nsIServiceWorkerUnregisterCallback > mCallback ;
~ UnregisterJobCallback ( )
{
}
public :
explicit UnregisterJobCallback ( nsIServiceWorkerUnregisterCallback * aCallback )
: mCallback ( aCallback )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( mCallback ) ;
}
void
JobFinished ( ServiceWorkerJob2 * aJob , ErrorResult & aStatus )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aJob ) ;
if ( aStatus . Failed ( ) ) {
mCallback - > UnregisterFailed ( ) ;
return ;
}
MOZ_ASSERT ( aJob - > GetType ( ) = = ServiceWorkerJob2 : : Type : : Unregister ) ;
RefPtr < ServiceWorkerUnregisterJob2 > unregisterJob =
static_cast < ServiceWorkerUnregisterJob2 * > ( aJob ) ;
mCallback - > UnregisterSucceeded ( unregisterJob - > GetResult ( ) ) ;
}
NS_INLINE_DECL_REFCOUNTING ( UnregisterJobCallback )
} ;
} // anonymous namespace
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
2016-03-08 14:55:41 +00:00
nsAutoCString scopeKey ;
rv = PrincipalToScopeKey ( aPrincipal , scopeKey ) ;
2015-06-03 08:43:43 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
2015-01-22 22:10:38 +00:00
NS_ConvertUTF16toUTF8 scope ( aScope ) ;
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerJobQueue2 > queue = GetOrCreateJobQueue ( scopeKey , scope ) ;
2015-01-22 22:10:38 +00:00
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerUnregisterJob2 > job =
new ServiceWorkerUnregisterJob2 ( aPrincipal , scope , true /* send to parent */ ) ;
2015-02-11 11:53:00 +00:00
2016-04-06 20:27:22 +00:00
if ( aCallback ) {
RefPtr < UnregisterJobCallback > cb = new UnregisterJobCallback ( aCallback ) ;
job - > AppendResultCallback ( cb ) ;
2015-02-11 11:53:00 +00:00
}
2016-04-06 20:27:22 +00:00
queue - > ScheduleJob ( job ) ;
2015-01-22 22:10:38 +00:00
return NS_OK ;
2014-12-19 10:00:29 +00:00
}
2016-02-20 06:03:00 +00:00
nsresult
ServiceWorkerManager : : NotifyUnregister ( nsIPrincipal * aPrincipal ,
const nsAString & aScope )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aPrincipal ) ;
nsresult rv ;
// 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 ;
rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , aScope , nullptr , nullptr ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
# endif
2016-03-08 14:55:41 +00:00
nsAutoCString scopeKey ;
rv = PrincipalToScopeKey ( aPrincipal , scopeKey ) ;
2016-02-20 06:03:00 +00:00
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return rv ;
}
NS_ConvertUTF16toUTF8 scope ( aScope ) ;
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerJobQueue2 > queue = GetOrCreateJobQueue ( scopeKey , scope ) ;
2016-02-20 06:03:00 +00:00
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerUnregisterJob2 > job =
new ServiceWorkerUnregisterJob2 ( aPrincipal , scope ,
false /* send to parent */ ) ;
2016-02-20 06:03:00 +00:00
2016-04-06 20:27:22 +00:00
queue - > ScheduleJob ( job ) ;
2016-02-20 06:03:00 +00:00
return NS_OK ;
}
2016-04-06 20:27:22 +00:00
already_AddRefed < ServiceWorkerJobQueue2 >
2015-06-03 08:43:43 +00:00
ServiceWorkerManager : : GetOrCreateJobQueue ( const nsACString & aKey ,
const nsACString & aScope )
{
2016-03-08 14:55:41 +00:00
MOZ_ASSERT ( ! aKey . IsEmpty ( ) ) ;
2015-06-03 08:43:43 +00:00
ServiceWorkerManager : : RegistrationDataPerPrincipal * data ;
if ( ! mRegistrationInfos . Get ( aKey , & data ) ) {
data = new RegistrationDataPerPrincipal ( ) ;
mRegistrationInfos . Put ( aKey , data ) ;
}
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerJobQueue2 > queue ;
if ( ! data - > mJobQueues . Get ( aScope , getter_AddRefs ( queue ) ) ) {
RefPtr < ServiceWorkerJobQueue2 > newQueue = new ServiceWorkerJobQueue2 ( ) ;
queue = newQueue ;
data - > mJobQueues . Put ( aScope , newQueue . forget ( ) ) ;
2015-06-03 08:43:43 +00:00
}
2016-04-06 20:27:22 +00:00
return queue . forget ( ) ;
2015-06-03 08:43:43 +00:00
}
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 ;
2016-04-01 06:08:45 +00:00
nsresult rv ;
if ( ! aFilename . IsEmpty ( ) ) {
rv = NS_NewURI ( getter_AddRefs ( uri ) , aFilename ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
2015-11-16 16:04:11 +00:00
}
2016-02-02 15:36:30 +00:00
AutoTArray < uint64_t , 16 > windows ;
2015-11-16 16:04:11 +00:00
// 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 ,
2016-03-11 04:28:41 +00:00
aColumnNumber ,
nsContentUtils : : eOMIT_LOCATION ) ;
2015-11-16 16:04:11 +00:00
}
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 ,
2016-03-11 04:28:41 +00:00
aColumnNumber ,
nsContentUtils : : eOMIT_LOCATION ) ;
2015-11-16 16:04:11 +00:00
}
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 ,
2016-03-11 04:28:41 +00:00
aColumnNumber ,
nsContentUtils : : eOMIT_LOCATION ) ;
2015-11-16 16:04:11 +00:00
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 {
2016-01-15 02:27:01 +00:00
// If active worker script matches our expectations for a "current worker",
// then we are done.
if ( registration - > mActiveWorker & &
registration - > mActiveWorker - > ScriptSpec ( ) = = aRegistration . currentWorkerURL ( ) ) {
2015-12-11 19:53:10 +00:00
// 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 =
2016-03-15 14:29:56 +00:00
new ServiceWorkerInfo ( registration - > mPrincipal , registration - > mScope ,
currentWorkerURL , aRegistration . cacheName ( ) ) ;
2015-06-04 18:51:57 +00:00
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
2016-01-13 00:04:18 +00:00
if ( mShuttingDown ) {
mPendingOperations . Clear ( ) ;
return ;
}
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 ) {
2016-04-06 20:27:22 +00:00
MOZ_ASSERT ( mPendingOperations [ i ] ) ;
nsresult rv = NS_DispatchToCurrentThread ( mPendingOperations [ i ] . forget ( ) ) ;
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " Failed to dispatch a runnable. " ) ;
2015-02-11 11:53:00 +00:00
}
}
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 >
2016-01-30 17:05:36 +00:00
ServiceWorkerManager : : GetServiceWorkerRegistrationInfo ( nsPIDOMWindowInner * 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 ;
}
2016-03-08 14:55:41 +00:00
nsAutoCString scopeKey ;
nsresult rv = PrincipalToScopeKey ( aPrincipal , scopeKey ) ;
2015-06-11 16:47:46 +00:00
if ( NS_FAILED ( rv ) ) {
2015-06-03 08:43:43 +00:00
return nullptr ;
}
2016-03-08 14:55:41 +00:00
return GetServiceWorkerRegistrationInfo ( scopeKey , aURI ) ;
2015-06-03 08:43:43 +00:00
}
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
2016-03-08 14:55:41 +00:00
nsAutoCString origin ;
rv = registration - > mPrincipal - > GetOrigin ( origin ) ;
2015-06-03 08:43:43 +00:00
MOZ_ASSERT ( NS_SUCCEEDED ( rv ) ) ;
2016-03-08 14:55:41 +00:00
MOZ_ASSERT ( origin . Equals ( aScopeKey ) ) ;
2015-06-03 08:43:43 +00:00
# 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 ;
}
2016-03-08 14:55:41 +00:00
nsresult rv = aPrincipal - > GetOrigin ( aKey ) ;
2015-06-03 08:43:43 +00:00
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 ;
}
2016-03-08 14:55:41 +00:00
MOZ_ASSERT ( ! scopeKey . IsEmpty ( ) ) ;
2015-06-03 08:43:43 +00:00
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 ) ;
}
2016-02-10 03:33:40 +00:00
// The registration should generally only be removed if there are no controlled
// documents, but mControlledDocuments can contain references to potentially
// controlled docs. This happens when the service worker is not active yet.
// We must purge these references since we are evicting the registration.
for ( auto iter = swm - > mControlledDocuments . Iter ( ) ; ! iter . Done ( ) ; iter . Next ( ) ) {
ServiceWorkerRegistrationInfo * reg = iter . UserData ( ) ;
MOZ_ASSERT ( reg ) ;
if ( reg - > mScope . Equals ( aRegistration - > mScope ) ) {
iter . Remove ( ) ;
}
}
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 ) {
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 ( ) ;
}
2016-02-25 01:03:28 +00:00
aRegistration - > TryToActivateAsync ( ) ;
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
*/
2016-01-30 17:05:36 +00:00
nsresult
ServiceWorkerManager : : GetServiceWorkerForScope ( nsPIDOMWindowInner * aWindow ,
2014-08-25 05:35:03 +00:00
const nsAString & aScope ,
WhichServiceWorker aWhichWorker ,
nsISupports * * aServiceWorker )
2014-07-23 21:05:08 +00:00
{
2014-08-25 05:35:03 +00:00
AssertIsOnMainThread ( ) ;
2016-01-30 17:05:36 +00:00
if ( NS_WARN_IF ( ! aWindow ) ) {
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
2016-01-30 17:05:36 +00:00
nsCOMPtr < nsIDocument > doc = aWindow - > GetExtantDoc ( ) ;
2014-08-25 05:35:03 +00:00
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 ;
}
2016-03-04 00:37:57 +00:00
RefPtr < ServiceWorker > serviceWorker = info - > GetOrCreateInstance ( aWindow ) ;
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
2016-01-04 22:40:04 +00:00
void
ServiceWorkerManager : : DispatchFetchEvent ( const PrincipalOriginAttributes & aOriginAttributes ,
nsIDocument * aDoc ,
const nsAString & aDocumentIdForTopLevelNavigation ,
nsIInterceptedChannel * aChannel ,
bool aIsReload ,
bool aIsSubresourceLoad ,
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 ) ) ) {
2016-01-04 22:40:04 +00:00
return ;
2015-11-25 23:05:34 +00:00
}
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 ( ) ) ) {
2016-01-04 22:40:04 +00:00
return ;
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 ) ) ;
2016-01-08 20:53:38 +00:00
// TODO: Use aDocumentIdForTopLevelNavigation for potentialClientId, pending
// the spec change.
2015-11-25 23:05:34 +00:00
2015-02-19 01:34:29 +00:00
nsCOMPtr < nsIURI > uri ;
2015-11-02 16:27:00 +00:00
aRv = aChannel - > GetSecureUpgradedChannelURI ( getter_AddRefs ( uri ) ) ;
2015-06-03 08:43:43 +00:00
if ( NS_WARN_IF ( aRv . Failed ( ) ) ) {
2016-01-04 22:40:04 +00:00
return ;
2015-06-03 08:43:43 +00:00
}
2015-02-19 01:34:29 +00:00
2016-03-08 14:55:41 +00:00
// non-subresource request means the URI contains the principal
nsCOMPtr < nsIPrincipal > principal =
BasePrincipal : : CreateCodebasePrincipal ( uri , aOriginAttributes ) ;
2015-10-18 05:24:48 +00:00
RefPtr < ServiceWorkerRegistrationInfo > registration =
2016-03-08 14:55:41 +00:00
GetServiceWorkerRegistrationInfo ( principal , 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 ) ;
2016-01-04 22:40:04 +00:00
return ;
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 ) {
2016-01-04 22:40:04 +00:00
return ;
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
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 ) {
2016-03-28 17:28:15 +00:00
MOZ_ALWAYS_SUCCEEDS ( continueRunnable - > 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.
2016-01-04 22:40:04 +00:00
aRv = uploadChannel - > EnsureUploadStreamIsCloneable ( continueRunnable ) ;
2015-02-19 01:34:29 +00:00
}
2015-06-03 08:43:43 +00:00
bool
2016-03-08 14:55:41 +00:00
ServiceWorkerManager : : IsAvailable ( nsIPrincipal * aPrincipal ,
2015-06-26 18:18:18 +00:00
nsIURI * aURI )
2015-02-19 01:34:29 +00:00
{
2016-03-08 14:55:41 +00:00
MOZ_ASSERT ( aPrincipal ) ;
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 =
2016-03-08 14:55:41 +00:00
GetServiceWorkerRegistrationInfo ( aPrincipal , aURI ) ;
2015-06-03 08:43:43 +00:00
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
2016-04-01 21:17:07 +00:00
if ( nsContentUtils : : IsInPrivateBrowsing ( aDoc ) ) {
// Handle the case where a service worker was previously registered in
// a non-private window (bug 1255621).
return false ;
}
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
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
2016-01-30 17:05:36 +00:00
ServiceWorkerManager : : GetDocumentController ( nsPIDOMWindowInner * aWindow ,
2015-07-15 19:21:40 +00:00
nsISupports * * aServiceWorker )
2014-07-23 21:05:08 +00:00
{
2016-01-30 17:05:36 +00:00
MOZ_ASSERT ( aWindow ) ;
nsCOMPtr < nsIDocument > doc = aWindow - > GetExtantDoc ( ) ;
if ( ! doc ) {
2015-11-05 17:33:33 +00:00
return NS_ERROR_DOM_INVALID_STATE_ERR ;
2014-07-23 21:05:08 +00:00
}
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 =
2016-03-04 00:37:57 +00:00
registration - > mActiveWorker - > GetOrCreateInstance ( aWindow ) ;
2014-07-23 21:05:08 +00:00
serviceWorker . forget ( aServiceWorker ) ;
return NS_OK ;
}
NS_IMETHODIMP
2016-01-30 17:05:36 +00:00
ServiceWorkerManager : : GetInstalling ( nsPIDOMWindowInner * 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
2016-01-30 17:05:36 +00:00
ServiceWorkerManager : : GetWaiting ( nsPIDOMWindowInner * 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
2016-01-30 17:05:36 +00:00
ServiceWorkerManager : : GetActive ( nsPIDOMWindowInner * aWindow ,
2014-08-25 05:35:03 +00:00
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-12-18 16:04:39 +00:00
ServiceWorkerManager : : SoftUpdate ( const PrincipalOriginAttributes & aOriginAttributes ,
2015-11-26 17:03:10 +00:00
const nsACString & aScope )
2015-06-03 08:43:43 +00:00
{
2015-11-26 17:03:10 +00:00
AssertIsOnMainThread ( ) ;
2015-12-18 16:04:39 +00:00
2016-01-13 00:04:18 +00:00
if ( mShuttingDown ) {
return ;
}
2015-12-18 16:04:39 +00:00
nsCOMPtr < nsIURI > scopeURI ;
nsresult rv = NS_NewURI ( getter_AddRefs ( scopeURI ) , aScope ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
nsCOMPtr < nsIPrincipal > principal =
BasePrincipal : : CreateCodebasePrincipal ( scopeURI , aOriginAttributes ) ;
if ( NS_WARN_IF ( ! principal ) ) {
return ;
}
2015-06-03 08:43:43 +00:00
nsAutoCString scopeKey ;
2016-03-08 14:55:41 +00:00
rv = PrincipalToScopeKey ( principal , scopeKey ) ;
if ( NS_WARN_IF ( NS_FAILED ( rv ) ) ) {
return ;
}
2015-11-26 17:03:10 +00:00
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 ) {
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerJobQueue2 > queue = GetOrCreateJobQueue ( scopeKey ,
aScope ) ;
2015-11-16 16:04:11 +00:00
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerUpdateJob2 > job =
new ServiceWorkerUpdateJob2 ( principal , registration - > mScope ,
newest - > ScriptSpec ( ) , nullptr ) ;
queue - > ScheduleJob ( job ) ;
2015-11-26 17:03:10 +00:00
}
}
2015-11-16 16:04:11 +00:00
2016-04-06 20:27:22 +00:00
namespace {
class UpdateJobCallback final : public ServiceWorkerJob2 : : Callback
{
RefPtr < ServiceWorkerUpdateFinishCallback > mCallback ;
~ UpdateJobCallback ( )
{
}
public :
explicit UpdateJobCallback ( ServiceWorkerUpdateFinishCallback * aCallback )
: mCallback ( aCallback )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( mCallback ) ;
}
void
JobFinished ( ServiceWorkerJob2 * aJob , ErrorResult & aStatus )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aJob ) ;
if ( aStatus . Failed ( ) ) {
mCallback - > UpdateFailed ( aStatus ) ;
return ;
}
MOZ_ASSERT ( aJob - > GetType ( ) = = ServiceWorkerJob2 : : Type : : Update ) ;
RefPtr < ServiceWorkerUpdateJob2 > updateJob =
static_cast < ServiceWorkerUpdateJob2 * > ( aJob ) ;
RefPtr < ServiceWorkerRegistrationInfo > reg = updateJob - > GetRegistration ( ) ;
mCallback - > UpdateSucceeded ( reg ) ;
}
NS_INLINE_DECL_REFCOUNTING ( UpdateJobCallback )
} ;
} // anonymous namespace
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
// "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
}
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerJobQueue2 > queue = GetOrCreateJobQueue ( scopeKey , aScope ) ;
2014-12-19 10:00:29 +00:00
2015-03-20 01:09:10 +00:00
// "Invoke Update algorithm, or its equivalent, with client, registration as
// its argument."
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerUpdateJob2 > job =
new ServiceWorkerUpdateJob2 ( aPrincipal , registration - > mScope ,
newest - > ScriptSpec ( ) , nullptr ) ;
RefPtr < UpdateJobCallback > cb = new UpdateJobCallback ( aCallback ) ;
job - > AppendResultCallback ( cb ) ;
queue - > ScheduleJob ( 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 ) ;
2016-01-30 17:05:36 +00:00
nsCOMPtr < nsPIDOMWindowInner > w = aDocument - > GetInnerWindow ( ) ;
2015-11-16 16:41:57 +00:00
if ( ! w ) {
NS_WARNING ( " Failed to dispatch controllerchange event " ) ;
return ;
}
2016-01-30 17:05:36 +00:00
auto * window = nsGlobalWindow : : Cast ( w . get ( ) ) ;
2015-05-14 19:41:42 +00:00
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 ) {
2016-02-25 01:03:28 +00:00
registration - > TryToActivateAsync ( ) ;
2015-06-02 11:12:00 +00:00
}
} 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 ) ) {
2015-02-10 22:33:23 +00:00
RemoveRegistration ( aRegistration ) ;
}
}
2015-02-11 18:51:32 +00:00
void
2016-02-15 12:40:00 +00:00
ServiceWorkerManager : : RemoveRegistration ( ServiceWorkerRegistrationInfo * aRegistration )
2015-02-11 18:51:32 +00:00
{
2016-02-15 12:40:00 +00:00
// Note, we do not need to call mActor->SendUnregister() here. There are a few
// ways we can get here:
// 1) Through a normal unregister which calls SendUnregister() in the unregister
// job Start() method.
// 2) Through origin storage being purged. These result in ForceUnregister()
// starting unregister jobs which in turn call SendUnregister().
// 3) Through the failure to install a new service worker. Since we don't store
// the registration until install succeeds, we do not need to call
// SendUnregister here.
// Assert these conditions by testing for pending uninstall (cases 1 and 2) or
// null workers (case 3).
# ifdef DEBUG
RefPtr < ServiceWorkerInfo > newest = aRegistration - > Newest ( ) ;
MOZ_ASSERT ( aRegistration - > mPendingUninstall | | ! newest ) ;
# endif
2015-02-11 18:51:32 +00:00
2016-02-15 12:40:00 +00:00
MOZ_ASSERT ( HasScope ( aRegistration - > mPrincipal , aRegistration - > mScope ) ) ;
2015-06-03 08:43:43 +00:00
2016-02-15 12:40:00 +00:00
// When a registration is removed, we must clear its contents since the DOM
// object may be held by content script.
aRegistration - > Clear ( ) ;
2015-02-19 16:40:21 +00:00
2015-06-03 08:43:43 +00:00
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 ) ;
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerJobQueue2 > queue ;
aRegistrationData - > mJobQueues . Get ( aRegistration - > mScope , getter_AddRefs ( queue ) ) ;
2015-06-03 08:43:43 +00:00
if ( queue ) {
2016-04-06 20:27:22 +00:00
queue - > CancelAll ( ) ;
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-12-18 10:58:41 +00:00
ServiceWorkerManager : : RemoveAllRegistrations ( OriginAttributesPattern * aPattern )
2015-06-11 17:42:38 +00:00
{
AssertIsOnMainThread ( ) ;
2015-12-18 10:58:41 +00:00
MOZ_ASSERT ( aPattern ) ;
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 ) ;
2015-12-18 10:58:41 +00:00
bool matches =
aPattern - > Matches ( BasePrincipal : : Cast ( reg - > mPrincipal ) - > OriginAttributesRef ( ) ) ;
if ( ! matches ) {
continue ;
2015-10-26 04:35:44 +00:00
}
2015-12-18 10:58:41 +00:00
RefPtr < ServiceWorkerManager > swm = ServiceWorkerManager : : GetInstance ( ) ;
swm - > ForceUnregister ( data , reg ) ;
2015-10-26 04:35:44 +00:00
}
}
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
2016-01-30 17:05:36 +00:00
ServiceWorkerManager : : ShouldReportToWindow ( mozIDOMWindowProxy * aWindow ,
2015-11-16 16:04:11 +00:00
const nsACString & aScope ,
bool * aResult )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aResult ) ;
* aResult = false ;
// Get the inner window ID to compare to our document windows below.
2016-01-30 17:05:36 +00:00
nsCOMPtr < nsPIDOMWindowOuter > targetWin = nsPIDOMWindowOuter : : From ( aWindow ) ;
2015-11-16 16:04:11 +00:00
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 ;
}
2016-01-30 17:05:36 +00:00
nsCOMPtr < nsPIDOMWindowOuter > win = doc - > GetWindow ( ) ;
2015-11-16 16:04:11 +00:00
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 ;
}
2016-01-30 17:05:36 +00:00
nsCOMPtr < nsPIDOMWindowInner > win = nsGlobalWindow : : GetInnerWindowWithId ( id ) - > AsInner ( ) ;
2015-11-16 16:04:11 +00:00
if ( ! win ) {
continue ;
}
2016-01-30 17:05:36 +00:00
nsCOMPtr < nsPIDOMWindowOuter > outer = win - > GetScriptableTop ( ) ;
2015-11-16 16:04:11 +00:00
// Match. We should report to this window.
2016-01-30 17:05:36 +00:00
if ( outer & & winId = = outer - > WindowID ( ) ) {
2015-11-16 16:04:11 +00:00
* 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 ;
}
2016-01-30 17:05:36 +00:00
nsCOMPtr < nsPIDOMWindowOuter > win = doc - > GetWindow ( ) ;
2015-11-16 16:04:11 +00:00
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-12-18 10:58:41 +00:00
OriginAttributesPattern pattern ;
MOZ_ALWAYS_TRUE ( pattern . Init ( nsAutoString ( aData ) ) ) ;
2015-06-11 17:42:38 +00:00
2015-12-18 10:58:41 +00:00
RemoveAllRegistrations ( & pattern ) ;
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 ( ) ;
2016-01-13 00:04:18 +00:00
for ( auto it2 = it1 . UserData ( ) - > mJobQueues . Iter ( ) ; ! it2 . Done ( ) ; it2 . Next ( ) ) {
2016-04-06 20:27:22 +00:00
RefPtr < ServiceWorkerJobQueue2 > queue = it2 . UserData ( ) ;
queue - > CancelAll ( ) ;
2016-01-13 00:04:18 +00:00
}
it1 . UserData ( ) - > mJobQueues . Clear ( ) ;
2015-12-11 19:53:10 +00:00
}
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 ;
2016-01-13 00:04:18 +00:00
} else {
mPendingOperations . Clear ( ) ;
2015-06-23 12:56:29 +00:00
}
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 =
2015-12-18 10:58:41 +00:00
BasePrincipal : : Cast ( aPrincipal ) - > OriginAttributesRef ( ) ;
2015-12-11 19:53:10 +00:00
2016-01-13 00:04:18 +00:00
SoftUpdate ( attrs , aScope ) ;
2015-12-11 19:53:10 +00:00
}
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 :
2016-02-02 15:36:30 +00:00
AutoTArray < RefPtr < ServiceWorker > , 1 > mInstances ;
2015-10-25 23:30:16 +00:00
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 ) ;
2016-03-28 17:28:15 +00:00
MOZ_ALWAYS_SUCCEEDS ( NS_DispatchToMainThread ( r . forget ( ) ) ) ;
2015-02-19 16:40:21 +00:00
}
2015-05-14 19:41:42 +00:00
2016-03-15 14:29:56 +00:00
ServiceWorkerInfo : : ServiceWorkerInfo ( nsIPrincipal * aPrincipal ,
const nsACString & aScope ,
2015-09-30 23:11:03 +00:00
const nsACString & aScriptSpec ,
const nsAString & aCacheName )
2016-03-15 14:29:56 +00:00
: mPrincipal ( aPrincipal )
, mScope ( aScope )
2015-09-30 23:11:03 +00:00
, 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 )
{
2016-03-15 14:29:56 +00:00
MOZ_ASSERT ( mPrincipal ) ;
MOZ_ASSERT ( ! mScope . IsEmpty ( ) ) ;
MOZ_ASSERT ( ! mScriptSpec . IsEmpty ( ) ) ;
MOZ_ASSERT ( ! mCacheName . IsEmpty ( ) ) ;
2015-09-30 23:11:03 +00:00
}
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 ;
}
2016-03-04 00:37:57 +00:00
already_AddRefed < ServiceWorker >
ServiceWorkerInfo : : GetOrCreateInstance ( nsPIDOMWindowInner * aWindow )
{
AssertIsOnMainThread ( ) ;
MOZ_ASSERT ( aWindow ) ;
RefPtr < ServiceWorker > ref ;
for ( uint32_t i = 0 ; i < mInstances . Length ( ) ; + + i ) {
MOZ_ASSERT ( mInstances [ i ] ) ;
if ( mInstances [ i ] - > GetOwner ( ) = = aWindow ) {
ref = mInstances [ i ] ;
break ;
}
}
if ( ! ref ) {
ref = new ServiceWorker ( aWindow , this ) ;
}
return ref . forget ( ) ;
}
2013-11-19 23:15:02 +00:00
END_WORKERS_NAMESPACE