Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/http/HttpBaseChannel.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set sw=2 ts=8 et tw=80 : */
3
4
/* This Source Code Form is subject to the terms of the Mozilla Public
5
 * License, v. 2.0. If a copy of the MPL was not distributed with this
6
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8
// HttpLog.h should generally be included first
9
#include "HttpLog.h"
10
11
#include "mozilla/net/HttpBaseChannel.h"
12
13
#include "nsGlobalWindowOuter.h"
14
#include "nsHttpHandler.h"
15
#include "nsMimeTypes.h"
16
#include "nsNetCID.h"
17
#include "nsNetUtil.h"
18
#include "nsReadableUtils.h"
19
20
#include "nsICachingChannel.h"
21
#include "nsIPrincipal.h"
22
#include "nsIScriptError.h"
23
#include "nsISeekableStream.h"
24
#include "nsIStorageStream.h"
25
#include "nsITimedChannel.h"
26
#include "nsIEncodedChannel.h"
27
#include "nsIApplicationCacheChannel.h"
28
#include "nsIMutableArray.h"
29
#include "nsEscape.h"
30
#include "nsStreamListenerWrapper.h"
31
#include "nsISecurityConsoleMessage.h"
32
#include "nsURLHelper.h"
33
#include "nsICookieService.h"
34
#include "nsIStreamConverterService.h"
35
#include "nsCRT.h"
36
#include "nsContentUtils.h"
37
#include "nsIMutableArray.h"
38
#include "nsIScriptSecurityManager.h"
39
#include "nsIObserverService.h"
40
#include "nsProxyRelease.h"
41
#include "nsPIDOMWindow.h"
42
#include "nsIDocShell.h"
43
#include "nsINetworkInterceptController.h"
44
#include "mozilla/dom/Performance.h"
45
#include "mozilla/dom/PerformanceStorage.h"
46
#include "mozilla/NullPrincipal.h"
47
#include "mozilla/Services.h"
48
#include "mozIThirdPartyUtil.h"
49
#include "nsStreamUtils.h"
50
#include "nsThreadUtils.h"
51
#include "nsContentSecurityManager.h"
52
#include "nsIChannelEventSink.h"
53
#include "nsILoadGroupChild.h"
54
#include "mozilla/ConsoleReportCollector.h"
55
#include "LoadInfo.h"
56
#include "nsISSLSocketControl.h"
57
#include "mozilla/Telemetry.h"
58
#include "nsIURL.h"
59
#include "nsIConsoleService.h"
60
#include "mozilla/BinarySearch.h"
61
#include "mozilla/DebugOnly.h"
62
#include "mozilla/Move.h"
63
#include "mozilla/net/PartiallySeekableInputStream.h"
64
#include "mozilla/InputStreamLengthHelper.h"
65
#include "nsIHttpHeaderVisitor.h"
66
#include "nsIMIMEInputStream.h"
67
#include "nsIXULRuntime.h"
68
#include "nsICacheInfoChannel.h"
69
#include "nsIDOMWindowUtils.h"
70
#include "nsHttpChannel.h"
71
#include "nsRedirectHistoryEntry.h"
72
#include "nsServerTiming.h"
73
74
#include <algorithm>
75
#include "HttpBaseChannel.h"
76
77
namespace mozilla {
78
namespace net {
79
80
static
81
bool IsHeaderBlacklistedForRedirectCopy(nsHttpAtom const& aHeader)
82
0
{
83
0
  // IMPORTANT: keep this list ASCII-code sorted
84
0
  static nsHttpAtom const* blackList[] = {
85
0
    &nsHttp::Accept,
86
0
    &nsHttp::Accept_Encoding,
87
0
    &nsHttp::Accept_Language,
88
0
    &nsHttp::Authentication,
89
0
    &nsHttp::Authorization,
90
0
    &nsHttp::Connection,
91
0
    &nsHttp::Content_Length,
92
0
    &nsHttp::Cookie,
93
0
    &nsHttp::Host,
94
0
    &nsHttp::If,
95
0
    &nsHttp::If_Match,
96
0
    &nsHttp::If_Modified_Since,
97
0
    &nsHttp::If_None_Match,
98
0
    &nsHttp::If_None_Match_Any,
99
0
    &nsHttp::If_Range,
100
0
    &nsHttp::If_Unmodified_Since,
101
0
    &nsHttp::Proxy_Authenticate,
102
0
    &nsHttp::Proxy_Authorization,
103
0
    &nsHttp::Range,
104
0
    &nsHttp::TE,
105
0
    &nsHttp::Transfer_Encoding,
106
0
    &nsHttp::Upgrade,
107
0
    &nsHttp::User_Agent,
108
0
    &nsHttp::WWW_Authenticate
109
0
  };
110
0
111
0
  class HttpAtomComparator
112
0
  {
113
0
    nsHttpAtom const& mTarget;
114
0
  public:
115
0
    explicit HttpAtomComparator(nsHttpAtom const& aTarget)
116
0
      : mTarget(aTarget) {}
117
0
    int operator()(nsHttpAtom const* aVal) const {
118
0
      if (mTarget == *aVal) {
119
0
        return 0;
120
0
      }
121
0
      return strcmp(mTarget._val, aVal->_val);
122
0
    }
123
0
  };
124
0
125
0
  size_t unused;
126
0
  return BinarySearchIf(blackList, 0, ArrayLength(blackList),
127
0
                        HttpAtomComparator(aHeader), &unused);
128
0
}
129
130
class AddHeadersToChannelVisitor final : public nsIHttpHeaderVisitor
131
{
132
public:
133
  NS_DECL_ISUPPORTS
134
135
  explicit AddHeadersToChannelVisitor(nsIHttpChannel *aChannel)
136
    : mChannel(aChannel)
137
0
  {
138
0
  }
139
140
  NS_IMETHOD VisitHeader(const nsACString& aHeader,
141
                         const nsACString& aValue) override
142
0
  {
143
0
    nsHttpAtom atom = nsHttp::ResolveAtom(aHeader);
144
0
    if (!IsHeaderBlacklistedForRedirectCopy(atom)) {
145
0
      DebugOnly<nsresult> rv = mChannel->SetRequestHeader(aHeader, aValue, false);
146
0
      MOZ_ASSERT(NS_SUCCEEDED(rv));
147
0
    }
148
0
    return NS_OK;
149
0
  }
150
private:
151
0
  ~AddHeadersToChannelVisitor() = default;
152
153
  nsCOMPtr<nsIHttpChannel> mChannel;
154
};
155
156
NS_IMPL_ISUPPORTS(AddHeadersToChannelVisitor, nsIHttpHeaderVisitor)
157
158
HttpBaseChannel::HttpBaseChannel()
159
  : mReportCollector(new ConsoleReportCollector())
160
  , mHttpHandler(gHttpHandler)
161
  , mChannelCreationTime(0)
162
  , mStartPos(UINT64_MAX)
163
  , mTransferSize(0)
164
  , mDecodedBodySize(0)
165
  , mEncodedBodySize(0)
166
  , mRequestContextID(0)
167
  , mContentWindowId(0)
168
  , mTopLevelOuterContentWindowId(0)
169
  , mAltDataLength(0)
170
  , mChannelId(0)
171
  , mReqContentLength(0U)
172
  , mStatus(NS_OK)
173
  , mCanceled(false)
174
  , mIsFirstPartyTrackingResource(false)
175
  , mIsThirdPartyTrackingResource(false)
176
  , mLoadFlags(LOAD_NORMAL)
177
  , mCaps(0)
178
  , mClassOfService(0)
179
  , mUpgradeToSecure(false)
180
  , mApplyConversion(true)
181
  , mIsPending(false)
182
  , mWasOpened(false)
183
  , mRequestObserversCalled(false)
184
  , mResponseHeadersModified(false)
185
  , mAllowSTS(true)
186
  , mThirdPartyFlags(0)
187
  , mUploadStreamHasHeaders(false)
188
  , mInheritApplicationCache(true)
189
  , mChooseApplicationCache(false)
190
  , mLoadedFromApplicationCache(false)
191
  , mChannelIsForDownload(false)
192
  , mTracingEnabled(true)
193
  , mTimingEnabled(false)
194
  , mReportTiming(true)
195
  , mAllowSpdy(true)
196
  , mAllowAltSvc(true)
197
  , mBeConservative(false)
198
  , mTRR(false)
199
  , mResponseTimeoutEnabled(true)
200
  , mAllRedirectsSameOrigin(true)
201
  , mAllRedirectsPassTimingAllowCheck(true)
202
  , mResponseCouldBeSynthesized(false)
203
  , mBlockAuthPrompt(false)
204
  , mAllowStaleCacheContent(false)
205
  , mAddedAsNonTailRequest(false)
206
  , mAsyncOpenWaitingForStreamLength(false)
207
  , mUpgradableToSecure(true)
208
  , mTlsFlags(0)
209
  , mSuspendCount(0)
210
  , mInitialRwin(0)
211
  , mProxyResolveFlags(0)
212
  , mContentDispositionHint(UINT32_MAX)
213
  , mReferrerPolicy(NS_GetDefaultReferrerPolicy())
214
  , mCorsMode(nsIHttpChannelInternal::CORS_MODE_NO_CORS)
215
  , mRedirectMode(nsIHttpChannelInternal::REDIRECT_MODE_FOLLOW)
216
  , mLastRedirectFlags(0)
217
  , mPriority(PRIORITY_NORMAL)
218
  , mRedirectionLimit(gHttpHandler->RedirectionLimit())
219
  , mRedirectCount(0)
220
  , mInternalRedirectCount(0)
221
  , mAsyncOpenTimeOverriden(false)
222
  , mForcePending(false)
223
  , mCorsIncludeCredentials(false)
224
  , mOnStartRequestCalled(false)
225
  , mOnStopRequestCalled(false)
226
  , mAfterOnStartRequestBegun(false)
227
  , mRequireCORSPreflight(false)
228
  , mAltDataForChild(false)
229
  , mForceMainDocumentChannel(false)
230
  , mPendingInputStreamLengthOperation(false)
231
0
{
232
0
  this->mSelfAddr.inet = {};
233
0
  this->mPeerAddr.inet = {};
234
0
  LOG(("Creating HttpBaseChannel @%p\n", this));
235
0
236
0
  // Subfields of unions cannot be targeted in an initializer list.
237
#ifdef MOZ_VALGRIND
238
  // Zero the entire unions so that Valgrind doesn't complain when we send them
239
  // to another process.
240
  memset(&mSelfAddr, 0, sizeof(NetAddr));
241
  memset(&mPeerAddr, 0, sizeof(NetAddr));
242
#endif
243
  mSelfAddr.raw.family = PR_AF_UNSPEC;
244
0
  mPeerAddr.raw.family = PR_AF_UNSPEC;
245
0
}
246
247
HttpBaseChannel::~HttpBaseChannel()
248
0
{
249
0
  LOG(("Destroying HttpBaseChannel @%p\n", this));
250
0
251
0
  // Make sure we don't leak
252
0
  CleanRedirectCacheChainIfNecessary();
253
0
254
0
  ReleaseMainThreadOnlyReferences();
255
0
}
256
257
namespace { // anon
258
259
class NonTailRemover : public nsISupports
260
{
261
  NS_DECL_THREADSAFE_ISUPPORTS
262
263
  explicit NonTailRemover(nsIRequestContext* rc)
264
    : mRequestContext(rc)
265
0
  {
266
0
  }
267
268
private:
269
  virtual ~NonTailRemover()
270
0
  {
271
0
    MOZ_ASSERT(NS_IsMainThread());
272
0
    mRequestContext->RemoveNonTailRequest();
273
0
  }
274
275
  nsCOMPtr<nsIRequestContext> mRequestContext;
276
};
277
278
NS_IMPL_ISUPPORTS0(NonTailRemover)
279
280
} // anon
281
282
void
283
HttpBaseChannel::ReleaseMainThreadOnlyReferences()
284
0
{
285
0
  if (NS_IsMainThread()) {
286
0
    // Already on main thread, let dtor to
287
0
    // take care of releasing references
288
0
    RemoveAsNonTailRequest();
289
0
    return;
290
0
  }
291
0
292
0
  nsTArray<nsCOMPtr<nsISupports>> arrayToRelease;
293
0
  arrayToRelease.AppendElement(mURI.forget());
294
0
  arrayToRelease.AppendElement(mOriginalURI.forget());
295
0
  arrayToRelease.AppendElement(mDocumentURI.forget());
296
0
  arrayToRelease.AppendElement(mLoadGroup.forget());
297
0
  arrayToRelease.AppendElement(mLoadInfo.forget());
298
0
  arrayToRelease.AppendElement(mCallbacks.forget());
299
0
  arrayToRelease.AppendElement(mProgressSink.forget());
300
0
  arrayToRelease.AppendElement(mReferrer.forget());
301
0
  arrayToRelease.AppendElement(mApplicationCache.forget());
302
0
  arrayToRelease.AppendElement(mAPIRedirectToURI.forget());
303
0
  arrayToRelease.AppendElement(mProxyURI.forget());
304
0
  arrayToRelease.AppendElement(mPrincipal.forget());
305
0
  arrayToRelease.AppendElement(mTopWindowURI.forget());
306
0
  arrayToRelease.AppendElement(mListener.forget());
307
0
  arrayToRelease.AppendElement(mListenerContext.forget());
308
0
  arrayToRelease.AppendElement(mCompressListener.forget());
309
0
310
0
  if (mAddedAsNonTailRequest) {
311
0
    // RemoveNonTailRequest() on our request context must be called on the main thread
312
0
    MOZ_RELEASE_ASSERT(mRequestContext, "Someone released rc or set flags w/o having it?");
313
0
314
0
    nsCOMPtr<nsISupports> nonTailRemover(new NonTailRemover(mRequestContext));
315
0
    arrayToRelease.AppendElement(nonTailRemover.forget());
316
0
  }
317
0
318
0
  NS_DispatchToMainThread(new ProxyReleaseRunnable(std::move(arrayToRelease)));
319
0
}
320
321
void
322
HttpBaseChannel::SetIsTrackingResource(bool aIsThirdParty)
323
0
{
324
0
  LOG(("HttpBaseChannel::SetIsTrackingResource thirdparty=%d %p",
325
0
       static_cast<int>(aIsThirdParty), this));
326
0
327
0
  if (aIsThirdParty) {
328
0
    MOZ_ASSERT(!mIsFirstPartyTrackingResource);
329
0
    mIsThirdPartyTrackingResource = true;
330
0
  } else {
331
0
    MOZ_ASSERT(!mIsThirdPartyTrackingResource);
332
0
    mIsFirstPartyTrackingResource = true;
333
0
  }
334
0
335
0
  if (mLoadInfo) {
336
0
    MOZ_ALWAYS_SUCCEEDS(mLoadInfo->SetIsTracker(true));
337
0
  }
338
0
}
339
340
nsresult
341
HttpBaseChannel::Init(nsIURI *aURI,
342
                      uint32_t aCaps,
343
                      nsProxyInfo *aProxyInfo,
344
                      uint32_t aProxyResolveFlags,
345
                      nsIURI *aProxyURI,
346
                      uint64_t aChannelId)
347
0
{
348
0
  LOG(("HttpBaseChannel::Init [this=%p]\n", this));
349
0
350
0
  MOZ_ASSERT(aURI, "null uri");
351
0
352
0
  mURI = aURI;
353
0
  mOriginalURI = aURI;
354
0
  mDocumentURI = nullptr;
355
0
  mCaps = aCaps;
356
0
  mProxyResolveFlags = aProxyResolveFlags;
357
0
  mProxyURI = aProxyURI;
358
0
  mChannelId = aChannelId;
359
0
360
0
  // Construct connection info object
361
0
  nsAutoCString host;
362
0
  int32_t port = -1;
363
0
  bool isHTTPS = false;
364
0
365
0
  nsresult rv = mURI->SchemeIs("https", &isHTTPS);
366
0
  if (NS_FAILED(rv)) return rv;
367
0
368
0
  rv = mURI->GetAsciiHost(host);
369
0
  if (NS_FAILED(rv)) return rv;
370
0
371
0
  // Reject the URL if it doesn't specify a host
372
0
  if (host.IsEmpty())
373
0
    return NS_ERROR_MALFORMED_URI;
374
0
375
0
  rv = mURI->GetPort(&port);
376
0
  if (NS_FAILED(rv)) return rv;
377
0
378
0
  LOG(("host=%s port=%d\n", host.get(), port));
379
0
380
0
  rv = mURI->GetAsciiSpec(mSpec);
381
0
  if (NS_FAILED(rv)) return rv;
382
0
  LOG(("uri=%s\n", mSpec.get()));
383
0
384
0
  // Assert default request method
385
0
  MOZ_ASSERT(mRequestHead.EqualsMethod(nsHttpRequestHead::kMethod_Get));
386
0
387
0
  // Set request headers
388
0
  nsAutoCString hostLine;
389
0
  rv = nsHttpHandler::GenerateHostPort(host, port, hostLine);
390
0
  if (NS_FAILED(rv)) return rv;
391
0
392
0
  rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
393
0
  if (NS_FAILED(rv)) return rv;
394
0
395
0
  rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead, isHTTPS);
396
0
  if (NS_FAILED(rv)) return rv;
397
0
398
0
  nsAutoCString type;
399
0
  if (aProxyInfo && NS_SUCCEEDED(aProxyInfo->GetType(type)) &&
400
0
      !type.EqualsLiteral("unknown"))
401
0
    mProxyInfo = aProxyInfo;
402
0
403
0
  return rv;
404
0
}
405
406
//-----------------------------------------------------------------------------
407
// HttpBaseChannel::nsISupports
408
//-----------------------------------------------------------------------------
409
410
NS_IMPL_ADDREF(HttpBaseChannel)
411
NS_IMPL_RELEASE(HttpBaseChannel)
412
413
0
NS_INTERFACE_MAP_BEGIN(HttpBaseChannel)
414
0
  NS_INTERFACE_MAP_ENTRY(nsIRequest)
415
0
  NS_INTERFACE_MAP_ENTRY(nsIChannel)
416
0
  NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel)
417
0
  NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
418
0
  NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
419
0
  NS_INTERFACE_MAP_ENTRY(nsIForcePendingChannel)
420
0
  NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
421
0
  NS_INTERFACE_MAP_ENTRY(nsIFormPOSTActionChannel)
422
0
  NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
423
0
  NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
424
0
  NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
425
0
  NS_INTERFACE_MAP_ENTRY(nsIPrivateBrowsingChannel)
426
0
  NS_INTERFACE_MAP_ENTRY(nsITimedChannel)
427
0
  NS_INTERFACE_MAP_ENTRY(nsIConsoleReportCollector)
428
0
  NS_INTERFACE_MAP_ENTRY(nsIThrottledInputChannel)
429
0
  NS_INTERFACE_MAP_ENTRY(nsIClassifiedChannel)
430
0
  NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpBaseChannel)
431
0
NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag)
432
433
//-----------------------------------------------------------------------------
434
// HttpBaseChannel::nsIRequest
435
//-----------------------------------------------------------------------------
436
437
NS_IMETHODIMP
438
HttpBaseChannel::GetName(nsACString& aName)
439
0
{
440
0
  aName = mSpec;
441
0
  return NS_OK;
442
0
}
443
444
NS_IMETHODIMP
445
HttpBaseChannel::IsPending(bool *aIsPending)
446
0
{
447
0
  NS_ENSURE_ARG_POINTER(aIsPending);
448
0
  *aIsPending = mIsPending || mForcePending;
449
0
  return NS_OK;
450
0
}
451
452
NS_IMETHODIMP
453
HttpBaseChannel::GetStatus(nsresult *aStatus)
454
0
{
455
0
  NS_ENSURE_ARG_POINTER(aStatus);
456
0
  *aStatus = mStatus;
457
0
  return NS_OK;
458
0
}
459
460
NS_IMETHODIMP
461
HttpBaseChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
462
0
{
463
0
  NS_ENSURE_ARG_POINTER(aLoadGroup);
464
0
  *aLoadGroup = mLoadGroup;
465
0
  NS_IF_ADDREF(*aLoadGroup);
466
0
  return NS_OK;
467
0
}
468
469
NS_IMETHODIMP
470
HttpBaseChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
471
0
{
472
0
  MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
473
0
474
0
  if (!CanSetLoadGroup(aLoadGroup)) {
475
0
    return NS_ERROR_FAILURE;
476
0
  }
477
0
478
0
  mLoadGroup = aLoadGroup;
479
0
  mProgressSink = nullptr;
480
0
  UpdatePrivateBrowsing();
481
0
  return NS_OK;
482
0
}
483
484
NS_IMETHODIMP
485
HttpBaseChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
486
0
{
487
0
  NS_ENSURE_ARG_POINTER(aLoadFlags);
488
0
  *aLoadFlags = mLoadFlags;
489
0
  return NS_OK;
490
0
}
491
492
NS_IMETHODIMP
493
HttpBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
494
0
{
495
0
  mLoadFlags = aLoadFlags;
496
0
  return NS_OK;
497
0
}
498
499
NS_IMETHODIMP
500
HttpBaseChannel::SetDocshellUserAgentOverride()
501
0
{
502
0
  // This sets the docshell specific user agent override, it will be overwritten
503
0
  // by UserAgentOverrides.jsm if site-specific user agent overrides are set.
504
0
  nsresult rv;
505
0
  nsCOMPtr<nsILoadContext> loadContext;
506
0
  NS_QueryNotificationCallbacks(this, loadContext);
507
0
  if (!loadContext) {
508
0
    return NS_OK;
509
0
  }
510
0
511
0
  nsCOMPtr<mozIDOMWindowProxy> domWindow;
512
0
  loadContext->GetAssociatedWindow(getter_AddRefs(domWindow));
513
0
  if (!domWindow) {
514
0
    return NS_OK;
515
0
  }
516
0
517
0
  auto* pDomWindow = nsPIDOMWindowOuter::From(domWindow);
518
0
  nsIDocShell* docshell = pDomWindow->GetDocShell();
519
0
  if (!docshell) {
520
0
    return NS_OK;
521
0
  }
522
0
523
0
  nsString customUserAgent;
524
0
  docshell->GetCustomUserAgent(customUserAgent);
525
0
  if (customUserAgent.IsEmpty()) {
526
0
    return NS_OK;
527
0
  }
528
0
529
0
  NS_ConvertUTF16toUTF8 utf8CustomUserAgent(customUserAgent);
530
0
  rv = SetRequestHeader(NS_LITERAL_CSTRING("User-Agent"), utf8CustomUserAgent, false);
531
0
  if (NS_FAILED(rv)) return rv;
532
0
533
0
  return NS_OK;
534
0
}
535
536
//-----------------------------------------------------------------------------
537
// HttpBaseChannel::nsIChannel
538
//-----------------------------------------------------------------------------
539
540
NS_IMETHODIMP
541
HttpBaseChannel::GetOriginalURI(nsIURI **aOriginalURI)
542
0
{
543
0
  NS_ENSURE_ARG_POINTER(aOriginalURI);
544
0
  *aOriginalURI = mOriginalURI;
545
0
  NS_ADDREF(*aOriginalURI);
546
0
  return NS_OK;
547
0
}
548
549
NS_IMETHODIMP
550
HttpBaseChannel::SetOriginalURI(nsIURI *aOriginalURI)
551
0
{
552
0
  ENSURE_CALLED_BEFORE_CONNECT();
553
0
554
0
  NS_ENSURE_ARG_POINTER(aOriginalURI);
555
0
  mOriginalURI = aOriginalURI;
556
0
  return NS_OK;
557
0
}
558
559
NS_IMETHODIMP
560
HttpBaseChannel::GetURI(nsIURI **aURI)
561
0
{
562
0
  NS_ENSURE_ARG_POINTER(aURI);
563
0
  *aURI = mURI;
564
0
  NS_ADDREF(*aURI);
565
0
  return NS_OK;
566
0
}
567
568
NS_IMETHODIMP
569
HttpBaseChannel::GetOwner(nsISupports **aOwner)
570
0
{
571
0
  NS_ENSURE_ARG_POINTER(aOwner);
572
0
  *aOwner = mOwner;
573
0
  NS_IF_ADDREF(*aOwner);
574
0
  return NS_OK;
575
0
}
576
577
NS_IMETHODIMP
578
HttpBaseChannel::SetOwner(nsISupports *aOwner)
579
0
{
580
0
  mOwner = aOwner;
581
0
  return NS_OK;
582
0
}
583
584
NS_IMETHODIMP
585
HttpBaseChannel::SetLoadInfo(nsILoadInfo *aLoadInfo)
586
0
{
587
0
  mLoadInfo = aLoadInfo;
588
0
  return NS_OK;
589
0
}
590
591
NS_IMETHODIMP
592
HttpBaseChannel::GetLoadInfo(nsILoadInfo **aLoadInfo)
593
0
{
594
0
  NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
595
0
  return NS_OK;
596
0
}
597
598
NS_IMETHODIMP
599
HttpBaseChannel::GetIsDocument(bool *aIsDocument)
600
0
{
601
0
  return NS_GetIsDocumentChannel(this, aIsDocument);
602
0
}
603
604
NS_IMETHODIMP
605
HttpBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
606
0
{
607
0
  *aCallbacks = mCallbacks;
608
0
  NS_IF_ADDREF(*aCallbacks);
609
0
  return NS_OK;
610
0
}
611
612
NS_IMETHODIMP
613
HttpBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
614
0
{
615
0
  MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
616
0
617
0
  if (!CanSetCallbacks(aCallbacks)) {
618
0
    return NS_ERROR_FAILURE;
619
0
  }
620
0
621
0
  mCallbacks = aCallbacks;
622
0
  mProgressSink = nullptr;
623
0
624
0
  UpdatePrivateBrowsing();
625
0
  return NS_OK;
626
0
}
627
628
NS_IMETHODIMP
629
HttpBaseChannel::GetContentType(nsACString& aContentType)
630
0
{
631
0
  if (!mResponseHead) {
632
0
    aContentType.Truncate();
633
0
    return NS_ERROR_NOT_AVAILABLE;
634
0
  }
635
0
636
0
  mResponseHead->ContentType(aContentType);
637
0
  if (!aContentType.IsEmpty()) {
638
0
    return NS_OK;
639
0
  }
640
0
641
0
  aContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
642
0
  return NS_OK;
643
0
}
644
645
NS_IMETHODIMP
646
HttpBaseChannel::SetContentType(const nsACString& aContentType)
647
0
{
648
0
  if (mListener || mWasOpened) {
649
0
    if (!mResponseHead)
650
0
      return NS_ERROR_NOT_AVAILABLE;
651
0
652
0
    nsAutoCString contentTypeBuf, charsetBuf;
653
0
    bool hadCharset;
654
0
    net_ParseContentType(aContentType, contentTypeBuf, charsetBuf, &hadCharset);
655
0
656
0
    mResponseHead->SetContentType(contentTypeBuf);
657
0
658
0
    // take care not to stomp on an existing charset
659
0
    if (hadCharset)
660
0
      mResponseHead->SetContentCharset(charsetBuf);
661
0
662
0
  } else {
663
0
    // We are being given a content-type hint.
664
0
    bool dummy;
665
0
    net_ParseContentType(aContentType, mContentTypeHint, mContentCharsetHint,
666
0
                         &dummy);
667
0
  }
668
0
669
0
  return NS_OK;
670
0
}
671
672
NS_IMETHODIMP
673
HttpBaseChannel::GetContentCharset(nsACString& aContentCharset)
674
0
{
675
0
  if (!mResponseHead)
676
0
    return NS_ERROR_NOT_AVAILABLE;
677
0
678
0
  mResponseHead->ContentCharset(aContentCharset);
679
0
  return NS_OK;
680
0
}
681
682
NS_IMETHODIMP
683
HttpBaseChannel::SetContentCharset(const nsACString& aContentCharset)
684
0
{
685
0
  if (mListener) {
686
0
    if (!mResponseHead)
687
0
      return NS_ERROR_NOT_AVAILABLE;
688
0
689
0
    mResponseHead->SetContentCharset(aContentCharset);
690
0
  } else {
691
0
    // Charset hint
692
0
    mContentCharsetHint = aContentCharset;
693
0
  }
694
0
  return NS_OK;
695
0
}
696
697
NS_IMETHODIMP
698
HttpBaseChannel::GetContentDisposition(uint32_t *aContentDisposition)
699
0
{
700
0
  nsresult rv;
701
0
  nsCString header;
702
0
703
0
  rv = GetContentDispositionHeader(header);
704
0
  if (NS_FAILED(rv)) {
705
0
    if (mContentDispositionHint == UINT32_MAX)
706
0
      return rv;
707
0
708
0
    *aContentDisposition = mContentDispositionHint;
709
0
    return NS_OK;
710
0
  }
711
0
712
0
  *aContentDisposition = NS_GetContentDispositionFromHeader(header, this);
713
0
  return NS_OK;
714
0
}
715
716
NS_IMETHODIMP
717
HttpBaseChannel::SetContentDisposition(uint32_t aContentDisposition)
718
0
{
719
0
  mContentDispositionHint = aContentDisposition;
720
0
  return NS_OK;
721
0
}
722
723
NS_IMETHODIMP
724
HttpBaseChannel::GetContentDispositionFilename(nsAString& aContentDispositionFilename)
725
0
{
726
0
  aContentDispositionFilename.Truncate();
727
0
  nsresult rv;
728
0
  nsCString header;
729
0
730
0
  rv = GetContentDispositionHeader(header);
731
0
  if (NS_FAILED(rv)) {
732
0
    if (!mContentDispositionFilename)
733
0
      return rv;
734
0
735
0
    aContentDispositionFilename = *mContentDispositionFilename;
736
0
    return NS_OK;
737
0
  }
738
0
739
0
  return NS_GetFilenameFromDisposition(aContentDispositionFilename,
740
0
                                       header, mURI);
741
0
}
742
743
NS_IMETHODIMP
744
HttpBaseChannel::SetContentDispositionFilename(const nsAString& aContentDispositionFilename)
745
0
{
746
0
  mContentDispositionFilename = new nsString(aContentDispositionFilename);
747
0
  return NS_OK;
748
0
}
749
750
NS_IMETHODIMP
751
HttpBaseChannel::GetContentDispositionHeader(nsACString& aContentDispositionHeader)
752
0
{
753
0
  if (!mResponseHead)
754
0
    return NS_ERROR_NOT_AVAILABLE;
755
0
756
0
  nsresult rv = mResponseHead->GetHeader(nsHttp::Content_Disposition,
757
0
                                         aContentDispositionHeader);
758
0
  if (NS_FAILED(rv) || aContentDispositionHeader.IsEmpty())
759
0
    return NS_ERROR_NOT_AVAILABLE;
760
0
761
0
  return NS_OK;
762
0
}
763
764
NS_IMETHODIMP
765
HttpBaseChannel::GetContentLength(int64_t *aContentLength)
766
0
{
767
0
  NS_ENSURE_ARG_POINTER(aContentLength);
768
0
769
0
  if (!mResponseHead)
770
0
    return NS_ERROR_NOT_AVAILABLE;
771
0
772
0
  if (!mAvailableCachedAltDataType.IsEmpty()) {
773
0
    *aContentLength = mAltDataLength;
774
0
    return NS_OK;
775
0
  }
776
0
777
0
  *aContentLength = mResponseHead->ContentLength();
778
0
  return NS_OK;
779
0
}
780
781
NS_IMETHODIMP
782
HttpBaseChannel::SetContentLength(int64_t value)
783
0
{
784
0
  MOZ_ASSERT_UNREACHABLE("HttpBaseChannel::SetContentLength");
785
0
  return NS_ERROR_NOT_IMPLEMENTED;
786
0
}
787
788
NS_IMETHODIMP
789
HttpBaseChannel::Open(nsIInputStream **aResult)
790
0
{
791
0
  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
792
0
793
0
  if (!gHttpHandler->Active()) {
794
0
    LOG(("HttpBaseChannel::Open after HTTP shutdown..."));
795
0
    return NS_ERROR_NOT_AVAILABLE;
796
0
  }
797
0
798
0
  return NS_ImplementChannelOpen(this, aResult);
799
0
}
800
801
NS_IMETHODIMP
802
HttpBaseChannel::Open2(nsIInputStream** aStream)
803
0
{
804
0
  if (!gHttpHandler->Active()) {
805
0
    LOG(("HttpBaseChannel::Open after HTTP shutdown..."));
806
0
    return NS_ERROR_NOT_AVAILABLE;
807
0
  }
808
0
809
0
  nsCOMPtr<nsIStreamListener> listener;
810
0
  nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
811
0
  NS_ENSURE_SUCCESS(rv, rv);
812
0
  return Open(aStream);
813
0
}
814
815
//-----------------------------------------------------------------------------
816
// HttpBaseChannel::nsIUploadChannel
817
//-----------------------------------------------------------------------------
818
819
NS_IMETHODIMP
820
HttpBaseChannel::GetUploadStream(nsIInputStream **stream)
821
0
{
822
0
  NS_ENSURE_ARG_POINTER(stream);
823
0
  *stream = mUploadStream;
824
0
  NS_IF_ADDREF(*stream);
825
0
  return NS_OK;
826
0
}
827
828
NS_IMETHODIMP
829
HttpBaseChannel::SetUploadStream(nsIInputStream *stream,
830
                                 const nsACString &contentTypeArg,
831
                                 int64_t contentLength)
832
0
{
833
0
  // NOTE: for backwards compatibility and for compatibility with old style
834
0
  // plugins, |stream| may include headers, specifically Content-Type and
835
0
  // Content-Length headers.  in this case, |contentType| and |contentLength|
836
0
  // would be unspecified.  this is traditionally the case of a POST request,
837
0
  // and so we select POST as the request method if contentType and
838
0
  // contentLength are unspecified.
839
0
840
0
  if (stream) {
841
0
    nsAutoCString method;
842
0
    bool hasHeaders = false;
843
0
844
0
    // This method and ExplicitSetUploadStream mean different things by "empty
845
0
    // content type string".  This method means "no header", but
846
0
    // ExplicitSetUploadStream means "header with empty value".  So we have to
847
0
    // massage the contentType argument into the form ExplicitSetUploadStream
848
0
    // expects.
849
0
    nsCOMPtr<nsIMIMEInputStream> mimeStream;
850
0
    nsCString contentType(contentTypeArg);
851
0
    if (contentType.IsEmpty()) {
852
0
      contentType.SetIsVoid(true);
853
0
      method = NS_LITERAL_CSTRING("POST");
854
0
855
0
      // MIME streams are a special case, and include headers which need to be
856
0
      // copied to the channel.
857
0
      mimeStream = do_QueryInterface(stream);
858
0
      if (mimeStream) {
859
0
        // Copy non-origin related headers to the channel.
860
0
        nsCOMPtr<nsIHttpHeaderVisitor> visitor =
861
0
          new AddHeadersToChannelVisitor(this);
862
0
        mimeStream->VisitHeaders(visitor);
863
0
864
0
        return ExplicitSetUploadStream(stream, contentType, contentLength,
865
0
                                       method, hasHeaders);
866
0
      }
867
0
868
0
      hasHeaders = true;
869
0
    } else {
870
0
      method = NS_LITERAL_CSTRING("PUT");
871
0
872
0
      MOZ_ASSERT(NS_FAILED(CallQueryInterface(stream, getter_AddRefs(mimeStream))),
873
0
                 "nsIMIMEInputStream should not be set with an explicit content type");
874
0
    }
875
0
    return ExplicitSetUploadStream(stream, contentType, contentLength,
876
0
                                   method, hasHeaders);
877
0
  }
878
0
879
0
  // if stream is null, ExplicitSetUploadStream returns error.
880
0
  // So we need special case for GET method.
881
0
  mUploadStreamHasHeaders = false;
882
0
  mRequestHead.SetMethod(NS_LITERAL_CSTRING("GET")); // revert to GET request
883
0
  mUploadStream = stream;
884
0
  return NS_OK;
885
0
}
886
887
namespace {
888
889
void
890
0
CopyComplete(void* aClosure, nsresult aStatus) {
891
#ifdef DEBUG
892
  // Called on the STS thread by NS_AsyncCopy
893
  nsCOMPtr<nsIEventTarget> sts =
894
    do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
895
  bool result = false;
896
  sts->IsOnCurrentThread(&result);
897
  MOZ_ASSERT(result, "Should only be called on the STS thread.");
898
#endif
899
900
0
  auto channel = static_cast<HttpBaseChannel*>(aClosure);
901
0
  channel->OnCopyComplete(aStatus);
902
0
}
903
904
} // anonymous namespace
905
906
NS_IMETHODIMP
907
HttpBaseChannel::EnsureUploadStreamIsCloneable(nsIRunnable* aCallback)
908
0
{
909
0
  MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
910
0
  NS_ENSURE_ARG_POINTER(aCallback);
911
0
912
0
  // We could in theory allow multiple callers to use this method,
913
0
  // but the complexity does not seem worth it yet.  Just fail if
914
0
  // this is called more than once simultaneously.
915
0
  NS_ENSURE_FALSE(mUploadCloneableCallback, NS_ERROR_UNEXPECTED);
916
0
917
0
  // If the CloneUploadStream() will succeed, then synchronously invoke
918
0
  // the callback to indicate we're already cloneable.
919
0
  if (!mUploadStream || NS_InputStreamIsCloneable(mUploadStream)) {
920
0
    aCallback->Run();
921
0
    return NS_OK;
922
0
  }
923
0
924
0
  nsCOMPtr<nsIStorageStream> storageStream;
925
0
  nsresult rv = NS_NewStorageStream(4096, UINT32_MAX,
926
0
                                    getter_AddRefs(storageStream));
927
0
  NS_ENSURE_SUCCESS(rv, rv);
928
0
929
0
  nsCOMPtr<nsIInputStream> newUploadStream;
930
0
  rv = storageStream->NewInputStream(0, getter_AddRefs(newUploadStream));
931
0
  NS_ENSURE_SUCCESS(rv, rv);
932
0
933
0
  nsCOMPtr<nsIOutputStream> sink;
934
0
  rv = storageStream->GetOutputStream(0, getter_AddRefs(sink));
935
0
  NS_ENSURE_SUCCESS(rv, rv);
936
0
937
0
  nsCOMPtr<nsIInputStream> source;
938
0
  if (NS_InputStreamIsBuffered(mUploadStream)) {
939
0
    source = mUploadStream;
940
0
  } else {
941
0
    rv = NS_NewBufferedInputStream(getter_AddRefs(source),
942
0
                                   mUploadStream.forget(), 4096);
943
0
    NS_ENSURE_SUCCESS(rv, rv);
944
0
  }
945
0
946
0
  nsCOMPtr<nsIEventTarget> target =
947
0
    do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
948
0
949
0
  mUploadCloneableCallback = aCallback;
950
0
951
0
  rv = NS_AsyncCopy(source, sink, target, NS_ASYNCCOPY_VIA_READSEGMENTS,
952
0
                    4096, // copy segment size
953
0
                    CopyComplete, this);
954
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
955
0
    mUploadCloneableCallback = nullptr;
956
0
    return rv;
957
0
  }
958
0
959
0
  // Since we're consuming the old stream, replace it with the new
960
0
  // stream immediately.
961
0
  mUploadStream = newUploadStream;
962
0
963
0
  // Explicity hold the stream alive until copying is complete.  This will
964
0
  // be released in EnsureUploadStreamIsCloneableComplete().
965
0
  AddRef();
966
0
967
0
  return NS_OK;
968
0
}
969
970
void
971
HttpBaseChannel::OnCopyComplete(nsresult aStatus)
972
0
{
973
0
  // Assert in parent process because we don't have to label the runnable
974
0
  // in parent process.
975
0
  MOZ_ASSERT(XRE_IsParentProcess());
976
0
977
0
  nsCOMPtr<nsIRunnable> runnable = NewRunnableMethod<nsresult>(
978
0
    "net::HttpBaseChannel::EnsureUploadStreamIsCloneableComplete",
979
0
    this,
980
0
    &HttpBaseChannel::EnsureUploadStreamIsCloneableComplete,
981
0
    aStatus);
982
0
  NS_DispatchToMainThread(runnable.forget());
983
0
}
984
985
void
986
HttpBaseChannel::EnsureUploadStreamIsCloneableComplete(nsresult aStatus)
987
0
{
988
0
  MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
989
0
  MOZ_ASSERT(mUploadCloneableCallback);
990
0
991
0
  if (NS_SUCCEEDED(mStatus)) {
992
0
    mStatus = aStatus;
993
0
  }
994
0
995
0
  mUploadCloneableCallback->Run();
996
0
  mUploadCloneableCallback = nullptr;
997
0
998
0
  // Release the reference we grabbed in EnsureUploadStreamIsCloneable() now
999
0
  // that the copying is complete.
1000
0
  Release();
1001
0
}
1002
1003
NS_IMETHODIMP
1004
HttpBaseChannel::CloneUploadStream(int64_t* aContentLength,
1005
                                   nsIInputStream** aClonedStream)
1006
0
{
1007
0
  NS_ENSURE_ARG_POINTER(aContentLength);
1008
0
  NS_ENSURE_ARG_POINTER(aClonedStream);
1009
0
  *aClonedStream = nullptr;
1010
0
1011
0
  if (!mUploadStream) {
1012
0
    return NS_OK;
1013
0
  }
1014
0
1015
0
  nsCOMPtr<nsIInputStream> clonedStream;
1016
0
  nsresult rv = NS_CloneInputStream(mUploadStream, getter_AddRefs(clonedStream));
1017
0
  NS_ENSURE_SUCCESS(rv, rv);
1018
0
1019
0
  clonedStream.forget(aClonedStream);
1020
0
1021
0
  *aContentLength = mReqContentLength;
1022
0
  return NS_OK;
1023
0
}
1024
1025
1026
//-----------------------------------------------------------------------------
1027
// HttpBaseChannel::nsIUploadChannel2
1028
//-----------------------------------------------------------------------------
1029
1030
NS_IMETHODIMP
1031
HttpBaseChannel::ExplicitSetUploadStream(nsIInputStream *aStream,
1032
                                         const nsACString &aContentType,
1033
                                         int64_t aContentLength,
1034
                                         const nsACString &aMethod,
1035
                                         bool aStreamHasHeaders)
1036
0
{
1037
0
  // Ensure stream is set and method is valid
1038
0
  NS_ENSURE_TRUE(aStream, NS_ERROR_FAILURE);
1039
0
1040
0
  {
1041
0
    DebugOnly<nsCOMPtr<nsIMIMEInputStream>> mimeStream;
1042
0
    MOZ_ASSERT(!aStreamHasHeaders ||
1043
0
               NS_FAILED(CallQueryInterface(aStream, getter_AddRefs(mimeStream.value))),
1044
0
               "nsIMIMEInputStream should not include headers");
1045
0
  }
1046
0
1047
0
  nsresult rv = SetRequestMethod(aMethod);
1048
0
  NS_ENSURE_SUCCESS(rv, rv);
1049
0
1050
0
  if (!aStreamHasHeaders && !aContentType.IsVoid()) {
1051
0
    if (aContentType.IsEmpty()) {
1052
0
      SetEmptyRequestHeader(NS_LITERAL_CSTRING("Content-Type"));
1053
0
    } else {
1054
0
      SetRequestHeader(NS_LITERAL_CSTRING("Content-Type"), aContentType,
1055
0
                       false);
1056
0
    }
1057
0
  }
1058
0
1059
0
  mUploadStreamHasHeaders = aStreamHasHeaders;
1060
0
1061
0
  nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(aStream);
1062
0
  if (!seekable) {
1063
0
    nsCOMPtr<nsIInputStream> stream = aStream;
1064
0
    seekable = new PartiallySeekableInputStream(stream.forget());
1065
0
  }
1066
0
1067
0
  mUploadStream = do_QueryInterface(seekable);
1068
0
1069
0
  if (aContentLength >= 0) {
1070
0
    ExplicitSetUploadStreamLength(aContentLength, aStreamHasHeaders);
1071
0
    return NS_OK;
1072
0
  }
1073
0
1074
0
  // Sync access to the stream length.
1075
0
  int64_t length;
1076
0
  if (InputStreamLengthHelper::GetSyncLength(aStream, &length)) {
1077
0
    ExplicitSetUploadStreamLength(length >= 0 ? length : 0,
1078
0
                                  aStreamHasHeaders);
1079
0
    return NS_OK;
1080
0
  }
1081
0
1082
0
  // Let's resolve the size of the stream.
1083
0
  RefPtr<HttpBaseChannel> self = this;
1084
0
  InputStreamLengthHelper::GetAsyncLength(aStream,
1085
0
    [self, aStreamHasHeaders](int64_t aLength) {
1086
0
      self->mPendingInputStreamLengthOperation = false;
1087
0
      self->ExplicitSetUploadStreamLength(aLength >= 0 ? aLength : 0,
1088
0
                                          aStreamHasHeaders);
1089
0
      self->MaybeResumeAsyncOpen();
1090
0
    });
1091
0
  mPendingInputStreamLengthOperation = true;
1092
0
  return NS_OK;
1093
0
}
1094
1095
nsresult
1096
HttpBaseChannel::ExplicitSetUploadStreamLength(uint64_t aContentLength,
1097
                                               bool aStreamHasHeaders)
1098
0
{
1099
0
  // We already have the content length. We don't need to determinate it.
1100
0
  mReqContentLength = aContentLength;
1101
0
1102
0
  if (aStreamHasHeaders) {
1103
0
    return NS_OK;
1104
0
  }
1105
0
1106
0
  nsAutoCString header;
1107
0
  header.AssignLiteral("Content-Length");
1108
0
1109
0
  // Maybe the content-length header has been already set.
1110
0
  nsAutoCString value;
1111
0
  nsresult rv = GetRequestHeader(header, value);
1112
0
  if (NS_SUCCEEDED(rv) && !value.IsEmpty()) {
1113
0
    return NS_OK;
1114
0
  }
1115
0
1116
0
  // SetRequestHeader propagates headers to chrome if HttpChannelChild
1117
0
  MOZ_ASSERT(!mWasOpened);
1118
0
  nsAutoCString contentLengthStr;
1119
0
  contentLengthStr.AppendInt(aContentLength);
1120
0
  SetRequestHeader(header, contentLengthStr, false);
1121
0
1122
0
  return NS_OK;
1123
0
}
1124
1125
NS_IMETHODIMP
1126
HttpBaseChannel::GetUploadStreamHasHeaders(bool *hasHeaders)
1127
0
{
1128
0
  NS_ENSURE_ARG(hasHeaders);
1129
0
1130
0
  *hasHeaders = mUploadStreamHasHeaders;
1131
0
  return NS_OK;
1132
0
}
1133
1134
bool
1135
HttpBaseChannel::MaybeWaitForUploadStreamLength(nsIStreamListener *aListener,
1136
                                                nsISupports *aContext)
1137
0
{
1138
0
  MOZ_ASSERT(NS_IsMainThread());
1139
0
  MOZ_ASSERT(!mAsyncOpenWaitingForStreamLength, "AsyncOpen() called twice?");
1140
0
1141
0
  if (!mPendingInputStreamLengthOperation) {
1142
0
    return false;
1143
0
  }
1144
0
1145
0
  mListener = aListener;
1146
0
  mListenerContext = aContext;
1147
0
  mAsyncOpenWaitingForStreamLength = true;
1148
0
  return true;
1149
0
}
1150
1151
void
1152
HttpBaseChannel::MaybeResumeAsyncOpen()
1153
0
{
1154
0
  MOZ_ASSERT(NS_IsMainThread());
1155
0
  MOZ_ASSERT(!mPendingInputStreamLengthOperation);
1156
0
1157
0
  if (!mAsyncOpenWaitingForStreamLength) {
1158
0
    return;
1159
0
  }
1160
0
1161
0
  nsCOMPtr<nsIStreamListener> listener;
1162
0
  listener.swap(mListener);
1163
0
1164
0
  nsCOMPtr<nsISupports> context;
1165
0
  context.swap(mListenerContext);
1166
0
1167
0
  mAsyncOpenWaitingForStreamLength = false;
1168
0
1169
0
  nsresult rv = AsyncOpen(listener, context);
1170
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
1171
0
    DoAsyncAbort(rv);
1172
0
  }
1173
0
}
1174
1175
//-----------------------------------------------------------------------------
1176
// HttpBaseChannel::nsIEncodedChannel
1177
//-----------------------------------------------------------------------------
1178
1179
NS_IMETHODIMP
1180
HttpBaseChannel::GetApplyConversion(bool *value)
1181
0
{
1182
0
  *value = mApplyConversion;
1183
0
  return NS_OK;
1184
0
}
1185
1186
NS_IMETHODIMP
1187
HttpBaseChannel::SetApplyConversion(bool value)
1188
0
{
1189
0
  LOG(("HttpBaseChannel::SetApplyConversion [this=%p value=%d]\n", this, value));
1190
0
  mApplyConversion = value;
1191
0
  return NS_OK;
1192
0
}
1193
1194
nsresult
1195
HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener,
1196
                                           nsIStreamListener** aNewNextListener)
1197
0
{
1198
0
  return DoApplyContentConversions(aNextListener,
1199
0
                                   aNewNextListener,
1200
0
                                   mListenerContext);
1201
0
}
1202
1203
// create a listener chain that looks like this
1204
// http-channel -> decompressor (n times) -> InterceptFailedOnSTop -> channel-creator-listener
1205
//
1206
// we need to do this because not every decompressor has fully streamed output so
1207
// may need a call to OnStopRequest to identify its completion state.. and if it
1208
// creates an error there the channel status code needs to be updated before calling
1209
// the terminal listener. Having the decompress do it via cancel() means channels cannot
1210
// effectively be used in two contexts (specifically this one and a peek context for
1211
// sniffing)
1212
//
1213
class InterceptFailedOnStop : public nsIStreamListener
1214
{
1215
0
  virtual ~InterceptFailedOnStop() = default;
1216
  nsCOMPtr<nsIStreamListener> mNext;
1217
  HttpBaseChannel *mChannel;
1218
1219
public:
1220
  InterceptFailedOnStop(nsIStreamListener *arg, HttpBaseChannel *chan)
1221
  : mNext(arg)
1222
0
  , mChannel(chan) {}
1223
  NS_DECL_THREADSAFE_ISUPPORTS
1224
1225
  NS_IMETHOD OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) override
1226
0
  {
1227
0
    return mNext->OnStartRequest(aRequest, aContext);
1228
0
  }
1229
1230
  NS_IMETHOD OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatusCode) override
1231
0
  {
1232
0
    if (NS_FAILED(aStatusCode) && NS_SUCCEEDED(mChannel->mStatus)) {
1233
0
      LOG(("HttpBaseChannel::InterceptFailedOnStop %p seting status %" PRIx32,
1234
0
           mChannel, static_cast<uint32_t>(aStatusCode)));
1235
0
      mChannel->mStatus = aStatusCode;
1236
0
    }
1237
0
    return mNext->OnStopRequest(aRequest, aContext, aStatusCode);
1238
0
  }
1239
1240
  NS_IMETHOD OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext,
1241
                           nsIInputStream *aInputStream, uint64_t aOffset,
1242
                           uint32_t aCount) override
1243
0
  {
1244
0
    return mNext->OnDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount);
1245
0
  }
1246
};
1247
1248
NS_IMPL_ISUPPORTS(InterceptFailedOnStop, nsIStreamListener, nsIRequestObserver)
1249
1250
NS_IMETHODIMP
1251
HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener,
1252
                                           nsIStreamListener** aNewNextListener,
1253
                                           nsISupports *aCtxt)
1254
0
{
1255
0
  *aNewNextListener = nullptr;
1256
0
  if (!mResponseHead || ! aNextListener) {
1257
0
    return NS_OK;
1258
0
  }
1259
0
1260
0
  LOG(("HttpBaseChannel::DoApplyContentConversions [this=%p]\n", this));
1261
0
1262
0
  if (!mApplyConversion) {
1263
0
    LOG(("not applying conversion per mApplyConversion\n"));
1264
0
    return NS_OK;
1265
0
  }
1266
0
1267
0
  if (!mAvailableCachedAltDataType.IsEmpty()) {
1268
0
    LOG(("not applying conversion because delivering alt-data\n"));
1269
0
    return NS_OK;
1270
0
  }
1271
0
1272
0
  nsAutoCString contentEncoding;
1273
0
  nsresult rv = mResponseHead->GetHeader(nsHttp::Content_Encoding, contentEncoding);
1274
0
  if (NS_FAILED(rv) || contentEncoding.IsEmpty())
1275
0
    return NS_OK;
1276
0
1277
0
  nsCOMPtr<nsIStreamListener> nextListener = new InterceptFailedOnStop(aNextListener, this);
1278
0
1279
0
  // The encodings are listed in the order they were applied
1280
0
  // (see rfc 2616 section 14.11), so they need to removed in reverse
1281
0
  // order. This is accomplished because the converter chain ends up
1282
0
  // being a stack with the last converter created being the first one
1283
0
  // to accept the raw network data.
1284
0
1285
0
  char* cePtr = contentEncoding.BeginWriting();
1286
0
  uint32_t count = 0;
1287
0
  while (char* val = nsCRT::strtok(cePtr, HTTP_LWS ",", &cePtr)) {
1288
0
    if (++count > 16) {
1289
0
      // That's ridiculous. We only understand 2 different ones :)
1290
0
      // but for compatibility with old code, we will just carry on without
1291
0
      // removing the encodings
1292
0
      LOG(("Too many Content-Encodings. Ignoring remainder.\n"));
1293
0
      break;
1294
0
    }
1295
0
1296
0
    bool isHTTPS = false;
1297
0
    mURI->SchemeIs("https", &isHTTPS);
1298
0
    if (gHttpHandler->IsAcceptableEncoding(val, isHTTPS)) {
1299
0
      nsCOMPtr<nsIStreamConverterService> serv;
1300
0
      rv = gHttpHandler->GetStreamConverterService(getter_AddRefs(serv));
1301
0
1302
0
      // we won't fail to load the page just because we couldn't load the
1303
0
      // stream converter service.. carry on..
1304
0
      if (NS_FAILED(rv)) {
1305
0
        if (val)
1306
0
          LOG(("Unknown content encoding '%s', ignoring\n", val));
1307
0
        continue;
1308
0
      }
1309
0
1310
0
      nsCOMPtr<nsIStreamListener> converter;
1311
0
      nsAutoCString from(val);
1312
0
      ToLowerCase(from);
1313
0
      rv = serv->AsyncConvertData(from.get(),
1314
0
                                  "uncompressed",
1315
0
                                  nextListener,
1316
0
                                  aCtxt,
1317
0
                                  getter_AddRefs(converter));
1318
0
      if (NS_FAILED(rv)) {
1319
0
        LOG(("Unexpected failure of AsyncConvertData %s\n", val));
1320
0
        return rv;
1321
0
      }
1322
0
1323
0
      LOG(("converter removed '%s' content-encoding\n", val));
1324
0
      if (gHttpHandler->IsTelemetryEnabled()) {
1325
0
        int mode = 0;
1326
0
        if (from.EqualsLiteral("gzip") || from.EqualsLiteral("x-gzip")) {
1327
0
          mode = 1;
1328
0
        } else if (from.EqualsLiteral("deflate") || from.EqualsLiteral("x-deflate")) {
1329
0
          mode = 2;
1330
0
        } else if (from.EqualsLiteral("br")) {
1331
0
          mode = 3;
1332
0
        }
1333
0
        Telemetry::Accumulate(Telemetry::HTTP_CONTENT_ENCODING, mode);
1334
0
      }
1335
0
      nextListener = converter;
1336
0
    }
1337
0
    else {
1338
0
      if (val)
1339
0
        LOG(("Unknown content encoding '%s', ignoring\n", val));
1340
0
    }
1341
0
  }
1342
0
  *aNewNextListener = nextListener;
1343
0
  NS_IF_ADDREF(*aNewNextListener);
1344
0
  return NS_OK;
1345
0
}
1346
1347
NS_IMETHODIMP
1348
HttpBaseChannel::GetContentEncodings(nsIUTF8StringEnumerator** aEncodings)
1349
0
{
1350
0
  if (!mResponseHead) {
1351
0
    *aEncodings = nullptr;
1352
0
    return NS_OK;
1353
0
  }
1354
0
1355
0
  nsAutoCString encoding;
1356
0
  Unused << mResponseHead->GetHeader(nsHttp::Content_Encoding, encoding);
1357
0
  if (encoding.IsEmpty()) {
1358
0
    *aEncodings = nullptr;
1359
0
    return NS_OK;
1360
0
  }
1361
0
  nsContentEncodings* enumerator = new nsContentEncodings(this,
1362
0
                                                          encoding.get());
1363
0
  NS_ADDREF(*aEncodings = enumerator);
1364
0
  return NS_OK;
1365
0
}
1366
1367
//-----------------------------------------------------------------------------
1368
// HttpBaseChannel::nsContentEncodings <public>
1369
//-----------------------------------------------------------------------------
1370
1371
HttpBaseChannel::nsContentEncodings::nsContentEncodings(nsIHttpChannel* aChannel,
1372
                                                        const char* aEncodingHeader)
1373
  : mEncodingHeader(aEncodingHeader)
1374
  , mChannel(aChannel)
1375
  , mReady(false)
1376
0
{
1377
0
  mCurEnd = aEncodingHeader + strlen(aEncodingHeader);
1378
0
  mCurStart = mCurEnd;
1379
0
}
1380
1381
//-----------------------------------------------------------------------------
1382
// HttpBaseChannel::nsContentEncodings::nsISimpleEnumerator
1383
//-----------------------------------------------------------------------------
1384
1385
NS_IMETHODIMP
1386
HttpBaseChannel::nsContentEncodings::HasMore(bool* aMoreEncodings)
1387
0
{
1388
0
  if (mReady) {
1389
0
    *aMoreEncodings = true;
1390
0
    return NS_OK;
1391
0
  }
1392
0
1393
0
  nsresult rv = PrepareForNext();
1394
0
  *aMoreEncodings = NS_SUCCEEDED(rv);
1395
0
  return NS_OK;
1396
0
}
1397
1398
NS_IMETHODIMP
1399
HttpBaseChannel::nsContentEncodings::GetNext(nsACString& aNextEncoding)
1400
0
{
1401
0
  aNextEncoding.Truncate();
1402
0
  if (!mReady) {
1403
0
    nsresult rv = PrepareForNext();
1404
0
    if (NS_FAILED(rv)) {
1405
0
      return NS_ERROR_FAILURE;
1406
0
    }
1407
0
  }
1408
0
1409
0
  const nsACString & encoding = Substring(mCurStart, mCurEnd);
1410
0
1411
0
  nsACString::const_iterator start, end;
1412
0
  encoding.BeginReading(start);
1413
0
  encoding.EndReading(end);
1414
0
1415
0
  bool haveType = false;
1416
0
  if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("gzip"), start, end)) {
1417
0
    aNextEncoding.AssignLiteral(APPLICATION_GZIP);
1418
0
    haveType = true;
1419
0
  }
1420
0
1421
0
  if (!haveType) {
1422
0
    encoding.BeginReading(start);
1423
0
    if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("compress"), start, end)) {
1424
0
      aNextEncoding.AssignLiteral(APPLICATION_COMPRESS);
1425
0
      haveType = true;
1426
0
    }
1427
0
  }
1428
0
1429
0
  if (!haveType) {
1430
0
    encoding.BeginReading(start);
1431
0
    if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("deflate"), start, end)) {
1432
0
      aNextEncoding.AssignLiteral(APPLICATION_ZIP);
1433
0
      haveType = true;
1434
0
    }
1435
0
  }
1436
0
1437
0
  if (!haveType) {
1438
0
    encoding.BeginReading(start);
1439
0
    if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("br"), start, end)) {
1440
0
      aNextEncoding.AssignLiteral(APPLICATION_BROTLI);
1441
0
      haveType = true;
1442
0
    }
1443
0
  }
1444
0
1445
0
  // Prepare to fetch the next encoding
1446
0
  mCurEnd = mCurStart;
1447
0
  mReady = false;
1448
0
1449
0
  if (haveType)
1450
0
    return NS_OK;
1451
0
1452
0
  NS_WARNING("Unknown encoding type");
1453
0
  return NS_ERROR_FAILURE;
1454
0
}
1455
1456
//-----------------------------------------------------------------------------
1457
// HttpBaseChannel::nsContentEncodings::nsISupports
1458
//-----------------------------------------------------------------------------
1459
1460
NS_IMPL_ISUPPORTS(HttpBaseChannel::nsContentEncodings, nsIUTF8StringEnumerator,
1461
                  nsIStringEnumerator)
1462
1463
//-----------------------------------------------------------------------------
1464
// HttpBaseChannel::nsContentEncodings <private>
1465
//-----------------------------------------------------------------------------
1466
1467
nsresult
1468
HttpBaseChannel::nsContentEncodings::PrepareForNext(void)
1469
0
{
1470
0
  MOZ_ASSERT(mCurStart == mCurEnd, "Indeterminate state");
1471
0
1472
0
  // At this point both mCurStart and mCurEnd point to somewhere
1473
0
  // past the end of the next thing we want to return
1474
0
1475
0
  while (mCurEnd != mEncodingHeader) {
1476
0
    --mCurEnd;
1477
0
    if (*mCurEnd != ',' && !nsCRT::IsAsciiSpace(*mCurEnd))
1478
0
      break;
1479
0
  }
1480
0
  if (mCurEnd == mEncodingHeader)
1481
0
    return NS_ERROR_NOT_AVAILABLE; // no more encodings
1482
0
  ++mCurEnd;
1483
0
1484
0
  // At this point mCurEnd points to the first char _after_ the
1485
0
  // header we want.  Furthermore, mCurEnd - 1 != mEncodingHeader
1486
0
1487
0
  mCurStart = mCurEnd - 1;
1488
0
  while (mCurStart != mEncodingHeader &&
1489
0
         *mCurStart != ',' && !nsCRT::IsAsciiSpace(*mCurStart))
1490
0
    --mCurStart;
1491
0
  if (*mCurStart == ',' || nsCRT::IsAsciiSpace(*mCurStart))
1492
0
    ++mCurStart; // we stopped because of a weird char, so move up one
1493
0
1494
0
  // At this point mCurStart and mCurEnd bracket the encoding string
1495
0
  // we want.  Check that it's not "identity"
1496
0
  if (Substring(mCurStart, mCurEnd).Equals("identity",
1497
0
                                           nsCaseInsensitiveCStringComparator())) {
1498
0
    mCurEnd = mCurStart;
1499
0
    return PrepareForNext();
1500
0
  }
1501
0
1502
0
  mReady = true;
1503
0
  return NS_OK;
1504
0
}
1505
1506
1507
//-----------------------------------------------------------------------------
1508
// HttpBaseChannel::nsIHttpChannel
1509
//-----------------------------------------------------------------------------
1510
1511
NS_IMETHODIMP
1512
HttpBaseChannel::GetChannelId(uint64_t *aChannelId)
1513
0
{
1514
0
  NS_ENSURE_ARG_POINTER(aChannelId);
1515
0
  *aChannelId = mChannelId;
1516
0
  return NS_OK;
1517
0
}
1518
1519
NS_IMETHODIMP
1520
HttpBaseChannel::SetChannelId(uint64_t aChannelId)
1521
0
{
1522
0
  mChannelId = aChannelId;
1523
0
  return NS_OK;
1524
0
}
1525
1526
NS_IMETHODIMP HttpBaseChannel::GetTopLevelContentWindowId(uint64_t *aWindowId)
1527
0
{
1528
0
  if (!mContentWindowId) {
1529
0
    nsCOMPtr<nsILoadContext> loadContext;
1530
0
    GetCallback(loadContext);
1531
0
    if (loadContext) {
1532
0
      nsCOMPtr<mozIDOMWindowProxy> topWindow;
1533
0
      loadContext->GetTopWindow(getter_AddRefs(topWindow));
1534
0
      nsCOMPtr<nsIDOMWindowUtils> windowUtils;
1535
0
      if (topWindow) {
1536
0
        windowUtils = nsGlobalWindowOuter::Cast(topWindow)->WindowUtils();
1537
0
      }
1538
0
      if (windowUtils) {
1539
0
        windowUtils->GetCurrentInnerWindowID(&mContentWindowId);
1540
0
      }
1541
0
    }
1542
0
  }
1543
0
  *aWindowId = mContentWindowId;
1544
0
  return NS_OK;
1545
0
}
1546
1547
NS_IMETHODIMP HttpBaseChannel::SetTopLevelOuterContentWindowId(uint64_t aWindowId)
1548
0
{
1549
0
  mTopLevelOuterContentWindowId = aWindowId;
1550
0
  return NS_OK;
1551
0
}
1552
1553
NS_IMETHODIMP HttpBaseChannel::GetTopLevelOuterContentWindowId(uint64_t *aWindowId)
1554
0
{
1555
0
  EnsureTopLevelOuterContentWindowId();
1556
0
  *aWindowId = mTopLevelOuterContentWindowId;
1557
0
  return NS_OK;
1558
0
}
1559
1560
NS_IMETHODIMP HttpBaseChannel::SetTopLevelContentWindowId(uint64_t aWindowId)
1561
0
{
1562
0
  mContentWindowId = aWindowId;
1563
0
  return NS_OK;
1564
0
}
1565
1566
NS_IMETHODIMP
1567
HttpBaseChannel::GetIsTrackingResource(bool* aIsTrackingResource)
1568
0
{
1569
0
  MOZ_ASSERT(!(mIsFirstPartyTrackingResource && mIsThirdPartyTrackingResource));
1570
0
  *aIsTrackingResource =
1571
0
    mIsThirdPartyTrackingResource || mIsFirstPartyTrackingResource;
1572
0
  return NS_OK;
1573
0
}
1574
1575
NS_IMETHODIMP
1576
HttpBaseChannel::GetIsThirdPartyTrackingResource(bool* aIsTrackingResource)
1577
0
{
1578
0
  MOZ_ASSERT(!(mIsFirstPartyTrackingResource && mIsThirdPartyTrackingResource));
1579
0
  *aIsTrackingResource = mIsThirdPartyTrackingResource;
1580
0
  return NS_OK;
1581
0
}
1582
1583
NS_IMETHODIMP
1584
HttpBaseChannel::OverrideTrackingFlagsForDocumentCookieAccessor(nsIHttpChannel* aDocumentChannel)
1585
0
{
1586
0
  LOG(("HttpBaseChannel::OverrideTrackingFlagsForDocumentCookieAccessor() %p "
1587
0
       "mIsFirstPartyTrackingResource=%d  mIsThirdPartyTrackingResource=%d",
1588
0
       this, static_cast<int>(mIsFirstPartyTrackingResource),
1589
0
       static_cast<int>(mIsThirdPartyTrackingResource)));
1590
0
1591
0
  // The semantics we'd like to achieve here are that document.cookie
1592
0
  // should follow the same rules that the document is subject to with
1593
0
  // regards to content blocking. Therefore we need to propagate the
1594
0
  // same flags from the document channel to the fake channel here.
1595
0
  if (aDocumentChannel->GetIsThirdPartyTrackingResource()) {
1596
0
    mIsThirdPartyTrackingResource = true;
1597
0
  } else {
1598
0
    mIsFirstPartyTrackingResource = true;
1599
0
  }
1600
0
1601
0
  MOZ_ASSERT(!(mIsFirstPartyTrackingResource && mIsThirdPartyTrackingResource));
1602
0
  return NS_OK;
1603
0
}
1604
1605
NS_IMETHODIMP
1606
HttpBaseChannel::GetTransferSize(uint64_t *aTransferSize)
1607
0
{
1608
0
  *aTransferSize = mTransferSize;
1609
0
  return NS_OK;
1610
0
}
1611
1612
NS_IMETHODIMP
1613
HttpBaseChannel::GetDecodedBodySize(uint64_t *aDecodedBodySize)
1614
0
{
1615
0
  *aDecodedBodySize = mDecodedBodySize;
1616
0
  return NS_OK;
1617
0
}
1618
1619
NS_IMETHODIMP
1620
HttpBaseChannel::GetEncodedBodySize(uint64_t *aEncodedBodySize)
1621
0
{
1622
0
  *aEncodedBodySize = mEncodedBodySize;
1623
0
  return NS_OK;
1624
0
}
1625
1626
NS_IMETHODIMP
1627
HttpBaseChannel::GetRequestMethod(nsACString& aMethod)
1628
0
{
1629
0
  mRequestHead.Method(aMethod);
1630
0
  return NS_OK;
1631
0
}
1632
1633
NS_IMETHODIMP
1634
HttpBaseChannel::SetRequestMethod(const nsACString& aMethod)
1635
0
{
1636
0
  ENSURE_CALLED_BEFORE_CONNECT();
1637
0
1638
0
  const nsCString& flatMethod = PromiseFlatCString(aMethod);
1639
0
1640
0
  // Method names are restricted to valid HTTP tokens.
1641
0
  if (!nsHttp::IsValidToken(flatMethod))
1642
0
    return NS_ERROR_INVALID_ARG;
1643
0
1644
0
  mRequestHead.SetMethod(flatMethod);
1645
0
  return NS_OK;
1646
0
}
1647
1648
NS_IMETHODIMP
1649
HttpBaseChannel::GetReferrer(nsIURI **referrer)
1650
0
{
1651
0
  NS_ENSURE_ARG_POINTER(referrer);
1652
0
  *referrer = mReferrer;
1653
0
  NS_IF_ADDREF(*referrer);
1654
0
  return NS_OK;
1655
0
}
1656
1657
NS_IMETHODIMP
1658
HttpBaseChannel::SetReferrer(nsIURI *referrer)
1659
0
{
1660
0
  bool isPrivate = mLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
1661
0
  return SetReferrerWithPolicy(referrer, NS_GetDefaultReferrerPolicy(isPrivate));
1662
0
}
1663
1664
NS_IMETHODIMP
1665
HttpBaseChannel::GetReferrerPolicy(uint32_t *referrerPolicy)
1666
0
{
1667
0
  NS_ENSURE_ARG_POINTER(referrerPolicy);
1668
0
  *referrerPolicy = mReferrerPolicy;
1669
0
  return NS_OK;
1670
0
}
1671
1672
1673
 /* Computing whether our URI is cross-origin may be expensive, so please do
1674
  * that in cases where we're going to use this information later on.
1675
  */
