Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/http/HttpChannelParent.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
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
// HttpLog.h should generally be included first
8
#include "HttpLog.h"
9
10
#include "mozilla/ipc/FileDescriptorSetParent.h"
11
#include "mozilla/ipc/IPCStreamUtils.h"
12
#include "mozilla/net/HttpChannelParent.h"
13
#include "mozilla/dom/ContentParent.h"
14
#include "mozilla/dom/Element.h"
15
#include "mozilla/dom/ServiceWorkerUtils.h"
16
#include "mozilla/dom/TabParent.h"
17
#include "mozilla/net/NeckoParent.h"
18
#include "mozilla/InputStreamLengthHelper.h"
19
#include "mozilla/IntegerPrintfMacros.h"
20
#include "mozilla/UniquePtr.h"
21
#include "mozilla/Unused.h"
22
#include "HttpBackgroundChannelParent.h"
23
#include "HttpChannelParentListener.h"
24
#include "nsHttpHandler.h"
25
#include "nsNetCID.h"
26
#include "nsNetUtil.h"
27
#include "nsISupportsPriority.h"
28
#include "nsIAuthPromptProvider.h"
29
#include "nsIBackgroundChannelRegistrar.h"
30
#include "nsSerializationHelper.h"
31
#include "nsISerializable.h"
32
#include "nsIApplicationCacheService.h"
33
#include "mozilla/ipc/InputStreamUtils.h"
34
#include "mozilla/ipc/URIUtils.h"
35
#include "SerializedLoadContext.h"
36
#include "nsIAuthInformation.h"
37
#include "nsIAuthPromptCallback.h"
38
#include "nsIContentPolicy.h"
39
#include "mozilla/ipc/BackgroundUtils.h"
40
#include "nsICachingChannel.h"
41
#include "mozilla/LoadInfo.h"
42
#include "nsQueryObject.h"
43
#include "mozilla/BasePrincipal.h"
44
#include "nsCORSListenerProxy.h"
45
#include "nsIIPCSerializableInputStream.h"
46
#include "nsIPrompt.h"
47
#include "mozilla/net/RedirectChannelRegistrar.h"
48
#include "nsIWindowWatcher.h"
49
#include "nsIDocument.h"
50
#include "nsStreamUtils.h"
51
#include "nsStringStream.h"
52
#include "nsIStorageStream.h"
53
#include "nsThreadUtils.h"
54
#include "nsQueryObject.h"
55
#include "nsIURIClassifier.h"
56
57
using mozilla::BasePrincipal;
58
using namespace mozilla::dom;
59
using namespace mozilla::ipc;
60
61
namespace mozilla {
62
namespace net {
63
64
HttpChannelParent::HttpChannelParent(const PBrowserOrId& iframeEmbedding,
65
                                     nsILoadContext* aLoadContext,
66
                                     PBOverrideStatus aOverrideStatus)
67
  : mLoadContext(aLoadContext)
68
  , mNestedFrameId(0)
69
  , mIPCClosed(false)
70
  , mPBOverride(aOverrideStatus)
71
  , mStatus(NS_OK)
72
  , mIgnoreProgress(false)
73
  , mSentRedirect1BeginFailed(false)
74
  , mReceivedRedirect2Verify(false)
75
  , mHasSuspendedByBackPressure(false)
76
  , mPendingDiversion(false)
77
  , mDivertingFromChild(false)
78
  , mDivertedOnStartRequest(false)
79
  , mSuspendedForDiversion(false)
80
  , mSuspendAfterSynthesizeResponse(false)
81
  , mWillSynthesizeResponse(false)
82
  , mCacheNeedFlowControlInitialized(false)
83
  , mNeedFlowControl(true)
84
  , mSuspendedForFlowControl(false)
85
  , mDoingCrossProcessRedirect(false)
86
0
{
87
0
  LOG(("Creating HttpChannelParent [this=%p]\n", this));
88
0
89
0
  // Ensure gHttpHandler is initialized: we need the atom table up and running.
90
0
  nsCOMPtr<nsIHttpProtocolHandler> dummyInitializer =
91
0
    do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http");
92
0
93
0
  MOZ_ASSERT(gHttpHandler);
94
0
  mHttpHandler = gHttpHandler;
95
0
96
0
  if (iframeEmbedding.type() == PBrowserOrId::TPBrowserParent) {
97
0
    mTabParent = static_cast<dom::TabParent*>(iframeEmbedding.get_PBrowserParent());
98
0
  } else {
99
0
    mNestedFrameId = iframeEmbedding.get_TabId();
100
0
  }
101
0
102
0
  mSendWindowSize = gHttpHandler->SendWindowSize();
103
0
104
0
  mEventQ = new ChannelEventQueue(static_cast<nsIParentRedirectingChannel*>(this));
105
0
}
106
107
HttpChannelParent::~HttpChannelParent()
108
0
{
109
0
  LOG(("Destroying HttpChannelParent [this=%p]\n", this));
110
0
  CleanupBackgroundChannel();
111
0
}
112
113
void
114
HttpChannelParent::ActorDestroy(ActorDestroyReason why)
115
0
{
116
0
  // We may still have refcount>0 if nsHttpChannel hasn't called OnStopRequest
117
0
  // yet, but child process has crashed.  We must not try to send any more msgs
118
0
  // to child, or IPDL will kill chrome process, too.
119
0
  mIPCClosed = true;
120
0
121
0
  // If this is an intercepted channel, we need to make sure that any resources are
122
0
  // cleaned up to avoid leaks.
123
0
  if (mParentListener) {
124
0
    mParentListener->ClearInterceptedChannel(this);
125
0
  }
126
0
127
0
  CleanupBackgroundChannel();
128
0
}
129
130
bool
131
HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs)
132
0
{
133
0
  LOG(("HttpChannelParent::Init [this=%p]\n", this));
134
0
  switch (aArgs.type()) {
135
0
  case HttpChannelCreationArgs::THttpChannelOpenArgs:
136
0
  {
137
0
    const HttpChannelOpenArgs& a = aArgs.get_HttpChannelOpenArgs();
138
0
    return DoAsyncOpen(a.uri(), a.original(), a.doc(), a.referrer(),
139
0
                       a.referrerPolicy(), a.apiRedirectTo(), a.topWindowURI(),
140
0
                       a.loadFlags(), a.requestHeaders(),
141
0
                       a.requestMethod(), a.uploadStream(),
142
0
                       a.uploadStreamHasHeaders(), a.priority(), a.classOfService(),
143
0
                       a.redirectionLimit(), a.allowSTS(),
144
0
                       a.thirdPartyFlags(), a.resumeAt(), a.startPos(),
145
0
                       a.entityID(), a.chooseApplicationCache(),
146
0
                       a.appCacheClientID(), a.allowSpdy(), a.allowAltSvc(), a.beConservative(),
147
0
                       a.tlsFlags(), a.loadInfo(), a.synthesizedResponseHead(),
148
0
                       a.synthesizedSecurityInfoSerialization(),
149
0
                       a.cacheKey(), a.requestContextID(), a.preflightArgs(),
150
0
                       a.initialRwin(), a.blockAuthPrompt(),
151
0
                       a.suspendAfterSynthesizeResponse(),
152
0
                       a.allowStaleCacheContent(), a.contentTypeHint(),
153
0
                       a.corsMode(), a.redirectMode(),
154
0
                       a.channelId(), a.integrityMetadata(),
155
0
                       a.contentWindowId(), a.preferredAlternativeType(),
156
0
                       a.topLevelOuterContentWindowId(),
157
0
                       a.launchServiceWorkerStart(),
158
0
                       a.launchServiceWorkerEnd(),
159
0
                       a.dispatchFetchEventStart(),
160
0
                       a.dispatchFetchEventEnd(),
161
0
                       a.handleFetchEventStart(),
162
0
                       a.handleFetchEventEnd(),
163
0
                       a.forceMainDocumentChannel(),
164
0
                       a.navigationStartTimeStamp());
165
0
  }
166
0
  case HttpChannelCreationArgs::THttpChannelConnectArgs:
167
0
  {
168
0
    const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs();
169
0
    return ConnectChannel(cArgs.registrarId(), cArgs.shouldIntercept());
170
0
  }
171
0
  default:
172
0
    MOZ_ASSERT_UNREACHABLE("unknown open type");
173
0
    return false;
174
0
  }
175
0
}
176
177
void
178
HttpChannelParent::TryInvokeAsyncOpen(nsresult aRv)
179
0
{
180
0
  LOG(("HttpChannelParent::TryInvokeAsyncOpen [this=%p barrier=%u rv=%" PRIx32
181
0
       "]\n", this, mAsyncOpenBarrier, static_cast<uint32_t>(aRv)));
182
0
  MOZ_ASSERT(NS_IsMainThread());
183
0
184
0
  // TryInvokeAsyncOpen is called more than we expected.
185
0
  // Assert in nightly build but ignore it in release channel.
186
0
  MOZ_DIAGNOSTIC_ASSERT(mAsyncOpenBarrier > 0);
187
0
  if (NS_WARN_IF(!mAsyncOpenBarrier)) {
188
0
    return;
189
0
  }
190
0
191
0
  if (--mAsyncOpenBarrier > 0 && NS_SUCCEEDED(aRv)) {
192
0
    // Need to wait for more events.
193
0
    return;
194
0
  }
195
0
196
0
  InvokeAsyncOpen(aRv);
197
0
}
198
199
void
200
HttpChannelParent::OnBackgroundParentReady(
201
                                         HttpBackgroundChannelParent* aBgParent)
202
0
{
203
0
  LOG(("HttpChannelParent::OnBackgroundParentReady [this=%p bgParent=%p]\n",
204
0
       this, aBgParent));
205
0
  MOZ_ASSERT(NS_IsMainThread());
206
0
  MOZ_ASSERT(!mBgParent);
207
0
208
0
  mBgParent = aBgParent;
209
0
210
0
  mPromise.ResolveIfExists(true, __func__);
211
0
}
212
213
void
214
HttpChannelParent::OnBackgroundParentDestroyed()
215
0
{
216
0
  LOG(("HttpChannelParent::OnBackgroundParentDestroyed [this=%p]\n", this));
217
0
  MOZ_ASSERT(NS_IsMainThread());
218
0
219
0
  if (!mPromise.IsEmpty()) {
220
0
    MOZ_ASSERT(!mBgParent);
221
0
    mPromise.Reject(NS_ERROR_FAILURE, __func__);
222
0
    return;
223
0
  }
224
0
225
0
  if (!mBgParent) {
226
0
    return;
227
0
  }
228
0
229
0
  // Background channel is closed unexpectly, abort PHttpChannel operation.
230
0
  mBgParent = nullptr;
231
0
  Delete();
232
0
}
233
234
void
235
HttpChannelParent::CleanupBackgroundChannel()
236
0
{
237
0
  LOG(("HttpChannelParent::CleanupBackgroundChannel [this=%p bgParent=%p]\n",
238
0
       this, mBgParent.get()));
239
0
  MOZ_ASSERT(NS_IsMainThread());
240
0
241
0
  if (mBgParent) {
242
0
    RefPtr<HttpBackgroundChannelParent> bgParent = mBgParent.forget();
243
0
    bgParent->OnChannelClosed();
244
0
    return;
245
0
  }
246
0
247
0
  // The nsHttpChannel may have a reference to this parent, release it
248
0
  // to avoid circular references.
249
0
  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel);
250
0
  if (httpChannelImpl) {
251
0
    httpChannelImpl->SetWarningReporter(nullptr);
252
0
  }
253
0
254
0
  if (!mPromise.IsEmpty()) {
255
0
    mRequest.DisconnectIfExists();
256
0
    mPromise.Reject(NS_ERROR_FAILURE, __func__);
257
0
258
0
    if (!mChannel) {
259
0
      return;
260
0
    }
261
0
262
0
    // This HttpChannelParent might still have a reference from
263
0
    // BackgroundChannelRegistrar.
264
0
    nsCOMPtr<nsIBackgroundChannelRegistrar> registrar =
265
0
      do_GetService(NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID);
266
0
    MOZ_ASSERT(registrar);
267
0
268
0
    registrar->DeleteChannel(mChannel->ChannelId());
269
0
270
0
    // If mAsyncOpenBarrier is greater than zero, it means AsyncOpen procedure
271
0
    // is still on going. we need to abort AsyncOpen with failure to destroy
272
0
    // PHttpChannel actor.
273
0
    if (mAsyncOpenBarrier) {
274
0
      TryInvokeAsyncOpen(NS_ERROR_FAILURE);
275
0
    }
276
0
  }
277
0
}
278
279
base::ProcessId
280
HttpChannelParent::OtherPid() const
281
0
{
282
0
  if (mIPCClosed) {
283
0
    return 0;
284
0
  }
285
0
  return Manager()->OtherPid();
286
0
}
287
288
//-----------------------------------------------------------------------------
289
// HttpChannelParent::nsISupports
290
//-----------------------------------------------------------------------------
291
292
NS_IMPL_ADDREF(HttpChannelParent)
293
NS_IMPL_RELEASE(HttpChannelParent)
294
0
NS_INTERFACE_MAP_BEGIN(HttpChannelParent)
295
0
  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
296
0
  NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
297
0
  NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
298
0
  NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
299
0
  NS_INTERFACE_MAP_ENTRY(nsIParentChannel)
300
0
  NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
301
0
  NS_INTERFACE_MAP_ENTRY(nsIParentRedirectingChannel)
302
0
  NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner)
303
0
  NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectReadyCallback)
304
0
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParentRedirectingChannel)
305
0
  NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpChannelParent)
