MultipartStream.java
上传用户:u_thks
上传日期:2022-07-31
资源大小:1910k
文件大小:17k
源码类别:

WEB源码(ASP,PHP,...)

开发平台:

Java

  1. package com.gamvan.fileUpload;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.OutputStream;
  6. import java.io.UnsupportedEncodingException;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpSession;
  9. import com.gamvan.tools.TypeChange;
  10. public class MultipartStream{
  11.     /**
  12.      * 取当前读取进度
  13.      */
  14.     private long readsBytes = 0;
  15.     
  16.     /**
  17.      * The maximum length of <code>header-part</code> that will be
  18.      * processed (10 kilobytes = 10240 bytes.).
  19.      */
  20.     public static final int HEADER_PART_SIZE_MAX = 10240;
  21.     
  22.     /**
  23.      * The default length of the buffer used for processing a request.
  24.      */
  25.     protected static final int DEFAULT_BUFSIZE = 4096;
  26.     /**
  27.      * A byte sequence that marks the end of <code>header-part</code>
  28.      * (<code>CRLFCRLF</code>).
  29.      */
  30.     protected static final byte[] HEADER_SEPARATOR = {0x0D, 0x0A, 0x0D, 0x0A};
  31.     /**
  32.      * A byte sequence that that follows a delimiter that will be
  33.      * followed by an encapsulation (<code>CRLF</code>).
  34.      */
  35.     protected static final byte[] FIELD_SEPARATOR = { 0x0D, 0x0A };
  36.     /**
  37.      * A byte sequence that that follows a delimiter of the last
  38.      * encapsulation in the stream (<code>--</code>).
  39.      */
  40.     protected static final byte[] STREAM_TERMINATOR = { 0x2D, 0x2D };
  41.     /**
  42.      * The input stream from which data is read.
  43.      */
  44.     private InputStream input;
  45.     /**
  46.      * The length of the boundary token plus the leading <code>CRLF--</code>.
  47.      */
  48.     private int boundaryLength;
  49.     /**
  50.      * The amount of data, in bytes, that must be kept in the buffer in order
  51.      * to detect delimiters reliably.
  52.      */
  53.     private int keepRegion;
  54.     /**
  55.      * The byte sequence that partitions the stream.
  56.      */
  57.     private byte[] boundary;
  58.     /**
  59.      * The length of the buffer used for processing the request.
  60.      */
  61.     private int bufSize;
  62.     /**
  63.      * The buffer used for processing the request.
  64.      */
  65.     private byte[] buffer;
  66.     /**
  67.      * The index of first valid character in the buffer.
  68.      * <br>
  69.      * 0 <= head < bufSize
  70.      */
  71.     private int head;
  72.     /**
  73.      * The index of last valid characer in the buffer + 1.
  74.      * <br>
  75.      * 0 <= tail <= bufSize
  76.      */
  77.     private int tail;
  78.     /**
  79.      * The content encoding to use when reading headers.
  80.      */
  81.     private String headerEncoding;
  82.     /**
  83.      * Default constructor.
  84.      *
  85.      * @see #MultipartStream(InputStream, byte[], int)
  86.      * @see #MultipartStream(InputStream, byte[])
  87.      *
  88.      */
  89.     public MultipartStream()
  90.     {
  91.     }
  92.     public MultipartStream(InputStream input, byte[] boundary,int bufSize){
  93.         this.input = input;
  94.         this.bufSize = bufSize;
  95.         this.buffer = new byte[bufSize];
  96.         // We prepend CR/LF to the boundary to chop trailng CR/LF from
  97.         // body-data tokens.
  98.         this.boundary = new byte[boundary.length + 4];
  99.         this.boundaryLength = boundary.length + 4;
  100.         this.keepRegion = boundary.length + 3;
  101.         this.boundary[0] = 0x0D;
  102.         this.boundary[1] = 0x0A;
  103.         this.boundary[2] = 0x2D;
  104.         this.boundary[3] = 0x2D;
  105.         System.arraycopy(boundary, 0, this.boundary, 4, boundary.length);
  106.         head = 0;
  107.         tail = 0;
  108.     }
  109.     public MultipartStream(InputStream input, byte[] boundary) throws IOException{
  110.         this(input, boundary, DEFAULT_BUFSIZE);
  111.     }
  112.     
  113.     public String getHeaderEncoding(){
  114.         return headerEncoding;
  115.     }
  116.     
  117.     public void setHeaderEncoding(String encoding){
  118.         headerEncoding = encoding;
  119.     }
  120.     
  121.     public byte readByte() throws IOException{
  122.         // Buffer depleted ?
  123.         if (head == tail){
  124.             head = 0;
  125.             // Refill.
  126.             tail = input.read(buffer, head, bufSize);
  127.             if (tail == -1){
  128.                 // No more data available.
  129.                 throw new IOException("No more data is available");
  130.             }
  131.         }
  132.         return buffer[head++];
  133.     }
  134.     
  135.     /**
  136.      * 
  137.      * @return
  138.      * @throws MalformedStreamException
  139.      */
  140.     public boolean readBoundary() throws MalformedStreamException{
  141.         byte[] marker = new byte[2];
  142.         boolean nextChunk = false;
  143.         head += boundaryLength;
  144.         try{
  145.             marker[0] = readByte();
  146.             marker[1] = readByte();
  147.             if (arrayequals(marker, STREAM_TERMINATOR, 2)){
  148.                 nextChunk = false;
  149.             }else if (arrayequals(marker, FIELD_SEPARATOR, 2)){
  150.                 nextChunk = true;
  151.             }else{
  152.                 throw new MalformedStreamException(
  153.                         "Unexpected characters follow a boundary");
  154.             }
  155.         }
  156.         catch (IOException e)
  157.         {
  158.             throw new MalformedStreamException("Stream ended unexpectedly");
  159.         }
  160.         return nextChunk;
  161.     }
  162.     
  163.     
  164.     
  165.     public void setBoundary(byte[] boundary) //设置边界
  166.         throws IllegalBoundaryException
  167.     {
  168.         if (boundary.length != boundaryLength - 4){
  169.             throw new IllegalBoundaryException("The length of a boundary token can not be changed");
  170.         }
  171.         System.arraycopy(boundary, 0, this.boundary, 4, boundary.length);
  172.     }
  173.     
  174. /*
  175.  * 
  176.  * 
  177.  * 
  178.  */    
  179.     public String readHeaders() throws MalformedStreamException{
  180.         int i = 0;
  181.         byte b[] = new byte[1];
  182.         // to support multi-byte characters
  183.         ByteArrayOutputStream baos = new ByteArrayOutputStream();
  184.         int sizeMax = HEADER_PART_SIZE_MAX;
  185.         int size = 0;
  186.         while (i < 4){
  187.             try{
  188.                 b[0] = readByte();
  189.             }catch (IOException e){
  190.                 throw new MalformedStreamException("Stream ended unexpectedly");
  191.             }
  192.             size++; //当前读取字节数
  193.             readsBytes += size; //读取进度 
  194.             
  195.             if (b[0] == HEADER_SEPARATOR[i]){
  196.                 i++;
  197.             }else{
  198.                 i = 0;
  199.             }
  200.             if (size <= sizeMax){
  201.                 baos.write(b[0]);
  202.             }
  203.         }
  204.         String headers = null;
  205.         if (headerEncoding != null){
  206.             try{
  207.                 headers = baos.toString(headerEncoding);
  208.                 
  209.             }catch (UnsupportedEncodingException e){
  210.                 // Fall back to platform default if specified encoding is not
  211.                 // supported.
  212.                 headers = baos.toString();
  213.             }
  214.         }else{
  215.             headers = baos.toString();
  216.         }
  217.         return headers;
  218.     }
  219.     
  220.     public int readBodyData(OutputStream output,HttpServletRequest req) throws MalformedStreamException, IOException{
  221.         boolean done = false;
  222.         int pad;
  223.         int pos;
  224.         int bytesRead;
  225.         int total = 0;
  226.         
  227.         HttpSession session = req.getSession();
  228.         
  229.         while (!done)
  230.         {
  231.             // Is boundary token present somewere in the buffer?
  232.             pos = findSeparator();
  233.             if (pos != -1)
  234.             {
  235.                 // Write the rest of the data before the boundary.
  236.                 output.write(buffer, head, pos - head);
  237.                 total += pos - head;
  238.                 head = pos;
  239.                 done = true;
  240.             }
  241.             else
  242.             {
  243.                 // Determine how much data should be kept in the
  244.                 // buffer.
  245.                 if (tail - head > keepRegion)
  246.                 {
  247.                     pad = keepRegion;
  248.                 }
  249.                 else
  250.                 {
  251.                     pad = tail - head;
  252.                 }
  253.                 // Write out the data belonging to the body-data.
  254.                 output.write(buffer, head, tail - head - pad);
  255.                 // Move the data to the beging of the buffer.
  256.                 
  257.                 total += tail - head - pad;
  258.                 System.arraycopy(buffer, tail - pad, buffer, 0, pad);
  259.                 
  260.                //if(readsBytes==0)
  261.                 //readsBytes = total; //当前读取的字节数。
  262.                 
  263.                 // Refill buffer with new data.
  264.                 head = 0;
  265.                 bytesRead = input.read(buffer, pad, bufSize - pad);
  266.                 if (bytesRead != -1)
  267.                 {
  268.                     tail = pad + bytesRead;
  269.                 }
  270.                 else
  271.                 {
  272.                     // The last pad amount is left in the buffer.
  273.                     // Boundary can't be in there so write out the
  274.                     // data you have and signal an error condition.
  275.                     output.write(buffer, 0, pad);
  276.                     output.flush();
  277.                     total += pad;
  278.                     throw new MalformedStreamException(
  279.                             "Stream ended unexpectedly");
  280.                 }
  281.             }
  282.             /************************************
  283.              * 读取进度
  284.              ************************************/
  285.             session.setAttribute("readsBytes", TypeChange.longToString(total));
  286.             /***************************************/ 
  287.         }
  288.         output.flush();
  289.         readsBytes = total;
  290.         return total;
  291.     }
  292.     
  293.     /**
  294.      * 
  295.      * @return
  296.      * @throws MalformedStreamException
  297.      * @throws IOException
  298.      */
  299.     public int discardBodyData() throws MalformedStreamException,IOException{
  300.         boolean done = false;
  301.         int pad;
  302.         int pos;
  303.         int bytesRead;
  304.         int total = 0;
  305.         while (!done){
  306.             // Is boundary token present somewere in the buffer?
  307.             pos = findSeparator();
  308.             if (pos != -1){
  309.                 // Write the rest of the data before the boundary.
  310.                 total += pos - head;
  311.                 head = pos;
  312.                 done = true;
  313.             }else{
  314.                 // Determine how much data should be kept in the
  315.                 // buffer.
  316.                 if (tail - head > keepRegion)
  317.                 {
  318.                     pad = keepRegion;
  319.                 }
  320.                 else
  321.                 {
  322.                     pad = tail - head;
  323.                 }
  324.                 total += tail - head - pad;
  325.                 // Move the data to the beging of the buffer.
  326.                 System.arraycopy(buffer, tail - pad, buffer, 0, pad);
  327.                 // Refill buffer with new data.
  328.                 head = 0;
  329.                 bytesRead = input.read(buffer, pad, bufSize - pad);
  330.              
  331.                 if (bytesRead != -1)
  332.                 {
  333.                     tail = pad + bytesRead;
  334.                 }
  335.                 else
  336.                 {
  337.                     // The last pad amount is left in the buffer.
  338.                     // Boundary can't be in there so signal an error
  339.                     // condition.
  340.                     total += pad;
  341.                     throw new MalformedStreamException(
  342.                             "Stream ended unexpectedly");
  343.                 }
  344.             }
  345.         }
  346.         readsBytes = total;
  347.         return total;
  348.     }
  349.     
  350.     
  351.     /**
  352.      * 
  353.      * @return
  354.      * @throws IOException
  355.      */
  356.     public boolean skipPreamble() throws IOException{
  357.         // First delimiter may be not preceeded with a CRLF.
  358.         System.arraycopy(boundary, 2, boundary, 0, boundary.length - 2);
  359.         boundaryLength = boundary.length - 2;
  360.         try{
  361.             // Discard all data up to the delimiter. 分隔符
  362.             discardBodyData();
  363.             // Read boundary - if succeded, the stream contains an
  364.             // encapsulation.
  365.             return readBoundary();
  366.         }catch (MalformedStreamException e){
  367.             return false;
  368.         }
  369.         finally{
  370.             // Restore delimiter.
  371.             System.arraycopy(boundary, 0, boundary, 2, boundary.length - 2);
  372.             boundaryLength = boundary.length;
  373.             boundary[0] = 0x0D;
  374.             boundary[1] = 0x0A;
  375.         }
  376.     }
  377.     
  378.     
  379.     public static boolean arrayequals(byte[] a, byte[] b, int count){
  380.         for (int i = 0; i < count; i++)
  381.         {
  382.             if (a[i] != b[i])
  383.             {
  384.                 return false;
  385.             }
  386.         }
  387.         return true;
  388.     }
  389.     
  390.     
  391.     
  392.     protected int findByte(byte value,int pos){
  393.         for (int i = pos; i < tail; i++)
  394.         {
  395.             if (buffer[i] == value)
  396.             {
  397.                 return i;
  398.             }
  399.         }
  400.         return -1;
  401.     }
  402.     
  403.     
  404.     
  405.     protected int findSeparator() {
  406.         int first;
  407.         int match = 0;
  408.         int maxpos = tail - boundaryLength;
  409.         for (first = head;
  410.              (first <= maxpos) && (match != boundaryLength);
  411.              first++)
  412.         {
  413.             first = findByte(boundary[0], first);
  414.             if (first == -1 || (first > maxpos))
  415.             {
  416.                 return -1;
  417.             }
  418.             for (match = 1; match < boundaryLength; match++)
  419.             {
  420.                 if (buffer[first + match] != boundary[match])
  421.                 {
  422.                     break;
  423.                 }
  424.             }
  425.         }
  426.         if (match == boundaryLength)
  427.         {
  428.             return first - 1;
  429.         }
  430.         return -1;
  431.     }
  432.     
  433.     
  434.     public String toString(){
  435.         StringBuffer sbTemp = new StringBuffer();
  436.         sbTemp.append("boundary='");
  437.         sbTemp.append(String.valueOf(boundary));
  438.         sbTemp.append("'nbufSize=");
  439.         sbTemp.append(bufSize);
  440.         return sbTemp.toString();
  441.     }
  442.     
  443.     
  444.     public class MalformedStreamException extends IOException {
  445.         /**
  446.          * Constructs a <code>MalformedStreamException</code> with no
  447.          * detail message.
  448.          */
  449.         public MalformedStreamException()
  450.         {
  451.             super();
  452.         }
  453.         /**
  454.          * Constructs an <code>MalformedStreamException</code> with
  455.          * the specified detail message.
  456.          *
  457.          * @param message The detail message.
  458.          */
  459.         public MalformedStreamException(String message)
  460.         {
  461.             super(message);
  462.         }
  463.     }
  464.    
  465.     public class IllegalBoundaryException extends IOException {
  466.         /**
  467.          * Constructs an <code>IllegalBoundaryException</code> with no
  468.          * detail message.
  469.          */
  470.         public IllegalBoundaryException()
  471.         {
  472.             super();
  473.         }
  474.         /**
  475.          * Constructs an <code>IllegalBoundaryException</code> with
  476.          * the specified detail message.
  477.          *
  478.          * @param message The detail message.
  479.          */
  480.         public IllegalBoundaryException(String message)
  481.         {
  482.             super(message);
  483.         }
  484.     }
  485.     /**
  486.      * 读取进度
  487.      */
  488.     public long getReadsBytes(){
  489.         return this.readsBytes;
  490.     }
  491.     
  492.     // ------------------------------------------------------ Debugging methods
  493.     // These are the methods that were used to debug this stuff.
  494.     /*
  495.     // Dump data.
  496.     protected void dump()
  497.     {
  498.         System.out.println("01234567890");
  499.         byte[] temp = new byte[buffer.length];
  500.         for(int i=0; i<buffer.length; i++)
  501.         {
  502.             if (buffer[i] == 0x0D || buffer[i] == 0x0A)
  503.             {
  504.                 temp[i] = 0x21;
  505.             }
  506.             else
  507.             {
  508.                 temp[i] = buffer[i];
  509.             }
  510.         }
  511.         System.out.println(new String(temp));
  512.         int i;
  513.         for (i=0; i<head; i++)
  514.             System.out.print(" ");
  515.         System.out.println("h");
  516.         for (i=0; i<tail; i++)
  517.             System.out.print(" ");
  518.         System.out.println("t");
  519.         System.out.flush();
  520.     }
  521.     // Main routine, for testing purposes only.
  522.     //
  523.     // @param args A String[] with the command line arguments.
  524.     // @exception Exception, a generic exception.
  525.     public static void main( String[] args )
  526.         throws Exception
  527.     {
  528.         File boundaryFile = new File("boundary.dat");
  529.         int boundarySize = (int)boundaryFile.length();
  530.         byte[] boundary = new byte[boundarySize];
  531.         FileInputStream input = new FileInputStream(boundaryFile);
  532.         input.read(boundary,0,boundarySize);
  533.         input = new FileInputStream("multipart.dat");
  534.         MultipartStream chunks = new MultipartStream(input, boundary);
  535.         int i = 0;
  536.         String header;
  537.         OutputStream output;
  538.         boolean nextChunk = chunks.skipPreamble();
  539.         while (nextChunk)
  540.         {
  541.             header = chunks.readHeaders();
  542.             System.out.println("!"+header+"!");
  543.             System.out.println("wrote part"+i+".dat");
  544.             output = new FileOutputStream("part"+(i++)+".dat");
  545.             chunks.readBodyData(output);
  546.             nextChunk = chunks.readBoundary();
  547.         }
  548.     }
  549.     */
  550. }