1676
bool
1677
HttpBaseChannel::IsCrossOriginWithReferrer()
1678
0
{
1679
0
  nsresult rv;
1680
0
  nsCOMPtr<nsIURI> triggeringURI;
1681
0
  if (mLoadInfo) {
1682
0
    nsCOMPtr<nsIPrincipal> triggeringPrincipal = mLoadInfo->TriggeringPrincipal();
1683
0
    if (triggeringPrincipal) {
1684
0
      triggeringPrincipal->GetURI(getter_AddRefs(triggeringURI));
1685
0
    }
1686
0
  }
1687
0
  if (triggeringURI) {
1688
0
    if (LOG_ENABLED()) {
1689
0
      nsAutoCString triggeringURISpec;
1690
0
      triggeringURI->GetAsciiSpec(triggeringURISpec);
1691
0
      LOG(("triggeringURI=%s\n", triggeringURISpec.get()));
1692
0
    }
1693
0
    nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
1694
0
    bool isPrivateWin = mLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
1695
0
    rv = ssm->CheckSameOriginURI(triggeringURI, mURI, false, isPrivateWin);
1696
0
    return (NS_FAILED(rv));
1697
0
  }
1698
0
1699
0
  LOG(("no triggering principal available via loadInfo, assuming load is cross-origin"));
1700
0
  return true;
1701
0
}
1702
1703
NS_IMETHODIMP
1704
HttpBaseChannel::SetReferrerWithPolicy(nsIURI *referrer,
1705
                                       uint32_t referrerPolicy)
