tor-browser

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

nsTransportUtils.cpp (4289B)


      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 "mozilla/Mutex.h"
      6 #include "nsCOMPtr.h"
      7 #include "nsITransport.h"
      8 #include "nsProxyRelease.h"
      9 #include "nsSocketTransportService2.h"
     10 #include "nsThreadUtils.h"
     11 #include "nsTransportUtils.h"
     12 
     13 using namespace mozilla;
     14 
     15 //-----------------------------------------------------------------------------
     16 
     17 class nsTransportStatusEvent;
     18 
     19 class nsTransportEventSinkProxy : public nsITransportEventSink {
     20 public:
     21  NS_DECL_THREADSAFE_ISUPPORTS
     22  NS_DECL_NSITRANSPORTEVENTSINK
     23 
     24  nsTransportEventSinkProxy(nsITransportEventSink* sink, nsIEventTarget* target)
     25      : mSink(sink),
     26        mTarget(target),
     27        mLock("nsTransportEventSinkProxy.mLock") {}
     28 
     29 private:
     30  virtual ~nsTransportEventSinkProxy() {
     31    // our reference to mSink could be the last, so be sure to release
     32    // it on the target thread.  otherwise, we could get into trouble.
     33    NS_ProxyRelease("nsTransportEventSinkProxy::mSink", mTarget,
     34                    mSink.forget());
     35  }
     36 
     37 public:
     38  nsCOMPtr<nsITransportEventSink> mSink;
     39  nsCOMPtr<nsIEventTarget> mTarget;
     40  Mutex mLock MOZ_UNANNOTATED;
     41  RefPtr<nsTransportStatusEvent> mLastEvent;
     42 };
     43 
     44 class nsTransportStatusEvent : public Runnable {
     45 public:
     46  nsTransportStatusEvent(nsTransportEventSinkProxy* proxy,
     47                         nsITransport* transport, nsresult status,
     48                         int64_t progress, int64_t progressMax)
     49      : Runnable("nsTransportStatusEvent"),
     50        mProxy(proxy),
     51        mTransport(transport),
     52        mStatus(status),
     53        mProgress(progress),
     54        mProgressMax(progressMax) {}
     55 
     56  ~nsTransportStatusEvent() {
     57    auto ReleaseTransport = [transport(std::move(mTransport))]() mutable {};
     58    if (!net::OnSocketThread()) {
     59      net::gSocketTransportService->Dispatch(NS_NewRunnableFunction(
     60          "nsHttpConnection::~nsHttpConnection", std::move(ReleaseTransport)));
     61    }
     62  }
     63 
     64  NS_IMETHOD Run() override {
     65    // since this event is being handled, we need to clear the proxy's ref.
     66    // if not coalescing all, then last event may not equal self!
     67    {
     68      MutexAutoLock lock(mProxy->mLock);
     69      if (mProxy->mLastEvent == this) {
     70        mProxy->mLastEvent = nullptr;
     71      }
     72    }
     73 
     74    mProxy->mSink->OnTransportStatus(mTransport, mStatus, mProgress,
     75                                     mProgressMax);
     76    mProxy = nullptr;
     77    return NS_OK;
     78  }
     79 
     80  RefPtr<nsTransportEventSinkProxy> mProxy;
     81 
     82  // parameters to OnTransportStatus
     83  nsCOMPtr<nsITransport> mTransport;
     84  nsresult mStatus;
     85  int64_t mProgress;
     86  int64_t mProgressMax;
     87 };
     88 
     89 NS_IMPL_ISUPPORTS(nsTransportEventSinkProxy, nsITransportEventSink)
     90 
     91 NS_IMETHODIMP
     92 nsTransportEventSinkProxy::OnTransportStatus(nsITransport* transport,
     93                                             nsresult status, int64_t progress,
     94                                             int64_t progressMax) {
     95  nsresult rv = NS_OK;
     96  RefPtr<nsTransportStatusEvent> event;
     97  {
     98    MutexAutoLock lock(mLock);
     99 
    100    // try to coalesce events! ;-)
    101    if (mLastEvent && (mLastEvent->mStatus == status)) {
    102      mLastEvent->mStatus = status;
    103      mLastEvent->mProgress = progress;
    104      mLastEvent->mProgressMax = progressMax;
    105    } else {
    106      event = new nsTransportStatusEvent(this, transport, status, progress,
    107                                         progressMax);
    108      if (!event) rv = NS_ERROR_OUT_OF_MEMORY;
    109      mLastEvent = event;  // weak ref
    110    }
    111  }
    112  if (event) {
    113    rv = mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
    114    if (NS_FAILED(rv)) {
    115      NS_WARNING("unable to post transport status event");
    116 
    117      MutexAutoLock lock(mLock);  // cleanup.. don't reference anymore!
    118      mLastEvent = nullptr;
    119    }
    120  }
    121  return rv;
    122 }
    123 
    124 //-----------------------------------------------------------------------------
    125 
    126 nsresult net_NewTransportEventSinkProxy(nsITransportEventSink** result,
    127                                        nsITransportEventSink* sink,
    128                                        nsIEventTarget* target) {
    129  RefPtr<nsTransportEventSinkProxy> res =
    130      new nsTransportEventSinkProxy(sink, target);
    131  res.forget(result);
    132  return NS_OK;
    133 }