1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.danube.http;
14
15
16 import java.io.IOException;
17 import java.io.InputStream;
18
19
20
21
22
23
24 public class HTTPBufferedInputStream extends InputStream {
25
26
27 public static final int DEFAULT_BUFFER_SIZE = 2048;
28
29
30 protected byte[] buffer;
31
32
33 protected int ptr;
34
35
36 protected int len;
37
38
39 protected int mark = -1;
40
41
42 protected InputStream inputStream;
43
44
45 protected int bufferSize;
46
47
48 protected boolean closed = false;
49
50
51 protected long contentLength = 0;
52
53
54 protected int readbytes = 0;
55
56
57 protected boolean chunkEncoding = false;
58
59
60 protected int chunkSize = 0;
61
62
63
64
65
66
67
68 public HTTPBufferedInputStream(InputStream inputStream, int defaultBufferSize) {
69 this.inputStream = inputStream;
70 this.bufferSize = defaultBufferSize;
71 }
72
73
74
75
76 public void resetInternals() {
77 closed = false;
78 ptr = 0;
79 contentLength = 0;
80 readbytes = 0;
81 chunkEncoding = false;
82 len = 0;
83 mark = -1;
84 }
85
86
87
88
89
90
91 public int getBufferSize() {
92 return bufferSize;
93 }
94
95
96
97
98
99
100
101 public void setBufferSize(int size) {
102 bufferSize = size;
103 }
104
105
106
107
108
109 public long getContentLength() {
110 return contentLength;
111 }
112
113
114
115
116
117 public void setContentLength(long contentLength) {
118 this.contentLength = contentLength;
119 }
120
121
122
123
124
125 public boolean isChunkEncoding() {
126 return chunkEncoding;
127 }
128
129
130
131
132
133 public void setChunkEncoding(boolean chunkEncoding) {
134 this.chunkEncoding = chunkEncoding;
135 }
136
137
138
139
140
141
142 protected int readChunkSize() throws IOException {
143 int size = 0;
144 int i = inputStream.read();
145 while ((i > 0)
146 && ((i >= '0') && (i <= '9')
147 || ((i >= 'a') && (i <= 'f'))
148 || ((i >= 'A') && (i <= 'F'))))
149 {
150 if ((i >= '0') && (i <= '9')) {
151 size = size * 16 + (i - '0');
152 } else if ((i >= 'a') && (i <= 'f')) {
153 size = size * 16 + (i - 'a' + 10);
154 } else if ((i >= 'A') && (i <= 'F')) {
155 size = size * 16 + (i - 'A' + 10);
156 }
157 i = inputStream.read();
158 }
159 if (i == 13) {
160
161 i = inputStream.read();
162 }
163 return size;
164 }
165
166
167
168
169
170
171 protected void checkBuffer() throws IOException {
172 if (chunkEncoding) {
173 if (chunkSize >= 0) {
174 if (ptr == len) {
175 ptr = 0;
176 len = 0;
177 mark = -1;
178 if ((buffer == null) || (bufferSize != buffer.length)) {
179 buffer = new byte[bufferSize];
180 }
181 int l = 0;
182 while ((l >= 0) && (len < buffer.length)) {
183 if (chunkSize == 0) {
184 chunkSize = readChunkSize();
185 if (chunkSize == 0) {
186 chunkSize = -1;
187 l = -1;
188 }
189 }
190 if (chunkSize > 0) {
191 l = chunkSize;
192 if (l > (buffer.length - len)) {
193 l = buffer.length - len;
194 }
195 l = inputStream.read(buffer, len, l);
196 if (l > 0) {
197 chunkSize = chunkSize - l;
198 len = len + l;
199 } else {
200 chunkSize = -1;
201 }
202 }
203 }
204 }
205 } else {
206 if (ptr == len) {
207 ptr = 0;
208 len = 0;
209 mark = -1;
210 if ((buffer != null) && (bufferSize != buffer.length)) {
211 buffer = null;
212 }
213 }
214 }
215 } else {
216 if (contentLength > 0) {
217 if (ptr == len) {
218 ptr = 0;
219 len = 0;
220 mark = -1;
221 if ((buffer == null) || (bufferSize != buffer.length)) {
222 buffer = new byte[bufferSize];
223 }
224 int l = buffer.length;
225 if (l > contentLength) {
226 l = (int)contentLength;
227 }
228 l = inputStream.read(buffer, 0, l);
229 len = len + l;
230 contentLength = contentLength - l;
231 }
232 } else {
233 if (ptr == len) {
234 ptr = 0;
235 len = 0;
236 mark = -1;
237 if ((buffer != null) && (bufferSize != buffer.length)) {
238 buffer = null;
239 }
240 }
241 }
242 }
243 }
244
245 @Override
246 public void close() throws IOException {
247 if (!closed) {
248 closed = true;
249 if (chunkEncoding) {
250 if (bufferSize <= 0) {
251 byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
252 while (chunkSize >= 0) {
253 if (chunkSize == 0) {
254 chunkSize = readChunkSize();
255 if (chunkSize == 0) {
256 chunkSize = -1;
257 }
258 }
259 if (chunkSize > 0) {
260 int r = DEFAULT_BUFFER_SIZE;
261 if (r > chunkSize) {
262 r = chunkSize;
263 }
264 r = inputStream.read(buf, 0, r);
265 chunkSize = chunkSize - r;
266 }
267 }
268 } else {
269 while (chunkSize >= 0) {
270 ptr = len;
271 checkBuffer();
272 }
273 }
274 } else {
275 if (bufferSize <= 0) {
276 if (contentLength > 0) {
277 byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
278 while (contentLength > 0) {
279 int r = DEFAULT_BUFFER_SIZE;
280 if (r > contentLength) {
281 r = (int)contentLength;
282 }
283 r = inputStream.read(buf, 0, r);
284 contentLength = contentLength - r;
285 }
286 }
287 } else {
288 while (contentLength > 0) {
289 contentLength = contentLength - (len - ptr);
290 checkBuffer();
291 }
292 }
293 }
294 }
295 }
296
297
298 @Override
299 public int read() throws IOException {
300 if (closed) {
301 throw new IOException("Stream is closed");
302 }
303 if (bufferSize <= 0) {
304 if (chunkEncoding) {
305 if (chunkSize == 0) {
306 chunkSize = readChunkSize();
307 if (chunkSize == 0) {
308 chunkSize = -1;
309 }
310 }
311 if (chunkSize > 0) {
312 int r = inputStream.read();
313 if (r >= 0) {
314 chunkSize = chunkSize - 1;
315 } else {
316 chunkSize = -1;
317 }
318 return r;
319 } else {
320 chunkSize = -1;
321 return -1;
322 }
323 } else {
324 if (contentLength > 0) {
325 int r = inputStream.read();
326 if (r >= 0) {
327 contentLength = contentLength - 1;
328 } else {
329 contentLength = 0;
330 }
331 return r;
332 } else {
333 return -1;
334 }
335 }
336 } else {
337 checkBuffer();
338 if (ptr < len) {
339 int b = buffer[ptr];
340 ptr = ptr + 1;
341 return b;
342 } else {
343 return -1;
344 }
345 }
346 }
347
348 @Override
349 public int read(byte[] buf) throws IOException {
350 return read(buf, 0, buf.length);
351 }
352
353 @Override
354 public int read(byte[] buf, int off, int l) throws IOException {
355 if (closed) {
356 throw new IOException("Stream is closed");
357 }
358 if (l == 0) {
359 return 0;
360 }
361 if (bufferSize <= 0) {
362 if (chunkEncoding) {
363 int r = 0;
364 while ((l > 0) && (chunkSize >= 0)) {
365 if (chunkSize == 0) {
366 chunkSize = readChunkSize();
367 if (chunkSize == 0) {
368 chunkSize = -1;
369 }
370 }
371 int ll = l;
372 if (ll > chunkSize) {
373 ll = chunkSize;
374 }
375 ll = inputStream.read(buf, off, ll);
376 if (ll >= 0) {
377 r = r + ll;
378 off = off + ll;
379 l = l - ll;
380 chunkSize = chunkSize - ll;
381 } else {
382 if (r > 0) {
383 return r;
384 } else {
385 return -1;
386 }
387 }
388 }
389 return r;
390 } else {
391 if (contentLength > 0) {
392 if (l > contentLength) {
393 l = (int)contentLength;
394 }
395 l = inputStream.read(buf, off, l);
396 if (l >= 0) {
397 contentLength = contentLength - l;
398 }
399 return l;
400 } else {
401 return -1;
402 }
403 }
404 } else {
405 checkBuffer();
406 int r = 0;
407 int ll = len - ptr;
408 while ((ll > 0) && (ll <= l)) {
409 System.arraycopy(buffer, ptr, buf, off, ll);
410 l = l - ll;
411 r = r + ll;
412 off = off + ll;
413 ptr = len;
414 checkBuffer();
415 ll = len - ptr;
416 }
417 if (ll > 0) {
418
419 if (((ptr + l) > buffer.length)
420 || ((off + l) > buf.length)) {
421 System.out.println("here");
422 }
423 System.arraycopy(buffer, ptr, buf, off, l);
424 ptr = ptr + l;
425 r = r + l;
426 }
427
428 if (r == 0) {
429
430 return -1;
431 } else {
432 return r;
433 }
434 }
435 }
436
437 @Override
438 public long skip(long l) throws IOException {
439 if (closed) {
440 throw new IOException("Stream is closed");
441 }
442 if (l == 0) {
443 return 0;
444 }
445 checkBuffer();
446 long r = 0;
447 int ll = len - ptr;
448 while ((ll > 0) && (ll <= l)) {
449 l = l - ll;
450 r = r + ll;
451 ptr = len;
452 checkBuffer();
453 ll = len - ptr;
454 }
455 if (ll > 0) {
456
457 ptr = ptr + (int)l;
458 r = r + l;
459 }
460
461 return r;
462 }
463
464 @Override
465 public int available() throws IOException {
466 if (closed) {
467 throw new IOException("Stream is closed");
468 }
469 return ptr - len;
470 }
471
472 @Override
473 public synchronized void mark(int i) {
474 if (!closed) {
475 if (chunkEncoding) {
476 try {
477 checkBuffer();
478 } catch (IOException e) {
479 return;
480 }
481 if ((chunkSize < 0) && (i > (ptr - len))) {
482 i = ptr - len;
483
484
485 }
486 } else {
487 if (i > contentLength) {
488 i = (int)contentLength;
489 }
490
491 }
492 if (i > bufferSize) {
493
494 byte[] newBuffer = new byte[i];
495 System.arraycopy(buffer, ptr, newBuffer, 0, (ptr - len));
496 buffer = newBuffer;
497 len = ptr - len;
498 ptr = 0;
499 mark = 0;
500 } else {
501 mark = ptr;
502 }
503 }
504 }
505
506 @Override
507 public synchronized void reset() throws IOException {
508 if (closed) {
509 throw new IOException("Stream is closed");
510 }
511 if (mark < 0) {
512 throw new IOException("Cannot reset - stream is part asked number of bytes after the mark.");
513 }
514 ptr = mark;
515 }
516
517 @Override
518 public boolean markSupported() {
519 return true;
520 }
521 }