tor-browser

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

nsBaseChannel.cpp (27874B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set sw=2 sts=2 ts=8 et tw=80 : */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "nsBaseChannel.h"
      8 #include "nsContentUtils.h"
      9 #include "nsURLHelper.h"
     10 #include "nsNetCID.h"
     11 #include "nsUnknownDecoder.h"
     12 #include "nsIScriptSecurityManager.h"
     13 #include "nsMimeTypes.h"
     14 #include "nsICancelable.h"
     15 #include "nsIChannelEventSink.h"
     16 #include "nsIStreamConverterService.h"
     17 #include "nsChannelClassifier.h"
     18 #include "nsAsyncRedirectVerifyHelper.h"
     19 #include "nsProxyRelease.h"
     20 #include "nsXULAppAPI.h"
     21 #include "nsContentSecurityManager.h"
     22 #include "LoadInfo.h"
     23 #include "nsServiceManagerUtils.h"
     24 #include "nsRedirectHistoryEntry.h"
     25 #include "mozilla/AntiTrackingUtils.h"
     26 #include "mozilla/BasePrincipal.h"
     27 
     28 using namespace mozilla;
     29 
     30 // This class is used to suspend a request across a function scope.
     31 class ScopedRequestSuspender {
     32 public:
     33  explicit ScopedRequestSuspender(nsIRequest* request) : mRequest(request) {
     34    if (mRequest && NS_FAILED(mRequest->Suspend())) {
     35      NS_WARNING("Couldn't suspend pump");
     36      mRequest = nullptr;
     37    }
     38  }
     39  ~ScopedRequestSuspender() {
     40    if (mRequest) mRequest->Resume();
     41  }
     42 
     43 private:
     44  nsIRequest* mRequest;
     45 };
     46 
     47 // Used to suspend data events from mRequest within a function scope.  This is
     48 // usually needed when a function makes callbacks that could process events.
     49 #define SUSPEND_PUMP_FOR_SCOPE() \
     50  ScopedRequestSuspender pump_suspender__(mRequest)
     51 
     52 //-----------------------------------------------------------------------------
     53 // nsBaseChannel
     54 
     55 nsBaseChannel::nsBaseChannel() : NeckoTargetHolder(nullptr) {
     56  mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
     57 }
     58 
     59 nsBaseChannel::~nsBaseChannel() {
     60  NS_ReleaseOnMainThread("nsBaseChannel::mLoadInfo", mLoadInfo.forget());
     61 }
     62 
     63 nsresult nsBaseChannel::Redirect(nsIChannel* newChannel, uint32_t redirectFlags,
     64                                 bool openNewChannel) {
     65  SUSPEND_PUMP_FOR_SCOPE();
     66 
     67  // Transfer properties
     68 
     69  newChannel->SetLoadGroup(mLoadGroup);
     70  newChannel->SetNotificationCallbacks(mCallbacks);
     71  newChannel->SetLoadFlags(mLoadFlags | LOAD_REPLACE);
     72 
     73  // make a copy of the loadinfo, append to the redirectchain
     74  // and set it on the new channel
     75  nsSecurityFlags secFlags =
     76      mLoadInfo->GetSecurityFlags() & ~nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
     77  nsCOMPtr<nsILoadInfo> newLoadInfo =
     78      static_cast<net::LoadInfo*>(mLoadInfo.get())
     79          ->CloneWithNewSecFlags(secFlags);
     80 
     81  bool isInternalRedirect =
     82      (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
     83                        nsIChannelEventSink::REDIRECT_STS_UPGRADE));
     84 
     85  newLoadInfo->AppendRedirectHistoryEntry(this, isInternalRedirect);
     86 
     87  // Ensure the channel's loadInfo's result principal URI so that it's
     88  // either non-null or updated to the redirect target URI.
     89  // We must do this because in case the loadInfo's result principal URI
     90  // is null, it would be taken from OriginalURI of the channel.  But we
     91  // overwrite it with the whole redirect chain first URI before opening
     92  // the target channel, hence the information would be lost.
     93  // If the protocol handler that created the channel wants to use
     94  // the originalURI of the channel as the principal URI, it has left
     95  // the result principal URI on the load info null.
     96  nsCOMPtr<nsIURI> resultPrincipalURI;
     97 
     98  nsCOMPtr<nsILoadInfo> existingLoadInfo = newChannel->LoadInfo();
     99  if (existingLoadInfo) {
    100    existingLoadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
    101  }
    102  if (!resultPrincipalURI) {
    103    newChannel->GetOriginalURI(getter_AddRefs(resultPrincipalURI));
    104  }
    105 
    106  newLoadInfo->SetResultPrincipalURI(resultPrincipalURI);
    107 
    108  newChannel->SetLoadInfo(newLoadInfo);
    109 
    110  // Preserve the privacy bit if it has been overridden
    111  if (mPrivateBrowsingOverriden) {
    112    nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel =
    113        do_QueryInterface(newChannel);
    114    if (newPBChannel) {
    115      newPBChannel->SetPrivate(mPrivateBrowsing);
    116    }
    117  }
    118 
    119  if (nsCOMPtr<nsIWritablePropertyBag> bag = ::do_QueryInterface(newChannel)) {
    120    nsHashPropertyBag::CopyFrom(bag, static_cast<nsIPropertyBag2*>(this));
    121  }
    122 
    123  // Notify consumer, giving chance to cancel redirect.
    124 
    125  auto redirectCallbackHelper = MakeRefPtr<net::nsAsyncRedirectVerifyHelper>();
    126 
    127  bool checkRedirectSynchronously = !openNewChannel;
    128  nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
    129 
    130  mRedirectChannel = newChannel;
    131  mRedirectFlags = redirectFlags;
    132  mOpenRedirectChannel = openNewChannel;
    133  nsresult rv = redirectCallbackHelper->Init(
    134      this, newChannel, redirectFlags, target, checkRedirectSynchronously);
    135  if (NS_FAILED(rv)) return rv;
    136 
    137  if (checkRedirectSynchronously && NS_FAILED(mStatus)) return mStatus;
    138 
    139  return NS_OK;
    140 }
    141 
    142 nsresult nsBaseChannel::ContinueRedirect() {
    143  // Make sure to do this _after_ making all the OnChannelRedirect calls
    144  mRedirectChannel->SetOriginalURI(OriginalURI());
    145 
    146  // If we fail to open the new channel, then we want to leave this channel
    147  // unaffected, so we defer tearing down our channel until we have succeeded
    148  // with the redirect.
    149 
    150  if (mOpenRedirectChannel) {
    151    nsresult rv = NS_OK;
    152    rv = mRedirectChannel->AsyncOpen(mListener);
    153    NS_ENSURE_SUCCESS(rv, rv);
    154  }
    155 
    156  mRedirectChannel = nullptr;
    157 
    158  // close down this channel
    159  Cancel(NS_BINDING_REDIRECTED);
    160  ChannelDone();
    161 
    162  return NS_OK;
    163 }
    164 
    165 bool nsBaseChannel::HasContentTypeHint() const {
    166  NS_ASSERTION(!Pending(), "HasContentTypeHint called too late");
    167  return !mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE);
    168 }
    169 
    170 nsresult nsBaseChannel::BeginPumpingData() {
    171  nsresult rv;
    172 
    173  rv = BeginAsyncRead(this, getter_AddRefs(mRequest),
    174                      getter_AddRefs(mCancelableAsyncRequest));
    175  if (NS_SUCCEEDED(rv)) {
    176    MOZ_ASSERT(mRequest || mCancelableAsyncRequest,
    177               "should have got a request or cancelable");
    178    mPumpingData = true;
    179    return NS_OK;
    180  }
    181  if (rv != NS_ERROR_NOT_IMPLEMENTED) {
    182    return rv;
    183  }
    184 
    185  nsCOMPtr<nsIInputStream> stream;
    186  nsCOMPtr<nsIChannel> channel;
    187  rv = OpenContentStream(true, getter_AddRefs(stream), getter_AddRefs(channel));
    188  if (NS_FAILED(rv)) return rv;
    189 
    190  NS_ASSERTION(!stream || !channel, "Got both a channel and a stream?");
    191 
    192  if (channel) {
    193    nsCOMPtr<nsIRunnable> runnable = new RedirectRunnable(this, channel);
    194    rv = Dispatch(runnable.forget());
    195    if (NS_SUCCEEDED(rv)) mWaitingOnAsyncRedirect = true;
    196    return rv;
    197  }
    198 
    199  // By assigning mPump, we flag this channel as pending (see Pending).  It's
    200  // important that the pending flag is set when we call into the stream (the
    201  // call to AsyncRead results in the stream's AsyncWait method being called)
    202  // and especially when we call into the loadgroup.  Our caller takes care to
    203  // release mPump if we return an error.
    204 
    205  nsCOMPtr<nsISerialEventTarget> target = GetNeckoTarget();
    206  rv = nsInputStreamPump::Create(getter_AddRefs(mPump), stream, 0, 0, true,
    207                                 target);
    208  if (NS_FAILED(rv)) {
    209    return rv;
    210  }
    211 
    212  mPumpingData = true;
    213  mRequest = mPump;
    214  rv = mPump->AsyncRead(this);
    215  if (NS_FAILED(rv)) {
    216    return rv;
    217  }
    218 
    219  RefPtr<BlockingPromise> promise;
    220  rv = ListenerBlockingPromise(getter_AddRefs(promise));
    221  if (NS_FAILED(rv)) {
    222    return rv;
    223  }
    224 
    225  if (promise) {
    226    mPump->Suspend();
    227 
    228    RefPtr<nsBaseChannel> self(this);
    229 
    230    promise->Then(
    231        target, __func__,
    232        [self, this](nsresult rv) {
    233          MOZ_ASSERT(mPump);
    234          MOZ_ASSERT(NS_SUCCEEDED(rv));
    235          mPump->Resume();
    236        },
    237        [self, this](nsresult rv) {
    238          MOZ_ASSERT(mPump);
    239          MOZ_ASSERT(NS_FAILED(rv));
    240          Cancel(rv);
    241          mPump->Resume();
    242        });
    243  }
    244 
    245  return NS_OK;
    246 }
    247 
    248 void nsBaseChannel::HandleAsyncRedirect(nsIChannel* newChannel) {
    249  NS_ASSERTION(!mPumpingData, "Shouldn't have gotten here");
    250 
    251  nsresult rv = mStatus;
    252  if (NS_SUCCEEDED(mStatus)) {
    253    rv = Redirect(newChannel, nsIChannelEventSink::REDIRECT_TEMPORARY, true);
    254    if (NS_SUCCEEDED(rv)) {
    255      // OnRedirectVerifyCallback will be called asynchronously
    256      return;
    257    }
    258  }
    259 
    260  ContinueHandleAsyncRedirect(rv);
    261 }
    262 
    263 void nsBaseChannel::ContinueHandleAsyncRedirect(nsresult result) {
    264  mWaitingOnAsyncRedirect = false;
    265 
    266  if (NS_FAILED(result)) Cancel(result);
    267 
    268  if (NS_FAILED(result) && mListener) {
    269    // Notify our consumer ourselves
    270    mListener->OnStartRequest(this);
    271    mListener->OnStopRequest(this, mStatus);
    272    ChannelDone();
    273  }
    274 
    275  if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus);
    276 
    277  // Drop notification callbacks to prevent cycles.
    278  mCallbacks = nullptr;
    279  CallbacksChanged();
    280 }
    281 
    282 void nsBaseChannel::ClassifyURI() {
    283  // For channels created in the child process, delegate to the parent to
    284  // classify URIs.
    285  if (!XRE_IsParentProcess()) {
    286    return;
    287  }
    288 
    289  if (NS_ShouldClassifyChannel(this, ClassifyType::SafeBrowsing)) {
    290    auto classifier = MakeRefPtr<net::nsChannelClassifier>(this);
    291    classifier->Start();
    292  }
    293 }
    294 
    295 //-----------------------------------------------------------------------------
    296 // nsBaseChannel::nsISupports
    297 
    298 NS_IMPL_ADDREF(nsBaseChannel)
    299 NS_IMPL_RELEASE(nsBaseChannel)
    300 
    301 NS_INTERFACE_MAP_BEGIN(nsBaseChannel)
    302  NS_INTERFACE_MAP_ENTRY(nsIRequest)
    303  NS_INTERFACE_MAP_ENTRY(nsIChannel)
    304  NS_INTERFACE_MAP_ENTRY(nsIBaseChannel)
    305  NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest)
    306  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
    307  NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
    308  NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
    309  NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
    310  NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableStreamListener)
    311  NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
    312  NS_INTERFACE_MAP_ENTRY(nsIPrivateBrowsingChannel)
    313 NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag)
    314 
    315 //-----------------------------------------------------------------------------
    316 // nsBaseChannel::nsIRequest
    317 
    318 NS_IMETHODIMP
    319 nsBaseChannel::GetName(nsACString& result) {
    320  if (!mURI) {
    321    result.Truncate();
    322    return NS_OK;
    323  }
    324  return mURI->GetSpec(result);
    325 }
    326 
    327 NS_IMETHODIMP
    328 nsBaseChannel::IsPending(bool* result) {
    329  *result = Pending();
    330  return NS_OK;
    331 }
    332 
    333 NS_IMETHODIMP
    334 nsBaseChannel::GetStatus(nsresult* status) {
    335  if (mRequest && NS_SUCCEEDED(mStatus)) {
    336    mRequest->GetStatus(status);
    337  } else {
    338    *status = mStatus;
    339  }
    340  return NS_OK;
    341 }
    342 
    343 NS_IMETHODIMP nsBaseChannel::SetCanceledReason(const nsACString& aReason) {
    344  return SetCanceledReasonImpl(aReason);
    345 }
    346 
    347 NS_IMETHODIMP nsBaseChannel::GetCanceledReason(nsACString& aReason) {
    348  return GetCanceledReasonImpl(aReason);
    349 }
    350 
    351 NS_IMETHODIMP nsBaseChannel::CancelWithReason(nsresult aStatus,
    352                                              const nsACString& aReason) {
    353  return CancelWithReasonImpl(aStatus, aReason);
    354 }
    355 
    356 NS_IMETHODIMP
    357 nsBaseChannel::Cancel(nsresult status) {
    358  // Ignore redundant cancelation
    359  if (mCanceled) {
    360    return NS_OK;
    361  }
    362 
    363  mCanceled = true;
    364  mStatus = status;
    365 
    366  if (mCancelableAsyncRequest) {
    367    mCancelableAsyncRequest->Cancel(status);
    368  }
    369 
    370  if (mRequest) {
    371    mRequest->Cancel(status);
    372  }
    373 
    374  return NS_OK;
    375 }
    376 
    377 NS_IMETHODIMP
    378 nsBaseChannel::Suspend() {
    379  NS_ENSURE_TRUE(mPumpingData, NS_ERROR_NOT_INITIALIZED);
    380  NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_IMPLEMENTED);
    381  return mRequest->Suspend();
    382 }
    383 
    384 NS_IMETHODIMP
    385 nsBaseChannel::Resume() {
    386  NS_ENSURE_TRUE(mPumpingData, NS_ERROR_NOT_INITIALIZED);
    387  NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_IMPLEMENTED);
    388  return mRequest->Resume();
    389 }
    390 
    391 NS_IMETHODIMP
    392 nsBaseChannel::GetLoadFlags(nsLoadFlags* aLoadFlags) {
    393  *aLoadFlags = mLoadFlags;
    394  return NS_OK;
    395 }
    396 
    397 NS_IMETHODIMP
    398 nsBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags) {
    399  mLoadFlags = aLoadFlags;
    400  return NS_OK;
    401 }
    402 
    403 NS_IMETHODIMP
    404 nsBaseChannel::GetTRRMode(nsIRequest::TRRMode* aTRRMode) {
    405  return GetTRRModeImpl(aTRRMode);
    406 }
    407 
    408 NS_IMETHODIMP
    409 nsBaseChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode) {
    410  return SetTRRModeImpl(aTRRMode);
    411 }
    412 
    413 NS_IMETHODIMP
    414 nsBaseChannel::GetLoadGroup(nsILoadGroup** aLoadGroup) {
    415  nsCOMPtr<nsILoadGroup> loadGroup(mLoadGroup);
    416  loadGroup.forget(aLoadGroup);
    417  return NS_OK;
    418 }
    419 
    420 NS_IMETHODIMP
    421 nsBaseChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) {
    422  if (!CanSetLoadGroup(aLoadGroup)) {
    423    return NS_ERROR_FAILURE;
    424  }
    425 
    426  mLoadGroup = aLoadGroup;
    427  CallbacksChanged();
    428  UpdatePrivateBrowsing();
    429  return NS_OK;
    430 }
    431 
    432 //-----------------------------------------------------------------------------
    433 // nsBaseChannel::nsIChannel
    434 
    435 NS_IMETHODIMP
    436 nsBaseChannel::GetOriginalURI(nsIURI** aURI) {
    437  RefPtr<nsIURI> uri = OriginalURI();
    438  uri.forget(aURI);
    439  return NS_OK;
    440 }
    441 
    442 NS_IMETHODIMP
    443 nsBaseChannel::SetOriginalURI(nsIURI* aURI) {
    444  NS_ENSURE_ARG_POINTER(aURI);
    445  mOriginalURI = aURI;
    446  return NS_OK;
    447 }
    448 
    449 NS_IMETHODIMP
    450 nsBaseChannel::GetURI(nsIURI** aURI) {
    451  nsCOMPtr<nsIURI> uri(mURI);
    452  uri.forget(aURI);
    453  return NS_OK;
    454 }
    455 
    456 NS_IMETHODIMP
    457 nsBaseChannel::GetOwner(nsISupports** aOwner) {
    458  nsCOMPtr<nsISupports> owner(mOwner);
    459  owner.forget(aOwner);
    460  return NS_OK;
    461 }
    462 
    463 NS_IMETHODIMP
    464 nsBaseChannel::SetOwner(nsISupports* aOwner) {
    465  mOwner = aOwner;
    466  return NS_OK;
    467 }
    468 
    469 NS_IMETHODIMP
    470 nsBaseChannel::SetLoadInfo(nsILoadInfo* aLoadInfo) {
    471  MOZ_RELEASE_ASSERT(aLoadInfo, "loadinfo can't be null");
    472  mLoadInfo = aLoadInfo;
    473 
    474  // Need to update |mNeckoTarget| when load info has changed.
    475  SetupNeckoTarget();
    476  return NS_OK;
    477 }
    478 
    479 NS_IMETHODIMP
    480 nsBaseChannel::GetLoadInfo(nsILoadInfo** aLoadInfo) {
    481  nsCOMPtr<nsILoadInfo> loadInfo(mLoadInfo);
    482  loadInfo.forget(aLoadInfo);
    483  return NS_OK;
    484 }
    485 
    486 NS_IMETHODIMP
    487 nsBaseChannel::GetIsDocument(bool* aIsDocument) {
    488  return NS_GetIsDocumentChannel(this, aIsDocument);
    489 }
    490 
    491 NS_IMETHODIMP
    492 nsBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks) {
    493  nsCOMPtr<nsIInterfaceRequestor> callbacks(mCallbacks);
    494  callbacks.forget(aCallbacks);
    495  return NS_OK;
    496 }
    497 
    498 NS_IMETHODIMP
    499 nsBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) {
    500  if (!CanSetCallbacks(aCallbacks)) {
    501    return NS_ERROR_FAILURE;
    502  }
    503 
    504  mCallbacks = aCallbacks;
    505  CallbacksChanged();
    506  UpdatePrivateBrowsing();
    507  return NS_OK;
    508 }
    509 
    510 NS_IMETHODIMP
    511 nsBaseChannel::GetSecurityInfo(nsITransportSecurityInfo** aSecurityInfo) {
    512  *aSecurityInfo = do_AddRef(mSecurityInfo).take();
    513  return NS_OK;
    514 }
    515 
    516 NS_IMETHODIMP
    517 nsBaseChannel::GetContentType(nsACString& aContentType) {
    518  aContentType = mContentType;
    519  return NS_OK;
    520 }
    521 
    522 NS_IMETHODIMP
    523 nsBaseChannel::SetContentType(const nsACString& aContentType) {
    524  // mContentCharset is unchanged if not parsed
    525  bool dummy;
    526  net_ParseContentType(aContentType, mContentType, mContentCharset, &dummy);
    527  return NS_OK;
    528 }
    529 
    530 NS_IMETHODIMP
    531 nsBaseChannel::GetContentCharset(nsACString& aContentCharset) {
    532  aContentCharset = mContentCharset;
    533  if (mContentCharset.IsEmpty() && (mOriginalURI->SchemeIs("chrome") ||
    534                                    mOriginalURI->SchemeIs("resource"))) {
    535    aContentCharset.AssignLiteral("UTF-8");
    536  }
    537  return NS_OK;
    538 }
    539 
    540 NS_IMETHODIMP
    541 nsBaseChannel::SetContentCharset(const nsACString& aContentCharset) {
    542  mContentCharset = aContentCharset;
    543  return NS_OK;
    544 }
    545 
    546 NS_IMETHODIMP
    547 nsBaseChannel::GetContentDisposition(uint32_t* aContentDisposition) {
    548  // preserve old behavior, fail unless explicitly set.
    549  if (mContentDispositionHint == UINT32_MAX) {
    550    return NS_ERROR_NOT_AVAILABLE;
    551  }
    552 
    553  *aContentDisposition = mContentDispositionHint;
    554  return NS_OK;
    555 }
    556 
    557 NS_IMETHODIMP
    558 nsBaseChannel::SetContentDisposition(uint32_t aContentDisposition) {
    559  mContentDispositionHint = aContentDisposition;
    560  return NS_OK;
    561 }
    562 
    563 NS_IMETHODIMP
    564 nsBaseChannel::GetContentDispositionFilename(
    565    nsAString& aContentDispositionFilename) {
    566  if (!mContentDispositionFilename) {
    567    return NS_ERROR_NOT_AVAILABLE;
    568  }
    569 
    570  aContentDispositionFilename = *mContentDispositionFilename;
    571  return NS_OK;
    572 }
    573 
    574 NS_IMETHODIMP
    575 nsBaseChannel::SetContentDispositionFilename(
    576    const nsAString& aContentDispositionFilename) {
    577  mContentDispositionFilename =
    578      MakeUnique<nsString>(aContentDispositionFilename);
    579 
    580  // For safety reasons ensure the filename doesn't contain null characters and
    581  // replace them with underscores. We may later pass the extension to system
    582  // MIME APIs that expect null terminated strings.
    583  mContentDispositionFilename->ReplaceChar(char16_t(0), '_');
    584 
    585  return NS_OK;
    586 }
    587 
    588 NS_IMETHODIMP
    589 nsBaseChannel::GetContentDispositionHeader(
    590    nsACString& aContentDispositionHeader) {
    591  return NS_ERROR_NOT_AVAILABLE;
    592 }
    593 
    594 NS_IMETHODIMP
    595 nsBaseChannel::GetContentLength(int64_t* aContentLength) {
    596  *aContentLength = mContentLength;
    597  return NS_OK;
    598 }
    599 
    600 NS_IMETHODIMP
    601 nsBaseChannel::SetContentLength(int64_t aContentLength) {
    602  mContentLength = aContentLength;
    603  return NS_OK;
    604 }
    605 
    606 NS_IMETHODIMP
    607 nsBaseChannel::Open(nsIInputStream** aStream) {
    608  nsCOMPtr<nsIStreamListener> listener;
    609  nsresult rv =
    610      nsContentSecurityManager::doContentSecurityCheck(this, listener);
    611  NS_ENSURE_SUCCESS(rv, rv);
    612 
    613  NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
    614  NS_ENSURE_TRUE(!mPumpingData, NS_ERROR_IN_PROGRESS);
    615  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
    616 
    617  nsCOMPtr<nsIChannel> chan;
    618  rv = OpenContentStream(false, aStream, getter_AddRefs(chan));
    619  NS_ASSERTION(!chan || !*aStream, "Got both a channel and a stream?");
    620  if (NS_SUCCEEDED(rv) && chan) {
    621    rv = Redirect(chan, nsIChannelEventSink::REDIRECT_INTERNAL, false);
    622    if (NS_FAILED(rv)) return rv;
    623    rv = chan->Open(aStream);
    624  } else if (rv == NS_ERROR_NOT_IMPLEMENTED) {
    625    return NS_ImplementChannelOpen(this, aStream);
    626  }
    627 
    628  if (NS_SUCCEEDED(rv)) {
    629    mWasOpened = true;
    630    ClassifyURI();
    631  }
    632 
    633  return rv;
    634 }
    635 
    636 NS_IMETHODIMP
    637 nsBaseChannel::AsyncOpen(nsIStreamListener* aListener) {
    638  nsCOMPtr<nsIStreamListener> listener = aListener;
    639 
    640  nsresult rv =
    641      nsContentSecurityManager::doContentSecurityCheck(this, listener);
    642  if (NS_FAILED(rv)) {
    643    mCallbacks = nullptr;
    644    return rv;
    645  }
    646 
    647  MOZ_ASSERT(
    648      mLoadInfo->GetSecurityMode() == 0 ||
    649          mLoadInfo->GetInitialSecurityCheckDone() ||
    650          (mLoadInfo->GetSecurityMode() ==
    651               nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL &&
    652           mLoadInfo->GetLoadingPrincipal() &&
    653           mLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()),
    654      "security flags in loadInfo but doContentSecurityCheck() not called");
    655 
    656  NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
    657  NS_ENSURE_TRUE(!mPumpingData, NS_ERROR_IN_PROGRESS);
    658  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
    659  NS_ENSURE_ARG(listener);
    660 
    661  SetupNeckoTarget();
    662 
    663  // Skip checking for chrome:// sub-resources.
    664  nsAutoCString scheme;
    665  mURI->GetScheme(scheme);
    666  if (!scheme.EqualsLiteral("file")) {
    667    NS_CompareLoadInfoAndLoadContext(this);
    668  }
    669 
    670  // Ensure that this is an allowed port before proceeding.
    671  rv = NS_CheckPortSafety(mURI);
    672  if (NS_FAILED(rv)) {
    673    mCallbacks = nullptr;
    674    return rv;
    675  }
    676 
    677  AntiTrackingUtils::UpdateAntiTrackingInfoForChannel(this);
    678 
    679  // Store the listener and context early so that OpenContentStream and the
    680  // stream's AsyncWait method (called by AsyncRead) can have access to them
    681  // via the StreamListener methods.  However, since
    682  // this typically introduces a reference cycle between this and the listener,
    683  // we need to be sure to break the reference if this method does not succeed.
    684  mListener = listener;
    685 
    686  // This method assigns mPump as a side-effect.  We need to clear mPump if
    687  // this method fails.
    688  rv = BeginPumpingData();
    689  if (NS_FAILED(rv)) {
    690    mPump = nullptr;
    691    mRequest = nullptr;
    692    mPumpingData = false;
    693    ChannelDone();
    694    mCallbacks = nullptr;
    695    return rv;
    696  }
    697 
    698  // At this point, we are going to return success no matter what.
    699 
    700  mWasOpened = true;
    701 
    702  SUSPEND_PUMP_FOR_SCOPE();
    703 
    704  if (mLoadGroup) mLoadGroup->AddRequest(this, nullptr);
    705 
    706  ClassifyURI();
    707 
    708  return NS_OK;
    709 }
    710 
    711 //-----------------------------------------------------------------------------
    712 // nsBaseChannel::nsITransportEventSink
    713 
    714 NS_IMETHODIMP
    715 nsBaseChannel::OnTransportStatus(nsITransport* transport, nsresult status,
    716                                 int64_t progress, int64_t progressMax) {
    717  // In some cases, we may wish to suppress transport-layer status events.
    718 
    719  if (!mPumpingData || NS_FAILED(mStatus)) {
    720    return NS_OK;
    721  }
    722 
    723  SUSPEND_PUMP_FOR_SCOPE();
    724 
    725  // Lazily fetch mProgressSink
    726  if (!mProgressSink) {
    727    if (mQueriedProgressSink) {
    728      return NS_OK;
    729    }
    730    GetCallback(mProgressSink);
    731    mQueriedProgressSink = true;
    732    if (!mProgressSink) {
    733      return NS_OK;
    734    }
    735  }
    736 
    737  if (!HasLoadFlag(LOAD_BACKGROUND)) {
    738    nsAutoString statusArg;
    739    if (GetStatusArg(status, statusArg)) {
    740      mProgressSink->OnStatus(this, status, statusArg.get());
    741    }
    742  }
    743 
    744  if (progress) {
    745    mProgressSink->OnProgress(this, progress, progressMax);
    746  }
    747 
    748  return NS_OK;
    749 }
    750 
    751 //-----------------------------------------------------------------------------
    752 // nsBaseChannel::nsIInterfaceRequestor
    753 
    754 NS_IMETHODIMP
    755 nsBaseChannel::GetInterface(const nsIID& iid, void** result) {
    756  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, iid, result);
    757  return *result ? NS_OK : NS_ERROR_NO_INTERFACE;
    758 }
    759 
    760 //-----------------------------------------------------------------------------
    761 // nsBaseChannel::nsIRequestObserver
    762 
    763 static void CallTypeSniffers(void* aClosure, const uint8_t* aData,
    764                             uint32_t aCount) {
    765  nsIChannel* chan = static_cast<nsIChannel*>(aClosure);
    766 
    767  nsAutoCString newType;
    768  NS_SniffContent(NS_CONTENT_SNIFFER_CATEGORY, chan, aData, aCount, newType);
    769  if (!newType.IsEmpty()) {
    770    chan->SetContentType(newType);
    771  }
    772 }
    773 
    774 static void CallUnknownTypeSniffer(void* aClosure, const uint8_t* aData,
    775                                   uint32_t aCount) {
    776  nsIChannel* chan = static_cast<nsIChannel*>(aClosure);
    777 
    778  RefPtr<nsUnknownDecoder> sniffer = new nsUnknownDecoder();
    779 
    780  nsAutoCString detected;
    781  nsresult rv = sniffer->GetMIMETypeFromContent(chan, aData, aCount, detected);
    782  if (NS_SUCCEEDED(rv)) chan->SetContentType(detected);
    783 }
    784 
    785 NS_IMETHODIMP
    786 nsBaseChannel::OnStartRequest(nsIRequest* request) {
    787  MOZ_ASSERT_IF(mRequest, request == mRequest);
    788  MOZ_ASSERT_IF(mCancelableAsyncRequest, !mRequest);
    789 
    790  if (mPump) {
    791    // If our content type is unknown, use the content type
    792    // sniffer. If the sniffer is not available for some reason, then we just
    793    // keep going as-is.
    794    if (NS_SUCCEEDED(mStatus) &&
    795        mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
    796      mPump->PeekStream(CallUnknownTypeSniffer, static_cast<nsIChannel*>(this));
    797    }
    798 
    799    // Now, the general type sniffers. Skip this if we have none.
    800    if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) {
    801      mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this));
    802    }
    803  }
    804 
    805  SUSPEND_PUMP_FOR_SCOPE();
    806 
    807  if (mListener) {  // null in case of redirect
    808    return mListener->OnStartRequest(this);
    809  }
    810  return NS_OK;
    811 }
    812 
    813 NS_IMETHODIMP
    814 nsBaseChannel::OnStopRequest(nsIRequest* request, nsresult status) {
    815  // If both mStatus and status are failure codes, we keep mStatus as-is since
    816  // that is consistent with our GetStatus and Cancel methods.
    817  if (NS_SUCCEEDED(mStatus)) mStatus = status;
    818 
    819  // Cause Pending to return false.
    820  mPump = nullptr;
    821  mRequest = nullptr;
    822  mCancelableAsyncRequest = nullptr;
    823  mPumpingData = false;
    824 
    825  if (mListener) {  // null in case of redirect
    826    mListener->OnStopRequest(this, mStatus);
    827  }
    828  ChannelDone();
    829 
    830  // No need to suspend pump in this scope since we will not be receiving
    831  // any more events from it.
    832 
    833  if (mLoadGroup) mLoadGroup->RemoveRequest(this, nullptr, mStatus);
    834 
    835  // Drop notification callbacks to prevent cycles.
    836  mCallbacks = nullptr;
    837  CallbacksChanged();
    838 
    839  return NS_OK;
    840 }
    841 
    842 //-----------------------------------------------------------------------------
    843 // nsBaseChannel::nsIStreamListener
    844 
    845 NS_IMETHODIMP
    846 nsBaseChannel::OnDataAvailable(nsIRequest* request, nsIInputStream* stream,
    847                               uint64_t offset, uint32_t count) {
    848  SUSPEND_PUMP_FOR_SCOPE();
    849 
    850  nsresult rv = mListener->OnDataAvailable(this, stream, offset, count);
    851  if (mSynthProgressEvents && NS_SUCCEEDED(rv)) {
    852    int64_t prog = offset + count;
    853    if (NS_IsMainThread()) {
    854      OnTransportStatus(nullptr, NS_NET_STATUS_READING, prog, mContentLength);
    855    } else {
    856      class OnTransportStatusAsyncEvent : public Runnable {
    857        RefPtr<nsBaseChannel> mChannel;
    858        int64_t mProgress;
    859        int64_t mContentLength;
    860 
    861       public:
    862        OnTransportStatusAsyncEvent(nsBaseChannel* aChannel, int64_t aProgress,
    863                                    int64_t aContentLength)
    864            : Runnable("OnTransportStatusAsyncEvent"),
    865              mChannel(aChannel),
    866              mProgress(aProgress),
    867              mContentLength(aContentLength) {}
    868 
    869        NS_IMETHOD Run() override {
    870          return mChannel->OnTransportStatus(nullptr, NS_NET_STATUS_READING,
    871                                             mProgress, mContentLength);
    872        }
    873      };
    874 
    875      nsCOMPtr<nsIRunnable> runnable =
    876          new OnTransportStatusAsyncEvent(this, prog, mContentLength);
    877      Dispatch(runnable.forget());
    878    }
    879  }
    880 
    881  return rv;
    882 }
    883 
    884 NS_IMETHODIMP
    885 nsBaseChannel::OnRedirectVerifyCallback(nsresult result) {
    886  if (NS_SUCCEEDED(result)) result = ContinueRedirect();
    887 
    888  if (NS_FAILED(result) && !mWaitingOnAsyncRedirect) {
    889    if (NS_SUCCEEDED(mStatus)) mStatus = result;
    890    return NS_OK;
    891  }
    892 
    893  if (mWaitingOnAsyncRedirect) ContinueHandleAsyncRedirect(result);
    894 
    895  return NS_OK;
    896 }
    897 
    898 NS_IMETHODIMP
    899 nsBaseChannel::RetargetDeliveryTo(nsISerialEventTarget* aEventTarget) {
    900  MOZ_ASSERT(NS_IsMainThread());
    901 
    902  if (!mRequest) {
    903    return NS_ERROR_NOT_INITIALIZED;
    904  }
    905 
    906  nsCOMPtr<nsIThreadRetargetableRequest> req;
    907  if (mAllowThreadRetargeting) {
    908    req = do_QueryInterface(mRequest);
    909  }
    910 
    911  NS_ENSURE_TRUE(req, NS_ERROR_NOT_IMPLEMENTED);
    912 
    913  return req->RetargetDeliveryTo(aEventTarget);
    914 }
    915 
    916 NS_IMETHODIMP
    917 nsBaseChannel::GetDeliveryTarget(nsISerialEventTarget** aEventTarget) {
    918  MOZ_ASSERT(NS_IsMainThread());
    919 
    920  NS_ENSURE_TRUE(mRequest, NS_ERROR_NOT_INITIALIZED);
    921 
    922  nsCOMPtr<nsIThreadRetargetableRequest> req;
    923  req = do_QueryInterface(mRequest);
    924 
    925  NS_ENSURE_TRUE(req, NS_ERROR_NOT_IMPLEMENTED);
    926  return req->GetDeliveryTarget(aEventTarget);
    927 }
    928 
    929 NS_IMETHODIMP
    930 nsBaseChannel::CheckListenerChain() {
    931  MOZ_ASSERT(NS_IsMainThread());
    932 
    933  if (!mAllowThreadRetargeting) {
    934    return NS_ERROR_NOT_IMPLEMENTED;
    935  }
    936 
    937  nsCOMPtr<nsIThreadRetargetableStreamListener> listener =
    938      do_QueryInterface(mListener);
    939  if (!listener) {
    940    return NS_ERROR_NO_INTERFACE;
    941  }
    942 
    943  return listener->CheckListenerChain();
    944 }
    945 
    946 NS_IMETHODIMP
    947 nsBaseChannel::OnDataFinished(nsresult aStatus) {
    948  if (!mListener) {
    949    return NS_ERROR_FAILURE;
    950  }
    951 
    952  if (!mAllowThreadRetargeting) {
    953    return NS_ERROR_NOT_IMPLEMENTED;
    954  }
    955 
    956  nsCOMPtr<nsIThreadRetargetableStreamListener> listener =
    957      do_QueryInterface(mListener);
    958  if (listener) {
    959    return listener->OnDataFinished(aStatus);
    960  }
    961 
    962  return NS_OK;
    963 }
    964 
    965 NS_IMETHODIMP nsBaseChannel::GetCanceled(bool* aCanceled) {
    966  *aCanceled = mCanceled;
    967  return NS_OK;
    968 }
    969 
    970 void nsBaseChannel::SetupNeckoTarget() {
    971  mNeckoTarget = GetMainThreadSerialEventTarget();
    972 }
    973 
    974 NS_IMETHODIMP nsBaseChannel::GetContentRange(
    975    RefPtr<mozilla::net::ContentRange>* aRange) {
    976  if (aRange) {
    977    *aRange = mContentRange;
    978  }
    979  return NS_OK;
    980 }
    981 
    982 NS_IMETHODIMP nsBaseChannel::SetContentRange(
    983    RefPtr<mozilla::net::ContentRange> aRange) {
    984  mContentRange = aRange;
    985  return NS_OK;
    986 }
    987 
    988 NS_IMETHODIMP nsBaseChannel::GetFullMimeType(RefPtr<TMimeType<char>>* aOut) {
    989  if (aOut) {
    990    *aOut = mFullMimeType;
    991  }
    992  return NS_OK;
    993 }
    994 
    995 NS_IMETHODIMP nsBaseChannel::SetFullMimeType(RefPtr<TMimeType<char>> aType) {
    996  mFullMimeType = aType;
    997  return NS_OK;
    998 }