1 31 32 package org.apache.commons.httpclient; 33 34 import java.io.ByteArrayOutputStream ; 35 import java.io.IOException ; 36 import java.io.InputStream ; 37 38 39 62 63 public class ChunkedInputStream extends InputStream { 64 65 private InputStream in; 66 67 68 private int chunkSize; 69 70 71 private int pos; 72 73 74 private boolean bof = true; 75 76 77 private boolean eof = false; 78 79 80 private boolean closed = false; 81 82 83 private HttpMethod method; 84 85 93 public ChunkedInputStream( 94 final InputStream in, final HttpMethod method) throws IOException { 95 96 if (in == null) { 97 throw new IllegalArgumentException ("InputStream parameter may not be null"); 98 } 99 if (method == null) { 100 throw new IllegalArgumentException ("HttpMethod parameter may not be null"); 101 } 102 this.in = in; 103 this.method = method; 104 this.pos = 0; 105 } 106 107 121 public int read() throws IOException { 122 123 if (closed) { 124 throw new IOException ("Attempted read from closed stream."); 125 } 126 if (eof) { 127 return -1; 128 } 129 if (pos >= chunkSize) { 130 nextChunk(); 131 if (eof) { 132 return -1; 133 } 134 } 135 pos++; 136 return in.read(); 137 } 138 139 150 public int read (byte[] b, int off, int len) throws IOException { 151 152 if (closed) { 153 throw new IOException ("Attempted read from closed stream."); 154 } 155 156 if (eof) { 157 return -1; 158 } 159 if (pos >= chunkSize) { 160 nextChunk(); 161 if (eof) { 162 return -1; 163 } 164 } 165 len = Math.min(len, chunkSize - pos); 166 int count = in.read(b, off, len); 167 pos += count; 168 return count; 169 } 170 171 179 public int read (byte[] b) throws IOException { 180 return read(b, 0, b.length); 181 } 182 183 187 private void readCRLF() throws IOException { 188 int cr = in.read(); 189 int lf = in.read(); 190 if ((cr != '\r') || (lf != '\n')) { 191 throw new IOException ( 192 "CRLF expected at end of chunk: " + cr + "/" + lf); 193 } 194 } 195 196 197 201 private void nextChunk() throws IOException { 202 if (!bof) { 203 readCRLF(); 204 } 205 chunkSize = getChunkSizeFromInputStream(in); 206 bof = false; 207 pos = 0; 208 if (chunkSize == 0) { 209 eof = true; 210 parseTrailerHeaders(); 211 } 212 } 213 214 225 private static int getChunkSizeFromInputStream(final InputStream in) 226 throws IOException { 227 228 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 229 int state = 0; 231 while (state != -1) { 232 int b = in.read(); 233 if (b == -1) { 234 throw new IOException ("chunked stream ended unexpectedly"); 235 } 236 switch (state) { 237 case 0: 238 switch (b) { 239 case '\r': 240 state = 1; 241 break; 242 case '\"': 243 state = 2; 244 245 default: 246 baos.write(b); 247 } 248 break; 249 250 case 1: 251 if (b == '\n') { 252 state = -1; 253 } else { 254 throw new IOException ("Protocol violation: Unexpected" 256 + " single newline character in chunk size"); 257 } 258 break; 259 260 case 2: 261 switch (b) { 262 case '\\': 263 b = in.read(); 264 baos.write(b); 265 break; 266 case '\"': 267 state = 0; 268 269 default: 270 baos.write(b); 271 } 272 break; 273 default: throw new RuntimeException ("assertion failed"); 274 } 275 } 276 277 String dataString = HttpConstants.getString(baos.toByteArray()); 279 int separator = dataString.indexOf(';'); 280 dataString = (separator > 0) 281 ? dataString.substring(0, separator).trim() 282 : dataString.trim(); 283 284 int result; 285 try { 286 result = Integer.parseInt(dataString.trim(), 16); 287 } catch (NumberFormatException e) { 288 throw new IOException ("Bad chunk size: " + dataString); 289 } 290 return result; 291 } 292 293 297 private void parseTrailerHeaders() throws IOException { 298 Header[] footers = HttpParser.parseHeaders(in); 299 300 for (int i = 0; i < footers.length; i++) { 301 method.addResponseFooter(footers[i]); 302 } 303 } 304 305 311 public void close() throws IOException { 312 if (!closed) { 313 try { 314 if (!eof) { 315 exhaustInputStream(this); 316 } 317 } finally { 318 eof = true; 319 closed = true; 320 } 321 } 322 } 323 324 335 static void exhaustInputStream(InputStream inStream) throws IOException { 336 byte buffer[] = new byte[1024]; 338 while (inStream.read(buffer) >= 0) { 339 ; 340 } 341 } 342 } 343 | Popular Tags |