1706
0
{
1707
0
  ENSURE_CALLED_BEFORE_CONNECT();
1708
0
1709
0
  mReferrerPolicy = referrerPolicy;
1710
0
1711
0
  // clear existing referrer, if any
1712
0
  mReferrer = nullptr;
1713
0
  nsresult rv = mRequestHead.ClearHeader(nsHttp::Referer);
1714
0
  if(NS_FAILED(rv)) {
1715
0
    return rv;
1716
0
  }
1717
0
1718
0
  if (mReferrerPolicy == REFERRER_POLICY_UNSET) {
1719
0
    bool isPrivate = mLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
1720
0
    mReferrerPolicy = NS_GetDefaultReferrerPolicy(isPrivate);
1721
0
  }
1722
0
1723
0
  if (!referrer) {
1724
0
    return NS_OK;
1725
0
  }
1726
0
1727
0
  // Don't send referrer at all when the meta referrer setting is "no-referrer"
1728
0
  if (mReferrerPolicy == REFERRER_POLICY_NO_REFERRER) {
1729
0
    return NS_OK;
1730
0
  }
1731
0
1732
0
  // 0: never send referer
1733
0
  // 1: send referer for direct user action
1734
0
  // 2: always send referer
1735
0
  uint32_t userReferrerLevel = gHttpHandler->ReferrerLevel();
1736
0
1737
0
  // false: use real referrer
1738
0
  // true: spoof with URI of the current request
1739
0
  bool userSpoofReferrerSource = gHttpHandler->SpoofReferrerSource();
1740
0
1741
0
  // false: use real referrer when leaving .onion
1742
0
  // true: use an empty referrer
1743
0
  bool userHideOnionReferrerSource = gHttpHandler->HideOnionReferrerSource();
1744
0
1745
0
  // 0: send referer no matter what
1746
0
  // 1: send referer ONLY when base domains match
1747
0
  // 2: send referer ONLY when hosts match
1748
0
  int userReferrerXOriginPolicy = gHttpHandler->ReferrerXOriginPolicy();
1749
0
1750
0
  // check referrer blocking pref
1751
0
  uint32_t referrerLevel;
1752
0
  if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI) {
1753
0
    referrerLevel = 1; // user action
1754
0
  } else {
1755
0
    referrerLevel = 2; // inline content
1756
0
  }
1757
0
  if (userReferrerLevel < referrerLevel) {
1758
0
    return NS_OK;
1759
0
  }
1760
0
1761
0
  nsCOMPtr<nsIURI> referrerGrip;
1762
0
  bool match;
1763
0
1764
0
  //
1765
0
  // Strip off "wyciwyg://123/" from wyciwyg referrers.
1766
0
  //
1767
0
  // XXX this really belongs elsewhere since wyciwyg URLs aren't part of necko.
1768
0
  //   perhaps some sort of generic nsINestedURI could be used.  then, if an URI
1769
0
  //   fails the whitelist test, then we could check for an inner URI and try
1770
0
  //   that instead.  though, that might be too automatic.
1771
0
  //
1772
0
  rv = referrer->SchemeIs("wyciwyg", &match);
1773
0
  if (NS_FAILED(rv)) return rv;
1774
0
  if (match) {
1775
0
    nsAutoCString path;
1776
0
    rv = referrer->GetPathQueryRef(path);
1777
0
    if (NS_FAILED(rv)) return rv;
1778
0
1779
0
    uint32_t pathLength = path.Length();
1780
0
    if (pathLength <= 2) return NS_ERROR_FAILURE;
1781
0
1782
0
    // Path is of the form "//123/http://foo/bar", with a variable number of
1783
0
    // digits. To figure out where the "real" URL starts, search path for a
1784
0
    // '/', starting at the third character.
1785
0
    int32_t slashIndex = path.FindChar('/', 2);
1786
0
    if (slashIndex == kNotFound) return NS_ERROR_FAILURE;
1787
0
1788
0
    // Replace |referrer| with a URI without wyciwyg://123/.
1789
0
    rv = NS_NewURI(getter_AddRefs(referrerGrip),
1790
0
                   Substring(path, slashIndex + 1, pathLength - slashIndex - 1));
1791
0
    if (NS_FAILED(rv)) return rv;
1792
0
1793
0
    referrer = referrerGrip.get();
1794
0
  }
1795
0
1796
0
  // Enforce Referrer whitelist
1797
0
  if (!IsReferrerSchemeAllowed(referrer)) {
1798
0
    return NS_OK; // kick out....
1799
0
  }
1800
0
1801
0
  //
1802
0
  // Handle secure referrals.
1803
0
  //
1804
0
  // Support referrals from a secure server if this is a secure site
1805
0
  // and (optionally) if the host names are the same.
1806
0
  //
1807
0
  rv = referrer->SchemeIs("https", &match);
1808
0
  if (NS_FAILED(rv)) return rv;
1809
0
1810
0
  if (match) {
1811
0
    rv = mURI->SchemeIs("https", &match);
1812
0
    if (NS_FAILED(rv)) return rv;
1813
0
1814
0
    // It's ok to send referrer for https-to-http scenarios if the referrer
1815
0
    // policy is "unsafe-url", "origin", or "origin-when-cross-origin".
1816
0
    if (mReferrerPolicy != REFERRER_POLICY_UNSAFE_URL &&
1817
0
        mReferrerPolicy != REFERRER_POLICY_ORIGIN_WHEN_XORIGIN &&
1818
0
        mReferrerPolicy != REFERRER_POLICY_ORIGIN) {
1819
0
1820
0
      // in other referrer policies, https->http is not allowed...
1821
0
      if (!match) return NS_OK;
1822
0
    }
1823
0
  }
1824
0
1825
0
  nsCOMPtr<nsIURI> clone;
1826
0
  //
1827
0
  // we need to clone the referrer, so we can:
1828
0
  //  (1) modify it
1829
0
  //  (2) keep a reference to it after returning from this function
1830
0
  //
1831
0
  // Strip away any fragment per RFC 2616 section 14.36
1832
0
  // and Referrer Policy section 6.3.5.
1833
0
  rv = NS_GetURIWithoutRef(referrer, getter_AddRefs(clone));
1834
0
  if (NS_FAILED(rv)) return rv;
1835
0
1836
0
  nsAutoCString currentHost;
1837
0
  nsAutoCString referrerHost;
1838
0
1839
0
  rv = mURI->GetAsciiHost(currentHost);
1840
0
  if (NS_FAILED(rv)) return rv;
