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 // HttpLog.h should generally be included first
9 #include "HttpLog.h"
10 
11 #include "nsHttp.h"
12 #include "nsICacheEntry.h"
13 #include "mozilla/Unused.h"
14 #include "mozilla/dom/ContentChild.h"
15 #include "mozilla/dom/DocGroup.h"
16 #include "mozilla/dom/ServiceWorkerUtils.h"
17 #include "mozilla/dom/TabChild.h"
18 #include "mozilla/dom/TabGroup.h"
19 #include "mozilla/extensions/StreamFilterParent.h"
20 #include "mozilla/ipc/FileDescriptorSetChild.h"
21 #include "mozilla/ipc/IPCStreamUtils.h"
22 #include "mozilla/net/NeckoChild.h"
23 #include "mozilla/net/HttpChannelChild.h"
24 
25 #include "AltDataOutputStreamChild.h"
26 #include "CookieServiceChild.h"
27 #include "HttpBackgroundChannelChild.h"
28 #include "nsCOMPtr.h"
29 #include "nsISupportsPrimitives.h"
30 #include "nsChannelClassifier.h"
31 #include "nsContentPolicyUtils.h"
32 #include "nsGlobalWindow.h"
33 #include "nsStringStream.h"
34 #include "nsHttpChannel.h"
35 #include "nsHttpHandler.h"
36 #include "nsNetUtil.h"
37 #include "nsSerializationHelper.h"
38 #include "mozilla/Attributes.h"
39 #include "mozilla/dom/PerformanceStorage.h"
40 #include "mozilla/ipc/InputStreamUtils.h"
41 #include "mozilla/ipc/URIUtils.h"
42 #include "mozilla/ipc/BackgroundUtils.h"
43 #include "mozilla/net/ChannelDiverterChild.h"
44 #include "mozilla/net/DNS.h"
45 #include "SerializedLoadContext.h"
46 #include "nsInputStreamPump.h"
47 #include "InterceptedChannel.h"
48 #include "mozIThirdPartyUtil.h"
49 #include "nsContentSecurityManager.h"
50 #include "nsIDeprecationWarner.h"
51 #include "nsICompressConvStats.h"
52 #include "nsIDocument.h"
53 #include "nsIDOMDocument.h"
54 #include "nsIDOMWindowUtils.h"
55 #include "nsIEventTarget.h"
56 #include "nsRedirectHistoryEntry.h"
57 #include "nsSocketTransportService2.h"
58 #include "nsStreamUtils.h"
59 #include "nsThreadUtils.h"
60 #include "nsCORSListenerProxy.h"
61 
62 #ifdef MOZ_TASK_TRACER
63 #include "GeckoTaskTracer.h"
64 #endif
65 
66 using namespace mozilla::dom;
67 using namespace mozilla::ipc;
68 
69 namespace mozilla {
70 namespace net {
71 
72 #if defined(NIGHTLY_BUILD) || defined(MOZ_DEV_EDITION) || defined(DEBUG)
73 static bool gIPCSecurityDisabled = false;
74 #endif
75 
NS_IMPL_ISUPPORTS(InterceptStreamListener,nsIStreamListener,nsIRequestObserver,nsIProgressEventSink)76 NS_IMPL_ISUPPORTS(InterceptStreamListener, nsIStreamListener,
77                   nsIRequestObserver, nsIProgressEventSink)
78 
79 NS_IMETHODIMP
80 InterceptStreamListener::OnStartRequest(nsIRequest* aRequest,
81                                         nsISupports* aContext) {
82   if (mOwner) {
83     mOwner->DoOnStartRequest(mOwner, mContext);
84   }
85   return NS_OK;
86 }
87 
88 NS_IMETHODIMP
OnStatus(nsIRequest * aRequest,nsISupports * aContext,nsresult status,const char16_t * aStatusArg)89 InterceptStreamListener::OnStatus(nsIRequest* aRequest, nsISupports* aContext,
90                                   nsresult status, const char16_t* aStatusArg) {
91   if (mOwner) {
92     mOwner->DoOnStatus(mOwner, status);
93   }
94   return NS_OK;
95 }
96 
97 NS_IMETHODIMP
OnProgress(nsIRequest * aRequest,nsISupports * aContext,int64_t aProgress,int64_t aProgressMax)98 InterceptStreamListener::OnProgress(nsIRequest* aRequest, nsISupports* aContext,
99                                     int64_t aProgress, int64_t aProgressMax) {
100   if (mOwner) {
101     mOwner->DoOnProgress(mOwner, aProgress, aProgressMax);
102   }
103   return NS_OK;
104 }
105 
106 NS_IMETHODIMP
OnDataAvailable(nsIRequest * aRequest,nsISupports * aContext,nsIInputStream * aInputStream,uint64_t aOffset,uint32_t aCount)107 InterceptStreamListener::OnDataAvailable(nsIRequest* aRequest,
108                                          nsISupports* aContext,
109                                          nsIInputStream* aInputStream,
110                                          uint64_t aOffset, uint32_t aCount) {
111   if (!mOwner) {
112     return NS_OK;
113   }
114 
115   uint32_t loadFlags;
116   mOwner->GetLoadFlags(&loadFlags);
117 
118   if (!(loadFlags & HttpBaseChannel::LOAD_BACKGROUND)) {
119     nsCOMPtr<nsIURI> uri;
120     mOwner->GetURI(getter_AddRefs(uri));
121 
122     nsAutoCString host;
123     uri->GetHost(host);
124 
125     OnStatus(mOwner, aContext, NS_NET_STATUS_READING,
126              NS_ConvertUTF8toUTF16(host).get());
127 
128     int64_t progress = aOffset + aCount;
129     OnProgress(mOwner, aContext, progress, mOwner->mSynthesizedStreamLength);
130   }
131 
132   mOwner->DoOnDataAvailable(mOwner, mContext, aInputStream, aOffset, aCount);
133   return NS_OK;
134 }
135 
136 NS_IMETHODIMP
OnStopRequest(nsIRequest * aRequest,nsISupports * aContext,nsresult aStatusCode)137 InterceptStreamListener::OnStopRequest(nsIRequest* aRequest,
138                                        nsISupports* aContext,
139                                        nsresult aStatusCode) {
140   if (mOwner) {
141     mOwner->DoPreOnStopRequest(aStatusCode);
142     mOwner->DoOnStopRequest(mOwner, aStatusCode, mContext);
143   }
144   Cleanup();
145   return NS_OK;
146 }
147 
Cleanup()148 void InterceptStreamListener::Cleanup() {
149   mOwner = nullptr;
150   mContext = nullptr;
151 }
152 
153 //-----------------------------------------------------------------------------
154 // HttpChannelChild
155 //-----------------------------------------------------------------------------
156 
HttpChannelChild()157 HttpChannelChild::HttpChannelChild()
158     : HttpAsyncAborter<HttpChannelChild>(this),
159       NeckoTargetHolder(nullptr),
160       mSynthesizedStreamLength(0),
161       mIsFromCache(false),
162       mCacheEntryAvailable(false),
163       mCacheEntryId(0),
164       mAltDataCacheEntryAvailable(false),
165       mCacheFetchCount(0),
166       mCacheExpirationTime(nsICacheEntry::NO_EXPIRATION_TIME),
167       mSendResumeAt(false),
168       mDeletingChannelSent(false),
169       mIPCOpen(false),
170       mKeptAlive(false),
171       mUnknownDecoderInvolved(false),
172       mDivertingToParent(false),
173       mFlushedForDiversion(false),
174       mSuspendSent(false),
175       mSynthesizedResponse(false),
176       mShouldInterceptSubsequentRedirect(false),
177       mRedirectingForSubsequentSynthesizedResponse(false),
178       mPostRedirectChannelShouldIntercept(false),
179       mPostRedirectChannelShouldUpgrade(false),
180       mShouldParentIntercept(false),
181       mSuspendParentAfterSynthesizeResponse(false),
182       mBgChildMutex("HttpChannelChild::BgChildMutex"),
183       mEventTargetMutex("HttpChannelChild::EventTargetMutex") {
184   LOG(("Creating HttpChannelChild @%p\n", this));
185 
186   mChannelCreationTime = PR_Now();
187   mChannelCreationTimestamp = TimeStamp::Now();
188   mAsyncOpenTime = TimeStamp::Now();
189   mEventQ = new ChannelEventQueue(static_cast<nsIHttpChannel*>(this));
190 
191 #if defined(NIGHTLY_BUILD) || defined(MOZ_DEV_EDITION) || defined(DEBUG)
192   static bool sSecurityPrefChecked = false;
193   if (!sSecurityPrefChecked) {
194     Preferences::AddBoolVarCache(&gIPCSecurityDisabled,
195                                  "network.disable.ipc.security");
196     sSecurityPrefChecked = true;
197   }
198 #endif
199 
200   // Ensure that the cookie service is initialized before the first
201   // IPC HTTP channel is created.
202   // We require that the parent cookie service actor exists while
203   // processing HTTP responses.
204   RefPtr<CookieServiceChild> cookieService = CookieServiceChild::GetSingleton();
205 }
206 
~HttpChannelChild()207 HttpChannelChild::~HttpChannelChild() {
208   LOG(("Destroying HttpChannelChild @%p\n", this));
209 
210   ReleaseMainThreadOnlyReferences();
211 }
212 
ReleaseMainThreadOnlyReferences()213 void HttpChannelChild::ReleaseMainThreadOnlyReferences() {
214   if (NS_IsMainThread()) {
215     // Already on main thread, let dtor to
216     // take care of releasing references
217     return;
218   }
219 
220   nsTArray<nsCOMPtr<nsISupports>> arrayToRelease;
221   arrayToRelease.AppendElement(mCacheKey.forget());
222   arrayToRelease.AppendElement(mRedirectChannelChild.forget());
223 
224   // To solve multiple inheritence of nsISupports in InterceptStreamListener
225   nsCOMPtr<nsIStreamListener> listener = mInterceptListener.forget();
226   arrayToRelease.AppendElement(listener.forget());
227 
228   arrayToRelease.AppendElement(mInterceptedRedirectListener.forget());
229   arrayToRelease.AppendElement(mInterceptedRedirectContext.forget());
230 
231   NS_DispatchToMainThread(new ProxyReleaseRunnable(Move(arrayToRelease)));
232 }
233 //-----------------------------------------------------------------------------
234 // HttpChannelChild::nsISupports
235 //-----------------------------------------------------------------------------
236 
237 NS_IMPL_ADDREF(HttpChannelChild)
238 
NS_IMETHODIMP_(MozExternalRefCountType)239 NS_IMETHODIMP_(MozExternalRefCountType) HttpChannelChild::Release() {
240   if (!NS_IsMainThread()) {
241     nsrefcnt count = mRefCnt;
242     nsresult rv = NS_DispatchToMainThread(NewNonOwningRunnableMethod(
243         "HttpChannelChild::Release", this, &HttpChannelChild::Release));
244 
245     // Continue Release procedure if failed to dispatch to main thread.
246     if (!NS_WARN_IF(NS_FAILED(rv))) {
247       return count - 1;
248     }
249   }
250 
251   nsrefcnt count = --mRefCnt;
252   MOZ_ASSERT(int32_t(count) >= 0, "dup release");
253   NS_LOG_RELEASE(this, count, "HttpChannelChild");
254 
255   // Normally we Send_delete in OnStopRequest, but when we need to retain the
256   // remote channel for security info IPDL itself holds 1 reference, so we
257   // Send_delete when refCnt==1.  But if !mIPCOpen, then there's nobody to send
258   // to, so we fall through.
259   if (mKeptAlive && count == 1 && mIPCOpen) {
260     mKeptAlive = false;
261     // We send a message to the parent, which calls SendDelete, and then the
262     // child calling Send__delete__() to finally drop the refcount to 0.
263     TrySendDeletingChannel();
264     return 1;
265   }
266 
267   if (count == 0) {
268     mRefCnt = 1; /* stabilize */
269     delete this;
270     return 0;
271   }
272   return count;
273 }
274 
275 NS_INTERFACE_MAP_BEGIN(HttpChannelChild)
NS_INTERFACE_MAP_ENTRY(nsIRequest)276   NS_INTERFACE_MAP_ENTRY(nsIRequest)
277   NS_INTERFACE_MAP_ENTRY(nsIChannel)
278   NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
279   NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
280   NS_INTERFACE_MAP_ENTRY(nsICacheInfoChannel)
281   NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
282   NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
283   NS_INTERFACE_MAP_ENTRY(nsIClassOfService)
284   NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
285   NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
286   NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
287   NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel)
288   NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
289   NS_INTERFACE_MAP_ENTRY(nsIChildChannel)
290   NS_INTERFACE_MAP_ENTRY(nsIHttpChannelChild)
291   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAssociatedContentSecurity,
292                                      GetAssociatedContentSecurity())
293   NS_INTERFACE_MAP_ENTRY(nsIDivertableChannel)
294   NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest)
295 NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
296 
297 //-----------------------------------------------------------------------------
298 // HttpChannelChild::PHttpChannelChild
299 //-----------------------------------------------------------------------------
300 
301 void HttpChannelChild::AddIPDLReference() {
302   MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference");
303   mIPCOpen = true;
304   AddRef();
305 }
306 
ReleaseIPDLReference()307 void HttpChannelChild::ReleaseIPDLReference() {
308   MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference");
309   mIPCOpen = false;
310   Release();
311 }
312 
OnBackgroundChildReady(HttpBackgroundChannelChild * aBgChild)313 void HttpChannelChild::OnBackgroundChildReady(
314     HttpBackgroundChannelChild* aBgChild) {
315   LOG(("HttpChannelChild::OnBackgroundChildReady [this=%p, bgChild=%p]\n", this,
316        aBgChild));
317   MOZ_ASSERT(OnSocketThread());
318 
319   {
320     MutexAutoLock lock(mBgChildMutex);
321 
322     // mBgChild might be removed or replaced while the original background
323     // channel is inited on STS thread.
324     if (mBgChild != aBgChild) {
325       return;
326     }
327 
328     MOZ_ASSERT(mBgInitFailCallback);
329     mBgInitFailCallback = nullptr;
330   }
331 }
332 
OnBackgroundChildDestroyed(HttpBackgroundChannelChild * aBgChild)333 void HttpChannelChild::OnBackgroundChildDestroyed(
334     HttpBackgroundChannelChild* aBgChild) {
335   LOG(("HttpChannelChild::OnBackgroundChildDestroyed [this=%p]\n", this));
336   // This function might be called during shutdown phase, so OnSocketThread()
337   // might return false even on STS thread. Use IsOnCurrentThreadInfallible()
338   // to get correct information.
339   MOZ_ASSERT(gSocketTransportService);
340   MOZ_ASSERT(gSocketTransportService->IsOnCurrentThreadInfallible());
341 
342   nsCOMPtr<nsIRunnable> callback;
343   {
344     MutexAutoLock lock(mBgChildMutex);
345 
346     // mBgChild might be removed or replaced while the original background
347     // channel is destroyed on STS thread.
348     if (aBgChild != mBgChild) {
349       return;
350     }
351 
352     mBgChild = nullptr;
353     callback = mBgInitFailCallback.forget();
354   }
355 
356   if (callback) {
357     nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget();
358     neckoTarget->Dispatch(callback, NS_DISPATCH_NORMAL);
359   }
360 }
361 
362 class AssociateApplicationCacheEvent
363     : public NeckoTargetChannelEvent<HttpChannelChild> {
364  public:
AssociateApplicationCacheEvent(HttpChannelChild * aChild,const nsCString & aGroupID,const nsCString & aClientID)365   AssociateApplicationCacheEvent(HttpChannelChild* aChild,
366                                  const nsCString& aGroupID,
367                                  const nsCString& aClientID)
368       : NeckoTargetChannelEvent<HttpChannelChild>(aChild),
369         groupID(aGroupID),
370         clientID(aClientID) {}
371 
Run()372   void Run() override { mChild->AssociateApplicationCache(groupID, clientID); }
373 
374  private:
375   nsCString groupID;
376   nsCString clientID;
377 };
378 
RecvAssociateApplicationCache(const nsCString & groupID,const nsCString & clientID)379 mozilla::ipc::IPCResult HttpChannelChild::RecvAssociateApplicationCache(
380     const nsCString& groupID, const nsCString& clientID) {
381   LOG(("HttpChannelChild::RecvAssociateApplicationCache [this=%p]\n", this));
382   mEventQ->RunOrEnqueue(
383       new AssociateApplicationCacheEvent(this, groupID, clientID));
384   return IPC_OK();
385 }
386 
AssociateApplicationCache(const nsCString & groupID,const nsCString & clientID)387 void HttpChannelChild::AssociateApplicationCache(const nsCString& groupID,
388                                                  const nsCString& clientID) {
389   LOG(("HttpChannelChild::AssociateApplicationCache [this=%p]\n", this));
390   nsresult rv;
391   mApplicationCache = do_CreateInstance(NS_APPLICATIONCACHE_CONTRACTID, &rv);
392   if (NS_FAILED(rv)) return;
393 
394   mLoadedFromApplicationCache = true;
395   mApplicationCache->InitAsHandle(groupID, clientID);
396 }
397 
398 class StartRequestEvent : public NeckoTargetChannelEvent<HttpChannelChild> {
399  public:
StartRequestEvent(HttpChannelChild * aChild,const nsresult & aChannelStatus,const nsHttpResponseHead & aResponseHead,const bool & aUseResponseHead,const nsHttpHeaderArray & aRequestHeaders,const ParentLoadInfoForwarderArgs & loadInfoForwarder,const bool & aIsFromCache,const bool & aCacheEntryAvailable,const uint64_t & aCacheEntryId,const int32_t & aCacheFetchCount,const uint32_t & aCacheExpirationTime,const nsCString & aCachedCharset,const nsCString & aSecurityInfoSerialization,const NetAddr & aSelfAddr,const NetAddr & aPeerAddr,const uint32_t & aCacheKey,const nsCString & altDataType,const int64_t & altDataLen,Maybe<ServiceWorkerDescriptor> && aController,const bool & aApplyConversion)400   StartRequestEvent(
401       HttpChannelChild* aChild, const nsresult& aChannelStatus,
402       const nsHttpResponseHead& aResponseHead, const bool& aUseResponseHead,
403       const nsHttpHeaderArray& aRequestHeaders,
404       const ParentLoadInfoForwarderArgs& loadInfoForwarder,
405       const bool& aIsFromCache, const bool& aCacheEntryAvailable,
406       const uint64_t& aCacheEntryId, const int32_t& aCacheFetchCount,
407       const uint32_t& aCacheExpirationTime, const nsCString& aCachedCharset,
408       const nsCString& aSecurityInfoSerialization, const NetAddr& aSelfAddr,
409       const NetAddr& aPeerAddr, const uint32_t& aCacheKey,
410       const nsCString& altDataType, const int64_t& altDataLen,
411       Maybe<ServiceWorkerDescriptor>&& aController,
412       const bool& aApplyConversion)
413       : NeckoTargetChannelEvent<HttpChannelChild>(aChild),
414         mChannelStatus(aChannelStatus),
415         mResponseHead(aResponseHead),
416         mRequestHeaders(aRequestHeaders),
417         mUseResponseHead(aUseResponseHead),
418         mApplyConversion(aApplyConversion),
419         mIsFromCache(aIsFromCache),
420         mCacheEntryAvailable(aCacheEntryAvailable),
421         mCacheEntryId(aCacheEntryId),
422         mCacheFetchCount(aCacheFetchCount),
423         mCacheExpirationTime(aCacheExpirationTime),
424         mCachedCharset(aCachedCharset),
425         mSecurityInfoSerialization(aSecurityInfoSerialization),
426         mSelfAddr(aSelfAddr),
427         mPeerAddr(aPeerAddr),
428         mCacheKey(aCacheKey),
429         mAltDataType(altDataType),
430         mAltDataLen(altDataLen),
431         mController(Move(aController)),
432         mLoadInfoForwarder(loadInfoForwarder) {}
433 
Run()434   void Run() override {
435     LOG(("StartRequestEvent [this=%p]\n", mChild));
436     mChild->OnStartRequest(
437         mChannelStatus, mResponseHead, mUseResponseHead, mRequestHeaders,
438         mLoadInfoForwarder, mIsFromCache, mCacheEntryAvailable, mCacheEntryId,
439         mCacheFetchCount, mCacheExpirationTime, mCachedCharset,
440         mSecurityInfoSerialization, mSelfAddr, mPeerAddr, mCacheKey,
441         mAltDataType, mAltDataLen, mController, mApplyConversion);
442   }
443 
444  private:
445   nsresult mChannelStatus;
446   nsHttpResponseHead mResponseHead;
447   nsHttpHeaderArray mRequestHeaders;
448   bool mUseResponseHead;
449   bool mApplyConversion;
450   bool mIsFromCache;
451   bool mCacheEntryAvailable;
452   uint64_t mCacheEntryId;
453   int32_t mCacheFetchCount;
454   uint32_t mCacheExpirationTime;
455   nsCString mCachedCharset;
456   nsCString mSecurityInfoSerialization;
457   NetAddr mSelfAddr;
458   NetAddr mPeerAddr;
459   uint32_t mCacheKey;
460   nsCString mAltDataType;
461   int64_t mAltDataLen;
462   Maybe<ServiceWorkerDescriptor> mController;
463   ParentLoadInfoForwarderArgs mLoadInfoForwarder;
464 };
465 
RecvOnStartRequest(const nsresult & channelStatus,const nsHttpResponseHead & responseHead,const bool & useResponseHead,const nsHttpHeaderArray & requestHeaders,const ParentLoadInfoForwarderArgs & loadInfoForwarder,const bool & isFromCache,const bool & cacheEntryAvailable,const uint64_t & cacheEntryId,const int32_t & cacheFetchCount,const uint32_t & cacheExpirationTime,const nsCString & cachedCharset,const nsCString & securityInfoSerialization,const NetAddr & selfAddr,const NetAddr & peerAddr,const int16_t & redirectCount,const uint32_t & cacheKey,const nsCString & altDataType,const int64_t & altDataLen,const OptionalIPCServiceWorkerDescriptor & aController,const bool & aApplyConversion)466 mozilla::ipc::IPCResult HttpChannelChild::RecvOnStartRequest(
467     const nsresult& channelStatus, const nsHttpResponseHead& responseHead,
468     const bool& useResponseHead, const nsHttpHeaderArray& requestHeaders,
469     const ParentLoadInfoForwarderArgs& loadInfoForwarder,
470     const bool& isFromCache, const bool& cacheEntryAvailable,
471     const uint64_t& cacheEntryId, const int32_t& cacheFetchCount,
472     const uint32_t& cacheExpirationTime, const nsCString& cachedCharset,
473     const nsCString& securityInfoSerialization, const NetAddr& selfAddr,
474     const NetAddr& peerAddr, const int16_t& redirectCount,
475     const uint32_t& cacheKey, const nsCString& altDataType,
476     const int64_t& altDataLen,
477     const OptionalIPCServiceWorkerDescriptor& aController,
478     const bool& aApplyConversion) {
479   LOG(("HttpChannelChild::RecvOnStartRequest [this=%p]\n", this));
480   // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
481   // stage, as they are set in the listener's OnStartRequest.
482   MOZ_RELEASE_ASSERT(
483       !mFlushedForDiversion,
484       "mFlushedForDiversion should be unset before OnStartRequest!");
485   MOZ_RELEASE_ASSERT(
486       !mDivertingToParent,
487       "mDivertingToParent should be unset before OnStartRequest!");
488 
489   mRedirectCount = redirectCount;
490   Maybe<ServiceWorkerDescriptor> controller;
491   if (aController.type() != OptionalIPCServiceWorkerDescriptor::Tvoid_t) {
492     controller.emplace(
493         ServiceWorkerDescriptor(aController.get_IPCServiceWorkerDescriptor()));
494   }
495 
496   mEventQ->RunOrEnqueue(new StartRequestEvent(
497       this, channelStatus, responseHead, useResponseHead, requestHeaders,
498       loadInfoForwarder, isFromCache, cacheEntryAvailable, cacheEntryId,
499       cacheFetchCount, cacheExpirationTime, cachedCharset,
500       securityInfoSerialization, selfAddr, peerAddr, cacheKey, altDataType,
501       altDataLen, Move(controller), aApplyConversion));
502 
503   {
504     // Child's mEventQ is to control the execution order of the IPC messages
505     // from both main thread IPDL and PBackground IPDL.
506     // To guarantee the ordering, PBackground IPC messages that are sent after
507     // OnStartRequest will be throttled until OnStartRequest hits the Child's
508     // mEventQ.
509     MutexAutoLock lock(mBgChildMutex);
510 
511     if (mBgChild) {
512       MOZ_RELEASE_ASSERT(gSocketTransportService);
513       DebugOnly<nsresult> rv = gSocketTransportService->Dispatch(
514           NewRunnableMethod(
515               "HttpBackgroundChannelChild::OnStartRequestReceived", mBgChild,
516               &HttpBackgroundChannelChild::OnStartRequestReceived),
517           NS_DISPATCH_NORMAL);
518     }
519   }
520 
521   return IPC_OK();
522 }
523 
OnStartRequest(const nsresult & channelStatus,const nsHttpResponseHead & responseHead,const bool & useResponseHead,const nsHttpHeaderArray & requestHeaders,const ParentLoadInfoForwarderArgs & loadInfoForwarder,const bool & isFromCache,const bool & cacheEntryAvailable,const uint64_t & cacheEntryId,const int32_t & cacheFetchCount,const uint32_t & cacheExpirationTime,const nsCString & cachedCharset,const nsCString & securityInfoSerialization,const NetAddr & selfAddr,const NetAddr & peerAddr,const uint32_t & cacheKey,const nsCString & altDataType,const int64_t & altDataLen,const Maybe<ServiceWorkerDescriptor> & aController,const bool & aApplyConversion)524 void HttpChannelChild::OnStartRequest(
525     const nsresult& channelStatus, const nsHttpResponseHead& responseHead,
526     const bool& useResponseHead, const nsHttpHeaderArray& requestHeaders,
527     const ParentLoadInfoForwarderArgs& loadInfoForwarder,
528     const bool& isFromCache, const bool& cacheEntryAvailable,
529     const uint64_t& cacheEntryId, const int32_t& cacheFetchCount,
530     const uint32_t& cacheExpirationTime, const nsCString& cachedCharset,
531     const nsCString& securityInfoSerialization, const NetAddr& selfAddr,
532     const NetAddr& peerAddr, const uint32_t& cacheKey,
533     const nsCString& altDataType, const int64_t& altDataLen,
534     const Maybe<ServiceWorkerDescriptor>& aController,
535     const bool& aApplyConversion) {
536   LOG(("HttpChannelChild::OnStartRequest [this=%p]\n", this));
537 
538   // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
539   // stage, as they are set in the listener's OnStartRequest.
540   MOZ_RELEASE_ASSERT(
541       !mFlushedForDiversion,
542       "mFlushedForDiversion should be unset before OnStartRequest!");
543   MOZ_RELEASE_ASSERT(
544       !mDivertingToParent,
545       "mDivertingToParent should be unset before OnStartRequest!");
546 
547   if (!mCanceled && NS_SUCCEEDED(mStatus)) {
548     mStatus = channelStatus;
549   }
550 
551   if (useResponseHead && !mCanceled)
552     mResponseHead = new nsHttpResponseHead(responseHead);
553 
554   if (!securityInfoSerialization.IsEmpty()) {
555     NS_DeserializeObject(securityInfoSerialization,
556                          getter_AddRefs(mSecurityInfo));
557   }
558 
559   ipc::MergeParentLoadInfoForwarder(loadInfoForwarder, mLoadInfo);
560 
561   mIsFromCache = isFromCache;
562   mCacheEntryAvailable = cacheEntryAvailable;
563   mCacheEntryId = cacheEntryId;
564   mCacheFetchCount = cacheFetchCount;
565   mCacheExpirationTime = cacheExpirationTime;
566   mCachedCharset = cachedCharset;
567   mSelfAddr = selfAddr;
568   mPeerAddr = peerAddr;
569 
570   mAvailableCachedAltDataType = altDataType;
571   mAltDataLength = altDataLen;
572 
573   SetApplyConversion(aApplyConversion);
574 
575   if (ServiceWorkerParentInterceptEnabled()) {
576     const Maybe<ServiceWorkerDescriptor>& prevController =
577         mLoadInfo->GetController();
578 
579     // If we got a service worker controller from the parent, then note
580     // it on the LoadInfo.  This may indicate that a non-subresource request
581     // was intercepted and the resulting window/worker should be controlled.
582     if (aController.isSome() && prevController.isNothing()) {
583       mLoadInfo->SetController(aController.ref());
584     }
585 
586     // If we did not set a controller, then verify it was either because:
587     //  1. Neither the parent or child know about a controlling service worker.
588     //  2. The parent and child both have the same controlling service worker.
589     else {
590       MOZ_DIAGNOSTIC_ASSERT(
591           (prevController.isNothing() && aController.isNothing()) ||
592           (prevController.ref().Id() == aController.ref().Id() &&
593            prevController.ref().Scope() == aController.ref().Scope() &&
594            prevController.ref().PrincipalInfo() ==
595                aController.ref().PrincipalInfo()));
596     }
597   }
598 
599   mAfterOnStartRequestBegun = true;
600 
601   AutoEventEnqueuer ensureSerialDispatch(mEventQ);
602 
603   nsresult rv;
604   nsCOMPtr<nsISupportsPRUint32> container =
605       do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
606   if (NS_FAILED(rv)) {
607     Cancel(rv);
608     return;
609   }
610 
611   rv = container->SetData(cacheKey);
612   if (NS_FAILED(rv)) {
613     Cancel(rv);
614     return;
615   }
616   mCacheKey = container;
617 
618   // replace our request headers with what actually got sent in the parent
619   mRequestHead.SetHeaders(requestHeaders);
620 
621   // Note: this is where we would notify "http-on-examine-response" observers.
622   // We have deliberately disabled this for child processes (see bug 806753)
623   //
624   // gHttpHandler->OnExamineResponse(this);
625 
626   mTracingEnabled = false;
627 
628   DoOnStartRequest(this, mListenerContext);
629 }
630 
631 class SyntheticDiversionListener final : public nsIStreamListener {
632   RefPtr<HttpChannelChild> mChannel;
633 
~SyntheticDiversionListener()634   ~SyntheticDiversionListener() {}
635 
636  public:
SyntheticDiversionListener(HttpChannelChild * aChannel)637   explicit SyntheticDiversionListener(HttpChannelChild* aChannel)
638       : mChannel(aChannel) {
639     MOZ_ASSERT(mChannel);
640   }
641 
642   NS_IMETHOD
OnStartRequest(nsIRequest * aRequest,nsISupports * aContext)643   OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) override {
644     MOZ_ASSERT_UNREACHABLE(
645         "SyntheticDiversionListener should never see OnStartRequest");
646     return NS_OK;
647   }
648 
649   NS_IMETHOD
OnStopRequest(nsIRequest * aRequest,nsISupports * aContext,nsresult aStatus)650   OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
651                 nsresult aStatus) override {
652     if (mChannel->mIPCOpen) {
653       mChannel->SendDivertOnStopRequest(aStatus);
654       mChannel->SendDivertComplete();
655     }
656     return NS_OK;
657   }
658 
659   NS_IMETHOD
OnDataAvailable(nsIRequest * aRequest,nsISupports * aContext,nsIInputStream * aInputStream,uint64_t aOffset,uint32_t aCount)660   OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
661                   nsIInputStream* aInputStream, uint64_t aOffset,
662                   uint32_t aCount) override {
663     if (!mChannel->mIPCOpen) {
664       aRequest->Cancel(NS_ERROR_ABORT);
665       return NS_ERROR_ABORT;
666     }
667 
668     nsAutoCString data;
669     nsresult rv = NS_ConsumeStream(aInputStream, aCount, data);
670     if (NS_WARN_IF(NS_FAILED(rv))) {
671       aRequest->Cancel(rv);
672       return rv;
673     }
674 
675     mChannel->SendDivertOnDataAvailable(data, aOffset, aCount);
676     return NS_OK;
677   }
678 
679   NS_DECL_ISUPPORTS
680 };
681 
682 NS_IMPL_ISUPPORTS(SyntheticDiversionListener, nsIStreamListener);
683 
DoOnStartRequest(nsIRequest * aRequest,nsISupports * aContext)684 void HttpChannelChild::DoOnStartRequest(nsIRequest* aRequest,
685                                         nsISupports* aContext) {
686   nsresult rv;
687 
688   LOG(("HttpChannelChild::DoOnStartRequest [this=%p]\n", this));
689 
690   // In theory mListener should not be null, but in practice sometimes it is.
691   MOZ_ASSERT(mListener);
692   if (!mListener) {
693     Cancel(NS_ERROR_FAILURE);
694     return;
695   }
696 
697   if (mSynthesizedResponsePump && mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) {
698     mSynthesizedResponsePump->PeekStream(CallTypeSniffers,
699                                          static_cast<nsIChannel*>(this));
700   }
701 
702   if (mListener) {
703     nsCOMPtr<nsIStreamListener> listener(mListener);
704     rv = listener->OnStartRequest(aRequest, aContext);
705   } else {
706     rv = NS_ERROR_UNEXPECTED;
707   }
708 
709   if (NS_FAILED(rv)) {
710     Cancel(rv);
711     return;
712   }
713 
714   if (mDivertingToParent) {
715     mListener = nullptr;
716     mListenerContext = nullptr;
717     mCompressListener = nullptr;
718     if (mLoadGroup) {
719       mLoadGroup->RemoveRequest(this, nullptr, mStatus);
720     }
721 
722     // If the response has been synthesized in the child, then we are going
723     // be getting OnDataAvailable and OnStopRequest from the synthetic
724     // stream pump.  We need to forward these back to the parent diversion
725     // listener.
726     if (mSynthesizedResponse) {
727       mListener = new SyntheticDiversionListener(this);
728     }
729 
730     return;
731   }
732 
733   nsCOMPtr<nsIStreamListener> listener;
734   rv = DoApplyContentConversions(mListener, getter_AddRefs(listener),
735                                  mListenerContext);
736   if (NS_FAILED(rv)) {
737     Cancel(rv);
738   } else if (listener) {
739     mListener = listener;
740     mCompressListener = listener;
741   }
742 }
743 
744 class TransportAndDataEvent : public ChannelEvent {
745  public:
TransportAndDataEvent(HttpChannelChild * child,const nsresult & channelStatus,const nsresult & transportStatus,const nsCString & data,const uint64_t & offset,const uint32_t & count)746   TransportAndDataEvent(HttpChannelChild* child, const nsresult& channelStatus,
747                         const nsresult& transportStatus, const nsCString& data,
748                         const uint64_t& offset, const uint32_t& count)
749       : mChild(child),
750         mChannelStatus(channelStatus),
751         mTransportStatus(transportStatus),
752         mData(data),
753         mOffset(offset),
754         mCount(count) {}
755 
Run()756   void Run() override {
757     mChild->OnTransportAndData(mChannelStatus, mTransportStatus, mOffset,
758                                mCount, mData);
759   }
760 
GetEventTarget()761   already_AddRefed<nsIEventTarget> GetEventTarget() override {
762     MOZ_ASSERT(mChild);
763     nsCOMPtr<nsIEventTarget> target = mChild->GetODATarget();
764     return target.forget();
765   }
766 
767  private:
768   HttpChannelChild* mChild;
769   nsresult mChannelStatus;
770   nsresult mTransportStatus;
771   nsCString mData;
772   uint64_t mOffset;
773   uint32_t mCount;
774 };
775 
ProcessOnTransportAndData(const nsresult & aChannelStatus,const nsresult & aTransportStatus,const uint64_t & aOffset,const uint32_t & aCount,const nsCString & aData)776 void HttpChannelChild::ProcessOnTransportAndData(
777     const nsresult& aChannelStatus, const nsresult& aTransportStatus,
778     const uint64_t& aOffset, const uint32_t& aCount, const nsCString& aData) {
779   LOG(("HttpChannelChild::ProcessOnTransportAndData [this=%p]\n", this));
780   MOZ_ASSERT(OnSocketThread());
781   MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
782                      "Should not be receiving any more callbacks from parent!");
783   mEventQ->RunOrEnqueue(
784       new TransportAndDataEvent(this, aChannelStatus, aTransportStatus, aData,
785                                 aOffset, aCount),
786       mDivertingToParent);
787 }
788 
789 class MaybeDivertOnDataHttpEvent
790     : public NeckoTargetChannelEvent<HttpChannelChild> {
791  public:
MaybeDivertOnDataHttpEvent(HttpChannelChild * child,const nsCString & data,const uint64_t & offset,const uint32_t & count)792   MaybeDivertOnDataHttpEvent(HttpChannelChild* child, const nsCString& data,
793                              const uint64_t& offset, const uint32_t& count)
794       : NeckoTargetChannelEvent<HttpChannelChild>(child),
795         mData(data),
796         mOffset(offset),
797         mCount(count) {}
798 
Run()799   void Run() override { mChild->MaybeDivertOnData(mData, mOffset, mCount); }
800 
801  private:
802   nsCString mData;
803   uint64_t mOffset;
804   uint32_t mCount;
805 };
806 
MaybeDivertOnData(const nsCString & data,const uint64_t & offset,const uint32_t & count)807 void HttpChannelChild::MaybeDivertOnData(const nsCString& data,
808                                          const uint64_t& offset,
809                                          const uint32_t& count) {
810   LOG(("HttpChannelChild::MaybeDivertOnData [this=%p]", this));
811 
812   if (mDivertingToParent) {
813     SendDivertOnDataAvailable(data, offset, count);
814   }
815 }
816 
OnTransportAndData(const nsresult & channelStatus,const nsresult & transportStatus,const uint64_t & offset,const uint32_t & count,const nsCString & data)817 void HttpChannelChild::OnTransportAndData(const nsresult& channelStatus,
818                                           const nsresult& transportStatus,
819                                           const uint64_t& offset,
820                                           const uint32_t& count,
821                                           const nsCString& data) {
822   LOG(("HttpChannelChild::OnTransportAndData [this=%p]\n", this));
823 
824   if (!mCanceled && NS_SUCCEEDED(mStatus)) {
825     mStatus = channelStatus;
826   }
827 
828   // For diversion to parent, just SendDivertOnDataAvailable.
829   if (mDivertingToParent) {
830     MOZ_ASSERT(NS_IsMainThread());
831     MOZ_RELEASE_ASSERT(
832         !mFlushedForDiversion,
833         "Should not be processing any more callbacks from parent!");
834 
835     SendDivertOnDataAvailable(data, offset, count);
836     return;
837   }
838 
839   if (mCanceled) return;
840 
841   if (mUnknownDecoderInvolved) {
842     LOG(("UnknownDecoder is involved queue OnDataAvailable call. [this=%p]",
843          this));
844     MOZ_ASSERT(NS_IsMainThread());
845     mUnknownDecoderEventQ.AppendElement(
846         MakeUnique<MaybeDivertOnDataHttpEvent>(this, data, offset, count));
847   }
848 
849   // Hold queue lock throughout all three calls, else we might process a later
850   // necko msg in between them.
851   AutoEventEnqueuer ensureSerialDispatch(mEventQ);
852 
853   int64_t progressMax;
854   if (NS_FAILED(GetContentLength(&progressMax))) {
855     progressMax = -1;
856   }
857 
858   const int64_t progress = offset + count;
859 
860   // OnTransportAndData will be run on retargeted thread if applicable, however
861   // OnStatus/OnProgress event can only be fired on main thread. We need to
862   // dispatch the status/progress event handling back to main thread with the
863   // appropriate event target for networking.
864   if (NS_IsMainThread()) {
865     DoOnStatus(this, transportStatus);
866     DoOnProgress(this, progress, progressMax);
867   } else {
868     RefPtr<HttpChannelChild> self = this;
869     nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget();
870     MOZ_ASSERT(neckoTarget);
871 
872     DebugOnly<nsresult> rv = neckoTarget->Dispatch(
873         NS_NewRunnableFunction(
874             "net::HttpChannelChild::OnTransportAndData",
875             [self, transportStatus, progress, progressMax]() {
876               self->DoOnStatus(self, transportStatus);
877               self->DoOnProgress(self, progress, progressMax);
878             }),
879         NS_DISPATCH_NORMAL);
880     MOZ_ASSERT(NS_SUCCEEDED(rv));
881   }
882 
883   // OnDataAvailable
884   //
885   // NOTE: the OnDataAvailable contract requires the client to read all the data
886   // in the inputstream.  This code relies on that ('data' will go away after
887   // this function).  Apparently the previous, non-e10s behavior was to actually
888   // support only reading part of the data, allowing later calls to read the
889   // rest.
890   nsCOMPtr<nsIInputStream> stringStream;
891   nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(),
892                                       count, NS_ASSIGNMENT_DEPEND);
893   if (NS_FAILED(rv)) {
894     Cancel(rv);
895     return;
896   }
897 
898   DoOnDataAvailable(this, mListenerContext, stringStream, offset, count);
899   stringStream->Close();
900 }
901 
DoOnStatus(nsIRequest * aRequest,nsresult status)902 void HttpChannelChild::DoOnStatus(nsIRequest* aRequest, nsresult status) {
903   LOG(("HttpChannelChild::DoOnStatus [this=%p]\n", this));
904   MOZ_ASSERT(NS_IsMainThread());
905 
906   if (mCanceled) return;
907 
908   // cache the progress sink so we don't have to query for it each time.
909   if (!mProgressSink) GetCallback(mProgressSink);
910 
911   // Temporary fix for bug 1116124
912   // See 1124971 - Child removes LOAD_BACKGROUND flag from channel
913   if (status == NS_OK) return;
914 
915   // block status/progress after Cancel or OnStopRequest has been called,
916   // or if channel has LOAD_BACKGROUND set.
917   if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending &&
918       !(mLoadFlags & LOAD_BACKGROUND)) {
919     // OnStatus
920     //
921     MOZ_ASSERT(status == NS_NET_STATUS_RECEIVING_FROM ||
922                status == NS_NET_STATUS_READING);
923 
924     nsAutoCString host;
925     mURI->GetHost(host);
926     mProgressSink->OnStatus(aRequest, nullptr, status,
927                             NS_ConvertUTF8toUTF16(host).get());
928   }
929 }
930 
DoOnProgress(nsIRequest * aRequest,int64_t progress,int64_t progressMax)931 void HttpChannelChild::DoOnProgress(nsIRequest* aRequest, int64_t progress,
932                                     int64_t progressMax) {
933   LOG(("HttpChannelChild::DoOnProgress [this=%p]\n", this));
934   MOZ_ASSERT(NS_IsMainThread());
935 
936   if (mCanceled) return;
937 
938   // cache the progress sink so we don't have to query for it each time.
939   if (!mProgressSink) GetCallback(mProgressSink);
940 
941   // block status/progress after Cancel or OnStopRequest has been called,
942   // or if channel has LOAD_BACKGROUND set.
943   if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending &&
944       !(mLoadFlags & LOAD_BACKGROUND)) {
945     // OnProgress
946     //
947     if (progress > 0) {
948       mProgressSink->OnProgress(aRequest, nullptr, progress, progressMax);
949     }
950   }
951 }
952 
DoOnDataAvailable(nsIRequest * aRequest,nsISupports * aContext,nsIInputStream * aStream,uint64_t offset,uint32_t count)953 void HttpChannelChild::DoOnDataAvailable(nsIRequest* aRequest,
954                                          nsISupports* aContext,
955                                          nsIInputStream* aStream,
956                                          uint64_t offset, uint32_t count) {
957   LOG(("HttpChannelChild::DoOnDataAvailable [this=%p]\n", this));
958   if (mCanceled) return;
959 
960   if (mListener) {
961     nsCOMPtr<nsIStreamListener> listener(mListener);
962     nsresult rv = listener->OnDataAvailable(aRequest, aContext, aStream, offset, count);
963     if (NS_FAILED(rv)) {
964       CancelOnMainThread(rv);
965     }
966   }
967 }
968 
969 class StopRequestEvent : public NeckoTargetChannelEvent<HttpChannelChild> {
970  public:
StopRequestEvent(HttpChannelChild * child,const nsresult & channelStatus,const ResourceTimingStruct & timing,const nsHttpHeaderArray & aResponseTrailers)971   StopRequestEvent(HttpChannelChild* child, const nsresult& channelStatus,
972                    const ResourceTimingStruct& timing,
973                    const nsHttpHeaderArray& aResponseTrailers)
974       : NeckoTargetChannelEvent<HttpChannelChild>(child),
975         mChannelStatus(channelStatus),
976         mTiming(timing),
977         mResponseTrailers(aResponseTrailers) {}
978 
Run()979   void Run() override {
980     mChild->OnStopRequest(mChannelStatus, mTiming, mResponseTrailers);
981   }
982 
983  private:
984   nsresult mChannelStatus;
985   ResourceTimingStruct mTiming;
986   nsHttpHeaderArray mResponseTrailers;
987 };
988 
ProcessOnStopRequest(const nsresult & aChannelStatus,const ResourceTimingStruct & aTiming,const nsHttpHeaderArray & aResponseTrailers)989 void HttpChannelChild::ProcessOnStopRequest(
990     const nsresult& aChannelStatus, const ResourceTimingStruct& aTiming,
991     const nsHttpHeaderArray& aResponseTrailers) {
992   LOG(("HttpChannelChild::ProcessOnStopRequest [this=%p]\n", this));
993   MOZ_ASSERT(OnSocketThread());
994   MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
995                      "Should not be receiving any more callbacks from parent!");
996 
997   mEventQ->RunOrEnqueue(
998       new StopRequestEvent(this, aChannelStatus, aTiming, aResponseTrailers),
999       mDivertingToParent);
1000 }
1001 
1002 class MaybeDivertOnStopHttpEvent
1003     : public NeckoTargetChannelEvent<HttpChannelChild> {
1004  public:
MaybeDivertOnStopHttpEvent(HttpChannelChild * child,const nsresult & channelStatus)1005   MaybeDivertOnStopHttpEvent(HttpChannelChild* child,
1006                              const nsresult& channelStatus)
1007       : NeckoTargetChannelEvent<HttpChannelChild>(child),
1008         mChannelStatus(channelStatus) {}
1009 
Run()1010   void Run() override { mChild->MaybeDivertOnStop(mChannelStatus); }
1011 
1012  private:
1013   nsresult mChannelStatus;
1014 };
1015 
MaybeDivertOnStop(const nsresult & aChannelStatus)1016 void HttpChannelChild::MaybeDivertOnStop(const nsresult& aChannelStatus) {
1017   LOG(
1018       ("HttpChannelChild::MaybeDivertOnStop [this=%p, "
1019        "mDivertingToParent=%d status=%" PRIx32 "]",
1020        this, static_cast<bool>(mDivertingToParent),
1021        static_cast<uint32_t>(aChannelStatus)));
1022   if (mDivertingToParent) {
1023     SendDivertOnStopRequest(aChannelStatus);
1024   }
1025 }
1026 
OnStopRequest(const nsresult & channelStatus,const ResourceTimingStruct & timing,const nsHttpHeaderArray & aResponseTrailers)1027 void HttpChannelChild::OnStopRequest(
1028     const nsresult& channelStatus, const ResourceTimingStruct& timing,
1029     const nsHttpHeaderArray& aResponseTrailers) {
1030   LOG(("HttpChannelChild::OnStopRequest [this=%p status=%" PRIx32 "]\n", this,
1031        static_cast<uint32_t>(channelStatus)));
1032   MOZ_ASSERT(NS_IsMainThread());
1033 
1034   if (mDivertingToParent) {
1035     MOZ_RELEASE_ASSERT(
1036         !mFlushedForDiversion,
1037         "Should not be processing any more callbacks from parent!");
1038 
1039     SendDivertOnStopRequest(channelStatus);
1040     return;
1041   }
1042 
1043   if (mUnknownDecoderInvolved) {
1044     LOG(("UnknownDecoder is involved queue OnStopRequest call. [this=%p]",
1045          this));
1046     MOZ_ASSERT(NS_IsMainThread());
1047     mUnknownDecoderEventQ.AppendElement(
1048         MakeUnique<MaybeDivertOnStopHttpEvent>(this, channelStatus));
1049   }
1050 
1051   nsCOMPtr<nsICompressConvStats> conv = do_QueryInterface(mCompressListener);
1052   if (conv) {
1053     conv->GetDecodedDataLength(&mDecodedBodySize);
1054   }
1055 
1056   mTransactionTimings.domainLookupStart = timing.domainLookupStart;
1057   mTransactionTimings.domainLookupEnd = timing.domainLookupEnd;
1058   mTransactionTimings.connectStart = timing.connectStart;
1059   mTransactionTimings.tcpConnectEnd = timing.tcpConnectEnd;
1060   mTransactionTimings.secureConnectionStart = timing.secureConnectionStart;
1061   mTransactionTimings.connectEnd = timing.connectEnd;
1062   mTransactionTimings.requestStart = timing.requestStart;
1063   mTransactionTimings.responseStart = timing.responseStart;
1064   mTransactionTimings.responseEnd = timing.responseEnd;
1065 
1066   // Do not overwrite or adjust the original mAsyncOpenTime by timing.fetchStart
1067   // We must use the original child process time in order to account for child
1068   // side work and IPC transit overhead.
1069   // XXX: This depends on TimeStamp being equivalent across processes.
1070   // This is true for modern hardware but for older platforms it is not always
1071   // true.
1072 
1073   mRedirectStartTimeStamp = timing.redirectStart;
1074   mRedirectEndTimeStamp = timing.redirectEnd;
1075   mTransferSize = timing.transferSize;
1076   mEncodedBodySize = timing.encodedBodySize;
1077   mProtocolVersion = timing.protocolVersion;
1078 
1079   mCacheReadStart = timing.cacheReadStart;
1080   mCacheReadEnd = timing.cacheReadEnd;
1081 
1082   mResponseTrailers = new nsHttpHeaderArray(aResponseTrailers);
1083 
1084   DoPreOnStopRequest(channelStatus);
1085 
1086   {  // We must flush the queue before we Send__delete__
1087     // (although we really shouldn't receive any msgs after OnStop),
1088     // so make sure this goes out of scope before then.
1089     AutoEventEnqueuer ensureSerialDispatch(mEventQ);
1090 
1091     DoOnStopRequest(this, channelStatus, mListenerContext);
1092     // DoOnStopRequest() calls ReleaseListeners()
1093   }
1094 
1095   // If unknownDecoder is involved and the received content is short we will
1096   // know whether we need to divert to parent only after OnStopRequest of the
1097   // listeners chain is called in DoOnStopRequest. At that moment
1098   // unknownDecoder will call OnStartRequest of the real listeners of the
1099   // channel including the OnStopRequest of UrlLoader which decides whether we
1100   // need to divert to parent.
1101   // If we are diverting to parent we should not do a cleanup.
1102   if (mDivertingToParent) {
1103     LOG(
1104         ("HttpChannelChild::OnStopRequest  - We are diverting to parent, "
1105          "postpone cleaning up."));
1106     return;
1107   }
1108 
1109   CleanupBackgroundChannel();
1110 
1111   // If there is a possibility we might want to write alt data to the cache
1112   // entry, we keep the channel alive. We still send the DocumentChannelCleanup
1113   // message but request the cache entry to be kept by the parent.
1114   // If the channel has failed, the cache entry is in a non-writtable state and
1115   // we want to release it to not block following consumers.
1116   if (NS_SUCCEEDED(channelStatus) && !mPreferredCachedAltDataType.IsEmpty()) {
1117     mKeptAlive = true;
1118     SendDocumentChannelCleanup(false);  // don't clear cache entry
1119     return;
1120   }
1121 
1122   if (mLoadFlags & LOAD_DOCUMENT_URI) {
1123     // Keep IPDL channel open, but only for updating security info.
1124     // If IPDL is already closed, then do nothing.
1125     if (mIPCOpen) {
1126       mKeptAlive = true;
1127       SendDocumentChannelCleanup(true);
1128     }
1129   } else {
1130     // The parent process will respond by sending a DeleteSelf message and
1131     // making sure not to send any more messages after that.
1132     TrySendDeletingChannel();
1133   }
1134 }
1135 
DoPreOnStopRequest(nsresult aStatus)1136 void HttpChannelChild::DoPreOnStopRequest(nsresult aStatus) {
1137   LOG(("HttpChannelChild::DoPreOnStopRequest [this=%p status=%" PRIx32 "]\n",
1138        this, static_cast<uint32_t>(aStatus)));
1139   mIsPending = false;
1140 
1141   MaybeCallSynthesizedCallback();
1142 
1143   PerformanceStorage* performanceStorage = GetPerformanceStorage();
1144   if (performanceStorage) {
1145     performanceStorage->AddEntry(this, this);
1146   }
1147 
1148   if (!mCanceled && NS_SUCCEEDED(mStatus)) {
1149     mStatus = aStatus;
1150   }
1151 
1152   CollectOMTTelemetry();
1153 }
1154 
CollectOMTTelemetry()1155 void HttpChannelChild::CollectOMTTelemetry() {
1156   MOZ_ASSERT(NS_IsMainThread());
1157 
1158   // Only collect telemetry for HTTP channel that is loaded successfully and
1159   // completely.
1160   if (mCanceled || NS_FAILED(mStatus)) {
1161     return;
1162   }
1163 
1164   // Use content policy type to accumulate data by usage.
1165   nsContentPolicyType type = mLoadInfo ? mLoadInfo->InternalContentPolicyType()
1166                                        : nsIContentPolicy::TYPE_OTHER;
1167 
1168   nsAutoCString key(NS_CP_ContentTypeName(type));
1169 
1170   Telemetry::AccumulateCategoricalKeyed(key, mOMTResult);
1171 }
1172 
DoOnStopRequest(nsIRequest * aRequest,nsresult aChannelStatus,nsISupports * aContext)1173 void HttpChannelChild::DoOnStopRequest(nsIRequest* aRequest,
1174                                        nsresult aChannelStatus,
1175                                        nsISupports* aContext) {
1176   LOG(("HttpChannelChild::DoOnStopRequest [this=%p]\n", this));
1177   MOZ_ASSERT(NS_IsMainThread());
1178   MOZ_ASSERT(!mIsPending);
1179 
1180   // NB: We use aChannelStatus here instead of mStatus because if there was an
1181   // nsCORSListenerProxy on this request, it will override the tracking
1182   // protection's return value.
1183   if (aChannelStatus == NS_ERROR_TRACKING_URI ||
1184       aChannelStatus == NS_ERROR_MALWARE_URI ||
1185       aChannelStatus == NS_ERROR_UNWANTED_URI ||
1186       aChannelStatus == NS_ERROR_BLOCKED_URI ||
1187       aChannelStatus == NS_ERROR_HARMFUL_URI ||
1188       aChannelStatus == NS_ERROR_PHISHING_URI) {
1189     nsCString list, provider, fullhash;
1190 
1191     nsresult rv = GetMatchedList(list);
1192     NS_ENSURE_SUCCESS_VOID(rv);
1193 
1194     rv = GetMatchedProvider(provider);
1195     NS_ENSURE_SUCCESS_VOID(rv);
1196 
1197     rv = GetMatchedFullHash(fullhash);
1198     NS_ENSURE_SUCCESS_VOID(rv);
1199 
1200     nsChannelClassifier::SetBlockedContent(this, aChannelStatus, list, provider,
1201                                            fullhash);
1202   }
1203 
1204   MOZ_ASSERT(!mOnStopRequestCalled, "We should not call OnStopRequest twice");
1205 
1206   // In theory mListener should not be null, but in practice sometimes it is.
1207   MOZ_ASSERT(mListener);
1208   if (mListener) {
1209     nsCOMPtr<nsIStreamListener> listener(mListener);
1210     listener->OnStopRequest(aRequest, aContext, mStatus);
1211   }
1212   mOnStopRequestCalled = true;
1213 
1214   // notify "http-on-stop-connect" observers
1215   gHttpHandler->OnStopRequest(this);
1216 
1217   ReleaseListeners();
1218 
1219   // If a preferred alt-data type was set, the parent would hold a reference to
1220   // the cache entry in case the child calls openAlternativeOutputStream().
1221   // (see nsHttpChannel::OnStopRequest)
1222   if (!mPreferredCachedAltDataType.IsEmpty()) {
1223     mAltDataCacheEntryAvailable = mCacheEntryAvailable;
1224   }
1225   mCacheEntryAvailable = false;
1226 
1227   if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus);
1228 }
1229 
1230 class ProgressEvent : public NeckoTargetChannelEvent<HttpChannelChild> {
1231  public:
ProgressEvent(HttpChannelChild * child,const int64_t & progress,const int64_t & progressMax)1232   ProgressEvent(HttpChannelChild* child, const int64_t& progress,
1233                 const int64_t& progressMax)
1234       : NeckoTargetChannelEvent<HttpChannelChild>(child),
1235         mProgress(progress),
1236         mProgressMax(progressMax) {}
1237 
Run()1238   void Run() override { mChild->OnProgress(mProgress, mProgressMax); }
1239 
1240  private:
1241   int64_t mProgress, mProgressMax;
1242 };
1243 
ProcessOnProgress(const int64_t & aProgress,const int64_t & aProgressMax)1244 void HttpChannelChild::ProcessOnProgress(const int64_t& aProgress,
1245                                          const int64_t& aProgressMax) {
1246   LOG(("HttpChannelChild::ProcessOnProgress [this=%p]\n", this));
1247   MOZ_ASSERT(OnSocketThread());
1248   mEventQ->RunOrEnqueue(new ProgressEvent(this, aProgress, aProgressMax));
1249 }
1250 
OnProgress(const int64_t & progress,const int64_t & progressMax)1251 void HttpChannelChild::OnProgress(const int64_t& progress,
1252                                   const int64_t& progressMax) {
1253   LOG(("HttpChannelChild::OnProgress [this=%p progress=%" PRId64 "/%" PRId64
1254        "]\n",
1255        this, progress, progressMax));
1256 
1257   if (mCanceled) return;
1258 
1259   // cache the progress sink so we don't have to query for it each time.
1260   if (!mProgressSink) {
1261     GetCallback(mProgressSink);
1262   }
1263 
1264   AutoEventEnqueuer ensureSerialDispatch(mEventQ);
1265 
1266   // Block socket status event after Cancel or OnStopRequest has been called.
1267   if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending) {
1268     if (progress > 0) {
1269       mProgressSink->OnProgress(this, nullptr, progress, progressMax);
1270     }
1271   }
1272 }
1273 
1274 class StatusEvent : public NeckoTargetChannelEvent<HttpChannelChild> {
1275  public:
StatusEvent(HttpChannelChild * child,const nsresult & status)1276   StatusEvent(HttpChannelChild* child, const nsresult& status)
1277       : NeckoTargetChannelEvent<HttpChannelChild>(child), mStatus(status) {}
1278 
Run()1279   void Run() override { mChild->OnStatus(mStatus); }
1280 
1281  private:
1282   nsresult mStatus;
1283 };
1284 
ProcessOnStatus(const nsresult & aStatus)1285 void HttpChannelChild::ProcessOnStatus(const nsresult& aStatus) {
1286   LOG(("HttpChannelChild::ProcessOnStatus [this=%p]\n", this));
1287   MOZ_ASSERT(OnSocketThread());
1288   mEventQ->RunOrEnqueue(new StatusEvent(this, aStatus));
1289 }
1290 
OnStatus(const nsresult & status)1291 void HttpChannelChild::OnStatus(const nsresult& status) {
1292   LOG(("HttpChannelChild::OnStatus [this=%p status=%" PRIx32 "]\n", this,
1293        static_cast<uint32_t>(status)));
1294 
1295   if (mCanceled) return;
1296 
1297   // cache the progress sink so we don't have to query for it each time.
1298   if (!mProgressSink) GetCallback(mProgressSink);
1299 
1300   AutoEventEnqueuer ensureSerialDispatch(mEventQ);
1301 
1302   // block socket status event after Cancel or OnStopRequest has been called,
1303   // or if channel has LOAD_BACKGROUND set
1304   if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending &&
1305       !(mLoadFlags & LOAD_BACKGROUND)) {
1306     nsAutoCString host;
1307     mURI->GetHost(host);
1308     mProgressSink->OnStatus(this, nullptr, status,
1309                             NS_ConvertUTF8toUTF16(host).get());
1310   }
1311 }
1312 
1313 class FailedAsyncOpenEvent : public NeckoTargetChannelEvent<HttpChannelChild> {
1314  public:
FailedAsyncOpenEvent(HttpChannelChild * child,const nsresult & status)1315   FailedAsyncOpenEvent(HttpChannelChild* child, const nsresult& status)
1316       : NeckoTargetChannelEvent<HttpChannelChild>(child), mStatus(status) {}
1317 
Run()1318   void Run() override { mChild->FailedAsyncOpen(mStatus); }
1319 
1320  private:
1321   nsresult mStatus;
1322 };
1323 
RecvFailedAsyncOpen(const nsresult & status)1324 mozilla::ipc::IPCResult HttpChannelChild::RecvFailedAsyncOpen(
1325     const nsresult& status) {
1326   LOG(("HttpChannelChild::RecvFailedAsyncOpen [this=%p]\n", this));
1327   mEventQ->RunOrEnqueue(new FailedAsyncOpenEvent(this, status));
1328   return IPC_OK();
1329 }
1330 
1331 // We need to have an implementation of this function just so that we can keep
1332 // all references to mCallOnResume of type HttpChannelChild:  it's not OK in C++
1333 // to set a member function ptr to a base class function.
HandleAsyncAbort()1334 void HttpChannelChild::HandleAsyncAbort() {
1335   HttpAsyncAborter<HttpChannelChild>::HandleAsyncAbort();
1336 
1337   // Ignore all the messages from background channel after channel aborted.
1338   CleanupBackgroundChannel();
1339 }
1340 
FailedAsyncOpen(const nsresult & status)1341 void HttpChannelChild::FailedAsyncOpen(const nsresult& status) {
1342   LOG(("HttpChannelChild::FailedAsyncOpen [this=%p status=%" PRIx32 "]\n", this,
1343        static_cast<uint32_t>(status)));
1344   MOZ_ASSERT(NS_IsMainThread());
1345 
1346   // Might be called twice in race condition in theory.
1347   // (one by RecvFailedAsyncOpen, another by
1348   // HttpBackgroundChannelChild::ActorFailed)
1349   if (NS_WARN_IF(NS_FAILED(mStatus))) {
1350     return;
1351   }
1352 
1353   mStatus = status;
1354 
1355   // We're already being called from IPDL, therefore already "async"
1356   HandleAsyncAbort();
1357 
1358   if (mIPCOpen) {
1359     TrySendDeletingChannel();
1360   }
1361 }
1362 
CleanupBackgroundChannel()1363 void HttpChannelChild::CleanupBackgroundChannel() {
1364   MutexAutoLock lock(mBgChildMutex);
1365 
1366   LOG(("HttpChannelChild::CleanupBackgroundChannel [this=%p bgChild=%p]\n",
1367        this, mBgChild.get()));
1368 
1369   mBgInitFailCallback = nullptr;
1370 
1371   if (!mBgChild) {
1372     return;
1373   }
1374 
1375   RefPtr<HttpBackgroundChannelChild> bgChild = mBgChild.forget();
1376 
1377   MOZ_RELEASE_ASSERT(gSocketTransportService);
1378   if (!OnSocketThread()) {
1379     gSocketTransportService->Dispatch(
1380         NewRunnableMethod("HttpBackgroundChannelChild::OnChannelClosed",
1381                           bgChild,
1382                           &HttpBackgroundChannelChild::OnChannelClosed),
1383         NS_DISPATCH_NORMAL);
1384   } else {
1385     bgChild->OnChannelClosed();
1386   }
1387 }
1388 
DoNotifyListenerCleanup()1389 void HttpChannelChild::DoNotifyListenerCleanup() {
1390   LOG(("HttpChannelChild::DoNotifyListenerCleanup [this=%p]\n", this));
1391 
1392   if (mInterceptListener) {
1393     mInterceptListener->Cleanup();
1394     mInterceptListener = nullptr;
1395   }
1396 
1397   MaybeCallSynthesizedCallback();
1398 }
1399 
1400 class DeleteSelfEvent : public NeckoTargetChannelEvent<HttpChannelChild> {
1401  public:
DeleteSelfEvent(HttpChannelChild * child)1402   explicit DeleteSelfEvent(HttpChannelChild* child)
1403       : NeckoTargetChannelEvent<HttpChannelChild>(child) {}
Run()1404   void Run() override { mChild->DeleteSelf(); }
1405 };
1406 
RecvDeleteSelf()1407 mozilla::ipc::IPCResult HttpChannelChild::RecvDeleteSelf() {
1408   LOG(("HttpChannelChild::RecvDeleteSelf [this=%p]\n", this));
1409   mEventQ->RunOrEnqueue(new DeleteSelfEvent(this));
1410   return IPC_OK();
1411 }
1412 
OverrideRunnable(HttpChannelChild * aChannel,HttpChannelChild * aNewChannel,InterceptStreamListener * aListener,nsIInputStream * aInput,nsIInterceptedBodyCallback * aCallback,nsAutoPtr<nsHttpResponseHead> & aHead,nsICacheInfoChannel * aCacheInfo)1413 HttpChannelChild::OverrideRunnable::OverrideRunnable(
1414     HttpChannelChild* aChannel, HttpChannelChild* aNewChannel,
1415     InterceptStreamListener* aListener, nsIInputStream* aInput,
1416     nsIInterceptedBodyCallback* aCallback, nsAutoPtr<nsHttpResponseHead>& aHead,
1417     nsICacheInfoChannel* aCacheInfo)
1418     : Runnable("net::HttpChannelChild::OverrideRunnable") {
1419   mChannel = aChannel;
1420   mNewChannel = aNewChannel;
1421   mListener = aListener;
1422   mInput = aInput;
1423   mCallback = aCallback;
1424   mHead = aHead;
1425   mSynthesizedCacheInfo = aCacheInfo;
1426 }
1427 
OverrideWithSynthesizedResponse()1428 void HttpChannelChild::OverrideRunnable::OverrideWithSynthesizedResponse() {
1429   if (mNewChannel) {
1430     mNewChannel->OverrideWithSynthesizedResponse(
1431         mHead, mInput, mCallback, mListener, mSynthesizedCacheInfo);
1432   }
1433 }
1434 
1435 NS_IMETHODIMP
Run()1436 HttpChannelChild::OverrideRunnable::Run() {
1437   // Check to see if the channel was canceled in the middle of the redirect.
1438   nsresult rv = NS_OK;
1439   Unused << mChannel->GetStatus(&rv);
1440   if (NS_FAILED(rv)) {
1441     if (mCallback) {
1442       mCallback->BodyComplete(rv);
1443       mCallback = nullptr;
1444     }
1445     mChannel->CleanupRedirectingChannel(rv);
1446     if (mNewChannel) {
1447       mNewChannel->Cancel(rv);
1448     }
1449     return NS_OK;
1450   }
1451 
1452   bool ret = mChannel->Redirect3Complete(this);
1453 
1454   // If the method returns false, it means the IPDL connection is being
1455   // asyncly torn down and reopened, and OverrideWithSynthesizedResponse
1456   // will be called later from FinishInterceptedRedirect. This object will
1457   // be assigned to HttpChannelChild::mOverrideRunnable in order to do so.
1458   // If it is true, we can call the method right now.
1459   if (ret) {
1460     OverrideWithSynthesizedResponse();
1461   }
1462 
1463   return NS_OK;
1464 }
1465 
RecvFinishInterceptedRedirect()1466 mozilla::ipc::IPCResult HttpChannelChild::RecvFinishInterceptedRedirect() {
1467   // Hold a ref to this to keep it from being deleted by Send__delete__()
1468   RefPtr<HttpChannelChild> self(this);
1469   Send__delete__(this);
1470 
1471   {
1472     // Reset the event target since the IPC actor is about to be destroyed.
1473     // Following channel event should be handled on main thread.
1474     MutexAutoLock lock(mEventTargetMutex);
1475     mNeckoTarget = nullptr;
1476   }
1477 
1478   // The IPDL connection was torn down by a interception logic in
1479   // CompleteRedirectSetup, and we need to call FinishInterceptedRedirect.
1480   nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget();
1481   MOZ_ASSERT(neckoTarget);
1482 
1483   Unused << neckoTarget->Dispatch(
1484       NewRunnableMethod("net::HttpChannelChild::FinishInterceptedRedirect",
1485                         this, &HttpChannelChild::FinishInterceptedRedirect),
1486       NS_DISPATCH_NORMAL);
1487 
1488   return IPC_OK();
1489 }
1490 
DeleteSelf()1491 void HttpChannelChild::DeleteSelf() { Send__delete__(this); }
1492 
1493 class ContinueDoNotifyListenerEvent
1494     : public NeckoTargetChannelEvent<HttpChannelChild> {
1495  public:
ContinueDoNotifyListenerEvent(HttpChannelChild * child)1496   explicit ContinueDoNotifyListenerEvent(HttpChannelChild* child)
1497       : NeckoTargetChannelEvent<HttpChannelChild>(child) {}
Run()1498   void Run() override { mChild->ContinueDoNotifyListener(); }
1499 };
1500 
DoNotifyListener()1501 void HttpChannelChild::DoNotifyListener() {
1502   LOG(("HttpChannelChild::DoNotifyListener this=%p", this));
1503   MOZ_ASSERT(NS_IsMainThread());
1504 
1505   if (mListener) {
1506     MOZ_ASSERT(!mOnStartRequestCalled,
1507                "We should not call OnStartRequest twice");
1508 
1509     nsCOMPtr<nsIStreamListener> listener = mListener;
1510     listener->OnStartRequest(this, mListenerContext);
1511 
1512     mOnStartRequestCalled = true;
1513   }
1514 
1515   mEventQ->RunOrEnqueue(new ContinueDoNotifyListenerEvent(this));
1516 }
1517 
ContinueDoNotifyListener()1518 void HttpChannelChild::ContinueDoNotifyListener() {
1519   LOG(("HttpChannelChild::ContinueDoNotifyListener this=%p", this));
1520   MOZ_ASSERT(NS_IsMainThread());
1521 
1522   // Make sure mIsPending is set to false. At this moment we are done from
1523   // the point of view of our consumer and we have to report our self
1524   // as not-pending.
1525   mIsPending = false;
1526 
1527   if (mListener) {
1528     MOZ_ASSERT(!mOnStopRequestCalled, "We should not call OnStopRequest twice");
1529 
1530     nsCOMPtr<nsIStreamListener> listener = mListener;
1531     listener->OnStopRequest(this, mListenerContext, mStatus);
1532 
1533     mOnStopRequestCalled = true;
1534   }
1535 
1536   // notify "http-on-stop-connect" observers
1537   gHttpHandler->OnStopRequest(this);
1538 
1539   // This channel has finished its job, potentially release any tail-blocked
1540   // requests with this.
1541   RemoveAsNonTailRequest();
1542 
1543   // We have to make sure to drop the references to listeners and callbacks
1544   // no longer needed.
1545   ReleaseListeners();
1546 
1547   DoNotifyListenerCleanup();
1548 
1549   // If this is a navigation, then we must let the docshell flush the reports
1550   // to the console later.  The LoadDocument() is pointing at the detached
1551   // document that started the navigation.  We want to show the reports on the
1552   // new document.  Otherwise the console is wiped and the user never sees
1553   // the information.
1554   if (!IsNavigation()) {
1555     if (mLoadGroup) {
1556       FlushConsoleReports(mLoadGroup);
1557     } else if (mLoadInfo) {
1558       nsCOMPtr<nsIDOMDocument> dommyDoc;
1559       mLoadInfo->GetLoadingDocument(getter_AddRefs(dommyDoc));
1560       nsCOMPtr<nsIDocument> doc = do_QueryInterface(dommyDoc);
1561       FlushConsoleReports(doc);
1562     }
1563   }
1564 }
1565 
FinishInterceptedRedirect()1566 void HttpChannelChild::FinishInterceptedRedirect() {
1567   nsresult rv;
1568   if (mLoadInfo && mLoadInfo->GetEnforceSecurity()) {
1569     MOZ_ASSERT(!mInterceptedRedirectContext, "the context should be null!");
1570     rv = AsyncOpen2(mInterceptedRedirectListener);
1571   } else {
1572     rv = AsyncOpen(mInterceptedRedirectListener, mInterceptedRedirectContext);
1573   }
1574   mInterceptedRedirectListener = nullptr;
1575   mInterceptedRedirectContext = nullptr;
1576 
1577   if (mInterceptingChannel) {
1578     mInterceptingChannel->CleanupRedirectingChannel(rv);
1579     mInterceptingChannel = nullptr;
1580   }
1581 
1582   if (mOverrideRunnable) {
1583     mOverrideRunnable->OverrideWithSynthesizedResponse();
1584     mOverrideRunnable = nullptr;
1585   }
1586 }
1587 
RecvReportSecurityMessage(const nsString & messageTag,const nsString & messageCategory)1588 mozilla::ipc::IPCResult HttpChannelChild::RecvReportSecurityMessage(
1589     const nsString& messageTag, const nsString& messageCategory) {
1590   DebugOnly<nsresult> rv = AddSecurityMessage(messageTag, messageCategory);
1591   MOZ_ASSERT(NS_SUCCEEDED(rv));
1592   return IPC_OK();
1593 }
1594 
1595 class Redirect1Event : public NeckoTargetChannelEvent<HttpChannelChild> {
1596  public:
Redirect1Event(HttpChannelChild * child,const uint32_t & registrarId,const URIParams & newURI,const uint32_t & redirectFlags,const ParentLoadInfoForwarderArgs & loadInfoForwarder,const nsHttpResponseHead & responseHead,const nsACString & securityInfoSerialization,const uint64_t & channelId)1597   Redirect1Event(HttpChannelChild* child, const uint32_t& registrarId,
1598                  const URIParams& newURI, const uint32_t& redirectFlags,
1599                  const ParentLoadInfoForwarderArgs& loadInfoForwarder,
1600                  const nsHttpResponseHead& responseHead,
1601                  const nsACString& securityInfoSerialization,
1602                  const uint64_t& channelId)
1603       : NeckoTargetChannelEvent<HttpChannelChild>(child),
1604         mRegistrarId(registrarId),
1605         mNewURI(newURI),
1606         mRedirectFlags(redirectFlags),
1607         mResponseHead(responseHead),
1608         mSecurityInfoSerialization(securityInfoSerialization),
1609         mChannelId(channelId),
1610         mLoadInfoForwarder(loadInfoForwarder) {}
1611 
Run()1612   void Run() override {
1613     mChild->Redirect1Begin(mRegistrarId, mNewURI, mRedirectFlags,
1614                            mLoadInfoForwarder, mResponseHead,
1615                            mSecurityInfoSerialization, mChannelId);
1616   }
1617 
1618  private:
1619   uint32_t mRegistrarId;
1620   URIParams mNewURI;
1621   uint32_t mRedirectFlags;
1622   nsHttpResponseHead mResponseHead;
1623   nsCString mSecurityInfoSerialization;
1624   uint64_t mChannelId;
1625   ParentLoadInfoForwarderArgs mLoadInfoForwarder;
1626 };
1627 
RecvRedirect1Begin(const uint32_t & registrarId,const URIParams & newUri,const uint32_t & redirectFlags,const ParentLoadInfoForwarderArgs & loadInfoForwarder,const nsHttpResponseHead & responseHead,const nsCString & securityInfoSerialization,const uint64_t & channelId,const NetAddr & oldPeerAddr)1628 mozilla::ipc::IPCResult HttpChannelChild::RecvRedirect1Begin(
1629     const uint32_t& registrarId, const URIParams& newUri,
1630     const uint32_t& redirectFlags,
1631     const ParentLoadInfoForwarderArgs& loadInfoForwarder,
1632     const nsHttpResponseHead& responseHead,
1633     const nsCString& securityInfoSerialization, const uint64_t& channelId,
1634     const NetAddr& oldPeerAddr) {
1635   // TODO: handle security info
1636   LOG(("HttpChannelChild::RecvRedirect1Begin [this=%p]\n", this));
1637   // We set peer address of child to the old peer,
1638   // Then it will be updated to new peer in OnStartRequest
1639   mPeerAddr = oldPeerAddr;
1640 
1641   mEventQ->RunOrEnqueue(new Redirect1Event(
1642       this, registrarId, newUri, redirectFlags, loadInfoForwarder, responseHead,
1643       securityInfoSerialization, channelId));
1644   return IPC_OK();
1645 }
1646 
SetupRedirect(nsIURI * uri,const nsHttpResponseHead * responseHead,const uint32_t & redirectFlags,nsIChannel ** outChannel)1647 nsresult HttpChannelChild::SetupRedirect(nsIURI* uri,
1648                                          const nsHttpResponseHead* responseHead,
1649                                          const uint32_t& redirectFlags,
1650                                          nsIChannel** outChannel) {
1651   LOG(("HttpChannelChild::SetupRedirect [this=%p]\n", this));
1652 
1653   nsresult rv;
1654   nsCOMPtr<nsIIOService> ioService;
1655   rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
1656   NS_ENSURE_SUCCESS(rv, rv);
1657 
1658   nsCOMPtr<nsIChannel> newChannel;
1659   nsCOMPtr<nsILoadInfo> redirectLoadInfo =
1660       CloneLoadInfoForRedirect(uri, redirectFlags);
1661   rv = NS_NewChannelInternal(getter_AddRefs(newChannel), uri, redirectLoadInfo,
1662                              nullptr,  // PerformanceStorage
1663                              nullptr,  // aLoadGroup
1664                              nullptr,  // aCallbacks
1665                              nsIRequest::LOAD_NORMAL, ioService);
1666   NS_ENSURE_SUCCESS(rv, rv);
1667 
1668   // We won't get OnStartRequest, set cookies here.
1669   mResponseHead = new nsHttpResponseHead(*responseHead);
1670 
1671   bool rewriteToGET = HttpBaseChannel::ShouldRewriteRedirectToGET(
1672       mResponseHead->Status(), mRequestHead.ParsedMethod());
1673 
1674   rv = SetupReplacementChannel(uri, newChannel, !rewriteToGET, redirectFlags);
1675   NS_ENSURE_SUCCESS(rv, rv);
1676 
1677   nsCOMPtr<nsIHttpChannelChild> httpChannelChild =
1678       do_QueryInterface(newChannel);
1679   if (httpChannelChild) {
1680     bool shouldUpgrade = false;
1681     auto channelChild = static_cast<HttpChannelChild*>(httpChannelChild.get());
1682     if (mShouldInterceptSubsequentRedirect) {
1683       // In the case where there was a synthesized response that caused a
1684       // redirection, we must force the new channel to intercept the request in
1685       // the parent before a network transaction is initiated.
1686       rv = httpChannelChild->ForceIntercepted(false, false);
1687     } else if (mRedirectMode == nsIHttpChannelInternal::REDIRECT_MODE_MANUAL &&
1688                ((redirectFlags & (nsIChannelEventSink::REDIRECT_TEMPORARY |
1689                                   nsIChannelEventSink::REDIRECT_PERMANENT)) !=
1690                 0) &&
1691                channelChild->ShouldInterceptURI(uri, shouldUpgrade)) {
1692       // In the case where the redirect mode is manual, we need to check whether
1693       // the post-redirect channel needs to be intercepted.  If that is the
1694       // case, force the new channel to intercept the request in the parent
1695       // similar to the case above, but also remember that ShouldInterceptURI()
1696       // returned true to avoid calling it a second time.
1697       rv = httpChannelChild->ForceIntercepted(true, shouldUpgrade);
1698     }
1699     MOZ_ASSERT(NS_SUCCEEDED(rv));
1700   }
1701 
1702   mRedirectChannelChild = do_QueryInterface(newChannel);
1703   newChannel.forget(outChannel);
1704 
1705   return NS_OK;
1706 }
1707 
Redirect1Begin(const uint32_t & registrarId,const URIParams & newOriginalURI,const uint32_t & redirectFlags,const ParentLoadInfoForwarderArgs & loadInfoForwarder,const nsHttpResponseHead & responseHead,const nsACString & securityInfoSerialization,const uint64_t & channelId)1708 void HttpChannelChild::Redirect1Begin(
1709     const uint32_t& registrarId, const URIParams& newOriginalURI,
1710     const uint32_t& redirectFlags,
1711     const ParentLoadInfoForwarderArgs& loadInfoForwarder,
1712     const nsHttpResponseHead& responseHead,
1713     const nsACString& securityInfoSerialization, const uint64_t& channelId) {
1714   nsresult rv;
1715 
1716   LOG(("HttpChannelChild::Redirect1Begin [this=%p]\n", this));
1717 
1718   ipc::MergeParentLoadInfoForwarder(loadInfoForwarder, mLoadInfo);
1719 
1720   nsCOMPtr<nsIURI> uri = DeserializeURI(newOriginalURI);
1721 
1722   if (!securityInfoSerialization.IsEmpty()) {
1723     NS_DeserializeObject(securityInfoSerialization,
1724                          getter_AddRefs(mSecurityInfo));
1725   }
1726 
1727   nsCOMPtr<nsIChannel> newChannel;
1728   rv = SetupRedirect(uri, &responseHead, redirectFlags,
1729                      getter_AddRefs(newChannel));
1730 
1731   if (NS_SUCCEEDED(rv)) {
1732     if (mRedirectChannelChild) {
1733       // Set the channelId allocated in parent to the child instance
1734       nsCOMPtr<nsIHttpChannel> httpChannel =
1735           do_QueryInterface(mRedirectChannelChild);
1736       if (httpChannel) {
1737         rv = httpChannel->SetChannelId(channelId);
1738         MOZ_ASSERT(NS_SUCCEEDED(rv));
1739       }
1740       mRedirectChannelChild->ConnectParent(registrarId);
1741     }
1742 
1743     nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
1744     MOZ_ASSERT(target);
1745 
1746     rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, redirectFlags,
1747                                               target);
1748   }
1749 
1750   if (NS_FAILED(rv)) OnRedirectVerifyCallback(rv);
1751 }
1752 
BeginNonIPCRedirect(nsIURI * responseURI,const nsHttpResponseHead * responseHead,bool aResponseRedirected)1753 void HttpChannelChild::BeginNonIPCRedirect(
1754     nsIURI* responseURI, const nsHttpResponseHead* responseHead,
1755     bool aResponseRedirected) {
1756   LOG(("HttpChannelChild::BeginNonIPCRedirect [this=%p]\n", this));
1757 
1758   // If the response has been redirected, propagate all the URLs to content.
1759   // Thus, the exact value of the redirect flag does not matter as long as it's
1760   // not REDIRECT_INTERNAL.
1761   const uint32_t redirectFlag = aResponseRedirected
1762                                     ? nsIChannelEventSink::REDIRECT_TEMPORARY
1763                                     : nsIChannelEventSink::REDIRECT_INTERNAL;
1764 
1765   nsCOMPtr<nsIChannel> newChannel;
1766   nsresult rv = SetupRedirect(responseURI, responseHead, redirectFlag,
1767                               getter_AddRefs(newChannel));
1768 
1769   if (NS_SUCCEEDED(rv)) {
1770     // Ensure that the new channel shares the original channel's security
1771     // information, since it won't be provided via IPC. In particular, if the
1772     // target of this redirect is a synthesized response that has its own
1773     // security info, the pre-redirect channel has already received it and it
1774     // must be propagated to the post-redirect channel.
1775     nsCOMPtr<nsIHttpChannelChild> channelChild = do_QueryInterface(newChannel);
1776     if (mSecurityInfo && channelChild) {
1777       HttpChannelChild* httpChannelChild =
1778           static_cast<HttpChannelChild*>(channelChild.get());
1779       httpChannelChild->OverrideSecurityInfoForNonIPCRedirect(mSecurityInfo);
1780     }
1781 
1782     nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
1783     MOZ_ASSERT(target);
1784 
1785     rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, redirectFlag,
1786                                               target);
1787   }
1788 
1789   if (NS_FAILED(rv)) OnRedirectVerifyCallback(rv);
1790 }
1791 
OverrideSecurityInfoForNonIPCRedirect(nsISupports * securityInfo)1792 void HttpChannelChild::OverrideSecurityInfoForNonIPCRedirect(
1793     nsISupports* securityInfo) {
1794   mResponseCouldBeSynthesized = true;
1795   DebugOnly<nsresult> rv = OverrideSecurityInfo(securityInfo);
1796   MOZ_ASSERT(NS_SUCCEEDED(rv));
1797 }
1798 
1799 class Redirect3Event : public NeckoTargetChannelEvent<HttpChannelChild> {
1800  public:
Redirect3Event(HttpChannelChild * child)1801   explicit Redirect3Event(HttpChannelChild* child)
1802       : NeckoTargetChannelEvent<HttpChannelChild>(child) {}
Run()1803   void Run() override { mChild->Redirect3Complete(nullptr); }
1804 };
1805 
RecvRedirect3Complete()1806 mozilla::ipc::IPCResult HttpChannelChild::RecvRedirect3Complete() {
1807   LOG(("HttpChannelChild::RecvRedirect3Complete [this=%p]\n", this));
1808   mEventQ->RunOrEnqueue(new Redirect3Event(this));
1809   return IPC_OK();
1810 }
1811 
1812 class HttpFlushedForDiversionEvent
1813     : public NeckoTargetChannelEvent<HttpChannelChild> {
1814  public:
HttpFlushedForDiversionEvent(HttpChannelChild * aChild)1815   explicit HttpFlushedForDiversionEvent(HttpChannelChild* aChild)
1816       : NeckoTargetChannelEvent<HttpChannelChild>(aChild) {
1817     MOZ_RELEASE_ASSERT(aChild);
1818   }
1819 
Run()1820   void Run() override { mChild->FlushedForDiversion(); }
1821 };
1822 
ProcessFlushedForDiversion()1823 void HttpChannelChild::ProcessFlushedForDiversion() {
1824   LOG(("HttpChannelChild::ProcessFlushedForDiversion [this=%p]\n", this));
1825   MOZ_ASSERT(OnSocketThread());
1826   MOZ_RELEASE_ASSERT(mDivertingToParent);
1827 
1828   mEventQ->RunOrEnqueue(new HttpFlushedForDiversionEvent(this), true);
1829 }
1830 
ProcessNotifyTrackingProtectionDisabled()1831 void HttpChannelChild::ProcessNotifyTrackingProtectionDisabled() {
1832   LOG(("HttpChannelChild::ProcessNotifyTrackingProtectionDisabled [this=%p]\n",
1833        this));
1834   MOZ_ASSERT(OnSocketThread());
1835 
1836   RefPtr<HttpChannelChild> self = this;
1837   nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget();
1838   neckoTarget->Dispatch(
1839       NS_NewRunnableFunction(
1840           "nsChannelClassifier::NotifyTrackingProtectionDisabled",
1841           [self]() {
1842             nsChannelClassifier::NotifyTrackingProtectionDisabled(self);
1843           }),
1844       NS_DISPATCH_NORMAL);
1845 }
1846 
ProcessNotifyTrackingResource()1847 void HttpChannelChild::ProcessNotifyTrackingResource() {
1848   LOG(("HttpChannelChild::ProcessNotifyTrackingResource [this=%p]\n", this));
1849   MOZ_ASSERT(OnSocketThread());
1850 
1851   SetIsTrackingResource();
1852 }
1853 
FlushedForDiversion()1854 void HttpChannelChild::FlushedForDiversion() {
1855   LOG(("HttpChannelChild::FlushedForDiversion [this=%p]\n", this));
1856   MOZ_RELEASE_ASSERT(mDivertingToParent);
1857 
1858   // Once this is set, it should not be unset before HttpChannelChild is taken
1859   // down. After it is set, no OnStart/OnData/OnStop callbacks should be
1860   // received from the parent channel, nor dequeued from the ChannelEventQueue.
1861   mFlushedForDiversion = true;
1862 
1863   // If we're synthesized, it's up to the SyntheticDiversionListener to invoke
1864   // SendDivertComplete after it has sent the DivertOnStopRequestMessage.
1865   if (!mSynthesizedResponse) {
1866     SendDivertComplete();
1867   }
1868 }
1869 
ProcessSetClassifierMatchedInfo(const nsCString & aList,const nsCString & aProvider,const nsCString & aFullHash)1870 void HttpChannelChild::ProcessSetClassifierMatchedInfo(
1871     const nsCString& aList, const nsCString& aProvider,
1872     const nsCString& aFullHash) {
1873   LOG(("HttpChannelChild::ProcessSetClassifierMatchedInfo [this=%p]\n", this));
1874   MOZ_ASSERT(OnSocketThread());
1875 
1876   nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget();
1877   neckoTarget->Dispatch(
1878       NewRunnableMethod<const nsCString, const nsCString, const nsCString>(
1879           "HttpChannelChild::SetMatchedInfo", this,
1880           &HttpChannelChild::SetMatchedInfo, aList, aProvider, aFullHash),
1881       NS_DISPATCH_NORMAL);
1882 }
1883 
ProcessDivertMessages()1884 void HttpChannelChild::ProcessDivertMessages() {
1885   LOG(("HttpChannelChild::ProcessDivertMessages [this=%p]\n", this));
1886   MOZ_ASSERT(OnSocketThread());
1887   MOZ_RELEASE_ASSERT(mDivertingToParent);
1888 
1889   // DivertTo() has been called on parent, so we can now start sending queued
1890   // IPDL messages back to parent listener.
1891   nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget();
1892   MOZ_ASSERT(neckoTarget);
1893   nsresult rv =
1894       neckoTarget->Dispatch(NewRunnableMethod("HttpChannelChild::Resume", this,
1895                                               &HttpChannelChild::Resume),
1896                             NS_DISPATCH_NORMAL);
1897 
1898   MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
1899 }
1900 
1901 // Returns true if has actually completed the redirect and cleaned up the
1902 // channel, or false the interception logic kicked in and we need to asyncly
1903 // call FinishInterceptedRedirect and CleanupRedirectingChannel.
1904 // The argument is an optional OverrideRunnable that we pass to the redirected
1905 // channel.
Redirect3Complete(OverrideRunnable * aRunnable)1906 bool HttpChannelChild::Redirect3Complete(OverrideRunnable* aRunnable) {
1907   LOG(("HttpChannelChild::Redirect3Complete [this=%p]\n", this));
1908   nsresult rv = NS_OK;
1909 
1910   nsCOMPtr<nsIHttpChannelChild> chan = do_QueryInterface(mRedirectChannelChild);
1911   RefPtr<HttpChannelChild> httpChannelChild =
1912       static_cast<HttpChannelChild*>(chan.get());
1913   // Chrome channel has been AsyncOpen'd.  Reflect this in child.
1914   if (mRedirectChannelChild) {
1915     if (httpChannelChild) {
1916       httpChannelChild->mOverrideRunnable = aRunnable;
1917       httpChannelChild->mInterceptingChannel = this;
1918     }
1919     rv = mRedirectChannelChild->CompleteRedirectSetup(mListener,
1920                                                       mListenerContext);
1921   }
1922 
1923   if (!httpChannelChild || !httpChannelChild->mShouldParentIntercept) {
1924     // The redirect channel either isn't a HttpChannelChild, or the interception
1925     // logic wasn't triggered, so we can clean it up right here.
1926     CleanupRedirectingChannel(rv);
1927     if (httpChannelChild) {
1928       httpChannelChild->mOverrideRunnable = nullptr;
1929       httpChannelChild->mInterceptingChannel = nullptr;
1930     }
1931     return true;
1932   }
1933   return false;
1934 }
1935 
CleanupRedirectingChannel(nsresult rv)1936 void HttpChannelChild::CleanupRedirectingChannel(nsresult rv) {
1937   // Redirecting to new channel: shut this down and init new channel
1938   if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, NS_BINDING_ABORTED);
1939 
1940   if (NS_SUCCEEDED(rv)) {
1941     if (mLoadInfo) {
1942       nsCString remoteAddress;
1943       Unused << GetRemoteAddress(remoteAddress);
1944       nsCOMPtr<nsIRedirectHistoryEntry> entry = new nsRedirectHistoryEntry(
1945           GetURIPrincipal(), mReferrer, remoteAddress);
1946 
1947       mLoadInfo->AppendRedirectHistoryEntry(entry, false);
1948     }
1949   } else {
1950     NS_WARNING("CompleteRedirectSetup failed, HttpChannelChild already open?");
1951   }
1952 
1953   // Release ref to new channel.
1954   mRedirectChannelChild = nullptr;
1955 
1956   if (mInterceptListener) {
1957     mInterceptListener->Cleanup();
1958     mInterceptListener = nullptr;
1959   }
1960   ReleaseListeners();
1961 }
1962 
1963 //-----------------------------------------------------------------------------
1964 // HttpChannelChild::nsIChildChannel
1965 //-----------------------------------------------------------------------------
1966 
1967 NS_IMETHODIMP
ConnectParent(uint32_t registrarId)1968 HttpChannelChild::ConnectParent(uint32_t registrarId) {
1969   LOG(("HttpChannelChild::ConnectParent [this=%p, id=%" PRIu32 "]\n", this,
1970        registrarId));
1971   mozilla::dom::TabChild* tabChild = nullptr;
1972   nsCOMPtr<nsITabChild> iTabChild;
1973   GetCallback(iTabChild);
1974   if (iTabChild) {
1975     tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
1976   }
1977   if (MissingRequiredTabChild(tabChild, "http")) {
1978     return NS_ERROR_ILLEGAL_VALUE;
1979   }
1980 
1981   if (tabChild && !tabChild->IPCOpen()) {
1982     return NS_ERROR_FAILURE;
1983   }
1984 
1985   ContentChild* cc = static_cast<ContentChild*>(gNeckoChild->Manager());
1986   if (cc->IsShuttingDown()) {
1987     return NS_ERROR_FAILURE;
1988   }
1989 
1990   HttpBaseChannel::SetDocshellUserAgentOverride();
1991 
1992   // The socket transport in the chrome process now holds a logical ref to us
1993   // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
1994   AddIPDLReference();
1995 
1996   // This must happen before the constructor message is sent. Otherwise messages
1997   // from the parent could arrive quickly and be delivered to the wrong event
1998   // target.
1999   SetEventTarget();
2000 
2001   HttpChannelConnectArgs connectArgs(registrarId, mShouldParentIntercept);
2002   PBrowserOrId browser = static_cast<ContentChild*>(gNeckoChild->Manager())
2003                              ->GetBrowserOrId(tabChild);
2004   IPC::SerializedLoadContext slc(this);
2005   MOZ_DIAGNOSTIC_ASSERT(gIPCSecurityDisabled || slc.IsNotNull(),
2006                         "SerializedLoadContext should not be null");
2007   if (!gNeckoChild->SendPHttpChannelConstructor(this, browser, slc,
2008                                                 connectArgs)) {
2009     return NS_ERROR_FAILURE;
2010   }
2011 
2012   {
2013     MutexAutoLock lock(mBgChildMutex);
2014 
2015     MOZ_ASSERT(!mBgChild);
2016     MOZ_ASSERT(!mBgInitFailCallback);
2017 
2018     mBgInitFailCallback = NewRunnableMethod<nsresult>(
2019         "HttpChannelChild::OnRedirectVerifyCallback", this,
2020         &HttpChannelChild::OnRedirectVerifyCallback, NS_ERROR_FAILURE);
2021 
2022     RefPtr<HttpBackgroundChannelChild> bgChild =
2023         new HttpBackgroundChannelChild();
2024 
2025     MOZ_RELEASE_ASSERT(gSocketTransportService);
2026 
2027     RefPtr<HttpChannelChild> self = this;
2028     nsresult rv = gSocketTransportService->Dispatch(
2029         NewRunnableMethod<RefPtr<HttpChannelChild>>(
2030             "HttpBackgroundChannelChild::Init", bgChild,
2031             &HttpBackgroundChannelChild::Init, Move(self)),
2032         NS_DISPATCH_NORMAL);
2033 
2034     if (NS_WARN_IF(NS_FAILED(rv))) {
2035       return rv;
2036     }
2037 
2038     mBgChild = bgChild.forget();
2039   }
2040 
2041   return NS_OK;
2042 }
2043 
2044 NS_IMETHODIMP
CompleteRedirectSetup(nsIStreamListener * listener,nsISupports * aContext)2045 HttpChannelChild::CompleteRedirectSetup(nsIStreamListener* listener,
2046                                         nsISupports* aContext) {
2047   LOG(("HttpChannelChild::FinishRedirectSetup [this=%p]\n", this));
2048 
2049   NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
2050   NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
2051 
2052   if (mShouldParentIntercept) {
2053     // This is a redirected channel, and the corresponding parent channel has
2054     // started AsyncOpen but was intercepted and suspended. We must tear it down
2055     // and start fresh - we will intercept the child channel this time, before
2056     // creating a new parent channel unnecessarily.
2057 
2058     // Since this method is called from RecvRedirect3Complete which itself is
2059     // called from either OnRedirectVerifyCallback via OverrideRunnable, or from
2060     // RecvRedirect3Complete. The order of events must always be:
2061     //  1. Teardown the IPDL connection
2062     //  2. AsyncOpen the connection again
2063     //  3. Cleanup the redirecting channel (the one calling Redirect3Complete)
2064     //  4. [optional] Call OverrideWithSynthesizedResponse on the redirected
2065     //  channel if the call came from OverrideRunnable.
2066     mInterceptedRedirectListener = listener;
2067     mInterceptedRedirectContext = aContext;
2068 
2069     // This will send a message to the parent notifying it that we are closing
2070     // down. After closing the IPC channel, we will proceed to execute
2071     // FinishInterceptedRedirect() which AsyncOpen's the channel again.
2072     SendFinishInterceptedRedirect();
2073 
2074     // XXX valentin: The interception logic should be rewritten to avoid
2075     // calling AsyncOpen on the channel _after_ we call Send__delete__()
2076     return NS_OK;
2077   }
2078 
2079   /*
2080    * No need to check for cancel: we don't get here if nsHttpChannel canceled
2081    * before AsyncOpen(); if it's canceled after that, OnStart/Stop will just
2082    * get called with error code as usual.  So just setup mListener and make the
2083    * channel reflect AsyncOpen'ed state.
2084    */
2085 
2086   mIsPending = true;
2087   mWasOpened = true;
2088   mListener = listener;
2089   mListenerContext = aContext;
2090 
2091   // add ourselves to the load group.
2092   if (mLoadGroup) mLoadGroup->AddRequest(this, nullptr);
2093 
2094   // We already have an open IPDL connection to the parent. If on-modify-request
2095   // listeners or load group observers canceled us, let the parent handle it
2096   // and send it back to us naturally.
2097   return NS_OK;
2098 }
2099 
2100 //-----------------------------------------------------------------------------
2101 // HttpChannelChild::nsIAsyncVerifyRedirectCallback
2102 //-----------------------------------------------------------------------------
2103 
2104 NS_IMETHODIMP
OnRedirectVerifyCallback(nsresult result)2105 HttpChannelChild::OnRedirectVerifyCallback(nsresult result) {
2106   LOG(("HttpChannelChild::OnRedirectVerifyCallback [this=%p]\n", this));
2107   OptionalURIParams redirectURI;
2108   nsresult rv;
2109 
2110   uint32_t referrerPolicy = REFERRER_POLICY_UNSET;
2111   OptionalURIParams referrerURI;
2112   SerializeURI(nullptr, referrerURI);
2113 
2114   nsCOMPtr<nsIHttpChannel> newHttpChannel =
2115       do_QueryInterface(mRedirectChannelChild);
2116 
2117   if (NS_SUCCEEDED(result) && !mRedirectChannelChild) {
2118     // mRedirectChannelChild doesn't exist means we're redirecting to a protocol
2119     // that doesn't implement nsIChildChannel. The redirect result should be set
2120     // as failed by veto listeners and shouldn't enter this condition. As the
2121     // last resort, we synthesize the error result as NS_ERROR_DOM_BAD_URI here
2122     // to let nsHttpChannel::ContinueProcessResponse2 know it's redirecting to
2123     // another protocol and throw an error.
2124     LOG(("  redirecting to a protocol that doesn't implement nsIChildChannel"));
2125     result = NS_ERROR_DOM_BAD_URI;
2126   }
2127 
2128   if (newHttpChannel) {
2129     // Must not be called until after redirect observers called.
2130     newHttpChannel->SetOriginalURI(mOriginalURI);
2131 
2132     rv = newHttpChannel->GetReferrerPolicy(&referrerPolicy);
2133     MOZ_ASSERT(NS_SUCCEEDED(rv));
2134     nsCOMPtr<nsIURI> newChannelReferrerURI;
2135     rv = newHttpChannel->GetReferrer(getter_AddRefs(newChannelReferrerURI));
2136     MOZ_ASSERT(NS_SUCCEEDED(rv));
2137 
2138     SerializeURI(newChannelReferrerURI, referrerURI);
2139   }
2140 
2141   if (mRedirectingForSubsequentSynthesizedResponse) {
2142     nsCOMPtr<nsIHttpChannelChild> httpChannelChild =
2143         do_QueryInterface(mRedirectChannelChild);
2144     RefPtr<HttpChannelChild> redirectedChannel =
2145         static_cast<HttpChannelChild*>(httpChannelChild.get());
2146     // redirectChannel will be NULL if mRedirectChannelChild isn't a
2147     // nsIHttpChannelChild (it could be a DataChannelChild).
2148 
2149     RefPtr<InterceptStreamListener> streamListener =
2150         new InterceptStreamListener(redirectedChannel, mListenerContext);
2151 
2152     nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget();
2153     MOZ_ASSERT(neckoTarget);
2154 
2155     nsCOMPtr<nsIInterceptedBodyCallback> callback =
2156         mSynthesizedCallback.forget();
2157 
2158     Unused << neckoTarget->Dispatch(
2159         new OverrideRunnable(this, redirectedChannel, streamListener,
2160                              mSynthesizedInput, callback, mResponseHead,
2161                              mSynthesizedCacheInfo),
2162         NS_DISPATCH_NORMAL);
2163 
2164     return NS_OK;
2165   }
2166 
2167   RequestHeaderTuples emptyHeaders;
2168   RequestHeaderTuples* headerTuples = &emptyHeaders;
2169   nsLoadFlags loadFlags = 0;
2170   OptionalCorsPreflightArgs corsPreflightArgs = mozilla::void_t();
2171 
2172   nsCOMPtr<nsIHttpChannelChild> newHttpChannelChild =
2173       do_QueryInterface(mRedirectChannelChild);
2174   if (newHttpChannelChild && NS_SUCCEEDED(result)) {
2175     rv = newHttpChannelChild->AddCookiesToRequest();
2176     MOZ_ASSERT(NS_SUCCEEDED(rv));
2177     rv = newHttpChannelChild->GetClientSetRequestHeaders(&headerTuples);
2178     MOZ_ASSERT(NS_SUCCEEDED(rv));
2179     newHttpChannelChild->GetClientSetCorsPreflightParameters(corsPreflightArgs);
2180   }
2181 
2182   /* If the redirect was canceled, bypass OMR and send an empty API
2183    * redirect URI */
2184   SerializeURI(nullptr, redirectURI);
2185 
2186   if (NS_SUCCEEDED(result)) {
2187     // Note: this is where we would notify "http-on-modify-response" observers.
2188     // We have deliberately disabled this for child processes (see bug 806753)
2189     //
2190     // After we verify redirect, nsHttpChannel may hit the network: must give
2191     // "http-on-modify-request" observers the chance to cancel before that.
2192     // base->CallOnModifyRequestObservers();
2193 
2194     nsCOMPtr<nsIHttpChannelInternal> newHttpChannelInternal =
2195         do_QueryInterface(mRedirectChannelChild);
2196     if (newHttpChannelInternal) {
2197       nsCOMPtr<nsIURI> apiRedirectURI;
2198       rv = newHttpChannelInternal->GetApiRedirectToURI(
2199           getter_AddRefs(apiRedirectURI));
2200       if (NS_SUCCEEDED(rv) && apiRedirectURI) {
2201         /* If there was an API redirect of this channel, we need to send it
2202          * up here, since it can't be sent via SendAsyncOpen. */
2203         SerializeURI(apiRedirectURI, redirectURI);
2204       }
2205     }
2206 
2207     nsCOMPtr<nsIRequest> request = do_QueryInterface(mRedirectChannelChild);
2208     if (request) {
2209       request->GetLoadFlags(&loadFlags);
2210     }
2211   }
2212 
2213   MaybeCallSynthesizedCallback();
2214 
2215   bool chooseAppcache = false;
2216   nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
2217       do_QueryInterface(newHttpChannel);
2218   if (appCacheChannel) {
2219     appCacheChannel->GetChooseApplicationCache(&chooseAppcache);
2220   }
2221 
2222   if (mIPCOpen)
2223     SendRedirect2Verify(result, *headerTuples, loadFlags, referrerPolicy,
2224                         referrerURI, redirectURI, corsPreflightArgs,
2225                         chooseAppcache);
2226 
2227   return NS_OK;
2228 }
2229 
2230 //-----------------------------------------------------------------------------
2231 // HttpChannelChild::nsIRequest
2232 //-----------------------------------------------------------------------------
2233 
2234 NS_IMETHODIMP
Cancel(nsresult status)2235 HttpChannelChild::Cancel(nsresult status) {
2236   LOG(("HttpChannelChild::Cancel [this=%p, status=%" PRIx32 "]\n", this,
2237        static_cast<uint32_t>(status)));
2238   MOZ_ASSERT(NS_IsMainThread());
2239 
2240   if (!mCanceled) {
2241     // If this cancel occurs before nsHttpChannel has been set up, AsyncOpen
2242     // is responsible for cleaning up.
2243     mCanceled = true;
2244     mStatus = status;
2245     if (RemoteChannelExists()) {
2246       SendCancel(status);
2247     }
2248 
2249     // If the channel is intercepted and already pumping, then just
2250     // cancel the pump.  This will call OnStopRequest().
2251     if (mSynthesizedResponsePump) {
2252       mSynthesizedResponsePump->Cancel(status);
2253     }
2254 
2255     // If we are canceled while intercepting, but not yet pumping, then
2256     // we must call AsyncAbort() to trigger OnStopRequest().
2257     else if (mInterceptListener) {
2258       mInterceptListener->Cleanup();
2259       mInterceptListener = nullptr;
2260       Unused << AsyncAbort(status);
2261     }
2262   }
2263   return NS_OK;
2264 }
2265 
2266 NS_IMETHODIMP
Suspend()2267 HttpChannelChild::Suspend() {
2268   LOG(("HttpChannelChild::Suspend [this=%p, mSuspendCount=%" PRIu32 ", "
2269        "mDivertingToParent=%d]\n",
2270        this, mSuspendCount + 1, static_cast<bool>(mDivertingToParent)));
2271   NS_ENSURE_TRUE(RemoteChannelExists() || mInterceptListener,
2272                  NS_ERROR_NOT_AVAILABLE);
2273 
2274   // SendSuspend only once, when suspend goes from 0 to 1.
2275   // Don't SendSuspend at all if we're diverting callbacks to the parent;
2276   // suspend will be called at the correct time in the parent itself.
2277   if (!mSuspendCount++ && !mDivertingToParent) {
2278     if (RemoteChannelExists()) {
2279       SendSuspend();
2280       mSuspendSent = true;
2281     }
2282   }
2283   if (mSynthesizedResponsePump) {
2284     mSynthesizedResponsePump->Suspend();
2285   }
2286   mEventQ->Suspend();
2287 
2288   return NS_OK;
2289 }
2290 
2291 NS_IMETHODIMP
Resume()2292 HttpChannelChild::Resume() {
2293   LOG(("HttpChannelChild::Resume [this=%p, mSuspendCount=%" PRIu32 ", "
2294        "mDivertingToParent=%d]\n",
2295        this, mSuspendCount - 1, static_cast<bool>(mDivertingToParent)));
2296   NS_ENSURE_TRUE(RemoteChannelExists() || mInterceptListener,
2297                  NS_ERROR_NOT_AVAILABLE);
2298   NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED);
2299 
2300   nsresult rv = NS_OK;
2301 
2302   // SendResume only once, when suspend count drops to 0.
2303   // Don't SendResume at all if we're diverting callbacks to the parent (unless
2304   // suspend was sent earlier); otherwise, resume will be called at the correct
2305   // time in the parent itself.
2306   if (!--mSuspendCount && (!mDivertingToParent || mSuspendSent)) {
2307     if (RemoteChannelExists()) {
2308       SendResume();
2309     }
2310     if (mCallOnResume) {
2311       rv = AsyncCall(mCallOnResume);
2312       NS_ENSURE_SUCCESS(rv, rv);
2313       mCallOnResume = nullptr;
2314     }
2315   }
2316   if (mSynthesizedResponsePump) {
2317     mSynthesizedResponsePump->Resume();
2318   }
2319   mEventQ->Resume();
2320 
2321   return rv;
2322 }
2323 
2324 //-----------------------------------------------------------------------------
2325 // HttpChannelChild::nsIChannel
2326 //-----------------------------------------------------------------------------
2327 
2328 NS_IMETHODIMP
GetSecurityInfo(nsISupports ** aSecurityInfo)2329 HttpChannelChild::GetSecurityInfo(nsISupports** aSecurityInfo) {
2330   NS_ENSURE_ARG_POINTER(aSecurityInfo);
2331   NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
2332   return NS_OK;
2333 }
2334 
2335 NS_IMETHODIMP
AsyncOpen(nsIStreamListener * listener,nsISupports * aContext)2336 HttpChannelChild::AsyncOpen(nsIStreamListener* listener,
2337                             nsISupports* aContext) {
2338   MOZ_ASSERT(
2339       !mLoadInfo || mLoadInfo->GetSecurityMode() == 0 ||
2340           mLoadInfo->GetInitialSecurityCheckDone() ||
2341           (mLoadInfo->GetSecurityMode() ==
2342                nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
2343            nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())),
2344       "security flags in loadInfo but asyncOpen2() not called");
2345 
2346   LOG(("HttpChannelChild::AsyncOpen [this=%p uri=%s]\n", this, mSpec.get()));
2347 
2348   if (LOG4_ENABLED()) {
2349     JSContext* cx = nsContentUtils::GetCurrentJSContext();
2350     if (cx) {
2351       nsAutoCString fileNameString;
2352       uint32_t line = 0, col = 0;
2353       if (nsJSUtils::GetCallingLocation(cx, fileNameString, &line, &col)) {
2354         LOG(("HttpChannelChild %p source script=%s:%u:%u", this,
2355              fileNameString.get(), line, col));
2356       }
2357     }
2358   }
2359 
2360 #ifdef DEBUG
2361   AssertPrivateBrowsingId();
2362 #endif
2363 
2364   if (mCanceled) return mStatus;
2365 
2366   NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE);
2367   NS_ENSURE_ARG_POINTER(listener);
2368   NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
2369   NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
2370 
2371   mAsyncOpenTime = TimeStamp::Now();
2372 #ifdef MOZ_TASK_TRACER
2373   if (tasktracer::IsStartLogging()) {
2374     nsCOMPtr<nsIURI> uri;
2375     GetURI(getter_AddRefs(uri));
2376     nsAutoCString urispec;
2377     uri->GetSpec(urispec);
2378     tasktracer::AddLabel("HttpChannelChild::AsyncOpen %s", urispec.get());
2379   }
2380 #endif
2381 
2382   // Port checked in parent, but duplicate here so we can return with error
2383   // immediately
2384   nsresult rv;
2385   rv = NS_CheckPortSafety(mURI);
2386   if (NS_FAILED(rv)) return rv;
2387 
2388   nsAutoCString cookie;
2389   if (NS_SUCCEEDED(mRequestHead.GetHeader(nsHttp::Cookie, cookie))) {
2390     mUserSetCookieHeader = cookie;
2391   }
2392 
2393   rv = AddCookiesToRequest();
2394   MOZ_ASSERT(NS_SUCCEEDED(rv));
2395 
2396   //
2397   // NOTE: From now on we must return NS_OK; all errors must be handled via
2398   // OnStart/OnStopRequest
2399   //
2400 
2401   // We notify "http-on-opening-request" observers in the child
2402   // process so that devtools can capture a stack trace at the
2403   // appropriate spot.  See bug 806753 for some information about why
2404   // other http-* notifications are disabled in child processes.
2405   gHttpHandler->OnOpeningRequest(this);
2406 
2407   mIsPending = true;
2408   mWasOpened = true;
2409   mListener = listener;
2410   mListenerContext = aContext;
2411 
2412   // add ourselves to the load group.
2413   if (mLoadGroup) mLoadGroup->AddRequest(this, nullptr);
2414 
2415   if (mCanceled) {
2416     // We may have been canceled already, either by on-modify-request
2417     // listeners or by load group observers; in that case, don't create IPDL
2418     // connection. See nsHttpChannel::AsyncOpen().
2419     return NS_OK;
2420   }
2421 
2422   // Set user agent override from docshell
2423   HttpBaseChannel::SetDocshellUserAgentOverride();
2424 
2425   MOZ_ASSERT_IF(mPostRedirectChannelShouldUpgrade,
2426                 mPostRedirectChannelShouldIntercept);
2427   bool shouldUpgrade = mPostRedirectChannelShouldUpgrade;
2428   if (mPostRedirectChannelShouldIntercept ||
2429       ShouldInterceptURI(mURI, shouldUpgrade)) {
2430     mResponseCouldBeSynthesized = true;
2431 
2432     nsCOMPtr<nsINetworkInterceptController> controller;
2433     GetCallback(controller);
2434 
2435     mInterceptListener = new InterceptStreamListener(this, mListenerContext);
2436 
2437     RefPtr<InterceptedChannelContent> intercepted =
2438         new InterceptedChannelContent(this, controller, mInterceptListener,
2439                                       shouldUpgrade);
2440     intercepted->NotifyController();
2441     return NS_OK;
2442   }
2443 
2444   return ContinueAsyncOpen();
2445 }
2446 
2447 NS_IMETHODIMP
AsyncOpen2(nsIStreamListener * aListener)2448 HttpChannelChild::AsyncOpen2(nsIStreamListener* aListener) {
2449   nsCOMPtr<nsIStreamListener> listener = aListener;
2450   nsresult rv =
2451       nsContentSecurityManager::doContentSecurityCheck(this, listener);
2452   if (NS_WARN_IF(NS_FAILED(rv))) {
2453     ReleaseListeners();
2454     return rv;
2455   }
2456   return AsyncOpen(listener, nullptr);
2457 }
2458 
2459 // Assigns an nsIEventTarget to our IPDL actor so that IPC messages are sent to
2460 // the correct DocGroup/TabGroup.
SetEventTarget()2461 void HttpChannelChild::SetEventTarget() {
2462   nsCOMPtr<nsILoadInfo> loadInfo;
2463   GetLoadInfo(getter_AddRefs(loadInfo));
2464 
2465   nsCOMPtr<nsIEventTarget> target =
2466       nsContentUtils::GetEventTargetByLoadInfo(loadInfo, TaskCategory::Network);
2467 
2468   if (!target) {
2469     return;
2470   }
2471 
2472   gNeckoChild->SetEventTargetForActor(this, target);
2473 
2474   {
2475     MutexAutoLock lock(mEventTargetMutex);
2476     mNeckoTarget = target;
2477   }
2478 }
2479 
GetNeckoTarget()2480 already_AddRefed<nsIEventTarget> HttpChannelChild::GetNeckoTarget() {
2481   nsCOMPtr<nsIEventTarget> target;
2482   {
2483     MutexAutoLock lock(mEventTargetMutex);
2484     target = mNeckoTarget;
2485   }
2486 
2487   if (!target) {
2488     target = GetMainThreadEventTarget();
2489   }
2490   return target.forget();
2491 }
2492 
GetODATarget()2493 already_AddRefed<nsIEventTarget> HttpChannelChild::GetODATarget() {
2494   nsCOMPtr<nsIEventTarget> target;
2495   {
2496     MutexAutoLock lock(mEventTargetMutex);
2497     target = mODATarget ? mODATarget : mNeckoTarget;
2498   }
2499 
2500   if (!target) {
2501     target = GetMainThreadEventTarget();
2502   }
2503   return target.forget();
2504 }
2505 
ContinueAsyncOpen()2506 nsresult HttpChannelChild::ContinueAsyncOpen() {
2507   nsCString appCacheClientId;
2508   if (mInheritApplicationCache) {
2509     // Pick up an application cache from the notification
2510     // callbacks if available
2511     nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer;
2512     GetCallback(appCacheContainer);
2513 
2514     if (appCacheContainer) {
2515       nsCOMPtr<nsIApplicationCache> appCache;
2516       nsresult rv =
2517           appCacheContainer->GetApplicationCache(getter_AddRefs(appCache));
2518       if (NS_SUCCEEDED(rv) && appCache) {
2519         appCache->GetClientID(appCacheClientId);
2520       }
2521     }
2522   }
2523 
2524   //
2525   // Send request to the chrome process...
2526   //
2527 
2528   mozilla::dom::TabChild* tabChild = nullptr;
2529   nsCOMPtr<nsITabChild> iTabChild;
2530   GetCallback(iTabChild);
2531   if (iTabChild) {
2532     tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
2533   }
2534   if (MissingRequiredTabChild(tabChild, "http")) {
2535     return NS_ERROR_ILLEGAL_VALUE;
2536   }
2537 
2538   // This id identifies the inner window's top-level document,
2539   // which changes on every new load or navigation.
2540   uint64_t contentWindowId = 0;
2541   if (tabChild) {
2542     MOZ_ASSERT(tabChild->WebNavigation());
2543     nsCOMPtr<nsIDocument> document = tabChild->GetDocument();
2544     if (document) {
2545       contentWindowId = document->InnerWindowID();
2546       mTopLevelOuterContentWindowId = document->OuterWindowID();
2547     }
2548   }
2549   SetTopLevelContentWindowId(contentWindowId);
2550 
2551   HttpChannelOpenArgs openArgs;
2552   // No access to HttpChannelOpenArgs members, but they each have a
2553   // function with the struct name that returns a ref.
2554   SerializeURI(mURI, openArgs.uri());
2555   SerializeURI(mOriginalURI, openArgs.original());
2556   SerializeURI(mDocumentURI, openArgs.doc());
2557   SerializeURI(mReferrer, openArgs.referrer());
2558   openArgs.referrerPolicy() = mReferrerPolicy;
2559   SerializeURI(mAPIRedirectToURI, openArgs.apiRedirectTo());
2560   openArgs.loadFlags() = mLoadFlags;
2561   openArgs.requestHeaders() = mClientSetRequestHeaders;
2562   mRequestHead.Method(openArgs.requestMethod());
2563   openArgs.preferredAlternativeType() = mPreferredCachedAltDataType;
2564 
2565   AutoIPCStream autoStream(openArgs.uploadStream());
2566   if (mUploadStream) {
2567     autoStream.Serialize(mUploadStream, ContentChild::GetSingleton());
2568     autoStream.TakeOptionalValue();
2569   }
2570 
2571   if (mResponseHead) {
2572     openArgs.synthesizedResponseHead() = *mResponseHead;
2573     openArgs.suspendAfterSynthesizeResponse() =
2574         mSuspendParentAfterSynthesizeResponse;
2575   } else {
2576     openArgs.synthesizedResponseHead() = mozilla::void_t();
2577     openArgs.suspendAfterSynthesizeResponse() = false;
2578   }
2579 
2580   nsCOMPtr<nsISerializable> secInfoSer = do_QueryInterface(mSecurityInfo);
2581   if (secInfoSer) {
2582     NS_SerializeToString(secInfoSer,
2583                          openArgs.synthesizedSecurityInfoSerialization());
2584   }
2585 
2586   OptionalCorsPreflightArgs optionalCorsPreflightArgs;
2587   GetClientSetCorsPreflightParameters(optionalCorsPreflightArgs);
2588 
2589   // NB: This call forces us to cache mTopWindowURI if we haven't already.
2590   nsCOMPtr<nsIURI> uri;
2591   GetTopWindowURI(getter_AddRefs(uri));
2592 
2593   SerializeURI(mTopWindowURI, openArgs.topWindowURI());
2594 
2595   openArgs.preflightArgs() = optionalCorsPreflightArgs;
2596 
2597   openArgs.uploadStreamHasHeaders() = mUploadStreamHasHeaders;
2598   openArgs.priority() = mPriority;
2599   openArgs.classOfService() = mClassOfService;
2600   openArgs.redirectionLimit() = mRedirectionLimit;
2601   openArgs.allowSTS() = mAllowSTS;
2602   openArgs.thirdPartyFlags() = mThirdPartyFlags;
2603   openArgs.resumeAt() = mSendResumeAt;
2604   openArgs.startPos() = mStartPos;
2605   openArgs.entityID() = mEntityID;
2606   openArgs.chooseApplicationCache() = mChooseApplicationCache;
2607   openArgs.appCacheClientID() = appCacheClientId;
2608   openArgs.allowSpdy() = mAllowSpdy;
2609   openArgs.allowAltSvc() = mAllowAltSvc;
2610   openArgs.beConservative() = mBeConservative;
2611   openArgs.tlsFlags() = mTlsFlags;
2612   openArgs.initialRwin() = mInitialRwin;
2613 
2614   uint32_t cacheKey = 0;
2615   if (mCacheKey) {
2616     nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(mCacheKey);
2617     if (!container) {
2618       return NS_ERROR_ILLEGAL_VALUE;
2619     }
2620 
2621     nsresult rv = container->GetData(&cacheKey);
2622     if (NS_FAILED(rv)) {
2623       return rv;
2624     }
2625   }
2626   openArgs.cacheKey() = cacheKey;
2627 
2628   openArgs.blockAuthPrompt() = mBlockAuthPrompt;
2629 
2630   openArgs.allowStaleCacheContent() = mAllowStaleCacheContent;
2631 
2632   openArgs.contentTypeHint() = mContentTypeHint;
2633 
2634   nsresult rv =
2635       mozilla::ipc::LoadInfoToLoadInfoArgs(mLoadInfo, &openArgs.loadInfo());
2636   NS_ENSURE_SUCCESS(rv, rv);
2637 
2638   EnsureRequestContextID();
2639   openArgs.requestContextID() = mRequestContextID;
2640 
2641   openArgs.corsMode() = mCorsMode;
2642   openArgs.redirectMode() = mRedirectMode;
2643 
2644   openArgs.channelId() = mChannelId;
2645 
2646   openArgs.contentWindowId() = contentWindowId;
2647   openArgs.topLevelOuterContentWindowId() = mTopLevelOuterContentWindowId;
2648 
2649   LOG(("HttpChannelChild::ContinueAsyncOpen this=%p gid=%" PRIu64
2650        " topwinid=%" PRIx64,
2651        this, mChannelId, mTopLevelOuterContentWindowId));
2652 
2653   if (tabChild && !tabChild->IPCOpen()) {
2654     return NS_ERROR_FAILURE;
2655   }
2656 
2657   ContentChild* cc = static_cast<ContentChild*>(gNeckoChild->Manager());
2658   if (cc->IsShuttingDown()) {
2659     return NS_ERROR_FAILURE;
2660   }
2661 
2662   openArgs.launchServiceWorkerStart() = mLaunchServiceWorkerStart;
2663   openArgs.launchServiceWorkerEnd() = mLaunchServiceWorkerEnd;
2664   openArgs.dispatchFetchEventStart() = mDispatchFetchEventStart;
2665   openArgs.dispatchFetchEventEnd() = mDispatchFetchEventEnd;
2666   openArgs.handleFetchEventStart() = mHandleFetchEventStart;
2667   openArgs.handleFetchEventEnd() = mHandleFetchEventEnd;
2668 
2669   openArgs.forceMainDocumentChannel() = mForceMainDocumentChannel;
2670 
2671   // This must happen before the constructor message is sent. Otherwise messages
2672   // from the parent could arrive quickly and be delivered to the wrong event
2673   // target.
2674   SetEventTarget();
2675 
2676   // The socket transport in the chrome process now holds a logical ref to us
2677   // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
2678   AddIPDLReference();
2679 
2680   PBrowserOrId browser = cc->GetBrowserOrId(tabChild);
2681   IPC::SerializedLoadContext slc(this);
2682   MOZ_DIAGNOSTIC_ASSERT(gIPCSecurityDisabled || slc.IsNotNull(),
2683                         "SerializedLoadContext should not be null");
2684   if (!gNeckoChild->SendPHttpChannelConstructor(this, browser, slc, openArgs)) {
2685     return NS_ERROR_FAILURE;
2686   }
2687 
2688   {
2689     MutexAutoLock lock(mBgChildMutex);
2690 
2691     MOZ_RELEASE_ASSERT(gSocketTransportService);
2692 
2693     // Service worker might use the same HttpChannelChild to do async open
2694     // twice. Need to disconnect with previous background channel before
2695     // creating the new one, to prevent receiving further notification
2696     // from it.
2697     if (mBgChild) {
2698       RefPtr<HttpBackgroundChannelChild> prevBgChild = mBgChild.forget();
2699       gSocketTransportService->Dispatch(
2700           NewRunnableMethod("HttpBackgroundChannelChild::OnChannelClosed",
2701                             prevBgChild,
2702                             &HttpBackgroundChannelChild::OnChannelClosed),
2703           NS_DISPATCH_NORMAL);
2704     }
2705 
2706     MOZ_ASSERT(!mBgInitFailCallback);
2707 
2708     mBgInitFailCallback = NewRunnableMethod<nsresult>(
2709         "HttpChannelChild::FailedAsyncOpen", this,
2710         &HttpChannelChild::FailedAsyncOpen, NS_ERROR_FAILURE);
2711 
2712     RefPtr<HttpBackgroundChannelChild> bgChild =
2713         new HttpBackgroundChannelChild();
2714 
2715     RefPtr<HttpChannelChild> self = this;
2716     nsresult rv = gSocketTransportService->Dispatch(
2717         NewRunnableMethod<RefPtr<HttpChannelChild>>(
2718             "HttpBackgroundChannelChild::Init", bgChild,
2719             &HttpBackgroundChannelChild::Init, self),
2720         NS_DISPATCH_NORMAL);
2721 
2722     if (NS_WARN_IF(NS_FAILED(rv))) {
2723       return rv;
2724     }
2725 
2726     mBgChild = bgChild.forget();
2727   }
2728 
2729   return NS_OK;
2730 }
2731 
2732 //-----------------------------------------------------------------------------
2733 // HttpChannelChild::nsIHttpChannel
2734 //-----------------------------------------------------------------------------
2735 
2736 NS_IMETHODIMP
SetReferrerWithPolicy(nsIURI * referrer,uint32_t referrerPolicy)2737 HttpChannelChild::SetReferrerWithPolicy(nsIURI* referrer,
2738                                         uint32_t referrerPolicy) {
2739   ENSURE_CALLED_BEFORE_CONNECT();
2740 
2741   // remove old referrer if any, loop backwards
2742   for (int i = mClientSetRequestHeaders.Length() - 1; i >= 0; --i) {
2743     if (NS_LITERAL_CSTRING("Referer").Equals(
2744             mClientSetRequestHeaders[i].mHeader)) {
2745       mClientSetRequestHeaders.RemoveElementAt(i);
2746     }
2747   }
2748 
2749   nsresult rv =
2750       HttpBaseChannel::SetReferrerWithPolicy(referrer, referrerPolicy);
2751   if (NS_FAILED(rv)) return rv;
2752   return NS_OK;
2753 }
2754 NS_IMETHODIMP
SetRequestHeader(const nsACString & aHeader,const nsACString & aValue,bool aMerge)2755 HttpChannelChild::SetRequestHeader(const nsACString& aHeader,
2756                                    const nsACString& aValue, bool aMerge) {
2757   LOG(("HttpChannelChild::SetRequestHeader [this=%p]\n", this));
2758   nsresult rv = HttpBaseChannel::SetRequestHeader(aHeader, aValue, aMerge);
2759   if (NS_FAILED(rv)) return rv;
2760 
2761   RequestHeaderTuple* tuple = mClientSetRequestHeaders.AppendElement();
2762   if (!tuple) return NS_ERROR_OUT_OF_MEMORY;
2763 
2764   tuple->mHeader = aHeader;
2765   tuple->mValue = aValue;
2766   tuple->mMerge = aMerge;
2767   tuple->mEmpty = false;
2768   return NS_OK;
2769 }
2770 
2771 NS_IMETHODIMP
SetEmptyRequestHeader(const nsACString & aHeader)2772 HttpChannelChild::SetEmptyRequestHeader(const nsACString& aHeader) {
2773   LOG(("HttpChannelChild::SetEmptyRequestHeader [this=%p]\n", this));
2774   nsresult rv = HttpBaseChannel::SetEmptyRequestHeader(aHeader);
2775   if (NS_FAILED(rv)) return rv;
2776 
2777   RequestHeaderTuple* tuple = mClientSetRequestHeaders.AppendElement();
2778   if (!tuple) return NS_ERROR_OUT_OF_MEMORY;
2779 
2780   tuple->mHeader = aHeader;
2781   tuple->mMerge = false;
2782   tuple->mEmpty = true;
2783   return NS_OK;
2784 }
2785 
2786 NS_IMETHODIMP
RedirectTo(nsIURI * newURI)2787 HttpChannelChild::RedirectTo(nsIURI* newURI) {
2788   // disabled until/unless addons run in child or something else needs this
2789   return NS_ERROR_NOT_IMPLEMENTED;
2790 }
2791 
2792 NS_IMETHODIMP
UpgradeToSecure()2793 HttpChannelChild::UpgradeToSecure() {
2794   // disabled until/unless addons run in child or something else needs this
2795   return NS_ERROR_NOT_IMPLEMENTED;
2796 }
2797 
2798 NS_IMETHODIMP
GetProtocolVersion(nsACString & aProtocolVersion)2799 HttpChannelChild::GetProtocolVersion(nsACString& aProtocolVersion) {
2800   aProtocolVersion = mProtocolVersion;
2801   return NS_OK;
2802 }
2803 
2804 //-----------------------------------------------------------------------------
2805 // HttpChannelChild::nsIHttpChannelInternal
2806 //-----------------------------------------------------------------------------
2807 
2808 NS_IMETHODIMP
SetupFallbackChannel(const char * aFallbackKey)2809 HttpChannelChild::SetupFallbackChannel(const char* aFallbackKey) {
2810   DROP_DEAD();
2811 }
2812 
2813 //-----------------------------------------------------------------------------
2814 // HttpChannelChild::nsICacheInfoChannel
2815 //-----------------------------------------------------------------------------
2816 
2817 NS_IMETHODIMP
GetCacheTokenFetchCount(int32_t * _retval)2818 HttpChannelChild::GetCacheTokenFetchCount(int32_t* _retval) {
2819   NS_ENSURE_ARG_POINTER(_retval);
2820 
2821   if (mSynthesizedCacheInfo) {
2822     return mSynthesizedCacheInfo->GetCacheTokenFetchCount(_retval);
2823   }
2824 
2825   if (!mCacheEntryAvailable && !mAltDataCacheEntryAvailable) {
2826     return NS_ERROR_NOT_AVAILABLE;
2827   }
2828 
2829   *_retval = mCacheFetchCount;
2830   return NS_OK;
2831 }
2832 
2833 NS_IMETHODIMP
GetCacheTokenExpirationTime(uint32_t * _retval)2834 HttpChannelChild::GetCacheTokenExpirationTime(uint32_t* _retval) {
2835   NS_ENSURE_ARG_POINTER(_retval);
2836 
2837   if (mSynthesizedCacheInfo) {
2838     return mSynthesizedCacheInfo->GetCacheTokenExpirationTime(_retval);
2839   }
2840 
2841   if (!mCacheEntryAvailable) return NS_ERROR_NOT_AVAILABLE;
2842 
2843   *_retval = mCacheExpirationTime;
2844   return NS_OK;
2845 }
2846 
2847 NS_IMETHODIMP
GetCacheTokenCachedCharset(nsACString & _retval)2848 HttpChannelChild::GetCacheTokenCachedCharset(nsACString& _retval) {
2849   if (mSynthesizedCacheInfo) {
2850     return mSynthesizedCacheInfo->GetCacheTokenCachedCharset(_retval);
2851   }
2852 
2853   if (!mCacheEntryAvailable) return NS_ERROR_NOT_AVAILABLE;
2854 
2855   _retval = mCachedCharset;
2856   return NS_OK;
2857 }
2858 NS_IMETHODIMP
SetCacheTokenCachedCharset(const nsACString & aCharset)2859 HttpChannelChild::SetCacheTokenCachedCharset(const nsACString& aCharset) {
2860   if (mSynthesizedCacheInfo) {
2861     return mSynthesizedCacheInfo->SetCacheTokenCachedCharset(aCharset);
2862   }
2863 
2864   if (!mCacheEntryAvailable || !RemoteChannelExists())
2865     return NS_ERROR_NOT_AVAILABLE;
2866 
2867   mCachedCharset = aCharset;
2868   if (!SendSetCacheTokenCachedCharset(PromiseFlatCString(aCharset))) {
2869     return NS_ERROR_FAILURE;
2870   }
2871   return NS_OK;
2872 }
2873 
2874 NS_IMETHODIMP
IsFromCache(bool * value)2875 HttpChannelChild::IsFromCache(bool* value) {
2876   if (mSynthesizedCacheInfo) {
2877     return mSynthesizedCacheInfo->IsFromCache(value);
2878   }
2879 
2880   if (!mIsPending) return NS_ERROR_NOT_AVAILABLE;
2881 
2882   *value = mIsFromCache;
2883   return NS_OK;
2884 }
2885 
2886 NS_IMETHODIMP
GetCacheEntryId(uint64_t * aCacheEntryId)2887 HttpChannelChild::GetCacheEntryId(uint64_t* aCacheEntryId) {
2888   if (mSynthesizedCacheInfo) {
2889     return mSynthesizedCacheInfo->GetCacheEntryId(aCacheEntryId);
2890   }
2891 
2892   bool fromCache = false;
2893   if (NS_FAILED(IsFromCache(&fromCache)) || !fromCache ||
2894       !mCacheEntryAvailable) {
2895     return NS_ERROR_NOT_AVAILABLE;
2896   }
2897 
2898   *aCacheEntryId = mCacheEntryId;
2899   return NS_OK;
2900 }
2901 
2902 NS_IMETHODIMP
GetCacheKey(nsISupports ** cacheKey)2903 HttpChannelChild::GetCacheKey(nsISupports** cacheKey) {
2904   if (mSynthesizedCacheInfo) {
2905     return mSynthesizedCacheInfo->GetCacheKey(cacheKey);
2906   }
2907 
2908   NS_IF_ADDREF(*cacheKey = mCacheKey);
2909   return NS_OK;
2910 }
2911 NS_IMETHODIMP
SetCacheKey(nsISupports * cacheKey)2912 HttpChannelChild::SetCacheKey(nsISupports* cacheKey) {
2913   if (mSynthesizedCacheInfo) {
2914     return mSynthesizedCacheInfo->SetCacheKey(cacheKey);
2915   }
2916 
2917   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
2918 
2919   mCacheKey = cacheKey;
2920   return NS_OK;
2921 }
2922 
2923 NS_IMETHODIMP
SetAllowStaleCacheContent(bool aAllowStaleCacheContent)2924 HttpChannelChild::SetAllowStaleCacheContent(bool aAllowStaleCacheContent) {
2925   if (mSynthesizedCacheInfo) {
2926     return mSynthesizedCacheInfo->SetAllowStaleCacheContent(
2927         aAllowStaleCacheContent);
2928   }
2929 
2930   mAllowStaleCacheContent = aAllowStaleCacheContent;
2931   return NS_OK;
2932 }
2933 NS_IMETHODIMP
GetAllowStaleCacheContent(bool * aAllowStaleCacheContent)2934 HttpChannelChild::GetAllowStaleCacheContent(bool* aAllowStaleCacheContent) {
2935   if (mSynthesizedCacheInfo) {
2936     return mSynthesizedCacheInfo->GetAllowStaleCacheContent(
2937         aAllowStaleCacheContent);
2938   }
2939 
2940   NS_ENSURE_ARG(aAllowStaleCacheContent);
2941   *aAllowStaleCacheContent = mAllowStaleCacheContent;
2942   return NS_OK;
2943 }
2944 
2945 NS_IMETHODIMP
PreferAlternativeDataType(const nsACString & aType)2946 HttpChannelChild::PreferAlternativeDataType(const nsACString& aType) {
2947   ENSURE_CALLED_BEFORE_ASYNC_OPEN();
2948 
2949   if (mSynthesizedCacheInfo) {
2950     return mSynthesizedCacheInfo->PreferAlternativeDataType(aType);
2951   }
2952 
2953   mPreferredCachedAltDataType = aType;
2954   return NS_OK;
2955 }
2956 
2957 NS_IMETHODIMP
GetPreferredAlternativeDataType(nsACString & aType)2958 HttpChannelChild::GetPreferredAlternativeDataType(nsACString& aType) {
2959   aType = mPreferredCachedAltDataType;
2960   return NS_OK;
2961 }
2962 
2963 NS_IMETHODIMP
GetAlternativeDataType(nsACString & aType)2964 HttpChannelChild::GetAlternativeDataType(nsACString& aType) {
2965   if (mSynthesizedCacheInfo) {
2966     return mSynthesizedCacheInfo->GetAlternativeDataType(aType);
2967   }
2968 
2969   // Must be called during or after OnStartRequest
2970   if (!mAfterOnStartRequestBegun) {
2971     return NS_ERROR_NOT_AVAILABLE;
2972   }
2973 
2974   aType = mAvailableCachedAltDataType;
2975   return NS_OK;
2976 }
2977 
2978 NS_IMETHODIMP
OpenAlternativeOutputStream(const nsACString & aType,nsIOutputStream ** _retval)2979 HttpChannelChild::OpenAlternativeOutputStream(const nsACString& aType,
2980                                               nsIOutputStream** _retval) {
2981   MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
2982 
2983   if (mSynthesizedCacheInfo) {
2984     return mSynthesizedCacheInfo->OpenAlternativeOutputStream(aType, _retval);
2985   }
2986 
2987   if (!mIPCOpen) {
2988     return NS_ERROR_NOT_AVAILABLE;
2989   }
2990   if (static_cast<ContentChild*>(gNeckoChild->Manager())->IsShuttingDown()) {
2991     return NS_ERROR_NOT_AVAILABLE;
2992   }
2993 
2994   nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget();
2995   MOZ_ASSERT(neckoTarget);
2996 
2997   RefPtr<AltDataOutputStreamChild> stream = new AltDataOutputStreamChild();
2998   stream->AddIPDLReference();
2999 
3000   gNeckoChild->SetEventTargetForActor(stream, neckoTarget);
3001 
3002   if (!gNeckoChild->SendPAltDataOutputStreamConstructor(
3003           stream, nsCString(aType), this)) {
3004     return NS_ERROR_FAILURE;
3005   }
3006 
3007   stream.forget(_retval);
3008   return NS_OK;
3009 }
3010 
3011 //-----------------------------------------------------------------------------
3012 // HttpChannelChild::nsIResumableChannel
3013 //-----------------------------------------------------------------------------
3014 
3015 NS_IMETHODIMP
ResumeAt(uint64_t startPos,const nsACString & entityID)3016 HttpChannelChild::ResumeAt(uint64_t startPos, const nsACString& entityID) {
3017   LOG(("HttpChannelChild::ResumeAt [this=%p]\n", this));
3018   ENSURE_CALLED_BEFORE_CONNECT();
3019   mStartPos = startPos;
3020   mEntityID = entityID;
3021   mSendResumeAt = true;
3022   return NS_OK;
3023 }
3024 
3025 // GetEntityID is shared in HttpBaseChannel
3026 
3027 //-----------------------------------------------------------------------------
3028 // HttpChannelChild::nsISupportsPriority
3029 //-----------------------------------------------------------------------------
3030 
3031 NS_IMETHODIMP
SetPriority(int32_t aPriority)3032 HttpChannelChild::SetPriority(int32_t aPriority) {
3033   LOG(("HttpChannelChild::SetPriority %p p=%d", this, aPriority));
3034 
3035   int16_t newValue = clamped<int32_t>(aPriority, INT16_MIN, INT16_MAX);
3036   if (mPriority == newValue) return NS_OK;
3037   mPriority = newValue;
3038   if (RemoteChannelExists()) SendSetPriority(mPriority);
3039   return NS_OK;
3040 }
3041 
3042 //-----------------------------------------------------------------------------
3043 // HttpChannelChild::nsIClassOfService
3044 //-----------------------------------------------------------------------------
3045 NS_IMETHODIMP
SetClassFlags(uint32_t inFlags)3046 HttpChannelChild::SetClassFlags(uint32_t inFlags) {
3047   if (mClassOfService == inFlags) {
3048     return NS_OK;
3049   }
3050 
3051   mClassOfService = inFlags;
3052 
3053   LOG(("HttpChannelChild %p ClassOfService=%u", this, mClassOfService));
3054 
3055   if (RemoteChannelExists()) {
3056     SendSetClassOfService(mClassOfService);
3057   }
3058   return NS_OK;
3059 }
3060 
3061 NS_IMETHODIMP
AddClassFlags(uint32_t inFlags)3062 HttpChannelChild::AddClassFlags(uint32_t inFlags) {
3063   mClassOfService |= inFlags;
3064 
3065   LOG(("HttpChannelChild %p ClassOfService=%u", this, mClassOfService));
3066 
3067   if (RemoteChannelExists()) {
3068     SendSetClassOfService(mClassOfService);
3069   }
3070   return NS_OK;
3071 }
3072 
3073 NS_IMETHODIMP
ClearClassFlags(uint32_t inFlags)3074 HttpChannelChild::ClearClassFlags(uint32_t inFlags) {
3075   mClassOfService &= ~inFlags;
3076 
3077   LOG(("HttpChannelChild %p ClassOfService=%u", this, mClassOfService));
3078 
3079   if (RemoteChannelExists()) {
3080     SendSetClassOfService(mClassOfService);
3081   }
3082   return NS_OK;
3083 }
3084 
3085 //-----------------------------------------------------------------------------
3086 // HttpChannelChild::nsIProxiedChannel
3087 //-----------------------------------------------------------------------------
3088 
3089 NS_IMETHODIMP
GetProxyInfo(nsIProxyInfo ** aProxyInfo)3090 HttpChannelChild::GetProxyInfo(nsIProxyInfo** aProxyInfo) { DROP_DEAD(); }
3091 
3092 //-----------------------------------------------------------------------------
3093 // HttpChannelChild::nsIApplicationCacheContainer
3094 //-----------------------------------------------------------------------------
3095 
3096 NS_IMETHODIMP
GetApplicationCache(nsIApplicationCache ** aApplicationCache)3097 HttpChannelChild::GetApplicationCache(nsIApplicationCache** aApplicationCache) {
3098   NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
3099   return NS_OK;
3100 }
3101 NS_IMETHODIMP
SetApplicationCache(nsIApplicationCache * aApplicationCache)3102 HttpChannelChild::SetApplicationCache(nsIApplicationCache* aApplicationCache) {
3103   NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
3104 
3105   mApplicationCache = aApplicationCache;
3106   return NS_OK;
3107 }
3108 
3109 //-----------------------------------------------------------------------------
3110 // HttpChannelChild::nsIApplicationCacheChannel
3111 //-----------------------------------------------------------------------------
3112 
3113 NS_IMETHODIMP
GetApplicationCacheForWrite(nsIApplicationCache ** aApplicationCache)3114 HttpChannelChild::GetApplicationCacheForWrite(
3115     nsIApplicationCache** aApplicationCache) {
3116   *aApplicationCache = nullptr;
3117   return NS_OK;
3118 }
3119 NS_IMETHODIMP
SetApplicationCacheForWrite(nsIApplicationCache * aApplicationCache)3120 HttpChannelChild::SetApplicationCacheForWrite(
3121     nsIApplicationCache* aApplicationCache) {
3122   NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
3123 
3124   // Child channels are not intended to be used for cache writes
3125   return NS_ERROR_NOT_IMPLEMENTED;
3126 }
3127 
3128 NS_IMETHODIMP
GetLoadedFromApplicationCache(bool * aLoadedFromApplicationCache)3129 HttpChannelChild::GetLoadedFromApplicationCache(
3130     bool* aLoadedFromApplicationCache) {
3131   *aLoadedFromApplicationCache = mLoadedFromApplicationCache;
3132   return NS_OK;
3133 }
3134 
3135 NS_IMETHODIMP
GetInheritApplicationCache(bool * aInherit)3136 HttpChannelChild::GetInheritApplicationCache(bool* aInherit) {
3137   *aInherit = mInheritApplicationCache;
3138   return NS_OK;
3139 }
3140 NS_IMETHODIMP
SetInheritApplicationCache(bool aInherit)3141 HttpChannelChild::SetInheritApplicationCache(bool aInherit) {
3142   mInheritApplicationCache = aInherit;
3143   return NS_OK;
3144 }
3145 
3146 NS_IMETHODIMP
GetChooseApplicationCache(bool * aChoose)3147 HttpChannelChild::GetChooseApplicationCache(bool* aChoose) {
3148   *aChoose = mChooseApplicationCache;
3149   return NS_OK;
3150 }
3151 
3152 NS_IMETHODIMP
SetChooseApplicationCache(bool aChoose)3153 HttpChannelChild::SetChooseApplicationCache(bool aChoose) {
3154   mChooseApplicationCache = aChoose;
3155   return NS_OK;
3156 }
3157 
3158 NS_IMETHODIMP
MarkOfflineCacheEntryAsForeign()3159 HttpChannelChild::MarkOfflineCacheEntryAsForeign() {
3160   SendMarkOfflineCacheEntryAsForeign();
3161   return NS_OK;
3162 }
3163 
3164 //-----------------------------------------------------------------------------
3165 // HttpChannelChild::nsIAssociatedContentSecurity
3166 //-----------------------------------------------------------------------------
3167 
GetAssociatedContentSecurity(nsIAssociatedContentSecurity ** _result)3168 bool HttpChannelChild::GetAssociatedContentSecurity(
3169     nsIAssociatedContentSecurity** _result) {
3170   if (!mSecurityInfo) return false;
3171 
3172   nsCOMPtr<nsIAssociatedContentSecurity> assoc =
3173       do_QueryInterface(mSecurityInfo);
3174   if (!assoc) return false;
3175 
3176   if (_result) assoc.forget(_result);
3177   return true;
3178 }
3179 
3180 NS_IMETHODIMP
GetCountSubRequestsBrokenSecurity(int32_t * aSubRequestsBrokenSecurity)3181 HttpChannelChild::GetCountSubRequestsBrokenSecurity(
3182     int32_t* aSubRequestsBrokenSecurity) {
3183   nsCOMPtr<nsIAssociatedContentSecurity> assoc;
3184   if (!GetAssociatedContentSecurity(getter_AddRefs(assoc))) return NS_OK;
3185 
3186   return assoc->GetCountSubRequestsBrokenSecurity(aSubRequestsBrokenSecurity);
3187 }
3188 NS_IMETHODIMP
SetCountSubRequestsBrokenSecurity(int32_t aSubRequestsBrokenSecurity)3189 HttpChannelChild::SetCountSubRequestsBrokenSecurity(
3190     int32_t aSubRequestsBrokenSecurity) {
3191   nsCOMPtr<nsIAssociatedContentSecurity> assoc;
3192   if (!GetAssociatedContentSecurity(getter_AddRefs(assoc))) return NS_OK;
3193 
3194   return assoc->SetCountSubRequestsBrokenSecurity(aSubRequestsBrokenSecurity);
3195 }
3196 
3197 NS_IMETHODIMP
GetCountSubRequestsNoSecurity(int32_t * aSubRequestsNoSecurity)3198 HttpChannelChild::GetCountSubRequestsNoSecurity(
3199     int32_t* aSubRequestsNoSecurity) {
3200   nsCOMPtr<nsIAssociatedContentSecurity> assoc;
3201   if (!GetAssociatedContentSecurity(getter_AddRefs(assoc))) return NS_OK;
3202 
3203   return assoc->GetCountSubRequestsNoSecurity(aSubRequestsNoSecurity);
3204 }
3205 NS_IMETHODIMP
SetCountSubRequestsNoSecurity(int32_t aSubRequestsNoSecurity)3206 HttpChannelChild::SetCountSubRequestsNoSecurity(
3207     int32_t aSubRequestsNoSecurity) {
3208   nsCOMPtr<nsIAssociatedContentSecurity> assoc;
3209   if (!GetAssociatedContentSecurity(getter_AddRefs(assoc))) return NS_OK;
3210 
3211   return assoc->SetCountSubRequestsNoSecurity(aSubRequestsNoSecurity);
3212 }
3213 
3214 NS_IMETHODIMP
Flush()3215 HttpChannelChild::Flush() {
3216   nsCOMPtr<nsIAssociatedContentSecurity> assoc;
3217   if (!GetAssociatedContentSecurity(getter_AddRefs(assoc))) return NS_OK;
3218 
3219   nsresult rv;
3220   int32_t broken, no;
3221 
3222   rv = assoc->GetCountSubRequestsBrokenSecurity(&broken);
3223   NS_ENSURE_SUCCESS(rv, rv);
3224   rv = assoc->GetCountSubRequestsNoSecurity(&no);
3225   NS_ENSURE_SUCCESS(rv, rv);
3226 
3227   if (mIPCOpen) SendUpdateAssociatedContentSecurity(broken, no);
3228 
3229   return NS_OK;
3230 }
3231 
3232 //-----------------------------------------------------------------------------
3233 // HttpChannelChild::nsIHttpChannelChild
3234 //-----------------------------------------------------------------------------
3235 
AddCookiesToRequest()3236 NS_IMETHODIMP HttpChannelChild::AddCookiesToRequest() {
3237   HttpBaseChannel::AddCookiesToRequest();
3238   return NS_OK;
3239 }
3240 
GetClientSetRequestHeaders(RequestHeaderTuples ** aRequestHeaders)3241 NS_IMETHODIMP HttpChannelChild::GetClientSetRequestHeaders(
3242     RequestHeaderTuples** aRequestHeaders) {
3243   *aRequestHeaders = &mClientSetRequestHeaders;
3244   return NS_OK;
3245 }
3246 
GetClientSetCorsPreflightParameters(OptionalCorsPreflightArgs & aArgs)3247 void HttpChannelChild::GetClientSetCorsPreflightParameters(
3248     OptionalCorsPreflightArgs& aArgs) {
3249   if (mRequireCORSPreflight) {
3250     CorsPreflightArgs args;
3251     args.unsafeHeaders() = mUnsafeHeaders;
3252     aArgs = args;
3253   } else {
3254     aArgs = mozilla::void_t();
3255   }
3256 }
3257 
3258 NS_IMETHODIMP
RemoveCorsPreflightCacheEntry(nsIURI * aURI,nsIPrincipal * aPrincipal)3259 HttpChannelChild::RemoveCorsPreflightCacheEntry(nsIURI* aURI,
3260                                                 nsIPrincipal* aPrincipal) {
3261   URIParams uri;
3262   SerializeURI(aURI, uri);
3263   PrincipalInfo principalInfo;
3264   nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
3265   if (NS_WARN_IF(NS_FAILED(rv))) {
3266     return rv;
3267   }
3268   bool result = false;
3269   // Be careful to not attempt to send a message to the parent after the
3270   // actor has been destroyed.
3271   if (mIPCOpen) {
3272     result = SendRemoveCorsPreflightCacheEntry(uri, principalInfo);
3273   }
3274   return result ? NS_OK : NS_ERROR_FAILURE;
3275 }
3276 
3277 //-----------------------------------------------------------------------------
3278 // HttpChannelChild::nsIDivertableChannel
3279 //-----------------------------------------------------------------------------
3280 NS_IMETHODIMP
DivertToParent(ChannelDiverterChild ** aChild)3281 HttpChannelChild::DivertToParent(ChannelDiverterChild** aChild) {
3282   LOG(("HttpChannelChild::DivertToParent [this=%p]\n", this));
3283   MOZ_RELEASE_ASSERT(aChild);
3284   MOZ_RELEASE_ASSERT(gNeckoChild);
3285   MOZ_RELEASE_ASSERT(!mDivertingToParent);
3286 
3287   nsresult rv = NS_OK;
3288 
3289   // If the channel was intercepted, then we likely do not have an IPC actor
3290   // yet.  We need one, though, in order to have a parent side to divert to.
3291   // Therefore, create the actor just in time for us to suspend and divert it.
3292   if (mSynthesizedResponse && !RemoteChannelExists()) {
3293     mSuspendParentAfterSynthesizeResponse = true;
3294     rv = ContinueAsyncOpen();
3295     NS_ENSURE_SUCCESS(rv, rv);
3296   }
3297 
3298   // We must fail DivertToParent() if there's no parent end of the channel (and
3299   // won't be!) due to early failure.
3300   if (NS_FAILED(mStatus) && !RemoteChannelExists()) {
3301     return mStatus;
3302   }
3303 
3304   // Once this is set, it should not be unset before the child is taken down.
3305   mDivertingToParent = true;
3306 
3307   rv = Suspend();
3308   if (NS_WARN_IF(NS_FAILED(rv))) {
3309     return rv;
3310   }
3311   if (static_cast<ContentChild*>(gNeckoChild->Manager())->IsShuttingDown()) {
3312     return NS_ERROR_FAILURE;
3313   }
3314 
3315   HttpChannelDiverterArgs args;
3316   args.mChannelChild() = this;
3317   args.mApplyConversion() = mApplyConversion;
3318 
3319   PChannelDiverterChild* diverter =
3320       gNeckoChild->SendPChannelDiverterConstructor(args);
3321   MOZ_RELEASE_ASSERT(diverter);
3322 
3323   *aChild = static_cast<ChannelDiverterChild*>(diverter);
3324 
3325   return NS_OK;
3326 }
3327 
3328 NS_IMETHODIMP
UnknownDecoderInvolvedKeepData()3329 HttpChannelChild::UnknownDecoderInvolvedKeepData() {
3330   LOG(("HttpChannelChild::UnknownDecoderInvolvedKeepData [this=%p]", this));
3331   MOZ_ASSERT(NS_IsMainThread());
3332 
3333   mUnknownDecoderInvolved = true;
3334   return NS_OK;
3335 }
3336 
3337 NS_IMETHODIMP
UnknownDecoderInvolvedOnStartRequestCalled()3338 HttpChannelChild::UnknownDecoderInvolvedOnStartRequestCalled() {
3339   LOG(
3340       ("HttpChannelChild::UnknownDecoderInvolvedOnStartRequestCalled "
3341        "[this=%p, mDivertingToParent=%d]",
3342        this, static_cast<bool>(mDivertingToParent)));
3343   MOZ_ASSERT(NS_IsMainThread());
3344 
3345   mUnknownDecoderInvolved = false;
3346 
3347   nsresult rv = NS_OK;
3348 
3349   if (mDivertingToParent) {
3350     rv = mEventQ->PrependEvents(mUnknownDecoderEventQ);
3351   }
3352   mUnknownDecoderEventQ.Clear();
3353 
3354   return rv;
3355 }
3356 
3357 NS_IMETHODIMP
GetDivertingToParent(bool * aDiverting)3358 HttpChannelChild::GetDivertingToParent(bool* aDiverting) {
3359   NS_ENSURE_ARG_POINTER(aDiverting);
3360   *aDiverting = mDivertingToParent;
3361   return NS_OK;
3362 }
3363 
3364 //-----------------------------------------------------------------------------
3365 // HttpChannelChild::nsIThreadRetargetableRequest
3366 //-----------------------------------------------------------------------------
3367 
3368 NS_IMETHODIMP
RetargetDeliveryTo(nsIEventTarget * aNewTarget)3369 HttpChannelChild::RetargetDeliveryTo(nsIEventTarget* aNewTarget) {
3370   LOG(("HttpChannelChild::RetargetDeliveryTo [this=%p, aNewTarget=%p]", this,
3371        aNewTarget));
3372 
3373   MOZ_ASSERT(NS_IsMainThread(), "Should be called on main thread only");
3374   MOZ_ASSERT(!mODATarget);
3375   MOZ_ASSERT(aNewTarget);
3376 
3377   NS_ENSURE_ARG(aNewTarget);
3378   if (aNewTarget->IsOnCurrentThread()) {
3379     NS_WARNING("Retargeting delivery to same thread");
3380     mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::successMainThread;
3381     return NS_OK;
3382   }
3383 
3384   // Ensure that |mListener| and any subsequent listeners can be retargeted
3385   // to another thread.
3386   nsresult rv = NS_OK;
3387   nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
3388       do_QueryInterface(mListener, &rv);
3389   if (!retargetableListener || NS_FAILED(rv)) {
3390     NS_WARNING("Listener is not retargetable");
3391     mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::failListener;
3392     return NS_ERROR_NO_INTERFACE;
3393   }
3394 
3395   rv = retargetableListener->CheckListenerChain();
3396   if (NS_FAILED(rv)) {
3397     NS_WARNING("Subsequent listeners are not retargetable");
3398     mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::failListenerChain;
3399     return rv;
3400   }
3401 
3402   {
3403     MutexAutoLock lock(mEventTargetMutex);
3404     mODATarget = aNewTarget;
3405   }
3406 
3407   mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::success;
3408   return NS_OK;
3409 }
3410 
3411 NS_IMETHODIMP
GetDeliveryTarget(nsIEventTarget ** aEventTarget)3412 HttpChannelChild::GetDeliveryTarget(nsIEventTarget** aEventTarget) {
3413   MutexAutoLock lock(mEventTargetMutex);
3414 
3415   nsCOMPtr<nsIEventTarget> target = mODATarget;
3416   if (!mODATarget) {
3417     target = GetCurrentThreadEventTarget();
3418   }
3419   target.forget(aEventTarget);
3420   return NS_OK;
3421 }
3422 
ResetInterception()3423 void HttpChannelChild::ResetInterception() {
3424   NS_ENSURE_TRUE_VOID(gNeckoChild != nullptr);
3425 
3426   if (mInterceptListener) {
3427     mInterceptListener->Cleanup();
3428   }
3429   mInterceptListener = nullptr;
3430 
3431   // The chance to intercept any further requests associated with this channel
3432   // (such as redirects) has passed.
3433   if (mRedirectMode != nsIHttpChannelInternal::REDIRECT_MODE_MANUAL) {
3434     mLoadFlags |= LOAD_BYPASS_SERVICE_WORKER;
3435   }
3436 
3437   // If the channel has already been aborted or canceled, just stop.
3438   if (NS_FAILED(mStatus)) {
3439     return;
3440   }
3441 
3442   // Continue with the original cross-process request
3443   nsresult rv = ContinueAsyncOpen();
3444   if (NS_WARN_IF(NS_FAILED(rv))) {
3445     Unused << Cancel(rv);
3446   }
3447 }
3448 
3449 NS_IMETHODIMP
GetResponseSynthesized(bool * aSynthesized)3450 HttpChannelChild::GetResponseSynthesized(bool* aSynthesized) {
3451   NS_ENSURE_ARG_POINTER(aSynthesized);
3452   *aSynthesized = mSynthesizedResponse;
3453   return NS_OK;
3454 }
3455 
TrySendDeletingChannel()3456 void HttpChannelChild::TrySendDeletingChannel() {
3457   if (!mDeletingChannelSent.compareExchange(false, true)) {
3458     // SendDeletingChannel is already sent.
3459     return;
3460   }
3461 
3462   if (NS_IsMainThread()) {
3463     if (NS_WARN_IF(!mIPCOpen)) {
3464       // IPC actor is detroyed already, do not send more messages.
3465       return;
3466     }
3467 
3468     Unused << PHttpChannelChild::SendDeletingChannel();
3469     return;
3470   }
3471 
3472   nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget();
3473   MOZ_ASSERT(neckoTarget);
3474 
3475   DebugOnly<nsresult> rv = neckoTarget->Dispatch(
3476       NewNonOwningRunnableMethod(
3477           "net::HttpChannelChild::TrySendDeletingChannel", this,
3478           &HttpChannelChild::TrySendDeletingChannel),
3479       NS_DISPATCH_NORMAL);
3480   MOZ_ASSERT(NS_SUCCEEDED(rv));
3481 }
3482 
OnCopyComplete(nsresult aStatus)3483 void HttpChannelChild::OnCopyComplete(nsresult aStatus) {
3484   nsCOMPtr<nsIRunnable> runnable = NewRunnableMethod<nsresult>(
3485       "net::HttpBaseChannel::EnsureUploadStreamIsCloneableComplete", this,
3486       &HttpChannelChild::EnsureUploadStreamIsCloneableComplete, aStatus);
3487   nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget();
3488   MOZ_ASSERT(neckoTarget);
3489 
3490   Unused << neckoTarget->Dispatch(runnable, NS_DISPATCH_NORMAL);
3491 }
3492 
AsyncCall(void (HttpChannelChild::* funcPtr)(),nsRunnableMethod<HttpChannelChild> ** retval)3493 nsresult HttpChannelChild::AsyncCall(
3494     void (HttpChannelChild::*funcPtr)(),
3495     nsRunnableMethod<HttpChannelChild>** retval) {
3496   nsresult rv;
3497 
3498   RefPtr<nsRunnableMethod<HttpChannelChild>> event =
3499       NewRunnableMethod("net::HttpChannelChild::AsyncCall", this, funcPtr);
3500   nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget();
3501   MOZ_ASSERT(neckoTarget);
3502 
3503   rv = neckoTarget->Dispatch(event, NS_DISPATCH_NORMAL);
3504 
3505   if (NS_SUCCEEDED(rv) && retval) {
3506     *retval = event;
3507   }
3508 
3509   return rv;
3510 }
3511 
3512 class CancelEvent final : public NeckoTargetChannelEvent<HttpChannelChild> {
3513  public:
CancelEvent(HttpChannelChild * aChild,nsresult aRv)3514   CancelEvent(HttpChannelChild* aChild, nsresult aRv)
3515       : NeckoTargetChannelEvent<HttpChannelChild>(aChild), mRv(aRv) {
3516     MOZ_ASSERT(!NS_IsMainThread());
3517     MOZ_ASSERT(aChild);
3518   }
3519 
Run()3520   void Run() override {
3521     MOZ_ASSERT(NS_IsMainThread());
3522     mChild->Cancel(mRv);
3523   }
3524 
3525  private:
3526   const nsresult mRv;
3527 };
3528 
CancelOnMainThread(nsresult aRv)3529 void HttpChannelChild::CancelOnMainThread(nsresult aRv) {
3530   LOG(("HttpChannelChild::CancelOnMainThread [this=%p]", this));
3531 
3532   if (NS_IsMainThread()) {
3533     Cancel(aRv);
3534     return;
3535   }
3536 
3537   mEventQ->Suspend();
3538   // Cancel is expected to preempt any other channel events, thus we put this
3539   // event in the front of mEventQ to make sure nsIStreamListener not receiving
3540   // any ODA/OnStopRequest callbacks.
3541   UniquePtr<ChannelEvent> cancelEvent = MakeUnique<CancelEvent>(this, aRv);
3542   mEventQ->PrependEvent(cancelEvent);
3543   mEventQ->Resume();
3544 }
3545 
OverrideWithSynthesizedResponse(nsAutoPtr<nsHttpResponseHead> & aResponseHead,nsIInputStream * aSynthesizedInput,nsIInterceptedBodyCallback * aSynthesizedCallback,InterceptStreamListener * aStreamListener,nsICacheInfoChannel * aCacheInfoChannel)3546 void HttpChannelChild::OverrideWithSynthesizedResponse(
3547     nsAutoPtr<nsHttpResponseHead>& aResponseHead,
3548     nsIInputStream* aSynthesizedInput,
3549     nsIInterceptedBodyCallback* aSynthesizedCallback,
3550     InterceptStreamListener* aStreamListener,
3551     nsICacheInfoChannel* aCacheInfoChannel) {
3552   nsresult rv = NS_OK;
3553   auto autoCleanup = MakeScopeExit([&] {
3554     // Auto-cancel on failure.  Do this first to get mStatus set, if necessary.
3555     if (NS_FAILED(rv)) {
3556       Cancel(rv);
3557     }
3558 
3559     // If we early exit before taking ownership of the body, then automatically
3560     // invoke the callback.  This could be due to an error or because we're not
3561     // going to consume it due to a redirect, etc.
3562     if (aSynthesizedCallback) {
3563       aSynthesizedCallback->BodyComplete(mStatus);
3564     }
3565   });
3566 
3567   if (NS_FAILED(mStatus)) {
3568     return;
3569   }
3570 
3571   mInterceptListener = aStreamListener;
3572 
3573   // Intercepted responses should already be decoded.  If its a redirect,
3574   // however, we want to respect the encoding of the final result instead.
3575   if (!nsHttpChannel::WillRedirect(aResponseHead)) {
3576     SetApplyConversion(false);
3577   }
3578 
3579   mResponseHead = aResponseHead;
3580   mSynthesizedResponse = true;
3581 
3582   mSynthesizedInput = aSynthesizedInput;
3583 
3584   if (!mSynthesizedInput) {
3585     rv = NS_NewCStringInputStream(getter_AddRefs(mSynthesizedInput),
3586                                   EmptyCString());
3587     NS_ENSURE_SUCCESS_VOID(rv);
3588   }
3589 
3590   if (nsHttpChannel::WillRedirect(mResponseHead)) {
3591     // Normally we handle redirect limits in the parent process.  The way
3592     // e10s synthesized redirects work, however, the parent process does not
3593     // get an accurate redirect count.  Therefore we need to enforce it here.
3594     rv = CheckRedirectLimit(nsIChannelEventSink::REDIRECT_TEMPORARY);
3595     if (NS_WARN_IF(NS_FAILED(rv))) {
3596       Cancel(rv);
3597       return;
3598     }
3599 
3600     mShouldInterceptSubsequentRedirect = true;
3601     if (mInterceptListener) {
3602       mInterceptListener->Cleanup();
3603       mInterceptListener = nullptr;
3604     }
3605     // Continue with the original cross-process request
3606     rv = ContinueAsyncOpen();
3607     return;
3608   }
3609 
3610   // For progress we trust the content-length for the "maximum" size.
3611   // We can't determine the full size from the stream itself since we
3612   // only receive the data incrementally.  We can't trust Available()
3613   // here.
3614   // TODO: We could implement an nsIFixedLengthInputStream interface and
3615   //       QI to it here.  This would let us determine the total length
3616   //       for streams that support it.  See bug 1388774.
3617   rv = GetContentLength(&mSynthesizedStreamLength);
3618   if (NS_FAILED(rv)) {
3619     mSynthesizedStreamLength = -1;
3620   }
3621 
3622   nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget();
3623   MOZ_ASSERT(neckoTarget);
3624 
3625   rv = nsInputStreamPump::Create(getter_AddRefs(mSynthesizedResponsePump),
3626                                  mSynthesizedInput, 0, 0, true, neckoTarget);
3627   NS_ENSURE_SUCCESS_VOID(rv);
3628 
3629   mSynthesizedCacheInfo = aCacheInfoChannel;
3630 
3631   rv = mSynthesizedResponsePump->AsyncRead(aStreamListener, nullptr);
3632   NS_ENSURE_SUCCESS_VOID(rv);
3633 
3634   // The pump is started, so take ownership of the body callback.  We
3635   // clear the argument to avoid auto-completing it via the ScopeExit
3636   // lambda.
3637   mSynthesizedCallback = aSynthesizedCallback;
3638   aSynthesizedCallback = nullptr;
3639 
3640   // if this channel has been suspended previously, the pump needs to be
3641   // correspondingly suspended now that it exists.
3642   for (uint32_t i = 0; i < mSuspendCount; i++) {
3643     rv = mSynthesizedResponsePump->Suspend();
3644     NS_ENSURE_SUCCESS_VOID(rv);
3645   }
3646 
3647   MOZ_DIAGNOSTIC_ASSERT(!mCanceled);
3648 }
3649 
3650 NS_IMETHODIMP
ForceIntercepted(bool aPostRedirectChannelShouldIntercept,bool aPostRedirectChannelShouldUpgrade)3651 HttpChannelChild::ForceIntercepted(bool aPostRedirectChannelShouldIntercept,
3652                                    bool aPostRedirectChannelShouldUpgrade) {
3653   mShouldParentIntercept = true;
3654   mPostRedirectChannelShouldIntercept = aPostRedirectChannelShouldIntercept;
3655   mPostRedirectChannelShouldUpgrade = aPostRedirectChannelShouldUpgrade;
3656   return NS_OK;
3657 }
3658 
ForceIntercepted(nsIInputStream * aSynthesizedInput,nsIInterceptedBodyCallback * aSynthesizedCallback,nsICacheInfoChannel * aCacheInfo)3659 void HttpChannelChild::ForceIntercepted(
3660     nsIInputStream* aSynthesizedInput,
3661     nsIInterceptedBodyCallback* aSynthesizedCallback,
3662     nsICacheInfoChannel* aCacheInfo) {
3663   mSynthesizedInput = aSynthesizedInput;
3664   mSynthesizedCallback = aSynthesizedCallback;
3665   mSynthesizedCacheInfo = aCacheInfo;
3666   mSynthesizedResponse = true;
3667   mRedirectingForSubsequentSynthesizedResponse = true;
3668 }
3669 
RecvIssueDeprecationWarning(const uint32_t & warning,const bool & asError)3670 mozilla::ipc::IPCResult HttpChannelChild::RecvIssueDeprecationWarning(
3671     const uint32_t& warning, const bool& asError) {
3672   nsCOMPtr<nsIDeprecationWarner> warner;
3673   GetCallback(warner);
3674   if (warner) {
3675     warner->IssueWarning(warning, asError);
3676   }
3677   return IPC_OK();
3678 }
3679 
ShouldInterceptURI(nsIURI * aURI,bool & aShouldUpgrade)3680 bool HttpChannelChild::ShouldInterceptURI(nsIURI* aURI, bool& aShouldUpgrade) {
3681   bool isHttps = false;
3682   nsresult rv = aURI->SchemeIs("https", &isHttps);
3683   NS_ENSURE_SUCCESS(rv, false);
3684   nsCOMPtr<nsIPrincipal> resultPrincipal;
3685   if (!isHttps && mLoadInfo) {
3686     nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
3687         this, getter_AddRefs(resultPrincipal));
3688   }
3689   OriginAttributes originAttributes;
3690   NS_ENSURE_TRUE(NS_GetOriginAttributes(this, originAttributes), false);
3691   rv =
3692       NS_ShouldSecureUpgrade(aURI, mLoadInfo, resultPrincipal, mPrivateBrowsing,
3693                              mAllowSTS, originAttributes, aShouldUpgrade);
3694   NS_ENSURE_SUCCESS(rv, false);
3695 
3696   nsCOMPtr<nsIURI> upgradedURI;
3697   if (aShouldUpgrade) {
3698     rv = NS_GetSecureUpgradedURI(aURI, getter_AddRefs(upgradedURI));
3699     NS_ENSURE_SUCCESS(rv, false);
3700   }
3701 
3702   return ShouldIntercept(upgradedURI ? upgradedURI.get() : aURI);
3703 }
3704 
RecvSetPriority(const int16_t & aPriority)3705 mozilla::ipc::IPCResult HttpChannelChild::RecvSetPriority(
3706     const int16_t& aPriority) {
3707   mPriority = aPriority;
3708   return IPC_OK();
3709 }
3710 
RecvAttachStreamFilter(Endpoint<extensions::PStreamFilterParent> && aEndpoint)3711 mozilla::ipc::IPCResult HttpChannelChild::RecvAttachStreamFilter(
3712     Endpoint<extensions::PStreamFilterParent>&& aEndpoint) {
3713   extensions::StreamFilterParent::Attach(this, Move(aEndpoint));
3714   return IPC_OK();
3715 }
3716 
RecvCancelDiversion()3717 mozilla::ipc::IPCResult HttpChannelChild::RecvCancelDiversion() {
3718   MOZ_ASSERT(NS_IsMainThread());
3719 
3720   // This method is a very special case for cancellation of a diverted
3721   // intercepted channel.  Normally we would go through the mEventQ in order to
3722   // serialize event execution in the face of sync XHR and now background
3723   // channels.  However, similar to how CancelOnMainThread describes, Cancel()
3724   // pre-empts everything.  (And frankly, we want this stack frame on the stack
3725   // if a crash happens.)
3726   Cancel(NS_ERROR_ABORT);
3727   return IPC_OK();
3728 }
3729 
ActorDestroy(ActorDestroyReason aWhy)3730 void HttpChannelChild::ActorDestroy(ActorDestroyReason aWhy) {
3731   MOZ_ASSERT(NS_IsMainThread());
3732 
3733   // OnStartRequest might be dropped if IPDL is destroyed abnormally
3734   // and BackgroundChild might have pending IPC messages.
3735   // Clean up BackgroundChild at this time to prevent memleak.
3736   if (aWhy != Deletion) {
3737     CleanupBackgroundChannel();
3738   }
3739 }
3740 
RecvLogBlockedCORSRequest(const nsString & aMessage)3741 mozilla::ipc::IPCResult HttpChannelChild::RecvLogBlockedCORSRequest(
3742     const nsString& aMessage) {
3743   Unused << LogBlockedCORSRequest(aMessage);
3744   return IPC_OK();
3745 }
3746 
3747 NS_IMETHODIMP
LogBlockedCORSRequest(const nsAString & aMessage)3748 HttpChannelChild::LogBlockedCORSRequest(const nsAString& aMessage) {
3749   if (mLoadInfo) {
3750     uint64_t innerWindowID = mLoadInfo->GetInnerWindowID();
3751     nsCORSListenerProxy::LogBlockedCORSRequest(innerWindowID, aMessage);
3752   }
3753   return NS_OK;
3754 }
3755 
MaybeCallSynthesizedCallback()3756 void HttpChannelChild::MaybeCallSynthesizedCallback() {
3757   if (!mSynthesizedCallback) {
3758     return;
3759   }
3760 
3761   mSynthesizedCallback->BodyComplete(mStatus);
3762   mSynthesizedCallback = nullptr;
3763 }
3764 
3765 }  // namespace net
3766 }  // namespace mozilla
3767