gecko/netwerk/base/nsStreamListenerTee.cpp

142 lines
4.4 KiB
C++

/* 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 "nsStreamListenerTee.h"
#include "nsProxyRelease.h"
NS_IMPL_ISUPPORTS(nsStreamListenerTee,
nsIStreamListener,
nsIRequestObserver,
nsIStreamListenerTee,
nsIThreadRetargetableStreamListener)
NS_IMETHODIMP
nsStreamListenerTee::OnStartRequest(nsIRequest *request,
nsISupports *context)
{
NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED);
nsresult rv1 = mListener->OnStartRequest(request, context);
nsresult rv2 = NS_OK;
if (mObserver)
rv2 = mObserver->OnStartRequest(request, context);
// Preserve NS_SUCCESS_XXX in rv1 in case mObserver didn't throw
return (NS_FAILED(rv2) && NS_SUCCEEDED(rv1)) ? rv2 : rv1;
}
NS_IMETHODIMP
nsStreamListenerTee::OnStopRequest(nsIRequest *request,
nsISupports *context,
nsresult status)
{
NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED);
// it is critical that we close out the input stream tee
if (mInputTee) {
mInputTee->SetSink(nullptr);
mInputTee = 0;
}
// release sink on the same thread where the data was written (bug 716293)
if (mEventTarget) {
nsIOutputStream *sink = nullptr;
mSink.swap(sink);
if (NS_FAILED(NS_ProxyRelease(mEventTarget, sink))) {
NS_WARNING("Releasing sink on the current thread!");
NS_RELEASE(sink);
}
}
else {
mSink = 0;
}
nsresult rv = mListener->OnStopRequest(request, context, status);
if (mObserver)
mObserver->OnStopRequest(request, context, status);
mObserver = 0;
return rv;
}
NS_IMETHODIMP
nsStreamListenerTee::OnDataAvailable(nsIRequest *request,
nsISupports *context,
nsIInputStream *input,
uint64_t offset,
uint32_t count)
{
NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_TRUE(mSink, NS_ERROR_NOT_INITIALIZED);
nsCOMPtr<nsIInputStream> tee;
nsresult rv;
if (!mInputTee) {
if (mEventTarget)
rv = NS_NewInputStreamTeeAsync(getter_AddRefs(tee), input,
mSink, mEventTarget);
else
rv = NS_NewInputStreamTee(getter_AddRefs(tee), input, mSink);
if (NS_FAILED(rv)) return rv;
mInputTee = do_QueryInterface(tee, &rv);
if (NS_FAILED(rv)) return rv;
}
else {
// re-initialize the input tee since the input stream may have changed.
rv = mInputTee->SetSource(input);
if (NS_FAILED(rv)) return rv;
tee = do_QueryInterface(mInputTee, &rv);
if (NS_FAILED(rv)) return rv;
}
return mListener->OnDataAvailable(request, context, tee, offset, count);
}
NS_IMETHODIMP
nsStreamListenerTee::CheckListenerChain()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread!");
nsresult rv = NS_OK;
nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
do_QueryInterface(mListener, &rv);
if (retargetableListener) {
rv = retargetableListener->CheckListenerChain();
}
if (NS_FAILED(rv)) {
return rv;
}
if (!mObserver) {
return rv;
}
retargetableListener = do_QueryInterface(mObserver, &rv);
if (retargetableListener) {
rv = retargetableListener->CheckListenerChain();
}
return rv;
}
NS_IMETHODIMP
nsStreamListenerTee::Init(nsIStreamListener *listener,
nsIOutputStream *sink,
nsIRequestObserver *requestObserver)
{
NS_ENSURE_ARG_POINTER(listener);
NS_ENSURE_ARG_POINTER(sink);
mListener = listener;
mSink = sink;
mObserver = requestObserver;
return NS_OK;
}
NS_IMETHODIMP
nsStreamListenerTee::InitAsync(nsIStreamListener *listener,
nsIEventTarget *eventTarget,
nsIOutputStream *sink,
nsIRequestObserver *requestObserver)
{
NS_ENSURE_ARG_POINTER(eventTarget);
mEventTarget = eventTarget;
return Init(listener, sink, requestObserver);
}