306
0
NS_INTERFACE_MAP_END
307
308
//-----------------------------------------------------------------------------
309
// HttpChannelParent::nsIInterfaceRequestor
310
//-----------------------------------------------------------------------------
311
312
NS_IMETHODIMP
313
HttpChannelParent::GetInterface(const nsIID& aIID, void **result)
314
0
{
315
0
  if (aIID.Equals(NS_GET_IID(nsIAuthPromptProvider)) ||
316
0
      aIID.Equals(NS_GET_IID(nsISecureBrowserUI)) ||
317
0
      aIID.Equals(NS_GET_IID(nsITabParent))) {
318
0
    if (mTabParent) {
319
0
      return mTabParent->QueryInterface(aIID, result);
320
0
    }
321
0
  }
322
0
323
0
  // Only support nsIAuthPromptProvider in Content process
324
0
  if (XRE_IsParentProcess() &&
325
0
      aIID.Equals(NS_GET_IID(nsIAuthPromptProvider))) {
326
0
    *result = nullptr;
327
0
    return NS_OK;
328
0
  }
329
0
330
0
  // Only support nsILoadContext if child channel's callbacks did too
331
0
  if (aIID.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
332
0
    nsCOMPtr<nsILoadContext> copy = mLoadContext;
333
0
    copy.forget(result);
334
0
    return NS_OK;
335
0
  }
336
0
337
0
  if (mTabParent && aIID.Equals(NS_GET_IID(nsIPrompt))) {
338
0
    nsCOMPtr<Element> frameElement = mTabParent->GetOwnerElement();
339
0
    if (frameElement) {
340
0
      nsCOMPtr<nsPIDOMWindowOuter> win =frameElement->OwnerDoc()->GetWindow();
341
0
      NS_ENSURE_TRUE(win, NS_ERROR_UNEXPECTED);
342
0
343
0
      nsresult rv;
344
0
      nsCOMPtr<nsIWindowWatcher> wwatch =
345
0
        do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
346
0
347
0
      if (NS_WARN_IF(!NS_SUCCEEDED(rv))) {
348
0
        return rv;
349
0
      }
350
0
351
0
      nsCOMPtr<nsIPrompt> prompt;
352
0
      rv = wwatch->GetNewPrompter(win, getter_AddRefs(prompt));
353
0
      if (NS_WARN_IF(!NS_SUCCEEDED(rv))) {
354
0
        return rv;
355
0
      }
356
0
357
0
      prompt.forget(result);
358
0
      return NS_OK;
359
0
    }
360
0
  }
361
0
362
0
  return QueryInterface(aIID, result);
363
0
}
364
365
//-----------------------------------------------------------------------------
366
// HttpChannelParent::PHttpChannelParent
367
//-----------------------------------------------------------------------------
368
369
void
370
HttpChannelParent::AsyncOpenFailed(nsresult aRv)
371
0
{
372
0
  MOZ_ASSERT(NS_IsMainThread());
373
0
  MOZ_ASSERT(NS_FAILED(aRv));
374
0
375
0
  // Break the reference cycle among HttpChannelParent,
376
0
  // HttpChannelParentListener, and nsHttpChannel to avoid memory leakage.
377
0
  mChannel = nullptr;
378
0
  mParentListener = nullptr;
379
0
380
0
  if (!mIPCClosed) {
381
0
    Unused << SendFailedAsyncOpen(aRv);
382
0
  }
383
0
}
384
385
void
386
HttpChannelParent::InvokeAsyncOpen(nsresult rv)
387
0
{
388
0
  LOG(("HttpChannelParent::InvokeAsyncOpen [this=%p rv=%" PRIx32 "]\n",
389
0
       this, static_cast<uint32_t>(rv)));
390
0
  MOZ_ASSERT(NS_IsMainThread());
391
0
392
0
  if (NS_FAILED(rv)) {
393
0
    AsyncOpenFailed(rv);
394
0
    return;
395
0
  }
396
0
397
0
  nsCOMPtr<nsILoadInfo> loadInfo;
398
0
  rv = mChannel->GetLoadInfo(getter_AddRefs(loadInfo));
399
0
  if (NS_FAILED(rv)) {
400
0
    AsyncOpenFailed(rv);
401
0
    return;
402
0
  }
403
0
  if (loadInfo && loadInfo->GetEnforceSecurity()) {
404
0
    rv = mChannel->AsyncOpen2(mParentListener);
405
0
  }
406
0
  else {
407
0
    rv = mChannel->AsyncOpen(mParentListener, nullptr);
408
0
  }
409
0
  if (NS_FAILED(rv)) {
410
0
    AsyncOpenFailed(rv);
411
0
  }
412
0
}
413
414
bool
415
HttpChannelParent::DoAsyncOpen(  const URIParams&           aURI,
416
                                 const OptionalURIParams&   aOriginalURI,
417
                                 const OptionalURIParams&   aDocURI,
418
                                 const OptionalURIParams&   aReferrerURI,
419
                                 const uint32_t&            aReferrerPolicy,
420
                                 const OptionalURIParams&   aAPIRedirectToURI,
421
                                 const OptionalURIParams&   aTopWindowURI,
422
                                 const uint32_t&            aLoadFlags,
423
                                 const RequestHeaderTuples& requestHeaders,
424
                                 const nsCString&           requestMethod,
425
                                 const OptionalIPCStream&   uploadStream,
426
                                 const bool&                uploadStreamHasHeaders,
427
                                 const int16_t&             priority,
428
                                 const uint32_t&            classOfService,
429
                                 const uint8_t&             redirectionLimit,
430
                                 const bool&                allowSTS,
431
                                 const uint32_t&            thirdPartyFlags,
432
                                 const bool&                doResumeAt,
433
                                 const uint64_t&            startPos,
434
                                 const nsCString&           entityID,
435
                                 const bool&                chooseApplicationCache,
436
                                 const nsCString&           appCacheClientID,
437
                                 const bool&                allowSpdy,
438
                                 const bool&                allowAltSvc,
439
                                 const bool&                beConservative,
440
                                 const uint32_t&            tlsFlags,
441
                                 const OptionalLoadInfoArgs& aLoadInfoArgs,
442
                                 const OptionalHttpResponseHead& aSynthesizedResponseHead,
443
                                 const nsCString&           aSecurityInfoSerialization,
444
                                 const uint32_t&            aCacheKey,
445
                                 const uint64_t&            aRequestContextID,
446
                                 const OptionalCorsPreflightArgs& aCorsPreflightArgs,
447
                                 const uint32_t&            aInitialRwin,
448
                                 const bool&                aBlockAuthPrompt,
449
                                 const bool&                aSuspendAfterSynthesizeResponse,
450
                                 const bool&                aAllowStaleCacheContent,
451
                                 const nsCString&           aContentTypeHint,
452
                                 const uint32_t&            aCorsMode,
453
                                 const uint32_t&            aRedirectMode,
454
                                 const uint64_t&            aChannelId,
455
                                 const nsString&            aIntegrityMetadata,
456
                                 const uint64_t&            aContentWindowId,
457
                                 const nsCString&           aPreferredAlternativeType,
458
                                 const uint64_t&            aTopLevelOuterContentWindowId,
459
                                 const TimeStamp&           aLaunchServiceWorkerStart,
460
                                 const TimeStamp&           aLaunchServiceWorkerEnd,
461
                                 const TimeStamp&           aDispatchFetchEventStart,
462
                                 const TimeStamp&           aDispatchFetchEventEnd,
463
                                 const TimeStamp&           aHandleFetchEventStart,
464
                                 const TimeStamp&           aHandleFetchEventEnd,
465
                                 const bool&                aForceMainDocumentChannel,
466
                                 const TimeStamp&           aNavigationStartTimeStamp)
467
0
{
468
0
  nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
469
0
  if (!uri) {
470
0
    // URIParams does MOZ_ASSERT if null, but we need to protect opt builds from
471
0
    // null deref here.
472
0
    return false;
473
0
  }
474
0
  nsCOMPtr<nsIURI> originalUri = DeserializeURI(aOriginalURI);
475
0
  nsCOMPtr<nsIURI> docUri = DeserializeURI(aDocURI);
476
0
  nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI);
477
0
  nsCOMPtr<nsIURI> apiRedirectToUri = DeserializeURI(aAPIRedirectToURI);
478
0
  nsCOMPtr<nsIURI> topWindowUri = DeserializeURI(aTopWindowURI);
479
0
480
0
  LOG(("HttpChannelParent RecvAsyncOpen [this=%p uri=%s, gid=%" PRIu64 " topwinid=%" PRIx64 "]\n",
481
0
       this, uri->GetSpecOrDefault().get(), aChannelId, aTopLevelOuterContentWindowId));
482
0
483
0
  nsresult rv;
484
0
485
0
  nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
486
0
  if (NS_FAILED(rv))
487
0
    return SendFailedAsyncOpen(rv);
488
0
489
0
  nsCOMPtr<nsILoadInfo> loadInfo;
490
0
  rv = mozilla::ipc::LoadInfoArgsToLoadInfo(aLoadInfoArgs,
491
0
                                            getter_AddRefs(loadInfo));
492
0
  if (NS_FAILED(rv)) {
493
0
    return SendFailedAsyncOpen(rv);
494
0
  }
495
0
496
0
  if (!loadInfo) {
497
0
    return SendFailedAsyncOpen(NS_ERROR_UNEXPECTED);
498
0
  }
499
0
500
0
  nsCOMPtr<nsIChannel> channel;
501
0
  rv = NS_NewChannelInternal(getter_AddRefs(channel), uri, loadInfo,
502
0
                             nullptr, nullptr, nullptr, aLoadFlags, ios);
503
0
  if (NS_FAILED(rv)) {
504
0
    return SendFailedAsyncOpen(rv);
505
0
  }
506
0
507
0
  RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(channel, &rv);
508
0
  if (NS_FAILED(rv)) {
509
0
    return SendFailedAsyncOpen(rv);
510
0
  }
511
0
512
0
  // Set attributes needed to create a FetchEvent from this channel.
513
0
  httpChannel->SetCorsMode(aCorsMode);
514
0
  httpChannel->SetRedirectMode(aRedirectMode);
515
0
516
0
  // Set the channelId allocated in child to the parent instance
517
0
  httpChannel->SetChannelId(aChannelId);
518
0
  httpChannel->SetTopLevelContentWindowId(aContentWindowId);
519
0
  httpChannel->SetTopLevelOuterContentWindowId(aTopLevelOuterContentWindowId);
520
0
521
0
  httpChannel->SetIntegrityMetadata(aIntegrityMetadata);
522
0
523
0
  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(httpChannel);
524
0
  if (httpChannelImpl) {
525
0
    httpChannelImpl->SetWarningReporter(this);
526
0
  }
527
0
  httpChannel->SetTimingEnabled(true);
528
0
  if (mPBOverride != kPBOverride_Unset) {
529
0
    httpChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
530
0
  }
531
0
532
0
  if (doResumeAt)
533
0
    httpChannel->ResumeAt(startPos, entityID);
534
0
535
0
  if (originalUri)
536
0
    httpChannel->SetOriginalURI(originalUri);
537
0
  if (docUri)
538
0
    httpChannel->SetDocumentURI(docUri);
539
0
  if (referrerUri) {
540
0
    rv = httpChannel->SetReferrerWithPolicyInternal(referrerUri, aReferrerPolicy);
541
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
542
0
  }
543
0
  if (apiRedirectToUri)
544
0
    httpChannel->RedirectTo(apiRedirectToUri);
545
0
  if (topWindowUri) {
546
0
    rv = httpChannel->SetTopWindowURI(topWindowUri);
547
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
548
0
  }
549
0
  if (aLoadFlags != nsIRequest::LOAD_NORMAL)
550
0
    httpChannel->SetLoadFlags(aLoadFlags);
551
0
552
0
  if (aForceMainDocumentChannel) {
553
0
    httpChannel->SetIsMainDocumentChannel(true);
554
0
  }
555
0
556
0
  for (uint32_t i = 0; i < requestHeaders.Length(); i++) {
557
0
    if (requestHeaders[i].mEmpty) {
558
0
      httpChannel->SetEmptyRequestHeader(requestHeaders[i].mHeader);
559
0
    } else {
560
0
      httpChannel->SetRequestHeader(requestHeaders[i].mHeader,
561
0
                                    requestHeaders[i].mValue,
562
0
                                    requestHeaders[i].mMerge);
563
0
    }
564
0
  }
565
0
566
0
  RefPtr<HttpChannelParentListener> parentListener
567
0
    = new HttpChannelParentListener(this);
568
0
569
0
  httpChannel->SetRequestMethod(nsDependentCString(requestMethod.get()));
570
0
571
0
  if (aCorsPreflightArgs.type() == OptionalCorsPreflightArgs::TCorsPreflightArgs) {
572
0
    const CorsPreflightArgs& args = aCorsPreflightArgs.get_CorsPreflightArgs();
573
0
    httpChannel->SetCorsPreflightParameters(args.unsafeHeaders());
574
0
  }
575
0
576
0
  nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(uploadStream);
577
0
  if (stream) {
578
0
    int64_t length;
579
0
    if (InputStreamLengthHelper::GetSyncLength(stream, &length)) {
580
0
      httpChannel->InternalSetUploadStreamLength(length >= 0 ? length : 0);
581
0
    } else {
582
0
      // Wait for the nputStreamLengthHelper::GetAsyncLength callback.
583
0
      ++mAsyncOpenBarrier;
584
0
585
0
      // Let's resolve the size of the stream. The following operation is always
586
0
      // async.
587
0
      RefPtr<HttpChannelParent> self = this;
588
0
      InputStreamLengthHelper::GetAsyncLength(stream,
589
0
        [self, httpChannel](int64_t aLength) {
590
0
          httpChannel->InternalSetUploadStreamLength(aLength >= 0 ? aLength : 0);
591
0
          self->TryInvokeAsyncOpen(NS_OK);
592
0
        });
593
0
    }
594
0
595
0
    httpChannel->InternalSetUploadStream(stream);
596
0
    httpChannel->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
597
0
  }
598
0
599
0
  if (aSynthesizedResponseHead.type() == OptionalHttpResponseHead::TnsHttpResponseHead) {
600
0
    parentListener->SetupInterception(aSynthesizedResponseHead.get_nsHttpResponseHead());
601
0
    mWillSynthesizeResponse = true;
602
0
    httpChannelImpl->SetCouldBeSynthesized();
603
0
604
0
    if (!aSecurityInfoSerialization.IsEmpty()) {
605
0
      nsCOMPtr<nsISupports> secInfo;
606
0
      NS_DeserializeObject(aSecurityInfoSerialization, getter_AddRefs(secInfo));
607
0
      rv = httpChannel->OverrideSecurityInfo(secInfo);
608
0
      MOZ_ASSERT(NS_SUCCEEDED(rv));
609
0
    }
610
0
  }
611
0
612
0
  nsCOMPtr<nsICacheInfoChannel> cacheChannel =
613
0
    do_QueryInterface(static_cast<nsIChannel*>(httpChannel.get()));
614
0
  if (cacheChannel) {
615
0
    cacheChannel->SetCacheKey(aCacheKey);
616
0
    cacheChannel->PreferAlternativeDataType(aPreferredAlternativeType);
617
0
618
0
    cacheChannel->SetAllowStaleCacheContent(aAllowStaleCacheContent);
619
0
620
0
    // This is to mark that the results are going to the content process.
621
0
    if (httpChannelImpl) {
622
0
      httpChannelImpl->SetAltDataForChild(true);
623
0
    }
624
0
  }
625
0
626
0
627
0
  httpChannel->SetContentType(aContentTypeHint);
