1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_FetchDriver_h 8 #define mozilla_dom_FetchDriver_h 9 10 #include "nsIChannelEventSink.h" 11 #include "nsIInterfaceRequestor.h" 12 #include "nsIStreamListener.h" 13 #include "nsIThreadRetargetableStreamListener.h" 14 #include "mozilla/ConsoleReportCollector.h" 15 #include "mozilla/dom/AbortSignal.h" 16 #include "mozilla/dom/SafeRefPtr.h" 17 #include "mozilla/dom/SerializedStackHolder.h" 18 #include "mozilla/dom/SRIMetadata.h" 19 #include "mozilla/RefPtr.h" 20 #include "mozilla/UniquePtr.h" 21 22 #include "mozilla/DebugOnly.h" 23 24 class nsIConsoleReportCollector; 25 class nsICookieJarSettings; 26 class nsICSPEventListener; 27 class nsIEventTarget; 28 class nsIOutputStream; 29 class nsILoadGroup; 30 class nsIPrincipal; 31 32 namespace mozilla { 33 namespace dom { 34 35 class Document; 36 class InternalRequest; 37 class InternalResponse; 38 class PerformanceStorage; 39 40 /** 41 * Provides callbacks to be called when response is available or on error. 42 * Implemenations usually resolve or reject the promise returned from fetch(). 43 * The callbacks can be called synchronously or asynchronously from 44 * FetchDriver::Fetch. 45 */ 46 class FetchDriverObserver { 47 public: FetchDriverObserver()48 FetchDriverObserver() 49 : mReporter(new ConsoleReportCollector()), mGotResponseAvailable(false) {} 50 51 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchDriverObserver); OnResponseAvailable(InternalResponse * aResponse)52 void OnResponseAvailable(InternalResponse* aResponse) { 53 MOZ_ASSERT(!mGotResponseAvailable); 54 mGotResponseAvailable = true; 55 OnResponseAvailableInternal(aResponse); 56 } 57 58 enum EndReason { 59 eAborted, 60 eByNetworking, 61 }; 62 OnResponseEnd(EndReason aReason)63 virtual void OnResponseEnd(EndReason aReason){}; 64 GetReporter()65 nsIConsoleReportCollector* GetReporter() const { return mReporter; } 66 67 virtual void FlushConsoleReport() = 0; 68 69 // Called in OnStartRequest() to determine if the OnDataAvailable() method 70 // needs to be called. Invoking that method may generate additional main 71 // thread runnables. 72 virtual bool NeedOnDataAvailable() = 0; 73 74 // Called once when the first byte of data is received iff 75 // NeedOnDataAvailable() returned true when called in OnStartRequest(). 76 virtual void OnDataAvailable() = 0; 77 78 protected: 79 virtual ~FetchDriverObserver() = default; 80 81 virtual void OnResponseAvailableInternal(InternalResponse* aResponse) = 0; 82 83 nsCOMPtr<nsIConsoleReportCollector> mReporter; 84 85 private: 86 bool mGotResponseAvailable; 87 }; 88 89 class AlternativeDataStreamListener; 90 91 class FetchDriver final : public nsIStreamListener, 92 public nsIChannelEventSink, 93 public nsIInterfaceRequestor, 94 public nsIThreadRetargetableStreamListener, 95 public AbortFollower { 96 public: 97 NS_DECL_THREADSAFE_ISUPPORTS 98 NS_DECL_NSIREQUESTOBSERVER 99 NS_DECL_NSISTREAMLISTENER 100 NS_DECL_NSICHANNELEVENTSINK 101 NS_DECL_NSIINTERFACEREQUESTOR 102 NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER 103 104 FetchDriver(SafeRefPtr<InternalRequest> aRequest, nsIPrincipal* aPrincipal, 105 nsILoadGroup* aLoadGroup, nsIEventTarget* aMainThreadEventTarget, 106 nsICookieJarSettings* aCookieJarSettings, 107 PerformanceStorage* aPerformanceStorage, bool aIsTrackingFetch); 108 109 nsresult Fetch(AbortSignalImpl* aSignalImpl, FetchDriverObserver* aObserver); 110 111 void SetDocument(Document* aDocument); 112 113 void SetCSPEventListener(nsICSPEventListener* aCSPEventListener); 114 115 void SetClientInfo(const ClientInfo& aClientInfo); 116 117 void SetController(const Maybe<ServiceWorkerDescriptor>& aController); 118 SetWorkerScript(const nsACString & aWorkerScript)119 void SetWorkerScript(const nsACString& aWorkerScript) { 120 MOZ_ASSERT(!aWorkerScript.IsEmpty()); 121 mWorkerScript = aWorkerScript; 122 } 123 SetOriginStack(UniquePtr<SerializedStackHolder> && aOriginStack)124 void SetOriginStack(UniquePtr<SerializedStackHolder>&& aOriginStack) { 125 mOriginStack = std::move(aOriginStack); 126 } 127 128 // AbortFollower 129 void Abort() override; 130 131 private: 132 nsCOMPtr<nsIPrincipal> mPrincipal; 133 nsCOMPtr<nsILoadGroup> mLoadGroup; 134 SafeRefPtr<InternalRequest> mRequest; 135 RefPtr<InternalResponse> mResponse; 136 nsCOMPtr<nsIOutputStream> mPipeOutputStream; 137 RefPtr<FetchDriverObserver> mObserver; 138 RefPtr<Document> mDocument; 139 nsCOMPtr<nsICSPEventListener> mCSPEventListener; 140 Maybe<ClientInfo> mClientInfo; 141 Maybe<ServiceWorkerDescriptor> mController; 142 nsCOMPtr<nsIChannel> mChannel; 143 UniquePtr<SRICheckDataVerifier> mSRIDataVerifier; 144 nsCOMPtr<nsIEventTarget> mMainThreadEventTarget; 145 146 nsCOMPtr<nsICookieJarSettings> mCookieJarSettings; 147 148 // This is set only when Fetch is used in workers. 149 RefPtr<PerformanceStorage> mPerformanceStorage; 150 151 SRIMetadata mSRIMetadata; 152 nsCString mWorkerScript; 153 UniquePtr<SerializedStackHolder> mOriginStack; 154 155 // This is written once in OnStartRequest on the main thread and then 156 // written/read in OnDataAvailable() on any thread. Necko guarantees 157 // that these do not overlap. 158 bool mNeedToObserveOnDataAvailable; 159 160 bool mIsTrackingFetch; 161 162 RefPtr<AlternativeDataStreamListener> mAltDataListener; 163 bool mOnStopRequestCalled; 164 165 // This flag is true when this fetch has found a matching preload and is being 166 // satisfied by a its response. 167 bool mFromPreload = false; 168 // This flag is set in call to Abort() and spans the possible window this 169 // fetch doesn't have mChannel (to be cancelled) between reuse of the matching 170 // preload, that has already finished and dropped reference to its channel, 171 // and OnStartRequest notification. It let's us cancel the load when we get 172 // the channel in OnStartRequest. 173 bool mAborted = false; 174 175 #ifdef DEBUG 176 bool mResponseAvailableCalled; 177 bool mFetchCalled; 178 #endif 179 180 friend class AlternativeDataStreamListener; 181 182 FetchDriver() = delete; 183 FetchDriver(const FetchDriver&) = delete; 184 FetchDriver& operator=(const FetchDriver&) = delete; 185 ~FetchDriver(); 186 187 already_AddRefed<PreloaderBase> FindPreload(nsIURI* aURI); 188 189 void UpdateReferrerInfoFromNewChannel(nsIChannel* aChannel); 190 191 nsresult HttpFetch( 192 const nsACString& aPreferredAlternativeDataType = EmptyCString()); 193 // Returns the filtered response sent to the observer. 194 already_AddRefed<InternalResponse> BeginAndGetFilteredResponse( 195 InternalResponse* aResponse, bool aFoundOpaqueRedirect); 196 // Utility since not all cases need to do any post processing of the filtered 197 // response. 198 void FailWithNetworkError(nsresult rv); 199 200 void SetRequestHeaders(nsIHttpChannel* aChannel, 201 bool aStripRequestBodyHeader) const; 202 203 void FinishOnStopRequest(AlternativeDataStreamListener* aAltDataListener); 204 }; 205 206 } // namespace dom 207 } // namespace mozilla 208 209 #endif // mozilla_dom_FetchDriver_h 210