diff options
Diffstat (limited to 'netwerk/base/nsTransportUtils.cpp')
-rw-r--r-- | netwerk/base/nsTransportUtils.cpp | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/netwerk/base/nsTransportUtils.cpp b/netwerk/base/nsTransportUtils.cpp new file mode 100644 index 0000000000..e29bbfdab5 --- /dev/null +++ b/netwerk/base/nsTransportUtils.cpp @@ -0,0 +1,142 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Mutex.h" +#include "nsTransportUtils.h" +#include "nsITransport.h" +#include "nsProxyRelease.h" +#include "nsThreadUtils.h" +#include "nsAutoPtr.h" +#include "nsCOMPtr.h" + +using namespace mozilla; + +//----------------------------------------------------------------------------- + +class nsTransportStatusEvent; + +class nsTransportEventSinkProxy : public nsITransportEventSink +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSITRANSPORTEVENTSINK + + nsTransportEventSinkProxy(nsITransportEventSink *sink, + nsIEventTarget *target) + : mSink(sink) + , mTarget(target) + , mLock("nsTransportEventSinkProxy.mLock") + , mLastEvent(nullptr) + { + NS_ADDREF(mSink); + } + +private: + virtual ~nsTransportEventSinkProxy() + { + // our reference to mSink could be the last, so be sure to release + // it on the target thread. otherwise, we could get into trouble. + NS_ProxyRelease(mTarget, dont_AddRef(mSink)); + } + +public: + nsITransportEventSink *mSink; + nsCOMPtr<nsIEventTarget> mTarget; + Mutex mLock; + nsTransportStatusEvent *mLastEvent; +}; + +class nsTransportStatusEvent : public Runnable +{ +public: + nsTransportStatusEvent(nsTransportEventSinkProxy *proxy, + nsITransport *transport, + nsresult status, + int64_t progress, + int64_t progressMax) + : mProxy(proxy) + , mTransport(transport) + , mStatus(status) + , mProgress(progress) + , mProgressMax(progressMax) + {} + + ~nsTransportStatusEvent() {} + + NS_IMETHOD Run() override + { + // since this event is being handled, we need to clear the proxy's ref. + // if not coalescing all, then last event may not equal self! + { + MutexAutoLock lock(mProxy->mLock); + if (mProxy->mLastEvent == this) + mProxy->mLastEvent = nullptr; + } + + mProxy->mSink->OnTransportStatus(mTransport, mStatus, mProgress, + mProgressMax); + return NS_OK; + } + + RefPtr<nsTransportEventSinkProxy> mProxy; + + // parameters to OnTransportStatus + nsCOMPtr<nsITransport> mTransport; + nsresult mStatus; + int64_t mProgress; + int64_t mProgressMax; +}; + +NS_IMPL_ISUPPORTS(nsTransportEventSinkProxy, nsITransportEventSink) + +NS_IMETHODIMP +nsTransportEventSinkProxy::OnTransportStatus(nsITransport *transport, + nsresult status, + int64_t progress, + int64_t progressMax) +{ + nsresult rv = NS_OK; + RefPtr<nsTransportStatusEvent> event; + { + MutexAutoLock lock(mLock); + + // try to coalesce events! ;-) + if (mLastEvent && (mLastEvent->mStatus == status)) { + mLastEvent->mStatus = status; + mLastEvent->mProgress = progress; + mLastEvent->mProgressMax = progressMax; + } + else { + event = new nsTransportStatusEvent(this, transport, status, + progress, progressMax); + if (!event) + rv = NS_ERROR_OUT_OF_MEMORY; + mLastEvent = event; // weak ref + } + } + if (event) { + rv = mTarget->Dispatch(event, NS_DISPATCH_NORMAL); + if (NS_FAILED(rv)) { + NS_WARNING("unable to post transport status event"); + + MutexAutoLock lock(mLock); // cleanup.. don't reference anymore! + mLastEvent = nullptr; + } + } + return rv; +} + +//----------------------------------------------------------------------------- + +nsresult +net_NewTransportEventSinkProxy(nsITransportEventSink **result, + nsITransportEventSink *sink, + nsIEventTarget *target) +{ + *result = new nsTransportEventSinkProxy(sink, target); + if (!*result) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(*result); + return NS_OK; +} |