/* -*- 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 aResponse); enum EndReason { eAborted, eByNetworking, }; virtual void OnResponseEnd(EndReason aReason, JS::Handle 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 aResponse) = 0; nsCOMPtr 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 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& aController); void SetWorkerScript(const nsACString& aWorkerScript) { MOZ_ASSERT(!aWorkerScript.IsEmpty()); mWorkerScript = aWorkerScript; } void SetOriginStack(UniquePtr&& 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 mPrincipal; nsCOMPtr mLoadGroup; SafeRefPtr mRequest; SafeRefPtr mResponse; nsCOMPtr mPipeOutputStream; // Access to mObserver can be racy from OnDataAvailable and // FetchAbortActions. This must not be modified // in either of these functions. RefPtr mObserver; RefPtr mDocument; nsCOMPtr mCSPEventListener; Maybe mClientInfo; Maybe mController; nsCOMPtr mChannel; UniquePtr mSRIDataVerifier; nsCOMPtr mMainThreadEventTarget; nsCOMPtr mCookieJarSettings; // This is set only when Fetch is used in workers. RefPtr mPerformanceStorage; SRIMetadata mSRIMetadata; nsCString mWorkerScript; UniquePtr 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 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 mInterceptController; uint64_t mAssociatedBrowsingContextID{0}; friend class AlternativeDataStreamListener; FetchDriver() = delete; FetchDriver(const FetchDriver&) = delete; FetchDriver& operator=(const FetchDriver&) = delete; ~FetchDriver(); already_AddRefed FindPreload(nsIURI* aURI); void UpdateReferrerInfoFromNewChannel(nsIChannel* aChannel); nsresult HttpFetch(const nsACString& aPreferredAlternativeDataType = ""_ns); // Returns the filtered response sent to the observer. SafeRefPtr BeginAndGetFilteredResponse( SafeRefPtr 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