Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 "nsIOService.h"
6 #include "nsSyncStreamListener.h"
7 #include "nsIPipe.h"
8 #include "nsThreadUtils.h"
9 #include <algorithm>
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 }
22 nsresult
23 nsSyncStreamListener::WaitForData()
24 {
25 mKeepWaiting = true;
27 while (mKeepWaiting)
28 NS_ENSURE_STATE(NS_ProcessNextEvent(NS_GetCurrentThread()));
30 return NS_OK;
31 }
33 //-----------------------------------------------------------------------------
34 // nsSyncStreamListener::nsISupports
35 //-----------------------------------------------------------------------------
37 NS_IMPL_ISUPPORTS(nsSyncStreamListener,
38 nsIStreamListener,
39 nsIRequestObserver,
40 nsIInputStream,
41 nsISyncStreamListener)
43 //-----------------------------------------------------------------------------
44 // nsSyncStreamListener::nsISyncStreamListener
45 //-----------------------------------------------------------------------------
47 NS_IMETHODIMP
48 nsSyncStreamListener::GetInputStream(nsIInputStream **result)
49 {
50 NS_ADDREF(*result = this);
51 return NS_OK;
52 }
54 //-----------------------------------------------------------------------------
55 // nsSyncStreamListener::nsIStreamListener
56 //-----------------------------------------------------------------------------
58 NS_IMETHODIMP
59 nsSyncStreamListener::OnStartRequest(nsIRequest *request,
60 nsISupports *context)
61 {
62 return NS_OK;
63 }
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;
74 nsresult rv = mPipeOut->WriteFrom(stream, count, &bytesWritten);
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;
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");
87 mKeepWaiting = false; // unblock Read
88 return NS_OK;
89 }
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 }
102 //-----------------------------------------------------------------------------
103 // nsSyncStreamListener::nsIInputStream
104 //-----------------------------------------------------------------------------
106 NS_IMETHODIMP
107 nsSyncStreamListener::Close()
108 {
109 mStatus = NS_BASE_STREAM_CLOSED;
110 mDone = true;
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 }
122 NS_IMETHODIMP
123 nsSyncStreamListener::Available(uint64_t *result)
124 {
125 if (NS_FAILED(mStatus))
126 return mStatus;
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 }
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 }
147 uint64_t avail64;
148 if (NS_FAILED(Available(&avail64)))
149 return mStatus;
151 uint32_t avail = (uint32_t)std::min(avail64, (uint64_t)bufLen);
152 mStatus = mPipeIn->Read(buf, avail, result);
153 return mStatus;
154 }
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 }
167 uint64_t avail64;
168 if (NS_FAILED(Available(&avail64)))
169 return mStatus;
171 uint32_t avail = (uint32_t)std::min(avail64, (uint64_t)count);
172 mStatus = mPipeIn->ReadSegments(writer, closure, avail, result);
173 return mStatus;
174 }
176 NS_IMETHODIMP
177 nsSyncStreamListener::IsNonBlocking(bool *result)
178 {
179 *result = false;
180 return NS_OK;
181 }