1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 #ifndef mozilla_net_HttpChannelChild_h
9 #define mozilla_net_HttpChannelChild_h
10
11 #include "mozilla/Mutex.h"
12 #include "mozilla/Telemetry.h"
13 #include "mozilla/UniquePtr.h"
14 #include "mozilla/net/HttpBaseChannel.h"
15 #include "mozilla/net/NeckoTargetHolder.h"
16 #include "mozilla/net/PHttpChannelChild.h"
17 #include "mozilla/net/ChannelEventQueue.h"
18
19 #include "nsIStreamListener.h"
20 #include "nsILoadGroup.h"
21 #include "nsIInterfaceRequestor.h"
22 #include "nsIInterfaceRequestorUtils.h"
23 #include "nsIProgressEventSink.h"
24 #include "nsICacheInfoChannel.h"
25 #include "nsIApplicationCache.h"
26 #include "nsIApplicationCacheChannel.h"
27 #include "nsIUploadChannel2.h"
28 #include "nsIResumableChannel.h"
29 #include "nsIProxiedChannel.h"
30 #include "nsIAsyncVerifyRedirectCallback.h"
31 #include "nsIAssociatedContentSecurity.h"
32 #include "nsIChildChannel.h"
33 #include "nsIHttpChannelChild.h"
34 #include "nsIDivertableChannel.h"
35 #include "nsIThreadRetargetableRequest.h"
36 #include "mozilla/net/DNS.h"
37
38 using mozilla::Telemetry::LABELS_HTTP_CHILD_OMT_STATS;
39
40 class nsIEventTarget;
41 class nsInputStreamPump;
42 class nsIInterceptedBodyCallback;
43
44 namespace mozilla {
45 namespace net {
46
47 class HttpBackgroundChannelChild;
48 class InterceptedChannelContent;
49 class InterceptStreamListener;
50 class SyntheticDiversionListener;
51
52 class HttpChannelChild final : public PHttpChannelChild,
53 public HttpBaseChannel,
54 public HttpAsyncAborter<HttpChannelChild>,
55 public nsICacheInfoChannel,
56 public nsIProxiedChannel,
57 public nsIApplicationCacheChannel,
58 public nsIAsyncVerifyRedirectCallback,
59 public nsIAssociatedContentSecurity,
60 public nsIChildChannel,
61 public nsIHttpChannelChild,
62 public nsIDivertableChannel,
63 public nsIThreadRetargetableRequest,
64 public NeckoTargetHolder {
65 virtual ~HttpChannelChild();
66
67 public:
68 NS_DECL_ISUPPORTS_INHERITED
69 NS_DECL_NSICACHEINFOCHANNEL
70 NS_DECL_NSIPROXIEDCHANNEL
71 NS_DECL_NSIAPPLICATIONCACHECONTAINER
72 NS_DECL_NSIAPPLICATIONCACHECHANNEL
73 NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
74 NS_DECL_NSIASSOCIATEDCONTENTSECURITY
75 NS_DECL_NSICHILDCHANNEL
76 NS_DECL_NSIHTTPCHANNELCHILD
77 NS_DECL_NSIDIVERTABLECHANNEL
78 NS_DECL_NSITHREADRETARGETABLEREQUEST
79
80 HttpChannelChild();
81
82 // Methods HttpBaseChannel didn't implement for us or that we override.
83 //
84 // nsIRequest
85 NS_IMETHOD Cancel(nsresult status) override;
86 NS_IMETHOD Suspend() override;
87 NS_IMETHOD Resume() override;
88 // nsIChannel
89 NS_IMETHOD GetSecurityInfo(nsISupports** aSecurityInfo) override;
90 NS_IMETHOD AsyncOpen(nsIStreamListener* listener,
91 nsISupports* aContext) override;
92 NS_IMETHOD AsyncOpen2(nsIStreamListener* aListener) override;
93
94 // HttpBaseChannel::nsIHttpChannel
95 NS_IMETHOD SetReferrerWithPolicy(nsIURI* referrer,
96 uint32_t referrerPolicy) override;
97 NS_IMETHOD SetRequestHeader(const nsACString& aHeader,
98 const nsACString& aValue, bool aMerge) override;
99 NS_IMETHOD SetEmptyRequestHeader(const nsACString& aHeader) override;
100 NS_IMETHOD RedirectTo(nsIURI* newURI) override;
101 NS_IMETHOD UpgradeToSecure() override;
102 NS_IMETHOD GetProtocolVersion(nsACString& aProtocolVersion) override;
103 // nsIHttpChannelInternal
104 NS_IMETHOD SetupFallbackChannel(const char* aFallbackKey) override;
105 // nsISupportsPriority
106 NS_IMETHOD SetPriority(int32_t value) override;
107 // nsIClassOfService
108 NS_IMETHOD SetClassFlags(uint32_t inFlags) override;
109 NS_IMETHOD AddClassFlags(uint32_t inFlags) override;
110 NS_IMETHOD ClearClassFlags(uint32_t inFlags) override;
111 // nsIResumableChannel
112 NS_IMETHOD ResumeAt(uint64_t startPos, const nsACString& entityID) override;
113
114 // IPDL holds a reference while the PHttpChannel protocol is live (starting at
115 // AsyncOpen, and ending at either OnStopRequest or any IPDL error, either of
116 // which call NeckoChild::DeallocPHttpChannelChild()).
117 void AddIPDLReference();
118 void ReleaseIPDLReference();
119
120 MOZ_MUST_USE bool IsSuspended();
121
122 void FlushedForDiversion();
123
124 void OnCopyComplete(nsresult aStatus) override;
125
126 // Callback while background channel is ready.
127 void OnBackgroundChildReady(HttpBackgroundChannelChild* aBgChild);
128 // Callback while background channel is destroyed.
129 void OnBackgroundChildDestroyed(HttpBackgroundChannelChild* aBgChild);
130
131 protected:
132 mozilla::ipc::IPCResult RecvOnStartRequest(
133 const nsresult& channelStatus, const nsHttpResponseHead& responseHead,
134 const bool& useResponseHead, const nsHttpHeaderArray& requestHeaders,
135 const ParentLoadInfoForwarderArgs& loadInfoForwarder,
136 const bool& isFromCache, const bool& cacheEntryAvailable,
137 const uint64_t& cacheEntryId, const int32_t& cacheFetchCount,
138 const uint32_t& cacheExpirationTime, const nsCString& cachedCharset,
139 const nsCString& securityInfoSerialization, const NetAddr& selfAddr,
140 const NetAddr& peerAddr, const int16_t& redirectCount,
141 const uint32_t& cacheKey, const nsCString& altDataType,
142 const int64_t& altDataLen,
143 const OptionalIPCServiceWorkerDescriptor& aController,
144 const bool& aApplyConversion) override;
145 mozilla::ipc::IPCResult RecvFailedAsyncOpen(const nsresult& status) override;
146 mozilla::ipc::IPCResult RecvRedirect1Begin(
147 const uint32_t& registrarId, const URIParams& newURI,
148 const uint32_t& redirectFlags,
149 const ParentLoadInfoForwarderArgs& loadInfoForwarder,
150 const nsHttpResponseHead& responseHead,
151 const nsCString& securityInfoSerialization, const uint64_t& channelId,
152 const NetAddr& oldPeerAddr) override;
153 mozilla::ipc::IPCResult RecvRedirect3Complete() override;
154 mozilla::ipc::IPCResult RecvAssociateApplicationCache(
155 const nsCString& groupID, const nsCString& clientID) override;
156 mozilla::ipc::IPCResult RecvDeleteSelf() override;
157 mozilla::ipc::IPCResult RecvFinishInterceptedRedirect() override;
158
159 mozilla::ipc::IPCResult RecvReportSecurityMessage(
160 const nsString& messageTag, const nsString& messageCategory) override;
161
162 mozilla::ipc::IPCResult RecvIssueDeprecationWarning(
163 const uint32_t& warning, const bool& asError) override;
164
165 mozilla::ipc::IPCResult RecvSetPriority(const int16_t& aPriority) override;
166
167 mozilla::ipc::IPCResult RecvAttachStreamFilter(
168 Endpoint<extensions::PStreamFilterParent>&& aEndpoint) override;
169
170 mozilla::ipc::IPCResult RecvCancelDiversion() override;
171
172 virtual void ActorDestroy(ActorDestroyReason aWhy) override;
173
174 MOZ_MUST_USE bool GetAssociatedContentSecurity(
175 nsIAssociatedContentSecurity** res = nullptr);
176 virtual void DoNotifyListenerCleanup() override;
177
178 NS_IMETHOD GetResponseSynthesized(bool* aSynthesized) override;
179
180 nsresult AsyncCall(
181 void (HttpChannelChild::*funcPtr)(),
182 nsRunnableMethod<HttpChannelChild>** retval = nullptr) override;
183
184 // Get event target for processing network events.
185 already_AddRefed<nsIEventTarget> GetNeckoTarget() override;
186
187 virtual mozilla::ipc::IPCResult RecvLogBlockedCORSRequest(
188 const nsString& aMessage) override;
189 NS_IMETHOD LogBlockedCORSRequest(const nsAString& aMessage) override;
190
191 private:
192 // this section is for main-thread-only object
193 // all the references need to be proxy released on main thread.
194 nsCOMPtr<nsISupports> mCacheKey;
195 nsCOMPtr<nsIChildChannel> mRedirectChannelChild;
196 RefPtr<InterceptStreamListener> mInterceptListener;
197 // Needed to call AsyncOpen in FinishInterceptedRedirect
198 nsCOMPtr<nsIStreamListener> mInterceptedRedirectListener;
199 nsCOMPtr<nsISupports> mInterceptedRedirectContext;
200
201 // Proxy release all members above on main thread.
202 void ReleaseMainThreadOnlyReferences();
203
204 private:
205 class OverrideRunnable : public Runnable {
206 public:
207 OverrideRunnable(HttpChannelChild* aChannel, HttpChannelChild* aNewChannel,
208 InterceptStreamListener* aListener, nsIInputStream* aInput,
209 nsIInterceptedBodyCallback* aCallback,
210 nsAutoPtr<nsHttpResponseHead>& aHead,
211 nsICacheInfoChannel* aCacheInfo);
212
213 NS_IMETHOD Run() override;
214 void OverrideWithSynthesizedResponse();
215
216 private:
217 RefPtr<HttpChannelChild> mChannel;
218 RefPtr<HttpChannelChild> mNewChannel;
219 RefPtr<InterceptStreamListener> mListener;
220 nsCOMPtr<nsIInputStream> mInput;
221 nsCOMPtr<nsIInterceptedBodyCallback> mCallback;
222 nsAutoPtr<nsHttpResponseHead> mHead;
223 nsCOMPtr<nsICacheInfoChannel> mSynthesizedCacheInfo;
224 };
225
226 // Sets the event target for future IPC messages. Messages will either be
227 // directed to the TabGroup or DocGroup, depending on the LoadInfo associated
228 // with the channel. Should be called when a new channel is being set up,
229 // before the constructor message is sent to the parent.
230 void SetEventTarget();
231
232 // Get event target for ODA.
233 already_AddRefed<nsIEventTarget> GetODATarget();
234
235 MOZ_MUST_USE nsresult ContinueAsyncOpen();
236
237 // Callbacks while receiving OnTransportAndData/OnStopRequest/OnProgress/
238 // OnStatus/FlushedForDiversion/DivertMessages on background IPC channel.
239 void ProcessOnTransportAndData(const nsresult& aChannelStatus,
240 const nsresult& aStatus,
241 const uint64_t& aOffset,
242 const uint32_t& aCount,
243 const nsCString& aData);
244 void ProcessOnStopRequest(const nsresult& aStatusCode,
245 const ResourceTimingStruct& aTiming,
246 const nsHttpHeaderArray& aResponseTrailers);
247 void ProcessOnProgress(const int64_t& aProgress, const int64_t& aProgressMax);
248 void ProcessOnStatus(const nsresult& aStatus);
249 void ProcessFlushedForDiversion();
250 void ProcessDivertMessages();
251 void ProcessNotifyTrackingProtectionDisabled();
252 void ProcessNotifyTrackingResource();
253 void ProcessSetClassifierMatchedInfo(const nsCString& aList,
254 const nsCString& aProvider,
255 const nsCString& aFullHash);
256
257 void DoOnStartRequest(nsIRequest* aRequest, nsISupports* aContext);
258 void DoOnStatus(nsIRequest* aRequest, nsresult status);
259 void DoOnProgress(nsIRequest* aRequest, int64_t progress,
260 int64_t progressMax);
261 void DoOnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
262 nsIInputStream* aStream, uint64_t offset,
263 uint32_t count);
264 void DoPreOnStopRequest(nsresult aStatus);
265 void DoOnStopRequest(nsIRequest* aRequest, nsresult aChannelStatus,
266 nsISupports* aContext);
267
268 bool ShouldInterceptURI(nsIURI* aURI, bool& aShouldUpgrade);
269
270 // Discard the prior interception and continue with the original network
271 // request.
272 void ResetInterception();
273
274 // Override this channel's pending response with a synthesized one. The
275 // content will be asynchronously read from the pump.
276 void OverrideWithSynthesizedResponse(
277 nsAutoPtr<nsHttpResponseHead>& aResponseHead,
278 nsIInputStream* aSynthesizedInput,
279 nsIInterceptedBodyCallback* aSynthesizedCallback,
280 InterceptStreamListener* aStreamListener,
281 nsICacheInfoChannel* aCacheInfoChannel);
282
283 void ForceIntercepted(nsIInputStream* aSynthesizedInput,
284 nsIInterceptedBodyCallback* aSynthesizedCallback,
285 nsICacheInfoChannel* aCacheInfo);
286
287 // Try send DeletingChannel message to parent side. Dispatch an async task to
288 // main thread if invoking on non-main thread.
289 void TrySendDeletingChannel();
290
291 // Try invoke Cancel if on main thread, or prepend a CancelEvent in mEventQ to
292 // ensure Cacnel is processed before any other channel events.
293 void CancelOnMainThread(nsresult aRv);
294
295 void MaybeCallSynthesizedCallback();
296
297 RequestHeaderTuples mClientSetRequestHeaders;
298 RefPtr<nsInputStreamPump> mSynthesizedResponsePump;
299 nsCOMPtr<nsIInputStream> mSynthesizedInput;
300 nsCOMPtr<nsIInterceptedBodyCallback> mSynthesizedCallback;
301 int64_t mSynthesizedStreamLength;
302
303 bool mIsFromCache;
304 bool mCacheEntryAvailable;
305 uint64_t mCacheEntryId;
306 bool mAltDataCacheEntryAvailable;
307 int32_t mCacheFetchCount;
308 uint32_t mCacheExpirationTime;
309 nsCString mCachedCharset;
310
311 nsCOMPtr<nsICacheInfoChannel> mSynthesizedCacheInfo;
312
313 nsCString mProtocolVersion;
314
315 // If ResumeAt is called before AsyncOpen, we need to send extra data upstream
316 bool mSendResumeAt;
317
318 // To ensure only one SendDeletingChannel is triggered.
319 Atomic<bool> mDeletingChannelSent;
320
321 Atomic<bool> mIPCOpen;
322 bool mKeptAlive; // IPC kept open, but only for security info
323 RefPtr<ChannelEventQueue> mEventQ;
324
325 // If nsUnknownDecoder is involved OnStartRequest call will be delayed and
326 // this queue keeps OnDataAvailable data until OnStartRequest is finally
327 // called.
328 nsTArray<UniquePtr<ChannelEvent>> mUnknownDecoderEventQ;
329 Atomic<bool, ReleaseAcquire> mUnknownDecoderInvolved;
330
331 // Once set, OnData and possibly OnStop will be diverted to the parent.
332 Atomic<bool, ReleaseAcquire> mDivertingToParent;
333 // Once set, no OnStart/OnData/OnStop callbacks should be received from the
334 // parent channel, nor dequeued from the ChannelEventQueue.
335 Atomic<bool, ReleaseAcquire> mFlushedForDiversion;
336 // Set if SendSuspend is called. Determines if SendResume is needed when
337 // diverting callbacks to parent.
338 bool mSuspendSent;
339
340 // Set if a response was synthesized, indicating that any forthcoming
341 // redirects should be intercepted.
342 bool mSynthesizedResponse;
343
344 // Set if a synthesized response should cause us to explictly allows
345 // intercepting an expected forthcoming redirect.
346 bool mShouldInterceptSubsequentRedirect;
347 // Set if a redirection is being initiated to facilitate providing a
348 // synthesized response to a channel using a different principal than the
349 // current one.
350 bool mRedirectingForSubsequentSynthesizedResponse;
351
352 // Set if a manual redirect mode channel needs to be intercepted in the
353 // parent.
354 bool mPostRedirectChannelShouldIntercept;
355 // Set if a manual redirect mode channel needs to be upgraded to a secure URI
356 // when it's being considered for interception. Can only be true if
357 // mPostRedirectChannelShouldIntercept is true.
358 bool mPostRedirectChannelShouldUpgrade;
359
360 // Set if the corresponding parent channel should force an interception to
361 // occur before the network transaction is initiated.
362 bool mShouldParentIntercept;
363
364 // Set if the corresponding parent channel should suspend after a response
365 // is synthesized.
366 bool mSuspendParentAfterSynthesizeResponse;
367
368 // Used to ensure atomicity of mBgChild and mBgInitFailCallback
369 Mutex mBgChildMutex;
370
371 // Associated HTTP background channel
372 RefPtr<HttpBackgroundChannelChild> mBgChild;
373
374 // Error handling procedure if failed to establish PBackground IPC
375 nsCOMPtr<nsIRunnable> mBgInitFailCallback;
376
377 // Remove the association with background channel after OnStopRequest
378 // or AsyncAbort.
379 void CleanupBackgroundChannel();
380
381 // Needed to call CleanupRedirectingChannel in FinishInterceptedRedirect
382 RefPtr<HttpChannelChild> mInterceptingChannel;
383 // Used to call OverrideWithSynthesizedResponse in FinishInterceptedRedirect
384 RefPtr<OverrideRunnable> mOverrideRunnable;
385
386 // Target thread for delivering ODA.
387 nsCOMPtr<nsIEventTarget> mODATarget;
388 // Used to ensure atomicity of mNeckoTarget / mODATarget;
389 Mutex mEventTargetMutex;
390
391 void FinishInterceptedRedirect();
392 void CleanupRedirectingChannel(nsresult rv);
393
394 // true after successful AsyncOpen until OnStopRequest completes.
RemoteChannelExists()395 bool RemoteChannelExists() { return mIPCOpen && !mKeptAlive; }
396
397 void AssociateApplicationCache(const nsCString& groupID,
398 const nsCString& clientID);
399 void OnStartRequest(
400 const nsresult& channelStatus, const nsHttpResponseHead& responseHead,
401 const bool& useResponseHead, const nsHttpHeaderArray& requestHeaders,
402 const ParentLoadInfoForwarderArgs& loadInfoForwarder,
403 const bool& isFromCache, const bool& cacheEntryAvailable,
404 const uint64_t& cacheEntryId, const int32_t& cacheFetchCount,
405 const uint32_t& cacheExpirationTime, const nsCString& cachedCharset,
406 const nsCString& securityInfoSerialization, const NetAddr& selfAddr,
407 const NetAddr& peerAddr, const uint32_t& cacheKey,
408 const nsCString& altDataType, const int64_t& altDataLen,
409 const Maybe<mozilla::dom::ServiceWorkerDescriptor>& aController,
410 const bool& aApplyConversion);
411 void MaybeDivertOnData(const nsCString& data, const uint64_t& offset,
412 const uint32_t& count);
413 void OnTransportAndData(const nsresult& channelStatus, const nsresult& status,
414 const uint64_t& offset, const uint32_t& count,
415 const nsCString& data);
416 void OnStopRequest(const nsresult& channelStatus,
417 const ResourceTimingStruct& timing,
418 const nsHttpHeaderArray& aResponseTrailers);
419 void MaybeDivertOnStop(const nsresult& aChannelStatus);
420 void OnProgress(const int64_t& progress, const int64_t& progressMax);
421 void OnStatus(const nsresult& status);
422 void FailedAsyncOpen(const nsresult& status);
423 void HandleAsyncAbort();
424 void Redirect1Begin(const uint32_t& registrarId, const URIParams& newUri,
425 const uint32_t& redirectFlags,
426 const ParentLoadInfoForwarderArgs& loadInfoForwarder,
427 const nsHttpResponseHead& responseHead,
428 const nsACString& securityInfoSerialization,
429 const uint64_t& channelId);
430 bool Redirect3Complete(OverrideRunnable* aRunnable);
431 void DeleteSelf();
432 void DoNotifyListener();
433 void ContinueDoNotifyListener();
434
435 // Create a a new channel to be used in a redirection, based on the provided
436 // response headers.
437 MOZ_MUST_USE nsresult SetupRedirect(nsIURI* uri,
438 const nsHttpResponseHead* responseHead,
439 const uint32_t& redirectFlags,
440 nsIChannel** outChannel);
441
442 // Perform a redirection without communicating with the parent process at all.
443 void BeginNonIPCRedirect(nsIURI* responseURI,
444 const nsHttpResponseHead* responseHead,
445 bool responseRedirected);
446
447 // Override the default security info pointer during a non-IPC redirection.
448 void OverrideSecurityInfoForNonIPCRedirect(nsISupports* securityInfo);
449
450 // Collect telemetry for the successful rate of OMT.
451 void CollectOMTTelemetry();
452
453 // The result of RetargetDeliveryTo for this channel.
454 // |notRequested| represents OMT is not requested by the channel owner.
455 LABELS_HTTP_CHILD_OMT_STATS mOMTResult =
456 LABELS_HTTP_CHILD_OMT_STATS::notRequested;
457
458 friend class AssociateApplicationCacheEvent;
459 friend class StartRequestEvent;
460 friend class StopRequestEvent;
461 friend class TransportAndDataEvent;
462 friend class MaybeDivertOnDataHttpEvent;
463 friend class MaybeDivertOnStopHttpEvent;
464 friend class ProgressEvent;
465 friend class StatusEvent;
466 friend class FailedAsyncOpenEvent;
467 friend class Redirect1Event;
468 friend class Redirect3Event;
469 friend class DeleteSelfEvent;
470 friend class HttpFlushedForDiversionEvent;
471 friend class CancelEvent;
472 friend class HttpAsyncAborter<HttpChannelChild>;
473 friend class InterceptStreamListener;
474 friend class InterceptedChannelContent;
475 friend class SyntheticDiversionListener;
476 friend class HttpBackgroundChannelChild;
477 friend class NeckoTargetChannelEvent<HttpChannelChild>;
478 friend class ContinueDoNotifyListenerEvent;
479 };
480
481 // A stream listener interposed between the nsInputStreamPump used for
482 // intercepted channels and this channel's original listener. This is only used
483 // to ensure the original listener sees the channel as the request object, and
484 // to synthesize OnStatus and OnProgress notifications.
485 class InterceptStreamListener : public nsIStreamListener,
486 public nsIProgressEventSink {
487 RefPtr<HttpChannelChild> mOwner;
488 nsCOMPtr<nsISupports> mContext;
~InterceptStreamListener()489 virtual ~InterceptStreamListener() {}
490
491 public:
InterceptStreamListener(HttpChannelChild * aOwner,nsISupports * aContext)492 InterceptStreamListener(HttpChannelChild* aOwner, nsISupports* aContext)
493 : mOwner(aOwner), mContext(aContext) {}
494
495 NS_DECL_ISUPPORTS
496 NS_DECL_NSIREQUESTOBSERVER
497 NS_DECL_NSISTREAMLISTENER
498 NS_DECL_NSIPROGRESSEVENTSINK
499
500 void Cleanup();
501 };
502
503 //-----------------------------------------------------------------------------
504 // inline functions
505 //-----------------------------------------------------------------------------
506
IsSuspended()507 inline bool HttpChannelChild::IsSuspended() { return mSuspendCount != 0; }
508
509 } // namespace net
510 } // namespace mozilla
511
512 #endif // mozilla_net_HttpChannelChild_h
513