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/. */
5 #include "nsStreamListenerTee.h"
6 #include "nsProxyRelease.h"
11 NS_IMPL_ISUPPORTS(nsStreamListenerTee
, nsIStreamListener
, nsIRequestObserver
,
12 nsIStreamListenerTee
, nsIThreadRetargetableStreamListener
,
13 nsIMultiPartChannelListener
)
16 nsStreamListenerTee::OnStartRequest(nsIRequest
* request
) {
17 NS_ENSURE_TRUE(mListener
, NS_ERROR_NOT_INITIALIZED
);
19 nsCOMPtr
<nsIMultiPartChannel
> multiPartChannel
= do_QueryInterface(request
);
20 if (multiPartChannel
) {
24 nsresult rv1
= mListener
->OnStartRequest(request
);
26 if (mObserver
) rv2
= mObserver
->OnStartRequest(request
);
28 // Preserve NS_SUCCESS_XXX in rv1 in case mObserver didn't throw
29 return (NS_FAILED(rv2
) && NS_SUCCEEDED(rv1
)) ? rv2
: rv1
;
33 nsStreamListenerTee::OnStopRequest(nsIRequest
* request
, nsresult status
) {
34 NS_ENSURE_TRUE(mListener
, NS_ERROR_NOT_INITIALIZED
);
35 // it is critical that we close out the input stream tee
37 mInputTee
->SetSink(nullptr);
42 // release sink on the same thread where the data was written (bug 716293)
44 NS_ProxyRelease("nsStreamListenerTee::mSink", mEventTarget
,
51 nsresult rv
= mListener
->OnStopRequest(request
, status
);
52 if (mObserver
) mObserver
->OnStopRequest(request
, status
);
60 nsStreamListenerTee::OnDataAvailable(nsIRequest
* request
, nsIInputStream
* input
,
61 uint64_t offset
, uint32_t count
) {
62 NS_ENSURE_TRUE(mListener
, NS_ERROR_NOT_INITIALIZED
);
63 NS_ENSURE_TRUE(mSink
, NS_ERROR_NOT_INITIALIZED
);
65 nsCOMPtr
<nsIInputStream
> tee
;
70 rv
= NS_NewInputStreamTeeAsync(getter_AddRefs(tee
), input
, mSink
,
73 rv
= NS_NewInputStreamTee(getter_AddRefs(tee
), input
, mSink
);
75 if (NS_FAILED(rv
)) return rv
;
77 mInputTee
= do_QueryInterface(tee
, &rv
);
78 if (NS_FAILED(rv
)) return rv
;
80 // re-initialize the input tee since the input stream may have changed.
81 rv
= mInputTee
->SetSource(input
);
82 if (NS_FAILED(rv
)) return rv
;
87 return mListener
->OnDataAvailable(request
, tee
, offset
, count
);
91 nsStreamListenerTee::OnAfterLastPart(nsresult aStatus
) {
92 // release sink on the same thread where the data was written (bug 716293)
94 NS_ProxyRelease("nsStreamListenerTee::mSink", mEventTarget
, mSink
.forget());
99 if (nsCOMPtr
<nsIMultiPartChannelListener
> multi
=
100 do_QueryInterface(mListener
)) {
101 multi
->OnAfterLastPart(aStatus
);
103 if (!SameCOMIdentity(mListener
, mObserver
)) {
104 if (nsCOMPtr
<nsIMultiPartChannelListener
> multi
=
105 do_QueryInterface(mObserver
)) {
106 multi
->OnAfterLastPart(aStatus
);
115 nsStreamListenerTee::CheckListenerChain() {
116 NS_ASSERTION(NS_IsMainThread(), "Should be on main thread!");
118 nsCOMPtr
<nsIThreadRetargetableStreamListener
> retargetableListener
=
119 do_QueryInterface(mListener
, &rv
);
120 if (retargetableListener
) {
121 rv
= retargetableListener
->CheckListenerChain();
129 retargetableListener
= do_QueryInterface(mObserver
, &rv
);
130 if (retargetableListener
) {
131 rv
= retargetableListener
->CheckListenerChain();
137 nsStreamListenerTee::Init(nsIStreamListener
* listener
, nsIOutputStream
* sink
,
138 nsIRequestObserver
* requestObserver
) {
139 NS_ENSURE_ARG_POINTER(listener
);
140 NS_ENSURE_ARG_POINTER(sink
);
141 mListener
= listener
;
143 mObserver
= requestObserver
;
148 nsStreamListenerTee::InitAsync(nsIStreamListener
* listener
,
149 nsIEventTarget
* eventTarget
,
150 nsIOutputStream
* sink
,
151 nsIRequestObserver
* requestObserver
) {
152 NS_ENSURE_ARG_POINTER(eventTarget
);
153 mEventTarget
= eventTarget
;
154 return Init(listener
, sink
, requestObserver
);
158 } // namespace mozilla