tor-browser

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

RemoteStreamGetter.cpp (3992B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "RemoteStreamGetter.h"
      8 #include "mozilla/MozPromise.h"
      9 #include "mozilla/net/NeckoChild.h"
     10 #include "mozilla/RefPtr.h"
     11 #include "nsContentUtils.h"
     12 #include "nsIInputStreamPump.h"
     13 
     14 namespace mozilla {
     15 namespace net {
     16 
     17 NS_IMPL_ISUPPORTS(RemoteStreamGetter, nsICancelable)
     18 
     19 RemoteStreamGetter::RemoteStreamGetter(nsIURI* aURI, nsILoadInfo* aLoadInfo)
     20    : mURI(aURI), mLoadInfo(aLoadInfo) {
     21  MOZ_ASSERT(aURI);
     22  MOZ_ASSERT(aLoadInfo);
     23 }
     24 
     25 // Request an input stream from the parent.
     26 RequestOrReason RemoteStreamGetter::GetAsync(nsIStreamListener* aListener,
     27                                             nsIChannel* aChannel,
     28                                             Method aMethod) {
     29  MOZ_ASSERT(IsNeckoChild());
     30  MOZ_ASSERT(aMethod);
     31 
     32  mListener = aListener;
     33  mChannel = aChannel;
     34 
     35  nsCOMPtr<nsICancelable> cancelableRequest(this);
     36 
     37  RefPtr<RemoteStreamGetter> self = this;
     38  LoadInfoArgs loadInfoArgs;
     39  nsresult rv = ipc::LoadInfoToLoadInfoArgs(mLoadInfo, &loadInfoArgs);
     40  if (NS_FAILED(rv)) {
     41    return Err(rv);
     42  }
     43 
     44  (gNeckoChild->*aMethod)(mURI, loadInfoArgs)
     45      ->Then(
     46          GetMainThreadSerialEventTarget(), __func__,
     47          [self](const Maybe<RemoteStreamInfo>& info) { self->OnStream(info); },
     48          [self](const mozilla::ipc::ResponseRejectReason) {
     49            self->OnStream(Nothing());
     50          });
     51  return RequestOrCancelable(WrapNotNull(cancelableRequest));
     52 }
     53 
     54 // Called to cancel the ongoing async request.
     55 NS_IMETHODIMP
     56 RemoteStreamGetter::Cancel(nsresult aStatus) {
     57  if (mCanceled) {
     58    return NS_OK;
     59  }
     60 
     61  mCanceled = true;
     62  mStatus = aStatus;
     63 
     64  if (mPump) {
     65    mPump->Cancel(aStatus);
     66    mPump = nullptr;
     67  }
     68 
     69  return NS_OK;
     70 }
     71 
     72 // static
     73 void RemoteStreamGetter::CancelRequest(nsIStreamListener* aListener,
     74                                       nsIChannel* aChannel, nsresult aResult) {
     75  MOZ_ASSERT(aListener);
     76  MOZ_ASSERT(aChannel);
     77 
     78  aListener->OnStartRequest(aChannel);
     79  aListener->OnStopRequest(aChannel, aResult);
     80  aChannel->CancelWithReason(NS_BINDING_ABORTED,
     81                             "RemoteStreamGetter::CancelRequest"_ns);
     82 }
     83 
     84 // Handle an input stream sent from the parent.
     85 void RemoteStreamGetter::OnStream(const Maybe<RemoteStreamInfo>& aStreamInfo) {
     86  MOZ_ASSERT(IsNeckoChild());
     87  MOZ_ASSERT(mChannel);
     88  MOZ_ASSERT(mListener);
     89 
     90  nsCOMPtr<nsIChannel> channel = std::move(mChannel);
     91 
     92  // We must keep an owning reference to the listener until we pass it on
     93  // to AsyncRead.
     94  nsCOMPtr<nsIStreamListener> listener = mListener.forget();
     95 
     96  if (aStreamInfo.isNothing()) {
     97    // The parent didn't send us back a stream.
     98    CancelRequest(listener, channel, NS_ERROR_FILE_ACCESS_DENIED);
     99    return;
    100  }
    101 
    102  if (mCanceled) {
    103    // The channel that has created this stream getter has been canceled.
    104    CancelRequest(listener, channel, mStatus);
    105    return;
    106  }
    107 
    108  nsCOMPtr<nsIInputStream> stream = std::move(aStreamInfo.ref().inputStream());
    109  if (!stream) {
    110    // We somehow failed to get a stream, so just cancel the request.
    111    CancelRequest(listener, channel, mStatus);
    112    return;
    113  }
    114 
    115  nsCOMPtr<nsIInputStreamPump> pump;
    116  nsresult rv =
    117      NS_NewInputStreamPump(getter_AddRefs(pump), stream.forget(), 0, 0, false,
    118                            GetMainThreadSerialEventTarget());
    119  if (NS_FAILED(rv)) {
    120    CancelRequest(listener, channel, rv);
    121    return;
    122  }
    123 
    124  channel->SetContentType(aStreamInfo.ref().contentType());
    125  channel->SetContentLength(aStreamInfo.ref().contentLength());
    126 
    127  rv = pump->AsyncRead(listener);
    128  if (NS_FAILED(rv)) {
    129    CancelRequest(listener, channel, rv);
    130    return;
    131  }
    132 
    133  mPump = pump;
    134 }
    135 
    136 }  // namespace net
    137 }  // namespace mozilla