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