forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			221 lines
		
	
	
	
		
			7.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
	
		
			7.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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 "nsIContentPolicy.h"
 | |
| #include "nsIInputStreamPump.h"
 | |
| #include "nsIStreamLoader.h"
 | |
| #include "nsStringFwd.h"
 | |
| #include "nsStreamUtils.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/cache/Cache.h"
 | |
| #include "mozilla/dom/cache/CacheStorage.h"
 | |
| #include "mozilla/dom/WorkerCommon.h"
 | |
| #include "mozilla/dom/WorkerRef.h"
 | |
| 
 | |
| #include "mozilla/dom/workerinternals/ScriptLoader.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);
 | |
|   void 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__ */
 | 
