1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is Mozilla.
15 : *
16 : * The Initial Developer of the Original Code is IBM Corporation.
17 : * Portions created by IBM Corporation are Copyright (C) 2003
18 : * IBM Corporation. All Rights Reserved.
19 : *
20 : * Contributor(s):
21 : * IBM Corp.
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either the GNU General Public License Version 2 or later (the "GPL"), or
25 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include "nsIOService.h"
38 : #include "nsSyncStreamListener.h"
39 : #include "nsIPipe.h"
40 :
41 : nsresult
42 18 : nsSyncStreamListener::Init()
43 : {
44 18 : return NS_NewPipe(getter_AddRefs(mPipeIn),
45 18 : getter_AddRefs(mPipeOut),
46 : nsIOService::gDefaultSegmentSize,
47 : PR_UINT32_MAX, // no size limit
48 : false,
49 18 : false);
50 : }
51 :
52 : nsresult
53 20 : nsSyncStreamListener::WaitForData()
54 : {
55 20 : mKeepWaiting = true;
56 :
57 98 : while (mKeepWaiting)
58 58 : NS_ENSURE_STATE(NS_ProcessNextEvent(NS_GetCurrentThread()));
59 :
60 20 : return NS_OK;
61 : }
62 :
63 : //-----------------------------------------------------------------------------
64 : // nsSyncStreamListener::nsISupports
65 : //-----------------------------------------------------------------------------
66 :
67 823 : NS_IMPL_ISUPPORTS4(nsSyncStreamListener,
68 : nsIStreamListener,
69 : nsIRequestObserver,
70 : nsIInputStream,
71 : nsISyncStreamListener)
72 :
73 : //-----------------------------------------------------------------------------
74 : // nsSyncStreamListener::nsISyncStreamListener
75 : //-----------------------------------------------------------------------------
76 :
77 : NS_IMETHODIMP
78 18 : nsSyncStreamListener::GetInputStream(nsIInputStream **result)
79 : {
80 18 : NS_ADDREF(*result = this);
81 18 : return NS_OK;
82 : }
83 :
84 : //-----------------------------------------------------------------------------
85 : // nsSyncStreamListener::nsIStreamListener
86 : //-----------------------------------------------------------------------------
87 :
88 : NS_IMETHODIMP
89 18 : nsSyncStreamListener::OnStartRequest(nsIRequest *request,
90 : nsISupports *context)
91 : {
92 18 : return NS_OK;
93 : }
94 :
95 : NS_IMETHODIMP
96 18 : nsSyncStreamListener::OnDataAvailable(nsIRequest *request,
97 : nsISupports *context,
98 : nsIInputStream *stream,
99 : PRUint32 offset,
100 : PRUint32 count)
101 : {
102 : PRUint32 bytesWritten;
103 :
104 18 : nsresult rv = mPipeOut->WriteFrom(stream, count, &bytesWritten);
105 :
106 : // if we get an error, then return failure. this will cause the
107 : // channel to be canceled, and as a result our OnStopRequest method
108 : // will be called immediately. because of this we do not need to
109 : // set mStatus or mKeepWaiting here.
110 18 : if (NS_FAILED(rv))
111 0 : return rv;
112 :
113 : // we expect that all data will be written to the pipe because
114 : // the pipe was created to have "infinite" room.
115 18 : NS_ASSERTION(bytesWritten == count, "did not write all data");
116 :
117 18 : mKeepWaiting = false; // unblock Read
118 18 : return NS_OK;
119 : }
120 :
121 : NS_IMETHODIMP
122 18 : nsSyncStreamListener::OnStopRequest(nsIRequest *request,
123 : nsISupports *context,
124 : nsresult status)
125 : {
126 18 : mStatus = status;
127 18 : mKeepWaiting = false; // unblock Read
128 18 : mDone = true;
129 18 : return NS_OK;
130 : }
131 :
132 : //-----------------------------------------------------------------------------
133 : // nsSyncStreamListener::nsIInputStream
134 : //-----------------------------------------------------------------------------
135 :
136 : NS_IMETHODIMP
137 0 : nsSyncStreamListener::Close()
138 : {
139 0 : mStatus = NS_BASE_STREAM_CLOSED;
140 0 : mDone = true;
141 :
142 : // It'd be nice if we could explicitly cancel the request at this point,
143 : // but we don't have a reference to it, so the best we can do is close the
144 : // pipe so that the next OnDataAvailable event will fail.
145 0 : if (mPipeIn) {
146 0 : mPipeIn->Close();
147 0 : mPipeIn = nsnull;
148 : }
149 0 : return NS_OK;
150 : }
151 :
152 : NS_IMETHODIMP
153 86 : nsSyncStreamListener::Available(PRUint32 *result)
154 : {
155 86 : if (NS_FAILED(mStatus))
156 0 : return mStatus;
157 :
158 86 : mStatus = mPipeIn->Available(result);
159 86 : if (NS_SUCCEEDED(mStatus) && (*result == 0) && !mDone) {
160 20 : mStatus = WaitForData();
161 20 : if (NS_SUCCEEDED(mStatus))
162 20 : mStatus = mPipeIn->Available(result);
163 : }
164 86 : return mStatus;
165 : }
166 :
167 : NS_IMETHODIMP
168 17 : nsSyncStreamListener::Read(char *buf,
169 : PRUint32 bufLen,
170 : PRUint32 *result)
171 : {
172 17 : if (mStatus == NS_BASE_STREAM_CLOSED) {
173 0 : *result = 0;
174 0 : return NS_OK;
175 : }
176 :
177 : PRUint32 avail;
178 17 : if (NS_FAILED(Available(&avail)))
179 0 : return mStatus;
180 :
181 17 : avail = NS_MIN(avail, bufLen);
182 17 : mStatus = mPipeIn->Read(buf, avail, result);
183 17 : return mStatus;
184 : }
185 :
186 : NS_IMETHODIMP
187 0 : nsSyncStreamListener::ReadSegments(nsWriteSegmentFun writer,
188 : void *closure,
189 : PRUint32 count,
190 : PRUint32 *result)
191 : {
192 0 : if (mStatus == NS_BASE_STREAM_CLOSED) {
193 0 : *result = 0;
194 0 : return NS_OK;
195 : }
196 :
197 : PRUint32 avail;
198 0 : if (NS_FAILED(Available(&avail)))
199 0 : return mStatus;
200 :
201 0 : avail = NS_MIN(avail, count);
202 0 : mStatus = mPipeIn->ReadSegments(writer, closure, avail, result);
203 0 : return mStatus;
204 : }
205 :
206 : NS_IMETHODIMP
207 0 : nsSyncStreamListener::IsNonBlocking(bool *result)
208 : {
209 0 : *result = false;
210 0 : return NS_OK;
211 : }
|