diff options
Diffstat (limited to 'dom/fetch/FetchDriver.h')
-rw-r--r-- | dom/fetch/FetchDriver.h | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/dom/fetch/FetchDriver.h b/dom/fetch/FetchDriver.h new file mode 100644 index 0000000000..84391ef951 --- /dev/null +++ b/dom/fetch/FetchDriver.h @@ -0,0 +1,232 @@ +/* -*- 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_FetchDriver_h +#define mozilla_dom_FetchDriver_h + +#include "nsIChannelEventSink.h" +#include "nsIInterfaceRequestor.h" +#include "nsINetworkInterceptController.h" +#include "nsIStreamListener.h" +#include "nsIThreadRetargetableStreamListener.h" +#include "mozilla/ConsoleReportCollector.h" +#include "mozilla/dom/AbortSignal.h" +#include "mozilla/dom/SafeRefPtr.h" +#include "mozilla/dom/SerializedStackHolder.h" +#include "mozilla/dom/SRIMetadata.h" +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" + +#include "mozilla/DebugOnly.h" + +class nsIConsoleReportCollector; +class nsICookieJarSettings; +class nsICSPEventListener; +class nsIEventTarget; +class nsIOutputStream; +class nsILoadGroup; +class nsIPrincipal; + +namespace mozilla { +class PreloaderBase; + +namespace dom { + +class Document; +class InternalRequest; +class InternalResponse; +class PerformanceStorage; +class PerformanceTimingData; + +/** + * Provides callbacks to be called when response is available or on error. + * Implemenations usually resolve or reject the promise returned from fetch(). + * The callbacks can be called synchronously or asynchronously from + * FetchDriver::Fetch. + */ +class FetchDriverObserver { + public: + FetchDriverObserver() + : mReporter(new ConsoleReportCollector()), mGotResponseAvailable(false) {} + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchDriverObserver); + void OnResponseAvailable(SafeRefPtr<InternalResponse> aResponse); + + enum EndReason { + eAborted, + eByNetworking, + }; + + virtual void OnResponseEnd(EndReason aReason, + JS::Handle<JS::Value> aReasonDetails){}; + + nsIConsoleReportCollector* GetReporter() const { return mReporter; } + + virtual void FlushConsoleReport() = 0; + + // Called in OnStartRequest() to determine if the OnDataAvailable() method + // needs to be called. Invoking that method may generate additional main + // thread runnables. + virtual bool NeedOnDataAvailable() = 0; + + // Called once when the first byte of data is received iff + // NeedOnDataAvailable() returned true when called in OnStartRequest(). + virtual void OnDataAvailable() = 0; + + virtual void OnReportPerformanceTiming() {} + + virtual void OnNotifyNetworkMonitorAlternateStack(uint64_t aChannelID) {} + + protected: + virtual ~FetchDriverObserver() = default; + + virtual void OnResponseAvailableInternal( + SafeRefPtr<InternalResponse> aResponse) = 0; + + nsCOMPtr<nsIConsoleReportCollector> mReporter; + + private: + bool mGotResponseAvailable; +}; + +class AlternativeDataStreamListener; + +class FetchDriver final : public nsIStreamListener, + public nsIChannelEventSink, + public nsIInterfaceRequestor, + public nsINetworkInterceptController, + public nsIThreadRetargetableStreamListener, + public AbortFollower { + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSICHANNELEVENTSINK + NS_DECL_NSIINTERFACEREQUESTOR + NS_DECL_NSINETWORKINTERCEPTCONTROLLER + NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER + + FetchDriver(SafeRefPtr<InternalRequest> aRequest, nsIPrincipal* aPrincipal, + nsILoadGroup* aLoadGroup, nsIEventTarget* aMainThreadEventTarget, + nsICookieJarSettings* aCookieJarSettings, + PerformanceStorage* aPerformanceStorage, bool aIsTrackingFetch); + + nsresult Fetch(AbortSignalImpl* aSignalImpl, FetchDriverObserver* aObserver); + + void SetDocument(Document* aDocument); + + void SetCSPEventListener(nsICSPEventListener* aCSPEventListener); + + void SetClientInfo(const ClientInfo& aClientInfo); + + void SetController(const Maybe<ServiceWorkerDescriptor>& aController); + + void SetWorkerScript(const nsACString& aWorkerScript) { + MOZ_ASSERT(!aWorkerScript.IsEmpty()); + mWorkerScript = aWorkerScript; + } + + void SetOriginStack(UniquePtr<SerializedStackHolder>&& aOriginStack) { + mOriginStack = std::move(aOriginStack); + } + + PerformanceTimingData* GetPerformanceTimingData(nsAString& aInitiatorType, + nsAString& aEntryName); + + // AbortFollower + void RunAbortAlgorithm() override; + void FetchDriverAbortActions(AbortSignalImpl* aSignalImpl); + + void EnableNetworkInterceptControl(); + + void SetAssociatedBrowsingContextID(uint64_t aID) { + mAssociatedBrowsingContextID = aID; + } + + private: + nsCOMPtr<nsIPrincipal> mPrincipal; + nsCOMPtr<nsILoadGroup> mLoadGroup; + SafeRefPtr<InternalRequest> mRequest; + SafeRefPtr<InternalResponse> mResponse; + nsCOMPtr<nsIOutputStream> mPipeOutputStream; + // Access to mObserver can be racy from OnDataAvailable and + // FetchAbortActions. This must not be modified + // in either of these functions. + RefPtr<FetchDriverObserver> mObserver; + RefPtr<Document> mDocument; + nsCOMPtr<nsICSPEventListener> mCSPEventListener; + Maybe<ClientInfo> mClientInfo; + Maybe<ServiceWorkerDescriptor> mController; + nsCOMPtr<nsIChannel> mChannel; + UniquePtr<SRICheckDataVerifier> mSRIDataVerifier; + nsCOMPtr<nsIEventTarget> mMainThreadEventTarget; + + nsCOMPtr<nsICookieJarSettings> mCookieJarSettings; + + // This is set only when Fetch is used in workers. + RefPtr<PerformanceStorage> mPerformanceStorage; + + SRIMetadata mSRIMetadata; + nsCString mWorkerScript; + UniquePtr<SerializedStackHolder> mOriginStack; + + // This is written once in OnStartRequest on the main thread and then + // written/read in OnDataAvailable() on any thread. Necko guarantees + // that these do not overlap. + bool mNeedToObserveOnDataAvailable; + + bool mIsTrackingFetch; + + RefPtr<AlternativeDataStreamListener> mAltDataListener; + bool mOnStopRequestCalled; + + // This flag is true when this fetch has found a matching preload and is being + // satisfied by a its response. + bool mFromPreload = false; + // This flag is set in call to Abort() and spans the possible window this + // fetch doesn't have mChannel (to be cancelled) between reuse of the matching + // preload, that has already finished and dropped reference to its channel, + // and OnStartRequest notification. It let's us cancel the load when we get + // the channel in OnStartRequest. + bool mAborted = false; + +#ifdef DEBUG + bool mResponseAvailableCalled; + bool mFetchCalled; +#endif + nsCOMPtr<nsINetworkInterceptController> mInterceptController; + + uint64_t mAssociatedBrowsingContextID{0}; + + friend class AlternativeDataStreamListener; + + FetchDriver() = delete; + FetchDriver(const FetchDriver&) = delete; + FetchDriver& operator=(const FetchDriver&) = delete; + ~FetchDriver(); + + already_AddRefed<PreloaderBase> FindPreload(nsIURI* aURI); + + void UpdateReferrerInfoFromNewChannel(nsIChannel* aChannel); + + nsresult HttpFetch(const nsACString& aPreferredAlternativeDataType = ""_ns); + // Returns the filtered response sent to the observer. + SafeRefPtr<InternalResponse> BeginAndGetFilteredResponse( + SafeRefPtr<InternalResponse> aResponse, bool aFoundOpaqueRedirect); + // Utility since not all cases need to do any post processing of the filtered + // response. + void FailWithNetworkError(nsresult rv); + + void SetRequestHeaders(nsIHttpChannel* aChannel, bool aStripRequestBodyHeader, + bool aStripAuthHeader) const; + + void FinishOnStopRequest(AlternativeDataStreamListener* aAltDataListener); +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_FetchDriver_h |