1841
0
1842
0
  rv = clone->GetAsciiHost(referrerHost);
1843
0
  if (NS_FAILED(rv)) return rv;
1844
0
1845
0
  // Send an empty referrer if leaving a .onion domain.
1846
0
  if(userHideOnionReferrerSource &&
1847
0
     !currentHost.Equals(referrerHost) &&
1848
0
     StringEndsWith(referrerHost, NS_LITERAL_CSTRING(".onion"))) {
1849
0
    return NS_OK;
1850
0
  }
1851
0
1852
0
  // check policy for sending ref only when hosts match
1853
0
  if (userReferrerXOriginPolicy == 2 && !currentHost.Equals(referrerHost))
1854
0
    return NS_OK;
1855
0
1856
0
  if (userReferrerXOriginPolicy == 1) {
1857
0
    nsAutoCString currentDomain = currentHost;
1858
0
    nsAutoCString referrerDomain = referrerHost;
1859
0
    uint32_t extraDomains = 0;
1860
0
    nsCOMPtr<nsIEffectiveTLDService> eTLDService = do_GetService(
1861
0
      NS_EFFECTIVETLDSERVICE_CONTRACTID);
1862
0
    if (eTLDService) {
1863
0
      rv = eTLDService->GetBaseDomain(mURI, extraDomains, currentDomain);
1864
0
      if (NS_FAILED(rv)) return rv;
1865
0
      rv = eTLDService->GetBaseDomain(clone, extraDomains, referrerDomain);
1866
0
      if (NS_FAILED(rv)) return rv;
1867
0
    }
1868
0
1869
0
    // check policy for sending only when effective top level domain matches.
1870
0
    // this falls back on using host if eTLDService does not work
1871
0
    if (!currentDomain.Equals(referrerDomain))
1872
0
      return NS_OK;
1873
0
  }
1874
0
1875
0
  // send spoofed referrer if desired
1876
0
  if (userSpoofReferrerSource) {
1877
0
    nsCOMPtr<nsIURI> mURIclone;
1878
0
    rv = NS_GetURIWithoutRef(mURI, getter_AddRefs(mURIclone));
1879
0
    if (NS_FAILED(rv)) return rv;
1880
0
    clone = mURIclone;
1881
0
    currentHost = referrerHost;
1882
0
  }
1883
0
1884
0
  // strip away any userpass; we don't want to be giving out passwords ;-)
1885
0
  // This is required by Referrer Policy stripping algorithm.
1886
0
  rv = NS_MutateURI(clone)
1887
0
         .SetUserPass(EmptyCString())
1888
0
         .Finalize(clone);
1889
0
  if (NS_FAILED(rv)) return rv;
1890
0
1891
0
  // 0: full URI
1892
0
  // 1: scheme+host+port+path
1893
0
  // 2: scheme+host+port
1894
0
  int userReferrerTrimmingPolicy = gHttpHandler->ReferrerTrimmingPolicy();
1895
0
  int userReferrerXOriginTrimmingPolicy =
1896
0
    gHttpHandler->ReferrerXOriginTrimmingPolicy();
1897
0
1898
0
  switch (mReferrerPolicy) {
1899
0
    case REFERRER_POLICY_SAME_ORIGIN:
1900
0
      // Don't send referrer when the request is cross-origin and policy is "same-origin".
1901
0
      if (IsCrossOriginWithReferrer()) {
1902
0
        return NS_OK;
1903
0
      }
1904
0
      break;
1905
0
1906
0
    case REFERRER_POLICY_ORIGIN:
1907
0
    case REFERRER_POLICY_STRICT_ORIGIN:
1908
0
      userReferrerTrimmingPolicy = 2;
1909
0
      break;
1910
0
1911
0
    case REFERRER_POLICY_ORIGIN_WHEN_XORIGIN:
1912
0
    case REFERRER_POLICY_STRICT_ORIGIN_WHEN_XORIGIN:
1913
0
      if (userReferrerTrimmingPolicy != 2 && IsCrossOriginWithReferrer()) {
1914
0
        // Ignore set userReferrerTrimmingPolicy if it is already the strictest
1915
0
        // policy.
1916
0
        userReferrerTrimmingPolicy = 2;
1917
0
      }
1918
0
      break;
1919
0
1920
0
    case REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE:
1921
0
    case REFERRER_POLICY_UNSAFE_URL:
1922
0
      if (userReferrerTrimmingPolicy != 2) {
1923
0
        // Ignore set userReferrerTrimmingPolicy if it is already the strictest
1924
0
        // policy. Apply the user cross-origin trimming policy if it's more
1925
0
        // restrictive than the general one.
1926
0
        if (userReferrerXOriginTrimmingPolicy != 0 && IsCrossOriginWithReferrer()) {
1927
0
          userReferrerTrimmingPolicy =
1928
0
            std::max(userReferrerTrimmingPolicy, userReferrerXOriginTrimmingPolicy);
1929
0
        }
1930
0
      }
1931
0
1932
0
      break;
1933
0
1934
0
    case REFERRER_POLICY_NO_REFERRER:
1935
0
    case REFERRER_POLICY_UNSET:
1936
0
    default:
1937
0
      MOZ_ASSERT_UNREACHABLE("Unexpected value");
1938
0
      break;
1939
0
  }
1940
0
1941
0
  nsAutoCString spec;
1942
0
  // check how much referer to send
1943
0
  if (userReferrerTrimmingPolicy) {
1944
0
    // All output strings start with: scheme+host+port
1945
0
    // We want the IDN-normalized PrePath.  That's not something currently
1946
0
    // available and there doesn't yet seem to be justification for adding it to
1947
0
    // the interfaces, so just build it up ourselves from scheme+AsciiHostPort
1948
0
    nsAutoCString scheme, asciiHostPort;
1949
0
    rv = clone->GetScheme(scheme);
1950
0
    if (NS_FAILED(rv)) return rv;
1951
0
    spec = scheme;
1952
0
    spec.AppendLiteral("://");
1953
0
    // Note we explicitly cleared UserPass above, so do not need to build it.
1954
0
    rv = clone->GetAsciiHostPort(asciiHostPort);
1955
0
    if (NS_FAILED(rv)) return rv;
1956
0
    spec.Append(asciiHostPort);
1957
0
1958
0
    switch (userReferrerTrimmingPolicy) {
1959
0
      case 1: { // scheme+host+port+path
1960
0
        nsCOMPtr<nsIURL> url(do_QueryInterface(clone));
1961
0
        if (url) {
1962
0
          nsAutoCString path;
1963
0
          rv = url->GetFilePath(path);
1964
0
          if (NS_FAILED(rv)) return rv;
1965
0
          spec.Append(path);
1966
0
          rv = NS_MutateURI(url)
1967
0
                 .SetQuery(EmptyCString())
1968
0
                 .SetRef(EmptyCString())
1969
0
                 .Finalize(clone);
1970
0
          if (NS_FAILED(rv)) return rv;
1971
0
          break;
1972
0
        }
1973
0
        // No URL, so fall through to truncating the path and any query/ref off
1974
0
        // as well.
1975
0
      }
1976
0
      MOZ_FALLTHROUGH;
1977
0
      default: // (Pref limited to [0,2] enforced by clamp, MOZ_CRASH overkill.)
1978
0
      case 2: // scheme+host+port+/
1979
0
        spec.AppendLiteral("/");
1980
0
        // This nukes any query/ref present as well in the case of nsStandardURL
1981
0
        rv = NS_MutateURI(clone)
1982
0
               .SetPathQueryRef(EmptyCString())
1983
0
               .Finalize(clone);
1984
0
        if (NS_FAILED(rv)) return rv;
1985
0
        break;
1986
0
    }
1987
0
  } else {
1988
0
    // use the full URI
1989
0
    rv = clone->GetAsciiSpec(spec);
1990
0
    if (NS_FAILED(rv)) return rv;
1991
0
  }
1992
0
1993
0
  // finally, remember the referrer URI and set the Referer header.
1994
0
  rv = SetRequestHeader(NS_LITERAL_CSTRING("Referer"), spec, false);
1995
0
  if (NS_FAILED(rv)) return rv;
1996
0
1997
0
  mReferrer = clone;
1998
0
  return NS_OK;
1999
0
}
2000
2001
// Return the channel's proxy URI, or if it doesn't exist, the
2002
// channel's main URI.
2003
NS_IMETHODIMP
2004
HttpBaseChannel::GetProxyURI(nsIURI **aOut)
2005
0
{
2006
0
  NS_ENSURE_ARG_POINTER(aOut);
2007
0
  nsCOMPtr<nsIURI> result(mProxyURI);
2008
0
  result.forget(aOut);
2009
0
  return NS_OK;
2010
0
}
2011
2012
NS_IMETHODIMP
2013
HttpBaseChannel::GetRequestHeader(const nsACString& aHeader,
2014
                                  nsACString& aValue)
2015
0
{
2016
0
  aValue.Truncate();
2017
0
2018
0
  // XXX might be better to search the header list directly instead of
2019
0
  // hitting the http atom hash table.
2020
0
  nsHttpAtom atom = nsHttp::ResolveAtom(aHeader);
2021
0
  if (!atom)
2022
0
    return NS_ERROR_NOT_AVAILABLE;
2023
0
2024
0
  return mRequestHead.GetHeader(atom, aValue);
2025
0
}
2026
2027
NS_IMETHODIMP
2028
HttpBaseChannel::SetRequestHeader(const nsACString& aHeader,
2029
                                  const nsACString& aValue,
2030
                                  bool aMerge)
2031
0
{
2032
0
  const nsCString &flatHeader = PromiseFlatCString(aHeader);
2033
0
  const nsCString &flatValue  = PromiseFlatCString(aValue);
2034
0
2035
0
  LOG(("HttpBaseChannel::SetRequestHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
2036
0
      this, flatHeader.get(), flatValue.get(), aMerge));
2037
0
2038
0
  // Verify header names are valid HTTP tokens and header values are reasonably
2039
0
  // close to whats allowed in RFC 2616.
2040
0
  if (!nsHttp::IsValidToken(flatHeader) ||
2041
0
      !nsHttp::IsReasonableHeaderValue(flatValue)) {
2042
0
    return NS_ERROR_INVALID_ARG;
2043
0
  }
2044
0
2045
0
  return mRequestHead.SetHeader(aHeader, flatValue, aMerge);
2046
0
}
2047
2048
NS_IMETHODIMP
2049
HttpBaseChannel::SetEmptyRequestHeader(const nsACString& aHeader)
2050
0
{
2051
0
  const nsCString &flatHeader = PromiseFlatCString(aHeader);
2052
0
2053
0
  LOG(("HttpBaseChannel::SetEmptyRequestHeader [this=%p header=\"%s\"]\n",
2054
0
      this, flatHeader.get()));
2055
0
2056
0
  // Verify header names are valid HTTP tokens and header values are reasonably
2057
0
  // close to whats allowed in RFC 2616.
2058
0
  if (!nsHttp::IsValidToken(flatHeader)) {
2059
0
    return NS_ERROR_INVALID_ARG;
2060
0
  }
2061
0
2062
0
  return mRequestHead.SetEmptyHeader(aHeader);
2063
0
}
2064
2065
NS_IMETHODIMP
2066
HttpBaseChannel::VisitRequestHeaders(nsIHttpHeaderVisitor *visitor)
2067
0
{
2068
0
  return mRequestHead.VisitHeaders(visitor);
2069
0
}
2070
2071
NS_IMETHODIMP
2072
HttpBaseChannel::VisitNonDefaultRequestHeaders(nsIHttpHeaderVisitor *visitor)
2073
0
{
2074
0
  return mRequestHead.VisitHeaders(visitor,
2075
0
                                   nsHttpHeaderArray::eFilterSkipDefault);
2076
0
}
2077
2078
NS_IMETHODIMP
2079
HttpBaseChannel::GetResponseHeader(const nsACString &header, nsACString &value)
2080
0
{
2081
0
  value.Truncate();
2082
0
2083
0
  if (!mResponseHead)
2084
0
    return NS_ERROR_NOT_AVAILABLE;
2085
0
2086
0
  nsHttpAtom atom = nsHttp::ResolveAtom(header);
2087
0
  if (!atom)
2088
0
    return NS_ERROR_NOT_AVAILABLE;
2089
0
2090
0
  return mResponseHead->GetHeader(atom, value);
2091
0
}
2092
2093
NS_IMETHODIMP
2094
HttpBaseChannel::SetResponseHeader(const nsACString& header,
2095
                                   const nsACString& value,
2096
                                   bool merge)
2097
0
{
2098
0
  LOG(("HttpBaseChannel::SetResponseHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
2099
0
      this, PromiseFlatCString(header).get(), PromiseFlatCString(value).get(), merge));
2100
0
2101
0
  if (!mResponseHead)
2102
0
    return NS_ERROR_NOT_AVAILABLE;
2103
0
2104
0
  nsHttpAtom atom = nsHttp::ResolveAtom(header);
2105
0
  if (!atom)
2106
0
    return NS_ERROR_NOT_AVAILABLE;
2107
0
2108
0
  // these response headers must not be changed
2109
0
  if (atom == nsHttp::Content_Type ||
2110
0
      atom == nsHttp::Content_Length ||
2111
0
      atom == nsHttp::Content_Encoding ||
2112
0
      atom == nsHttp::Trailer ||
2113
0
      atom == nsHttp::Transfer_Encoding)
2114
0
    return NS_ERROR_ILLEGAL_VALUE;
2115
0
2116
0
  mResponseHeadersModified = true;
2117
0
2118
0
  return mResponseHead->SetHeader(header, value, merge);
2119
0
}
2120
2121
NS_IMETHODIMP
2122
HttpBaseChannel::VisitResponseHeaders(nsIHttpHeaderVisitor *visitor)
2123
0
{
2124
0
  if (!mResponseHead) {
2125
0
    return NS_ERROR_NOT_AVAILABLE;
2126
0
  }
2127
0
  return mResponseHead->VisitHeaders(visitor,
2128
0
    nsHttpHeaderArray::eFilterResponse);
2129
0
}
2130
2131
NS_IMETHODIMP
2132
HttpBaseChannel::GetOriginalResponseHeader(const nsACString& aHeader,
2133
                                           nsIHttpHeaderVisitor *aVisitor)
2134
0
{
2135
0
  if (!mResponseHead) {
2136
0
    return NS_ERROR_NOT_AVAILABLE;
2137
0
  }
2138
0
2139
0
  nsHttpAtom atom = nsHttp::ResolveAtom(aHeader);
2140
0
  if (!atom) {
2141
0
    return NS_ERROR_NOT_AVAILABLE;
2142
0
  }
2143
0
2144
0
  return mResponseHead->GetOriginalHeader(atom, aVisitor);
2145
0
}
2146
2147
NS_IMETHODIMP
2148
HttpBaseChannel::VisitOriginalResponseHeaders(nsIHttpHeaderVisitor *aVisitor)
2149
0
{
2150
0
  if (!mResponseHead) {
2151
0
    return NS_ERROR_NOT_AVAILABLE;
2152
0
  }
2153
0
2154
0
  return mResponseHead->VisitHeaders(aVisitor,
2155
0
      nsHttpHeaderArray::eFilterResponseOriginal);
2156
0
}
2157
2158
NS_IMETHODIMP
2159
HttpBaseChannel::GetAllowPipelining(bool *value)
2160
0
{
2161
0
  NS_ENSURE_ARG_POINTER(value);
2162
0
  *value = false;
2163
0
  return NS_OK;
2164
0
}
2165
2166
NS_IMETHODIMP
2167
HttpBaseChannel::SetAllowPipelining(bool value)
2168
0
{
2169
0
  ENSURE_CALLED_BEFORE_CONNECT();
2170
0
  // nop
2171
0
  return NS_OK;
2172
0
}
2173
2174
NS_IMETHODIMP
2175
HttpBaseChannel::GetAllowSTS(bool *value)
2176
0
{
2177
0
  NS_ENSURE_ARG_POINTER(value);
2178
0
  *value = mAllowSTS;
2179
0
  return NS_OK;
2180
0
}
2181
2182
NS_IMETHODIMP
2183
HttpBaseChannel::SetAllowSTS(bool value)
2184
0
{
2185
0
  ENSURE_CALLED_BEFORE_CONNECT();
2186
0
2187
0
  mAllowSTS = value;
2188
0
  return NS_OK;
2189
0
}
2190
2191
NS_IMETHODIMP
2192
HttpBaseChannel::GetRedirectionLimit(uint32_t *value)
2193
0
{
2194
0
  NS_ENSURE_ARG_POINTER(value);
2195
0
  *value = mRedirectionLimit;
2196
0
  return NS_OK;
2197
0
}
2198
2199
NS_IMETHODIMP
2200
HttpBaseChannel::SetRedirectionLimit(uint32_t value)
2201
0
{
2202
0
  ENSURE_CALLED_BEFORE_CONNECT();
2203
0
2204
0
  mRedirectionLimit = std::min<uint32_t>(value, 0xff);
2205
0
  return NS_OK;
2206
0
}
2207
2208
nsresult
2209
HttpBaseChannel::OverrideSecurityInfo(nsISupports* aSecurityInfo)
2210
0
{
2211
0
  MOZ_ASSERT(!mSecurityInfo,
2212
0
             "This can only be called when we don't have a security info object already");
2213
0
  MOZ_RELEASE_ASSERT(aSecurityInfo,
2214
0
                     "This can only be called with a valid security info object");
2215
0
  MOZ_ASSERT(!BypassServiceWorker(),
2216
0
             "This can only be called on channels that are not bypassing interception");
2217
0
  MOZ_ASSERT(mResponseCouldBeSynthesized,
2218
0
             "This can only be called on channels that can be intercepted");
2219
0
  if (mSecurityInfo) {
2220
0
    LOG(("HttpBaseChannel::OverrideSecurityInfo mSecurityInfo is null! "
2221
0
         "[this=%p]\n", this));
2222
0
    return NS_ERROR_UNEXPECTED;
2223
0
  }
2224
0
  if (!mResponseCouldBeSynthesized) {
2225
0
    LOG(("HttpBaseChannel::OverrideSecurityInfo channel cannot be intercepted! "
2226
0
         "[this=%p]\n", this));
2227
0
    return NS_ERROR_UNEXPECTED;
2228
0
  }
2229
0
2230
0
  mSecurityInfo = aSecurityInfo;
2231
0
  return NS_OK;
2232
0
}
2233
2234
NS_IMETHODIMP
2235
HttpBaseChannel::IsNoStoreResponse(bool *value)
2236
0
{
2237
0
  if (!mResponseHead)
2238
0
    return NS_ERROR_NOT_AVAILABLE;
2239
0
  *value = mResponseHead->NoStore();
2240
0
  return NS_OK;
2241
0
}
2242
2243
NS_IMETHODIMP
2244
HttpBaseChannel::IsNoCacheResponse(bool *value)
2245
0
{
2246
0
  if (!mResponseHead)
2247
0
    return NS_ERROR_NOT_AVAILABLE;
2248
0
  *value = mResponseHead->NoCache();
2249
0
  if (!*value)
2250
0
    *value = mResponseHead->ExpiresInPast();
2251
0
  return NS_OK;
2252
0
}
2253
2254
NS_IMETHODIMP
2255
HttpBaseChannel::IsPrivateResponse(bool *value)
2256
0
{
2257
0
  if (!mResponseHead)
2258
0
    return NS_ERROR_NOT_AVAILABLE;
2259
0
  *value = mResponseHead->Private();
2260
0
  return NS_OK;
2261
0
}
2262
2263
NS_IMETHODIMP
2264
HttpBaseChannel::GetResponseStatus(uint32_t *aValue)
2265
0
{
2266
0
  if (!mResponseHead)
2267
0
    return NS_ERROR_NOT_AVAILABLE;
2268
0
  *aValue = mResponseHead->Status();
2269
0
  return NS_OK;
2270
0
}
2271
2272
NS_IMETHODIMP
2273
HttpBaseChannel::GetResponseStatusText(nsACString& aValue)
2274
0
{
2275
0
  if (!mResponseHead)
2276
0
    return NS_ERROR_NOT_AVAILABLE;
2277
0
  mResponseHead->StatusText(aValue);
2278
0
  return NS_OK;
2279
0
}
2280
2281
NS_IMETHODIMP
2282
HttpBaseChannel::GetRequestSucceeded(bool *aValue)
2283
0
{
2284
0
  if (!mResponseHead)
2285
0
    return NS_ERROR_NOT_AVAILABLE;
2286
0
  uint32_t status = mResponseHead->Status();
2287
0
  *aValue = (status / 100 == 2);
2288
0
  return NS_OK;
2289
0
}
2290
2291
NS_IMETHODIMP
2292
HttpBaseChannel::RedirectTo(nsIURI *targetURI)
2293
0
{
2294
0
  NS_ENSURE_ARG(targetURI);
2295
0
2296
0
  nsAutoCString spec;
2297
0
  targetURI->GetAsciiSpec(spec);
2298
0
  LOG(("HttpBaseChannel::RedirectTo [this=%p, uri=%s]", this, spec.get()));
2299
0
  LogCallingScriptLocation(this);
2300
0
2301
0
  // We cannot redirect after OnStartRequest of the listener
2302
0
  // has been called, since to redirect we have to switch channels
2303
0
  // and the dance with OnStartRequest et al has to start over.
2304
0
  // This would break the nsIStreamListener contract.
2305
0
  NS_ENSURE_FALSE(mOnStartRequestCalled, NS_ERROR_NOT_AVAILABLE);
2306
0
2307
0
  mAPIRedirectToURI = targetURI;
2308
0
  // Only Web Extensions are allowed to redirect a channel to a data:
2309
0
  // URI. To avoid any bypasses after the channel was flagged by
2310
0
  // the WebRequst API, we are dropping the flag here.
2311
0
  if (mLoadInfo) {
2312
0
    mLoadInfo->SetAllowInsecureRedirectToDataURI(false);
2313
0
  }
2314
0
  return NS_OK;
2315
0
}
2316
2317
NS_IMETHODIMP
2318
HttpBaseChannel::UpgradeToSecure()
2319
0
{
2320
0
  // Upgrades are handled internally between http-on-modify-request and
2321
0
  // http-on-before-connect, which means upgrades are only possible during
2322
0
  // on-modify, or WebRequest.onBeforeRequest in Web Extensions.  Once we are
2323
0
  // past the code path where upgrades are handled, attempting an upgrade
2324
0
  // will throw an error.
2325
0
  NS_ENSURE_TRUE(mUpgradableToSecure, NS_ERROR_NOT_AVAILABLE);
2326
0
2327
0
  mUpgradeToSecure = true;
2328
0
  return NS_OK;
2329
0
}
2330
2331
NS_IMETHODIMP
2332
HttpBaseChannel::GetRequestContextID(uint64_t *aRCID)
2333
0
{
2334
0
  NS_ENSURE_ARG_POINTER(aRCID);
2335
0
  *aRCID = mRequestContextID;
2336
0
  return NS_OK;
2337
0
}
2338
2339
NS_IMETHODIMP
2340
HttpBaseChannel::SetRequestContextID(uint64_t aRCID)
2341
0
{
2342
0
  mRequestContextID = aRCID;
2343
0
  return NS_OK;
2344
0
}
2345
2346
NS_IMETHODIMP
2347
HttpBaseChannel::GetIsMainDocumentChannel(bool* aValue)
2348
0
{
2349
0
  NS_ENSURE_ARG_POINTER(aValue);
2350
0
  *aValue = IsNavigation();
2351
0
  return NS_OK;
2352
0
}
2353
2354
NS_IMETHODIMP
2355
HttpBaseChannel::SetIsMainDocumentChannel(bool aValue)
2356
0
{
2357
0
  mForceMainDocumentChannel = aValue;
2358
0
  return NS_OK;
2359
0
}
2360
2361
NS_IMETHODIMP
2362
HttpBaseChannel::GetProtocolVersion(nsACString& aProtocolVersion)
2363
0
{
2364
0
  nsresult rv;
2365
0
  nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(mSecurityInfo, &rv);
2366
0
  nsAutoCString protocol;
2367
0
  if (NS_SUCCEEDED(rv) && ssl &&
2368
0
      NS_SUCCEEDED(ssl->GetNegotiatedNPN(protocol)) &&
2369
0
      !protocol.IsEmpty()) {
2370
0
    // The negotiated protocol was not empty so we can use it.
2371
0
    aProtocolVersion = protocol;
2372
0
    return NS_OK;
2373
0
  }
2374
0
2375
0
  if (mResponseHead) {
2376
0
    HttpVersion version = mResponseHead->Version();
2377
0
    aProtocolVersion.Assign(nsHttp::GetProtocolVersion(version));
2378
0
    return NS_OK;
2379
0
  }
2380
0
2381
0
  return NS_ERROR_NOT_AVAILABLE;
2382
0
}
2383
2384
2385
//-----------------------------------------------------------------------------
2386
// HttpBaseChannel::nsIHttpChannelInternal
2387
//-----------------------------------------------------------------------------
2388
2389
NS_IMETHODIMP
2390
HttpBaseChannel::SetTopWindowURIIfUnknown(nsIURI *aTopWindowURI)
2391
0
{
2392
0
  if (!aTopWindowURI) {
2393
0
    return NS_ERROR_INVALID_ARG;
2394
0
  }
2395
0
2396
0
  if (mTopWindowURI) {
2397
0
    LOG(("HttpChannelBase::SetTopWindowURIIfUnknown [this=%p] "
2398
0
         "mTopWindowURI is already set.\n", this));
2399
0
    return NS_ERROR_FAILURE;
2400
0
  }
2401
0
2402
0
  nsCOMPtr<nsIURI> topWindowURI;
2403
0
  Unused << GetTopWindowURI(getter_AddRefs(topWindowURI));
2404
0
2405
0
  // Don't modify |mTopWindowURI| if we can get one from GetTopWindowURI().
2406
0
  if (topWindowURI) {
2407
0
    LOG(("HttpChannelBase::SetTopWindowURIIfUnknown [this=%p] "
2408
0
         "Return an error since we got a top window uri.\n", this));
2409
0
    return NS_ERROR_FAILURE;
2410
0
  }
2411
0
2412
0
  mTopWindowURI = aTopWindowURI;
2413
0
  return NS_OK;
2414
0
}
2415
2416
NS_IMETHODIMP
2417
HttpBaseChannel::GetTopWindowURI(nsIURI **aTopWindowURI)
2418
0
{
2419
0
  nsresult rv = NS_OK;
2420
0
  nsCOMPtr<mozIThirdPartyUtil> util;
2421
0
  // Only compute the top window URI once. In e10s, this must be computed in the
2422
0
  // child. The parent gets the top window URI through HttpChannelOpenArgs.
2423
0
  if (!mTopWindowURI) {
2424
0
    util = services::GetThirdPartyUtil();
2425
0
    if (!util) {
2426
0
      return NS_ERROR_NOT_AVAILABLE;
2427
0
    }
2428
0
    nsCOMPtr<mozIDOMWindowProxy> win;
2429
0
    rv = util->GetTopWindowForChannel(this, getter_AddRefs(win));
2430
0
    if (NS_SUCCEEDED(rv)) {
2431
0
      rv = util->GetURIFromWindow(win, getter_AddRefs(mTopWindowURI));
2432
#if DEBUG
2433
      if (mTopWindowURI) {
2434
        nsCString spec;
2435
        if (NS_SUCCEEDED(mTopWindowURI->GetSpec(spec))) {
2436
          LOG(("HttpChannelBase::Setting topwindow URI spec %s [this=%p]\n",
2437
               spec.get(), this));
2438
        }
2439
      }
2440
#endif
2441
    }
2442
0
  }
2443
0
  NS_IF_ADDREF(*aTopWindowURI = mTopWindowURI);
2444
0
  return rv;
2445
0
}
2446
2447
NS_IMETHODIMP
2448
HttpBaseChannel::GetDocumentURI(nsIURI **aDocumentURI)
2449
0
{
2450
0
  NS_ENSURE_ARG_POINTER(aDocumentURI);
2451
0
  *aDocumentURI = mDocumentURI;
2452
0
  NS_IF_ADDREF(*aDocumentURI);
2453
0
  return NS_OK;
2454
0
}
2455
2456
NS_IMETHODIMP
2457
HttpBaseChannel::SetDocumentURI(nsIURI *aDocumentURI)
2458
0
{
2459
0
  ENSURE_CALLED_BEFORE_CONNECT();
2460
0
2461
0
  mDocumentURI = aDocumentURI;
2462
0
  return NS_OK;
2463
0
}
2464
2465
NS_IMETHODIMP
2466
HttpBaseChannel::GetRequestVersion(uint32_t *major, uint32_t *minor)
2467
0
{
2468
0
  HttpVersion version = mRequestHead.Version();
2469
0
2470
0
  if (major) { *major = static_cast<uint32_t>(version) / 10; }
2471
0
  if (minor) { *minor = static_cast<uint32_t>(version) % 10; }
2472
0
2473
0
  return NS_OK;
2474
0
}
2475
2476
NS_IMETHODIMP
2477
HttpBaseChannel::GetResponseVersion(uint32_t *major, uint32_t *minor)
2478
0
{
2479
0
  if (!mResponseHead)
2480
0
  {
2481
0
    *major = *minor = 0; // we should at least be kind about it
2482
0
    return NS_ERROR_NOT_AVAILABLE;
2483
0
  }
2484
0
2485
0
  HttpVersion version = mResponseHead->Version();
2486
0
2487
0
  if (major) { *major = static_cast<uint32_t>(version) / 10; }
2488
0
  if (minor) { *minor = static_cast<uint32_t>(version) % 10; }
2489
0
2490
0
  return NS_OK;
2491
0
}
2492
2493
void
2494
HttpBaseChannel::NotifySetCookie(char const *aCookie)
2495
0
{
2496
0
  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
2497
0
  if (obs) {
2498
0
    nsAutoString cookie;
2499
0
    CopyASCIItoUTF16(mozilla::MakeStringSpan(aCookie), cookie);
2500
0
    obs->NotifyObservers(static_cast<nsIChannel*>(this),
2501
0
                         "http-on-response-set-cookie",
2502
0
                         cookie.get());
2503
0
  }
2504
0
}
2505
2506
NS_IMETHODIMP
2507
HttpBaseChannel::SetCookie(const char *aCookieHeader)
2508
0
{
2509
0
  if (mLoadFlags & LOAD_ANONYMOUS)
2510
0
    return NS_OK;
2511
0
2512
0
  // empty header isn't an error
2513
0
  if (!(aCookieHeader && *aCookieHeader))
2514
0
    return NS_OK;
2515
0
2516
0
  nsICookieService *cs = gHttpHandler->GetCookieService();
2517
0
  NS_ENSURE_TRUE(cs, NS_ERROR_FAILURE);
2518
0
2519
0
  nsAutoCString date;
2520
0
  // empty date is not an error
2521
0
  Unused << mResponseHead->GetHeader(nsHttp::Date, date);
2522
0
  nsresult rv = cs->SetCookieStringFromHttp(mURI, nullptr, nullptr,
2523
0
                                            aCookieHeader, date.get(), this);
2524
0
  if (NS_SUCCEEDED(rv)) {
2525
0
    NotifySetCookie(aCookieHeader);
2526
0
  }
2527
0
  return rv;
2528
0
}
2529
2530
NS_IMETHODIMP
2531
HttpBaseChannel::GetThirdPartyFlags(uint32_t  *aFlags)
2532
0
{
2533
0
  *aFlags = mThirdPartyFlags;
2534
0
  return NS_OK;
2535
0
}
2536
2537
NS_IMETHODIMP
2538
HttpBaseChannel::SetThirdPartyFlags(uint32_t aFlags)
2539
0
{
2540
0
  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
2541
0
2542
0
  mThirdPartyFlags = aFlags;
2543
0
  return NS_OK;
2544
0
}
2545
2546
NS_IMETHODIMP
2547
HttpBaseChannel::GetForceAllowThirdPartyCookie(bool *aForce)
2548
0
{
2549
0
  *aForce = !!(mThirdPartyFlags & nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
2550
0
  return NS_OK;
2551
0
}
2552
2553
NS_IMETHODIMP
2554
HttpBaseChannel::SetForceAllowThirdPartyCookie(bool aForce)
2555
0
{
2556
0
  ENSURE_CALLED_BEFORE_ASYNC_OPEN();
2557
0
2558
0
  if (aForce)
2559
0
    mThirdPartyFlags |= nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW;
2560
0
  else
2561
0
    mThirdPartyFlags &= ~nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW;
2562
0
2563
0
  return NS_OK;
2564
0
}
2565
2566
NS_IMETHODIMP
2567
HttpBaseChannel::GetCanceled(bool *aCanceled)
2568
0
{
2569
0
  *aCanceled = mCanceled;
2570
0
  return NS_OK;
2571
0
}
2572
2573
NS_IMETHODIMP
2574
HttpBaseChannel::GetChannelIsForDownload(bool *aChannelIsForDownload)
2575
0
{
2576
0
  *aChannelIsForDownload = mChannelIsForDownload;
2577
0
  return NS_OK;
2578
0
}
2579
2580
NS_IMETHODIMP
2581
HttpBaseChannel::SetChannelIsForDownload(bool aChannelIsForDownload)
2582
0
{
2583
0
  mChannelIsForDownload = aChannelIsForDownload;
2584
0
  return NS_OK;
2585
0
}
2586
2587
NS_IMETHODIMP
2588
HttpBaseChannel::SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys)
2589
0
{
2590
0
  mRedirectedCachekeys = cacheKeys;
2591
0
  return NS_OK;
2592
0
}
2593
2594
NS_IMETHODIMP
2595
HttpBaseChannel::GetLocalAddress(nsACString& addr)
2596
0
{
2597
0
  if (mSelfAddr.raw.family == PR_AF_UNSPEC)
2598
0
    return NS_ERROR_NOT_AVAILABLE;
2599
0
2600
0
  addr.SetLength(kIPv6CStrBufSize);
2601
0
  NetAddrToString(&mSelfAddr, addr.BeginWriting(), kIPv6CStrBufSize);
2602
0
  addr.SetLength(strlen(addr.BeginReading()));
2603
0
2604
0
  return NS_OK;
2605
0
}
2606
2607
NS_IMETHODIMP
2608
HttpBaseChannel::TakeAllSecurityMessages(
2609
    nsCOMArray<nsISecurityConsoleMessage> &aMessages)
