00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 package org.apache.commons.fileupload;
00064
00065
00066 import java.io.ByteArrayOutputStream;
00067 import java.io.IOException;
00068 import java.io.InputStream;
00069 import java.io.OutputStream;
00070 import java.io.UnsupportedEncodingException;
00071
00072
00134 public class MultipartStream
00135 {
00136
00137
00138
00139
00144 public static final int HEADER_PART_SIZE_MAX = 10240;
00145
00146
00150 protected static final int DEFAULT_BUFSIZE = 4096;
00151
00152
00157 protected static final byte[] HEADER_SEPARATOR = {0x0D, 0x0A, 0x0D, 0x0A};
00158
00159
00164 protected static final byte[] FIELD_SEPARATOR = { 0x0D, 0x0A };
00165
00166
00171 protected static final byte[] STREAM_TERMINATOR = { 0x2D, 0x2D };
00172
00173
00174
00175
00176
00180 private InputStream input;
00181
00182
00186 private int boundaryLength;
00187
00188
00193 private int keepRegion;
00194
00195
00199 private byte[] boundary;
00200
00201
00205 private int bufSize;
00206
00207
00211 private byte[] buffer;
00212
00213
00219 private int head;
00220
00221
00227 private int tail;
00228
00229
00233 private String headerEncoding;
00234
00235
00236
00237
00238
00246 public MultipartStream()
00247 {
00248 }
00249
00250
00269 public MultipartStream(InputStream input,
00270 byte[] boundary,
00271 int bufSize)
00272 {
00273 this.input = input;
00274 this.bufSize = bufSize;
00275 this.buffer = new byte[bufSize];
00276
00277
00278
00279 this.boundary = new byte[boundary.length + 4];
00280 this.boundaryLength = boundary.length + 4;
00281 this.keepRegion = boundary.length + 3;
00282 this.boundary[0] = 0x0D;
00283 this.boundary[1] = 0x0A;
00284 this.boundary[2] = 0x2D;
00285 this.boundary[3] = 0x2D;
00286 System.arraycopy(boundary, 0, this.boundary, 4, boundary.length);
00287
00288 head = 0;
00289 tail = 0;
00290 }
00291
00292
00306 public MultipartStream(InputStream input,
00307 byte[] boundary)
00308 throws IOException
00309 {
00310 this(input, boundary, DEFAULT_BUFSIZE);
00311 }
00312
00313
00314
00315
00316
00325 public String getHeaderEncoding()
00326 {
00327 return headerEncoding;
00328 }
00329
00330
00338 public void setHeaderEncoding(String encoding)
00339 {
00340 headerEncoding = encoding;
00341 }
00342
00343
00352 public byte readByte()
00353 throws IOException
00354 {
00355
00356 if (head == tail)
00357 {
00358 head = 0;
00359
00360 tail = input.read(buffer, head, bufSize);
00361 if (tail == -1)
00362 {
00363
00364 throw new IOException("No more data is available");
00365 }
00366 }
00367 return buffer[head++];
00368 }
00369
00370
00381 public boolean readBoundary()
00382 throws MalformedStreamException
00383 {
00384 byte[] marker = new byte[2];
00385 boolean nextChunk = false;
00386
00387 head += boundaryLength;
00388 try
00389 {
00390 marker[0] = readByte();
00391 marker[1] = readByte();
00392 if (arrayequals(marker, STREAM_TERMINATOR, 2))
00393 {
00394 nextChunk = false;
00395 }
00396 else if (arrayequals(marker, FIELD_SEPARATOR, 2))
00397 {
00398 nextChunk = true;
00399 }
00400 else
00401 {
00402 throw new MalformedStreamException(
00403 "Unexpected characters follow a boundary");
00404 }
00405 }
00406 catch (IOException e)
00407 {
00408 throw new MalformedStreamException("Stream ended unexpectedly");
00409 }
00410 return nextChunk;
00411 }
00412
00413
00433 public void setBoundary(byte[] boundary)
00434 throws IllegalBoundaryException
00435 {
00436 if (boundary.length != boundaryLength - 4)
00437 {
00438 throw new IllegalBoundaryException(
00439 "The length of a boundary token can not be changed");
00440 }
00441 System.arraycopy(boundary, 0, this.boundary, 4, boundary.length);
00442 }
00443
00444
00460 public String readHeaders()
00461 throws MalformedStreamException
00462 {
00463 int i = 0;
00464 byte b[] = new byte[1];
00465
00466 ByteArrayOutputStream baos = new ByteArrayOutputStream();
00467 int sizeMax = HEADER_PART_SIZE_MAX;
00468 int size = 0;
00469 while (i < 4)
00470 {
00471 try
00472 {
00473 b[0] = readByte();
00474 }
00475 catch (IOException e)
00476 {
00477 throw new MalformedStreamException("Stream ended unexpectedly");
00478 }
00479 size++;
00480 if (b[0] == HEADER_SEPARATOR[i])
00481 {
00482 i++;
00483 }
00484 else
00485 {
00486 i = 0;
00487 }
00488 if (size <= sizeMax)
00489 {
00490 baos.write(b[0]);
00491 }
00492 }
00493
00494 String headers = null;
00495 if (headerEncoding != null)
00496 {
00497 try
00498 {
00499 headers = baos.toString(headerEncoding);
00500 }
00501 catch (UnsupportedEncodingException e)
00502 {
00503
00504
00505 headers = baos.toString();
00506 }
00507 }
00508 else
00509 {
00510 headers = baos.toString();
00511 }
00512
00513 return headers;
00514 }
00515
00516
00533 public int readBodyData(OutputStream output)
00534 throws MalformedStreamException,
00535 IOException
00536 {
00537 boolean done = false;
00538 int pad;
00539 int pos;
00540 int bytesRead;
00541 int total = 0;
00542 while (!done)
00543 {
00544
00545 pos = findSeparator();
00546 if (pos != -1)
00547 {
00548
00549 output.write(buffer, head, pos - head);
00550 total += pos - head;
00551 head = pos;
00552 done = true;
00553 }
00554 else
00555 {
00556
00557
00558 if (tail - head > keepRegion)
00559 {
00560 pad = keepRegion;
00561 }
00562 else
00563 {
00564 pad = tail - head;
00565 }
00566
00567 output.write(buffer, head, tail - head - pad);
00568
00569
00570 total += tail - head - pad;
00571 System.arraycopy(buffer, tail - pad, buffer, 0, pad);
00572
00573
00574 head = 0;
00575 bytesRead = input.read(buffer, pad, bufSize - pad);
00576
00577
00578 if (bytesRead != -1)
00579 {
00580 tail = pad + bytesRead;
00581 }
00582 else
00583 {
00584
00585
00586
00587 output.write(buffer, 0, pad);
00588 output.flush();
00589 total += pad;
00590 throw new MalformedStreamException(
00591 "Stream ended unexpectedly");
00592 }
00593 }
00594 }
00595 output.flush();
00596 return total;
00597 }
00598
00599
00612 public int discardBodyData()
00613 throws MalformedStreamException,
00614 IOException
00615 {
00616 boolean done = false;
00617 int pad;
00618 int pos;
00619 int bytesRead;
00620 int total = 0;
00621 while (!done)
00622 {
00623
00624 pos = findSeparator();
00625 if (pos != -1)
00626 {
00627
00628 total += pos - head;
00629 head = pos;
00630 done = true;
00631 }
00632 else
00633 {
00634
00635
00636 if (tail - head > keepRegion)
00637 {
00638 pad = keepRegion;
00639 }
00640 else
00641 {
00642 pad = tail - head;
00643 }
00644 total += tail - head - pad;
00645
00646
00647 System.arraycopy(buffer, tail - pad, buffer, 0, pad);
00648
00649
00650 head = 0;
00651 bytesRead = input.read(buffer, pad, bufSize - pad);
00652
00653
00654 if (bytesRead != -1)
00655 {
00656 tail = pad + bytesRead;
00657 }
00658 else
00659 {
00660
00661
00662
00663 total += pad;
00664 throw new MalformedStreamException(
00665 "Stream ended unexpectedly");
00666 }
00667 }
00668 }
00669 return total;
00670 }
00671
00672
00681 public boolean skipPreamble()
00682 throws IOException
00683 {
00684
00685 System.arraycopy(boundary, 2, boundary, 0, boundary.length - 2);
00686 boundaryLength = boundary.length - 2;
00687 try
00688 {
00689
00690 discardBodyData();
00691
00692
00693
00694 return readBoundary();
00695 }
00696 catch (MalformedStreamException e)
00697 {
00698 return false;
00699 }
00700 finally
00701 {
00702
00703 System.arraycopy(boundary, 0, boundary, 2, boundary.length - 2);
00704 boundaryLength = boundary.length;
00705 boundary[0] = 0x0D;
00706 boundary[1] = 0x0A;
00707 }
00708 }
00709
00710
00722 public static boolean arrayequals(byte[] a,
00723 byte[] b,
00724 int count)
00725 {
00726 for (int i = 0; i < count; i++)
00727 {
00728 if (a[i] != b[i])
00729 {
00730 return false;
00731 }
00732 }
00733 return true;
00734 }
00735
00736
00747 protected int findByte(byte value,
00748 int pos)
00749 {
00750 for (int i = pos; i < tail; i++)
00751 {
00752 if (buffer[i] == value)
00753 {
00754 return i;
00755 }
00756 }
00757
00758 return -1;
00759 }
00760
00761
00770 protected int findSeparator()
00771 {
00772 int first;
00773 int match = 0;
00774 int maxpos = tail - boundaryLength;
00775 for (first = head;
00776 (first <= maxpos) && (match != boundaryLength);
00777 first++)
00778 {
00779 first = findByte(boundary[0], first);
00780 if (first == -1 || (first > maxpos))
00781 {
00782 return -1;
00783 }
00784 for (match = 1; match < boundaryLength; match++)
00785 {
00786 if (buffer[first + match] != boundary[match])
00787 {
00788 break;
00789 }
00790 }
00791 }
00792 if (match == boundaryLength)
00793 {
00794 return first - 1;
00795 }
00796 return -1;
00797 }
00798
00804 public String toString()
00805 {
00806 StringBuffer sbTemp = new StringBuffer();
00807 sbTemp.append("boundary='");
00808 sbTemp.append(String.valueOf(boundary));
00809 sbTemp.append("'\nbufSize=");
00810 sbTemp.append(bufSize);
00811 return sbTemp.toString();
00812 }
00813
00818 public class MalformedStreamException
00819 extends IOException
00820 {
00825 public MalformedStreamException()
00826 {
00827 super();
00828 }
00829
00836 public MalformedStreamException(String message)
00837 {
00838 super(message);
00839 }
00840 }
00841
00842
00846 public class IllegalBoundaryException
00847 extends IOException
00848 {
00853 public IllegalBoundaryException()
00854 {
00855 super();
00856 }
00857
00864 public IllegalBoundaryException(String message)
00865 {
00866 super(message);
00867 }
00868 }
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936 }