Bug 1878930 - s/RawBuffer/Span/: TexImage: GetRangeFromData. r=gfx-reviewers,lsalzman
[gecko.git] / netwerk / base / nsStreamListenerTee.cpp
blob4de5db56f57292bb069a7d2dd1accb4a52b4113d
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"
9 namespace mozilla {
10 namespace net {
12 NS_IMPL_ISUPPORTS(nsStreamListenerTee, nsIStreamListener, nsIRequestObserver,
13 nsIStreamListenerTee, nsIThreadRetargetableStreamListener,
14 nsIMultiPartChannelListener)
16 NS_IMETHODIMP
17 nsStreamListenerTee::OnStartRequest(nsIRequest* request) {
18 NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED);
20 nsCOMPtr<nsIMultiPartChannel> multiPartChannel = do_QueryInterface(request);
21 if (multiPartChannel) {
22 mIsMultiPart = true;
25 nsresult rv1 = mListener->OnStartRequest(request);
26 nsresult rv2 = NS_OK;
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;
33 NS_IMETHODIMP
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
37 if (mInputTee) {
38 mInputTee->SetSink(nullptr);
39 mInputTee = nullptr;
42 if (!mIsMultiPart) {
43 // release sink on the same thread where the data was written (bug 716293)
44 if (mEventTarget) {
45 NS_ProxyRelease("nsStreamListenerTee::mSink", mEventTarget,
46 mSink.forget());
47 } else {
48 mSink = nullptr;
52 nsresult rv = mListener->OnStopRequest(request, status);
53 if (!mIsMultiPart) {
54 mListener = nullptr;
56 if (mObserver) {
57 mObserver->OnStopRequest(request, status);
58 if (!mIsMultiPart) {
59 mObserver = nullptr;
62 return rv;
65 NS_IMETHODIMP
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;
72 nsresult rv;
74 if (!mInputTee) {
75 if (mEventTarget) {
76 rv = NS_NewInputStreamTeeAsync(getter_AddRefs(tee), input, mSink,
77 mEventTarget);
78 } else {
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;
85 } else {
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;
90 tee = mInputTee;
93 return mListener->OnDataAvailable(request, tee, offset, count);
96 NS_IMETHODIMP
97 nsStreamListenerTee::OnAfterLastPart(nsresult aStatus) {
98 // release sink on the same thread where the data was written (bug 716293)
99 if (mEventTarget) {
100 NS_ProxyRelease("nsStreamListenerTee::mSink", mEventTarget, mSink.forget());
101 } else {
102 mSink = nullptr;
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);
116 mObserver = nullptr;
117 return NS_OK;
120 NS_IMETHODIMP
121 nsStreamListenerTee::CheckListenerChain() {
122 NS_ASSERTION(NS_IsMainThread(), "Should be on main thread!");
123 nsresult rv = NS_OK;
124 nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
125 do_QueryInterface(mListener, &rv);
126 if (retargetableListener) {
127 rv = retargetableListener->CheckListenerChain();
129 if (NS_FAILED(rv)) {
130 return rv;
132 if (!mObserver) {
133 return rv;
135 retargetableListener = do_QueryInterface(mObserver, &rv);
136 if (retargetableListener) {
137 rv = retargetableListener->CheckListenerChain();
139 return rv;
142 NS_IMETHODIMP
143 nsStreamListenerTee::OnDataFinished(nsresult aStatus) {
144 nsresult rv = NS_OK;
145 nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
146 do_QueryInterface(mListener, &rv);
147 if (retargetableListener) {
148 rv = retargetableListener->OnDataFinished(aStatus);
150 if (NS_FAILED(rv)) {
151 return rv;
153 if (!mObserver) {
154 return rv;
156 retargetableListener = do_QueryInterface(mObserver, &rv);
157 if (retargetableListener) {
158 rv = retargetableListener->OnDataFinished(aStatus);
160 return rv;
163 NS_IMETHODIMP
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;
169 mSink = sink;
170 mObserver = requestObserver;
171 return NS_OK;
174 NS_IMETHODIMP
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);
184 } // namespace net
185 } // namespace mozilla