libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / gnu / java / net / protocol / http / ChunkedInputStream.java
blob8a30e51db57334da5be8e3f9a1476e9cf4809d2c
1 /* ChunkedInputStream.java --
2 Copyright (C) 2004, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.java.net.protocol.http;
41 import gnu.java.lang.CPStringBuilder;
43 import java.io.IOException;
44 import java.io.InputStream;
45 import java.net.ProtocolException;
49 // Note that we rely on the implemtation of skip() in the super class
50 // (InputStream) calling our read methods to account for chunk headers
51 // while skipping.
55 /**
56 * Input stream wrapper for the "chunked" transfer-coding.
58 * @author Chris Burdess (dog@gnu.org)
60 public class ChunkedInputStream
61 extends InputStream
63 Headers headers;
65 /** The underlying stream. */
66 private InputStream in;
68 /** Size of the chunk we're reading. */
69 int size;
70 /** Number of bytes we've read in this chunk. */
71 int count;
72 /**
73 * True when we should read meta-information, false when we should
74 * read data.
76 boolean meta;
77 /** True when we've hit EOF. */
78 boolean eof;
80 /**
81 * Constructor.
82 * @param in the response socket input stream
83 * @param headers the headers to receive additional header lines
85 public ChunkedInputStream(InputStream in, Headers headers)
87 this.in = in;
88 this.headers = headers;
89 size = -1;
90 count = 0;
91 meta = true;
94 public int read()
95 throws IOException
97 byte[] buf = new byte[1];
98 int len = read(buf, 0, 1);
99 if (len == -1)
101 return -1;
103 return 0xff & buf[0];
106 public synchronized int read(byte[] buffer, int offset, int length)
107 throws IOException
109 if (eof)
111 return -1;
113 if (meta)
115 // Read chunk header
116 int c, last = 0;
117 boolean seenSemi = false;
118 CPStringBuilder buf = new CPStringBuilder();
121 c = in.read();
122 if (c == 0x3b) // ;
124 seenSemi = true;
126 else if (c == 0x0a && last == 0x0d) // CRLF
130 size = Integer.parseInt(buf.toString(), 16);
132 catch (NumberFormatException nfe)
134 IOException ioe = new IOException("Bad chunk header");
135 ioe.initCause(nfe);
136 // Unrecoverable. Don't try to read more.
137 in.close();
138 throw ioe;
140 break;
142 else if (!seenSemi && c >= 0x30)
144 buf.append ((char) c);
146 last = c;
148 while(c != -1);
149 count = 0;
150 meta = false;
152 if (size == 0)
154 // Read trailer
155 headers.parse(in);
156 eof = true;
157 return -1;
159 else
161 int canRead = Math.min(size - count, length);
162 int len = in.read(buffer, offset, canRead);
163 if (len == -1)
165 // This is an error condition but it isn't clear what we
166 // should do with it.
167 eof = true;
168 return -1;
170 count += len;
171 if (count == size)
173 // Read CRLF
174 int c1 = in.read();
175 int c2 = in.read();
176 if (c1 == -1 || c2 == -1)
178 // EOF before CRLF: bad, but ignore
179 eof = true;
180 return -1;
182 if (c1 != 0x0d || c2 != 0x0a)
184 throw new ProtocolException("expecting CRLF: " + c1 + "," + c2);
186 meta = true;
188 return len;
193 * This method returns the number of bytes that can be read from
194 * this stream before a read might block. Even if the underlying
195 * InputStream has data available past the end of the current chunk,
196 * we have no way of knowing how large the next chunk header will
197 * be. So we cannot report available data past the current chunk.
199 * @return The number of bytes that can be read before a read might
200 * block
202 * @exception IOException If an error occurs
204 public int available() throws IOException
206 if (meta)
207 return 0;
209 return Math.min(in.available(), size - count);
213 * This method closes the ChunkedInputStream by closing the underlying
214 * InputStream.
216 * @exception IOException If an error occurs
218 public void close() throws IOException
220 in.close();