628
0
629
0
  if (priority != nsISupportsPriority::PRIORITY_NORMAL) {
630
0
    httpChannel->SetPriority(priority);
631
0
  }
632
0
  if (classOfService) {
633
0
    httpChannel->SetClassFlags(classOfService);
634
0
  }
635
0
  httpChannel->SetRedirectionLimit(redirectionLimit);
636
0
  httpChannel->SetAllowSTS(allowSTS);
637
0
  httpChannel->SetThirdPartyFlags(thirdPartyFlags);
638
0
  httpChannel->SetAllowSpdy(allowSpdy);
639
0
  httpChannel->SetAllowAltSvc(allowAltSvc);
640
0
  httpChannel->SetBeConservative(beConservative);
641
0
  httpChannel->SetTlsFlags(tlsFlags);
642
0
  httpChannel->SetInitialRwin(aInitialRwin);
643
0
  httpChannel->SetBlockAuthPrompt(aBlockAuthPrompt);
644
0
645
0
  httpChannel->SetLaunchServiceWorkerStart(aLaunchServiceWorkerStart);
646
0
  httpChannel->SetLaunchServiceWorkerEnd(aLaunchServiceWorkerEnd);
647
0
  httpChannel->SetDispatchFetchEventStart(aDispatchFetchEventStart);
648
0
  httpChannel->SetDispatchFetchEventEnd(aDispatchFetchEventEnd);
649
0
  httpChannel->SetHandleFetchEventStart(aHandleFetchEventStart);
650
0
  httpChannel->SetHandleFetchEventEnd(aHandleFetchEventEnd);
651
0
652
0
  httpChannel->SetNavigationStartTimeStamp(aNavigationStartTimeStamp);
653
0
654
0
  nsCOMPtr<nsIApplicationCacheChannel> appCacheChan =
655
0
    do_QueryObject(httpChannel);
656
0
  nsCOMPtr<nsIApplicationCacheService> appCacheService =
657
0
    do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID);
658
0
659
0
  bool setChooseApplicationCache = chooseApplicationCache;
660
0
  if (appCacheChan && appCacheService) {
661
0
    // We might potentially want to drop this flag (that is TRUE by default)
662
0
    // after we successfully associate the channel with an application cache
663
0
    // reported by the channel child.  Dropping it here may be too early.
664
0
    appCacheChan->SetInheritApplicationCache(false);
665
0
    if (!appCacheClientID.IsEmpty()) {
666
0
      nsCOMPtr<nsIApplicationCache> appCache;
667
0
      rv = appCacheService->GetApplicationCache(appCacheClientID,
668
0
                                                getter_AddRefs(appCache));
669
0
      if (NS_SUCCEEDED(rv)) {
670
0
        appCacheChan->SetApplicationCache(appCache);
671
0
        setChooseApplicationCache = false;
672
0
      }
673
0
    }
674
0
675
0
    if (setChooseApplicationCache) {
676
0
      OriginAttributes attrs;
677
0
      NS_GetOriginAttributes(httpChannel, attrs);
678
0
679
0
      nsCOMPtr<nsIPrincipal> principal =
680
0
        BasePrincipal::CreateCodebasePrincipal(uri, attrs);
681
0
682
0
      bool chooseAppCache = false;
683
0
      // This works because we've already called SetNotificationCallbacks and
684
0
      // done mPBOverride logic by this point.
685
0
      chooseAppCache = NS_ShouldCheckAppCache(principal);
686
0
687
0
      appCacheChan->SetChooseApplicationCache(chooseAppCache);
688
0
    }
689
0
  }
690
0
691
0
  httpChannel->SetRequestContextID(aRequestContextID);
692
0
693
0
  // Store the strong reference of channel and parent listener object until
694
0
  // all the initialization procedure is complete without failure, to remove
695
0
  // cycle reference in fail case and to avoid memory leakage.
696
0
  mChannel = httpChannel.forget();
697
0
  mParentListener = parentListener.forget();
698
0
  mChannel->SetNotificationCallbacks(mParentListener);
699
0
700
0
701
0
  mSuspendAfterSynthesizeResponse = aSuspendAfterSynthesizeResponse;
702
0
703
0
  MOZ_ASSERT(!mBgParent);
704
0
  MOZ_ASSERT(mPromise.IsEmpty());
705
0
  // Wait for HttpBackgrounChannel to continue the async open procedure.
706
0
  ++mAsyncOpenBarrier;
707
0
  RefPtr<GenericPromise> promise = WaitForBgParent();
708
0
  RefPtr<HttpChannelParent> self = this;
709
0
  promise->Then(GetMainThreadSerialEventTarget(), __func__,
710
0
                [self]() {
711
0
                  self->mRequest.Complete();
712
0
                  self->TryInvokeAsyncOpen(NS_OK);
713
0
                },
714
0
                [self](nsresult aStatus) {
715
0
                  self->mRequest.Complete();
716
0
                  self->TryInvokeAsyncOpen(aStatus);
717
0
                })
718
0
         ->Track(mRequest);
719
0
720
0
  return true;
721
0
}
722
723
already_AddRefed<GenericPromise>
724
HttpChannelParent::WaitForBgParent()
725
0
{
726
0
  LOG(("HttpChannelParent::WaitForBgParent [this=%p]\n", this));
727
0
  MOZ_ASSERT(!mBgParent);
728
0
  MOZ_ASSERT(mChannel);
729
0
730
0
731
0
  nsCOMPtr<nsIBackgroundChannelRegistrar> registrar =
732
0
    do_GetService(NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID);
733
0
  MOZ_ASSERT(registrar);
734
0
  registrar->LinkHttpChannel(mChannel->ChannelId(), this);
735
0
736
0
  if (mBgParent) {
737
0
    RefPtr<GenericPromise> promise = mPromise.Ensure(__func__);
738
0
    // resolve promise immediatedly if bg channel is ready.
739
0
    mPromise.Resolve(true, __func__);
740
0
    return promise.forget();
741
0
  }
742
0
743
0
  return mPromise.Ensure(__func__);;
744
0
}
745
746
bool
747
HttpChannelParent::ConnectChannel(const uint32_t& registrarId, const bool& shouldIntercept)
748
0
{
749
0
  nsresult rv;
750
0
751
0
  LOG(("HttpChannelParent::ConnectChannel: Looking for a registered channel "
752
0
       "[this=%p, id=%" PRIu32 "]\n", this, registrarId));
753
0
  nsCOMPtr<nsIChannel> channel;
754
0
  rv = NS_LinkRedirectChannels(registrarId, this, getter_AddRefs(channel));
755
0
  if (NS_FAILED(rv)) {
756
0
    NS_ERROR("Could not find the http channel to connect its IPC parent");
757
0
    // This makes the channel delete itself safely.  It's the only thing
758
0
    // we can do now, since this parent channel cannot be used and there is
759
0
    // no other way to tell the child side there were something wrong.
760
0
    Delete();
761
0
    return true;
762
0
  }
763
0
764
0
  LOG(("  found channel %p, rv=%08" PRIx32, channel.get(), static_cast<uint32_t>(rv)));
765
0
  mChannel = do_QueryObject(channel);
766
0
  if (!mChannel) {
767
0
    LOG(("  but it's not HttpBaseChannel"));
768
0
    Delete();
769
0
    return true;
770
0
  }
771
0
772
0
  LOG(("  and it is HttpBaseChannel %p", mChannel.get()));
773
0
774
0
  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel);
775
0
  if (httpChannelImpl) {
776
0
    httpChannelImpl->SetWarningReporter(this);
777
0
  }
778
0
779
0
  nsCOMPtr<nsINetworkInterceptController> controller;
780
0
  NS_QueryNotificationCallbacks(channel, controller);
781
0
  RefPtr<HttpChannelParentListener> parentListener = do_QueryObject(controller);
782
0
  MOZ_ASSERT(parentListener);
783
0
  parentListener->SetupInterceptionAfterRedirect(shouldIntercept);
784
0
785
0
  if (mPBOverride != kPBOverride_Unset) {
786
0
    // redirected-to channel may not support PB
787
0
    nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryObject(mChannel);
788
0
    if (pbChannel) {
789
0
      pbChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
790
0
    }
791
0
  }
792
0
793
0
  MOZ_ASSERT(!mBgParent);
794
0
  MOZ_ASSERT(mPromise.IsEmpty());
795
0
  // Waiting for background channel
796
0
  RefPtr<GenericPromise> promise = WaitForBgParent();
797
0
  RefPtr<HttpChannelParent> self = this;
798
0
  promise->Then(GetMainThreadSerialEventTarget(), __func__,
799
0
                [self]() {
800
0
                  self->mRequest.Complete();
801
0
                },
802
0
                [self](const nsresult& aResult) {
803
0
                  NS_ERROR("failed to establish the background channel");
804
0
                  self->mRequest.Complete();
805
0
                })
806
0
         ->Track(mRequest);
807
0
  return true;
808
0
}
809
810
mozilla::ipc::IPCResult
811
HttpChannelParent::RecvSetPriority(const int16_t& priority)
812
0
{
813
0
  LOG(("HttpChannelParent::RecvSetPriority [this=%p, priority=%d]\n",
814
0
       this, priority));
815
0
816
0
  if (mChannel) {
817
0
    mChannel->SetPriority(priority);
818
0
  }
819
0
820
0
  nsCOMPtr<nsISupportsPriority> priorityRedirectChannel =
821
0
      do_QueryInterface(mRedirectChannel);
822
0
  if (priorityRedirectChannel)
823
0
    priorityRedirectChannel->SetPriority(priority);
824
0
825
0
  return IPC_OK();
826
0
}
827
828
mozilla::ipc::IPCResult
829
HttpChannelParent::RecvSetClassOfService(const uint32_t& cos)
830
0
{
831
0
  if (mChannel) {
832
0
    mChannel->SetClassFlags(cos);
833
0
  }
834
0
  return IPC_OK();
835
0
}
836
837
mozilla::ipc::IPCResult
838
HttpChannelParent::RecvSuspend()
839
0
{
840
0
  LOG(("HttpChannelParent::RecvSuspend [this=%p]\n", this));
841
0
842
0
  if (mChannel) {
843
0
    mChannel->Suspend();
844
0
  }
845
0
  return IPC_OK();
846
0
}
847
848
mozilla::ipc::IPCResult
849
HttpChannelParent::RecvResume()
850
0
{
851
0
  LOG(("HttpChannelParent::RecvResume [this=%p]\n", this));
852
0
853
0
  if (mChannel) {
854
0
    mChannel->Resume();
855
0
  }
856
0
  return IPC_OK();
857
0
}
858
859
mozilla::ipc::IPCResult
860
HttpChannelParent::RecvCancel(const nsresult& status)
861
0
{
862
0
  LOG(("HttpChannelParent::RecvCancel [this=%p]\n", this));
863
0
864
0
  // May receive cancel before channel has been constructed!
865
0
  if (mChannel) {
866
0
    mChannel->Cancel(status);
867
0
  }
868
0
  return IPC_OK();
869
0
}
870
871
872
mozilla::ipc::IPCResult
873
HttpChannelParent::RecvSetCacheTokenCachedCharset(const nsCString& charset)
874
0
{
875
0
  if (mCacheEntry)
876
0
    mCacheEntry->SetMetaDataElement("charset", charset.get());
877
0
  return IPC_OK();
878
0
}
879
880
mozilla::ipc::IPCResult
881
HttpChannelParent::RecvRedirect2Verify(const nsresult& aResult,
882
                                       const RequestHeaderTuples& changedHeaders,
883
                                       const ChildLoadInfoForwarderArgs& aLoadInfoForwarder,
884
                                       const uint32_t& loadFlags,
885
                                       const uint32_t& referrerPolicy,
886
                                       const OptionalURIParams& aReferrerURI,
887
                                       const OptionalURIParams& aAPIRedirectURI,
888
                                       const OptionalCorsPreflightArgs& aCorsPreflightArgs,
889
                                       const bool& aChooseAppcache)
890
0
{
891
0
  LOG(("HttpChannelParent::RecvRedirect2Verify [this=%p result=%" PRIx32 "]\n",
892
0
       this, static_cast<uint32_t>(aResult)));
893
0
894
0
  // Result from the child.  If something fails here, we might overwrite a
895
0
  // success with a further failure.
896
0
  nsresult result = aResult;
897
0
898
0
  // Local results.
899
0
  nsresult rv;
900
0
901
0
  if (NS_SUCCEEDED(result)) {
902
0
    nsCOMPtr<nsIHttpChannel> newHttpChannel =
903
0
        do_QueryInterface(mRedirectChannel);
904
0
905
0
    if (newHttpChannel) {
906
0
      nsCOMPtr<nsIURI> apiRedirectUri = DeserializeURI(aAPIRedirectURI);
907
0
908
0
      if (apiRedirectUri) {
909
0
        rv = newHttpChannel->RedirectTo(apiRedirectUri);
910
0
        MOZ_ASSERT(NS_SUCCEEDED(rv));
911
0
      }
912
0
913
0
      for (uint32_t i = 0; i < changedHeaders.Length(); i++) {
914
0
        if (changedHeaders[i].mEmpty) {
915
0
          rv = newHttpChannel->SetEmptyRequestHeader(changedHeaders[i].mHeader);
916
0
        } else {
917
0
          rv = newHttpChannel->SetRequestHeader(changedHeaders[i].mHeader,
918
0
                                                changedHeaders[i].mValue,
919
0
                                                changedHeaders[i].mMerge);
920
0
        }
921
0
        MOZ_ASSERT(NS_SUCCEEDED(rv));
922
0
      }
923
0
924
0
      // A successfully redirected channel must have the LOAD_REPLACE flag.
925
0
      MOZ_ASSERT(loadFlags & nsIChannel::LOAD_REPLACE);
926
0
      if (loadFlags & nsIChannel::LOAD_REPLACE) {
927
0
        newHttpChannel->SetLoadFlags(loadFlags);
928
0
      }
929
0
930
0
      if (aCorsPreflightArgs.type() == OptionalCorsPreflightArgs::TCorsPreflightArgs) {
931
0
        nsCOMPtr<nsIHttpChannelInternal> newInternalChannel =
932
0
          do_QueryInterface(newHttpChannel);
933
0
        MOZ_RELEASE_ASSERT(newInternalChannel);
934
0
        const CorsPreflightArgs& args = aCorsPreflightArgs.get_CorsPreflightArgs();
935
0
        newInternalChannel->SetCorsPreflightParameters(args.unsafeHeaders());
936
0
      }
937
0
938
0
      nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI);
939
0
      rv = newHttpChannel->SetReferrerWithPolicy(referrerUri, referrerPolicy);
940
0
      MOZ_ASSERT(NS_SUCCEEDED(rv));
941
0
942
0
      nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
943
0
        do_QueryInterface(newHttpChannel);
944
0
      if (appCacheChannel) {
945
0
        appCacheChannel->SetChooseApplicationCache(aChooseAppcache);
946
0
      }
947
0
948
0
      nsCOMPtr<nsILoadInfo> newLoadInfo;
949
0
      Unused << newHttpChannel->GetLoadInfo(getter_AddRefs(newLoadInfo));
950
0
      rv = MergeChildLoadInfoForwarder(aLoadInfoForwarder, newLoadInfo);
951
0
      if (NS_FAILED(rv) && NS_SUCCEEDED(result)) {
952
0
        result = rv;
953
0
      }
954
0
    }
955
0
  }
