1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
/* 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 "nsCOMPtr.h"
#include "nsITransport.h"
#include "nsProxyRelease.h"
#include "nsSocketTransportService2.h"
#include "nsThreadUtils.h"
#include "nsTransportUtils.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") {}
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("nsTransportEventSinkProxy::mSink", mTarget,
mSink.forget());
}
public:
nsCOMPtr<nsITransportEventSink> mSink;
nsCOMPtr<nsIEventTarget> mTarget;
Mutex mLock MOZ_UNANNOTATED;
RefPtr<nsTransportStatusEvent> mLastEvent;
};
class nsTransportStatusEvent : public Runnable {
public:
nsTransportStatusEvent(nsTransportEventSinkProxy* proxy,
nsITransport* transport, nsresult status,
int64_t progress, int64_t progressMax)
: Runnable("nsTransportStatusEvent"),
mProxy(proxy),
mTransport(transport),
mStatus(status),
mProgress(progress),
mProgressMax(progressMax) {}
~nsTransportStatusEvent() {
auto ReleaseTransport = [transport(std::move(mTransport))]() mutable {};
if (!net::OnSocketThread()) {
net::gSocketTransportService->Dispatch(NS_NewRunnableFunction(
"nsHttpConnection::~nsHttpConnection", std::move(ReleaseTransport)));
}
}
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);
mProxy = nullptr;
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) {
RefPtr<nsTransportEventSinkProxy> res =
new nsTransportEventSinkProxy(sink, target);
res.forget(result);
return NS_OK;
}
|