tor-browser

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

GeckoViewContentChannelChild.cpp (9262B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=4 sw=2 sts=2 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 "GeckoViewContentChannelChild.h"
      8 
      9 #include "mozilla/dom/BrowserChild.h"
     10 #include "mozilla/dom/ContentChild.h"
     11 #include "mozilla/ipc/URIUtils.h"
     12 #include "mozilla/net/NeckoChild.h"
     13 #include "nsContentSecurityManager.h"
     14 #include "nsGkAtoms.h"
     15 #include "nsIBrowserChild.h"
     16 #include "nsIURIMutator.h"
     17 #include "nsStringStream.h"
     18 #include "SerializedLoadContext.h"
     19 
     20 namespace mozilla::net {
     21 
     22 NS_IMPL_ISUPPORTS_INHERITED(GeckoViewContentChannelChild, nsBaseChannel,
     23                            nsIChildChannel)
     24 
     25 GeckoViewContentChannelChild::GeckoViewContentChannelChild(nsIURI* aURI)
     26    : mEventQ(new ChannelEventQueue(static_cast<nsIChildChannel*>(this))) {
     27  SetURI(aURI);
     28  SetOriginalURI(aURI);
     29 }
     30 
     31 NS_IMETHODIMP
     32 GeckoViewContentChannelChild::ConnectParent(uint32_t aId) {
     33  mozilla::dom::BrowserChild* browserChild = nullptr;
     34  nsCOMPtr<nsIBrowserChild> iBrowserChild;
     35  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
     36                                NS_GET_IID(nsIBrowserChild),
     37                                getter_AddRefs(iBrowserChild));
     38  GetCallback(iBrowserChild);
     39  if (iBrowserChild) {
     40    browserChild =
     41        static_cast<mozilla::dom::BrowserChild*>(iBrowserChild.get());
     42  }
     43 
     44  GeckoViewContentChannelConnectArgs connectArgs(aId);
     45  if (!gNeckoChild->SendPGeckoViewContentChannelConstructor(
     46          this, browserChild, IPC::SerializedLoadContext(this), connectArgs)) {
     47    return NS_ERROR_FAILURE;
     48  }
     49 
     50  return NS_OK;
     51 }
     52 
     53 NS_IMETHODIMP
     54 GeckoViewContentChannelChild::CompleteRedirectSetup(
     55    nsIStreamListener* aListener) {
     56  mListener = aListener;
     57 
     58  if (mLoadGroup) {
     59    mLoadGroup->AddRequest(this, nullptr);
     60  }
     61 
     62  return NS_OK;
     63 }
     64 
     65 void GeckoViewContentChannelChild::ActorDestroy(ActorDestroyReason why) {}
     66 
     67 NS_IMETHODIMP
     68 GeckoViewContentChannelChild::AsyncOpen(nsIStreamListener* aListener) {
     69  nsCOMPtr<nsIStreamListener> listener = aListener;
     70 
     71  nsresult rv =
     72      nsContentSecurityManager::doContentSecurityCheck(this, listener);
     73  if (MOZ_UNLIKELY(NS_FAILED(rv))) {
     74    return rv;
     75  }
     76 
     77  NS_ENSURE_TRUE(!!gNeckoChild, NS_ERROR_FAILURE);
     78  NS_ENSURE_TRUE(!dom::ContentChild::GetSingleton()->IsShuttingDown(),
     79                 NS_ERROR_FAILURE);
     80  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
     81  NS_ENSURE_ARG(listener);
     82 
     83  // Ensure that this is an allowed port before proceeding.
     84  rv = NS_CheckPortSafety(nsBaseChannel::URI());
     85  if (MOZ_UNLIKELY(NS_FAILED(rv))) {
     86    return rv;
     87  }
     88 
     89  if (mLoadGroup) {
     90    mLoadGroup->AddRequest(this, nullptr);
     91  }
     92 
     93  uint32_t loadFlags = 0;
     94  GetLoadFlags(&loadFlags);
     95 
     96  GeckoViewContentChannelOpenArgs openArgs;
     97  ipc::SerializeURI(nsBaseChannel::URI(), openArgs.uri());
     98  openArgs.loadFlags() = loadFlags;
     99 
    100  nsCOMPtr<nsILoadInfo> loadInfo = nsBaseChannel::LoadInfo();
    101  rv = mozilla::ipc::LoadInfoToLoadInfoArgs(loadInfo, &openArgs.loadInfo());
    102  if (MOZ_UNLIKELY(NS_FAILED(rv))) {
    103    return rv;
    104  }
    105 
    106  mozilla::dom::BrowserChild* browserChild = nullptr;
    107  nsCOMPtr<nsIBrowserChild> iBrowserChild;
    108  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
    109                                NS_GET_IID(nsIBrowserChild),
    110                                getter_AddRefs(iBrowserChild));
    111  GetCallback(iBrowserChild);
    112  if (iBrowserChild) {
    113    browserChild =
    114        static_cast<mozilla::dom::BrowserChild*>(iBrowserChild.get());
    115  }
    116 
    117  if (!gNeckoChild->SendPGeckoViewContentChannelConstructor(
    118          this, browserChild, IPC::SerializedLoadContext(this), openArgs)) {
    119    return NS_ERROR_FAILURE;
    120  }
    121 
    122  return NS_OK;
    123 }
    124 
    125 NS_IMETHODIMP
    126 GeckoViewContentChannelChild::Cancel(nsresult aStatus) {
    127  if (mCanceled) {
    128    return NS_OK;
    129  }
    130 
    131  mCanceled = true;
    132  mStatus = aStatus;
    133 
    134  if (CanSend()) {
    135    SendCancel(aStatus);
    136  }
    137 
    138  return NS_OK;
    139 }
    140 
    141 NS_IMETHODIMP
    142 GeckoViewContentChannelChild::Suspend() {
    143  if (!mSuspendCount++) {
    144    SendSuspend();
    145    mSuspendSent = true;
    146  }
    147  mEventQ->Suspend();
    148 
    149  return NS_OK;
    150 }
    151 
    152 NS_IMETHODIMP
    153 GeckoViewContentChannelChild::Resume() {
    154  if (!mSuspendCount) {
    155    return NS_ERROR_UNEXPECTED;
    156  }
    157 
    158  if (!--mSuspendCount && mSuspendSent) {
    159    SendResume();
    160  }
    161  mEventQ->Resume();
    162 
    163  return NS_OK;
    164 }
    165 
    166 nsresult GeckoViewContentChannelChild::OpenContentStream(
    167    bool aAsync, nsIInputStream** aStream, nsIChannel** aChannel) {
    168  MOZ_ASSERT_UNREACHABLE(
    169      "GeckoViewContentChannel*Child* should never have OpenContentStream "
    170      "called!");
    171  return NS_OK;
    172 }
    173 
    174 mozilla::ipc::IPCResult GeckoViewContentChannelChild::RecvOnStartRequest(
    175    const nsresult& aChannelStatus, const nsACString& aContentType,
    176    const nsACString& aEntityID, mozilla::NotNull<nsIURI*> aURI) {
    177  mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
    178      this, [self = UnsafePtr<GeckoViewContentChannelChild>(this),
    179             aChannelStatus, aContentType = nsCString(aContentType),
    180             aEntityID = nsCString(aEntityID), aURI = RefPtr{aURI.get()}]() {
    181        self->DoOnStartRequest(aChannelStatus, aContentType, aEntityID, aURI);
    182      }));
    183  return IPC_OK();
    184 }
    185 
    186 void GeckoViewContentChannelChild::DoOnStartRequest(
    187    const nsresult& aChannelStatus, const nsCString& aContentType,
    188    const nsCString& aEntityID, nsIURI* aURI) {
    189  // content:// doesn't know data length at this time.
    190  mContentLength = -1;
    191  SetContentType(aContentType);
    192 
    193  nsCString spec;
    194  nsresult rv = aURI->GetSpec(spec);
    195  if (NS_SUCCEEDED(rv)) {
    196    // Changes nsBaseChannel::URI()
    197    rv = NS_MutateURI(mURI).SetSpec(spec).Finalize(mURI);
    198  }
    199 
    200  if (NS_FAILED(rv)) {
    201    Cancel(rv);
    202  }
    203 
    204  AutoEventEnqueuer ensureSerialDispatch(mEventQ);
    205  rv = mListener->OnStartRequest(reinterpret_cast<nsBaseChannel*>(this));
    206  if (MOZ_UNLIKELY(NS_FAILED(rv))) {
    207    Cancel(rv);
    208  }
    209 }
    210 
    211 mozilla::ipc::IPCResult GeckoViewContentChannelChild::RecvOnDataAvailable(
    212    const nsresult& aChannelStatus, const nsACString& aData,
    213    const uint64_t& aOffset, const uint32_t& aCount) {
    214  mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
    215      this, [self = UnsafePtr<GeckoViewContentChannelChild>(this),
    216             aChannelStatus, aData = nsCString(aData), aOffset, aCount]() {
    217        self->DoOnDataAvailable(aChannelStatus, aData, aOffset, aCount);
    218      }));
    219  return IPC_OK();
    220 }
    221 
    222 void GeckoViewContentChannelChild::DoOnDataAvailable(
    223    const nsresult& aChannelStatus, const nsCString& aData,
    224    const uint64_t& aOffset, const uint32_t& aCount) {
    225  nsCOMPtr<nsIInputStream> stringStream;
    226  nsresult rv =
    227      NS_NewByteInputStream(getter_AddRefs(stringStream),
    228                            Span(aData).To(aCount), NS_ASSIGNMENT_DEPEND);
    229  if (MOZ_UNLIKELY(NS_FAILED(rv))) {
    230    Cancel(rv);
    231    return;
    232  }
    233 
    234  AutoEventEnqueuer ensureSerialDispatch(mEventQ);
    235  rv = mListener->OnDataAvailable(reinterpret_cast<nsBaseChannel*>(this),
    236                                  stringStream, aOffset, aCount);
    237  stringStream->Close();
    238  if (MOZ_UNLIKELY(NS_FAILED(rv))) {
    239    Cancel(rv);
    240  }
    241 }
    242 
    243 mozilla::ipc::IPCResult GeckoViewContentChannelChild::RecvOnStopRequest(
    244    const nsresult& aChannelStatus) {
    245  mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
    246      this, [self = UnsafePtr<GeckoViewContentChannelChild>(this),
    247             aChannelStatus]() { self->DoOnStopRequest(aChannelStatus); }));
    248  return IPC_OK();
    249 }
    250 
    251 void GeckoViewContentChannelChild::DoOnStopRequest(
    252    const nsresult& aChannelStatus) {
    253  if (!mCanceled) {
    254    mStatus = aChannelStatus;
    255  }
    256 
    257  {
    258    AutoEventEnqueuer ensureSerialDispatch(mEventQ);
    259    mListener->OnStopRequest(reinterpret_cast<nsBaseChannel*>(this),
    260                             aChannelStatus);
    261    mListener = nullptr;
    262 
    263    if (mLoadGroup) {
    264      mLoadGroup->RemoveRequest(this, nullptr, aChannelStatus);
    265    }
    266  }
    267 
    268  Send__delete__(this);
    269 }
    270 
    271 mozilla::ipc::IPCResult GeckoViewContentChannelChild::RecvOnAsyncOpenFailed(
    272    const nsresult& aChannelStatus) {
    273  mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
    274      this, [self = UnsafePtr<GeckoViewContentChannelChild>(this),
    275             aChannelStatus]() { self->DoOnAsyncOpenFailed(aChannelStatus); }));
    276  return IPC_OK();
    277 }
    278 
    279 void GeckoViewContentChannelChild::DoOnAsyncOpenFailed(
    280    const nsresult& aChannelStatus) {
    281  mStatus = aChannelStatus;
    282 
    283  if (mLoadGroup) {
    284    mLoadGroup->RemoveRequest(this, nullptr, aChannelStatus);
    285  }
    286 
    287  if (mListener) {
    288    mListener->OnStartRequest(reinterpret_cast<nsBaseChannel*>(this));
    289    mListener->OnStopRequest(reinterpret_cast<nsBaseChannel*>(this),
    290                             aChannelStatus);
    291  }
    292 
    293  mListener = nullptr;
    294 
    295  if (CanSend()) {
    296    Send__delete__(this);
    297  }
    298 }
    299 
    300 mozilla::ipc::IPCResult GeckoViewContentChannelChild::RecvDeleteSelf() {
    301  mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
    302      this, [self = UnsafePtr<GeckoViewContentChannelChild>(this)]() {
    303        self->DoDeleteSelf();
    304      }));
    305  return IPC_OK();
    306 }
    307 
    308 void GeckoViewContentChannelChild::DoDeleteSelf() {
    309  if (CanSend()) {
    310    Send__delete__(this);
    311  }
    312 }
    313 
    314 }  // namespace mozilla::net