956
0
957
0
  // Continue the verification procedure if child has veto the redirection.
958
0
  if (NS_FAILED(result)) {
959
0
    ContinueRedirect2Verify(result);
960
0
    return IPC_OK();
961
0
  }
962
0
963
0
  // Wait for background channel ready on target channel
964
0
  nsCOMPtr<nsIRedirectChannelRegistrar> redirectReg =
965
0
    RedirectChannelRegistrar::GetOrCreate();
966
0
  MOZ_ASSERT(redirectReg);
967
0
968
0
  nsCOMPtr<nsIParentChannel> redirectParentChannel;
969
0
  rv = redirectReg->GetParentChannel(mRedirectRegistrarId,
970
0
                                     getter_AddRefs(redirectParentChannel));
971
0
  MOZ_ASSERT(redirectParentChannel);
972
0
  if (!redirectParentChannel) {
973
0
    ContinueRedirect2Verify(rv);
974
0
    return IPC_OK();
975
0
  }
976
0
977
0
  nsCOMPtr<nsIParentRedirectingChannel> redirectedParent =
978
0
    do_QueryInterface(redirectParentChannel);
979
0
  if (!redirectedParent) {
980
0
    // Continue verification procedure if redirecting to non-Http protocol
981
0
    ContinueRedirect2Verify(result);
982
0
    return IPC_OK();
983
0
  }
984
0
985
0
  // Ask redirected channel if verification can proceed.
986
0
  // ContinueRedirect2Verify will be invoked when redirected channel is ready.
987
0
  redirectedParent->ContinueVerification(this);
988
0
989
0
  return IPC_OK();
990
0
}
991
992
// from nsIParentRedirectingChannel
993
NS_IMETHODIMP
994
HttpChannelParent::ContinueVerification(nsIAsyncVerifyRedirectReadyCallback* aCallback)
995
0
{
996
0
  LOG(("HttpChannelParent::ContinueVerification [this=%p callback=%p]\n",
997
0
       this, aCallback));
998
0
999
0
  MOZ_ASSERT(NS_IsMainThread());
1000
0
  MOZ_ASSERT(aCallback);
1001
0
1002
0
  // Continue the verification procedure if background channel is ready.
1003
0
  if (mBgParent) {
1004
0
    aCallback->ReadyToVerify(NS_OK);
1005
0
    return NS_OK;
1006
0
  }
1007
0
1008
0
  // ConnectChannel must be received before Redirect2Verify.
1009
0
  MOZ_ASSERT(!mPromise.IsEmpty());
1010
0
1011
0
  // Otherwise, wait for the background channel.
1012
0
  RefPtr<GenericPromise> promise = WaitForBgParent();
1013
0
  nsCOMPtr<nsIAsyncVerifyRedirectReadyCallback> callback = aCallback;
1014
0
  promise->Then(GetMainThreadSerialEventTarget(), __func__,
1015
0
                [callback]() {
1016
0
                  callback->ReadyToVerify(NS_OK);
1017
0
                },
1018
0
                [callback](const nsresult& aResult) {
1019
0
                  NS_ERROR("failed to establish the background channel");
1020
0
                  callback->ReadyToVerify(aResult);
1021
0
                });
1022
0
  return NS_OK;
1023
0
}
1024
1025
void
1026
HttpChannelParent::ContinueRedirect2Verify(const nsresult& aResult)
1027
0
{
1028
0
  LOG(("HttpChannelParent::ContinueRedirect2Verify [this=%p result=%" PRIx32 "]\n",
1029
0
       this, static_cast<uint32_t>(aResult)));
1030
0
1031
0
  if (!mRedirectCallback) {
1032
0
    // This should according the logic never happen, log the situation.
1033
0
    if (mReceivedRedirect2Verify)
1034
0
      LOG(("RecvRedirect2Verify[%p]: Duplicate fire", this));
1035
0
    if (mSentRedirect1BeginFailed)
1036
0
      LOG(("RecvRedirect2Verify[%p]: Send to child failed", this));
1037
0
    if ((mRedirectRegistrarId > 0) && NS_FAILED(aResult))
1038
0
      LOG(("RecvRedirect2Verify[%p]: Redirect failed", this));
1039
0
    if ((mRedirectRegistrarId > 0) && NS_SUCCEEDED(aResult))
1040
0
      LOG(("RecvRedirect2Verify[%p]: Redirect succeeded", this));
1041
0
    if (!mRedirectChannel)
1042
0
      LOG(("RecvRedirect2Verify[%p]: Missing redirect channel", this));
1043
0
1044
0
    NS_ERROR("Unexpcted call to HttpChannelParent::RecvRedirect2Verify, "
1045
0
             "mRedirectCallback null");
1046
0
  }
1047
0
1048
0
  mReceivedRedirect2Verify = true;
1049
0
1050
0
  if (mRedirectCallback) {
1051
0
    LOG(("HttpChannelParent::ContinueRedirect2Verify call OnRedirectVerifyCallback"
1052
0
         " [this=%p result=%" PRIx32 ", mRedirectCallback=%p]\n",
1053
0
         this, static_cast<uint32_t>(aResult), mRedirectCallback.get()));
1054
0
    mRedirectCallback->OnRedirectVerifyCallback(aResult);
1055
0
    mRedirectCallback = nullptr;
1056
0
  }
1057
0
}
1058
1059
mozilla::ipc::IPCResult
1060
HttpChannelParent::RecvDocumentChannelCleanup(const bool& clearCacheEntry)
1061
0
{
1062
0
  CleanupBackgroundChannel(); // Background channel can be closed.
1063
0
  mChannel = nullptr;          // Reclaim some memory sooner.
1064
0
  if (clearCacheEntry) {
1065
0
    mCacheEntry = nullptr;  // Else we'll block other channels reading same URI
1066
0
  }
1067
0
  return IPC_OK();
1068
0
}
1069
1070
mozilla::ipc::IPCResult
1071
HttpChannelParent::RecvMarkOfflineCacheEntryAsForeign()
1072
0
{
1073
0
  if (mOfflineForeignMarker) {
1074
0
    mOfflineForeignMarker->MarkAsForeign();
1075
0
    mOfflineForeignMarker = nullptr;
1076
0
  }
1077
0
1078
0
  return IPC_OK();
1079
0
}
1080
1081
class DivertDataAvailableEvent : public MainThreadChannelEvent
1082
{
1083
public:
1084
  DivertDataAvailableEvent(HttpChannelParent* aParent,
1085
                           const nsCString& data,
1086
                           const uint64_t& offset,
1087
                           const uint32_t& count)
1088
  : mParent(aParent)
1089
  , mData(data)
1090
  , mOffset(offset)
1091
  , mCount(count)
1092
0
  {
1093
0
  }
1094
1095
  void Run() override
1096
0
  {
1097
0
    mParent->DivertOnDataAvailable(mData, mOffset, mCount);
1098
0
  }
1099
1100
private:
1101
  HttpChannelParent* mParent;
1102
  nsCString mData;
1103
  uint64_t mOffset;
1104
  uint32_t mCount;
1105
};
1106
1107
mozilla::ipc::IPCResult
1108
HttpChannelParent::RecvDivertOnDataAvailable(const nsCString& data,
1109
                                             const uint64_t& offset,
1110
                                             const uint32_t& count)
1111
0
{
1112
0
  LOG(("HttpChannelParent::RecvDivertOnDataAvailable [this=%p]\n", this));
1113
0
1114
0
  MOZ_ASSERT(mParentListener);
1115
0
  if (NS_WARN_IF(!mDivertingFromChild)) {
1116
0
    MOZ_ASSERT(mDivertingFromChild,
1117
0
               "Cannot RecvDivertOnDataAvailable if diverting is not set!");
1118
0
    FailDiversion(NS_ERROR_UNEXPECTED);
1119
0
    return IPC_FAIL_NO_REASON(this);
1120
0
  }
1121
0
1122
0
  // Drop OnDataAvailables if the parent was canceled already.
1123
0
  if (NS_FAILED(mStatus)) {
1124
0
    return IPC_OK();
1125
0
  }
1126
0
1127
0
  mEventQ->RunOrEnqueue(new DivertDataAvailableEvent(this, data, offset,
1128
0
                                                     count));
1129
0
  return IPC_OK();
1130
0
}
1131
1132
void
1133
HttpChannelParent::DivertOnDataAvailable(const nsCString& data,
1134
                                         const uint64_t& offset,
1135
                                         const uint32_t& count)
1136
0
{
1137
0
  LOG(("HttpChannelParent::DivertOnDataAvailable [this=%p]\n", this));
1138
0
1139
0
  MOZ_ASSERT(mParentListener);
1140
0
  if (NS_WARN_IF(!mDivertingFromChild)) {
1141
0
    MOZ_ASSERT(mDivertingFromChild,
1142
0
               "Cannot DivertOnDataAvailable if diverting is not set!");
1143
0
    FailDiversion(NS_ERROR_UNEXPECTED);
1144
0
    return;
1145
0
  }
1146
0
1147
0
  // Drop OnDataAvailables if the parent was canceled already.
1148
0
  if (NS_FAILED(mStatus)) {
1149
0
    return;
1150
0
  }
1151
0
1152
0
  nsCOMPtr<nsIInputStream> stringStream;
1153
0
  nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(),
1154
0
                                      count, NS_ASSIGNMENT_DEPEND);
1155
0
  if (NS_FAILED(rv)) {
1156
0
    if (mChannel) {
1157
0
      mChannel->Cancel(rv);
1158
0
    }
1159
0
    mStatus = rv;
1160
0
    return;
1161
0
  }
1162
0
1163
0
  AutoEventEnqueuer ensureSerialDispatch(mEventQ);
1164
0
1165
0
  rv = mParentListener->OnDataAvailable(mChannel, nullptr, stringStream,
1166
0
                                        offset, count);
1167
0
  stringStream->Close();
1168
0
  if (NS_FAILED(rv)) {
1169
0
    if (mChannel) {
1170
0
      mChannel->Cancel(rv);
1171
0
    }
1172
0
    mStatus = rv;
1173
0
  }
1174
0
}
1175
1176
class DivertStopRequestEvent : public MainThreadChannelEvent
1177
{
1178
public:
1179
  DivertStopRequestEvent(HttpChannelParent* aParent,
1180
                         const nsresult& statusCode)
1181
  : mParent(aParent)
1182
  , mStatusCode(statusCode)
1183
0
  {
1184
0
  }
1185
1186
  void Run() override
1187
0
  {
1188
0
    mParent->DivertOnStopRequest(mStatusCode);
1189
0
  }
1190
1191
private:
1192
  HttpChannelParent* mParent;
1193
  nsresult mStatusCode;
1194
};
1195
1196
mozilla::ipc::IPCResult
1197
HttpChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode)
1198
0
{
1199
0
  LOG(("HttpChannelParent::RecvDivertOnStopRequest [this=%p]\n", this));
1200
0
1201
0
  MOZ_ASSERT(mParentListener);
1202
0
  if (NS_WARN_IF(!mDivertingFromChild)) {
1203
0
    MOZ_ASSERT(mDivertingFromChild,
1204
0
               "Cannot RecvDivertOnStopRequest if diverting is not set!");
1205
0
    FailDiversion(NS_ERROR_UNEXPECTED);
1206
0
    return IPC_FAIL_NO_REASON(this);
1207
0
  }
1208
0
1209
0
  mEventQ->RunOrEnqueue(new DivertStopRequestEvent(this, statusCode));
1210
0
  return IPC_OK();
1211
0
}
1212
1213
void
1214
HttpChannelParent::DivertOnStopRequest(const nsresult& statusCode)
1215
0
{
1216
0
  LOG(("HttpChannelParent::DivertOnStopRequest [this=%p]\n", this));
1217
0
1218
0
  MOZ_ASSERT(mParentListener);
1219
0
  if (NS_WARN_IF(!mDivertingFromChild)) {
1220
0
    MOZ_ASSERT(mDivertingFromChild,
1221
0
               "Cannot DivertOnStopRequest if diverting is not set!");
1222
0
    FailDiversion(NS_ERROR_UNEXPECTED);
1223
0
    return;
1224
0
  }
1225
0
1226
0
  // Honor the channel's status even if the underlying transaction completed.
1227
0
  nsresult status = NS_FAILED(mStatus) ? mStatus : statusCode;
1228
0
1229
0
  // Reset fake pending status in case OnStopRequest has already been called.
1230
0
  if (mChannel) {
1231
0
    mChannel->ForcePending(false);
1232
0
  }
1233
0
1234
0
  AutoEventEnqueuer ensureSerialDispatch(mEventQ);
1235
0
  mParentListener->OnStopRequest(mChannel, nullptr, status);
1236
0
}
1237
1238
class DivertCompleteEvent : public MainThreadChannelEvent
1239
{
1240
public:
1241
  explicit DivertCompleteEvent(HttpChannelParent* aParent)
1242
  : mParent(aParent)
1243
0
  {
1244
0
  }
1245
1246
  void Run() override
1247
0
  {
1248
0
    mParent->DivertComplete();
1249
0
  }
1250
1251
private:
1252
  HttpChannelParent* mParent;
1253
};
1254
1255
mozilla::ipc::IPCResult
1256
HttpChannelParent::RecvDivertComplete()
1257
0
{
1258
0
  LOG(("HttpChannelParent::RecvDivertComplete [this=%p]\n", this));
1259
0
1260
0
  MOZ_ASSERT(mParentListener);
1261
0
  if (NS_WARN_IF(!mDivertingFromChild)) {
1262
0
    MOZ_ASSERT(mDivertingFromChild,
1263
0
               "Cannot RecvDivertComplete if diverting is not set!");
1264
0
    FailDiversion(NS_ERROR_UNEXPECTED);
1265
0
    return IPC_FAIL_NO_REASON(this);
1266
0
  }
1267
0
1268
0
  mEventQ->RunOrEnqueue(new DivertCompleteEvent(this));
1269
0
  return IPC_OK();
1270
0
}
1271
1272
void
1273
HttpChannelParent::DivertComplete()
1274
0
{
1275
0
  LOG(("HttpChannelParent::DivertComplete [this=%p]\n", this));
1276
0
1277
0
  MOZ_ASSERT(mParentListener);
1278
0
  if (NS_WARN_IF(!mDivertingFromChild)) {
1279
0
    MOZ_ASSERT(mDivertingFromChild,
1280
0
               "Cannot DivertComplete if diverting is not set!");
1281
0
    FailDiversion(NS_ERROR_UNEXPECTED);
1282
0
    return;
1283
0
  }
1284
0
1285
0
  nsresult rv = ResumeForDiversion();
1286
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
1287
0
    FailDiversion(NS_ERROR_UNEXPECTED);
1288
0
    return;
1289
0
  }