2610
0
{
2611
0
  MOZ_ASSERT(NS_IsMainThread());
2612
0
2613
0
  aMessages.Clear();
2614
0
  for (auto pair : mSecurityConsoleMessages) {
2615
0
    nsresult rv;
2616
0
    nsCOMPtr<nsISecurityConsoleMessage> message =
2617
0
      do_CreateInstance(NS_SECURITY_CONSOLE_MESSAGE_CONTRACTID, &rv);
2618
0
    NS_ENSURE_SUCCESS(rv, rv);
2619
0
2620
0
    message->SetTag(pair.first());
2621
0
    message->SetCategory(pair.second());
2622
0
    aMessages.AppendElement(message);
2623
0
  }
2624
0
2625
0
  MOZ_ASSERT(mSecurityConsoleMessages.Length() == aMessages.Length());
2626
0
  mSecurityConsoleMessages.Clear();
2627
0
2628
0
  return NS_OK;
2629
0
}
2630
2631
/* Please use this method with care. This can cause the message
2632
 * queue to grow large and cause the channel to take up a lot
2633
 * of memory. Use only static string messages and do not add
2634
 * server side data to the queue, as that can be large.
2635
 * Add only a limited number of messages to the queue to keep
2636
 * the channel size down and do so only in rare erroneous situations.
2637
 * More information can be found here:
2638
 * https://bugzilla.mozilla.org/show_bug.cgi?id=846918
2639
 */
2640
nsresult
2641
HttpBaseChannel::AddSecurityMessage(const nsAString &aMessageTag,
2642
    const nsAString &aMessageCategory)
2643
0
{
2644
0
  MOZ_ASSERT(NS_IsMainThread());
2645
0
2646
0
  nsresult rv;
2647
0
2648
0
  // nsSecurityConsoleMessage is not thread-safe refcounted.
2649
0
  // Delay the object construction until requested.
2650
0
  // See TakeAllSecurityMessages()
2651
0
  Pair<nsString, nsString> pair(aMessageTag, aMessageCategory);
2652
0
  mSecurityConsoleMessages.AppendElement(std::move(pair));
2653
0
2654
0
  nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
2655
0
  if (!console) {
2656
0
    return NS_ERROR_FAILURE;
2657
0
  }
2658
0
2659
0
  nsCOMPtr<nsILoadInfo> loadInfo;
2660
0
  GetLoadInfo(getter_AddRefs(loadInfo));
2661
0
  if (!loadInfo) {
2662
0
    return NS_ERROR_FAILURE;
2663
0
  }
2664
0
2665
0
  auto innerWindowID = loadInfo->GetInnerWindowID();
2666
0
2667
0
  nsAutoString errorText;
2668
0
  rv = nsContentUtils::GetLocalizedString(
2669
0
          nsContentUtils::eSECURITY_PROPERTIES,
2670
0
          NS_ConvertUTF16toUTF8(aMessageTag).get(),
2671
0
          errorText);
2672
0
  NS_ENSURE_SUCCESS(rv, rv);
2673
0
2674
0
  nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
2675
0
  error->InitWithSourceURI(errorText, mURI,
2676
0
                           EmptyString(), 0, 0,
2677
0
                           nsIScriptError::warningFlag,
2678
0
                           NS_ConvertUTF16toUTF8(aMessageCategory),
2679
0
                           innerWindowID);
2680
0
2681
0
  console->LogMessage(error);
2682
0
2683
0
  return NS_OK;
2684
0
}
2685
2686
NS_IMETHODIMP
2687
HttpBaseChannel::GetLocalPort(int32_t* port)
2688
0
{
2689
0
  NS_ENSURE_ARG_POINTER(port);
2690
0
2691
0
  if (mSelfAddr.raw.family == PR_AF_INET) {
2692
0
    *port = (int32_t)ntohs(mSelfAddr.inet.port);
2693
0
  }
2694
0
  else if (mSelfAddr.raw.family == PR_AF_INET6) {
2695
0
    *port = (int32_t)ntohs(mSelfAddr.inet6.port);
2696
0
  }
2697
0
  else
2698
0
    return NS_ERROR_NOT_AVAILABLE;
2699
0
2700
0
  return NS_OK;
2701
0
}
2702
2703
NS_IMETHODIMP
2704
HttpBaseChannel::GetRemoteAddress(nsACString& addr)
2705
0
{
2706
0
  if (mPeerAddr.raw.family == PR_AF_UNSPEC)
2707
0
    return NS_ERROR_NOT_AVAILABLE;
2708
0
2709
0
  addr.SetLength(kIPv6CStrBufSize);
2710
0
  NetAddrToString(&mPeerAddr, addr.BeginWriting(), kIPv6CStrBufSize);
2711
0
  addr.SetLength(strlen(addr.BeginReading()));
2712
0
2713
0
  return NS_OK;
2714
0
}
2715
2716
NS_IMETHODIMP
2717
HttpBaseChannel::GetRemotePort(int32_t* port)
2718
0
{
2719
0
  NS_ENSURE_ARG_POINTER(port);
2720
0
2721
0
  if (mPeerAddr.raw.family == PR_AF_INET) {
2722
0
    *port = (int32_t)ntohs(mPeerAddr.inet.port);
2723
0
  }
2724
0
  else if (mPeerAddr.raw.family == PR_AF_INET6) {
2725
0
    *port = (int32_t)ntohs(mPeerAddr.inet6.port);
2726
0
  }
2727
0
  else
2728
0
    return NS_ERROR_NOT_AVAILABLE;
2729
0
2730
0
  return NS_OK;
2731
0
}
2732
2733
NS_IMETHODIMP
2734
HttpBaseChannel::HTTPUpgrade(const nsACString &aProtocolName,
2735
                             nsIHttpUpgradeListener *aListener)
2736
0
{
2737
0
    NS_ENSURE_ARG(!aProtocolName.IsEmpty());
2738
0
    NS_ENSURE_ARG_POINTER(aListener);
2739
0
2740
0
    mUpgradeProtocol = aProtocolName;
2741
0
    mUpgradeProtocolCallback = aListener;
2742
0
    return NS_OK;
2743
0
}
2744
2745
NS_IMETHODIMP
2746
HttpBaseChannel::GetAllowSpdy(bool *aAllowSpdy)
2747
0
{
2748
0
  NS_ENSURE_ARG_POINTER(aAllowSpdy);
2749
0
2750
0
  *aAllowSpdy = mAllowSpdy;
2751
0
  return NS_OK;
2752
0
}
2753
2754
NS_IMETHODIMP
2755
HttpBaseChannel::SetAllowSpdy(bool aAllowSpdy)
2756
0
{
2757
0
  mAllowSpdy = aAllowSpdy;
2758
0
  return NS_OK;
2759
0
}
2760
2761
NS_IMETHODIMP
2762
HttpBaseChannel::GetAllowAltSvc(bool *aAllowAltSvc)
2763
0
{
2764
0
  NS_ENSURE_ARG_POINTER(aAllowAltSvc);
2765
0
2766
0
  *aAllowAltSvc = mAllowAltSvc;
2767
0
  return NS_OK;
2768
0
}
2769
2770
NS_IMETHODIMP
2771
HttpBaseChannel::SetAllowAltSvc(bool aAllowAltSvc)
2772
0
{
2773
0
  mAllowAltSvc = aAllowAltSvc;
2774
0
  return NS_OK;
2775
0
}
2776
2777
NS_IMETHODIMP
2778
HttpBaseChannel::GetBeConservative(bool *aBeConservative)
2779
0
{
2780
0
  NS_ENSURE_ARG_POINTER(aBeConservative);
2781
0
2782
0
  *aBeConservative = mBeConservative;
2783
0
  return NS_OK;
2784
0
}
2785
2786
NS_IMETHODIMP
2787
HttpBaseChannel::SetBeConservative(bool aBeConservative)
2788
0
{
2789
0
  mBeConservative = aBeConservative;
2790
0
  return NS_OK;
2791
0
}
2792
2793
NS_IMETHODIMP
2794
HttpBaseChannel::GetTrr(bool *aTRR)
2795
0
{
2796
0
  NS_ENSURE_ARG_POINTER(aTRR);
2797
0
2798
0
  *aTRR = mTRR;
2799
0
  return NS_OK;
2800
0
}
2801
2802
NS_IMETHODIMP
2803
HttpBaseChannel::SetTrr(bool aTRR)
2804
0
{
2805
0
  mTRR = aTRR;
2806
0
  return NS_OK;
2807
0
}
2808
2809
NS_IMETHODIMP
2810
HttpBaseChannel::GetTlsFlags(uint32_t *aTlsFlags)
2811
0
{
2812
0
  NS_ENSURE_ARG_POINTER(aTlsFlags);
2813
0
2814
0
  *aTlsFlags = mTlsFlags;
2815
0
  return NS_OK;
2816
0
}
2817
2818
NS_IMETHODIMP
2819
HttpBaseChannel::SetTlsFlags(uint32_t aTlsFlags)
2820
0
{
2821
0
  mTlsFlags = aTlsFlags;
2822
0
  return NS_OK;
2823
0
}
2824
2825
NS_IMETHODIMP
2826
HttpBaseChannel::GetApiRedirectToURI(nsIURI ** aResult)
2827
0
{
2828
0
  NS_ENSURE_ARG_POINTER(aResult);
2829
0
  NS_IF_ADDREF(*aResult = mAPIRedirectToURI);
2830
0
  return NS_OK;
2831
0
}
2832
2833
NS_IMETHODIMP
2834
HttpBaseChannel::GetResponseTimeoutEnabled(bool *aEnable)
2835
0
{
2836
0
  if (NS_WARN_IF(!aEnable)) {
2837
0
    return NS_ERROR_NULL_POINTER;
2838
0
  }
2839
0
  *aEnable = mResponseTimeoutEnabled;
2840
0
  return NS_OK;
2841
0
}
2842
2843
NS_IMETHODIMP
2844
HttpBaseChannel::SetResponseTimeoutEnabled(bool aEnable)
2845
0
{
2846
0
  mResponseTimeoutEnabled = aEnable;
2847
0
  return NS_OK;
2848
0
}
2849
2850
NS_IMETHODIMP
2851
HttpBaseChannel::GetInitialRwin(uint32_t *aRwin)
2852
0
{
2853
0
  if (NS_WARN_IF(!aRwin)) {
2854
0
    return NS_ERROR_NULL_POINTER;
2855
0
  }
2856
0
  *aRwin = mInitialRwin;
2857
0
  return NS_OK;
2858
0
}
2859
2860
NS_IMETHODIMP
2861
HttpBaseChannel::SetInitialRwin(uint32_t aRwin)
2862
0
{
2863
0
  ENSURE_CALLED_BEFORE_CONNECT();
2864
0
  mInitialRwin = aRwin;
2865
0
  return NS_OK;
2866
0
}
2867
2868
NS_IMETHODIMP
2869
HttpBaseChannel::ForcePending(bool aForcePending)
2870
0
{
2871
0
  mForcePending = aForcePending;
2872
0
  return NS_OK;
2873
0
}
2874
2875
NS_IMETHODIMP
2876
HttpBaseChannel::GetLastModifiedTime(PRTime* lastModifiedTime)
2877
0
{
2878
0
  if (!mResponseHead)
2879
0
    return NS_ERROR_NOT_AVAILABLE;
2880
0
  uint32_t lastMod;
2881
0
  nsresult rv = mResponseHead->GetLastModifiedValue(&lastMod);
2882
0
  NS_ENSURE_SUCCESS(rv, rv);
2883
0
  *lastModifiedTime = lastMod;
2884
0
  return NS_OK;
2885
0
}
2886
2887
NS_IMETHODIMP
2888
HttpBaseChannel::GetCorsIncludeCredentials(bool* aInclude)
2889
0
{
2890
0
  *aInclude = mCorsIncludeCredentials;
2891
0
  return NS_OK;
2892
0
}
2893
2894
NS_IMETHODIMP
2895
HttpBaseChannel::SetCorsIncludeCredentials(bool aInclude)
2896
0
{
2897
0
  mCorsIncludeCredentials = aInclude;
2898
0
  return NS_OK;
2899
0
}
2900
2901
NS_IMETHODIMP
2902
HttpBaseChannel::GetCorsMode(uint32_t* aMode)
2903
0
{
2904
0
  *aMode = mCorsMode;
2905
0
  return NS_OK;
2906
0
}
2907
2908
NS_IMETHODIMP
2909
HttpBaseChannel::SetCorsMode(uint32_t aMode)
2910
0
{
2911
0
  mCorsMode = aMode;
2912
0
  return NS_OK;
2913
0
}
2914
2915
NS_IMETHODIMP
2916
HttpBaseChannel::GetRedirectMode(uint32_t* aMode)
2917
0
{
2918
0
  *aMode = mRedirectMode;
2919
0
  return NS_OK;
2920
0
}
2921
2922
NS_IMETHODIMP
2923
HttpBaseChannel::SetRedirectMode(uint32_t aMode)
2924
0
{
2925
0
  mRedirectMode = aMode;
2926
0
  return NS_OK;
2927
0
}
2928
2929
namespace {
2930
2931
bool
2932
ContainsAllFlags(uint32_t aLoadFlags, uint32_t aMask)
2933
0
{
2934
0
  return (aLoadFlags & aMask) == aMask;
2935
0
}
2936
2937
} // anonymous namespace
2938
2939
NS_IMETHODIMP
2940
HttpBaseChannel::GetFetchCacheMode(uint32_t* aFetchCacheMode)
2941
0
{
2942
0
  NS_ENSURE_ARG_POINTER(aFetchCacheMode);
2943
0
2944
0
  // Otherwise try to guess an appropriate cache mode from the load flags.
2945
0
  if (ContainsAllFlags(mLoadFlags, INHIBIT_CACHING | LOAD_BYPASS_CACHE)) {
2946
0
    *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_STORE;
2947
0
  } else if (ContainsAllFlags(mLoadFlags, LOAD_BYPASS_CACHE)) {
2948
0
    *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_RELOAD;
2949
0
  } else if (ContainsAllFlags(mLoadFlags, VALIDATE_ALWAYS)) {
2950
0
    *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_CACHE;
2951
0
  } else if (ContainsAllFlags(mLoadFlags, VALIDATE_NEVER |
2952
0
                                          nsICachingChannel::LOAD_ONLY_FROM_CACHE)) {
2953
0
    *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_ONLY_IF_CACHED;
2954
0
  } else if (ContainsAllFlags(mLoadFlags, VALIDATE_NEVER)) {
2955
0
    *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_FORCE_CACHE;
2956
0
  } else {
2957
0
    *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_DEFAULT;
2958
0
  }
2959
0
2960
0
  return NS_OK;
2961
0
}
2962
2963
namespace {
2964
2965
void
2966
SetCacheFlags(uint32_t& aLoadFlags, uint32_t aFlags)
2967
0
{
2968
0
  // First, clear any possible cache related flags.
2969
0
  uint32_t allPossibleFlags = nsIRequest::INHIBIT_CACHING
2970
0
                            | nsIRequest::LOAD_BYPASS_CACHE
2971
0
                            | nsIRequest::VALIDATE_ALWAYS
2972
0
                            | nsIRequest::LOAD_FROM_CACHE
2973
0
                            | nsICachingChannel::LOAD_ONLY_FROM_CACHE;
2974
0
  aLoadFlags &= ~allPossibleFlags;
2975
0
2976
0
  // Then set the new flags.
2977
0
  aLoadFlags |= aFlags;
2978
0
}
2979
2980
} // anonymous namespace
2981
2982
NS_IMETHODIMP
2983
HttpBaseChannel::SetFetchCacheMode(uint32_t aFetchCacheMode)
2984
0
{
2985
0
  ENSURE_CALLED_BEFORE_CONNECT();
2986
0
2987
0
  // Now, set the load flags that implement each cache mode.
2988
0
  switch (aFetchCacheMode) {
2989
0
  case nsIHttpChannelInternal::FETCH_CACHE_MODE_DEFAULT:
2990
0
    // The "default" mode means to use the http cache normally and
2991
0
    // respect any http cache-control headers.  We effectively want
2992
0
    // to clear our cache related load flags.
2993
0
    SetCacheFlags(mLoadFlags, 0);
2994
0
    break;
2995
0
  case nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_STORE:
2996
0
    // no-store means don't consult the cache on the way to the network, and
2997
0
    // don't store the response in the cache even if it's cacheable.
2998
0
    SetCacheFlags(mLoadFlags, INHIBIT_CACHING | LOAD_BYPASS_CACHE);
2999
0
    break;
3000
0
  case nsIHttpChannelInternal::FETCH_CACHE_MODE_RELOAD:
3001
0
    // reload means don't consult the cache on the way to the network, but
3002
0
    // do store the response in the cache if possible.
3003
0
    SetCacheFlags(mLoadFlags, LOAD_BYPASS_CACHE);
3004
0
    break;
3005
0
  case nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_CACHE:
3006
0
    // no-cache means always validate what's in the cache.
3007
0
    SetCacheFlags(mLoadFlags, VALIDATE_ALWAYS);
3008
0
    break;
3009
0
  case nsIHttpChannelInternal::FETCH_CACHE_MODE_FORCE_CACHE:
3010
0
    // force-cache means don't validate unless if the response would vary.
3011
0
    SetCacheFlags(mLoadFlags, VALIDATE_NEVER);
3012
0
    break;
3013
0
  case nsIHttpChannelInternal::FETCH_CACHE_MODE_ONLY_IF_CACHED:
3014
0
    // only-if-cached means only from cache, no network, no validation, generate
3015
0
    // a network error if the document was't in the cache.
3016
0
    // The privacy implications of these flags (making it fast/easy to check if
3017
0
    // the user has things in their cache without any network traffic side
3018
0
    // effects) are addressed in the Request constructor which enforces/requires
3019
0
    // same-origin request mode.
3020
0
    SetCacheFlags(mLoadFlags, VALIDATE_NEVER |
3021
0
                              nsICachingChannel::LOAD_ONLY_FROM_CACHE);
3022
0
    break;
3023
0
  }
3024
0
3025
0
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
3026
0
  uint32_t finalMode = 0;
3027
0
  MOZ_ALWAYS_SUCCEEDS(GetFetchCacheMode(&finalMode));
3028
0
  MOZ_DIAGNOSTIC_ASSERT(finalMode == aFetchCacheMode);
3029
0
#endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
3030
0
3031
0
  return NS_OK;
3032
0
}
3033
3034
NS_IMETHODIMP
3035
HttpBaseChannel::SetIntegrityMetadata(const nsAString& aIntegrityMetadata)
3036
0
{
3037
0
  mIntegrityMetadata = aIntegrityMetadata;
3038
0
  return NS_OK;
3039
0
}
3040
3041
NS_IMETHODIMP
3042
HttpBaseChannel::GetIntegrityMetadata(nsAString& aIntegrityMetadata)
3043
0
{
3044
0
  aIntegrityMetadata = mIntegrityMetadata;
3045
0
  return NS_OK;
3046
0
}
3047
3048
//-----------------------------------------------------------------------------
3049
// HttpBaseChannel::nsISupportsPriority
3050
//-----------------------------------------------------------------------------
3051
3052
NS_IMETHODIMP
3053
HttpBaseChannel::GetPriority(int32_t *value)
3054
0
{
3055
0
  *value = mPriority;
3056
0
  return NS_OK;
3057
0
}
3058
3059
NS_IMETHODIMP
3060
HttpBaseChannel::AdjustPriority(int32_t delta)
3061
0
{
3062
0
  return SetPriority(mPriority + delta);
3063
0
}
3064
3065
//-----------------------------------------------------------------------------
3066
// HttpBaseChannel::nsIResumableChannel
3067
//-----------------------------------------------------------------------------
3068
3069
NS_IMETHODIMP
3070
HttpBaseChannel::GetEntityID(nsACString& aEntityID)
3071
0
{
3072
0
  // Don't return an entity ID for Non-GET requests which require
3073
0
  // additional data
3074
0
  if (!mRequestHead.IsGet()) {
3075
0
    return NS_ERROR_NOT_RESUMABLE;
3076
0
  }
3077
0
3078
0
  uint64_t size = UINT64_MAX;
3079
0
  nsAutoCString etag, lastmod;
3080
0
  if (mResponseHead) {
3081
0
    // Don't return an entity if the server sent the following header:
3082
0
    // Accept-Ranges: none
3083
0
    // Not sending the Accept-Ranges header means we can still try
3084
0
    // sending range requests.
3085
0
    nsAutoCString acceptRanges;
3086
0
    Unused << mResponseHead->GetHeader(nsHttp::Accept_Ranges, acceptRanges);
3087
0
    if (!acceptRanges.IsEmpty() &&
3088
0
        !nsHttp::FindToken(acceptRanges.get(), "bytes", HTTP_HEADER_VALUE_SEPS)) {
3089
0
      return NS_ERROR_NOT_RESUMABLE;
3090
0
    }
3091
0
3092
0
    size = mResponseHead->TotalEntitySize();
3093
0
    Unused << mResponseHead->GetHeader(nsHttp::Last_Modified, lastmod);
3094
0
    Unused << mResponseHead->GetHeader(nsHttp::ETag, etag);
3095
0
  }
3096
0
  nsCString entityID;
3097
0
  NS_EscapeURL(etag.BeginReading(), etag.Length(), esc_AlwaysCopy |
3098
0
               esc_FileBaseName | esc_Forced, entityID);
3099
0
  entityID.Append('/');
3100
0
  entityID.AppendInt(int64_t(size));
3101
0
  entityID.Append('/');
3102
0
  entityID.Append(lastmod);
3103
0
  // NOTE: Appending lastmod as the last part avoids having to escape it
3104
0
3105
0
  aEntityID = entityID;
3106
0
3107
0
  return NS_OK;
3108
0
}
3109
3110
//-----------------------------------------------------------------------------
3111
// HttpBaseChannel::nsIConsoleReportCollector
3112
//-----------------------------------------------------------------------------
3113
3114
void
3115
HttpBaseChannel::AddConsoleReport(uint32_t aErrorFlags,
3116
                                  const nsACString& aCategory,
3117
                                  nsContentUtils::PropertiesFile aPropertiesFile,
3118
                                  const nsACString& aSourceFileURI,
3119
                                  uint32_t aLineNumber, uint32_t aColumnNumber,
3120
                                  const nsACString& aMessageName,
3121
                                  const nsTArray<nsString>& aStringParams)
