tor-browser

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

nsStreamListenerTee.cpp (5352B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "nsStreamListenerTee.h"
      6 #include "nsProxyRelease.h"
      7 #include "nsIRequest.h"
      8 
      9 namespace mozilla {
     10 namespace net {
     11 
     12 NS_IMPL_ISUPPORTS(nsStreamListenerTee, nsIStreamListener, nsIRequestObserver,
     13                  nsIStreamListenerTee, nsIThreadRetargetableStreamListener,
     14                  nsIMultiPartChannelListener)
     15 
     16 NS_IMETHODIMP
     17 nsStreamListenerTee::OnStartRequest(nsIRequest* request) {
     18  NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED);
     19 
     20  nsCOMPtr<nsIMultiPartChannel> multiPartChannel = do_QueryInterface(request);
     21  if (multiPartChannel) {
     22    mIsMultiPart = true;
     23  }
     24 
     25  nsresult rv1 = mListener->OnStartRequest(request);
     26  nsresult rv2 = NS_OK;
     27  if (mObserver) rv2 = mObserver->OnStartRequest(request);
     28 
     29  // Preserve NS_SUCCESS_XXX in rv1 in case mObserver didn't throw
     30  return (NS_FAILED(rv2) && NS_SUCCEEDED(rv1)) ? rv2 : rv1;
     31 }
     32 
     33 NS_IMETHODIMP
     34 nsStreamListenerTee::OnStopRequest(nsIRequest* request, nsresult status) {
     35  NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED);
     36  // it is critical that we close out the input stream tee
     37  if (mInputTee) {
     38    mInputTee->SetSink(nullptr);
     39    mInputTee = nullptr;
     40  }
     41 
     42  if (!mIsMultiPart) {
     43    // release sink on the same thread where the data was written (bug 716293)
     44    if (mEventTarget) {
     45      NS_ProxyRelease("nsStreamListenerTee::mSink", mEventTarget,
     46                      mSink.forget());
     47    } else {
     48      mSink = nullptr;
     49    }
     50  }
     51 
     52  nsresult rv = mListener->OnStopRequest(request, status);
     53  if (!mIsMultiPart) {
     54    mListener = nullptr;
     55  }
     56  if (mObserver) {
     57    mObserver->OnStopRequest(request, status);
     58    if (!mIsMultiPart) {
     59      mObserver = nullptr;
     60    }
     61  }
     62  return rv;
     63 }
     64 
     65 NS_IMETHODIMP
     66 nsStreamListenerTee::OnDataAvailable(nsIRequest* request, nsIInputStream* input,
     67                                     uint64_t offset, uint32_t count) {
     68  NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED);
     69  NS_ENSURE_TRUE(mSink, NS_ERROR_NOT_INITIALIZED);
     70 
     71  nsCOMPtr<nsIInputStream> tee;
     72  nsresult rv;
     73 
     74  if (!mInputTee) {
     75    if (mEventTarget) {
     76      rv = NS_NewInputStreamTeeAsync(getter_AddRefs(tee), input, mSink,
     77                                     mEventTarget);
     78    } else {
     79      rv = NS_NewInputStreamTee(getter_AddRefs(tee), input, mSink);
     80    }
     81    if (NS_FAILED(rv)) return rv;
     82 
     83    mInputTee = do_QueryInterface(tee, &rv);
     84    if (NS_FAILED(rv)) return rv;
     85  } else {
     86    // re-initialize the input tee since the input stream may have changed.
     87    rv = mInputTee->SetSource(input);
     88    if (NS_FAILED(rv)) return rv;
     89 
     90    tee = mInputTee;
     91  }
     92 
     93  return mListener->OnDataAvailable(request, tee, offset, count);
     94 }
     95 
     96 NS_IMETHODIMP
     97 nsStreamListenerTee::OnAfterLastPart(nsresult aStatus) {
     98  // release sink on the same thread where the data was written (bug 716293)
     99  if (mEventTarget) {
    100    NS_ProxyRelease("nsStreamListenerTee::mSink", mEventTarget, mSink.forget());
    101  } else {
    102    mSink = nullptr;
    103  }
    104 
    105  if (nsCOMPtr<nsIMultiPartChannelListener> multi =
    106          do_QueryInterface(mListener)) {
    107    multi->OnAfterLastPart(aStatus);
    108  }
    109  if (!SameCOMIdentity(mListener, mObserver)) {
    110    if (nsCOMPtr<nsIMultiPartChannelListener> multi =
    111            do_QueryInterface(mObserver)) {
    112      multi->OnAfterLastPart(aStatus);
    113    }
    114  }
    115 
    116  mObserver = nullptr;
    117  return NS_OK;
    118 }
    119 
    120 NS_IMETHODIMP
    121 nsStreamListenerTee::CheckListenerChain() {
    122  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread!");
    123  nsresult rv = NS_OK;
    124  nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
    125      do_QueryInterface(mListener, &rv);
    126  if (retargetableListener) {
    127    rv = retargetableListener->CheckListenerChain();
    128  }
    129  if (NS_FAILED(rv)) {
    130    return rv;
    131  }
    132  if (!mObserver) {
    133    return rv;
    134  }
    135  retargetableListener = do_QueryInterface(mObserver, &rv);
    136  if (retargetableListener) {
    137    rv = retargetableListener->CheckListenerChain();
    138  }
    139  return rv;
    140 }
    141 
    142 NS_IMETHODIMP
    143 nsStreamListenerTee::OnDataFinished(nsresult aStatus) {
    144  nsresult rv = NS_OK;
    145  nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
    146      do_QueryInterface(mListener, &rv);
    147  if (retargetableListener) {
    148    rv = retargetableListener->OnDataFinished(aStatus);
    149  }
    150  if (NS_FAILED(rv)) {
    151    return rv;
    152  }
    153  if (!mObserver) {
    154    return rv;
    155  }
    156  retargetableListener = do_QueryInterface(mObserver, &rv);
    157  if (retargetableListener) {
    158    rv = retargetableListener->OnDataFinished(aStatus);
    159  }
    160  return rv;
    161 }
    162 
    163 NS_IMETHODIMP
    164 nsStreamListenerTee::Init(nsIStreamListener* listener, nsIOutputStream* sink,
    165                          nsIRequestObserver* requestObserver) {
    166  NS_ENSURE_ARG_POINTER(listener);
    167  NS_ENSURE_ARG_POINTER(sink);
    168  mListener = listener;
    169  mSink = sink;
    170  mObserver = requestObserver;
    171  return NS_OK;
    172 }
    173 
    174 NS_IMETHODIMP
    175 nsStreamListenerTee::InitAsync(nsIStreamListener* listener,
    176                               nsIEventTarget* eventTarget,
    177                               nsIOutputStream* sink,
    178                               nsIRequestObserver* requestObserver) {
    179  NS_ENSURE_ARG_POINTER(eventTarget);
    180  mEventTarget = eventTarget;
    181  return Init(listener, sink, requestObserver);
    182 }
    183 
    184 }  // namespace net
    185 }  // namespace mozilla