1290
0
1291
0
  mParentListener = nullptr;
1292
0
}
1293
1294
void
1295
HttpChannelParent::MaybeFlushPendingDiversion()
1296
0
{
1297
0
  if (!mPendingDiversion) {
1298
0
    return;
1299
0
  }
1300
0
1301
0
  mPendingDiversion = false;
1302
0
1303
0
  nsresult rv = SuspendForDiversion();
1304
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
1305
0
    return;
1306
0
  }
1307
0
1308
0
  if (mDivertListener) {
1309
0
    DivertTo(mDivertListener);
1310
0
  }
1311
0
1312
0
}
1313
1314
static void
1315
FinishCrossProcessRedirect(nsHttpChannel *channel, nsresult status)
1316
0
{
1317
0
  if (NS_SUCCEEDED(status)) {
1318
0
    nsCOMPtr<nsINetworkInterceptController> controller;
1319
0
    NS_QueryNotificationCallbacks(channel, controller);
1320
0
    RefPtr<HttpChannelParentListener> parentListener = do_QueryObject(controller);
1321
0
    MOZ_ASSERT(parentListener);
1322
0
1323
0
    // This updates HttpChannelParentListener to point to this parent and at
1324
0
    // the same time cancels the old channel.
1325
0
    parentListener->OnRedirectResult(status == NS_OK);
1326
0
  }
1327
0
1328
0
  channel->OnRedirectVerifyCallback(status);
1329
0
}
1330
1331
mozilla::ipc::IPCResult
1332
HttpChannelParent::RecvCrossProcessRedirectDone(const nsresult& aResult)
1333
0
{
1334
0
  RefPtr<nsHttpChannel> chan = do_QueryObject(mChannel);
1335
0
  if (!mBgParent) {
1336
0
    RefPtr<GenericPromise> promise = WaitForBgParent();
1337
0
    RefPtr<HttpChannelParent> self = this;
1338
0
    promise->Then(GetMainThreadSerialEventTarget(), __func__,
1339
0
                  [self, chan, aResult]() {
1340
0
                    FinishCrossProcessRedirect(chan, aResult);
1341
0
                  },
1342
0
                  [self, chan](const nsresult& aRejectionRv) {
1343
0
                    MOZ_ASSERT(NS_FAILED(aRejectionRv), "This should be an error code");
1344
0
                    FinishCrossProcessRedirect(chan, aRejectionRv);
1345
0
                  });
1346
0
  } else {
1347
0
    FinishCrossProcessRedirect(chan, aResult);
1348
0
  }
1349
0
1350
0
  return IPC_OK();
1351
0
}
1352
1353
void
1354
HttpChannelParent::ResponseSynthesized()
1355
0
{
1356
0
  // Suspend now even though the FinishSynthesizeResponse runnable has
1357
0
  // not executed.  We want to suspend after we get far enough to trigger
1358
0
  // the synthesis, but not actually allow the nsHttpChannel to trigger
1359
0
  // any OnStartRequests().
1360
0
  if (mSuspendAfterSynthesizeResponse) {
1361
0
    mChannel->Suspend();
1362
0
  }
1363
0
1364
0
  mWillSynthesizeResponse = false;
1365
0
1366
0
  MaybeFlushPendingDiversion();
1367
0
}
1368
1369
mozilla::ipc::IPCResult
1370
HttpChannelParent::RecvRemoveCorsPreflightCacheEntry(const URIParams& uri,
1371
  const mozilla::ipc::PrincipalInfo& requestingPrincipal)
1372
0
{
1373
0
  nsCOMPtr<nsIURI> deserializedURI = DeserializeURI(uri);
1374
0
  if (!deserializedURI) {
1375
0
    return IPC_FAIL_NO_REASON(this);
1376
0
  }
1377
0
  nsCOMPtr<nsIPrincipal> principal =
1378
0
    PrincipalInfoToPrincipal(requestingPrincipal);
1379
0
  if (!principal) {
1380
0
    return IPC_FAIL_NO_REASON(this);
1381
0
  }
1382
0
  nsCORSListenerProxy::RemoveFromCorsPreflightCache(deserializedURI,
1383
0
                                                    principal);
1384
0
  return IPC_OK();
1385
0
}
1386
1387
//-----------------------------------------------------------------------------
1388
// HttpChannelParent::nsIRequestObserver
1389
//-----------------------------------------------------------------------------
1390
1391
static void
1392
GetTimingAttributes(HttpBaseChannel* aChannel, ResourceTimingStruct& aTiming)
1393
0
{
1394
0
  aChannel->GetDomainLookupStart(&aTiming.domainLookupStart);
1395
0
  aChannel->GetDomainLookupEnd(&aTiming.domainLookupEnd);
1396
0
  aChannel->GetConnectStart(&aTiming.connectStart);
1397
0
  aChannel->GetTcpConnectEnd(&aTiming.tcpConnectEnd);
1398
0
  aChannel->GetSecureConnectionStart(&aTiming.secureConnectionStart);
1399
0
  aChannel->GetConnectEnd(&aTiming.connectEnd);
1400
0
  aChannel->GetRequestStart(&aTiming.requestStart);
1401
0
  aChannel->GetResponseStart(&aTiming.responseStart);
1402
0
  aChannel->GetResponseEnd(&aTiming.responseEnd);
1403
0
  aChannel->GetAsyncOpen(&aTiming.fetchStart);
1404
0
  aChannel->GetRedirectStart(&aTiming.redirectStart);
1405
0
  aChannel->GetRedirectEnd(&aTiming.redirectEnd);
1406
0
  aChannel->GetTransferSize(&aTiming.transferSize);
1407
0
  aChannel->GetEncodedBodySize(&aTiming.encodedBodySize);
1408
0
  // decodedBodySize can be computed in the child process so it doesn't need
1409
0
  // to be passed down.
1410
0
  aChannel->GetProtocolVersion(aTiming.protocolVersion);
1411
0
1412
0
  aChannel->GetCacheReadStart(&aTiming.cacheReadStart);
1413
0
  aChannel->GetCacheReadEnd(&aTiming.cacheReadEnd);
1414
0
}
1415
1416
NS_IMETHODIMP
1417
HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
1418
0
{
1419
0
  nsresult rv;
1420
0
1421
0
  LOG(("HttpChannelParent::OnStartRequest [this=%p, aRequest=%p]\n",
1422
0
       this, aRequest));
1423
0
  MOZ_ASSERT(NS_IsMainThread());
1424
0
1425
0
  MOZ_RELEASE_ASSERT(!mDivertingFromChild,
1426
0
    "Cannot call OnStartRequest if diverting is set!");
1427
0
1428
0
  RefPtr<HttpBaseChannel> chan = do_QueryObject(aRequest);
1429
0
  if (!chan) {
1430
0
    LOG(("  aRequest is not HttpBaseChannel"));
1431
0
    NS_ERROR("Expecting only HttpBaseChannel as aRequest in HttpChannelParent::OnStartRequest");
1432
0
    return NS_ERROR_UNEXPECTED;
1433
0
  }
1434
0
1435
0
  MOZ_ASSERT(mChannel == chan,
1436
0
             "HttpChannelParent getting OnStartRequest from a different HttpBaseChannel instance");
1437
0
1438
0
  // Send down any permissions which are relevant to this URL if we are
1439
0
  // performing a document load. We can't do that if mIPCClosed is set.
1440
0
  if (!mIPCClosed) {
1441
0
    PContentParent* pcp = Manager()->Manager();
1442
0
    MOZ_ASSERT(pcp, "We should have a manager if our IPC isn't closed");
1443
0
    DebugOnly<nsresult> rv =
1444
0
      static_cast<ContentParent*>(pcp)->AboutToLoadHttpFtpWyciwygDocumentForChild(chan);
1445
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
1446
0
  }
1447
0
1448
0
  bool isFromCache = false;
1449
0
  uint64_t cacheEntryId = 0;
1450
0
  int32_t fetchCount = 0;
1451
0
  uint32_t expirationTime = nsICacheEntry::NO_EXPIRATION_TIME;
1452
0
  nsCString cachedCharset;
1453
0
1454
0
  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(chan);
1455
0
1456
0
  if (httpChannelImpl) {
1457
0
    httpChannelImpl->IsFromCache(&isFromCache);
1458
0
    httpChannelImpl->GetCacheEntryId(&cacheEntryId);
1459
0
    httpChannelImpl->GetCacheTokenFetchCount(&fetchCount);
1460
0
    httpChannelImpl->GetCacheTokenExpirationTime(&expirationTime);
1461
0
    httpChannelImpl->GetCacheTokenCachedCharset(cachedCharset);
1462
0
  }
1463
0
1464
0
  bool loadedFromApplicationCache = false;
1465
0
1466
0
  if (httpChannelImpl) {
1467
0
    httpChannelImpl->GetLoadedFromApplicationCache(&loadedFromApplicationCache);
1468
0
    if (loadedFromApplicationCache) {
1469
0
      mOfflineForeignMarker = httpChannelImpl->GetOfflineCacheEntryAsForeignMarker();
1470
0
      nsCOMPtr<nsIApplicationCache> appCache;
1471
0
      httpChannelImpl->GetApplicationCache(getter_AddRefs(appCache));
1472
0
      nsCString appCacheGroupId;
1473
0
      nsCString appCacheClientId;
1474
0
      appCache->GetGroupID(appCacheGroupId);
1475
0
      appCache->GetClientID(appCacheClientId);
1476
0
      if (mIPCClosed ||
1477
0
          !SendAssociateApplicationCache(appCacheGroupId, appCacheClientId))
1478
0
      {
1479
0
        return NS_ERROR_UNEXPECTED;
1480
0
      }
1481
0
    }
1482
0
  }
1483
0
1484
0
  // Propagate whether or not conversion should occur from the parent-side
1485
0
  // channel to the child-side channel.  Then disable the parent-side
1486
0
  // conversion so that it only occurs in the child.
1487
0
  bool applyConversion = true;
1488
0
  Unused << chan->GetApplyConversion(&applyConversion);
1489
0
  chan->SetApplyConversion(false);
1490
0
1491
0
  nsresult channelStatus = NS_OK;
1492
0
  chan->GetStatus(&channelStatus);
1493
0
1494
0
  // Keep the cache entry for future use in RecvSetCacheTokenCachedCharset().
1495
0
  // It could be already released by nsHttpChannel at that time.
1496
0
  nsCOMPtr<nsISupports> cacheEntry;
1497
0
  uint32_t cacheKey = 0;
1498
0
  nsAutoCString altDataType;
1499
0
1500
0
  if (httpChannelImpl) {
1501
0
    httpChannelImpl->GetCacheToken(getter_AddRefs(cacheEntry));
1502
0
    mCacheEntry = do_QueryInterface(cacheEntry);
1503
0
1504
0
    httpChannelImpl->GetCacheKey(&cacheKey);
1505
0
1506
0
    httpChannelImpl->GetAlternativeDataType(altDataType);
1507
0
  }
1508
0
1509
0
  nsCString secInfoSerialization;
1510
0
  UpdateAndSerializeSecurityInfo(secInfoSerialization);
1511
0
1512
0
  uint8_t redirectCount = 0;
1513
0
  chan->GetRedirectCount(&redirectCount);
1514
0
1515
0
  int64_t altDataLen = chan->GetAltDataLength();
1516
0
1517
0
  nsCOMPtr<nsILoadInfo> loadInfo;
1518
0
  Unused << chan->GetLoadInfo(getter_AddRefs(loadInfo));
1519
0
1520
0
  ParentLoadInfoForwarderArgs loadInfoForwarderArg;
1521
0
  mozilla::ipc::LoadInfoToParentLoadInfoForwarder(loadInfo, &loadInfoForwarderArg);
1522
0
1523
0
  nsHttpResponseHead *responseHead = chan->GetResponseHead();
1524
0
  bool useResponseHead = !!responseHead;
1525
0
  nsHttpResponseHead cleanedUpResponseHead;
1526
0
  if (responseHead && responseHead->HasHeader(nsHttp::Set_Cookie)) {
1527
0
    cleanedUpResponseHead = *responseHead;
1528
0
    cleanedUpResponseHead.ClearHeader(nsHttp::Set_Cookie);
1529
0
    responseHead = &cleanedUpResponseHead;
1530
0
  }
1531
0
1532
0
  if (!responseHead) {
1533
0
    responseHead = &cleanedUpResponseHead;
1534
0
  }
1535
0
1536
0
  nsHttpRequestHead *requestHead = chan->GetRequestHead();
1537
0
  // !!! We need to lock headers and please don't forget to unlock them !!!
1538
0
  requestHead->Enter();
1539
0
1540
0
  nsHttpHeaderArray cleanedUpRequestHeaders;
1541
0
  bool cleanedUpRequest = false;
1542
0
  if (requestHead->HasHeader(nsHttp::Cookie)) {
1543
0
    cleanedUpRequestHeaders = requestHead->Headers();
1544
0
    cleanedUpRequestHeaders.ClearHeader(nsHttp::Cookie);
1545
0
    cleanedUpRequest = true;
1546
0
  }
1547
0
1548
0
  ResourceTimingStruct timing;
1549
0
  GetTimingAttributes(mChannel, timing);
1550
0
1551
0
  rv = NS_OK;
1552
0
  if (mIPCClosed ||
1553
0
      !SendOnStartRequest(channelStatus,
1554
0
                          *responseHead,
1555
0
                          useResponseHead,
1556
0
                          cleanedUpRequest ? cleanedUpRequestHeaders : requestHead->Headers(),
1557
0
                          loadInfoForwarderArg,
1558
0
                          isFromCache,
1559
0
                          mCacheEntry ? true : false,
1560
0
                          cacheEntryId,
1561
0
                          fetchCount, expirationTime,
1562
0
                          cachedCharset, secInfoSerialization,
1563
0
                          chan->GetSelfAddr(), chan->GetPeerAddr(),
1564
0
                          redirectCount,
1565
0
                          cacheKey,
1566
0
                          altDataType,
1567
0
                          altDataLen,
1568
0
                          applyConversion,
1569
0
                          timing))
1570
0
  {
1571
0
    rv = NS_ERROR_UNEXPECTED;
1572
0
  }
1573
0
  requestHead->Exit();
1574
0
1575
0
  // OnStartRequest is sent to content process successfully.
1576
0
  // Notify PHttpBackgroundChannelChild that all following IPC mesasges
1577
0
  // should be run after OnStartRequest is handled.
1578
0
  if (NS_SUCCEEDED(rv)) {
1579
0
    MOZ_ASSERT(mBgParent);
1580
0
    if (!mBgParent->OnStartRequestSent()) {
1581
0
      rv = NS_ERROR_UNEXPECTED;
1582
0
    }
1583
0
  }
1584
0
1585
0
  return rv;
1586
0
}
1587
1588
NS_IMETHODIMP
1589
HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
1590
                                 nsISupports *aContext,
