Source code

Revision control

Other Tools

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