1 17 18 19 package org.apache.tomcat.util.http.fileupload; 20 21 22 import java.io.ByteArrayOutputStream ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.io.OutputStream ; 26 import java.io.UnsupportedEncodingException ; 27 28 29 90 public class MultipartStream 91 { 92 93 95 96 100 public static final int HEADER_PART_SIZE_MAX = 10240; 101 102 103 106 protected static final int DEFAULT_BUFSIZE = 4096; 107 108 109 113 protected static final byte[] HEADER_SEPARATOR = {0x0D, 0x0A, 0x0D, 0x0A}; 114 115 116 120 protected static final byte[] FIELD_SEPARATOR = { 0x0D, 0x0A }; 121 122 123 127 protected static final byte[] STREAM_TERMINATOR = { 0x2D, 0x2D }; 128 129 130 132 133 136 private InputStream input; 137 138 139 142 private int boundaryLength; 143 144 145 149 private int keepRegion; 150 151 152 155 private byte[] boundary; 156 157 158 161 private int bufSize; 162 163 164 167 private byte[] buffer; 168 169 170 175 private int head; 176 177 178 183 private int tail; 184 185 186 189 private String headerEncoding; 190 191 192 194 195 202 public MultipartStream() 203 { 204 } 205 206 207 225 public MultipartStream(InputStream input, 226 byte[] boundary, 227 int bufSize) 228 { 229 this.input = input; 230 this.bufSize = bufSize; 231 this.buffer = new byte[bufSize]; 232 233 this.boundary = new byte[boundary.length + 4]; 236 this.boundaryLength = boundary.length + 4; 237 this.keepRegion = boundary.length + 3; 238 this.boundary[0] = 0x0D; 239 this.boundary[1] = 0x0A; 240 this.boundary[2] = 0x2D; 241 this.boundary[3] = 0x2D; 242 System.arraycopy(boundary, 0, this.boundary, 4, boundary.length); 243 244 head = 0; 245 tail = 0; 246 } 247 248 249 262 public MultipartStream(InputStream input, 263 byte[] boundary) 264 throws IOException 265 { 266 this(input, boundary, DEFAULT_BUFSIZE); 267 } 268 269 270 272 273 281 public String getHeaderEncoding() 282 { 283 return headerEncoding; 284 } 285 286 287 294 public void setHeaderEncoding(String encoding) 295 { 296 headerEncoding = encoding; 297 } 298 299 300 308 public byte readByte() 309 throws IOException 310 { 311 if (head == tail) 313 { 314 head = 0; 315 tail = input.read(buffer, head, bufSize); 317 if (tail == -1) 318 { 319 throw new IOException ("No more data is available"); 321 } 322 } 323 return buffer[head++]; 324 } 325 326 327 337 public boolean readBoundary() 338 throws MalformedStreamException 339 { 340 byte[] marker = new byte[2]; 341 boolean nextChunk = false; 342 343 head += boundaryLength; 344 try 345 { 346 marker[0] = readByte(); 347 marker[1] = readByte(); 348 if (arrayequals(marker, STREAM_TERMINATOR, 2)) 349 { 350 nextChunk = false; 351 } 352 else if (arrayequals(marker, FIELD_SEPARATOR, 2)) 353 { 354 nextChunk = true; 355 } 356 else 357 { 358 throw new MalformedStreamException( 359 "Unexpected characters follow a boundary"); 360 } 361 } 362 catch (IOException e) 363 { 364 throw new MalformedStreamException("Stream ended unexpectedly"); 365 } 366 return nextChunk; 367 } 368 369 370 389 public void setBoundary(byte[] boundary) 390 throws IllegalBoundaryException 391 { 392 if (boundary.length != boundaryLength - 4) 393 { 394 throw new IllegalBoundaryException( 395 "The length of a boundary token can not be changed"); 396 } 397 System.arraycopy(boundary, 0, this.boundary, 4, boundary.length); 398 } 399 400 401 416 public String readHeaders() 417 throws MalformedStreamException 418 { 419 int i = 0; 420 byte b[] = new byte[1]; 421 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 423 int sizeMax = HEADER_PART_SIZE_MAX; 424 int size = 0; 425 while (i < 4) 426 { 427 try 428 { 429 b[0] = readByte(); 430 } 431 catch (IOException e) 432 { 433 throw new MalformedStreamException("Stream ended unexpectedly"); 434 } 435 size++; 436 if (b[0] == HEADER_SEPARATOR[i]) 437 { 438 i++; 439 } 440 else 441 { 442 i = 0; 443 } 444 if (size <= sizeMax) 445 { 446 baos.write(b[0]); 447 } 448 } 449 450 String headers = null; 451 if (headerEncoding != null) 452 { 453 try 454 { 455 headers = baos.toString(headerEncoding); 456 } 457 catch (UnsupportedEncodingException e) 458 { 459 headers = baos.toString(); 462 } 463 } 464 else 465 { 466 headers = baos.toString(); 467 } 468 469 return headers; 470 } 471 472 473 489 public int readBodyData(OutputStream output) 490 throws MalformedStreamException, 491 IOException 492 { 493 boolean done = false; 494 int pad; 495 int pos; 496 int bytesRead; 497 int total = 0; 498 while (!done) 499 { 500 pos = findSeparator(); 502 if (pos != -1) 503 { 504 output.write(buffer, head, pos - head); 506 total += pos - head; 507 head = pos; 508 done = true; 509 } 510 else 511 { 512 if (tail - head > keepRegion) 515 { 516 pad = keepRegion; 517 } 518 else 519 { 520 pad = tail - head; 521 } 522 output.write(buffer, head, tail - head - pad); 524 525 total += tail - head - pad; 527 System.arraycopy(buffer, tail - pad, buffer, 0, pad); 528 529 head = 0; 531 bytesRead = input.read(buffer, pad, bufSize - pad); 532 533 if (bytesRead != -1) 535 { 536 tail = pad + bytesRead; 537 } 538 else 539 { 540 output.write(buffer, 0, pad); 544 output.flush(); 545 total += pad; 546 throw new MalformedStreamException( 547 "Stream ended unexpectedly"); 548 } 549 } 550 } 551 output.flush(); 552 return total; 553 } 554 555 556 568 public int discardBodyData() 569 throws MalformedStreamException, 570 IOException 571 { 572 boolean done = false; 573 int pad; 574 int pos; 575 int bytesRead; 576 int total = 0; 577 while (!done) 578 { 579 pos = findSeparator(); 581 if (pos != -1) 582 { 583 total += pos - head; 585 head = pos; 586 done = true; 587 } 588 else 589 { 590 if (tail - head > keepRegion) 593 { 594 pad = keepRegion; 595 } 596 else 597 { 598 pad = tail - head; 599 } 600 total += tail - head - pad; 601 602 System.arraycopy(buffer, tail - pad, buffer, 0, pad); 604 605 head = 0; 607 bytesRead = input.read(buffer, pad, bufSize - pad); 608 609 if (bytesRead != -1) 611 { 612 tail = pad + bytesRead; 613 } 614 else 615 { 616 total += pad; 620 throw new MalformedStreamException( 621 "Stream ended unexpectedly"); 622 } 623 } 624 } 625 return total; 626 } 627 628 629 637 public boolean skipPreamble() 638 throws IOException 639 { 640 System.arraycopy(boundary, 2, boundary, 0, boundary.length - 2); 642 boundaryLength = boundary.length - 2; 643 try 644 { 645 discardBodyData(); 647 648 return readBoundary(); 651 } 652 catch (MalformedStreamException e) 653 { 654 return false; 655 } 656 finally 657 { 658 System.arraycopy(boundary, 0, boundary, 2, boundary.length - 2); 660 boundaryLength = boundary.length; 661 boundary[0] = 0x0D; 662 boundary[1] = 0x0A; 663 } 664 } 665 666 667 678 public static boolean arrayequals(byte[] a, 679 byte[] b, 680 int count) 681 { 682 for (int i = 0; i < count; i++) 683 { 684 if (a[i] != b[i]) 685 { 686 return false; 687 } 688 } 689 return true; 690 } 691 692 693 703 protected int findByte(byte value, 704 int pos) 705 { 706 for (int i = pos; i < tail; i++) 707 { 708 if (buffer[i] == value) 709 { 710 return i; 711 } 712 } 713 714 return -1; 715 } 716 717 718 726 protected int findSeparator() 727 { 728 int first; 729 int match = 0; 730 int maxpos = tail - boundaryLength; 731 for (first = head; 732 (first <= maxpos) && (match != boundaryLength); 733 first++) 734 { 735 first = findByte(boundary[0], first); 736 if (first == -1 || (first > maxpos)) 737 { 738 return -1; 739 } 740 for (match = 1; match < boundaryLength; match++) 741 { 742 if (buffer[first + match] != boundary[match]) 743 { 744 break; 745 } 746 } 747 } 748 if (match == boundaryLength) 749 { 750 return first - 1; 751 } 752 return -1; 753 } 754 755 760 public String toString() 761 { 762 StringBuffer sbTemp = new StringBuffer (); 763 sbTemp.append("boundary='"); 764 sbTemp.append(String.valueOf(boundary)); 765 sbTemp.append("'\nbufSize="); 766 sbTemp.append(bufSize); 767 return sbTemp.toString(); 768 } 769 770 774 public class MalformedStreamException 775 extends IOException 776 { 777 781 public MalformedStreamException() 782 { 783 super(); 784 } 785 786 792 public MalformedStreamException(String message) 793 { 794 super(message); 795 } 796 } 797 798 799 802 public class IllegalBoundaryException 803 extends IOException 804 { 805 809 public IllegalBoundaryException() 810 { 811 super(); 812 } 813 814 820 public IllegalBoundaryException(String message) 821 { 822 super(message); 823 } 824 } 825 826 827 829 830 892 } 893 | Popular Tags |