1591
                                 nsresult aStatusCode)
1592
0
{
1593
0
  LOG(("HttpChannelParent::OnStopRequest: [this=%p aRequest=%p status=%" PRIx32 "]\n",
1594
0
       this, aRequest, static_cast<uint32_t>(aStatusCode)));
1595
0
  MOZ_ASSERT(NS_IsMainThread());
1596
0
1597
0
  MOZ_RELEASE_ASSERT(!mDivertingFromChild,
1598
0
    "Cannot call OnStopRequest if diverting is set!");
1599
0
  ResourceTimingStruct timing;
1600
0
  GetTimingAttributes(mChannel, timing);
1601
0
1602
0
  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel);
1603
0
  if (httpChannelImpl) {
1604
0
    httpChannelImpl->SetWarningReporter(nullptr);
1605
0
  }
1606
0
1607
0
  nsHttpHeaderArray *responseTrailer = mChannel->GetResponseTrailers();
1608
0
1609
0
  // Either IPC channel is closed or background channel
1610
0
  // is ready to send OnStopRequest.
1611
0
  MOZ_ASSERT(mIPCClosed || mBgParent);
1612
0
1613
0
  if (mIPCClosed ||
1614
0
      !mBgParent ||
1615
0
      !mBgParent->OnStopRequest(aStatusCode, timing,
1616
0
                                responseTrailer ? *responseTrailer : nsHttpHeaderArray())) {
1617
0
    return NS_ERROR_UNEXPECTED;
1618
0
  }
1619
0
1620
0
  if (NeedFlowControl()) {
1621
0
    Telemetry::Accumulate(Telemetry::NETWORK_BACK_PRESSURE_SUSPENSION_RATE, mHasSuspendedByBackPressure);
1622
0
  }
1623
0
1624
0
  return NS_OK;
1625
0
}
1626
1627
//-----------------------------------------------------------------------------
1628
// HttpChannelParent::nsIStreamListener
1629
//-----------------------------------------------------------------------------
1630
1631
NS_IMETHODIMP
1632
HttpChannelParent::OnDataAvailable(nsIRequest *aRequest,
1633
                                   nsISupports *aContext,
1634
                                   nsIInputStream *aInputStream,
1635
                                   uint64_t aOffset,
1636
                                   uint32_t aCount)
1637
0
{
1638
0
  LOG(("HttpChannelParent::OnDataAvailable [this=%p aRequest=%p offset=%" PRIu64
1639
0
       " count=%" PRIu32 "]\n", this, aRequest, aOffset, aCount));
1640
0
  MOZ_ASSERT(NS_IsMainThread());
1641
0
1642
0
  MOZ_RELEASE_ASSERT(!mDivertingFromChild,
1643
0
    "Cannot call OnDataAvailable if diverting is set!");
1644
0
1645
0
  nsresult channelStatus = NS_OK;
1646
0
  mChannel->GetStatus(&channelStatus);
1647
0
1648
0
  nsresult transportStatus = NS_NET_STATUS_RECEIVING_FROM;
1649
0
  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel);
1650
0
  if (httpChannelImpl && httpChannelImpl->IsReadingFromCache()) {
1651
0
    transportStatus = NS_NET_STATUS_READING;
1652
0
  }
1653
0
1654
0
  static uint32_t const kCopyChunkSize = 128 * 1024;
1655
0
  uint32_t toRead = std::min<uint32_t>(aCount, kCopyChunkSize);
1656
0
1657
0
  nsCString data;
1658
0
  if (!data.SetCapacity(toRead, fallible)) {
1659
0
    LOG(("  out of memory!"));
1660
0
    return NS_ERROR_OUT_OF_MEMORY;
1661
0
  }
1662
0
1663
0
  int32_t count = static_cast<int32_t>(aCount);
1664
0
1665
0
  while (aCount) {
1666
0
    nsresult rv = NS_ReadInputStreamToString(aInputStream, data, toRead);
1667
0
    if (NS_FAILED(rv)) {
1668
0
      return rv;
1669
0
    }
1670
0
1671
0
    // Either IPC channel is closed or background channel
1672
0
    // is ready to send OnTransportAndData.
1673
0
    MOZ_ASSERT(mIPCClosed || mBgParent);
1674
0
1675
0
    if (mIPCClosed || !mBgParent ||
1676
0
        !mBgParent->OnTransportAndData(channelStatus, transportStatus,
1677
0
                                       aOffset, toRead, data)) {
1678
0
      return NS_ERROR_UNEXPECTED;
1679
0
    }
1680
0
1681
0
    aOffset += toRead;
1682
0
    aCount -= toRead;
1683
0
    toRead = std::min<uint32_t>(aCount, kCopyChunkSize);
1684
0
  }
1685
0
1686
0
  if (NeedFlowControl()) {
1687
0
    // We're going to run out of sending window size
1688
0
    if (mSendWindowSize > 0 && mSendWindowSize <= count) {
1689
0
      MOZ_ASSERT(!mSuspendedForFlowControl);
1690
0
      Unused << mChannel->Suspend();
1691
0
      mSuspendedForFlowControl = true;
1692
0
      mHasSuspendedByBackPressure = true;
1693
0
    }
1694
0
    mSendWindowSize -= count;
1695
0
  }
1696
0
1697
0
  return NS_OK;
1698
0
}
1699
1700
bool
1701
HttpChannelParent::NeedFlowControl()
1702
0
{
1703
0
  if (mCacheNeedFlowControlInitialized) {
1704
0
    return mNeedFlowControl;
1705
0
  }
1706
0
1707
0
  int64_t contentLength = -1;
1708
0
1709
0
  RefPtr<nsHttpChannel> httpChannelImpl = do_QueryObject(mChannel);
1710
0
1711
0
  // By design, we won't trigger the flow control if
1712
0
  // a. pref-out
1713
0
  // b. the resource is from cache or partial cache
1714
0
  // c. the resource is small
1715
0
  // Note that we served the cached resource first for partical cache, which is
1716
0
  // ignored here since we only take the first ODA into consideration.
1717
0
  if (gHttpHandler->SendWindowSize() == 0 ||
1718
0
      !httpChannelImpl ||
1719
0
      httpChannelImpl->IsReadingFromCache() ||
1720
0
      NS_FAILED(httpChannelImpl->GetContentLength(&contentLength)) ||
1721
0
      contentLength < gHttpHandler->SendWindowSize()) {
1722
0
    mNeedFlowControl = false;
1723
0
  }
1724
0
  mCacheNeedFlowControlInitialized = true;
1725
0
  return mNeedFlowControl;
1726
0
}
1727
1728
mozilla::ipc::IPCResult
1729
HttpChannelParent::RecvBytesRead(const int32_t& aCount)
1730
0
{
1731
0
  if (!NeedFlowControl()) {
1732
0
    return IPC_OK();
1733
0
  }
1734
0
1735
0
  LOG(("HttpChannelParent::RecvBytesRead [this=%p count=%" PRId32 "]\n", this, aCount));
1736
0
1737
0
  if (mSendWindowSize <= 0 && mSendWindowSize + aCount > 0) {
1738
0
    MOZ_ASSERT(mSuspendedForFlowControl);
1739
0
    Unused << mChannel->Resume();
1740
0
    mSuspendedForFlowControl = false;
1741
0
  }
1742
0
  mSendWindowSize += aCount;
1743
0
  return IPC_OK();
1744
0
}
1745
1746
//-----------------------------------------------------------------------------
1747
// HttpChannelParent::nsIProgressEventSink
1748
//-----------------------------------------------------------------------------
1749
1750
NS_IMETHODIMP
1751
HttpChannelParent::OnProgress(nsIRequest *aRequest,
1752
                              nsISupports *aContext,
1753
                              int64_t aProgress,
1754
                              int64_t aProgressMax)
1755
0
{
1756
0
  LOG(("HttpChannelParent::OnStatus [this=%p progress=%" PRId64 "max=%" PRId64
1757
0
       "]\n", this, aProgress, aProgressMax));
1758
0
  MOZ_ASSERT(NS_IsMainThread());
1759
0
1760
0
  // If it indicates this precedes OnDataAvailable, child can derive the value in ODA.
1761
0
  if (mIgnoreProgress) {
1762
0
    mIgnoreProgress = false;
1763
0
    return NS_OK;
1764
0
  }
1765
0
1766
0
  // Either IPC channel is closed or background channel
1767
0
  // is ready to send OnProgress.
1768
0
  MOZ_ASSERT(mIPCClosed || mBgParent);
1769
0
1770
0
  // Send OnProgress events to the child for data upload progress notifications
1771
0
  // (i.e. status == NS_NET_STATUS_SENDING_TO) or if the channel has
1772
0
  // LOAD_BACKGROUND set.
1773
0
  if (mIPCClosed || !mBgParent
1774
0
      || !mBgParent->OnProgress(aProgress, aProgressMax)) {
1775
0
    return NS_ERROR_UNEXPECTED;
1776
0
  }
1777
0
1778
0
  return NS_OK;
1779
0
}
1780
1781
NS_IMETHODIMP
1782
HttpChannelParent::OnStatus(nsIRequest *aRequest,
1783
                            nsISupports *aContext,
1784
                            nsresult aStatus,
1785
                            const char16_t *aStatusArg)
1786
0
{
1787
0
  LOG(("HttpChannelParent::OnStatus [this=%p status=%" PRIx32 "]\n",
1788
0
       this, static_cast<uint32_t>(aStatus)));
1789
0
  MOZ_ASSERT(NS_IsMainThread());
1790
0
1791
0
  // If this precedes OnDataAvailable, transportStatus will be derived in ODA.
1792
0
  if (aStatus == NS_NET_STATUS_RECEIVING_FROM ||
1793
0
      aStatus == NS_NET_STATUS_READING) {
1794
0
    // The transport status and progress generated by ODA will be coalesced
1795
0
    // into one IPC message. Therefore, we can ignore the next OnProgress event
1796
0
    // since it is generated by ODA as well.
1797
0
    mIgnoreProgress = true;
1798
0
    return NS_OK;
1799
0
  }
1800
0
1801
0
  // Either IPC channel is closed or background channel
1802
0
  // is ready to send OnStatus.
1803
0
  MOZ_ASSERT(mIPCClosed || mBgParent);
1804
0
1805
0
  // Otherwise, send to child now
1806
0
  if (mIPCClosed || !mBgParent || !mBgParent->OnStatus(aStatus)) {
1807
0
    return NS_ERROR_UNEXPECTED;
1808
0
  }
1809
0
1810
0
  return NS_OK;
1811
0
}
1812
1813
//-----------------------------------------------------------------------------
1814
// HttpChannelParent::nsIParentChannel
1815
//-----------------------------------------------------------------------------
1816
1817
NS_IMETHODIMP
1818
HttpChannelParent::SetParentListener(HttpChannelParentListener* aListener)
1819
0
{
1820
0
  LOG(("HttpChannelParent::SetParentListener [this=%p aListener=%p]\n",
1821
0
       this, aListener));
1822
0
  MOZ_ASSERT(aListener);
1823
0
  MOZ_ASSERT(!mParentListener, "SetParentListener should only be called for "
1824
0
                               "new HttpChannelParents after a redirect, when "
1825
0
                               "mParentListener is null.");
1826
0
  mParentListener = aListener;
1827
0
  return NS_OK;
1828
0
}
1829
1830
NS_IMETHODIMP
1831
HttpChannelParent::NotifyTrackingProtectionDisabled()
1832
0
{
1833
0
  LOG(("HttpChannelParent::NotifyTrackingProtectionDisabled [this=%p]\n", this));
1834
0
  if (!mIPCClosed) {
1835
0
    MOZ_ASSERT(mBgParent);
1836
0
    Unused << NS_WARN_IF(!mBgParent->OnNotifyTrackingProtectionDisabled());
1837
0
  }
1838
0
  return NS_OK;
1839
0
}
1840
1841
NS_IMETHODIMP
1842
HttpChannelParent::NotifyTrackingCookieBlocked(uint32_t aRejectedReason)
1843
0
{
1844
0
  LOG(("HttpChannelParent::NotifyTrackingCookieBlocked [this=%p]\n", this));
1845
0
  if (!mIPCClosed) {
1846
0
    MOZ_ASSERT(mBgParent);
1847
0
    Unused << NS_WARN_IF(!mBgParent->OnNotifyTrackingCookieBlocked(aRejectedReason));
1848
0
  }
1849
0
  return NS_OK;
1850
0
}
1851
1852
NS_IMETHODIMP
1853
HttpChannelParent::SetClassifierMatchedInfo(const nsACString& aList,
1854
                                            const nsACString& aProvider,
1855
                                            const nsACString& aFullHash)
