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