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