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