1 61 62 63 package org.apache.commons.fileupload; 64 65 66 import java.io.ByteArrayOutputStream ; 67 import java.io.IOException ; 68 import java.io.InputStream ; 69 import java.io.OutputStream ; 70 import java.io.UnsupportedEncodingException ; 71 72 73 134 public class MultipartStream 135 { 136 137 139 140 144 public static final int HEADER_PART_SIZE_MAX = 10240; 145 146 147 150 protected static final int DEFAULT_BUFSIZE = 4096; 151 152 153 157 protected static final byte[] HEADER_SEPARATOR = {0x0D, 0x0A, 0x0D, 0x0A}; 158 159 160 164 protected static final byte[] FIELD_SEPARATOR = { 0x0D, 0x0A }; 165 166 167 171 protected static final byte[] STREAM_TERMINATOR = { 0x2D, 0x2D }; 172 173 174 176 177 180 private InputStream input; 181 182 183 186 private int boundaryLength; 187 188 189 193 private int keepRegion; 194 195 196 199 private byte[] boundary; 200 201 202 205 private int bufSize; 206 207 208 211 private byte[] buffer; 212 213 214 219 private int head; 220 221 222 227 private int tail; 228 229 230 233 private String headerEncoding; 234 235 236 238 239 246 public MultipartStream() 247 { 248 } 249 250 251 269 public MultipartStream(InputStream input, 270 byte[] boundary, 271 int bufSize) 272 { 273 this.input = input; 274 this.bufSize = bufSize; 275 this.buffer = new byte[bufSize]; 276 277 this.boundary = new byte[boundary.length + 4]; 280 this.boundaryLength = boundary.length + 4; 281 this.keepRegion = boundary.length + 3; 282 this.boundary[0] = 0x0D; 283 this.boundary[1] = 0x0A; 284 this.boundary[2] = 0x2D; 285 this.boundary[3] = 0x2D; 286 System.arraycopy(boundary, 0, this.boundary, 4, boundary.length); 287 288 head = 0; 289 tail = 0; 290 } 291 292 293 306 public MultipartStream(InputStream input, 307 byte[] boundary) 308 throws IOException 309 { 310 this(input, boundary, DEFAULT_BUFSIZE); 311 } 312 313 314 316 317 325 public String getHeaderEncoding() 326 { 327 return headerEncoding; 328 } 329 330 331 338 public void setHeaderEncoding(String encoding) 339 { 340 headerEncoding = encoding; 341 } 342 343 344 352 public byte readByte() 353 throws IOException 354 { 355 if (head == tail) 357 { 358 head = 0; 359 tail = input.read(buffer, head, bufSize); 361 if (tail == -1) 362 { 363 throw new IOException ("No more data is available"); 365 } 366 } 367 return buffer[head++]; 368 } 369 370 371 381 public boolean readBoundary() 382 throws MalformedStreamException 383 { 384 byte[] marker = new byte[2]; 385 boolean nextChunk = false; 386 387 head += boundaryLength; 388 try 389 { 390 marker[0] = readByte(); 391 marker[1] = readByte(); 392 if (arrayequals(marker, STREAM_TERMINATOR, 2)) 393 { 394 nextChunk = false; 395 } 396 else if (arrayequals(marker, FIELD_SEPARATOR, 2)) 397 { 398 nextChunk = true; 399 } 400 else 401 { 402 throw new MalformedStreamException( 403 "Unexpected characters follow a boundary"); 404 } 405 } 406 catch (IOException e) 407 { 408 throw new MalformedStreamException("Stream ended unexpectedly"); 409 } 410 return nextChunk; 411 } 412 413 414 433 public void setBoundary(byte[] boundary) 434 throws IllegalBoundaryException 435 { 436 if (boundary.length != boundaryLength - 4) 437 { 438 throw new IllegalBoundaryException( 439 "The length of a boundary token can not be changed"); 440 } 441 System.arraycopy(boundary, 0, this.boundary, 4, boundary.length); 442 } 443 444 445 460 public String readHeaders() 461 throws MalformedStreamException 462 { 463 int i = 0; 464 byte b[] = new byte[1]; 465 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 467 int sizeMax = HEADER_PART_SIZE_MAX; 468 int size = 0; 469 while (i < 4) 470 { 471 try 472 { 473 b[0] = readByte(); 474 } 475 catch (IOException e) 476 { 477 throw new MalformedStreamException("Stream ended unexpectedly"); 478 } 479 size++; 480 if (b[0] == HEADER_SEPARATOR[i]) 481 { 482 i++; 483 } 484 else 485 { 486 i = 0; 487 } 488 if (size <= sizeMax) 489 { 490 baos.write(b[0]); 491 } 492 } 493 494 String headers = null; 495 if (headerEncoding != null) 496 { 497 try 498 { 499 headers = baos.toString(headerEncoding); 500 } 501 catch (UnsupportedEncodingException e) 502 { 503 headers = baos.toString(); 506 } 507 } 508 else 509 { 510 headers = baos.toString(); 511 } 512 513 return headers; 514 } 515 516 517 533 public int readBodyData(OutputStream output) 534 throws MalformedStreamException, 535 IOException 536 { 537 boolean done = false; 538 int pad; 539 int pos; 540 int bytesRead; 541 int total = 0; 542 while (!done) 543 { 544 pos = findSeparator(); 546 if (pos != -1) 547 { 548 output.write(buffer, head, pos - head); 550 total += pos - head; 551 head = pos; 552 done = true; 553 } 554 else 555 { 556 if (tail - head > keepRegion) 559 { 560 pad = keepRegion; 561 } 562 else 563 { 564 pad = tail - head; 565 } 566 output.write(buffer, head, tail - head - pad); 568 569 total += tail - head - pad; 571 System.arraycopy(buffer, tail - pad, buffer, 0, pad); 572 573 head = 0; 575 bytesRead = input.read(buffer, pad, bufSize - pad); 576 577 if (bytesRead != -1) 579 { 580 tail = pad + bytesRead; 581 } 582 else 583 { 584 output.write(buffer, 0, pad); 588 output.flush(); 589 total += pad; 590 throw new MalformedStreamException( 591 "Stream ended unexpectedly"); 592 } 593 } 594 } 595 output.flush(); 596 return total; 597 } 598 599 600 612 public int discardBodyData() 613 throws MalformedStreamException, 614 IOException 615 { 616 boolean done = false; 617 int pad; 618 int pos; 619 int bytesRead; 620 int total = 0; 621 while (!done) 622 { 623 pos = findSeparator(); 625 if (pos != -1) 626 { 627 total += pos - head; 629 head = pos; 630 done = true; 631 } 632 else 633 { 634 if (tail - head > keepRegion) 637 { 638 pad = keepRegion; 639 } 640 else 641 { 642 pad = tail - head; 643 } 644 total += tail - head - pad; 645 646 System.arraycopy(buffer, tail - pad, buffer, 0, pad); 648 649 head = 0; 651 bytesRead = input.read(buffer, pad, bufSize - pad); 652 653 if (bytesRead != -1) 655 { 656 tail = pad + bytesRead; 657 } 658 else 659 { 660 total += pad; 664 throw new MalformedStreamException( 665 "Stream ended unexpectedly"); 666 } 667 } 668 } 669 return total; 670 } 671 672 673 681 public boolean skipPreamble() 682 throws IOException 683 { 684 System.arraycopy(boundary, 2, boundary, 0, boundary.length - 2); 686 boundaryLength = boundary.length - 2; 687 try 688 { 689 discardBodyData(); 691 692 return readBoundary(); 695 } 696 catch (MalformedStreamException e) 697 { 698 return false; 699 } 700 finally 701 { 702 System.arraycopy(boundary, 0, boundary, 2, boundary.length - 2); 704 boundaryLength = boundary.length; 705 boundary[0] = 0x0D; 706 boundary[1] = 0x0A; 707 } 708 } 709 710 711 722 public static boolean arrayequals(byte[] a, 723 byte[] b, 724 int count) 725 { 726 for (int i = 0; i < count; i++) 727 { 728 if (a[i] != b[i]) 729 { 730 return false; 731 } 732 } 733 return true; 734 } 735 736 737 747 protected int findByte(byte value, 748 int pos) 749 { 750 for (int i = pos; i < tail; i++) 751 { 752 if (buffer[i] == value) 753 { 754 return i; 755 } 756 } 757 758 return -1; 759 } 760 761 762 770 protected int findSeparator() 771 { 772 int first; 773 int match = 0; 774 int maxpos = tail - boundaryLength; 775 for (first = head; 776 (first <= maxpos) && (match != boundaryLength); 777 first++) 778 { 779 first = findByte(boundary[0], first); 780 if (first == -1 || (first > maxpos)) 781 { 782 return -1; 783 } 784 for (match = 1; match < boundaryLength; match++) 785 { 786 if (buffer[first + match] != boundary[match]) 787 { 788 break; 789 } 790 } 791 } 792 if (match == boundaryLength) 793 { 794 return first - 1; 795 } 796 return -1; 797 } 798 799 804 public String toString() 805 { 806 StringBuffer sbTemp = new StringBuffer (); 807 sbTemp.append("boundary='"); 808 sbTemp.append(String.valueOf(boundary)); 809 sbTemp.append("'\nbufSize="); 810 sbTemp.append(bufSize); 811 return sbTemp.toString(); 812 } 813 814 818 public class MalformedStreamException 819 extends IOException 820 { 821 825 public MalformedStreamException() 826 { 827 super(); 828 } 829 830 836 public MalformedStreamException(String message) 837 { 838 super(message); 839 } 840 } 841 842 843 846 public class IllegalBoundaryException 847 extends IOException 848 { 849 853 public IllegalBoundaryException() 854 { 855 super(); 856 } 857 858 864 public IllegalBoundaryException(String message) 865 { 866 super(message); 867 } 868 } 869 870 871 873 874 936 } 937 | Popular Tags |