1856
0
{
1857
0
  LOG(("HttpChannelParent::SetClassifierMatchedInfo [this=%p]\n", this));
1858
0
  if (!mIPCClosed) {
1859
0
    MOZ_ASSERT(mBgParent);
1860
0
    Unused << mBgParent->OnSetClassifierMatchedInfo(aList, aProvider, aFullHash);
1861
0
  }
1862
0
  return NS_OK;
1863
0
}
1864
1865
NS_IMETHODIMP
1866
HttpChannelParent::NotifyTrackingResource(bool aIsThirdParty)
1867
0
{
1868
0
  LOG(("HttpChannelParent::NotifyTrackingResource thirdparty=%d [this=%p]\n",
1869
0
       static_cast<int>(aIsThirdParty), this));
1870
0
  if (!mIPCClosed) {
1871
0
    MOZ_ASSERT(mBgParent);
1872
0
    Unused << mBgParent->OnNotifyTrackingResource(aIsThirdParty);
1873
0
  }
1874
0
  return NS_OK;
1875
0
}
1876
1877
NS_IMETHODIMP
1878
HttpChannelParent::Delete()
1879
0
{
1880
0
  if (!mIPCClosed)
1881
0
    Unused << DoSendDeleteSelf();
1882
0
1883
0
  return NS_OK;
1884
0
}
1885
1886
//-----------------------------------------------------------------------------
1887
// HttpChannelParent::nsIParentRedirectingChannel
1888
//-----------------------------------------------------------------------------
1889
1890
NS_IMETHODIMP
1891
HttpChannelParent::StartRedirect(uint32_t registrarId,
1892
                                 nsIChannel* newChannel,
1893
                                 uint32_t redirectFlags,
1894
                                 nsIAsyncVerifyRedirectCallback* callback)
1895
0
{
1896
0
  nsresult rv;
1897
0
1898
0
  LOG(("HttpChannelParent::StartRedirect [this=%p, registrarId=%" PRIu32 " "
1899
0
       "newChannel=%p callback=%p]\n", this, registrarId, newChannel,
1900
0
       callback));
1901
0
1902
0
  if (mIPCClosed) {
1903
0
    return NS_BINDING_ABORTED;
1904
0
  }
1905
0
1906
0
  // If this is an internal redirect for service worker interception, then
1907
0
  // hide it from the child process.  The original e10s interception code
1908
0
  // was not designed with this in mind and its not necessary to replace
1909
0
  // the HttpChannelChild/Parent objects in this case.
1910
0
  if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
1911
0
    nsCOMPtr<nsIInterceptedChannel> oldIntercepted =
1912
0
        do_QueryInterface(static_cast<nsIChannel*>(mChannel.get()));
1913
0
    nsCOMPtr<nsIInterceptedChannel> newIntercepted = do_QueryInterface(newChannel);
1914
0
1915
0
    // We only want to hide the special internal redirect from nsHttpChannel
1916
0
    // to InterceptedHttpChannel.  We want to allow through internal redirects
1917
0
    // initiated from the InterceptedHttpChannel even if they are to another
1918
0
    // InterceptedHttpChannel.
1919
0
    if (!oldIntercepted && newIntercepted) {
1920
0
      // We need to move across the reserved and initial client information
1921
0
      // to the new channel.  Normally this would be handled by the child
1922
0
      // ClientChannelHelper, but that is not notified of this redirect since
1923
0
      // we're not propagating it back to the child process.
1924
0
      nsCOMPtr<nsILoadInfo> oldLoadInfo;
1925
0
      Unused << mChannel->GetLoadInfo(getter_AddRefs(oldLoadInfo));
1926
0
      nsCOMPtr<nsILoadInfo> newLoadInfo;
1927
0
      Unused << newChannel->GetLoadInfo(getter_AddRefs(newLoadInfo));
1928
0
      if (oldLoadInfo && newLoadInfo) {
1929
0
        Maybe<ClientInfo> reservedClientInfo(oldLoadInfo->GetReservedClientInfo());
1930
0
        if (reservedClientInfo.isSome()) {
1931
0
          newLoadInfo->SetReservedClientInfo(reservedClientInfo.ref());
1932
0
        }
1933
0
1934
0
        Maybe<ClientInfo> initialClientInfo(oldLoadInfo->GetInitialClientInfo());
1935
0
        if (initialClientInfo.isSome()) {
1936
0
          newLoadInfo->SetInitialClientInfo(initialClientInfo.ref());
1937
0
        }
1938
0
      }
1939
0
1940
0
      // Re-link the HttpChannelParent to the new InterceptedHttpChannel.
1941
0
      nsCOMPtr<nsIChannel> linkedChannel;
1942
0
      rv = NS_LinkRedirectChannels(registrarId, this, getter_AddRefs(linkedChannel));
1943
0
      NS_ENSURE_SUCCESS(rv, rv);
1944
0
      MOZ_ASSERT(linkedChannel == newChannel);
1945
0
1946
0
      // We immediately store the InterceptedHttpChannel as our nested
1947
0
      // mChannel.  None of the redirect IPC messaging takes place.
1948
0
      mChannel = do_QueryObject(newChannel);
1949
0
1950
0
      callback->OnRedirectVerifyCallback(NS_OK);
1951
0
      return NS_OK;
1952
0
    }
1953
0
  }
1954
0
1955
0
  // Sending down the original URI, because that is the URI we have
1956
0
  // to construct the channel from - this is the URI we've been actually
1957
0
  // redirected to.  URI of the channel may be an inner channel URI.
1958
0
  // URI of the channel will be reconstructed by the protocol handler
1959
0
  // on the child process, no need to send it then.
1960
0
  nsCOMPtr<nsIURI> newOriginalURI;
1961
0
  newChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
1962
0
1963
0
  URIParams uriParams;
1964
0
  SerializeURI(newOriginalURI, uriParams);
1965
0
1966
0
  uint32_t newLoadFlags = nsIRequest::LOAD_NORMAL;
1967
0
  MOZ_ALWAYS_SUCCEEDS(newChannel->GetLoadFlags(&newLoadFlags));
1968
0
1969
0
  nsCString secInfoSerialization;
1970
0
  UpdateAndSerializeSecurityInfo(secInfoSerialization);
1971
0
1972
0
  // If the channel is a HTTP channel, we also want to inform the child
1973
0
  // about the parent's channelId attribute, so that both parent and child
1974
0
  // share the same ID. Useful for monitoring channel activity in devtools.
1975
0
  uint64_t channelId = 0;
1976
0
  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
1977
0
  if (httpChannel) {
1978
0
    rv = httpChannel->GetChannelId(&channelId);
1979
0
    NS_ENSURE_SUCCESS(rv, NS_BINDING_ABORTED);
1980
0
  }
1981
0
1982
0
  nsCOMPtr<nsILoadInfo> loadInfo;
1983
0
  Unused << mChannel->GetLoadInfo(getter_AddRefs(loadInfo));
1984
0
1985
0
  ParentLoadInfoForwarderArgs loadInfoForwarderArg;
1986
0
  mozilla::ipc::LoadInfoToParentLoadInfoForwarder(loadInfo, &loadInfoForwarderArg);
1987
0
1988
0
  nsHttpResponseHead *responseHead = mChannel->GetResponseHead();
1989
0
1990
0
  nsHttpResponseHead cleanedUpResponseHead;
1991
0
  if (responseHead && responseHead->HasHeader(nsHttp::Set_Cookie)) {
1992
0
    cleanedUpResponseHead = *responseHead;
1993
0
    cleanedUpResponseHead.ClearHeader(nsHttp::Set_Cookie);
1994
0
    responseHead = &cleanedUpResponseHead;
1995
0
  }
1996
0
1997
0
  if (!responseHead) {
1998
0
    responseHead = &cleanedUpResponseHead;
1999
0
  }
2000
0
2001
0
  bool result = false;
2002
0
  if (!mIPCClosed) {
2003
0
    result = SendRedirect1Begin(registrarId, uriParams, newLoadFlags,
2004
0
                                redirectFlags, loadInfoForwarderArg,
2005
0
                                *responseHead,
2006
0
                                secInfoSerialization,
2007
0
                                channelId,
2008
0
                                mChannel->GetPeerAddr());
2009
0
  }
2010
0
  if (!result) {
2011
0
    // Bug 621446 investigation
2012
0
    mSentRedirect1BeginFailed = true;
2013
0
    return NS_BINDING_ABORTED;
2014
0
  }
2015
0
2016
0
  // Bug 621446 investigation
2017
0
  // Store registrar Id of the new channel to find the redirect
2018
0
  // HttpChannelParent later in verification phase.
2019
0
  mRedirectRegistrarId = registrarId;
2020
0
2021
0
  // Result is handled in RecvRedirect2Verify above
2022
0
2023
0
  mRedirectChannel = newChannel;
2024
0
  mRedirectCallback = callback;
2025
0
  return NS_OK;
2026
0
}
2027
2028
NS_IMETHODIMP
2029
HttpChannelParent::CompleteRedirect(bool succeeded)
2030
0
{
2031
0
  LOG(("HttpChannelParent::CompleteRedirect [this=%p succeeded=%d]\n",
2032
0
       this, succeeded));
2033
0
2034
0
  // The channel was redirected to another process, and the channel parent
2035
0
  // is about to be deleted. We send a CancelRedirected message in order to
2036
0
  // inform the listener that this child is going away.
2037
0
  if (mDoingCrossProcessRedirect && !mIPCClosed) {
2038
0
      MOZ_ASSERT(!mRedirectChannel);
2039
0
      Unused << SendCancelRedirected();
2040
0
      return NS_OK;
2041
0
  }
2042
0
2043
0
  // If this was an internal redirect for a service worker interception then
2044
0
  // we will not have a redirecting channel here.  Hide this redirect from
2045
0
  // the child.
2046
0
  if (!mRedirectChannel) {
2047
0
    return NS_OK;
2048
0
  }
2049
0
2050
0
  if (succeeded && !mIPCClosed) {
2051
0
    // TODO: check return value: assume child dead if failed
2052
0
    Unused << SendRedirect3Complete();
2053
0
  }
2054
0
2055
0
  mRedirectChannel = nullptr;
2056
0
  return NS_OK;
2057
0
}
2058
2059
//-----------------------------------------------------------------------------
2060
// HttpChannelParent::ADivertableParentChannel
2061
//-----------------------------------------------------------------------------
2062
nsresult
2063
HttpChannelParent::SuspendForDiversion()
2064
0
{
2065
0
  LOG(("HttpChannelParent::SuspendForDiversion [this=%p]\n", this));
2066
0
  MOZ_ASSERT(mChannel);
2067
0
  MOZ_ASSERT(mParentListener);
2068
0
2069
0
  // If we're in the process of opening a synthesized response, we must wait
2070
0
  // to perform the diversion.  Some of our diversion listeners clear callbacks
2071
0
  // which breaks the synthesis process.
2072
0
  if (mWillSynthesizeResponse) {
2073
0
    mPendingDiversion = true;
2074
0
    return NS_OK;
2075
0
  }
2076
0
2077
0
  if (NS_WARN_IF(mDivertingFromChild)) {
2078
0
    MOZ_ASSERT(!mDivertingFromChild, "Already suspended for diversion!");
2079
0
    return NS_ERROR_UNEXPECTED;
2080
0
  }
2081
0
2082
0
  // MessageDiversionStarted call will suspend mEventQ as many times as the
2083
0
  // channel has been suspended, so that channel and this queue are in sync.
2084
0
  nsCOMPtr<nsIChannelWithDivertableParentListener> divertChannel =
2085
0
    do_QueryInterface(static_cast<nsIChannel*>(mChannel.get()));
2086
0
  divertChannel->MessageDiversionStarted(this);
2087
0
2088
0
  nsresult rv = NS_OK;
2089
0
2090
0
  // Try suspending the channel. Allow it to fail, since OnStopRequest may have
2091
0
  // been called and thus the channel may not be pending.  If we've already
2092
0
  // automatically suspended after synthesizing the response, then we don't
2093
0
  // need to suspend again here.
2094
0
  if (!mSuspendAfterSynthesizeResponse) {
2095
0
    // We need to suspend only nsHttpChannel (i.e. we should not suspend
2096
0
    // mEventQ). Therefore we call mChannel->SuspendInternal() and not
2097
0
    // mChannel->Suspend().
2098
0
    // We are suspending only nsHttpChannel here because we want to stop
2099
0
    // OnDataAvailable until diversion is over. At the same time we should
2100
0
    // send the diverted OnDataAvailable-s to the listeners and not queue them
2101
0
    // in mEventQ.
2102
0
    rv = divertChannel->SuspendInternal();
2103
0
    MOZ_ASSERT(NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_AVAILABLE);
2104
0
    mSuspendedForDiversion = NS_SUCCEEDED(rv);
2105
0
  } else {
2106
0
    // Take ownership of the automatic suspend that occurred after synthesizing
2107
0
    // the response.
2108
0
    mSuspendedForDiversion = true;
2109
0
2110
0
    // If mSuspendAfterSynthesizeResponse is true channel has been already
2111
0
    // suspended. From comment above mSuspendedForDiversion takes the ownership
2112
0
    // of this suspend, therefore mEventQ should not be suspened so we need to
2113
0
    // resume it once.
2114
0
    mEventQ->Resume();
2115
0
  }
2116
0
2117
0
  rv = mParentListener->SuspendForDiversion();
2118
0
  MOZ_ASSERT(NS_SUCCEEDED(rv));
2119
0
2120
0
  // Once this is set, no more OnStart/OnData/OnStop callbacks should be sent
2121
0
  // to the child.
2122
0
  mDivertingFromChild = true;
2123
0
2124
0
  return NS_OK;
2125
0
}
2126
2127
nsresult
2128
HttpChannelParent::SuspendMessageDiversion()
2129
0
{
2130
0
  LOG(("HttpChannelParent::SuspendMessageDiversion [this=%p]", this));
2131
0
  // This only needs to suspend message queue.
2132
0
  mEventQ->Suspend();
2133
0
  return NS_OK;
2134
0
}
2135
2136
nsresult
2137
HttpChannelParent::ResumeMessageDiversion()
2138
0
{
2139
0
  LOG(("HttpChannelParent::SuspendMessageDiversion [this=%p]", this));
2140
0
  // This only needs to resumes message queue.
2141
0
  mEventQ->Resume();
2142
0
  return NS_OK;
2143
0
}
2144
2145
nsresult
2146
HttpChannelParent::CancelDiversion()
2147
0
{
2148
0
  LOG(("HttpChannelParent::CancelDiversion [this=%p]", this));
2149
0
  if (!mIPCClosed) {
2150
0
    Unused << SendCancelDiversion();
2151
0
  }
2152
0
  return NS_OK;
2153
0
}
2154
2155
/* private, supporting function for ADivertableParentChannel */
2156
nsresult
2157
HttpChannelParent::ResumeForDiversion()
2158
0
{
2159
0
  LOG(("HttpChannelParent::ResumeForDiversion [this=%p]\n", this));
2160
0
  MOZ_ASSERT(mChannel);
2161
0
  if (NS_WARN_IF(!mDivertingFromChild)) {
2162
0
    MOZ_ASSERT(mDivertingFromChild,
2163
0
               "Cannot ResumeForDiversion if not diverting!");
2164
0
    return NS_ERROR_UNEXPECTED;
2165
0
  }
2166
0
2167
0
  nsCOMPtr<nsIChannelWithDivertableParentListener> divertChannel =
2168
0
    do_QueryInterface(static_cast<nsIChannel*>(mChannel.get()));
2169
0
  divertChannel->MessageDiversionStop();
2170
0
2171
0
  if (mSuspendedForDiversion) {
2172
0
    // The nsHttpChannel will deliver remaining OnData/OnStop for the transfer.
2173
0
    nsresult rv = divertChannel->ResumeInternal();
2174
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
2175
0
      return rv;
2176
0
    }
2177
0
    mSuspendedForDiversion = false;
2178
0
  }
