|
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 "nsIOService.h" |
|
6 #include "nsSyncStreamListener.h" |
|
7 #include "nsIPipe.h" |
|
8 #include "nsThreadUtils.h" |
|
9 #include <algorithm> |
|
10 |
|
11 nsresult |
|
12 nsSyncStreamListener::Init() |
|
13 { |
|
14 return NS_NewPipe(getter_AddRefs(mPipeIn), |
|
15 getter_AddRefs(mPipeOut), |
|
16 nsIOService::gDefaultSegmentSize, |
|
17 UINT32_MAX, // no size limit |
|
18 false, |
|
19 false); |
|
20 } |
|
21 |
|
22 nsresult |
|
23 nsSyncStreamListener::WaitForData() |
|
24 { |
|
25 mKeepWaiting = true; |
|
26 |
|
27 while (mKeepWaiting) |
|
28 NS_ENSURE_STATE(NS_ProcessNextEvent(NS_GetCurrentThread())); |
|
29 |
|
30 return NS_OK; |
|
31 } |
|
32 |
|
33 //----------------------------------------------------------------------------- |
|
34 // nsSyncStreamListener::nsISupports |
|
35 //----------------------------------------------------------------------------- |
|
36 |
|
37 NS_IMPL_ISUPPORTS(nsSyncStreamListener, |
|
38 nsIStreamListener, |
|
39 nsIRequestObserver, |
|
40 nsIInputStream, |
|
41 nsISyncStreamListener) |
|
42 |
|
43 //----------------------------------------------------------------------------- |
|
44 // nsSyncStreamListener::nsISyncStreamListener |
|
45 //----------------------------------------------------------------------------- |
|
46 |
|
47 NS_IMETHODIMP |
|
48 nsSyncStreamListener::GetInputStream(nsIInputStream **result) |
|
49 { |
|
50 NS_ADDREF(*result = this); |
|
51 return NS_OK; |
|
52 } |
|
53 |
|
54 //----------------------------------------------------------------------------- |
|
55 // nsSyncStreamListener::nsIStreamListener |
|
56 //----------------------------------------------------------------------------- |
|
57 |
|
58 NS_IMETHODIMP |
|
59 nsSyncStreamListener::OnStartRequest(nsIRequest *request, |
|
60 nsISupports *context) |
|
61 { |
|
62 return NS_OK; |
|
63 } |
|
64 |
|
65 NS_IMETHODIMP |
|
66 nsSyncStreamListener::OnDataAvailable(nsIRequest *request, |
|
67 nsISupports *context, |
|
68 nsIInputStream *stream, |
|
69 uint64_t offset, |
|
70 uint32_t count) |
|
71 { |
|
72 uint32_t bytesWritten; |
|
73 |
|
74 nsresult rv = mPipeOut->WriteFrom(stream, count, &bytesWritten); |
|
75 |
|
76 // if we get an error, then return failure. this will cause the |
|
77 // channel to be canceled, and as a result our OnStopRequest method |
|
78 // will be called immediately. because of this we do not need to |
|
79 // set mStatus or mKeepWaiting here. |
|
80 if (NS_FAILED(rv)) |
|
81 return rv; |
|
82 |
|
83 // we expect that all data will be written to the pipe because |
|
84 // the pipe was created to have "infinite" room. |
|
85 NS_ASSERTION(bytesWritten == count, "did not write all data"); |
|
86 |
|
87 mKeepWaiting = false; // unblock Read |
|
88 return NS_OK; |
|
89 } |
|
90 |
|
91 NS_IMETHODIMP |
|
92 nsSyncStreamListener::OnStopRequest(nsIRequest *request, |
|
93 nsISupports *context, |
|
94 nsresult status) |
|
95 { |
|
96 mStatus = status; |
|
97 mKeepWaiting = false; // unblock Read |
|
98 mDone = true; |
|
99 return NS_OK; |
|
100 } |
|
101 |
|
102 //----------------------------------------------------------------------------- |
|
103 // nsSyncStreamListener::nsIInputStream |
|
104 //----------------------------------------------------------------------------- |
|
105 |
|
106 NS_IMETHODIMP |
|
107 nsSyncStreamListener::Close() |
|
108 { |
|
109 mStatus = NS_BASE_STREAM_CLOSED; |
|
110 mDone = true; |
|
111 |
|
112 // It'd be nice if we could explicitly cancel the request at this point, |
|
113 // but we don't have a reference to it, so the best we can do is close the |
|
114 // pipe so that the next OnDataAvailable event will fail. |
|
115 if (mPipeIn) { |
|
116 mPipeIn->Close(); |
|
117 mPipeIn = nullptr; |
|
118 } |
|
119 return NS_OK; |
|
120 } |
|
121 |
|
122 NS_IMETHODIMP |
|
123 nsSyncStreamListener::Available(uint64_t *result) |
|
124 { |
|
125 if (NS_FAILED(mStatus)) |
|
126 return mStatus; |
|
127 |
|
128 mStatus = mPipeIn->Available(result); |
|
129 if (NS_SUCCEEDED(mStatus) && (*result == 0) && !mDone) { |
|
130 mStatus = WaitForData(); |
|
131 if (NS_SUCCEEDED(mStatus)) |
|
132 mStatus = mPipeIn->Available(result); |
|
133 } |
|
134 return mStatus; |
|
135 } |
|
136 |
|
137 NS_IMETHODIMP |
|
138 nsSyncStreamListener::Read(char *buf, |
|
139 uint32_t bufLen, |
|
140 uint32_t *result) |
|
141 { |
|
142 if (mStatus == NS_BASE_STREAM_CLOSED) { |
|
143 *result = 0; |
|
144 return NS_OK; |
|
145 } |
|
146 |
|
147 uint64_t avail64; |
|
148 if (NS_FAILED(Available(&avail64))) |
|
149 return mStatus; |
|
150 |
|
151 uint32_t avail = (uint32_t)std::min(avail64, (uint64_t)bufLen); |
|
152 mStatus = mPipeIn->Read(buf, avail, result); |
|
153 return mStatus; |
|
154 } |
|
155 |
|
156 NS_IMETHODIMP |
|
157 nsSyncStreamListener::ReadSegments(nsWriteSegmentFun writer, |
|
158 void *closure, |
|
159 uint32_t count, |
|
160 uint32_t *result) |
|
161 { |
|
162 if (mStatus == NS_BASE_STREAM_CLOSED) { |
|
163 *result = 0; |
|
164 return NS_OK; |
|
165 } |
|
166 |
|
167 uint64_t avail64; |
|
168 if (NS_FAILED(Available(&avail64))) |
|
169 return mStatus; |
|
170 |
|
171 uint32_t avail = (uint32_t)std::min(avail64, (uint64_t)count); |
|
172 mStatus = mPipeIn->ReadSegments(writer, closure, avail, result); |
|
173 return mStatus; |
|
174 } |
|
175 |
|
176 NS_IMETHODIMP |
|
177 nsSyncStreamListener::IsNonBlocking(bool *result) |
|
178 { |
|
179 *result = false; |
|
180 return NS_OK; |
|
181 } |