3122
0
{
3123
0
  mReportCollector->AddConsoleReport(aErrorFlags, aCategory, aPropertiesFile,
3124
0
                                     aSourceFileURI, aLineNumber,
3125
0
                                     aColumnNumber, aMessageName,
3126
0
                                     aStringParams);
3127
0
}
3128
3129
void
3130
HttpBaseChannel::FlushReportsToConsole(uint64_t aInnerWindowID,
3131
                                       ReportAction aAction)
3132
0
{
3133
0
  mReportCollector->FlushReportsToConsole(aInnerWindowID, aAction);
3134
0
}
3135
3136
void
3137
HttpBaseChannel::FlushReportsToConsoleForServiceWorkerScope(const nsACString& aScope,
3138
                                                            ReportAction aAction)
3139
0
{
3140
0
  mReportCollector->FlushReportsToConsoleForServiceWorkerScope(aScope, aAction);
3141
0
}
3142
3143
void
3144
HttpBaseChannel::FlushConsoleReports(nsIDocument* aDocument,
3145
                                     ReportAction aAction)
3146
0
{
3147
0
  mReportCollector->FlushConsoleReports(aDocument, aAction);
3148
0
}
3149
3150
void
3151
HttpBaseChannel::FlushConsoleReports(nsILoadGroup* aLoadGroup,
3152
                                     ReportAction aAction)
3153
0
{
3154
0
  mReportCollector->FlushConsoleReports(aLoadGroup, aAction);
3155
0
}
3156
3157
void
3158
HttpBaseChannel::FlushConsoleReports(nsIConsoleReportCollector* aCollector)
3159
0
{
3160
0
  mReportCollector->FlushConsoleReports(aCollector);
3161
0
}
3162
3163
void
3164
HttpBaseChannel::ClearConsoleReports()
3165
0
{
3166
0
  mReportCollector->ClearConsoleReports();
3167
0
}
3168
3169
nsIPrincipal *
3170
HttpBaseChannel::GetURIPrincipal()
3171
0
{
3172
0
  if (mPrincipal) {
3173
0
      return mPrincipal;
3174
0
  }
3175
0
3176
0
  nsIScriptSecurityManager *securityManager =
3177
0
      nsContentUtils::GetSecurityManager();
3178
0
3179
0
  if (!securityManager) {
3180
0
      LOG(("HttpBaseChannel::GetURIPrincipal: No security manager [this=%p]",
3181
0
           this));
3182
0
      return nullptr;
3183
0
  }
3184
0
3185
0
  securityManager->GetChannelURIPrincipal(this, getter_AddRefs(mPrincipal));
3186
0
  if (!mPrincipal) {
3187
0
      LOG(("HttpBaseChannel::GetURIPrincipal: No channel principal [this=%p]",
3188
0
           this));
3189
0
      return nullptr;
3190
0
  }
3191
0
3192
0
  return mPrincipal;
3193
0
}
3194
3195
bool
3196
HttpBaseChannel::IsNavigation()
3197
0
{
3198
0
  return mForceMainDocumentChannel || (mLoadFlags & LOAD_DOCUMENT_URI);
3199
0
}
3200
3201
bool
3202
HttpBaseChannel::BypassServiceWorker() const
3203
0
{
3204
0
  return mLoadFlags & LOAD_BYPASS_SERVICE_WORKER;
3205
0
}
3206
3207
bool
3208
HttpBaseChannel::ShouldIntercept(nsIURI* aURI)
3209
0
{
3210
0
  nsCOMPtr<nsINetworkInterceptController> controller;
3211
0
  GetCallback(controller);
3212
0
  bool shouldIntercept = false;
3213
0
3214
0
  // We should never intercept internal redirects.  The ServiceWorker code
3215
0
  // can trigger interntal redirects as the result of a FetchEvent.  If
3216
0
  // we re-intercept then an infinite loop can occur.
3217
0
  //
3218
0
  // Its also important that we do not set the LOAD_BYPASS_SERVICE_WORKER
3219
0
  // flag because an internal redirect occurs.  Its possible that another
3220
0
  // interception should occur after the internal redirect.  For example,
3221
0
  // if the ServiceWorker chooses not to call respondWith() the channel
3222
0
  // will be reset with an internal redirect.  If the request is a navigation
3223
0
  // and the network then triggers a redirect its possible the new URL
3224
0
  // should be intercepted again.
3225
0
  //
3226
0
  // Note, HSTS upgrade redirects are often treated the same as internal
3227
0
  // redirects.  In this case, however, we intentionally allow interception
3228
0
  // of HSTS upgrade redirects.  This matches the expected spec behavior and
3229
0
  // does not run the risk of infinite loops as described above.
3230
0
  bool internalRedirect = mLastRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL;
3231
0
3232
0
  if (controller && mLoadInfo && !BypassServiceWorker() && !internalRedirect) {
3233
0
    nsresult rv = controller->ShouldPrepareForIntercept(aURI ? aURI : mURI.get(),
3234
0
                                                        this,
3235
0
                                                        &shouldIntercept);
3236
0
    if (NS_FAILED(rv)) {
3237
0
      return false;
3238
0
    }
3239
0
  }
3240
0
  return shouldIntercept;
3241
0
}
3242
3243
void
3244
HttpBaseChannel::AddAsNonTailRequest()
3245
0
{
3246
0
  MOZ_ASSERT(NS_IsMainThread());
3247
0
3248
0
  if (EnsureRequestContext()) {
3249
0
    LOG(("HttpBaseChannel::AddAsNonTailRequest this=%p, rc=%p, already added=%d",
3250
0
         this, mRequestContext.get(), (bool)mAddedAsNonTailRequest));
3251
0
3252
0
    if (!mAddedAsNonTailRequest) {
3253
0
      mRequestContext->AddNonTailRequest();
3254
0
      mAddedAsNonTailRequest = true;
3255
0
    }
3256
0
  }
3257
0
}
3258
3259
void
3260
HttpBaseChannel::RemoveAsNonTailRequest()
3261
0
{
3262
0
  MOZ_ASSERT(NS_IsMainThread());
3263
0
3264
0
  if (mRequestContext) {
3265
0
    LOG(("HttpBaseChannel::RemoveAsNonTailRequest this=%p, rc=%p, already added=%d",
3266
0
         this, mRequestContext.get(), (bool)mAddedAsNonTailRequest));
3267
0
3268
0
    if (mAddedAsNonTailRequest) {
3269
0
      mRequestContext->RemoveNonTailRequest();
3270
0
      mAddedAsNonTailRequest = false;
3271
0
    }
3272
0
  }
3273
0
}
3274
3275
#ifdef DEBUG
3276
void HttpBaseChannel::AssertPrivateBrowsingId()
3277
{
3278
  nsCOMPtr<nsILoadContext> loadContext;
3279
  NS_QueryNotificationCallbacks(this, loadContext);
3280
  // For addons it's possible that mLoadInfo is null.
3281
  if (!mLoadInfo) {
3282
    return;
3283
  }
3284
3285
  if (!loadContext) {
3286
    return;
3287
  }
3288
3289
  // We skip testing of favicon loading here since it could be triggered by XUL image
3290
  // which uses SystemPrincipal. The SystemPrincpal doesn't have mPrivateBrowsingId.
3291
  if (nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal()) &&
3292
      mLoadInfo->InternalContentPolicyType() == nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON) {
3293
    return;
3294
  }
3295
3296
  OriginAttributes docShellAttrs;
3297
  loadContext->GetOriginAttributes(docShellAttrs);
3298
  MOZ_ASSERT(mLoadInfo->GetOriginAttributes().mPrivateBrowsingId == docShellAttrs.mPrivateBrowsingId,
3299
             "PrivateBrowsingId values are not the same between LoadInfo and LoadContext.");
3300
}
3301
#endif
3302
3303
already_AddRefed<nsILoadInfo>
3304
HttpBaseChannel::CloneLoadInfoForRedirect(nsIURI * newURI, uint32_t redirectFlags)
3305
0
{
3306
0
  // make a copy of the loadinfo, append to the redirectchain
3307
0
  // this will be set on the newly created channel for the redirect target.
3308
0
  if (!mLoadInfo) {
3309
0
    return nullptr;
3310
0
  }
3311
0
3312
0
  nsCOMPtr<nsILoadInfo> newLoadInfo =
3313
0
    static_cast<mozilla::net::LoadInfo*>(mLoadInfo.get())->Clone();
3314
0
3315
0
  nsContentPolicyType contentPolicyType = mLoadInfo->GetExternalContentPolicyType();
3316
0
  if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
3317
0
      contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
3318
0
    nsCOMPtr<nsIPrincipal> nullPrincipalToInherit = NullPrincipal::CreateWithoutOriginAttributes();
3319
0
    newLoadInfo->SetPrincipalToInherit(nullPrincipalToInherit);
3320
0
  }
3321
0
3322
0
  // re-compute the origin attributes of the loadInfo if it's top-level load.
3323
0
  bool isTopLevelDoc =
3324
0
    newLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT;
3325
0
3326
0
  if (isTopLevelDoc) {
3327
0
    nsCOMPtr<nsILoadContext> loadContext;
3328
0
    NS_QueryNotificationCallbacks(this, loadContext);
3329
0
    OriginAttributes docShellAttrs;
3330
0
    if (loadContext) {
3331
0
      loadContext->GetOriginAttributes(docShellAttrs);
3332
0
    }
3333
0
3334
0
    OriginAttributes attrs = newLoadInfo->GetOriginAttributes();
3335
0
3336
0
    MOZ_ASSERT(docShellAttrs.mUserContextId == attrs.mUserContextId,
3337
0
                "docshell and necko should have the same userContextId attribute.");
3338
0
    MOZ_ASSERT(docShellAttrs.mInIsolatedMozBrowser == attrs.mInIsolatedMozBrowser,
3339
0
                "docshell and necko should have the same inIsolatedMozBrowser attribute.");
3340
0
    MOZ_ASSERT(docShellAttrs.mPrivateBrowsingId == attrs.mPrivateBrowsingId,
3341
0
                "docshell and necko should have the same privateBrowsingId attribute.");
3342
0
3343
0
    attrs = docShellAttrs;
3344
0
    attrs.SetFirstPartyDomain(true, newURI);
3345
0
    newLoadInfo->SetOriginAttributes(attrs);
3346
0
  }
3347
0
3348
0
  // Leave empty, we want a 'clean ground' when creating the new channel.
3349
0
  // This will be ensured to be either set by the protocol handler or set
3350
0
  // to the redirect target URI properly after the channel creation.
3351
0
  newLoadInfo->SetResultPrincipalURI(nullptr);
3352
0
3353
0
  bool isInternalRedirect =
3354
0
    (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
3355
0
                      nsIChannelEventSink::REDIRECT_STS_UPGRADE));
3356
0
3357
0
  nsCString remoteAddress;
3358
0
  Unused << GetRemoteAddress(remoteAddress);
3359
0
  nsCOMPtr<nsIRedirectHistoryEntry> entry =
3360
0
    new nsRedirectHistoryEntry(GetURIPrincipal(), mReferrer, remoteAddress);
3361
0
3362
0
  newLoadInfo->AppendRedirectHistoryEntry(entry, isInternalRedirect);
3363
0
3364
0
  return newLoadInfo.forget();
3365
0
}
3366
3367
//-----------------------------------------------------------------------------
3368
// nsHttpChannel::nsITraceableChannel
3369
//-----------------------------------------------------------------------------
3370
3371
NS_IMETHODIMP
3372
HttpBaseChannel::SetNewListener(nsIStreamListener *aListener, nsIStreamListener **_retval)
3373
0
{
3374
0
  LOG(("HttpBaseChannel::SetNewListener [this=%p, mListener=%p, newListener=%p]",
3375
0
       this, mListener.get(), aListener));
3376
0
3377
0
  if (!mTracingEnabled)
3378
0
    return NS_ERROR_FAILURE;
3379
0
3380
0
  NS_ENSURE_STATE(mListener);
3381
0
  NS_ENSURE_ARG_POINTER(aListener);
3382
0
3383
0
  nsCOMPtr<nsIStreamListener> wrapper = new nsStreamListenerWrapper(mListener);
3384
0
3385
0
  wrapper.forget(_retval);
3386
0
  mListener = aListener;
3387
0
  return NS_OK;
3388
0
}
3389
3390
//-----------------------------------------------------------------------------
3391
// HttpBaseChannel helpers
3392
//-----------------------------------------------------------------------------
3393
3394
void
3395
HttpBaseChannel::ReleaseListeners()
3396
0
{
3397
0
  MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
3398
0
3399
0
  mListener = nullptr;
3400
0
  mListenerContext = nullptr;
3401
0
  mCallbacks = nullptr;
3402
0
  mProgressSink = nullptr;
3403
0
  mCompressListener = nullptr;
3404
0
}
3405
3406
void
3407
HttpBaseChannel::DoNotifyListener()
3408
0
{
3409
0
  LOG(("HttpBaseChannel::DoNotifyListener this=%p", this));
3410
0
3411
0
  if (mListener) {
3412
0
    MOZ_ASSERT(!mOnStartRequestCalled,
3413
0
               "We should not call OnStartRequest twice");
3414
0
3415
0
    nsCOMPtr<nsIStreamListener> listener = mListener;
3416
0
    listener->OnStartRequest(this, mListenerContext);
3417
0
3418
0
    mOnStartRequestCalled = true;
3419
0
  }
3420
0
3421
0
  // Make sure mIsPending is set to false. At this moment we are done from
3422
0
  // the point of view of our consumer and we have to report our self
3423
0
  // as not-pending.
3424
0
  mIsPending = false;
3425
0
3426
0
  if (mListener) {
3427
0
    MOZ_ASSERT(!mOnStopRequestCalled,
3428
0
               "We should not call OnStopRequest twice");
3429
0
3430
0
    nsCOMPtr<nsIStreamListener> listener = mListener;
3431
0
    listener->OnStopRequest(this, mListenerContext, mStatus);
3432
0
3433
0
    mOnStopRequestCalled = true;
3434
0
  }
3435
0
3436
0
  // notify "http-on-stop-connect" observers
3437
0
  gHttpHandler->OnStopRequest(this);
3438
0
3439
0
  // This channel has finished its job, potentially release any tail-blocked
3440
0
  // requests with this.
3441
0
  RemoveAsNonTailRequest();
3442
0
3443
0
  // We have to make sure to drop the references to listeners and callbacks
3444
0
  // no longer needed.
3445
0
  ReleaseListeners();
3446
0
3447
0
  DoNotifyListenerCleanup();
3448
0
3449
0
  // If this is a navigation, then we must let the docshell flush the reports
3450
0
  // to the console later.  The LoadDocument() is pointing at the detached
3451
0
  // document that started the navigation.  We want to show the reports on the
3452
0
  // new document.  Otherwise the console is wiped and the user never sees
3453
0
  // the information.
3454
0
  if (!IsNavigation()) {
3455
0
    if (mLoadGroup) {
3456
0
      FlushConsoleReports(mLoadGroup);
3457
0
    } else if (mLoadInfo) {
3458
0
      nsCOMPtr<nsIDocument> doc;
3459
0
      mLoadInfo->GetLoadingDocument(getter_AddRefs(doc));
3460
0
      FlushConsoleReports(doc);
3461
0
    }
3462
0
  }
3463
0
}
3464
3465
void
3466
HttpBaseChannel::AddCookiesToRequest()
3467
0
{
3468
0
  if (mLoadFlags & LOAD_ANONYMOUS) {
3469
0
    return;
3470
0
  }
3471
0
3472
0
  bool useCookieService =
3473
0
    (XRE_IsParentProcess());
3474
0
  nsCString cookie;
3475
0
  if (useCookieService) {
3476
0
    nsICookieService *cs = gHttpHandler->GetCookieService();
3477
0
    if (cs) {
3478
0
      cs->GetCookieStringFromHttp(mURI,
3479
0
                                  nullptr,
3480
0
                                  this, getter_Copies(cookie));
3481
0
    }
3482
0
3483
0
    if (cookie.IsEmpty()) {
3484
0
      cookie = mUserSetCookieHeader;
3485
0
    }
3486
0
    else if (!mUserSetCookieHeader.IsEmpty()) {
3487
0
      cookie.AppendLiteral("; ");
3488
0
      cookie.Append(mUserSetCookieHeader);
3489
0
    }
3490
0
  }
3491
0
  else {
3492
0
    cookie = mUserSetCookieHeader;
3493
0
  }
3494
0
3495
0
  // If we are in the child process, we want the parent seeing any
3496
0
  // cookie headers that might have been set by SetRequestHeader()
3497
0
  SetRequestHeader(nsDependentCString(nsHttp::Cookie), cookie, false);
3498
0
}
3499
3500
/* static */
3501
bool
3502
HttpBaseChannel::IsReferrerSchemeAllowed(nsIURI *aReferrer)
3503
0
{
3504
0
  NS_ENSURE_TRUE(aReferrer, false);
3505
0
3506
0
  nsAutoCString scheme;
3507
0
  nsresult rv = aReferrer->GetScheme(scheme);
3508
0
  NS_ENSURE_SUCCESS(rv, false);
3509
0
3510
0
  if (scheme.EqualsIgnoreCase("https") ||
3511
0
      scheme.EqualsIgnoreCase("http") ||
3512
0
      scheme.EqualsIgnoreCase("ftp")) {
3513
0
    return true;
3514
0
  }
3515
0
  return false;
3516
0
}
3517
3518
/* static */
3519
void
3520
HttpBaseChannel::PropagateReferenceIfNeeded(nsIURI* aURI, nsCOMPtr<nsIURI>& aRedirectURI)
3521
0
{
3522
0
  bool hasRef = false;
3523
0
  nsresult rv = aRedirectURI->GetHasRef(&hasRef);
3524
0
  if (NS_SUCCEEDED(rv) && !hasRef) {
3525
0
    nsAutoCString ref;
3526
0
    aURI->GetRef(ref);
3527
0
    if (!ref.IsEmpty()) {
3528
0
      // NOTE: SetRef will fail if mRedirectURI is immutable
3529
0
      // (e.g. an about: URI)... Oh well.
3530
0
      Unused << NS_MutateURI(aRedirectURI)
3531
0
                  .SetRef(ref)
3532
0
                  .Finalize(aRedirectURI);
3533
0
    }
3534
0
  }
3535
0
}
3536
3537
bool
3538
HttpBaseChannel::ShouldRewriteRedirectToGET(uint32_t httpStatus,
3539
                                            nsHttpRequestHead::ParsedMethodType method)
3540
0
{
3541
0
  // for 301 and 302, only rewrite POST
3542
0
  if (httpStatus == 301 || httpStatus == 302)
3543
0
    return method == nsHttpRequestHead::kMethod_Post;
3544
0
3545
0
  // rewrite for 303 unless it was HEAD
3546
0
  if (httpStatus == 303)
3547
0
    return method != nsHttpRequestHead::kMethod_Head;
3548
0
3549
0
  // otherwise, such as for 307, do not rewrite
3550
0
  return false;
3551
0
}
3552
3553
nsresult
3554
HttpBaseChannel::SetupReplacementChannel(nsIURI       *newURI,
3555
                                         nsIChannel   *newChannel,
3556
                                         bool          preserveMethod,
3557
                                         uint32_t      redirectFlags)
3558
0
{
3559
0
  nsresult rv;
3560
0
3561
0
  LOG(("HttpBaseChannel::SetupReplacementChannel "
3562
0
     "[this=%p newChannel=%p preserveMethod=%d]",
3563
0
     this, newChannel, preserveMethod));
3564
0
3565
0
  // Ensure the channel's loadInfo's result principal URI so that it's
3566
0
  // either non-null or updated to the redirect target URI.
3567
0
  // We must do this because in case the loadInfo's result principal URI
3568
0
  // is null, it would be taken from OriginalURI of the channel.  But we
3569
0
  // overwrite it with the whole redirect chain first URI before opening
3570
0
  // the target channel, hence the information would be lost.
3571
0
  // If the protocol handler that created the channel wants to use
3572
0
  // the originalURI of the channel as the principal URI, this fulfills
3573
0
  // that request - newURI is the original URI of the channel.
3574
0
  nsCOMPtr<nsILoadInfo> newLoadInfo = newChannel->GetLoadInfo();
3575
0
  if (newLoadInfo) {
3576
0
    nsCOMPtr<nsIURI> resultPrincipalURI;
3577
0
    rv = newLoadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
3578
0
    NS_ENSURE_SUCCESS(rv, rv);
3579
0
3580
0
    if (!resultPrincipalURI) {
3581
0
      rv = newLoadInfo->SetResultPrincipalURI(newURI);
3582
0
      NS_ENSURE_SUCCESS(rv, rv);
3583
0
    }
3584
0
  }
3585
0
3586
0
  uint32_t newLoadFlags = mLoadFlags | LOAD_REPLACE;
3587
0
  // if the original channel was using SSL and this channel is not using
3588
0
  // SSL, then no need to inhibit persistent caching.  however, if the
3589
0
  // original channel was not using SSL and has INHIBIT_PERSISTENT_CACHING
3590
0
  // set, then allow the flag to apply to the redirected channel as well.
3591
0
  // since we force set INHIBIT_PERSISTENT_CACHING on all HTTPS channels,
3592
0
  // we only need to check if the original channel was using SSL.
3593
0
  bool usingSSL = false;
3594
0
  rv = mURI->SchemeIs("https", &usingSSL);
3595
0
  if (NS_SUCCEEDED(rv) && usingSSL)
3596
0
    newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING;
3597
0
3598
0
  // Do not pass along LOAD_CHECK_OFFLINE_CACHE
3599
0
  newLoadFlags &= ~nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE;
3600
0
3601
0
  newChannel->SetLoadGroup(mLoadGroup);
3602
0
  newChannel->SetNotificationCallbacks(mCallbacks);
3603
0
  newChannel->SetLoadFlags(newLoadFlags);
3604
0
3605
0
  nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(newChannel));
