1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_workers_CacheLoadHandler_h__
#define mozilla_dom_workers_CacheLoadHandler_h__
#include "mozilla/StaticPrefs_browser.h"
#include "mozilla/dom/CacheBinding.h"
#include "mozilla/dom/ChannelInfo.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/ScriptLoadHandler.h"
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/dom/WorkerRef.h"
#include "mozilla/dom/cache/Cache.h"
#include "mozilla/dom/cache/CacheStorage.h"
#include "mozilla/dom/workerinternals/ScriptLoader.h"
#include "nsIContentPolicy.h"
#include "nsIInputStreamPump.h"
#include "nsIStreamLoader.h"
#include "nsStreamUtils.h"
#include "nsStringFwd.h"
using mozilla::dom::cache::Cache;
using mozilla::dom::cache::CacheStorage;
using mozilla::ipc::PrincipalInfo;
namespace mozilla::dom {
class WorkerLoadContext;
namespace workerinternals::loader {
/*
* [DOMDOC] CacheLoadHandler for Workers
*
* A LoadHandler is a ScriptLoader helper class that reacts to an
* nsIStreamLoader's events for loading JS scripts. It is primarily responsible
* for decoding the stream into UTF8 or UTF16. Additionally, it takes care of
* any work that needs to follow the completion of a stream. Every LoadHandler
* also manages additional tasks for the type of load that it is doing.
*
* CacheLoadHandler is a specialized LoadHandler used by ServiceWorkers to
* implement the installation model used by ServiceWorkers to support running
* offline. When a ServiceWorker is installed, its main script is evaluated and
* all script resources that are loaded are saved. The spec does not specify the
* storage mechanism for this, but we chose to reuse the Cache API[1] mechanism
* that we expose to content to also store the script and its dependencies. We
* store the script resources in a special chrome namespace CacheStorage that is
* not visible to content. Each distinct ServiceWorker installation gets its own
* Cache keyed by a randomly-generated UUID.
*
* In terms of specification, this class implements step 4 of
* https://w3c.github.io/ServiceWorker/#importscripts
*
* Relationship to NetworkLoadHandler
*
* During ServiceWorker installation, the CacheLoadHandler falls back on the
* NetworkLoadHandler by calling `mLoader->LoadScript(...)`. If a script has not
* been seen before, then we will fall back on loading from the network.
* However, if the ServiceWorker is already installed, an error will be
* generated and the ServiceWorker will fail to load, per spec.
*
* CacheLoadHandler does not persist some pieces of information, such as the
* sourceMapUrl. Also, the DOM Cache API storage does not yet support alternate
* data streams for JS Bytecode or WASM caching; this is tracked by Bug 1336199.
*
* [1]: https://developer.mozilla.org/en-US/docs/Web/API/caches
*
*/
class CacheLoadHandler final : public PromiseNativeHandler,
public nsIStreamLoaderObserver {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLOADEROBSERVER
CacheLoadHandler(ThreadSafeWorkerRef* aWorkerRef,
ThreadSafeRequestHandle* aRequestHandle,
bool aIsWorkerScript,
bool aOnlyExistingCachedResourcesAllowed,
WorkerScriptLoader* aLoader);
void Fail(nsresult aRv);
void Load(Cache* aCache);
virtual void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
ErrorResult& aRv) override;
virtual void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
ErrorResult& aRv) override;
private:
~CacheLoadHandler() { AssertIsOnMainThread(); }
nsresult DataReceivedFromCache(const uint8_t* aString, uint32_t aStringLen,
const mozilla::dom::ChannelInfo& aChannelInfo,
UniquePtr<PrincipalInfo> aPrincipalInfo,
const nsACString& aCSPHeaderValue,
const nsACString& aCSPReportOnlyHeaderValue,
const nsACString& aReferrerPolicyHeaderValue);
nsresult DataReceived();
RefPtr<ThreadSafeRequestHandle> mRequestHandle;
const RefPtr<WorkerScriptLoader> mLoader;
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
const bool mIsWorkerScript;
bool mFailed;
bool mOnlyExistingCachedResourcesAllowed;
nsCOMPtr<nsIInputStreamPump> mPump;
nsCOMPtr<nsIURI> mBaseURI;
mozilla::dom::ChannelInfo mChannelInfo;
UniquePtr<PrincipalInfo> mPrincipalInfo;
UniquePtr<ScriptDecoder> mDecoder;
nsCString mCSPHeaderValue;
nsCString mCSPReportOnlyHeaderValue;
nsCString mReferrerPolicyHeaderValue;
nsCOMPtr<nsISerialEventTarget> mMainThreadEventTarget;
};
/*
* CacheCreator
*
* The CacheCreator is responsible for maintaining a CacheStorage for the
* purposes of caching ServiceWorkers (see comment on CacheLoadHandler). In
* addition, it tracks all CacheLoadHandlers and is used for cleanup once
* loading has finished.
*
*/
class CacheCreator final : public PromiseNativeHandler {
public:
NS_DECL_ISUPPORTS
explicit CacheCreator(WorkerPrivate* aWorkerPrivate);
void AddLoader(MovingNotNull<RefPtr<CacheLoadHandler>> aLoader) {
AssertIsOnMainThread();
MOZ_ASSERT(!mCacheStorage);
mLoaders.AppendElement(std::move(aLoader));
}
virtual void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
ErrorResult& aRv) override;
virtual void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
ErrorResult& aRv) override;
// Try to load from cache with aPrincipal used for cache access.
nsresult Load(nsIPrincipal* aPrincipal);
Cache* Cache_() const {
AssertIsOnMainThread();
MOZ_ASSERT(mCache);
return mCache;
}
nsIGlobalObject* Global() const {
AssertIsOnMainThread();
MOZ_ASSERT(mSandboxGlobalObject);
return mSandboxGlobalObject;
}
void DeleteCache(nsresult aReason);
private:
~CacheCreator() = default;
nsresult CreateCacheStorage(nsIPrincipal* aPrincipal);
void FailLoaders(nsresult aRv);
RefPtr<Cache> mCache;
RefPtr<CacheStorage> mCacheStorage;
nsCOMPtr<nsIGlobalObject> mSandboxGlobalObject;
nsTArray<NotNull<RefPtr<CacheLoadHandler>>> mLoaders;
nsString mCacheName;
OriginAttributes mOriginAttributes;
};
/*
* CachePromiseHandler
*
* This promise handler is used to track if a ServiceWorker has been written to
* Cache. It is responsible for tracking the state of the ServiceWorker being
* cached. It also handles cancelling caching of a ServiceWorker if loading is
* interrupted. It is initialized by the NetworkLoadHandler as part of the first
* load of a ServiceWorker.
*
*/
class CachePromiseHandler final : public PromiseNativeHandler {
public:
NS_DECL_ISUPPORTS
CachePromiseHandler(WorkerScriptLoader* aLoader,
ThreadSafeRequestHandle* aRequestHandle);
virtual void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
ErrorResult& aRv) override;
virtual void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
ErrorResult& aRv) override;
private:
~CachePromiseHandler() { AssertIsOnMainThread(); }
RefPtr<WorkerScriptLoader> mLoader;
RefPtr<ThreadSafeRequestHandle> mRequestHandle;
};
} // namespace workerinternals::loader
} // namespace mozilla::dom
#endif /* mozilla_dom_workers_CacheLoadHandler_h__ */
|