2179
0
2180
0
  if (NS_WARN_IF(mIPCClosed || !DoSendDeleteSelf())) {
2181
0
    return NS_ERROR_UNEXPECTED;
2182
0
  }
2183
0
  return NS_OK;
2184
0
}
2185
2186
void
2187
HttpChannelParent::DivertTo(nsIStreamListener *aListener)
2188
0
{
2189
0
  LOG(("HttpChannelParent::DivertTo [this=%p aListener=%p]\n",
2190
0
       this, aListener));
2191
0
  MOZ_ASSERT(mParentListener);
2192
0
2193
0
  // If we're in the process of opening a synthesized response, we must wait
2194
0
  // to perform the diversion.  Some of our diversion listeners clear callbacks
2195
0
  // which breaks the synthesis process.
2196
0
  if (mWillSynthesizeResponse) {
2197
0
    // We should already have started pending the diversion when
2198
0
    // SuspendForDiversion() was called.
2199
0
    MOZ_ASSERT(mPendingDiversion);
2200
0
    mDivertListener = aListener;
2201
0
    return;
2202
0
  }
2203
0
2204
0
  if (NS_WARN_IF(!mDivertingFromChild)) {
2205
0
    MOZ_ASSERT(mDivertingFromChild,
2206
0
               "Cannot DivertTo new listener if diverting is not set!");
2207
0
    return;
2208
0
  }
2209
0
2210
0
  mDivertListener = aListener;
2211
0
2212
0
  // Call OnStartRequest and SendDivertMessages asynchronously to avoid
2213
0
  // reentering client context.
2214
0
  NS_DispatchToCurrentThread(
2215
0
    NewRunnableMethod("net::HttpChannelParent::StartDiversion",
2216
0
                      this,
2217
0
                      &HttpChannelParent::StartDiversion));
2218
0
}
2219
2220
void
2221
HttpChannelParent::StartDiversion()
2222
0
{
2223
0
  LOG(("HttpChannelParent::StartDiversion [this=%p]\n", this));
2224
0
  if (NS_WARN_IF(!mDivertingFromChild)) {
2225
0
    MOZ_ASSERT(mDivertingFromChild,
2226
0
               "Cannot StartDiversion if diverting is not set!");
2227
0
    return;
2228
0
  }
2229
0
2230
0
  // Fake pending status in case OnStopRequest has already been called.
2231
0
  if (mChannel) {
2232
0
    mChannel->ForcePending(true);
2233
0
  }
2234
0
2235
0
  {
2236
0
    AutoEventEnqueuer ensureSerialDispatch(mEventQ);
2237
0
2238
0
    // Call OnStartRequest for the "DivertTo" listener.
2239
0
    nsresult rv = mDivertListener->OnStartRequest(mChannel, nullptr);
2240
0
    if (NS_FAILED(rv)) {
2241
0
      if (mChannel) {
2242
0
        mChannel->Cancel(rv);
2243
0
      }
2244
0
      mStatus = rv;
2245
0
    }
2246
0
  }
2247
0
  mDivertedOnStartRequest = true;
2248
0
2249
0
  // After OnStartRequest has been called, setup content decoders if needed.
2250
0
  //
2251
0
  // Create a content conversion chain based on mDivertListener and update
2252
0
  // mDivertListener.
2253
0
  nsCOMPtr<nsIStreamListener> converterListener;
2254
0
  Unused << mChannel->DoApplyContentConversions(mDivertListener,
2255
0
                                                getter_AddRefs(converterListener));
2256
0
  if (converterListener) {
2257
0
    mDivertListener = converterListener.forget();
2258
0
  }
2259
0
2260
0
  // Now mParentListener can be diverted to mDivertListener.
2261
0
  DebugOnly<nsresult> rvdbg = mParentListener->DivertTo(mDivertListener);
2262
0
  MOZ_ASSERT(NS_SUCCEEDED(rvdbg));
2263
0
  mDivertListener = nullptr;
2264
0
2265
0
  // Either IPC channel is closed or background channel
2266
0
  // is ready to send FlushedForDiversion and DivertMessages.
2267
0
  MOZ_ASSERT(mIPCClosed || mBgParent);
2268
0
2269
0
  if (NS_WARN_IF(mIPCClosed || !mBgParent || !mBgParent->OnDiversion())) {
2270
0
    FailDiversion(NS_ERROR_UNEXPECTED);
2271
0
    return;
2272
0
  }
2273
0
}
2274
2275
class HTTPFailDiversionEvent : public Runnable
2276
{
2277
public:
2278
  HTTPFailDiversionEvent(HttpChannelParent *aChannelParent,
2279
                         nsresult aErrorCode)
2280
    : Runnable("net::HTTPFailDiversionEvent")
2281
    , mChannelParent(aChannelParent)
2282
    , mErrorCode(aErrorCode)
2283
0
  {
2284
0
    MOZ_RELEASE_ASSERT(aChannelParent);
2285
0
    MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
2286
0
  }
2287
  NS_IMETHOD Run() override
2288
0
  {
2289
0
    mChannelParent->NotifyDiversionFailed(mErrorCode);
2290
0
    return NS_OK;
2291
0
  }
2292
private:
2293
  RefPtr<HttpChannelParent> mChannelParent;
2294
  nsresult mErrorCode;
2295
};
2296
2297
void
2298
HttpChannelParent::FailDiversion(nsresult aErrorCode)
2299
0
{
2300
0
  MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
2301
0
  MOZ_RELEASE_ASSERT(mDivertingFromChild);
2302
0
  MOZ_RELEASE_ASSERT(mParentListener);
2303
0
  MOZ_RELEASE_ASSERT(mChannel);
2304
0
2305
0
  NS_DispatchToCurrentThread(
2306
0
    new HTTPFailDiversionEvent(this, aErrorCode));
2307
0
}
2308
2309
void
2310
HttpChannelParent::NotifyDiversionFailed(nsresult aErrorCode)
2311
0
{
2312
0
  LOG(("HttpChannelParent::NotifyDiversionFailed [this=%p aErrorCode=%" PRIx32 "]\n",
2313
0
       this, static_cast<uint32_t>(aErrorCode)));
2314
0
  MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
2315
0
  MOZ_RELEASE_ASSERT(mDivertingFromChild);
2316
0
  MOZ_RELEASE_ASSERT(mParentListener);
2317
0
  MOZ_RELEASE_ASSERT(mChannel);
2318
0
2319
0
  mChannel->Cancel(aErrorCode);
2320
0
2321
0
  mChannel->ForcePending(false);
2322
0
2323
0
  bool isPending = false;
2324
0
  nsresult rv = mChannel->IsPending(&isPending);
2325
0
  MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
2326
0
2327
0
  // Resume only if we suspended earlier.
2328
0
  if (mSuspendedForDiversion) {
2329
0
    nsCOMPtr<nsIChannelWithDivertableParentListener> divertChannel =
2330
0
      do_QueryInterface(static_cast<nsIChannel*>(mChannel.get()));
2331
0
    divertChannel->ResumeInternal();
2332
0
  }
2333
0
  // Channel has already sent OnStartRequest to the child, so ensure that we
2334
0
  // call it here if it hasn't already been called.
2335
0
  if (!mDivertedOnStartRequest) {
2336
0
    mChannel->ForcePending(true);
2337
0
    mParentListener->OnStartRequest(mChannel, nullptr);
2338
0
    mChannel->ForcePending(false);
2339
0
  }
2340
0
  // If the channel is pending, it will call OnStopRequest itself; otherwise, do
2341
0
  // it here.
2342
0
  if (!isPending) {
2343
0
    mParentListener->OnStopRequest(mChannel, nullptr, aErrorCode);
2344
0
  }
2345
0
2346
0
  if (!mIPCClosed) {
2347
0
    Unused << DoSendDeleteSelf();
2348
0
  }
2349
0
2350
0
  // DoSendDeleteSelf will need channel Id to remove the strong reference in
2351
0
  // BackgroundChannelRegistrar if channel pairing is aborted.
2352
0
  // Thus we need to keep mChannel until DoSendDeleteSelf is done.
2353
0
  mParentListener = nullptr;
2354
0
  mChannel = nullptr;
2355
0
}
2356
2357
nsresult
2358
HttpChannelParent::OpenAlternativeOutputStream(const nsACString & type, int64_t predictedSize, nsIOutputStream * *_retval)
2359
0
{
2360
0
  // We need to make sure the child does not call SendDocumentChannelCleanup()
2361
0
  // before opening the altOutputStream, because that clears mCacheEntry.
2362
0
  if (!mCacheEntry) {
2363
0
    return NS_ERROR_NOT_AVAILABLE;
2364
0
  }
2365
0
  nsresult rv = mCacheEntry->OpenAlternativeOutputStream(type, predictedSize, _retval);
2366
0
  if (NS_SUCCEEDED(rv)) {
2367
0
    mCacheEntry->SetMetaDataElement("alt-data-from-child", "1");
2368
0
  }
2369
0
  return rv;
2370
0
}
2371
2372
NS_IMETHODIMP
2373
HttpChannelParent::GetAuthPrompt(uint32_t aPromptReason, const nsIID& iid,
2374
                                 void** aResult)
2375
0
{
2376
0
  nsCOMPtr<nsIAuthPrompt2> prompt =
2377
0
    new NeckoParent::NestedFrameAuthPrompt(Manager(), mNestedFrameId);
2378
0
  prompt.forget(aResult);
2379
0
  return NS_OK;
2380
0
}
2381
2382
void
2383
HttpChannelParent::UpdateAndSerializeSecurityInfo(nsACString& aSerializedSecurityInfoOut)
2384
0
{
2385
0
  nsCOMPtr<nsISupports> secInfoSupp;
2386
0
  mChannel->GetSecurityInfo(getter_AddRefs(secInfoSupp));
2387
0
  if (secInfoSupp) {
2388
0
    nsCOMPtr<nsISerializable> secInfoSer = do_QueryInterface(secInfoSupp);
2389
0
    if (secInfoSer) {
2390
0
      NS_SerializeToString(secInfoSer, aSerializedSecurityInfoOut);
2391
0
    }
2392
0
  }
2393
0
}
2394
2395
bool
2396
HttpChannelParent::DoSendDeleteSelf()
2397
0
{
2398
0
  mIPCClosed = true;
2399
0
  bool rv = SendDeleteSelf();
2400
0
2401
0
  CleanupBackgroundChannel();
2402
0
2403
0
  return rv;
2404
0
}
2405
2406
mozilla::ipc::IPCResult
2407
HttpChannelParent::RecvDeletingChannel()
2408
0
{
2409
0
  // We need to ensure that the parent channel will not be sending any more IPC
2410
0
  // messages after this, as the child is going away. DoSendDeleteSelf will
2411
0
  // set mIPCClosed = true;
2412
0
  if (!DoSendDeleteSelf()) {
2413
0
    return IPC_FAIL_NO_REASON(this);
2414
0
  }
2415
0
  return IPC_OK();
2416
0
}
2417
2418
mozilla::ipc::IPCResult
2419
HttpChannelParent::RecvFinishInterceptedRedirect()
2420
0
{
2421
0
  // We make sure not to send any more messages until the IPC channel is torn
2422
0
  // down by the child.
2423
0
  mIPCClosed = true;
2424
0
  if (!SendFinishInterceptedRedirect()) {
2425
0
    return IPC_FAIL_NO_REASON(this);
2426
0
  }
2427
0
  return IPC_OK();
2428
0
}
2429
2430
//-----------------------------------------------------------------------------
2431
// HttpChannelSecurityWarningReporter
2432
//-----------------------------------------------------------------------------
2433
2434
nsresult
2435
HttpChannelParent::ReportSecurityMessage(const nsAString& aMessageTag,
2436
                                         const nsAString& aMessageCategory)
2437
0
{
2438
0
  if (mIPCClosed ||
2439
0
      NS_WARN_IF(!SendReportSecurityMessage(nsString(aMessageTag),
2440
0
                                            nsString(aMessageCategory)))) {
2441
0
    return NS_ERROR_UNEXPECTED;
2442
0
  }
2443
0
  return NS_OK;
2444
0
}
2445
2446
NS_IMETHODIMP
2447
HttpChannelParent::IssueWarning(uint32_t aWarning, bool aAsError)
2448
0
{
2449
0
  Unused << SendIssueDeprecationWarning(aWarning, aAsError);
2450
0
  return NS_OK;
2451
0
}
2452
2453
//-----------------------------------------------------------------------------
2454
// nsIAsyncVerifyRedirectReadyCallback
2455
//-----------------------------------------------------------------------------
2456
2457
NS_IMETHODIMP
2458
HttpChannelParent::ReadyToVerify(nsresult aResult)
2459
0
{
2460
0
  LOG(("HttpChannelParent::ReadyToVerify [this=%p result=%" PRIx32 "]\n",
2461
0
       this, static_cast<uint32_t>(aResult)));
2462
0
  MOZ_ASSERT(NS_IsMainThread());
2463
0
2464
0
  ContinueRedirect2Verify(aResult);
2465
0
2466
0
  return NS_OK;
2467
0
}
2468
2469
void
2470
HttpChannelParent::DoSendSetPriority(int16_t aValue)
2471
0
{
2472
0
  if (!mIPCClosed) {
2473
0
    Unused << SendSetPriority(aValue);
2474
0
  }
2475
0
}
2476
2477
nsresult
2478
HttpChannelParent::LogBlockedCORSRequest(const nsAString& aMessage,
2479
                                         const nsACString& aCategory)
2480
0
{
2481
0
  if (mIPCClosed ||
2482
0
      NS_WARN_IF(!SendLogBlockedCORSRequest(nsString(aMessage),
2483
0
                                            nsCString(aCategory)))) {
2484
0
    return NS_ERROR_UNEXPECTED;
2485
0
  }
2486
0
  return NS_OK;
2487
0
}
2488
2489
} // namespace net
2490
} // namespace mozilla