1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/base/src/nsTransportUtils.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,144 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "mozilla/Mutex.h" 1.9 +#include "nsTransportUtils.h" 1.10 +#include "nsITransport.h" 1.11 +#include "nsProxyRelease.h" 1.12 +#include "nsThreadUtils.h" 1.13 +#include "nsAutoPtr.h" 1.14 +#include "nsCOMPtr.h" 1.15 + 1.16 +using namespace mozilla; 1.17 + 1.18 +//----------------------------------------------------------------------------- 1.19 + 1.20 +class nsTransportStatusEvent; 1.21 + 1.22 +class nsTransportEventSinkProxy : public nsITransportEventSink 1.23 +{ 1.24 +public: 1.25 + NS_DECL_THREADSAFE_ISUPPORTS 1.26 + NS_DECL_NSITRANSPORTEVENTSINK 1.27 + 1.28 + nsTransportEventSinkProxy(nsITransportEventSink *sink, 1.29 + nsIEventTarget *target, 1.30 + bool coalesceAll) 1.31 + : mSink(sink) 1.32 + , mTarget(target) 1.33 + , mLock("nsTransportEventSinkProxy.mLock") 1.34 + , mLastEvent(nullptr) 1.35 + , mCoalesceAll(coalesceAll) 1.36 + { 1.37 + NS_ADDREF(mSink); 1.38 + } 1.39 + 1.40 + virtual ~nsTransportEventSinkProxy() 1.41 + { 1.42 + // our reference to mSink could be the last, so be sure to release 1.43 + // it on the target thread. otherwise, we could get into trouble. 1.44 + NS_ProxyRelease(mTarget, mSink); 1.45 + } 1.46 + 1.47 + nsITransportEventSink *mSink; 1.48 + nsCOMPtr<nsIEventTarget> mTarget; 1.49 + Mutex mLock; 1.50 + nsTransportStatusEvent *mLastEvent; 1.51 + bool mCoalesceAll; 1.52 +}; 1.53 + 1.54 +class nsTransportStatusEvent : public nsRunnable 1.55 +{ 1.56 +public: 1.57 + nsTransportStatusEvent(nsTransportEventSinkProxy *proxy, 1.58 + nsITransport *transport, 1.59 + nsresult status, 1.60 + uint64_t progress, 1.61 + uint64_t progressMax) 1.62 + : mProxy(proxy) 1.63 + , mTransport(transport) 1.64 + , mStatus(status) 1.65 + , mProgress(progress) 1.66 + , mProgressMax(progressMax) 1.67 + {} 1.68 + 1.69 + ~nsTransportStatusEvent() {} 1.70 + 1.71 + NS_IMETHOD Run() 1.72 + { 1.73 + // since this event is being handled, we need to clear the proxy's ref. 1.74 + // if not coalescing all, then last event may not equal self! 1.75 + { 1.76 + MutexAutoLock lock(mProxy->mLock); 1.77 + if (mProxy->mLastEvent == this) 1.78 + mProxy->mLastEvent = nullptr; 1.79 + } 1.80 + 1.81 + mProxy->mSink->OnTransportStatus(mTransport, mStatus, mProgress, 1.82 + mProgressMax); 1.83 + return NS_OK; 1.84 + } 1.85 + 1.86 + nsRefPtr<nsTransportEventSinkProxy> mProxy; 1.87 + 1.88 + // parameters to OnTransportStatus 1.89 + nsCOMPtr<nsITransport> mTransport; 1.90 + nsresult mStatus; 1.91 + uint64_t mProgress; 1.92 + uint64_t mProgressMax; 1.93 +}; 1.94 + 1.95 +NS_IMPL_ISUPPORTS(nsTransportEventSinkProxy, nsITransportEventSink) 1.96 + 1.97 +NS_IMETHODIMP 1.98 +nsTransportEventSinkProxy::OnTransportStatus(nsITransport *transport, 1.99 + nsresult status, 1.100 + uint64_t progress, 1.101 + uint64_t progressMax) 1.102 +{ 1.103 + nsresult rv = NS_OK; 1.104 + nsRefPtr<nsTransportStatusEvent> event; 1.105 + { 1.106 + MutexAutoLock lock(mLock); 1.107 + 1.108 + // try to coalesce events! ;-) 1.109 + if (mLastEvent && (mCoalesceAll || mLastEvent->mStatus == status)) { 1.110 + mLastEvent->mStatus = status; 1.111 + mLastEvent->mProgress = progress; 1.112 + mLastEvent->mProgressMax = progressMax; 1.113 + } 1.114 + else { 1.115 + event = new nsTransportStatusEvent(this, transport, status, 1.116 + progress, progressMax); 1.117 + if (!event) 1.118 + rv = NS_ERROR_OUT_OF_MEMORY; 1.119 + mLastEvent = event; // weak ref 1.120 + } 1.121 + } 1.122 + if (event) { 1.123 + rv = mTarget->Dispatch(event, NS_DISPATCH_NORMAL); 1.124 + if (NS_FAILED(rv)) { 1.125 + NS_WARNING("unable to post transport status event"); 1.126 + 1.127 + MutexAutoLock lock(mLock); // cleanup.. don't reference anymore! 1.128 + mLastEvent = nullptr; 1.129 + } 1.130 + } 1.131 + return rv; 1.132 +} 1.133 + 1.134 +//----------------------------------------------------------------------------- 1.135 + 1.136 +nsresult 1.137 +net_NewTransportEventSinkProxy(nsITransportEventSink **result, 1.138 + nsITransportEventSink *sink, 1.139 + nsIEventTarget *target, 1.140 + bool coalesceAll) 1.141 +{ 1.142 + *result = new nsTransportEventSinkProxy(sink, target, coalesceAll); 1.143 + if (!*result) 1.144 + return NS_ERROR_OUT_OF_MEMORY; 1.145 + NS_ADDREF(*result); 1.146 + return NS_OK; 1.147 +}