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