Coverage Report

Created: 2018-09-25 14:53

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