tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsLoadGroup.cpp (36178B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set sw=2 ts=4 sts=2 et cin: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/DebugOnly.h"
      8 
      9 #include "nsLoadGroup.h"
     10 
     11 #include "nsArrayEnumerator.h"
     12 #include "nsCOMArray.h"
     13 #include "nsCOMPtr.h"
     14 #include "nsContentUtils.h"
     15 #include "mozilla/Logging.h"
     16 #include "nsString.h"
     17 #include "nsTArray.h"
     18 #include "nsIHttpChannel.h"
     19 #include "nsIHttpChannelInternal.h"
     20 #include "nsITimedChannel.h"
     21 #include "nsIInterfaceRequestor.h"
     22 #include "nsIRequestObserver.h"
     23 #include "CacheObserver.h"
     24 #include "MainThreadUtils.h"
     25 #include "RequestContextService.h"
     26 #include "mozilla/glean/NetwerkMetrics.h"
     27 #include "mozilla/glean/NetwerkProtocolHttpMetrics.h"
     28 #include "mozilla/StoragePrincipalHelper.h"
     29 #include "mozilla/net/NeckoCommon.h"
     30 #include "mozilla/net/NeckoChild.h"
     31 #include "mozilla/StaticPrefs_network.h"
     32 
     33 namespace mozilla {
     34 namespace net {
     35 
     36 //
     37 // Log module for nsILoadGroup logging...
     38 //
     39 // To enable logging (see prlog.h for full details):
     40 //
     41 //    set MOZ_LOG=LoadGroup:5
     42 //    set MOZ_LOG_FILE=network.log
     43 //
     44 // This enables LogLevel::Debug level information and places all output in
     45 // the file network.log.
     46 //
     47 static LazyLogModule gLoadGroupLog("LoadGroup");
     48 #undef LOG
     49 #define LOG(args) MOZ_LOG(gLoadGroupLog, mozilla::LogLevel::Debug, args)
     50 
     51 ////////////////////////////////////////////////////////////////////////////////
     52 
     53 class RequestMapEntry : public PLDHashEntryHdr {
     54 public:
     55  explicit RequestMapEntry(nsIRequest* aRequest) : mKey(aRequest) {}
     56 
     57  nsCOMPtr<nsIRequest> mKey;
     58 };
     59 
     60 static bool RequestHashMatchEntry(const PLDHashEntryHdr* entry,
     61                                  const void* key) {
     62  const RequestMapEntry* e = static_cast<const RequestMapEntry*>(entry);
     63  const nsIRequest* request = static_cast<const nsIRequest*>(key);
     64 
     65  return e->mKey == request;
     66 }
     67 
     68 static void RequestHashClearEntry(PLDHashTable* table, PLDHashEntryHdr* entry) {
     69  RequestMapEntry* e = static_cast<RequestMapEntry*>(entry);
     70 
     71  // An entry is being cleared, let the entry do its own cleanup.
     72  e->~RequestMapEntry();
     73 }
     74 
     75 static void RequestHashInitEntry(PLDHashEntryHdr* entry, const void* key) {
     76  const nsIRequest* const_request = static_cast<const nsIRequest*>(key);
     77  nsIRequest* request = const_cast<nsIRequest*>(const_request);
     78 
     79  // Initialize the entry with placement new
     80  new (entry) RequestMapEntry(request);
     81 }
     82 
     83 static const PLDHashTableOps sRequestHashOps = {
     84    PLDHashTable::HashVoidPtrKeyStub, RequestHashMatchEntry,
     85    PLDHashTable::MoveEntryStub, RequestHashClearEntry, RequestHashInitEntry};
     86 
     87 static void RescheduleRequest(nsIRequest* aRequest, int32_t delta) {
     88  nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(aRequest);
     89  if (p) p->AdjustPriority(delta);
     90 }
     91 
     92 nsLoadGroup::nsLoadGroup()
     93    : mRequests(&sRequestHashOps, sizeof(RequestMapEntry)) {
     94  LOG(("LOADGROUP [%p]: Created.\n", this));
     95 }
     96 
     97 nsLoadGroup::~nsLoadGroup() {
     98  DebugOnly<nsresult> rv =
     99      CancelWithReason(NS_BINDING_ABORTED, "nsLoadGroup::~nsLoadGroup"_ns);
    100  NS_ASSERTION(NS_SUCCEEDED(rv), "Cancel failed");
    101 
    102  mDefaultLoadRequest = nullptr;
    103 
    104  if (mRequestContext && !mExternalRequestContext) {
    105    mRequestContextService->RemoveRequestContext(mRequestContext->GetID());
    106    if (IsNeckoChild() && gNeckoChild && gNeckoChild->CanSend()) {
    107      gNeckoChild->SendRemoveRequestContext(mRequestContext->GetID());
    108    }
    109  }
    110 
    111  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    112  if (os) {
    113    (void)os->RemoveObserver(this, "last-pb-context-exited");
    114  }
    115 
    116  if (mPageSize) {
    117    glean::network::page_load_size.Get("page"_ns).Accumulate(mPageSize);
    118  }
    119  if (mTotalSubresourcesSize) {
    120    glean::network::page_load_size.Get("subresources"_ns)
    121        .Accumulate(mTotalSubresourcesSize);
    122  }
    123 
    124  LOG(("LOADGROUP [%p]: Destroyed.\n", this));
    125 }
    126 
    127 ////////////////////////////////////////////////////////////////////////////////
    128 // nsISupports methods:
    129 
    130 NS_IMPL_ISUPPORTS(nsLoadGroup, nsILoadGroup, nsILoadGroupChild, nsIRequest,
    131                  nsISupportsPriority, nsISupportsWeakReference, nsIObserver)
    132 
    133 ////////////////////////////////////////////////////////////////////////////////
    134 // nsIRequest methods:
    135 
    136 NS_IMETHODIMP
    137 nsLoadGroup::GetName(nsACString& result) {
    138  // XXX is this the right "name" for a load group?
    139 
    140  if (!mDefaultLoadRequest) {
    141    result.Truncate();
    142    return NS_OK;
    143  }
    144 
    145  return mDefaultLoadRequest->GetName(result);
    146 }
    147 
    148 NS_IMETHODIMP
    149 nsLoadGroup::IsPending(bool* aResult) {
    150  *aResult = mForegroundCount > 0;
    151  return NS_OK;
    152 }
    153 
    154 NS_IMETHODIMP
    155 nsLoadGroup::GetStatus(nsresult* status) {
    156  if (NS_SUCCEEDED(mStatus) && mDefaultLoadRequest) {
    157    return mDefaultLoadRequest->GetStatus(status);
    158  }
    159 
    160  *status = mStatus;
    161  return NS_OK;
    162 }
    163 
    164 static bool AppendRequestsToArray(PLDHashTable* aTable,
    165                                  nsTArray<nsIRequest*>* aArray) {
    166  for (auto iter = aTable->Iter(); !iter.Done(); iter.Next()) {
    167    auto* e = static_cast<RequestMapEntry*>(iter.Get());
    168    nsIRequest* request = e->mKey;
    169    MOZ_DIAGNOSTIC_ASSERT(request, "Null key in mRequests PLDHashTable entry");
    170 
    171    // XXX(Bug 1631371) Check if this should use a fallible operation as it
    172    // pretended earlier.
    173    aArray->AppendElement(request);
    174    NS_ADDREF(request);
    175  }
    176 
    177  if (aArray->Length() != aTable->EntryCount()) {
    178    for (uint32_t i = 0, len = aArray->Length(); i < len; ++i) {
    179      NS_RELEASE((*aArray)[i]);
    180    }
    181    return false;
    182  }
    183  return true;
    184 }
    185 
    186 NS_IMETHODIMP nsLoadGroup::SetCanceledReason(const nsACString& aReason) {
    187  return SetCanceledReasonImpl(aReason);
    188 }
    189 
    190 NS_IMETHODIMP nsLoadGroup::GetCanceledReason(nsACString& aReason) {
    191  return GetCanceledReasonImpl(aReason);
    192 }
    193 
    194 NS_IMETHODIMP nsLoadGroup::CancelWithReason(nsresult aStatus,
    195                                            const nsACString& aReason) {
    196  return CancelWithReasonImpl(aStatus, aReason);
    197 }
    198 
    199 NS_IMETHODIMP
    200 nsLoadGroup::Cancel(nsresult status) {
    201  MOZ_ASSERT(NS_IsMainThread());
    202 
    203  NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code");
    204  nsresult rv;
    205  uint32_t count = mRequests.EntryCount();
    206 
    207  AutoTArray<nsIRequest*, 8> requests;
    208 
    209  if (!AppendRequestsToArray(&mRequests, &requests)) {
    210    return NS_ERROR_OUT_OF_MEMORY;
    211  }
    212 
    213  // set the load group status to our cancel status while we cancel
    214  // all our requests...once the cancel is done, we'll reset it...
    215  //
    216  mStatus = status;
    217 
    218  // Set the flag indicating that the loadgroup is being canceled...  This
    219  // prevents any new channels from being added during the operation.
    220  //
    221  mIsCanceling = true;
    222 
    223  nsresult firstError = NS_OK;
    224  while (count > 0) {
    225    nsCOMPtr<nsIRequest> request = requests.ElementAt(--count);
    226 
    227    NS_ASSERTION(request, "NULL request found in list.");
    228 
    229    if (!mRequests.Search(request)) {
    230      // |request| was removed already
    231      // We need to null out the entry in the request array so we don't try
    232      // to notify the observers for this request.
    233      nsCOMPtr<nsIRequest> request = dont_AddRef(requests.ElementAt(count));
    234      requests.ElementAt(count) = nullptr;
    235 
    236      continue;
    237    }
    238 
    239    if (MOZ_LOG_TEST(gLoadGroupLog, LogLevel::Debug)) {
    240      nsAutoCString nameStr;
    241      request->GetName(nameStr);
    242      LOG(("LOADGROUP [%p]: Canceling request %p %s.\n", this, request.get(),
    243           nameStr.get()));
    244    }
    245 
    246    // Cancel the request...
    247    rv = request->CancelWithReason(status, mCanceledReason);
    248 
    249    // Remember the first failure and return it...
    250    if (NS_FAILED(rv) && NS_SUCCEEDED(firstError)) firstError = rv;
    251 
    252    if (NS_FAILED(RemoveRequestFromHashtable(request, status))) {
    253      // It's possible that request->Cancel causes the request to be removed
    254      // from the loadgroup causing RemoveRequestFromHashtable to fail.
    255      // In that case we shouldn't call NotifyRemovalObservers or decrement
    256      // mForegroundCount since that has already happened.
    257      nsCOMPtr<nsIRequest> request = dont_AddRef(requests.ElementAt(count));
    258      requests.ElementAt(count) = nullptr;
    259 
    260      continue;
    261    }
    262  }
    263 
    264  for (count = requests.Length(); count > 0;) {
    265    nsCOMPtr<nsIRequest> request = dont_AddRef(requests.ElementAt(--count));
    266    (void)NotifyRemovalObservers(request, status);
    267  }
    268 
    269  if (mRequestContext) {
    270    (void)mRequestContext->CancelTailPendingRequests(status);
    271  }
    272 
    273 #if defined(DEBUG)
    274  NS_ASSERTION(mRequests.EntryCount() == 0, "Request list is not empty.");
    275  NS_ASSERTION(mForegroundCount == 0, "Foreground URLs are active.");
    276 #endif
    277 
    278  mStatus = NS_OK;
    279  mIsCanceling = false;
    280 
    281  return firstError;
    282 }
    283 
    284 NS_IMETHODIMP
    285 nsLoadGroup::Suspend() {
    286  nsresult rv, firstError;
    287  uint32_t count = mRequests.EntryCount();
    288 
    289  AutoTArray<nsIRequest*, 8> requests;
    290 
    291  if (!AppendRequestsToArray(&mRequests, &requests)) {
    292    return NS_ERROR_OUT_OF_MEMORY;
    293  }
    294 
    295  firstError = NS_OK;
    296  //
    297  // Operate the elements from back to front so that if items get
    298  // get removed from the list it won't affect our iteration
    299  //
    300  while (count > 0) {
    301    nsCOMPtr<nsIRequest> request = dont_AddRef(requests.ElementAt(--count));
    302 
    303    NS_ASSERTION(request, "NULL request found in list.");
    304    if (!request) continue;
    305 
    306    if (MOZ_LOG_TEST(gLoadGroupLog, LogLevel::Debug)) {
    307      nsAutoCString nameStr;
    308      request->GetName(nameStr);
    309      LOG(("LOADGROUP [%p]: Suspending request %p %s.\n", this, request.get(),
    310           nameStr.get()));
    311    }
    312 
    313    // Suspend the request...
    314    rv = request->Suspend();
    315 
    316    // Remember the first failure and return it...
    317    if (NS_FAILED(rv) && NS_SUCCEEDED(firstError)) firstError = rv;
    318  }
    319 
    320  return firstError;
    321 }
    322 
    323 NS_IMETHODIMP
    324 nsLoadGroup::Resume() {
    325  nsresult rv, firstError;
    326  uint32_t count = mRequests.EntryCount();
    327 
    328  AutoTArray<nsIRequest*, 8> requests;
    329 
    330  if (!AppendRequestsToArray(&mRequests, &requests)) {
    331    return NS_ERROR_OUT_OF_MEMORY;
    332  }
    333 
    334  firstError = NS_OK;
    335  //
    336  // Operate the elements from back to front so that if items get
    337  // get removed from the list it won't affect our iteration
    338  //
    339  while (count > 0) {
    340    nsCOMPtr<nsIRequest> request = dont_AddRef(requests.ElementAt(--count));
    341 
    342    NS_ASSERTION(request, "NULL request found in list.");
    343    if (!request) continue;
    344 
    345    if (MOZ_LOG_TEST(gLoadGroupLog, LogLevel::Debug)) {
    346      nsAutoCString nameStr;
    347      request->GetName(nameStr);
    348      LOG(("LOADGROUP [%p]: Resuming request %p %s.\n", this, request.get(),
    349           nameStr.get()));
    350    }
    351 
    352    // Resume the request...
    353    rv = request->Resume();
    354 
    355    // Remember the first failure and return it...
    356    if (NS_FAILED(rv) && NS_SUCCEEDED(firstError)) firstError = rv;
    357  }
    358 
    359  return firstError;
    360 }
    361 
    362 NS_IMETHODIMP
    363 nsLoadGroup::GetLoadFlags(uint32_t* aLoadFlags) {
    364  *aLoadFlags = mLoadFlags;
    365  return NS_OK;
    366 }
    367 
    368 NS_IMETHODIMP
    369 nsLoadGroup::SetLoadFlags(uint32_t aLoadFlags) {
    370  mLoadFlags = aLoadFlags;
    371  return NS_OK;
    372 }
    373 
    374 NS_IMETHODIMP
    375 nsLoadGroup::GetTRRMode(nsIRequest::TRRMode* aTRRMode) {
    376  return GetTRRModeImpl(aTRRMode);
    377 }
    378 
    379 NS_IMETHODIMP
    380 nsLoadGroup::SetTRRMode(nsIRequest::TRRMode aTRRMode) {
    381  return SetTRRModeImpl(aTRRMode);
    382 }
    383 
    384 NS_IMETHODIMP
    385 nsLoadGroup::GetLoadGroup(nsILoadGroup** loadGroup) {
    386  nsCOMPtr<nsILoadGroup> result = mLoadGroup;
    387  result.forget(loadGroup);
    388  return NS_OK;
    389 }
    390 
    391 NS_IMETHODIMP
    392 nsLoadGroup::SetLoadGroup(nsILoadGroup* loadGroup) {
    393  mLoadGroup = loadGroup;
    394  return NS_OK;
    395 }
    396 
    397 ////////////////////////////////////////////////////////////////////////////////
    398 // nsILoadGroup methods:
    399 
    400 NS_IMETHODIMP
    401 nsLoadGroup::GetDefaultLoadRequest(nsIRequest** aRequest) {
    402  nsCOMPtr<nsIRequest> result = mDefaultLoadRequest;
    403  result.forget(aRequest);
    404  return NS_OK;
    405 }
    406 
    407 NS_IMETHODIMP
    408 nsLoadGroup::SetDefaultLoadRequest(nsIRequest* aRequest) {
    409  LOG(("nsLoadGroup::SetDefaultLoadRequest this=%p default-request=%p", this,
    410       aRequest));
    411 
    412  mDefaultLoadRequest = aRequest;
    413  // Inherit the group load flags from the default load request
    414  if (mDefaultLoadRequest) {
    415    mDefaultLoadRequest->GetLoadFlags(&mLoadFlags);
    416    //
    417    // Mask off any bits that are not part of the nsIRequest flags.
    418    // in particular, nsIChannel::LOAD_DOCUMENT_URI...
    419    //
    420    mLoadFlags &= nsIRequest::LOAD_REQUESTMASK;
    421 
    422    nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(aRequest);
    423    mDefaultLoadIsTimed = timedChannel != nullptr;
    424    if (mDefaultLoadIsTimed) {
    425      timedChannel->GetChannelCreation(&mDefaultRequestCreationTime);
    426    }
    427  }
    428  // Else, do not change the group's load flags (see bug 95981)
    429  return NS_OK;
    430 }
    431 
    432 NS_IMETHODIMP
    433 nsLoadGroup::AddRequest(nsIRequest* request, nsISupports* ctxt) {
    434  nsresult rv;
    435 
    436  if (MOZ_LOG_TEST(gLoadGroupLog, LogLevel::Debug)) {
    437    nsAutoCString nameStr;
    438    request->GetName(nameStr);
    439    LOG(("LOADGROUP [%p]: Adding request %p %s (count=%d).\n", this, request,
    440         nameStr.get(), mRequests.EntryCount()));
    441  }
    442 
    443  NS_ASSERTION(!mRequests.Search(request),
    444               "Entry added to loadgroup twice, don't do that");
    445 
    446  //
    447  // Do not add the channel, if the loadgroup is being canceled...
    448  //
    449  if (mIsCanceling) {
    450    LOG(
    451        ("LOADGROUP [%p]: AddChannel() ABORTED because LoadGroup is"
    452         " being canceled!!\n",
    453         this));
    454 
    455    return NS_BINDING_ABORTED;
    456  }
    457 
    458  nsLoadFlags flags;
    459  // if the request is the default load request or if the default load
    460  // request is null, then the load group should inherit its load flags from
    461  // the request, but also we need to enforce defaultLoadFlags.
    462  if (mDefaultLoadRequest == request || !mDefaultLoadRequest) {
    463    rv = MergeDefaultLoadFlags(request, flags);
    464  } else {
    465    rv = MergeLoadFlags(request, flags);
    466  }
    467  if (NS_FAILED(rv)) return rv;
    468 
    469  //
    470  // Add the request to the list of active requests...
    471  //
    472 
    473  auto* entry = static_cast<RequestMapEntry*>(mRequests.Add(request, fallible));
    474  if (!entry) {
    475    return NS_ERROR_OUT_OF_MEMORY;
    476  }
    477 
    478  if (mPriority != 0) RescheduleRequest(request, mPriority);
    479 
    480  bool foreground = !(flags & nsIRequest::LOAD_BACKGROUND);
    481  if (foreground) {
    482    // Update the count of foreground URIs..
    483    mForegroundCount += 1;
    484  }
    485 
    486  if (foreground || mNotifyObserverAboutBackgroundRequests) {
    487    //
    488    // Fire the OnStartRequest notification out to the observer...
    489    //
    490    // If the notification fails then DO NOT add the request to
    491    // the load group.
    492    //
    493    nsCOMPtr<nsIRequestObserver> observer = do_QueryReferent(mObserver);
    494    if (observer) {
    495      LOG(
    496          ("LOADGROUP [%p]: Firing OnStartRequest for request %p."
    497           "(foreground count=%d).\n",
    498           this, request, mForegroundCount));
    499 
    500      rv = observer->OnStartRequest(request);
    501      if (NS_FAILED(rv)) {
    502        LOG(("LOADGROUP [%p]: OnStartRequest for request %p FAILED.\n", this,
    503             request));
    504        //
    505        // The URI load has been canceled by the observer.  Clean up
    506        // the damage...
    507        //
    508 
    509        mRequests.Remove(request);
    510 
    511        rv = NS_OK;
    512 
    513        if (foreground) {
    514          mForegroundCount -= 1;
    515        }
    516      }
    517    }
    518 
    519    // Ensure that we're part of our loadgroup while pending
    520    if (foreground && mForegroundCount == 1 && mLoadGroup) {
    521      mLoadGroup->AddRequest(this, nullptr);
    522    }
    523  }
    524 
    525  return rv;
    526 }
    527 
    528 NS_IMETHODIMP
    529 nsLoadGroup::RemoveRequest(nsIRequest* request, nsISupports* ctxt,
    530                           nsresult aStatus) {
    531  // Make sure we have a owning reference to the request we're about
    532  // to remove.
    533  nsCOMPtr<nsIRequest> kungFuDeathGrip(request);
    534 
    535  nsresult rv = RemoveRequestFromHashtable(request, aStatus);
    536  if (NS_FAILED(rv)) {
    537    return rv;
    538  }
    539 
    540  return NotifyRemovalObservers(request, aStatus);
    541 }
    542 
    543 static uint64_t GetTransferSize(nsITimedChannel* aTimedChannel) {
    544  if (nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(aTimedChannel)) {
    545    uint64_t size = 0;
    546    (void)channel->GetTransferSize(&size);
    547    return size;
    548  }
    549 
    550  return 0;
    551 }
    552 
    553 nsresult nsLoadGroup::RemoveRequestFromHashtable(nsIRequest* request,
    554                                                 nsresult aStatus) {
    555  NS_ENSURE_ARG_POINTER(request);
    556  nsresult rv;
    557 
    558  if (MOZ_LOG_TEST(gLoadGroupLog, LogLevel::Debug)) {
    559    nsAutoCString nameStr;
    560    request->GetName(nameStr);
    561    LOG(("LOADGROUP [%p]: Removing request %p %s status %" PRIx32
    562         " (count=%d).\n",
    563         this, request, nameStr.get(), static_cast<uint32_t>(aStatus),
    564         mRequests.EntryCount() - 1));
    565  }
    566 
    567  //
    568  // Remove the request from the group.  If this fails, it means that
    569  // the request was *not* in the group so do not update the foreground
    570  // count or it will get messed up...
    571  //
    572  auto* entry = static_cast<RequestMapEntry*>(mRequests.Search(request));
    573 
    574  if (!entry) {
    575    LOG(("LOADGROUP [%p]: Unable to remove request %p. Not in group!\n", this,
    576         request));
    577 
    578    return NS_ERROR_FAILURE;
    579  }
    580 
    581  mRequests.RemoveEntry(entry);
    582 
    583  // Cache the status of mDefaultLoadRequest, It'll be used later in
    584  // TelemetryReport.
    585  if (request == mDefaultLoadRequest) {
    586    mDefaultStatus = aStatus;
    587  }
    588 
    589  // Collect telemetry stats only when default request is a timed channel.
    590  // Don't include failed requests in the timing statistics.
    591  if (mDefaultLoadIsTimed && NS_SUCCEEDED(aStatus)) {
    592    nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(request);
    593    if (timedChannel) {
    594      // Figure out if this request was served from the cache
    595      ++mTimedRequests;
    596      TimeStamp timeStamp;
    597      rv = timedChannel->GetCacheReadStart(&timeStamp);
    598      if (NS_SUCCEEDED(rv) && !timeStamp.IsNull()) {
    599        ++mCachedRequests;
    600      }
    601 
    602      if (request == mDefaultLoadRequest) {
    603        TelemetryReportChannel(timedChannel, true);
    604        mPageSize = GetTransferSize(timedChannel);
    605      } else {
    606        rv = timedChannel->GetAsyncOpen(&timeStamp);
    607        if (NS_SUCCEEDED(rv) && !timeStamp.IsNull()) {
    608          glean::http::subitem_open_latency_time.AccumulateRawDuration(
    609              timeStamp - mDefaultRequestCreationTime);
    610        }
    611 
    612        rv = timedChannel->GetResponseStart(&timeStamp);
    613        if (NS_SUCCEEDED(rv) && !timeStamp.IsNull()) {
    614          glean::http::subitem_first_byte_latency_time.AccumulateRawDuration(
    615              timeStamp - mDefaultRequestCreationTime);
    616        }
    617 
    618        TelemetryReportChannel(timedChannel, false);
    619        mTotalSubresourcesSize += GetTransferSize(timedChannel);
    620      }
    621    }
    622  }
    623 
    624  if (mRequests.EntryCount() == 0) {
    625    TelemetryReport();
    626  }
    627 
    628  return NS_OK;
    629 }
    630 
    631 nsresult nsLoadGroup::NotifyRemovalObservers(nsIRequest* request,
    632                                             nsresult aStatus) {
    633  NS_ENSURE_ARG_POINTER(request);
    634  // Undo any group priority delta...
    635  if (mPriority != 0) RescheduleRequest(request, -mPriority);
    636 
    637  nsLoadFlags flags;
    638  nsresult rv = request->GetLoadFlags(&flags);
    639  if (NS_FAILED(rv)) return rv;
    640 
    641  bool foreground = !(flags & nsIRequest::LOAD_BACKGROUND);
    642  if (foreground) {
    643    NS_ASSERTION(mForegroundCount > 0, "ForegroundCount messed up");
    644    mForegroundCount -= 1;
    645  }
    646 
    647  if (foreground || mNotifyObserverAboutBackgroundRequests) {
    648    // Fire the OnStopRequest out to the observer...
    649    nsCOMPtr<nsIRequestObserver> observer = do_QueryReferent(mObserver);
    650    if (observer) {
    651      LOG(
    652          ("LOADGROUP [%p]: Firing OnStopRequest for request %p."
    653           "(foreground count=%d).\n",
    654           this, request, mForegroundCount));
    655 
    656      rv = observer->OnStopRequest(request, aStatus);
    657 
    658      if (NS_FAILED(rv)) {
    659        LOG(("LOADGROUP [%p]: OnStopRequest for request %p FAILED.\n", this,
    660             request));
    661      }
    662    }
    663 
    664    // If that was the last request -> remove ourselves from loadgroup
    665    if (foreground && mForegroundCount == 0 && mLoadGroup) {
    666      mLoadGroup->RemoveRequest(this, nullptr, aStatus);
    667    }
    668  }
    669 
    670  return rv;
    671 }
    672 
    673 NS_IMETHODIMP
    674 nsLoadGroup::GetRequests(nsISimpleEnumerator** aRequests) {
    675  nsCOMArray<nsIRequest> requests;
    676  requests.SetCapacity(mRequests.EntryCount());
    677 
    678  for (auto iter = mRequests.Iter(); !iter.Done(); iter.Next()) {
    679    auto* e = static_cast<RequestMapEntry*>(iter.Get());
    680    requests.AppendObject(e->mKey);
    681  }
    682 
    683  return NS_NewArrayEnumerator(aRequests, requests, NS_GET_IID(nsIRequest));
    684 }
    685 
    686 NS_IMETHODIMP
    687 nsLoadGroup::GetTotalKeepAliveBytes(uint64_t* aTotalKeepAliveBytes) {
    688  MOZ_ASSERT(aTotalKeepAliveBytes);
    689  *aTotalKeepAliveBytes = mPendingKeepaliveRequestSize;
    690  return NS_OK;
    691 }
    692 
    693 NS_IMETHODIMP
    694 nsLoadGroup::SetTotalKeepAliveBytes(uint64_t aTotalKeepAliveBytes) {
    695  mPendingKeepaliveRequestSize = aTotalKeepAliveBytes;
    696  return NS_OK;
    697 }
    698 
    699 NS_IMETHODIMP
    700 nsLoadGroup::SetGroupObserver(nsIRequestObserver* aObserver) {
    701  SetGroupObserver(aObserver, false);
    702  return NS_OK;
    703 }
    704 
    705 void nsLoadGroup::SetGroupObserver(nsIRequestObserver* aObserver,
    706                                   bool aIncludeBackgroundRequests) {
    707  mObserver = do_GetWeakReference(aObserver);
    708  mNotifyObserverAboutBackgroundRequests = aIncludeBackgroundRequests;
    709 }
    710 
    711 NS_IMETHODIMP
    712 nsLoadGroup::GetGroupObserver(nsIRequestObserver** aResult) {
    713  nsCOMPtr<nsIRequestObserver> observer = do_QueryReferent(mObserver);
    714  observer.forget(aResult);
    715  return NS_OK;
    716 }
    717 
    718 NS_IMETHODIMP
    719 nsLoadGroup::GetActiveCount(uint32_t* aResult) {
    720  *aResult = mForegroundCount;
    721  return NS_OK;
    722 }
    723 
    724 NS_IMETHODIMP
    725 nsLoadGroup::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks) {
    726  NS_ENSURE_ARG_POINTER(aCallbacks);
    727  nsCOMPtr<nsIInterfaceRequestor> callbacks = mCallbacks;
    728  callbacks.forget(aCallbacks);
    729  return NS_OK;
    730 }
    731 
    732 NS_IMETHODIMP
    733 nsLoadGroup::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) {
    734  mCallbacks = aCallbacks;
    735  return NS_OK;
    736 }
    737 
    738 NS_IMETHODIMP
    739 nsLoadGroup::GetRequestContextID(uint64_t* aRCID) {
    740  if (!mRequestContext) {
    741    return NS_ERROR_NOT_AVAILABLE;
    742  }
    743  *aRCID = mRequestContext->GetID();
    744  return NS_OK;
    745 }
    746 
    747 ////////////////////////////////////////////////////////////////////////////////
    748 // nsILoadGroupChild methods:
    749 
    750 NS_IMETHODIMP
    751 nsLoadGroup::GetParentLoadGroup(nsILoadGroup** aParentLoadGroup) {
    752  *aParentLoadGroup = nullptr;
    753  nsCOMPtr<nsILoadGroup> parent = do_QueryReferent(mParentLoadGroup);
    754  if (!parent) return NS_OK;
    755  parent.forget(aParentLoadGroup);
    756  return NS_OK;
    757 }
    758 
    759 NS_IMETHODIMP
    760 nsLoadGroup::SetParentLoadGroup(nsILoadGroup* aParentLoadGroup) {
    761  mParentLoadGroup = do_GetWeakReference(aParentLoadGroup);
    762  return NS_OK;
    763 }
    764 
    765 NS_IMETHODIMP
    766 nsLoadGroup::GetChildLoadGroup(nsILoadGroup** aChildLoadGroup) {
    767  *aChildLoadGroup = do_AddRef(this).take();
    768  return NS_OK;
    769 }
    770 
    771 NS_IMETHODIMP
    772 nsLoadGroup::GetRootLoadGroup(nsILoadGroup** aRootLoadGroup) {
    773  // first recursively try the root load group of our parent
    774  nsCOMPtr<nsILoadGroupChild> ancestor = do_QueryReferent(mParentLoadGroup);
    775  if (ancestor) return ancestor->GetRootLoadGroup(aRootLoadGroup);
    776 
    777  // next recursively try the root load group of our own load grop
    778  ancestor = do_QueryInterface(mLoadGroup);
    779  if (ancestor) return ancestor->GetRootLoadGroup(aRootLoadGroup);
    780 
    781  // finally just return this
    782  *aRootLoadGroup = do_AddRef(this).take();
    783  return NS_OK;
    784 }
    785 
    786 ////////////////////////////////////////////////////////////////////////////////
    787 // nsISupportsPriority methods:
    788 
    789 NS_IMETHODIMP
    790 nsLoadGroup::GetPriority(int32_t* aValue) {
    791  *aValue = mPriority;
    792  return NS_OK;
    793 }
    794 
    795 NS_IMETHODIMP
    796 nsLoadGroup::SetPriority(int32_t aValue) {
    797  return AdjustPriority(aValue - mPriority);
    798 }
    799 
    800 NS_IMETHODIMP
    801 nsLoadGroup::AdjustPriority(int32_t aDelta) {
    802  // Update the priority for each request that supports nsISupportsPriority
    803  if (aDelta != 0) {
    804    mPriority += aDelta;
    805    for (auto iter = mRequests.Iter(); !iter.Done(); iter.Next()) {
    806      auto* e = static_cast<RequestMapEntry*>(iter.Get());
    807      RescheduleRequest(e->mKey, aDelta);
    808    }
    809  }
    810  return NS_OK;
    811 }
    812 
    813 NS_IMETHODIMP
    814 nsLoadGroup::GetDefaultLoadFlags(uint32_t* aFlags) {
    815  *aFlags = mDefaultLoadFlags;
    816  return NS_OK;
    817 }
    818 
    819 NS_IMETHODIMP
    820 nsLoadGroup::SetDefaultLoadFlags(uint32_t aFlags) {
    821  mDefaultLoadFlags = aFlags;
    822  return NS_OK;
    823 }
    824 
    825 ////////////////////////////////////////////////////////////////////////////////
    826 
    827 void nsLoadGroup::TelemetryReport() {
    828  // We should only report HTTP_PAGE_* telemetry if the defaultRequest was
    829  // actually successful.
    830  if (mDefaultLoadIsTimed && NS_SUCCEEDED(mDefaultStatus)) {
    831    glean::http::request_per_page.AccumulateSingleSample(mTimedRequests);
    832    if (mTimedRequests) {
    833      glean::http::request_per_page_from_cache.AccumulateSingleSample(
    834          mCachedRequests * 100 / mTimedRequests);
    835    }
    836  }
    837 
    838  mTimedRequests = 0;
    839  mCachedRequests = 0;
    840  mDefaultLoadIsTimed = false;
    841 }
    842 
    843 void nsLoadGroup::TelemetryReportChannel(nsITimedChannel* aTimedChannel,
    844                                         bool aDefaultRequest) {
    845  nsresult rv;
    846 
    847  TimeStamp asyncOpen;
    848  rv = aTimedChannel->GetAsyncOpen(&asyncOpen);
    849  // We do not check !asyncOpen.IsNull() bellow, prevent ASSERTIONs this way
    850  if (NS_FAILED(rv) || asyncOpen.IsNull()) return;
    851 
    852  TimeStamp cacheReadStart;
    853  rv = aTimedChannel->GetCacheReadStart(&cacheReadStart);
    854  if (NS_FAILED(rv)) return;
    855 
    856  TimeStamp cacheReadEnd;
    857  rv = aTimedChannel->GetCacheReadEnd(&cacheReadEnd);
    858  if (NS_FAILED(rv)) return;
    859 
    860  TimeStamp domainLookupStart;
    861  rv = aTimedChannel->GetDomainLookupStart(&domainLookupStart);
    862  if (NS_FAILED(rv)) return;
    863 
    864  TimeStamp domainLookupEnd;
    865  rv = aTimedChannel->GetDomainLookupEnd(&domainLookupEnd);
    866  if (NS_FAILED(rv)) return;
    867 
    868  TimeStamp connectStart;
    869  rv = aTimedChannel->GetConnectStart(&connectStart);
    870  if (NS_FAILED(rv)) return;
    871 
    872  TimeStamp secureConnectionStart;
    873  rv = aTimedChannel->GetSecureConnectionStart(&secureConnectionStart);
    874  if (NS_FAILED(rv)) return;
    875 
    876  TimeStamp connectEnd;
    877  rv = aTimedChannel->GetConnectEnd(&connectEnd);
    878  if (NS_FAILED(rv)) return;
    879 
    880  TimeStamp requestStart;
    881  rv = aTimedChannel->GetRequestStart(&requestStart);
    882  if (NS_FAILED(rv)) return;
    883 
    884  TimeStamp responseStart;
    885  rv = aTimedChannel->GetResponseStart(&responseStart);
    886  if (NS_FAILED(rv)) return;
    887 
    888  TimeStamp responseEnd;
    889  rv = aTimedChannel->GetResponseEnd(&responseEnd);
    890  if (NS_FAILED(rv)) return;
    891 #ifndef ANDROID
    892  bool useHttp3 = false;
    893 #endif
    894  bool supportHttp3 = false;
    895  nsCOMPtr<nsIHttpChannelInternal> httpChannel =
    896      do_QueryInterface(aTimedChannel);
    897  if (httpChannel) {
    898    uint32_t major;
    899    uint32_t minor;
    900    if (NS_SUCCEEDED(httpChannel->GetResponseVersion(&major, &minor))) {
    901 #ifndef ANDROID
    902      useHttp3 = major == 3;
    903 #endif
    904      if (major == 2) {
    905        if (NS_FAILED(httpChannel->GetSupportsHTTP3(&supportHttp3))) {
    906          supportHttp3 = false;
    907        }
    908      }
    909    }
    910  }
    911 
    912  // Glean instrumentation of metrics previously collected via Geckoview
    913  // Streaming.
    914  if (!domainLookupStart.IsNull()) {
    915    if (aDefaultRequest) {
    916      mozilla::glean::network::dns_start.AccumulateRawDuration(
    917          domainLookupStart - asyncOpen);
    918      if (!domainLookupEnd.IsNull()) {
    919        mozilla::glean::network::dns_end.AccumulateRawDuration(
    920            domainLookupEnd - domainLookupStart);
    921      }
    922    }
    923 #ifndef ANDROID
    924    else {
    925      mozilla::glean::network::sub_dns_start.AccumulateRawDuration(
    926          domainLookupStart - asyncOpen);
    927      if (!domainLookupEnd.IsNull()) {
    928        mozilla::glean::network::sub_dns_end.AccumulateRawDuration(
    929            domainLookupEnd - domainLookupStart);
    930      }
    931    }
    932 #endif
    933  }
    934  if (!connectEnd.IsNull()) {
    935    if (!connectStart.IsNull()) {
    936      if (aDefaultRequest) {
    937        mozilla::glean::network::tcp_connection.AccumulateRawDuration(
    938            connectEnd - connectStart);
    939      }
    940 #ifndef ANDROID
    941      else {
    942        mozilla::glean::network::sub_tcp_connection.AccumulateRawDuration(
    943            connectEnd - connectStart);
    944      }
    945 #endif
    946    }
    947    if (!secureConnectionStart.IsNull()) {
    948      if (aDefaultRequest) {
    949        mozilla::glean::network::tls_handshake.AccumulateRawDuration(
    950            connectEnd - secureConnectionStart);
    951      }
    952 #ifndef ANDROID
    953      else {
    954        mozilla::glean::network::sub_tls_handshake.AccumulateRawDuration(
    955            connectEnd - secureConnectionStart);
    956      }
    957 #endif
    958    }
    959  }
    960  if (!requestStart.IsNull() && !responseEnd.IsNull()) {
    961    if (aDefaultRequest) {
    962      mozilla::glean::network::open_to_first_sent.AccumulateRawDuration(
    963          requestStart - asyncOpen);
    964      mozilla::glean::network::first_sent_to_last_received
    965          .AccumulateRawDuration(responseEnd - requestStart);
    966 
    967      if (cacheReadStart.IsNull() && !responseStart.IsNull()) {
    968        mozilla::glean::network::open_to_first_received.AccumulateRawDuration(
    969            responseStart - asyncOpen);
    970      }
    971    }
    972 #ifndef ANDROID
    973    else {
    974      mozilla::glean::network::sub_open_to_first_sent.AccumulateRawDuration(
    975          requestStart - asyncOpen);
    976      mozilla::glean::network::sub_first_sent_to_last_received
    977          .AccumulateRawDuration(responseEnd - requestStart);
    978      if (cacheReadStart.IsNull() && !responseStart.IsNull()) {
    979        mozilla::glean::network::sub_open_to_first_received
    980            .AccumulateRawDuration(responseStart - asyncOpen);
    981      }
    982    }
    983 #endif
    984  }
    985  if (!cacheReadStart.IsNull() && !cacheReadEnd.IsNull()) {
    986    if (aDefaultRequest) {
    987      mozilla::glean::network::first_from_cache.AccumulateRawDuration(
    988          cacheReadStart - asyncOpen);
    989 #ifndef ANDROID
    990      mozilla::glean::network::cache_read_time.AccumulateRawDuration(
    991          cacheReadEnd - cacheReadStart);
    992      if (!requestStart.IsNull() && !responseEnd.IsNull()) {
    993        mozilla::glean::network::http_revalidation.AccumulateRawDuration(
    994            responseEnd - requestStart);
    995      }
    996 #endif
    997    }
    998 #ifndef ANDROID
    999    else {
   1000      mozilla::glean::network::sub_first_from_cache.AccumulateRawDuration(
   1001          cacheReadStart - asyncOpen);
   1002      mozilla::glean::network::sub_cache_read_time.AccumulateRawDuration(
   1003          cacheReadEnd - cacheReadStart);
   1004      if (!requestStart.IsNull() && !responseEnd.IsNull()) {
   1005        mozilla::glean::network::sub_http_revalidation.AccumulateRawDuration(
   1006            responseEnd - requestStart);
   1007      }
   1008    }
   1009 #endif
   1010  }
   1011 #ifndef ANDROID
   1012  if (!cacheReadEnd.IsNull()) {
   1013    if (aDefaultRequest) {
   1014      mozilla::glean::network::complete_load.AccumulateRawDuration(
   1015          cacheReadEnd - asyncOpen);
   1016      mozilla::glean::network::complete_load_cached.AccumulateRawDuration(
   1017          cacheReadEnd - asyncOpen);
   1018    } else {
   1019      mozilla::glean::network::sub_complete_load.AccumulateRawDuration(
   1020          cacheReadEnd - asyncOpen);
   1021      mozilla::glean::network::sub_complete_load_cached.AccumulateRawDuration(
   1022          cacheReadEnd - asyncOpen);
   1023    }
   1024  } else if (!responseEnd.IsNull()) {
   1025    if (aDefaultRequest) {
   1026      mozilla::glean::network::complete_load.AccumulateRawDuration(responseEnd -
   1027                                                                   asyncOpen);
   1028      mozilla::glean::network::complete_load_net.AccumulateRawDuration(
   1029          responseEnd - asyncOpen);
   1030    } else {
   1031      mozilla::glean::network::sub_complete_load.AccumulateRawDuration(
   1032          responseEnd - asyncOpen);
   1033      mozilla::glean::network::sub_complete_load_net.AccumulateRawDuration(
   1034          responseEnd - asyncOpen);
   1035    }
   1036  }
   1037 #endif
   1038 
   1039 #ifndef ANDROID
   1040  if ((useHttp3 || supportHttp3) && cacheReadStart.IsNull() &&
   1041      cacheReadEnd.IsNull()) {
   1042    nsCString key = (useHttp3) ? ((aDefaultRequest) ? "uses_http3_page"_ns
   1043                                                    : "uses_http3_sub"_ns)
   1044                               : ((aDefaultRequest) ? "supports_http3_page"_ns
   1045                                                    : "supports_http3_sub"_ns);
   1046 
   1047    if (!secureConnectionStart.IsNull() && !connectEnd.IsNull()) {
   1048      mozilla::glean::network::http3_tls_handshake.Get(key)
   1049          .AccumulateRawDuration(connectEnd - secureConnectionStart);
   1050    }
   1051 
   1052    if (supportHttp3 && !connectStart.IsNull() && !connectEnd.IsNull()) {
   1053      mozilla::glean::network::sup_http3_tcp_connection.Get(key)
   1054          .AccumulateRawDuration(connectEnd - connectStart);
   1055    }
   1056 
   1057    if (!requestStart.IsNull() && !responseEnd.IsNull()) {
   1058      mozilla::glean::network::http3_open_to_first_sent.Get(key)
   1059          .AccumulateRawDuration(requestStart - asyncOpen);
   1060 
   1061      mozilla::glean::network::http3_first_sent_to_last_received.Get(key)
   1062          .AccumulateRawDuration(responseEnd - requestStart);
   1063 
   1064      if (!responseStart.IsNull()) {
   1065        mozilla::glean::network::http3_open_to_first_received.Get(key)
   1066            .AccumulateRawDuration(responseStart - asyncOpen);
   1067      }
   1068 
   1069      if (!responseEnd.IsNull()) {
   1070        mozilla::glean::network::http3_complete_load.Get(key)
   1071            .AccumulateRawDuration(responseEnd - asyncOpen);
   1072      }
   1073    }
   1074  }
   1075 #endif
   1076 
   1077  bool hasHTTPSRR = false;
   1078  if (httpChannel && NS_SUCCEEDED(httpChannel->GetHasHTTPSRR(&hasHTTPSRR)) &&
   1079      cacheReadStart.IsNull() && cacheReadEnd.IsNull() &&
   1080      !requestStart.IsNull()) {
   1081    TimeDuration elapsed = requestStart - asyncOpen;
   1082    if (hasHTTPSRR) {
   1083      if (aDefaultRequest) {
   1084        glean::networking::http_channel_page_open_to_first_sent_https_rr
   1085            .AccumulateRawDuration(elapsed);
   1086      } else {
   1087        glean::networking::http_channel_sub_open_to_first_sent_https_rr
   1088            .AccumulateRawDuration(elapsed);
   1089      }
   1090    } else {
   1091      if (aDefaultRequest) {
   1092        glean::networking::http_channel_page_open_to_first_sent
   1093            .AccumulateRawDuration(elapsed);
   1094      } else {
   1095        glean::networking::http_channel_sub_open_to_first_sent
   1096            .AccumulateRawDuration(elapsed);
   1097      }
   1098    }
   1099  }
   1100 }
   1101 
   1102 nsresult nsLoadGroup::MergeLoadFlags(nsIRequest* aRequest,
   1103                                     nsLoadFlags& outFlags) {
   1104  nsresult rv;
   1105  nsLoadFlags flags, oldFlags;
   1106 
   1107  rv = aRequest->GetLoadFlags(&flags);
   1108  if (NS_FAILED(rv)) {
   1109    return rv;
   1110  }
   1111 
   1112  oldFlags = flags;
   1113 
   1114  // Inherit some bits...
   1115  flags |= mLoadFlags & kInheritedLoadFlags;
   1116 
   1117  // ... and force the default flags.
   1118  flags |= mDefaultLoadFlags;
   1119 
   1120  if (flags != oldFlags) {
   1121    rv = aRequest->SetLoadFlags(flags);
   1122  }
   1123 
   1124  outFlags = flags;
   1125  return rv;
   1126 }
   1127 
   1128 nsresult nsLoadGroup::MergeDefaultLoadFlags(nsIRequest* aRequest,
   1129                                            nsLoadFlags& outFlags) {
   1130  nsresult rv;
   1131  nsLoadFlags flags, oldFlags;
   1132 
   1133  rv = aRequest->GetLoadFlags(&flags);
   1134  if (NS_FAILED(rv)) {
   1135    return rv;
   1136  }
   1137 
   1138  oldFlags = flags;
   1139  // ... and force the default flags.
   1140  flags |= mDefaultLoadFlags;
   1141 
   1142  if (flags != oldFlags) {
   1143    rv = aRequest->SetLoadFlags(flags);
   1144  }
   1145  outFlags = flags;
   1146  return rv;
   1147 }
   1148 
   1149 nsresult nsLoadGroup::Init() {
   1150  mRequestContextService = RequestContextService::GetOrCreate();
   1151  if (mRequestContextService) {
   1152    (void)mRequestContextService->NewRequestContext(
   1153        getter_AddRefs(mRequestContext));
   1154  }
   1155 
   1156  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   1157  NS_ENSURE_STATE(os);
   1158 
   1159  (void)os->AddObserver(this, "last-pb-context-exited", true);
   1160 
   1161  return NS_OK;
   1162 }
   1163 
   1164 nsresult nsLoadGroup::InitWithRequestContextId(
   1165    const uint64_t& aRequestContextId) {
   1166  mRequestContextService = RequestContextService::GetOrCreate();
   1167  if (mRequestContextService) {
   1168    (void)mRequestContextService->GetRequestContext(
   1169        aRequestContextId, getter_AddRefs(mRequestContext));
   1170  }
   1171  mExternalRequestContext = true;
   1172 
   1173  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   1174  NS_ENSURE_STATE(os);
   1175 
   1176  (void)os->AddObserver(this, "last-pb-context-exited", true);
   1177 
   1178  return NS_OK;
   1179 }
   1180 
   1181 NS_IMETHODIMP
   1182 nsLoadGroup::Observe(nsISupports* aSubject, const char* aTopic,
   1183                     const char16_t* aData) {
   1184  MOZ_ASSERT(!strcmp(aTopic, "last-pb-context-exited"));
   1185 
   1186  OriginAttributes attrs;
   1187  StoragePrincipalHelper::GetRegularPrincipalOriginAttributes(this, attrs);
   1188  if (!attrs.IsPrivateBrowsing()) {
   1189    return NS_OK;
   1190  }
   1191 
   1192  mBrowsingContextDiscarded = true;
   1193  return NS_OK;
   1194 }
   1195 
   1196 NS_IMETHODIMP
   1197 nsLoadGroup::GetIsBrowsingContextDiscarded(bool* aIsBrowsingContextDiscarded) {
   1198  *aIsBrowsingContextDiscarded = mBrowsingContextDiscarded;
   1199  return NS_OK;
   1200 }
   1201 
   1202 }  // namespace net
   1203 }  // namespace mozilla
   1204 
   1205 #undef LOG