1 | | /* | | 1 | | /* |
2 | | * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpRequestStream.java,v 1.10 2001/07/22 20 :25: 07 pier Exp $ | | 2 | | * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpRequestStream.java,v 1.11 2002/03/18 07:15:40 remm Exp $ |
3 | | * $Revision: 1.10 $ | | 3 | | * $Revision: 1.11 $ |
4 | | * $Date: 2001/07/22 20 :25: 07 $ | | 4 | | * $Date: 2002/03/18 07:15:40 $ |
5 | | * | | 5 | | * |
6 | | * ==================================================================== | | 6 | | * ==================================================================== |
7 | | * | | 7 | | * |
8 | | * The Apache Software License, Version 1.1 | | 8 | | * The Apache Software License, Version 1.1 |
9 | | * | | 9 | | * |
10 | | * Copyright (c) 1999 The Apache Software Foundation. All rights | | 10 | | * Copyright (c) 1999 The Apache Software Foundation. All rights |
11 | | * reserved. | | 11 | | * reserved. |
12 | | * | | 12 | | * |
13 | | * Redistribution and use in source and binary forms, with or without | | 13 | | * Redistribution and use in source and binary forms, with or without |
14 | | * modification, are permitted provided that the following conditions | | 14 | | * modification, are permitted provided that the following conditions |
15 | | * are met: | | 15 | | * are met: |
16 | | * | | 16 | | * |
17 | | * 1. Redistributions of source code must retain the above copyright | | 17 | | * 1. Redistributions of source code must retain the above copyright |
18 | | * notice, this list of conditions and the following disclaimer. | | 18 | | * notice, this list of conditions and the following disclaimer. |
19 | | * | | 19 | | * |
20 | | * 2. Redistributions in binary form must reproduce the above copyright | | 20 | | * 2. Redistributions in binary form must reproduce the above copyright |
21 | | * notice, this list of conditions and the following disclaimer in | | 21 | | * notice, this list of conditions and the following disclaimer in |
22 | | * the documentation and/or other materials provided with the | | 22 | | * the documentation and/or other materials provided with the |
23 | | * distribution. | | 23 | | * distribution. |
24 | | * | | 24 | | * |
25 | | * 3. The end-user documentation included with the redistribution, if | | 25 | | * 3. The end-user documentation included with the redistribution, if |
26 | | * any, must include the following acknowlegement: | | 26 | | * any, must include the following acknowlegement: |
27 | | * "This product includes software developed by the | | 27 | | * "This product includes software developed by the |
28 | | * Apache Software Foundation (http://www.apache.org/)." | | 28 | | * Apache Software Foundation (http://www.apache.org/)." |
29 | | * Alternately, this acknowlegement may appear in the software itself, | | 29 | | * Alternately, this acknowlegement may appear in the software itself, |
30 | | * if and wherever such third-party acknowlegements normally appear. | | 30 | | * if and wherever such third-party acknowlegements normally appear. |
31 | | * | | 31 | | * |
32 | | * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software | | 32 | | * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software |
33 | | * Foundation" must not be used to endorse or promote products derived | | 33 | | * Foundation" must not be used to endorse or promote products derived |
34 | | * from this software without prior written permission. For written | | 34 | | * from this software without prior written permission. For written |
35 | | * permission, please contact apache@apache.org. | | 35 | | * permission, please contact apache@apache.org. |
36 | | * | | 36 | | * |
37 | | * 5. Products derived from this software may not be called "Apache" | | 37 | | * 5. Products derived from this software may not be called "Apache" |
38 | | * nor may "Apache" appear in their names without prior written | | 38 | | * nor may "Apache" appear in their names without prior written |
39 | | * permission of the Apache Group. | | 39 | | * permission of the Apache Group. |
40 | | * | | 40 | | * |
41 | | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | | 41 | | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
42 | | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 42 | | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
43 | | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | | 43 | | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
44 | | * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | | 44 | | * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
45 | | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | | 45 | | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
46 | | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | | 46 | | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
47 | | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | | 47 | | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
48 | | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | | 48 | | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
49 | | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 49 | | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
50 | | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | | 50 | | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
51 | | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 51 | | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
52 | | * SUCH DAMAGE. | | 52 | | * SUCH DAMAGE. |
53 | | * ==================================================================== | | 53 | | * ==================================================================== |
54 | | * | | 54 | | * |
55 | | * This software consists of voluntary contributions made by many | | 55 | | * This software consists of voluntary contributions made by many |
56 | | * individuals on behalf of the Apache Software Foundation. For more | | 56 | | * individuals on behalf of the Apache Software Foundation. For more |
57 | | * information on the Apache Software Foundation, please see | | 57 | | * information on the Apache Software Foundation, please see |
58 | | * <http://www.apache.org/>. | | 58 | | * <http://www.apache.org/>. |
59 | | * | | 59 | | * |
60 | | * [Additional notices, if required by prior licensing conditions] | | 60 | | * [Additional notices, if required by prior licensing conditions] |
61 | | * | | 61 | | * |
62 | | */ | | 62 | | */ |
63 | | | | 63 | | |
64 | | | | 64 | | |
65 | | package org.apache.catalina.connector.http; | | 65 | | package org.apache.catalina.connector.http; |
66 | | | | 66 | | |
67 | | import java.io.IOException; | | 67 | | import java.io.IOException; |
68 | | import org.apache.catalina.Request; | | 68 | | import org.apache.catalina.Request; |
69 | | import org.apache.catalina.connector.RequestStream; | | 69 | | import org.apache.catalina.connector.RequestStream; |
70 | | | | 70 | | |
71 | | /** | | 71 | | /** |
72 | | * | | 72 | | * |
73 | | * | | 73 | | * |
74 | | * @author <a href="mailto:remm@apache.org">Remy Maucherat</a> | | 74 | | * @author <a href="mailto:remm@apache.org">Remy Maucherat</a> |
| | | | 75 | | * @deprecated |
75 | | */ | | 76 | | */ |
76 | | public class HttpRequestStream extends RequestStream { | | 77 | | public class HttpRequestStream extends RequestStream { |
77 | | | | 78 | | |
78 | | | | 79 | | |
79 | | // ----------------------------------------------------------- Constructors | | 80 | | // ----------------------------------------------------------- Constructors |
80 | | | | 81 | | |
81 | | | | 82 | | |
82 | | /** | | 83 | | /** |
83 | | * Construct a servlet input stream associated with the specified Request. | | 84 | | * Construct a servlet input stream associated with the specified Request. |
84 | | * | | 85 | | * |
85 | | * @param request The associated request | | 86 | | * @param request The associated request |
86 | | * @param response The associated response | | 87 | | * @param response The associated response |
87 | | */ | | 88 | | */ |
88 | | public HttpRequestStream(HttpRequestImpl request, | | 89 | | public HttpRequestStream(HttpRequestImpl request, |
89 | | HttpResponseImpl response) { | | 90 | | HttpResponseImpl response) { |
90 | | | | 91 | | |
91 | | super(request); | | 92 | | super(request); |
92 | | String transferEncoding = request.getHeader("Transfer-Encoding"); | | 93 | | String transferEncoding = request.getHeader("Transfer-Encoding"); |
93 | | | | 94 | | |
94 | | http11 = request.getProtocol().equals("HTTP/1.1"); | | 95 | | http11 = request.getProtocol().equals("HTTP/1.1"); |
95 | | chunk = ((transferEncoding != null) | | 96 | | chunk = ((transferEncoding != null) |
96 | | && (transferEncoding.indexOf("chunked") != -1)); | | 97 | | && (transferEncoding.indexOf("chunked") != -1)); |
97 | | | | 98 | | |
98 | | if ((!chunk) && (length == -1)) { | | 99 | | if ((!chunk) && (length == -1)) { |
99 | | // Ask for connection close | | 100 | | // Ask for connection close |
100 | | response.addHeader("Connection", "close"); | | 101 | | response.addHeader("Connection", "close"); |
101 | | } | | 102 | | } |
102 | | | | 103 | | |
103 | | } | | 104 | | } |
104 | | | | 105 | | |
105 | | | | 106 | | |
106 | | // ----------------------------------------------------- Instance Variables | | 107 | | // ----------------------------------------------------- Instance Variables |
107 | | | | 108 | | |
108 | | | | 109 | | |
109 | | /** | | 110 | | /** |
110 | | * Use chunking ? | | 111 | | * Use chunking ? |
111 | | */ | | 112 | | */ |
112 | | protected boolean chunk = false; | | 113 | | protected boolean chunk = false; |
113 | | | | 114 | | |
114 | | | | 115 | | |
115 | | /** | | 116 | | /** |
116 | | * True if the final chunk was found. | | 117 | | * True if the final chunk was found. |
117 | | */ | | 118 | | */ |
118 | | protected boolean endChunk = false; | | 119 | | protected boolean endChunk = false; |
119 | | | | 120 | | |
120 | | | | 121 | | |
121 | | /** | | 122 | | /** |
122 | | * Chunk buffer. | | 123 | | * Chunk buffer. |
123 | | */ | | 124 | | */ |
124 | | protected byte[] chunkBuffer = null; | | 125 | | protected byte[] chunkBuffer = null; |
125 | | | | 126 | | |
126 | | | | 127 | | |
127 | | /** | | 128 | | /** |
128 | | * Chunk length. | | 129 | | * Chunk length. |
129 | | */ | | 130 | | */ |
130 | | protected int chunkLength = 0; | | 131 | | protected int chunkLength = 0; |
131 | | | | 132 | | |
132 | | | | 133 | | |
133 | | /** | | 134 | | /** |
134 | | * Chunk buffer position. | | 135 | | * Chunk buffer position. |
135 | | */ | | 136 | | */ |
136 | | protected int chunkPos = 0; | | 137 | | protected int chunkPos = 0; |
137 | | | | 138 | | |
138 | | | | 139 | | |
139 | | /** | | 140 | | /** |
140 | | * HTTP/1.1 flag. | | 141 | | * HTTP/1.1 flag. |
141 | | */ | | 142 | | */ |
142 | | protected boolean http11 = false; | | 143 | | protected boolean http11 = false; |
143 | | | | 144 | | |
144 | | | | 145 | | |
145 | | // --------------------------------------------------------- Public Methods | | 146 | | // --------------------------------------------------------- Public Methods |
146 | | | | 147 | | |
147 | | | | 148 | | |
148 | | /** | | 149 | | /** |
149 | | * Close this input stream. No physical level I-O is performed, but | | 150 | | * Close this input stream. No physical level I-O is performed, but |
150 | | * any further attempt to read from this stream will throw an IOException. | | 151 | | * any further attempt to read from this stream will throw an IOException. |
151 | | * If a content length has been set but not all of the bytes have yet been | | 152 | | * If a content length has been set but not all of the bytes have yet been |
152 | | * consumed, the remaining bytes will be swallowed. | | 153 | | * consumed, the remaining bytes will be swallowed. |
153 | | */ | | 154 | | */ |
154 | | public void close() | | 155 | | public void close() |
155 | | throws IOException { | | 156 | | throws IOException { |
156 | | | | 157 | | |
157 | | if (closed) | | 158 | | if (closed) |
158 | | throw new IOException(sm.getString("requestStream.close.closed")); | | 159 | | throw new IOException(sm.getString("requestStream.close.closed")); |
159 | | | | 160 | | |
160 | | if (chunk) { | | 161 | | if (chunk) { |
161 | | | | 162 | | |
162 | | while (!endChunk) { | | 163 | | while (!endChunk) { |
163 | | int b = read(); | | 164 | | int b = read(); |
164 | | if (b < 0) | | 165 | | if (b < 0) |
165 | | break; | | 166 | | break; |
166 | | } | | 167 | | } |
167 | | | | 168 | | |
168 | | } else { | | 169 | | } else { |
169 | | | | 170 | | |
170 | | if (http11 && (length > 0)) { | | 171 | | if (http11 && (length > 0)) { |
171 | | while (count < length) { | | 172 | | while (count < length) { |
172 | | int b = read(); | | 173 | | int b = read(); |
173 | | if (b < 0) | | 174 | | if (b < 0) |
174 | | break; | | 175 | | break; |
175 | | } | | 176 | | } |
176 | | } | | 177 | | } |
177 | | | | 178 | | |
178 | | } | | 179 | | } |
179 | | | | 180 | | |
180 | | closed = true; | | 181 | | closed = true; |
181 | | | | 182 | | |
182 | | } | | 183 | | } |
183 | | | | 184 | | |
184 | | | | 185 | | |
185 | | /** | | 186 | | /** |
186 | | * Read and return a single byte from this input stream, or -1 if end of | | 187 | | * Read and return a single byte from this input stream, or -1 if end of |
187 | | * file has been encountered. | | 188 | | * file has been encountered. |
188 | | * | | 189 | | * |
189 | | * @exception IOException if an input/output error occurs | | 190 | | * @exception IOException if an input/output error occurs |
190 | | */ | | 191 | | */ |
191 | | public int read() | | 192 | | public int read() |
192 | | throws IOException { | | 193 | | throws IOException { |
193 | | | | 194 | | |
194 | | // Has this stream been closed? | | 195 | | // Has this stream been closed? |
195 | | if (closed) | | 196 | | if (closed) |
196 | | throw new IOException(sm.getString("requestStream.read.closed")); | | 197 | | throw new IOException(sm.getString("requestStream.read.closed")); |
197 | | | | 198 | | |
198 | | if (chunk) { | | 199 | | if (chunk) { |
199 | | | | 200 | | |
200 | | if (endChunk) | | 201 | | if (endChunk) |
201 | | return (-1); | | 202 | | return (-1); |
202 | | | | 203 | | |
203 | | if ((chunkBuffer == null) | | 204 | | if ((chunkBuffer == null) |
204 | | || (chunkPos >= chunkLength)) { | | 205 | | || (chunkPos >= chunkLength)) { |
205 | | if (!fillChunkBuffer()) | | 206 | | if (!fillChunkBuffer()) |
206 | | return (-1); | | 207 | | return (-1); |
207 | | } | | 208 | | } |
208 | | | | 209 | | |
209 | | return (chunkBuffer[chunkPos++] & 0xff); | | 210 | | return (chunkBuffer[chunkPos++] & 0xff); |
210 | | | | 211 | | |
211 | | } else { | | 212 | | } else { |
212 | | | | 213 | | |
213 | | return (super.read()); | | 214 | | return (super.read()); |
214 | | | | 215 | | |
215 | | } | | 216 | | } |
216 | | | | 217 | | |
217 | | } | | 218 | | } |
218 | | | | 219 | | |
219 | | | | 220 | | |
220 | | /** | | 221 | | /** |
221 | | * Read up to <code>len</code> bytes of data from the input stream | | 222 | | * Read up to <code>len</code> bytes of data from the input stream |
222 | | * into an array of bytes. An attempt is made to read as many as | | 223 | | * into an array of bytes. An attempt is made to read as many as |
223 | | * <code>len</code> bytes, but a smaller number may be read, | | 224 | | * <code>len</code> bytes, but a smaller number may be read, |
224 | | * possibly zero. The number of bytes actually read is returned as | | 225 | | * possibly zero. The number of bytes actually read is returned as |
225 | | * an integer. This method blocks until input data is available, | | 226 | | * an integer. This method blocks until input data is available, |
226 | | * end of file is detected, or an exception is thrown. | | 227 | | * end of file is detected, or an exception is thrown. |
227 | | * | | 228 | | * |
228 | | * @param b The buffer into which the data is read | | 229 | | * @param b The buffer into which the data is read |
229 | | * @param off The start offset into array <code>b</code> at which | | 230 | | * @param off The start offset into array <code>b</code> at which |
230 | | * the data is written | | 231 | | * the data is written |
231 | | * @param len The maximum number of bytes to read | | 232 | | * @param len The maximum number of bytes to read |
232 | | * | | 233 | | * |
233 | | * @exception IOException if an input/output error occurs | | 234 | | * @exception IOException if an input/output error occurs |
234 | | */ | | 235 | | */ |
235 | | public int read(byte b[], int off, int len) throws IOException { | | 236 | | public int read(byte b[], int off, int len) throws IOException { |
236 | | if (chunk) { | | 237 | | if (chunk) { |
237 | | | | 238 | | |
238 | | int avail = chunkLength - chunkPos; | | 239 | | int avail = chunkLength - chunkPos; |
239 | | if (avail == 0) | | 240 | | if (avail == 0) |
240 | | fillChunkBuffer(); | | 241 | | fillChunkBuffer(); |
241 | | avail = chunkLength - chunkPos; | | 242 | | avail = chunkLength - chunkPos; |
242 | | if (avail == 0) | | 243 | | if (avail == 0) |
243 | | return (-1); | | 244 | | return (-1); |
244 | | | | 245 | | |
245 | | int toCopy = avail; | | 246 | | int toCopy = avail; |
246 | | if (avail > len) | | 247 | | if (avail > len) |
247 | | toCopy = len; | | 248 | | toCopy = len; |
248 | | System.arraycopy(chunkBuffer, chunkPos, b, off, toCopy); | | 249 | | System.arraycopy(chunkBuffer, chunkPos, b, off, toCopy); |
249 | | chunkPos += toCopy; | | 250 | | chunkPos += toCopy; |
250 | | return toCopy; | | 251 | | return toCopy; |
251 | | | | 252 | | |
252 | | } else { | | 253 | | } else { |
253 | | return super.read(b, off, len); | | 254 | | return super.read(b, off, len); |
254 | | } | | 255 | | } |
255 | | } | | 256 | | } |
256 | | | | 257 | | |
257 | | | | 258 | | |
258 | | // -------------------------------------------------------- Private Methods | | 259 | | // -------------------------------------------------------- Private Methods |
259 | | | | 260 | | |
260 | | | | 261 | | |
261 | | /** | | 262 | | /** |
262 | | * Fill the chunk buffer. | | 263 | | * Fill the chunk buffer. |
263 | | */ | | 264 | | */ |
264 | | private synchronized boolean fillChunkBuffer() | | 265 | | private synchronized boolean fillChunkBuffer() |
265 | | throws IOException { | | 266 | | throws IOException { |
266 | | | | 267 | | |
267 | | chunkPos = 0; | | 268 | | chunkPos = 0; |
268 | | | | 269 | | |
269 | | try { | | 270 | | try { |
270 | | String numberValue = readLineFromStream(); | | 271 | | String numberValue = readLineFromStream(); |
271 | | if (numberValue != null) | | 272 | | if (numberValue != null) |
272 | | numberValue = numberValue.trim(); | | 273 | | numberValue = numberValue.trim(); |
273 | | chunkLength = | | 274 | | chunkLength = |
274 | | Integer.parseInt(numberValue, 16); | | 275 | | Integer.parseInt(numberValue, 16); |
275 | | } catch (NumberFormatException e) { | | 276 | | } catch (NumberFormatException e) { |
276 | | // Critical error, unable to parse the chunk length | | 277 | | // Critical error, unable to parse the chunk length |
277 | | chunkLength = 0; | | 278 | | chunkLength = 0; |
278 | | chunk = false; | | 279 | | chunk = false; |
279 | | close(); | | 280 | | close(); |
280 | | return false; | | 281 | | return false; |
281 | | } | | 282 | | } |
282 | | | | 283 | | |
283 | | if (chunkLength == 0) { | | 284 | | if (chunkLength == 0) { |
284 | | | | 285 | | |
285 | | // Skipping trailing headers, if any | | 286 | | // Skipping trailing headers, if any |
286 | | String trailingLine = readLineFromStream(); | | 287 | | String trailingLine = readLineFromStream(); |
287 | | while (!trailingLine.equals("")) | | 288 | | while (!trailingLine.equals("")) |
288 | | trailingLine = readLineFromStream(); | | 289 | | trailingLine = readLineFromStream(); |
289 | | endChunk = true; | | 290 | | endChunk = true; |
290 | | return false; | | 291 | | return false; |
291 | | // TODO : Should the stream be automatically closed ? | | 292 | | // TODO : Should the stream be automatically closed ? |
292 | | | | 293 | | |
293 | | } else { | | 294 | | } else { |
294 | | | | 295 | | |
295 | | if ((chunkBuffer == null) | | 296 | | if ((chunkBuffer == null) |
296 | | || (chunkLength > chunkBuffer.length)) | | 297 | | || (chunkLength > chunkBuffer.length)) |
297 | | chunkBuffer = new byte[chunkLength]; | | 298 | | chunkBuffer = new byte[chunkLength]; |
298 | | | | 299 | | |
299 | | // Now read the whole chunk into the buffer | | 300 | | // Now read the whole chunk into the buffer |
300 | | | | 301 | | |
301 | | int nbRead = 0; | | 302 | | int nbRead = 0; |
302 | | int currentRead = 0; | | 303 | | int currentRead = 0; |
303 | | | | 304 | | |
304 | | while (nbRead < chunkLength) { | | 305 | | while (nbRead < chunkLength) { |
305 | | try { | | 306 | | try { |
306 | | currentRead = | | 307 | | currentRead = |
307 | | stream.read(chunkBuffer, nbRead, | | 308 | | stream.read(chunkBuffer, nbRead, |
308 | | chunkLength - nbRead); | | 309 | | chunkLength - nbRead); |
309 | | } catch (Throwable t) { | | 310 | | } catch (Throwable t) { |
310 | | t.printStackTrace(); | | 311 | | t.printStackTrace(); |
311 | | throw new IOException(); | | 312 | | throw new IOException(); |
312 | | } | | 313 | | } |
313 | | if (currentRead < 0) { | | 314 | | if (currentRead < 0) { |
314 | | throw new IOException | | 315 | | throw new IOException |
315 | | (sm.getString("requestStream.read.error")); | | 316 | | (sm.getString("requestStream.read.error")); |
316 | | } | | 317 | | } |
317 | | nbRead += currentRead; | | 318 | | nbRead += currentRead; |
318 | | } | | 319 | | } |
319 | | | | 320 | | |
320 | | // Skipping the CRLF | | 321 | | // Skipping the CRLF |
321 | | String blank = readLineFromStream(); | | 322 | | String blank = readLineFromStream(); |
322 | | | | 323 | | |
323 | | } | | 324 | | } |
324 | | | | 325 | | |
325 | | return true; | | 326 | | return true; |
326 | | | | 327 | | |
327 | | } | | 328 | | } |
328 | | | | 329 | | |
329 | | | | 330 | | |
330 | | /** | | 331 | | /** |
331 | | * Reads the input stream, one line at a time. Reads bytes into an array, | | 332 | | * Reads the input stream, one line at a time. Reads bytes into an array, |
332 | | * until it reads a certain number of bytes or reaches a newline character, | | 333 | | * until it reads a certain number of bytes or reaches a newline character, |
333 | | * which it reads into the array as well. | | 334 | | * which it reads into the array as well. |
334 | | * | | 335 | | * |
335 | | * @param input Input stream on which the bytes are read | | 336 | | * @param input Input stream on which the bytes are read |
336 | | * @return The line that was read, or <code>null</code> if end-of-file | | 337 | | * @return The line that was read, or <code>null</code> if end-of-file |
337 | | * was encountered | | 338 | | * was encountered |
338 | | * @exception IOException if an input or output exception has occurred | | 339 | | * @exception IOException if an input or output exception has occurred |
339 | | */ | | 340 | | */ |
340 | | private String readLineFromStream() | | 341 | | private String readLineFromStream() |
341 | | throws IOException { | | 342 | | throws IOException { |
342 | | | | 343 | | |
343 | | StringBuffer sb = new StringBuffer(); | | 344 | | StringBuffer sb = new StringBuffer(); |
344 | | while (true) { | | 345 | | while (true) { |
345 | | int ch = super.read(); | | 346 | | int ch = super.read(); |
346 | | if (ch < 0) { | | 347 | | if (ch < 0) { |
347 | | if (sb.length() == 0) { | | 348 | | if (sb.length() == 0) { |
348 | | return (null); | | 349 | | return (null); |
349 | | } else { | | 350 | | } else { |
350 | | break; | | 351 | | break; |
351 | | } | | 352 | | } |
352 | | } else if (ch == '\r') { | | 353 | | } else if (ch == '\r') { |
353 | | continue; | | 354 | | continue; |
354 | | } else if (ch == '\n') { | | 355 | | } else if (ch == '\n') { |
355 | | break; | | 356 | | break; |
356 | | } | | 357 | | } |
357 | | sb.append((char) ch); | | 358 | | sb.append((char) ch); |
358 | | } | | 359 | | } |
359 | | return (sb.toString()); | | 360 | | return (sb.toString()); |
360 | | | | 361 | | |
361 | | } | | 362 | | } |
362 | | | | 363 | | |
363 | | | | 364 | | |
364 | | } | | 365 | | } |