3606
0
  if (cos) {
3607
0
    cos->SetClassFlags(mClassOfService);
3608
0
  }
3609
0
3610
0
  // Try to preserve the privacy bit if it has been overridden
3611
0
  if (mPrivateBrowsingOverriden) {
3612
0
    nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel =
3613
0
      do_QueryInterface(newChannel);
3614
0
    if (newPBChannel) {
3615
0
      newPBChannel->SetPrivate(mPrivateBrowsing);
3616
0
    }
3617
0
  }
3618
0
3619
0
  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
3620
0
  if (!httpChannel)
3621
0
    return NS_OK; // no other options to set
3622
0
3623
0
  // Preserve the CORS preflight information.
3624
0
  nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
3625
0
  if (httpInternal) {
3626
0
    httpInternal->SetLastRedirectFlags(redirectFlags);
3627
0
3628
0
    if (mRequireCORSPreflight) {
3629
0
      httpInternal->SetCorsPreflightParameters(mUnsafeHeaders);
3630
0
    }
3631
0
  }
3632
0
3633
0
  if (preserveMethod) {
3634
0
    nsCOMPtr<nsIUploadChannel> uploadChannel =
3635
0
      do_QueryInterface(httpChannel);
3636
0
    nsCOMPtr<nsIUploadChannel2> uploadChannel2 =
3637
0
      do_QueryInterface(httpChannel);
3638
0
    if (mUploadStream && (uploadChannel2 || uploadChannel)) {
3639
0
      // rewind upload stream
3640
0
      nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream);
3641
0
      MOZ_ASSERT(seekable);
3642
0
3643
0
      seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
3644
0
3645
0
      // replicate original call to SetUploadStream...
3646
0
      if (uploadChannel2) {
3647
0
        nsAutoCString ctype;
3648
0
        // If header is not present mRequestHead.HasHeaderValue will truncated
3649
0
        // it.  But we want to end up with a void string, not an empty string,
3650
0
        // because ExplicitSetUploadStream treats the former as "no header" and
3651
0
        // the latter as "header with empty string value".
3652
0
        nsresult ctypeOK = mRequestHead.GetHeader(nsHttp::Content_Type, ctype);
3653
0
        if (NS_FAILED(ctypeOK)) {
3654
0
          ctype.SetIsVoid(true);
3655
0
        }
3656
0
        nsAutoCString clen;
3657
0
        Unused << mRequestHead.GetHeader(nsHttp::Content_Length, clen);
3658
0
        nsAutoCString method;
3659
0
        mRequestHead.Method(method);
3660
0
        int64_t len = clen.IsEmpty() ? -1 : nsCRT::atoll(clen.get());
3661
0
        uploadChannel2->ExplicitSetUploadStream(
3662
0
                                  mUploadStream, ctype, len,
3663
0
                                  method,
3664
0
                                  mUploadStreamHasHeaders);
3665
0
      } else {
3666
0
        if (mUploadStreamHasHeaders) {
3667
0
          uploadChannel->SetUploadStream(mUploadStream, EmptyCString(),
3668
0
                           -1);
3669
0
        } else {
3670
0
          nsAutoCString ctype;
3671
0
          if (NS_FAILED(mRequestHead.GetHeader(nsHttp::Content_Type, ctype))) {
3672
0
            ctype =  NS_LITERAL_CSTRING("application/octet-stream");
3673
0
          }
3674
0
          nsAutoCString clen;
3675
0
          if (NS_SUCCEEDED(mRequestHead.GetHeader(nsHttp::Content_Length, clen))
3676
0
              &&
3677
0
              !clen.IsEmpty()) {
3678
0
            uploadChannel->SetUploadStream(mUploadStream,
3679
0
                                           ctype,
3680
0
                                           nsCRT::atoll(clen.get()));
3681
0
          }
3682
0
        }
3683
0
      }
3684
0
    }
3685
0
    // since preserveMethod is true, we need to ensure that the appropriate
3686
0
    // request method gets set on the channel, regardless of whether or not
3687
0
    // we set the upload stream above. This means SetRequestMethod() will
3688
0
    // be called twice if ExplicitSetUploadStream() gets called above.
3689
0
3690
0
    nsAutoCString method;
3691
0
    mRequestHead.Method(method);
3692
0
    rv = httpChannel->SetRequestMethod(method);
3693
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3694
0
  }
3695
0
  // convey the referrer if one was used for this channel to the next one
3696
0
  if (mReferrer) {
3697
0
    rv = httpChannel->SetReferrerWithPolicy(mReferrer, mReferrerPolicy);
3698
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3699
0
  }
3700
0
  // convey the mAllowSTS flags
3701
0
  rv = httpChannel->SetAllowSTS(mAllowSTS);
3702
0
  MOZ_ASSERT(NS_SUCCEEDED(rv));
3703
0
3704
0
  // convey the Accept header value
3705
0
  {
3706
0
    nsAutoCString oldAcceptValue;
3707
0
    nsresult hasHeader = mRequestHead.GetHeader(nsHttp::Accept, oldAcceptValue);
3708
0
    if (NS_SUCCEEDED(hasHeader)) {
3709
0
      rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
3710
0
                                         oldAcceptValue,
3711
0
                                         false);
3712
0
      MOZ_ASSERT(NS_SUCCEEDED(rv));
3713
0
    }
3714
0
  }
3715
0
3716
0
  // share the request context - see bug 1236650
3717
0
  rv = httpChannel->SetRequestContextID(mRequestContextID);
3718
0
  MOZ_ASSERT(NS_SUCCEEDED(rv));
3719
0
3720
0
  // When on the parent process, the channel can't attempt to get it itself.
3721
0
  // When on the child process, it would be waste to query it again.
3722
0
  rv = httpChannel->SetTopLevelOuterContentWindowId(mTopLevelOuterContentWindowId);
3723
0
  MOZ_ASSERT(NS_SUCCEEDED(rv));
3724
0
3725
0
  // Not setting this flag would break carrying permissions down to the child process
3726
0
  // when the channel is artificially forced to be a main document load.
3727
0
  rv = httpChannel->SetIsMainDocumentChannel(mForceMainDocumentChannel);
3728
0
  MOZ_ASSERT(NS_SUCCEEDED(rv));
3729
0
3730
0
  // Preserve the loading order
3731
0
  nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(newChannel);
3732
0
  if (p) {
3733
0
    p->SetPriority(mPriority);
3734
0
  }
3735
0
3736
0
  if (httpInternal) {
3737
0
    // Convey third party cookie, conservative, and spdy flags.
3738
0
    rv = httpInternal->SetThirdPartyFlags(mThirdPartyFlags);
3739
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3740
0
    rv = httpInternal->SetAllowSpdy(mAllowSpdy);
3741
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3742
0
    rv = httpInternal->SetAllowAltSvc(mAllowAltSvc);
3743
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3744
0
    rv = httpInternal->SetBeConservative(mBeConservative);
3745
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3746
0
    rv = httpInternal->SetTrr(mTRR);
3747
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3748
0
    rv = httpInternal->SetTlsFlags(mTlsFlags);
3749
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3750
0
3751
0
    RefPtr<nsHttpChannel> realChannel;
3752
0
    CallQueryInterface(newChannel, realChannel.StartAssignment());
3753
0
    if (realChannel) {
3754
0
      rv = realChannel->SetTopWindowURI(mTopWindowURI);
3755
0
      MOZ_ASSERT(NS_SUCCEEDED(rv));
3756
0
    }
3757
0
3758
0
    // update the DocumentURI indicator since we are being redirected.
3759
0
    // if this was a top-level document channel, then the new channel
3760
0
    // should have its mDocumentURI point to newURI; otherwise, we
3761
0
    // just need to pass along our mDocumentURI to the new channel.
3762
0
    if (newURI && (mURI == mDocumentURI))
3763
0
      rv = httpInternal->SetDocumentURI(newURI);
3764
0
    else
3765
0
      rv = httpInternal->SetDocumentURI(mDocumentURI);
3766
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3767
0
3768
0
    // if there is a chain of keys for redirect-responses we transfer it to
3769
0
    // the new channel (see bug #561276)
3770
0
    if (mRedirectedCachekeys) {
3771
0
        LOG(("HttpBaseChannel::SetupReplacementChannel "
3772
0
             "[this=%p] transferring chain of redirect cache-keys", this));
3773
0
        rv = httpInternal->SetCacheKeysRedirectChain(mRedirectedCachekeys.forget());
3774
0
        MOZ_ASSERT(NS_SUCCEEDED(rv));
3775
0
    }
3776
0
3777
0
    // Preserve CORS mode flag.
3778
0
    rv = httpInternal->SetCorsMode(mCorsMode);
3779
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3780
0
3781
0
    // Preserve Redirect mode flag.
3782
0
    rv = httpInternal->SetRedirectMode(mRedirectMode);
3783
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3784
0
3785
0
    // Preserve Integrity metadata.
3786
0
    rv = httpInternal->SetIntegrityMetadata(mIntegrityMetadata);
3787
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3788
0
3789
0
    httpInternal->SetAltDataForChild(mAltDataForChild);
3790
0
  }
3791
0
3792
0
  // transfer application cache information
3793
0
  nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
3794
0
    do_QueryInterface(newChannel);
3795
0
  if (appCacheChannel) {
3796
0
    appCacheChannel->SetApplicationCache(mApplicationCache);
3797
0
    appCacheChannel->SetInheritApplicationCache(mInheritApplicationCache);
3798
0
    // We purposely avoid transfering mChooseApplicationCache.
3799
0
  }
3800
0
3801
0
  // transfer any properties
3802
0
  nsCOMPtr<nsIWritablePropertyBag> bag(do_QueryInterface(newChannel));
3803
0
  if (bag) {
3804
0
    for (auto iter = mPropertyHash.Iter(); !iter.Done(); iter.Next()) {
3805
0
      bag->SetProperty(iter.Key(), iter.UserData());
3806
0
    }
3807
0
  }
3808
0
3809
0
  // Transfer the timing data (if we are dealing with an nsITimedChannel).
3810
0
  nsCOMPtr<nsITimedChannel> newTimedChannel(do_QueryInterface(newChannel));
3811
0
  nsCOMPtr<nsITimedChannel> oldTimedChannel(
3812
0
      do_QueryInterface(static_cast<nsIHttpChannel*>(this)));
3813
0
  if (oldTimedChannel && newTimedChannel) {
3814
0
    newTimedChannel->SetTimingEnabled(mTimingEnabled);
3815
0
3816
0
    if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
3817
0
      newTimedChannel->SetRedirectCount(mRedirectCount);
3818
0
      int8_t newCount = mInternalRedirectCount + 1;
3819
0
      newTimedChannel->SetInternalRedirectCount(
3820
0
        std::max(newCount, mInternalRedirectCount));
3821
0
    } else {
3822
0
      int8_t newCount = mRedirectCount + 1;
3823
0
      newTimedChannel->SetRedirectCount(
3824
0
        std::max(newCount, mRedirectCount));
3825
0
      newTimedChannel->SetInternalRedirectCount(mInternalRedirectCount);
3826
0
    }
3827
0
3828
0
    TimeStamp oldAsyncOpenTime;
3829
0
    oldTimedChannel->GetAsyncOpen(&oldAsyncOpenTime);
3830
0
3831
0
    if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
3832
0
      TimeStamp oldChannelCreationTimestamp;
3833
0
      oldTimedChannel->GetChannelCreation(&oldChannelCreationTimestamp);
3834
0
3835
0
      if (!oldChannelCreationTimestamp.IsNull()) {
3836
0
        newTimedChannel->SetChannelCreation(oldChannelCreationTimestamp);
3837
0
      }
3838
0
3839
0
      if (!oldAsyncOpenTime.IsNull()) {
3840
0
        newTimedChannel->SetAsyncOpen(oldAsyncOpenTime);
3841
0
      }
3842
0
    }
3843
0
3844
0
    // If the RedirectStart is null, we will use the AsyncOpen value of the
3845
0
    // previous channel (this is the first redirect in the redirects chain).
3846
0
    if (mRedirectStartTimeStamp.IsNull()) {
3847
0
      // Only do this for real redirects.  Internal redirects should be hidden.
3848
0
      if (!(redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
3849
0
        newTimedChannel->SetRedirectStart(oldAsyncOpenTime);
3850
0
      }
3851
0
    } else {
3852
0
      newTimedChannel->SetRedirectStart(mRedirectStartTimeStamp);
3853
0
    }
3854
0
3855
0
    // For internal redirects just propagate the last redirect end time
3856
0
    // forward.  Otherwise the new redirect end time is the last response
3857
0
    // end time.
3858
0
    TimeStamp newRedirectEnd;
3859
0
    if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
3860
0
      oldTimedChannel->GetRedirectEnd(&newRedirectEnd);
3861
0
    } else {
3862
0
      oldTimedChannel->GetResponseEnd(&newRedirectEnd);
3863
0
    }
3864
0
    newTimedChannel->SetRedirectEnd(newRedirectEnd);
3865
0
3866
0
    nsAutoString initiatorType;
3867
0
    oldTimedChannel->GetInitiatorType(initiatorType);
3868
0
    newTimedChannel->SetInitiatorType(initiatorType);
3869
0
3870
0
    // Check whether or not this was a cross-domain redirect.
3871
0
    newTimedChannel->SetAllRedirectsSameOrigin(
3872
0
        mAllRedirectsSameOrigin && SameOriginWithOriginalUri(newURI));
3873
0
3874
0
    // Execute the timing allow check to determine whether
3875
0
    // to report the redirect timing info
3876
0
    nsCOMPtr<nsILoadInfo> loadInfo;
3877
0
    GetLoadInfo(getter_AddRefs(loadInfo));
3878
0
    // TYPE_DOCUMENT loads don't have a loadingPrincipal, so we can't set
3879
0
    // AllRedirectsPassTimingAllowCheck on them.
3880
0
    if (loadInfo && loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT) {
3881
0
      nsCOMPtr<nsIPrincipal> principal = loadInfo->LoadingPrincipal();
3882
0
      newTimedChannel->SetAllRedirectsPassTimingAllowCheck(
3883
0
        mAllRedirectsPassTimingAllowCheck &&
3884
0
        oldTimedChannel->TimingAllowCheck(principal));
3885
0
    }
3886
0
3887
0
    // Propagate service worker measurements across redirects.  The
3888
0
    // PeformanceResourceTiming.workerStart API expects to see the
3889
0
    // worker start time after a redirect.
3890
0
    newTimedChannel->SetLaunchServiceWorkerStart(mLaunchServiceWorkerStart);
3891
0
    newTimedChannel->SetLaunchServiceWorkerEnd(mLaunchServiceWorkerEnd);
3892
0
    newTimedChannel->SetDispatchFetchEventStart(mDispatchFetchEventStart);
3893
0
    newTimedChannel->SetDispatchFetchEventEnd(mDispatchFetchEventEnd);
3894
0
    newTimedChannel->SetHandleFetchEventStart(mHandleFetchEventStart);
3895
0
    newTimedChannel->SetHandleFetchEventEnd(mHandleFetchEventEnd);
3896
0
  }
3897
0
3898
0
  // Pass the preferred alt-data type on to the new channel.
3899
0
  nsCOMPtr<nsICacheInfoChannel> cacheInfoChan(do_QueryInterface(newChannel));
3900
0
  if (cacheInfoChan) {
3901
0
    cacheInfoChan->PreferAlternativeDataType(mPreferredCachedAltDataType);
3902
0
  }
3903
0
3904
0
  if (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
3905
0
                       nsIChannelEventSink::REDIRECT_STS_UPGRADE)) {
3906
0
    // Copy non-origin related headers to the new channel.
3907
0
    nsCOMPtr<nsIHttpHeaderVisitor> visitor =
3908
0
      new AddHeadersToChannelVisitor(httpChannel);
3909
0
    rv = mRequestHead.VisitHeaders(visitor);
3910
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
3911
0
  }
3912
0
3913
0
  // This channel has been redirected. Don't report timing info.
3914
0
  mTimingEnabled = false;
3915
0
  return NS_OK;
3916
0
}
3917
3918
// Redirect Tracking
3919
bool
3920
HttpBaseChannel::SameOriginWithOriginalUri(nsIURI *aURI)
3921
0
{
3922
0
  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
3923
0
  bool isPrivateWin = mLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
3924
0
  nsresult rv = ssm->CheckSameOriginURI(aURI, mOriginalURI, false, isPrivateWin);
3925
0
  return (NS_SUCCEEDED(rv));
3926
0
}
3927
3928
3929
//-----------------------------------------------------------------------------
3930
// HttpBaseChannel::nsIClassifiedChannel
3931
3932
NS_IMETHODIMP
3933
HttpBaseChannel::GetMatchedList(nsACString& aList)
3934
0
{
3935
0
  aList = mMatchedList;
3936
0
  return NS_OK;
3937
0
}
3938
3939
NS_IMETHODIMP
3940
HttpBaseChannel::GetMatchedProvider(nsACString& aProvider)
3941
0
{
3942
0
  aProvider = mMatchedProvider;
3943
0
  return NS_OK;
3944
0
}
3945
3946
NS_IMETHODIMP
3947
HttpBaseChannel::GetMatchedFullHash(nsACString& aFullHash)
3948
0
{
3949
0
  aFullHash = mMatchedFullHash;
3950
0
  return NS_OK;
3951
0
}
3952
3953
NS_IMETHODIMP
3954
HttpBaseChannel::SetMatchedInfo(const nsACString& aList,
3955
                                const nsACString& aProvider,
3956
0
                                const nsACString& aFullHash) {
3957
0
  NS_ENSURE_ARG(!aList.IsEmpty());
3958
0
3959
0
  mMatchedList = aList;
3960
0
  mMatchedProvider = aProvider;
3961
0
  mMatchedFullHash = aFullHash;
3962
0
  return NS_OK;
3963
0
}
3964
3965
//-----------------------------------------------------------------------------
3966
// HttpBaseChannel::nsITimedChannel
3967
//-----------------------------------------------------------------------------
3968
3969
NS_IMETHODIMP
3970
0
HttpBaseChannel::SetTimingEnabled(bool enabled) {
3971
0
  mTimingEnabled = enabled;
3972
0
  return NS_OK;
3973
0
}
3974
3975
NS_IMETHODIMP
3976
0
HttpBaseChannel::GetTimingEnabled(bool* _retval) {
3977
0
  *_retval = mTimingEnabled;
3978
0
  return NS_OK;
3979
0
}
3980
3981
NS_IMETHODIMP
3982
0
HttpBaseChannel::GetChannelCreation(TimeStamp* _retval) {
3983
0
  *_retval = mChannelCreationTimestamp;
3984
0
  return NS_OK;
3985
0
}
3986
3987
NS_IMETHODIMP
3988
0
HttpBaseChannel::SetChannelCreation(TimeStamp aValue) {
3989
0
  MOZ_DIAGNOSTIC_ASSERT(!aValue.IsNull());
3990
0
  TimeDuration adjust = aValue - mChannelCreationTimestamp;
3991
0
  mChannelCreationTimestamp = aValue;
3992
0
  mChannelCreationTime += (PRTime)adjust.ToMicroseconds();
3993
0
  return NS_OK;
3994
0
}
3995
3996
NS_IMETHODIMP
3997
0
HttpBaseChannel::GetAsyncOpen(TimeStamp* _retval) {
3998
0
  *_retval = mAsyncOpenTime;
3999
0
  return NS_OK;
4000
0
}
4001
4002
NS_IMETHODIMP
4003
0
HttpBaseChannel::SetAsyncOpen(TimeStamp aValue) {
4004
0
  MOZ_DIAGNOSTIC_ASSERT(!aValue.IsNull());
4005
0
  mAsyncOpenTime = aValue;
4006
0
  mAsyncOpenTimeOverriden = true;
4007
0
  return NS_OK;
4008
0
}
4009
4010
/**
4011
 * @return the number of redirects. There is no check for cross-domain
4012
 * redirects. This check must be done by the consumers.
4013
 */
