tor-browser

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

DocumentChannel.cpp (15410B)


      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 #include "mozilla/net/DocumentChannel.h"
      9 
     10 #include <inttypes.h>
     11 #include "mozIDOMWindow.h"
     12 #include "mozilla/AlreadyAddRefed.h"
     13 #include "mozilla/Assertions.h"
     14 #include "mozilla/LoadInfo.h"
     15 #include "mozilla/Logging.h"
     16 #include "mozilla/RefPtr.h"
     17 #include "mozilla/TimeStamp.h"
     18 #include "mozilla/dom/Document.h"
     19 #include "mozilla/net/DocumentChannelChild.h"
     20 #include "mozilla/net/ParentProcessDocumentChannel.h"
     21 #include "nsCOMPtr.h"
     22 #include "nsDebug.h"
     23 #include "nsDocShell.h"
     24 #include "nsDocShellLoadState.h"
     25 #include "nsHttpHandler.h"
     26 #include "nsIContentPolicy.h"
     27 #include "nsIInterfaceRequestor.h"
     28 #include "nsILoadContext.h"
     29 #include "nsILoadGroup.h"
     30 #include "nsILoadInfo.h"
     31 #include "nsIStreamListener.h"
     32 #include "nsIURI.h"
     33 #include "nsLoadGroup.h"
     34 #include "nsMimeTypes.h"
     35 #include "nsNetUtil.h"
     36 #include "nsPIDOMWindow.h"
     37 #include "nsPIDOMWindowInlines.h"
     38 #include "nsStringFwd.h"
     39 #include "nsThreadUtils.h"
     40 #include "nsXULAppAPI.h"
     41 #include "nscore.h"
     42 
     43 using namespace mozilla::dom;
     44 using namespace mozilla::ipc;
     45 
     46 extern mozilla::LazyLogModule gDocumentChannelLog;
     47 #define LOG(fmt) MOZ_LOG(gDocumentChannelLog, mozilla::LogLevel::Verbose, fmt)
     48 
     49 namespace mozilla {
     50 namespace net {
     51 
     52 //-----------------------------------------------------------------------------
     53 // DocumentChannel::nsISupports
     54 
     55 NS_IMPL_ADDREF(DocumentChannel)
     56 NS_IMPL_RELEASE(DocumentChannel)
     57 
     58 NS_INTERFACE_MAP_BEGIN(DocumentChannel)
     59  NS_INTERFACE_MAP_ENTRY(nsIRequest)
     60  NS_INTERFACE_MAP_ENTRY(nsIChannel)
     61  NS_INTERFACE_MAP_ENTRY(nsIIdentChannel)
     62  NS_INTERFACE_MAP_ENTRY_CONCRETE(DocumentChannel)
     63  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRequest)
     64 NS_INTERFACE_MAP_END
     65 
     66 DocumentChannel::DocumentChannel(nsDocShellLoadState* aLoadState,
     67                                 net::LoadInfo* aLoadInfo,
     68                                 nsLoadFlags aLoadFlags, uint32_t aCacheKey,
     69                                 bool aUriModified,
     70                                 bool aIsEmbeddingBlockedError)
     71    : mLoadState(aLoadState),
     72      mCacheKey(aCacheKey),
     73      mLoadFlags(aLoadFlags),
     74      mURI(aLoadState->URI()),
     75      mLoadInfo(aLoadInfo),
     76      mUriModified(aUriModified),
     77      mIsEmbeddingBlockedError(aIsEmbeddingBlockedError) {
     78  LOG(("DocumentChannel ctor [this=%p, uri=%s]", this,
     79       aLoadState->URI()->GetSpecOrDefault().get()));
     80  RefPtr<nsHttpHandler> handler = nsHttpHandler::GetInstance();
     81  mChannelId = handler->NewChannelId();
     82 }
     83 
     84 NS_IMETHODIMP
     85 DocumentChannel::AsyncOpen(nsIStreamListener* aListener) {
     86  MOZ_CRASH("If we get here, something is broken");
     87  return NS_ERROR_NOT_IMPLEMENTED;
     88 }
     89 
     90 void DocumentChannel::ShutdownListeners(nsresult aStatusCode) {
     91  LOG(("DocumentChannel ShutdownListeners [this=%p, status=%" PRIx32 "]", this,
     92       static_cast<uint32_t>(aStatusCode)));
     93  mStatus = aStatusCode;
     94 
     95  nsCOMPtr<nsIStreamListener> listener = mListener;
     96  if (listener) {
     97    listener->OnStartRequest(this);
     98  }
     99 
    100  mIsPending = false;
    101 
    102  listener = mListener;  // it might have changed!
    103  nsCOMPtr<nsILoadGroup> loadGroup = mLoadGroup;
    104 
    105  mListener = nullptr;
    106  mLoadGroup = nullptr;
    107  mCallbacks = nullptr;
    108 
    109  NS_DispatchToMainThread(NS_NewRunnableFunction(
    110      "DocumentChannel::ShutdownListeners", [=, self = RefPtr{this}] {
    111        if (listener) {
    112          listener->OnStopRequest(self, aStatusCode);
    113        }
    114 
    115        if (loadGroup) {
    116          loadGroup->RemoveRequest(self, nullptr, aStatusCode);
    117        }
    118      }));
    119 
    120  DeleteIPDL();
    121 }
    122 
    123 void DocumentChannel::DisconnectChildListeners(
    124    const nsresult& aStatus, const nsresult& aLoadGroupStatus) {
    125  MOZ_ASSERT(NS_FAILED(aStatus));
    126 
    127  // In the case where the channel was redirected to be downloaded by the
    128  // nsExternalHelperAppService in the parent process, we'll be called with a
    129  // different aLoadGroupStatus and aStatus.
    130  //
    131  // Before DocumentChannel was implemented, the channel would have been removed
    132  // from the load group by the nsExternalHelperAppService. This simulates that
    133  // behaviour by removing the load group when the channel is no longer in use.
    134  //
    135  // We cannot unconditionally remove the channel from the load group here, as
    136  // that may unblock load events too early if new navigations will be started
    137  // by channel listeners. See bug 1961008.
    138  if (aStatus != aLoadGroupStatus) {
    139    MOZ_ASSERT(aStatus == NS_BINDING_RETARGETED);
    140    MOZ_ASSERT(NS_SUCCEEDED(aLoadGroupStatus));
    141 
    142    mStatus = aLoadGroupStatus;
    143    if (mLoadGroup) {
    144      mLoadGroup->RemoveRequest(this, nullptr, aStatus);
    145      mLoadGroup = nullptr;
    146    }
    147  }
    148 
    149  ShutdownListeners(aStatus);
    150 }
    151 
    152 nsDocShell* DocumentChannel::GetDocShell() {
    153  nsCOMPtr<nsILoadContext> loadContext;
    154  NS_QueryNotificationCallbacks(this, loadContext);
    155  if (!loadContext) {
    156    return nullptr;
    157  }
    158  nsCOMPtr<mozIDOMWindowProxy> domWindow;
    159  loadContext->GetAssociatedWindow(getter_AddRefs(domWindow));
    160  if (!domWindow) {
    161    return nullptr;
    162  }
    163  auto* pDomWindow = nsPIDOMWindowOuter::From(domWindow);
    164  nsIDocShell* docshell = pDomWindow->GetDocShell();
    165  return nsDocShell::Cast(docshell);
    166 }
    167 
    168 static bool URIUsesDocChannel(nsIURI* aURI) {
    169  if (aURI->SchemeIs("javascript")) {
    170    return false;
    171  }
    172 
    173  nsCString spec = aURI->GetSpecOrDefault();
    174  return
    175 #ifdef MOZ_WIDGET_ANDROID
    176      !spec.EqualsLiteral("about:crashcontentjava") &&
    177 #endif
    178      !spec.EqualsLiteral("about:crashcontent");
    179 }
    180 
    181 bool DocumentChannel::CanUseDocumentChannel(nsIURI* aURI) {
    182  // We want to use DocumentChannel if we're using a supported scheme.
    183  return URIUsesDocChannel(aURI);
    184 }
    185 
    186 /* static */
    187 already_AddRefed<DocumentChannel> DocumentChannel::CreateForDocument(
    188    nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
    189    nsLoadFlags aLoadFlags, nsIInterfaceRequestor* aNotificationCallbacks,
    190    uint32_t aCacheKey, bool aUriModified, bool aIsEmbeddingBlockedError) {
    191  RefPtr<DocumentChannel> channel;
    192  if (XRE_IsContentProcess()) {
    193    channel =
    194        new DocumentChannelChild(aLoadState, aLoadInfo, aLoadFlags, aCacheKey,
    195                                 aUriModified, aIsEmbeddingBlockedError);
    196  } else {
    197    channel = new ParentProcessDocumentChannel(
    198        aLoadState, aLoadInfo, aLoadFlags, aCacheKey, aUriModified,
    199        aIsEmbeddingBlockedError);
    200  }
    201  channel->SetNotificationCallbacks(aNotificationCallbacks);
    202  return channel.forget();
    203 }
    204 
    205 /* static */
    206 already_AddRefed<DocumentChannel> DocumentChannel::CreateForObject(
    207    nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
    208    nsLoadFlags aLoadFlags, nsIInterfaceRequestor* aNotificationCallbacks) {
    209  return CreateForDocument(aLoadState, aLoadInfo, aLoadFlags,
    210                           aNotificationCallbacks, 0, false, false);
    211 }
    212 
    213 NS_IMETHODIMP DocumentChannel::SetCanceledReason(const nsACString& aReason) {
    214  return SetCanceledReasonImpl(aReason);
    215 }
    216 
    217 NS_IMETHODIMP DocumentChannel::GetCanceledReason(nsACString& aReason) {
    218  return GetCanceledReasonImpl(aReason);
    219 }
    220 
    221 NS_IMETHODIMP DocumentChannel::CancelWithReason(nsresult aStatus,
    222                                                const nsACString& aReason) {
    223  return CancelWithReasonImpl(aStatus, aReason);
    224 }
    225 
    226 NS_IMETHODIMP
    227 DocumentChannel::Cancel(nsresult aStatusCode) {
    228  MOZ_CRASH("If we get here, something is broken");
    229  return NS_ERROR_NOT_IMPLEMENTED;
    230 }
    231 
    232 NS_IMETHODIMP
    233 DocumentChannel::Suspend() {
    234  MOZ_CRASH("If we get here, something is broken");
    235  return NS_ERROR_NOT_IMPLEMENTED;
    236 }
    237 
    238 NS_IMETHODIMP
    239 DocumentChannel::Resume() {
    240  MOZ_CRASH("If we get here, something is broken");
    241  return NS_ERROR_NOT_IMPLEMENTED;
    242 }
    243 
    244 //-----------------------------------------------------------------------------
    245 // Remainder of nsIRequest/nsIChannel.
    246 //-----------------------------------------------------------------------------
    247 
    248 NS_IMETHODIMP DocumentChannel::GetNotificationCallbacks(
    249    nsIInterfaceRequestor** aCallbacks) {
    250  nsCOMPtr<nsIInterfaceRequestor> callbacks(mCallbacks);
    251  callbacks.forget(aCallbacks);
    252  return NS_OK;
    253 }
    254 
    255 NS_IMETHODIMP DocumentChannel::SetNotificationCallbacks(
    256    nsIInterfaceRequestor* aNotificationCallbacks) {
    257  mCallbacks = aNotificationCallbacks;
    258  return NS_OK;
    259 }
    260 
    261 NS_IMETHODIMP DocumentChannel::GetLoadGroup(nsILoadGroup** aLoadGroup) {
    262  nsCOMPtr<nsILoadGroup> loadGroup(mLoadGroup);
    263  loadGroup.forget(aLoadGroup);
    264  return NS_OK;
    265 }
    266 
    267 NS_IMETHODIMP DocumentChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) {
    268  mLoadGroup = aLoadGroup;
    269  return NS_OK;
    270 }
    271 
    272 NS_IMETHODIMP DocumentChannel::GetStatus(nsresult* aStatus) {
    273  *aStatus = mStatus;
    274  return NS_OK;
    275 }
    276 
    277 NS_IMETHODIMP DocumentChannel::GetName(nsACString& aResult) {
    278  if (!mURI) {
    279    aResult.Truncate();
    280    return NS_OK;
    281  }
    282  nsCString spec;
    283  nsresult rv = mURI->GetSpec(spec);
    284  NS_ENSURE_SUCCESS(rv, rv);
    285 
    286  aResult.AssignLiteral("documentchannel:");
    287  aResult.Append(spec);
    288  return NS_OK;
    289 }
    290 
    291 NS_IMETHODIMP DocumentChannel::IsPending(bool* aResult) {
    292  *aResult = mIsPending;
    293  return NS_OK;
    294 }
    295 
    296 NS_IMETHODIMP DocumentChannel::GetLoadFlags(nsLoadFlags* aLoadFlags) {
    297  *aLoadFlags = mLoadFlags;
    298  return NS_OK;
    299 }
    300 
    301 NS_IMETHODIMP
    302 DocumentChannel::GetTRRMode(nsIRequest::TRRMode* aTRRMode) {
    303  return GetTRRModeImpl(aTRRMode);
    304 }
    305 
    306 NS_IMETHODIMP
    307 DocumentChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode) {
    308  return SetTRRModeImpl(aTRRMode);
    309 }
    310 
    311 NS_IMETHODIMP DocumentChannel::SetLoadFlags(nsLoadFlags aLoadFlags) {
    312  nsLoadFlags mayChange = 0;
    313  if (mLoadInfo->GetExternalContentPolicyType() ==
    314      ExtContentPolicy::TYPE_OBJECT) {
    315    // Setting load flags for TYPE_OBJECT is OK, so long as the channel to
    316    // parent isn't opened yet, or we're only setting the `LOAD_DOCUMENT_URI`
    317    // flag.
    318    mayChange = mWasOpened ? LOAD_DOCUMENT_URI : ~0u;
    319  } else if (!mWasOpened) {
    320    // If we haven't been opened yet, allow the LoadGroup to
    321    // set cache control flags inherited from the default channel.
    322    mayChange = nsLoadGroup::kInheritedLoadFlags;
    323  }
    324 
    325  // Check if we're allowed to adjust these flags.
    326  if ((mLoadFlags & ~mayChange) == (aLoadFlags & ~mayChange)) {
    327    mLoadFlags = aLoadFlags;
    328    return NS_OK;
    329  }
    330  MOZ_CRASH_UNSAFE_PRINTF(
    331      "DocumentChannel::SetLoadFlags: Don't set flags after creation "
    332      "(differing flags %x != %x)",
    333      (mLoadFlags ^ aLoadFlags) & mLoadFlags,
    334      (mLoadFlags ^ aLoadFlags) & aLoadFlags);
    335  return NS_OK;
    336 }
    337 
    338 NS_IMETHODIMP DocumentChannel::GetOriginalURI(nsIURI** aOriginalURI) {
    339  nsCOMPtr<nsIURI> originalURI =
    340      mLoadState->OriginalURI() ? mLoadState->OriginalURI() : mLoadState->URI();
    341  originalURI.forget(aOriginalURI);
    342  return NS_OK;
    343 }
    344 
    345 NS_IMETHODIMP DocumentChannel::SetOriginalURI(nsIURI* aOriginalURI) {
    346  MOZ_CRASH("If we get here, something is broken");
    347  return NS_ERROR_NOT_IMPLEMENTED;
    348 }
    349 
    350 NS_IMETHODIMP DocumentChannel::GetURI(nsIURI** aURI) {
    351  nsCOMPtr<nsIURI> uri(mURI);
    352  uri.forget(aURI);
    353  return NS_OK;
    354 }
    355 
    356 NS_IMETHODIMP DocumentChannel::GetOwner(nsISupports** aOwner) {
    357  nsCOMPtr<nsISupports> owner(mOwner);
    358  owner.forget(aOwner);
    359  return NS_OK;
    360 }
    361 
    362 NS_IMETHODIMP DocumentChannel::SetOwner(nsISupports* aOwner) {
    363  mOwner = aOwner;
    364  return NS_OK;
    365 }
    366 
    367 NS_IMETHODIMP DocumentChannel::GetSecurityInfo(
    368    nsITransportSecurityInfo** aSecurityInfo) {
    369  *aSecurityInfo = nullptr;
    370  return NS_OK;
    371 }
    372 
    373 NS_IMETHODIMP DocumentChannel::GetContentType(nsACString& aContentType) {
    374  // We may be trying to load HTML object data, and have determined that we're
    375  // going to be performing a document load. In that case, fake the "text/html"
    376  // content type for nsObjectLoadingContent.
    377  if ((mLoadFlags & nsIRequest::LOAD_HTML_OBJECT_DATA) &&
    378      (mLoadFlags & nsIChannel::LOAD_DOCUMENT_URI)) {
    379    aContentType = TEXT_HTML;
    380    return NS_OK;
    381  }
    382 
    383  NS_ERROR("If we get here, something is broken");
    384  return NS_ERROR_NOT_IMPLEMENTED;
    385 }
    386 
    387 NS_IMETHODIMP DocumentChannel::SetContentType(const nsACString& aContentType) {
    388  MOZ_CRASH("If we get here, something is broken");
    389  return NS_ERROR_NOT_IMPLEMENTED;
    390 }
    391 
    392 NS_IMETHODIMP DocumentChannel::GetContentCharset(nsACString& aContentCharset) {
    393  MOZ_CRASH("If we get here, something is broken");
    394  return NS_ERROR_NOT_IMPLEMENTED;
    395 }
    396 
    397 NS_IMETHODIMP DocumentChannel::SetContentCharset(
    398    const nsACString& aContentCharset) {
    399  MOZ_CRASH("If we get here, something is broken");
    400  return NS_ERROR_NOT_IMPLEMENTED;
    401 }
    402 
    403 NS_IMETHODIMP DocumentChannel::GetContentLength(int64_t* aContentLength) {
    404  MOZ_CRASH("If we get here, something is broken");
    405  return NS_ERROR_NOT_IMPLEMENTED;
    406 }
    407 
    408 NS_IMETHODIMP DocumentChannel::SetContentLength(int64_t aContentLength) {
    409  MOZ_CRASH("If we get here, something is broken");
    410  return NS_ERROR_NOT_IMPLEMENTED;
    411 }
    412 
    413 NS_IMETHODIMP DocumentChannel::Open(nsIInputStream** aStream) {
    414  MOZ_CRASH("If we get here, something is broken");
    415  return NS_ERROR_NOT_IMPLEMENTED;
    416 }
    417 
    418 NS_IMETHODIMP DocumentChannel::GetContentDisposition(
    419    uint32_t* aContentDisposition) {
    420  MOZ_CRASH("If we get here, something is broken");
    421  return NS_ERROR_NOT_IMPLEMENTED;
    422 }
    423 
    424 NS_IMETHODIMP DocumentChannel::SetContentDisposition(
    425    uint32_t aContentDisposition) {
    426  MOZ_CRASH("If we get here, something is broken");
    427  return NS_ERROR_NOT_IMPLEMENTED;
    428 }
    429 
    430 NS_IMETHODIMP DocumentChannel::GetContentDispositionFilename(
    431    nsAString& aContentDispositionFilename) {
    432  MOZ_CRASH("If we get here, something will be broken");
    433  return NS_ERROR_NOT_IMPLEMENTED;
    434 }
    435 
    436 NS_IMETHODIMP DocumentChannel::SetContentDispositionFilename(
    437    const nsAString& aContentDispositionFilename) {
    438  MOZ_CRASH("If we get here, something will be broken");
    439  return NS_ERROR_NOT_IMPLEMENTED;
    440 }
    441 
    442 NS_IMETHODIMP DocumentChannel::GetContentDispositionHeader(
    443    nsACString& aContentDispositionHeader) {
    444  MOZ_CRASH("If we get here, something is broken");
    445  return NS_ERROR_NOT_IMPLEMENTED;
    446 }
    447 
    448 NS_IMETHODIMP DocumentChannel::GetLoadInfo(nsILoadInfo** aLoadInfo) {
    449  nsCOMPtr<nsILoadInfo> loadInfo(mLoadInfo);
    450  loadInfo.forget(aLoadInfo);
    451  return NS_OK;
    452 }
    453 
    454 NS_IMETHODIMP DocumentChannel::SetLoadInfo(nsILoadInfo* aLoadInfo) {
    455  MOZ_CRASH("If we get here, something is broken");
    456  return NS_ERROR_NOT_IMPLEMENTED;
    457 }
    458 
    459 NS_IMETHODIMP DocumentChannel::GetIsDocument(bool* aIsDocument) {
    460  return NS_GetIsDocumentChannel(this, aIsDocument);
    461 }
    462 
    463 NS_IMETHODIMP DocumentChannel::GetCanceled(bool* aCanceled) {
    464  *aCanceled = mCanceled;
    465  return NS_OK;
    466 }
    467 
    468 //-----------------------------------------------------------------------------
    469 // nsIIdentChannel
    470 //-----------------------------------------------------------------------------
    471 
    472 NS_IMETHODIMP
    473 DocumentChannel::GetChannelId(uint64_t* aChannelId) {
    474  *aChannelId = mChannelId;
    475  return NS_OK;
    476 }
    477 
    478 NS_IMETHODIMP
    479 DocumentChannel::SetChannelId(uint64_t aChannelId) {
    480  mChannelId = aChannelId;
    481  return NS_OK;
    482 }
    483 
    484 //-----------------------------------------------------------------------------
    485 // Helpers
    486 //-----------------------------------------------------------------------------
    487 
    488 uint64_t InnerWindowIDForExtantDoc(nsDocShell* docShell) {
    489  if (!docShell) {
    490    return 0;
    491  }
    492 
    493  Document* doc = docShell->GetExtantDocument();
    494  if (!doc) {
    495    return 0;
    496  }
    497 
    498  return doc->InnerWindowID();
    499 }
    500 
    501 }  // namespace net
    502 }  // namespace mozilla
    503 
    504 #undef LOG