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"
7 #include "nsIRequest.h"
12 NS_IMPL_ISUPPORTS(nsStreamListenerTee
, nsIStreamListener
, nsIRequestObserver
,
13 nsIStreamListenerTee
, nsIThreadRetargetableStreamListener
,
14 nsIMultiPartChannelListener
)
17 nsStreamListenerTee::OnStartRequest(nsIRequest
* request
) {
18 NS_ENSURE_TRUE(mListener
, NS_ERROR_NOT_INITIALIZED
);
20 nsCOMPtr
<nsIMultiPartChannel
> multiPartChannel
= do_QueryInterface(request
);
21 if (multiPartChannel
) {
25 nsresult rv1
= mListener
->OnStartRequest(request
);
27 if (mObserver
) rv2
= mObserver
->OnStartRequest(request
);
29 // Preserve NS_SUCCESS_XXX in rv1 in case mObserver didn't throw
30 return (NS_FAILED(rv2
) && NS_SUCCEEDED(rv1
)) ? rv2
: rv1
;
34 nsStreamListenerTee::OnStopRequest(nsIRequest
* request
, nsresult status
) {
35 NS_ENSURE_TRUE(mListener
, NS_ERROR_NOT_INITIALIZED
);
36 // it is critical that we close out the input stream tee
38 mInputTee
->SetSink(nullptr);
43 // release sink on the same thread where the data was written (bug 716293)
45 NS_ProxyRelease("nsStreamListenerTee::mSink", mEventTarget
,
52 nsresult rv
= mListener
->OnStopRequest(request
, status
);
57 mObserver
->OnStopRequest(request
, status
);
66 nsStreamListenerTee::OnDataAvailable(nsIRequest
* request
, nsIInputStream
* input
,
67 uint64_t offset
, uint32_t count
) {
68 NS_ENSURE_TRUE(mListener
, NS_ERROR_NOT_INITIALIZED
);
69 NS_ENSURE_TRUE(mSink
, NS_ERROR_NOT_INITIALIZED
);
71 nsCOMPtr
<nsIInputStream
> tee
;
76 rv
= NS_NewInputStreamTeeAsync(getter_AddRefs(tee
), input
, mSink
,
79 rv
= NS_NewInputStreamTee(getter_AddRefs(tee
), input
, mSink
);
81 if (NS_FAILED(rv
)) return rv
;
83 mInputTee
= do_QueryInterface(tee
, &rv
);
84 if (NS_FAILED(rv
)) return rv
;
86 // re-initialize the input tee since the input stream may have changed.
87 rv
= mInputTee
->SetSource(input
);
88 if (NS_FAILED(rv
)) return rv
;
93 return mListener
->OnDataAvailable(request
, tee
, offset
, count
);
97 nsStreamListenerTee::OnAfterLastPart(nsresult aStatus
) {
98 // release sink on the same thread where the data was written (bug 716293)
100 NS_ProxyRelease("nsStreamListenerTee::mSink", mEventTarget
, mSink
.forget());
105 if (nsCOMPtr
<nsIMultiPartChannelListener
> multi
=
106 do_QueryInterface(mListener
)) {
107 multi
->OnAfterLastPart(aStatus
);
109 if (!SameCOMIdentity(mListener
, mObserver
)) {
110 if (nsCOMPtr
<nsIMultiPartChannelListener
> multi
=
111 do_QueryInterface(mObserver
)) {
112 multi
->OnAfterLastPart(aStatus
);
121 nsStreamListenerTee::CheckListenerChain() {
122 NS_ASSERTION(NS_IsMainThread(), "Should be on main thread!");
124 nsCOMPtr
<nsIThreadRetargetableStreamListener
> retargetableListener
=
125 do_QueryInterface(mListener
, &rv
);
126 if (retargetableListener
) {
127 rv
= retargetableListener
->CheckListenerChain();
135 retargetableListener
= do_QueryInterface(mObserver
, &rv
);
136 if (retargetableListener
) {
137 rv
= retargetableListener
->CheckListenerChain();
143 nsStreamListenerTee::OnDataFinished(nsresult aStatus
) {
145 nsCOMPtr
<nsIThreadRetargetableStreamListener
> retargetableListener
=
146 do_QueryInterface(mListener
, &rv
);
147 if (retargetableListener
) {
148 rv
= retargetableListener
->OnDataFinished(aStatus
);
156 retargetableListener
= do_QueryInterface(mObserver
, &rv
);
157 if (retargetableListener
) {
158 rv
= retargetableListener
->OnDataFinished(aStatus
);
164 nsStreamListenerTee::Init(nsIStreamListener
* listener
, nsIOutputStream
* sink
,
165 nsIRequestObserver
* requestObserver
) {
166 NS_ENSURE_ARG_POINTER(listener
);
167 NS_ENSURE_ARG_POINTER(sink
);
168 mListener
= listener
;
170 mObserver
= requestObserver
;
175 nsStreamListenerTee::InitAsync(nsIStreamListener
* listener
,
176 nsIEventTarget
* eventTarget
,
177 nsIOutputStream
* sink
,
178 nsIRequestObserver
* requestObserver
) {
179 NS_ENSURE_ARG_POINTER(eventTarget
);
180 mEventTarget
= eventTarget
;
181 return Init(listener
, sink
, requestObserver
);
185 } // namespace mozilla