4014
NS_IMETHODIMP
4015
HttpBaseChannel::GetRedirectCount(uint8_t *aRedirectCount)
4016
0
{
4017
0
  *aRedirectCount = mRedirectCount;
4018
0
  return NS_OK;
4019
0
}
4020
4021
NS_IMETHODIMP
4022
HttpBaseChannel::SetRedirectCount(uint8_t aRedirectCount)
4023
0
{
4024
0
  mRedirectCount = aRedirectCount;
4025
0
  return NS_OK;
4026
0
}
4027
4028
NS_IMETHODIMP
4029
HttpBaseChannel::GetInternalRedirectCount(uint8_t *aRedirectCount)
4030
0
{
4031
0
  *aRedirectCount = mInternalRedirectCount;
4032
0
  return NS_OK;
4033
0
}
4034
4035
NS_IMETHODIMP
4036
HttpBaseChannel::SetInternalRedirectCount(uint8_t aRedirectCount)
4037
0
{
4038
0
  mInternalRedirectCount = aRedirectCount;
4039
0
  return NS_OK;
4040
0
}
4041
4042
NS_IMETHODIMP
4043
HttpBaseChannel::GetRedirectStart(TimeStamp* _retval)
4044
0
{
4045
0
  *_retval = mRedirectStartTimeStamp;
4046
0
  return NS_OK;
4047
0
}
4048
4049
NS_IMETHODIMP
4050
HttpBaseChannel::SetRedirectStart(TimeStamp aRedirectStart)
4051
0
{
4052
0
  mRedirectStartTimeStamp = aRedirectStart;
4053
0
  return NS_OK;
4054
0
}
4055
4056
NS_IMETHODIMP
4057
HttpBaseChannel::GetRedirectEnd(TimeStamp* _retval)
4058
0
{
4059
0
  *_retval = mRedirectEndTimeStamp;
4060
0
  return NS_OK;
4061
0
}
4062
4063
NS_IMETHODIMP
4064
HttpBaseChannel::SetRedirectEnd(TimeStamp aRedirectEnd)
4065
0
{
4066
0
  mRedirectEndTimeStamp = aRedirectEnd;
4067
0
  return NS_OK;
4068
0
}
4069
4070
NS_IMETHODIMP
4071
HttpBaseChannel::GetAllRedirectsSameOrigin(bool *aAllRedirectsSameOrigin)
4072
0
{
4073
0
  *aAllRedirectsSameOrigin = mAllRedirectsSameOrigin;
4074
0
  return NS_OK;
4075
0
}
4076
4077
NS_IMETHODIMP
4078
HttpBaseChannel::SetAllRedirectsSameOrigin(bool aAllRedirectsSameOrigin)
4079
0
{
4080
0
  mAllRedirectsSameOrigin = aAllRedirectsSameOrigin;
4081
0
  return NS_OK;
4082
0
}
4083
4084
NS_IMETHODIMP
4085
HttpBaseChannel::GetAllRedirectsPassTimingAllowCheck(bool *aPassesCheck)
4086
0
{
4087
0
  *aPassesCheck = mAllRedirectsPassTimingAllowCheck;
4088
0
  return NS_OK;
4089
0
}
4090
4091
NS_IMETHODIMP
4092
HttpBaseChannel::SetAllRedirectsPassTimingAllowCheck(bool aPassesCheck)
4093
0
{
4094
0
  mAllRedirectsPassTimingAllowCheck = aPassesCheck;
4095
0
  return NS_OK;
4096
0
}
4097
4098
// http://www.w3.org/TR/resource-timing/#timing-allow-check
4099
NS_IMETHODIMP
4100
HttpBaseChannel::TimingAllowCheck(nsIPrincipal *aOrigin, bool *_retval)
4101
0
{
4102
0
  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
4103
0
  nsCOMPtr<nsIPrincipal> resourcePrincipal;
4104
0
  nsresult rv = ssm->GetChannelURIPrincipal(this, getter_AddRefs(resourcePrincipal));
4105
0
  if (NS_FAILED(rv) || !resourcePrincipal || !aOrigin) {
4106
0
    *_retval = false;
4107
0
    return NS_OK;
4108
0
  }
4109
0
4110
0
  bool sameOrigin = false;
4111
0
  rv = resourcePrincipal->Equals(aOrigin, &sameOrigin);
4112
0
  if (NS_SUCCEEDED(rv) && sameOrigin) {
4113
0
    *_retval = true;
4114
0
    return NS_OK;
4115
0
  }
4116
0
4117
0
  nsAutoCString headerValue;
4118
0
  rv = GetResponseHeader(NS_LITERAL_CSTRING("Timing-Allow-Origin"), headerValue);
4119
0
  if (NS_FAILED(rv)) {
4120
0
    *_retval = false;
4121
0
    return NS_OK;
4122
0
  }
4123
0
4124
0
  nsAutoCString origin;
4125
0
  nsContentUtils::GetASCIIOrigin(aOrigin, origin);
4126
0
4127
0
  Tokenizer p(headerValue);
4128
0
  Tokenizer::Token t;
4129
0
4130
0
  p.Record();
4131
0
  nsAutoCString headerItem;
4132
0
  while (p.Next(t)) {
4133
0
    if (t.Type() == Tokenizer::TOKEN_EOF ||
4134
0
        t.Equals(Tokenizer::Token::Char(','))) {
4135
0
      p.Claim(headerItem);
4136
0
      headerItem.StripWhitespace();
4137
0
      // If the list item contains a case-sensitive match for the value of the
4138
0
      // origin, or a wildcard, return pass
4139
0
      if (headerItem == origin || headerItem == "*") {
4140
0
        *_retval = true;
4141
0
        return NS_OK;
4142
0
      }
4143
0
      // We start recording again for the following items in the list
4144
0
      p.Record();
4145
0
    }
4146
0
  }
4147
0
4148
0
  *_retval = false;
4149
0
  return NS_OK;
4150
0
}
4151
4152
NS_IMETHODIMP
4153
0
HttpBaseChannel::GetLaunchServiceWorkerStart(TimeStamp* _retval) {
4154
0
  MOZ_ASSERT(_retval);
4155
0
  *_retval = mLaunchServiceWorkerStart;
4156
0
  return NS_OK;
4157
0
}
4158
4159
NS_IMETHODIMP
4160
0
HttpBaseChannel::SetLaunchServiceWorkerStart(TimeStamp aTimeStamp) {
4161
0
  mLaunchServiceWorkerStart = aTimeStamp;
4162
0
  return NS_OK;
4163
0
}
4164
4165
NS_IMETHODIMP
4166
0
HttpBaseChannel::GetLaunchServiceWorkerEnd(TimeStamp* _retval) {
4167
0
  MOZ_ASSERT(_retval);
4168
0
  *_retval = mLaunchServiceWorkerEnd;
4169
0
  return NS_OK;
4170
0
}
4171
4172
NS_IMETHODIMP
4173
0
HttpBaseChannel::SetLaunchServiceWorkerEnd(TimeStamp aTimeStamp) {
4174
0
  mLaunchServiceWorkerEnd = aTimeStamp;
4175
0
  return NS_OK;
4176
0
}
4177
4178
NS_IMETHODIMP
4179
0
HttpBaseChannel::GetDispatchFetchEventStart(TimeStamp* _retval) {
4180
0
  MOZ_ASSERT(_retval);
4181
0
  *_retval = mDispatchFetchEventStart;
4182
0
  return NS_OK;
4183
0
}
4184
4185
NS_IMETHODIMP
4186
0
HttpBaseChannel::SetDispatchFetchEventStart(TimeStamp aTimeStamp) {
4187
0
  mDispatchFetchEventStart = aTimeStamp;
4188
0
  return NS_OK;
4189
0
}
4190
4191
NS_IMETHODIMP
4192
0
HttpBaseChannel::GetDispatchFetchEventEnd(TimeStamp* _retval) {
4193
0
  MOZ_ASSERT(_retval);
4194
0
  *_retval = mDispatchFetchEventEnd;
4195
0
  return NS_OK;
4196
0
}
4197
4198
NS_IMETHODIMP
4199
0
HttpBaseChannel::SetDispatchFetchEventEnd(TimeStamp aTimeStamp) {
4200
0
  mDispatchFetchEventEnd = aTimeStamp;
4201
0
  return NS_OK;
4202
0
}
4203
4204
NS_IMETHODIMP
4205
0
HttpBaseChannel::GetHandleFetchEventStart(TimeStamp* _retval) {
4206
0
  MOZ_ASSERT(_retval);
4207
0
  *_retval = mHandleFetchEventStart;
4208
0
  return NS_OK;
4209
0
}
4210
4211
NS_IMETHODIMP
4212
0
HttpBaseChannel::SetHandleFetchEventStart(TimeStamp aTimeStamp) {
4213
0
  mHandleFetchEventStart = aTimeStamp;
4214
0
  return NS_OK;
4215
0
}
4216
4217
NS_IMETHODIMP
4218
0
HttpBaseChannel::GetHandleFetchEventEnd(TimeStamp* _retval) {
4219
0
  MOZ_ASSERT(_retval);
4220
0
  *_retval = mHandleFetchEventEnd;
4221
0
  return NS_OK;
4222
0
}
4223
4224
NS_IMETHODIMP
4225
0
HttpBaseChannel::SetHandleFetchEventEnd(TimeStamp aTimeStamp) {
4226
0
  mHandleFetchEventEnd = aTimeStamp;
4227
0
  return NS_OK;
4228
0
}
4229
4230
NS_IMETHODIMP
4231
0
HttpBaseChannel::GetDomainLookupStart(TimeStamp* _retval) {
4232
0
  *_retval = mTransactionTimings.domainLookupStart;
4233
0
  return NS_OK;
4234
0
}
4235
4236
NS_IMETHODIMP
4237
0
HttpBaseChannel::GetDomainLookupEnd(TimeStamp* _retval) {
4238
0
  *_retval = mTransactionTimings.domainLookupEnd;
4239
0
  return NS_OK;
4240
0
}
4241
4242
NS_IMETHODIMP
4243
0
HttpBaseChannel::GetConnectStart(TimeStamp* _retval) {
4244
0
  *_retval = mTransactionTimings.connectStart;
4245
0
  return NS_OK;
4246
0
}
4247
4248
NS_IMETHODIMP
4249
0
HttpBaseChannel::GetTcpConnectEnd(TimeStamp* _retval) {
4250
0
  *_retval = mTransactionTimings.tcpConnectEnd;
4251
0
  return NS_OK;
4252
0
}
4253
4254
NS_IMETHODIMP
4255
0
HttpBaseChannel::GetSecureConnectionStart(TimeStamp* _retval) {
4256
0
  *_retval = mTransactionTimings.secureConnectionStart;
4257
0
  return NS_OK;
4258
0
}
4259
4260
NS_IMETHODIMP
4261
0
HttpBaseChannel::GetConnectEnd(TimeStamp* _retval) {
4262
0
  *_retval = mTransactionTimings.connectEnd;
4263
0
  return NS_OK;
4264
0
}
4265
4266
NS_IMETHODIMP
4267
0
HttpBaseChannel::GetRequestStart(TimeStamp* _retval) {
4268
0
  *_retval = mTransactionTimings.requestStart;
4269
0
  return NS_OK;
4270
0
}
4271
4272
NS_IMETHODIMP
4273
0
HttpBaseChannel::GetResponseStart(TimeStamp* _retval) {
4274
0
  *_retval = mTransactionTimings.responseStart;
4275
0
  return NS_OK;
4276
0
}
4277
4278
NS_IMETHODIMP
4279
0
HttpBaseChannel::GetResponseEnd(TimeStamp* _retval) {
4280
0
  *_retval = mTransactionTimings.responseEnd;
4281
0
  return NS_OK;
4282
0
}
4283
4284
NS_IMETHODIMP
4285
0
HttpBaseChannel::GetCacheReadStart(TimeStamp* _retval) {
4286
0
  *_retval = mCacheReadStart;
4287
0
  return NS_OK;
4288
0
}
4289
4290
NS_IMETHODIMP
4291
0
HttpBaseChannel::GetCacheReadEnd(TimeStamp* _retval) {
4292
0
  *_retval = mCacheReadEnd;
4293
0
  return NS_OK;
4294
0
}
4295
4296
NS_IMETHODIMP
4297
HttpBaseChannel::GetInitiatorType(nsAString & aInitiatorType)
4298
0
{
4299
0
  aInitiatorType = mInitiatorType;
4300
0
  return NS_OK;
4301
0
}
4302
4303
NS_IMETHODIMP
4304
HttpBaseChannel::SetInitiatorType(const nsAString & aInitiatorType)
4305
0
{
4306
0
  mInitiatorType = aInitiatorType;
4307
0
  return NS_OK;
4308
0
}
4309
4310
#define IMPL_TIMING_ATTR(name)                                 \
4311
NS_IMETHODIMP                                                  \
4312
0
HttpBaseChannel::Get##name##Time(PRTime* _retval) {            \
4313
0
    TimeStamp stamp;                                           \
4314
0
    Get##name(&stamp);                                         \
4315
0
    if (stamp.IsNull()) {                                      \
4316
0
        *_retval = 0;                                          \
4317
0
        return NS_OK;                                          \
4318
0
    }                                                          \
4319
0
    *_retval = mChannelCreationTime +                          \
4320
0
        (PRTime) ((stamp - mChannelCreationTimestamp).ToSeconds() * 1e6); \
4321
0
    return NS_OK;                                              \
4322
0
}
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetChannelCreationTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetAsyncOpenTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetLaunchServiceWorkerStartTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetLaunchServiceWorkerEndTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetDispatchFetchEventStartTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetDispatchFetchEventEndTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetHandleFetchEventStartTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetHandleFetchEventEndTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetDomainLookupStartTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetDomainLookupEndTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetConnectStartTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetTcpConnectEndTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetSecureConnectionStartTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetConnectEndTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetRequestStartTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetResponseStartTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetResponseEndTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetCacheReadStartTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetCacheReadEndTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetRedirectStartTime(long*)
Unexecuted instantiation: mozilla::net::HttpBaseChannel::GetRedirectEndTime(long*)
4323
4324
IMPL_TIMING_ATTR(ChannelCreation)
4325
IMPL_TIMING_ATTR(AsyncOpen)
4326
IMPL_TIMING_ATTR(LaunchServiceWorkerStart)
4327
IMPL_TIMING_ATTR(LaunchServiceWorkerEnd)
4328
IMPL_TIMING_ATTR(DispatchFetchEventStart)
4329
IMPL_TIMING_ATTR(DispatchFetchEventEnd)
4330
IMPL_TIMING_ATTR(HandleFetchEventStart)
4331
IMPL_TIMING_ATTR(HandleFetchEventEnd)
4332
IMPL_TIMING_ATTR(DomainLookupStart)
4333
IMPL_TIMING_ATTR(DomainLookupEnd)
4334
IMPL_TIMING_ATTR(ConnectStart)
4335
IMPL_TIMING_ATTR(TcpConnectEnd)
4336
IMPL_TIMING_ATTR(SecureConnectionStart)
4337
IMPL_TIMING_ATTR(ConnectEnd)
4338
IMPL_TIMING_ATTR(RequestStart)
4339
IMPL_TIMING_ATTR(ResponseStart)
4340
IMPL_TIMING_ATTR(ResponseEnd)
4341
IMPL_TIMING_ATTR(CacheReadStart)
4342
IMPL_TIMING_ATTR(CacheReadEnd)
4343
IMPL_TIMING_ATTR(RedirectStart)
4344
IMPL_TIMING_ATTR(RedirectEnd)
4345
4346
#undef IMPL_TIMING_ATTR
4347
4348
mozilla::dom::PerformanceStorage*
4349
HttpBaseChannel::GetPerformanceStorage()
4350
0
{
4351
0
  // If performance timing is disabled, there is no need for the Performance
4352
0
  // object anymore.
4353
0
  if (!mTimingEnabled) {
4354
0
    return nullptr;
4355
0
  }
4356
0
4357
0
  // There is no point in continuing, since the performance object in the parent
4358
0
  // isn't the same as the one in the child which will be reporting resource performance.
4359
0
  if (XRE_IsE10sParentProcess()) {
4360
0
    return nullptr;
4361
0
  }
4362
0
4363
0
  if (!mLoadInfo) {
4364
0
    return nullptr;
4365
0
  }
4366
0
4367
0
  // If a custom performance storage is set, let's use it.
4368
0
  mozilla::dom::PerformanceStorage* performanceStorage = mLoadInfo->GetPerformanceStorage();
4369
0
  if (performanceStorage) {
4370
0
    return performanceStorage;
4371
0
  }
4372
0
4373
0
  nsCOMPtr<nsIDocument> loadingDocument;
4374
0
  mLoadInfo->GetLoadingDocument(getter_AddRefs(loadingDocument));
4375
0
  if (!loadingDocument) {
4376
0
    return nullptr;
4377
0
  }
4378
0
4379
0
  // We only add to the document's performance object if it has the same
4380
0
  // principal as the one triggering the load. This is to prevent navigations
4381
0
  // triggered _by_ the iframe from showing up in the parent document's
4382
0
  // performance entries if they have different origins.
4383
0
  if (!mLoadInfo->TriggeringPrincipal()->Equals(loadingDocument->NodePrincipal())) {
4384
0
    return nullptr;
4385
0
  }
4386
0
4387
0
  nsCOMPtr<nsPIDOMWindowInner> innerWindow = loadingDocument->GetInnerWindow();
4388
0
  if (!innerWindow) {
4389
0
    return nullptr;
4390
0
  }
4391
0
4392
0
  mozilla::dom::Performance* performance = innerWindow->GetPerformance();
4393
0
  if (!performance) {
4394
0
    return nullptr;
4395
0
  }
4396
0
4397
0
  return performance->AsPerformanceStorage();
4398
0
}
4399
4400
void
4401
HttpBaseChannel::MaybeReportTimingData()
4402
0
{
4403
0
  mozilla::dom::PerformanceStorage* documentPerformance = GetPerformanceStorage();
4404
0
  if (documentPerformance) {
4405
0
      documentPerformance->AddEntry(this, this);
4406
0
  }
4407
0
}
4408
4409
NS_IMETHODIMP
4410
0
HttpBaseChannel::SetReportResourceTiming(bool enabled) {
4411
0
  mReportTiming = enabled;
4412
0
  return NS_OK;
4413
0
}
4414
4415
NS_IMETHODIMP
4416
0
HttpBaseChannel::GetReportResourceTiming(bool* _retval) {
4417
0
  *_retval = mReportTiming;
4418
0
  return NS_OK;
4419
0
}
4420
4421
nsIURI*
4422
HttpBaseChannel::GetReferringPage()
4423
0
{
4424
0
  nsCOMPtr<nsPIDOMWindowInner> pDomWindow = GetInnerDOMWindow();
4425
0
  if (!pDomWindow) {
4426
0
    return nullptr;
4427
0
  }
4428
0
  return pDomWindow->GetDocumentURI();
4429
0
}
4430
4431
nsPIDOMWindowInner*
4432
HttpBaseChannel::GetInnerDOMWindow()
4433
0
{
4434
0
    nsCOMPtr<nsILoadContext> loadContext;
4435
0
    NS_QueryNotificationCallbacks(this, loadContext);
4436
0
    if (!loadContext) {
4437
0
        return nullptr;
4438
0
    }
4439
0
    nsCOMPtr<mozIDOMWindowProxy> domWindow;
4440
0
    loadContext->GetAssociatedWindow(getter_AddRefs(domWindow));
4441
0
    if (!domWindow) {
4442
0
        return nullptr;
4443
0
    }
4444
0
    auto* pDomWindow = nsPIDOMWindowOuter::From(domWindow);
4445
0
    if (!pDomWindow) {
4446
0
        return nullptr;
4447
0
    }
4448
0
    nsCOMPtr<nsPIDOMWindowInner> innerWindow = pDomWindow->GetCurrentInnerWindow();
4449
0
    if (!innerWindow) {
4450
0
      return nullptr;
4451
0
    }
4452
0
4453
0
    return innerWindow;
4454
0
}
4455
4456
//-----------------------------------------------------------------------------
4457
// HttpBaseChannel::nsIThrottledInputChannel
4458
//-----------------------------------------------------------------------------
4459
4460
NS_IMETHODIMP
4461
HttpBaseChannel::SetThrottleQueue(nsIInputChannelThrottleQueue* aQueue)
4462
0
{
4463
0
  if (!XRE_IsParentProcess()) {
4464
0
    return NS_ERROR_FAILURE;
4465
0
  }
4466
0
4467
0
  mThrottleQueue = aQueue;
4468
0
  return NS_OK;
4469
0
}
4470
4471
NS_IMETHODIMP
4472
HttpBaseChannel::GetThrottleQueue(nsIInputChannelThrottleQueue** aQueue)
4473
0
{
4474
0
  *aQueue = mThrottleQueue;
4475
0
  return NS_OK;
4476
0
}
4477
4478
//------------------------------------------------------------------------------
4479
4480
bool
4481
HttpBaseChannel::EnsureRequestContextID()
4482
0
{
4483
0
    if (mRequestContextID) {
4484
0
        // Already have a request context ID, no need to do the rest of this work
4485
0
        LOG(("HttpBaseChannel::EnsureRequestContextID this=%p id=%" PRIx64,
4486
0
             this, mRequestContextID));
4487
0
        return true;
4488
0
    }
4489
0
4490
0
    // Find the loadgroup at the end of the chain in order
4491
0
    // to make sure all channels derived from the load group
4492
0
    // use the same connection scope.
4493
0
    nsCOMPtr<nsILoadGroupChild> childLoadGroup = do_QueryInterface(mLoadGroup);
4494
0
    if (!childLoadGroup) {
4495
0
        return false;
4496
0
    }
4497
0
4498
0
    nsCOMPtr<nsILoadGroup> rootLoadGroup;
4499
0
    childLoadGroup->GetRootLoadGroup(getter_AddRefs(rootLoadGroup));
4500
0
    if (!rootLoadGroup) {
4501
0
        return false;
4502
0
    }
4503
0
4504
0
    // Set the load group connection scope on this channel and its transaction
4505
0
    rootLoadGroup->GetRequestContextID(&mRequestContextID);
4506
0
4507
0
    LOG(("HttpBaseChannel::EnsureRequestContextID this=%p id=%" PRIx64,
4508
0
         this, mRequestContextID));
4509
0
4510
0
    return true;
4511
0
}
4512
4513
bool
4514
HttpBaseChannel::EnsureRequestContext()
4515
0
{
4516
0
    if (mRequestContext) {
4517
0
        // Already have a request context, no need to do the rest of this work
4518
0
        return true;
4519
0
    }
4520
0
4521
0
    if (!EnsureRequestContextID()) {
4522
0
        return false;
4523
0
    }
4524
0
4525
0
    nsIRequestContextService* rcsvc = gHttpHandler->GetRequestContextService();
4526
0
    if (!rcsvc) {
4527
0
        return false;
4528
0
    }
4529
0
4530
0
    rcsvc->GetRequestContext(mRequestContextID, getter_AddRefs(mRequestContext));
4531
0
    if (!mRequestContext) {
4532
0
        return false;
4533
0
    }
4534
0
4535
0
    return true;
4536
0
}
4537
4538
void
4539
HttpBaseChannel::EnsureTopLevelOuterContentWindowId()
4540
0
{
4541
0
  if (mTopLevelOuterContentWindowId) {
4542
0
    return;
4543
0
  }
4544
0
4545
0
  nsCOMPtr<nsILoadContext> loadContext;
4546
0
  GetCallback(loadContext);
4547
0
  if (!loadContext) {
4548
0
    return;
4549
0
  }
4550
0
4551
0
  nsCOMPtr<mozIDOMWindowProxy> topWindow;
4552
0
  loadContext->GetTopWindow(getter_AddRefs(topWindow));
4553
0
  if (!topWindow) {
4554
0
    return;
4555
0
  }
4556
0
4557
0
  mTopLevelOuterContentWindowId =
4558
0
    nsPIDOMWindowOuter::From(topWindow)->WindowID();
4559
0
}
4560
4561
void
4562
HttpBaseChannel::SetCorsPreflightParameters(const nsTArray<nsCString>& aUnsafeHeaders)
4563
0
{
4564
0
  MOZ_RELEASE_ASSERT(!mRequestObserversCalled);
4565
0
4566
0
  mRequireCORSPreflight = true;
4567
0
  mUnsafeHeaders = aUnsafeHeaders;
4568
0
}
4569
4570
void
4571
HttpBaseChannel::SetAltDataForChild(bool aIsForChild)
4572
0
{
4573
0
  mAltDataForChild = aIsForChild;
4574
0
}
4575
4576
NS_IMETHODIMP
4577
HttpBaseChannel::GetBlockAuthPrompt(bool* aValue)
4578
0
{
4579
0
  if (!aValue) {
4580
0
    return NS_ERROR_FAILURE;
4581
0
  }
4582
0
4583
0
  *aValue = mBlockAuthPrompt;
4584
0
  return NS_OK;
4585
0
}
4586
4587
NS_IMETHODIMP
4588
HttpBaseChannel::SetBlockAuthPrompt(bool aValue)
4589
0
{
4590
0
  ENSURE_CALLED_BEFORE_CONNECT();
4591
0
4592
0
  mBlockAuthPrompt = aValue;
4593
0
  return NS_OK;
4594
0
}
4595
4596
NS_IMETHODIMP
4597
HttpBaseChannel::GetConnectionInfoHashKey(nsACString& aConnectionInfoHashKey)
4598
0
{
4599
0
  if (!mConnectionInfo) {
4600
0
    return NS_ERROR_FAILURE;
4601
0
  }
4602
0
  aConnectionInfoHashKey.Assign(mConnectionInfo->HashKey());
4603
0
  return NS_OK;
4604
0
}
4605
4606
NS_IMETHODIMP
4607
HttpBaseChannel::GetLastRedirectFlags(uint32_t *aValue)
4608
0
{
4609
0
  NS_ENSURE_ARG(aValue);
4610
0
  *aValue = mLastRedirectFlags;
4611
0
  return NS_OK;
4612
0
}
4613
4614
NS_IMETHODIMP
4615
HttpBaseChannel::SetLastRedirectFlags(uint32_t aValue)
4616
0
{
4617
0
  mLastRedirectFlags = aValue;
4618
0
  return NS_OK;
4619
0
}
4620
4621
NS_IMETHODIMP
4622
HttpBaseChannel::GetNavigationStartTimeStamp(TimeStamp* aTimeStamp)
4623
0
{
4624
0
  return NS_ERROR_NOT_IMPLEMENTED;
4625
0
}
4626
4627
NS_IMETHODIMP
4628
HttpBaseChannel::SetNavigationStartTimeStamp(TimeStamp aTimeStamp)
4629
0
{
4630
0
  return NS_ERROR_NOT_IMPLEMENTED;
4631
0
}
4632
4633
nsresult
4634
HttpBaseChannel::CheckRedirectLimit(uint32_t aRedirectFlags) const
4635
0
{
4636
0
  if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
4637
0
    // Some platform features, like Service Workers, depend on internal
4638
0
    // redirects.  We should allow some number of internal redirects above
4639
0
    // and beyond the normal redirect limit so these features continue
4640
0
    // to work.
4641
0
    static const int8_t kMinInternalRedirects = 5;
4642
0
4643
0
    if (mInternalRedirectCount >= (mRedirectionLimit + kMinInternalRedirects)) {
4644
0
      LOG(("internal redirection limit reached!\n"));
4645
0
      return NS_ERROR_REDIRECT_LOOP;
4646
0
    }
4647
0
    return NS_OK;
4648
0
  }
4649
0
4650
0
  MOZ_ASSERT(aRedirectFlags & (nsIChannelEventSink::REDIRECT_TEMPORARY |
4651
0
                               nsIChannelEventSink::REDIRECT_PERMANENT |
4652
0
                               nsIChannelEventSink::REDIRECT_STS_UPGRADE));
4653
0
4654
0
  if (mRedirectCount >= mRedirectionLimit) {
4655
0
    LOG(("redirection limit reached!\n"));
4656
0
    return NS_ERROR_REDIRECT_LOOP;
4657
0
  }
4658
0
4659
0
  return NS_OK;
4660
0
}
4661
4662
// NOTE: This function duplicates code from nsBaseChannel. This will go away
4663
// once HTTP uses nsBaseChannel (part of bug 312760)
4664
/* static */ void
4665
HttpBaseChannel::CallTypeSniffers(void *aClosure, const uint8_t *aData,
4666
                                  uint32_t aCount)
4667
0
{
4668
0
  nsIChannel *chan = static_cast<nsIChannel*>(aClosure);
4669
0
4670
0
  nsAutoCString newType;
4671
0
  NS_SniffContent(NS_CONTENT_SNIFFER_CATEGORY, chan, aData, aCount, newType);
4672
0
  if (!newType.IsEmpty()) {
4673
0
    chan->SetContentType(newType);
4674
0
  }
4675
0
}
4676
4677
template <class T>
4678
static void
4679
ParseServerTimingHeader(const nsAutoPtr<T> &aHeader,
4680
                        nsTArray<nsCOMPtr<nsIServerTiming>>& aOutput)
4681
0
{
4682
0
  if (!aHeader) {
4683
0
    return;
4684
0
  }
4685
0
4686
0
  nsAutoCString serverTimingHeader;
4687
0
  Unused << aHeader->GetHeader(nsHttp::Server_Timing, serverTimingHeader);
4688
0
  if (serverTimingHeader.IsEmpty()) {
4689
0
    return;
4690
0
  }
4691
0
4692
0
  ServerTimingParser parser(serverTimingHeader);
4693
0
  parser.Parse();
4694
0
4695
0
  nsTArray<nsCOMPtr<nsIServerTiming>> array = parser.TakeServerTimingHeaders();
4696
0
  aOutput.AppendElements(array);
4697
0
}
Unexecuted instantiation: Unified_cpp_protocol_http0.cpp:void mozilla::net::ParseServerTimingHeader<mozilla::net::nsHttpResponseHead>(nsAutoPtr<mozilla::net::nsHttpResponseHead> const&, nsTArray<nsCOMPtr<nsIServerTiming> >&)
Unexecuted instantiation: Unified_cpp_protocol_http0.cpp:void mozilla::net::ParseServerTimingHeader<mozilla::net::nsHttpHeaderArray>(nsAutoPtr<mozilla::net::nsHttpHeaderArray> const&, nsTArray<nsCOMPtr<nsIServerTiming> >&)
4698
4699
NS_IMETHODIMP
4700
HttpBaseChannel::GetServerTiming(nsIArray **aServerTiming)
4701
0
{
4702
0
  nsresult rv;
4703
0
  NS_ENSURE_ARG_POINTER(aServerTiming);
4704
0
4705
0
  nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
4706
0
  NS_ENSURE_SUCCESS(rv, rv);
4707
0
4708
0
  nsTArray<nsCOMPtr<nsIServerTiming>> data;
4709
0
  rv = GetNativeServerTiming(data);
4710
0
  NS_ENSURE_SUCCESS(rv, rv);
4711
0
4712
0
  for (const auto &entry : data) {
4713
0
    array->AppendElement(entry);
4714
0
  }
4715
0
4716
0
  array.forget(aServerTiming);
4717
0
  return NS_OK;
4718
0
}
4719
4720
NS_IMETHODIMP
4721
HttpBaseChannel::GetNativeServerTiming(nsTArray<nsCOMPtr<nsIServerTiming>>& aServerTiming)
4722
0
{
4723
0
  aServerTiming.Clear();
4724
0
4725
0
  bool isHTTPS = false;
4726
0
  if (NS_SUCCEEDED(mURI->SchemeIs("https", &isHTTPS)) && isHTTPS) {
4727
0
    ParseServerTimingHeader(mResponseHead, aServerTiming);
4728
0
    ParseServerTimingHeader(mResponseTrailers, aServerTiming);
4729
0
  }
4730
0
4731
0
  return NS_OK;
4732
0
}
4733
4734
NS_IMETHODIMP
4735
HttpBaseChannel::CancelForTrackingProtection()
4736
0
{
4737
0
  return Cancel(NS_ERROR_TRACKING_URI);
4738
0
}
4739
4740
} // namespace net
4741
} // namespace mozilla