1 16 package net.jforum.util.legacy.commons.fileupload; 17 18 import java.io.ByteArrayOutputStream ; 19 import java.io.IOException ; 20 import java.io.InputStream ; 21 import java.io.OutputStream ; 22 import java.io.UnsupportedEncodingException ; 23 24 85 public class MultipartStream { 86 87 89 90 93 public static final byte CR = 0x0D; 94 95 96 99 public static final byte LF = 0x0A; 100 101 102 105 public static final byte DASH = 0x2D; 106 107 108 112 public static final int HEADER_PART_SIZE_MAX = 10240; 113 114 115 118 protected static final int DEFAULT_BUFSIZE = 4096; 119 120 121 125 protected static final byte[] HEADER_SEPARATOR = { 126 CR, LF, CR, LF }; 127 128 129 133 protected static final byte[] FIELD_SEPARATOR = { 134 CR, LF}; 135 136 137 141 protected static final byte[] STREAM_TERMINATOR = { 142 DASH, DASH}; 143 144 145 147 148 151 private InputStream input; 152 153 154 157 private int boundaryLength; 158 159 160 164 private int keepRegion; 165 166 167 170 private byte[] boundary; 171 172 173 176 private int bufSize; 177 178 179 182 private byte[] buffer; 183 184 185 190 private int head; 191 192 193 198 private int tail; 199 200 201 204 private String headerEncoding; 205 206 207 209 210 217 public MultipartStream() { 218 } 219 220 221 239 public MultipartStream(InputStream input, 240 byte[] boundary, 241 int bufSize) { 242 this.input = input; 243 this.bufSize = bufSize; 244 this.buffer = new byte[bufSize]; 245 246 this.boundary = new byte[boundary.length + 4]; 249 this.boundaryLength = boundary.length + 4; 250 this.keepRegion = boundary.length + 3; 251 this.boundary[0] = CR; 252 this.boundary[1] = LF; 253 this.boundary[2] = DASH; 254 this.boundary[3] = DASH; 255 System.arraycopy(boundary, 0, this.boundary, 4, boundary.length); 256 257 head = 0; 258 tail = 0; 259 } 260 261 262 275 public MultipartStream(InputStream input, 276 byte[] boundary) { 277 this(input, boundary, DEFAULT_BUFSIZE); 278 } 279 280 281 283 284 292 public String getHeaderEncoding() { 293 return headerEncoding; 294 } 295 296 297 304 public void setHeaderEncoding(String encoding) { 305 headerEncoding = encoding; 306 } 307 308 309 317 public byte readByte() 318 throws IOException { 319 if (head == tail) { 321 head = 0; 322 tail = input.read(buffer, head, bufSize); 324 if (tail == -1) { 325 throw new IOException ("No more data is available"); 327 } 328 } 329 return buffer[head++]; 330 } 331 332 333 343 public boolean readBoundary() 344 throws MalformedStreamException { 345 byte[] marker = new byte[2]; 346 boolean nextChunk = false; 347 348 head += boundaryLength; 349 try { 350 marker[0] = readByte(); 351 if (marker[0] == LF) { 352 return true; 359 } 360 361 marker[1] = readByte(); 362 if (arrayequals(marker, STREAM_TERMINATOR, 2)) { 363 nextChunk = false; 364 } else if (arrayequals(marker, FIELD_SEPARATOR, 2)) { 365 nextChunk = true; 366 } else { 367 throw new MalformedStreamException( 368 "Unexpected characters follow a boundary"); 369 } 370 } catch (IOException e) { 371 throw new MalformedStreamException("Stream ended unexpectedly"); 372 } 373 return nextChunk; 374 } 375 376 377 396 public void setBoundary(byte[] boundary) 397 throws IllegalBoundaryException { 398 if (boundary.length != boundaryLength - 4) { 399 throw new IllegalBoundaryException( 400 "The length of a boundary token can not be changed"); 401 } 402 System.arraycopy(boundary, 0, this.boundary, 4, boundary.length); 403 } 404 405 406 421 public String readHeaders() 422 throws MalformedStreamException { 423 int i = 0; 424 byte[] b = new byte[1]; 425 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 427 int sizeMax = HEADER_PART_SIZE_MAX; 428 int size = 0; 429 while (i < 4) { 430 try { 431 b[0] = readByte(); 432 } catch (IOException e) { 433 throw new MalformedStreamException("Stream ended unexpectedly"); 434 } 435 size++; 436 if (b[0] == HEADER_SEPARATOR[i]) { 437 i++; 438 } else { 439 i = 0; 440 } 441 if (size <= sizeMax) { 442 baos.write(b[0]); 443 } 444 } 445 446 String headers = null; 447 if (headerEncoding != null) { 448 try { 449 headers = baos.toString(headerEncoding); 450 } catch (UnsupportedEncodingException e) { 451 headers = baos.toString(); 454 } 455 } else { 456 headers = baos.toString(); 457 } 458 459 return headers; 460 } 461 462 463 479 public int readBodyData(OutputStream output) 480 throws MalformedStreamException, 481 IOException { 482 boolean done = false; 483 int pad; 484 int pos; 485 int bytesRead; 486 int total = 0; 487 while (!done) { 488 pos = findSeparator(); 490 if (pos != -1) { 491 output.write(buffer, head, pos - head); 493 total += pos - head; 494 head = pos; 495 done = true; 496 } else { 497 if (tail - head > keepRegion) { 500 pad = keepRegion; 501 } else { 502 pad = tail - head; 503 } 504 output.write(buffer, head, tail - head - pad); 506 507 total += tail - head - pad; 509 System.arraycopy(buffer, tail - pad, buffer, 0, pad); 510 511 head = 0; 513 bytesRead = input.read(buffer, pad, bufSize - pad); 514 515 if (bytesRead != -1) { 517 tail = pad + bytesRead; 518 } else { 519 output.write(buffer, 0, pad); 523 output.flush(); 524 total += pad; 525 throw new MalformedStreamException( 526 "Stream ended unexpectedly"); 527 } 528 } 529 } 530 output.flush(); 531 return total; 532 } 533 534 535 547 public int discardBodyData() 548 throws MalformedStreamException, 549 IOException { 550 boolean done = false; 551 int pad; 552 int pos; 553 int bytesRead; 554 int total = 0; 555 while (!done) { 556 pos = findSeparator(); 558 if (pos != -1) { 559 total += pos - head; 561 head = pos; 562 done = true; 563 } else { 564 if (tail - head > keepRegion) { 567 pad = keepRegion; 568 } else { 569 pad = tail - head; 570 } 571 total += tail - head - pad; 572 573 System.arraycopy(buffer, tail - pad, buffer, 0, pad); 575 576 head = 0; 578 bytesRead = input.read(buffer, pad, bufSize - pad); 579 580 if (bytesRead != -1) { 582 tail = pad + bytesRead; 583 } else { 584 total += pad; 588 throw new MalformedStreamException( 589 "Stream ended unexpectedly"); 590 } 591 } 592 } 593 return total; 594 } 595 596 597 605 public boolean skipPreamble() 606 throws IOException { 607 System.arraycopy(boundary, 2, boundary, 0, boundary.length - 2); 609 boundaryLength = boundary.length - 2; 610 try { 611 discardBodyData(); 613 614 return readBoundary(); 617 } catch (MalformedStreamException e) { 618 return false; 619 } finally { 620 System.arraycopy(boundary, 0, boundary, 2, boundary.length - 2); 622 boundaryLength = boundary.length; 623 boundary[0] = CR; 624 boundary[1] = LF; 625 } 626 } 627 628 629 640 public static boolean arrayequals(byte[] a, 641 byte[] b, 642 int count) { 643 for (int i = 0; i < count; i++) { 644 if (a[i] != b[i]) { 645 return false; 646 } 647 } 648 return true; 649 } 650 651 652 662 protected int findByte(byte value, 663 int pos) { 664 for (int i = pos; i < tail; i++) { 665 if (buffer[i] == value) { 666 return i; 667 } 668 } 669 670 return -1; 671 } 672 673 674 682 protected int findSeparator() { 683 int first; 684 int match = 0; 685 int maxpos = tail - boundaryLength; 686 for (first = head; 687 (first <= maxpos) && (match != boundaryLength); 688 first++) { 689 first = findByte(boundary[0], first); 690 if (first == -1 || (first > maxpos)) { 691 return -1; 692 } 693 for (match = 1; match < boundaryLength; match++) { 694 if (buffer[first + match] != boundary[match]) { 695 break; 696 } 697 } 698 } 699 if (match == boundaryLength) { 700 return first - 1; 701 } 702 return -1; 703 } 704 705 710 public String toString() { 711 StringBuffer sbTemp = new StringBuffer (); 712 sbTemp.append("boundary='"); 713 sbTemp.append(String.valueOf(boundary)); 714 sbTemp.append("'\nbufSize="); 715 sbTemp.append(bufSize); 716 return sbTemp.toString(); 717 } 718 719 723 public class MalformedStreamException 724 extends IOException { 725 729 public MalformedStreamException() { 730 super(); 731 } 732 733 739 public MalformedStreamException(String message) { 740 super(message); 741 } 742 } 743 744 745 748 public class IllegalBoundaryException 749 extends IOException { 750 754 public IllegalBoundaryException() { 755 super(); 756 } 757 758 764 public IllegalBoundaryException(String message) { 765 super(message); 766 } 767 } 768 769 770 772 773 835 } 836 | Popular Tags |