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 }