|
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/. */ |
|
4 |
|
5 #include "nsStreamListenerTee.h" |
|
6 #include "nsProxyRelease.h" |
|
7 |
|
8 NS_IMPL_ISUPPORTS(nsStreamListenerTee, |
|
9 nsIStreamListener, |
|
10 nsIRequestObserver, |
|
11 nsIStreamListenerTee, |
|
12 nsIThreadRetargetableStreamListener) |
|
13 |
|
14 NS_IMETHODIMP |
|
15 nsStreamListenerTee::OnStartRequest(nsIRequest *request, |
|
16 nsISupports *context) |
|
17 { |
|
18 NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED); |
|
19 nsresult rv1 = mListener->OnStartRequest(request, context); |
|
20 nsresult rv2 = NS_OK; |
|
21 if (mObserver) |
|
22 rv2 = mObserver->OnStartRequest(request, context); |
|
23 |
|
24 // Preserve NS_SUCCESS_XXX in rv1 in case mObserver didn't throw |
|
25 return (NS_FAILED(rv2) && NS_SUCCEEDED(rv1)) ? rv2 : rv1; |
|
26 } |
|
27 |
|
28 NS_IMETHODIMP |
|
29 nsStreamListenerTee::OnStopRequest(nsIRequest *request, |
|
30 nsISupports *context, |
|
31 nsresult status) |
|
32 { |
|
33 NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED); |
|
34 // it is critical that we close out the input stream tee |
|
35 if (mInputTee) { |
|
36 mInputTee->SetSink(nullptr); |
|
37 mInputTee = 0; |
|
38 } |
|
39 |
|
40 // release sink on the same thread where the data was written (bug 716293) |
|
41 if (mEventTarget) { |
|
42 nsIOutputStream *sink = nullptr; |
|
43 mSink.swap(sink); |
|
44 if (NS_FAILED(NS_ProxyRelease(mEventTarget, sink))) { |
|
45 NS_WARNING("Releasing sink on the current thread!"); |
|
46 NS_RELEASE(sink); |
|
47 } |
|
48 } |
|
49 else { |
|
50 mSink = 0; |
|
51 } |
|
52 |
|
53 nsresult rv = mListener->OnStopRequest(request, context, status); |
|
54 if (mObserver) |
|
55 mObserver->OnStopRequest(request, context, status); |
|
56 mObserver = 0; |
|
57 return rv; |
|
58 } |
|
59 |
|
60 NS_IMETHODIMP |
|
61 nsStreamListenerTee::OnDataAvailable(nsIRequest *request, |
|
62 nsISupports *context, |
|
63 nsIInputStream *input, |
|
64 uint64_t offset, |
|
65 uint32_t count) |
|
66 { |
|
67 NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED); |
|
68 NS_ENSURE_TRUE(mSink, NS_ERROR_NOT_INITIALIZED); |
|
69 |
|
70 nsCOMPtr<nsIInputStream> tee; |
|
71 nsresult rv; |
|
72 |
|
73 if (!mInputTee) { |
|
74 if (mEventTarget) |
|
75 rv = NS_NewInputStreamTeeAsync(getter_AddRefs(tee), input, |
|
76 mSink, mEventTarget); |
|
77 else |
|
78 rv = NS_NewInputStreamTee(getter_AddRefs(tee), input, mSink); |
|
79 if (NS_FAILED(rv)) return rv; |
|
80 |
|
81 mInputTee = do_QueryInterface(tee, &rv); |
|
82 if (NS_FAILED(rv)) return rv; |
|
83 } |
|
84 else { |
|
85 // re-initialize the input tee since the input stream may have changed. |
|
86 rv = mInputTee->SetSource(input); |
|
87 if (NS_FAILED(rv)) return rv; |
|
88 |
|
89 tee = do_QueryInterface(mInputTee, &rv); |
|
90 if (NS_FAILED(rv)) return rv; |
|
91 } |
|
92 |
|
93 return mListener->OnDataAvailable(request, context, tee, offset, count); |
|
94 } |
|
95 |
|
96 NS_IMETHODIMP |
|
97 nsStreamListenerTee::CheckListenerChain() |
|
98 { |
|
99 NS_ASSERTION(NS_IsMainThread(), "Should be on main thread!"); |
|
100 nsresult rv = NS_OK; |
|
101 nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener = |
|
102 do_QueryInterface(mListener, &rv); |
|
103 if (retargetableListener) { |
|
104 rv = retargetableListener->CheckListenerChain(); |
|
105 } |
|
106 if (NS_FAILED(rv)) { |
|
107 return rv; |
|
108 } |
|
109 if (!mObserver) { |
|
110 return rv; |
|
111 } |
|
112 retargetableListener = do_QueryInterface(mObserver, &rv); |
|
113 if (retargetableListener) { |
|
114 rv = retargetableListener->CheckListenerChain(); |
|
115 } |
|
116 return rv; |
|
117 } |
|
118 |
|
119 NS_IMETHODIMP |
|
120 nsStreamListenerTee::Init(nsIStreamListener *listener, |
|
121 nsIOutputStream *sink, |
|
122 nsIRequestObserver *requestObserver) |
|
123 { |
|
124 NS_ENSURE_ARG_POINTER(listener); |
|
125 NS_ENSURE_ARG_POINTER(sink); |
|
126 mListener = listener; |
|
127 mSink = sink; |
|
128 mObserver = requestObserver; |
|
129 return NS_OK; |
|
130 } |
|
131 |
|
132 NS_IMETHODIMP |
|
133 nsStreamListenerTee::InitAsync(nsIStreamListener *listener, |
|
134 nsIEventTarget *eventTarget, |
|
135 nsIOutputStream *sink, |
|
136 nsIRequestObserver *requestObserver) |
|
137 { |
|
138 NS_ENSURE_ARG_POINTER(eventTarget); |
|
139 mEventTarget = eventTarget; |
|
140 return Init(listener, sink, requestObserver); |
|
141 } |