001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.fileupload;
018
019import static java.lang.String.format;
020
021import java.io.ByteArrayOutputStream;
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.OutputStream;
025import java.io.UnsupportedEncodingException;
026
027import org.apache.commons.fileupload.FileUploadBase.FileUploadIOException;
028import org.apache.commons.fileupload.util.Closeable;
029import org.apache.commons.fileupload.util.Streams;
030
031/**
032 * <p> Low level API for processing file uploads.
033 *
034 * <p> This class can be used to process data streams conforming to MIME
035 * 'multipart' format as defined in
036 * <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>. Arbitrarily
037 * large amounts of data in the stream can be processed under constant
038 * memory usage.
039 *
040 * <p> The format of the stream is defined in the following way:<br>
041 *
042 * <code>
043 *   multipart-body := preamble 1*encapsulation close-delimiter epilogue<br>
044 *   encapsulation := delimiter body CRLF<br>
045 *   delimiter := "--" boundary CRLF<br>
046 *   close-delimiter := "--" boundary "--"<br>
047 *   preamble := &lt;ignore&gt;<br>
048 *   epilogue := &lt;ignore&gt;<br>
049 *   body := header-part CRLF body-part<br>
050 *   header-part := 1*header CRLF<br>
051 *   header := header-name ":" header-value<br>
052 *   header-name := &lt;printable ascii characters except ":"&gt;<br>
053 *   header-value := &lt;any ascii characters except CR &amp; LF&gt;<br>
054 *   body-data := &lt;arbitrary data&gt;<br>
055 * </code>
056 *
057 * <p>Note that body-data can contain another mulipart entity.  There
058 * is limited support for single pass processing of such nested
059 * streams.  The nested stream is <strong>required</strong> to have a
060 * boundary token of the same length as the parent stream (see {@link
061 * #setBoundary(byte[])}).
062 *
063 * <p>Here is an example of usage of this class.<br>
064 *
065 * <pre>
066 *   try {
067 *     MultipartStream multipartStream = new MultipartStream(input, boundary);
068 *     boolean nextPart = multipartStream.skipPreamble();
069 *     OutputStream output;
070 *     while(nextPart) {
071 *       String header = multipartStream.readHeaders();
072 *       // process headers
073 *       // create some output stream
074 *       multipartStream.readBodyData(output);
075 *       nextPart = multipartStream.readBoundary();
076 *     }
077 *   } catch(MultipartStream.MalformedStreamException e) {
078 *     // the stream failed to follow required syntax
079 *   } catch(IOException e) {
080 *     // a read or write error occurred
081 *   }
082 * </pre>
083 */
084public class MultipartStream {
085
086    /**
087     * Internal class, which is used to invoke the
088     * {@link ProgressListener}.
089     */
090    public static class ProgressNotifier {
091
092        /**
093         * The listener to invoke.
094         */
095        private final ProgressListener listener;
096
097        /**
098         * Number of expected bytes, if known, or -1.
099         */
100        private final long contentLength;
101
102        /**
103         * Number of bytes, which have been read so far.
104         */
105        private long bytesRead;
106
107        /**
108         * Number of items, which have been read so far.
109         */
110        private int items;
111
112        /**
113         * Creates a new instance with the given listener
114         * and content length.
115         *
116         * @param pListener The listener to invoke.
117         * @param pContentLength The expected content length.
118         */
119        ProgressNotifier(ProgressListener pListener, long pContentLength) {
120            listener = pListener;
121            contentLength = pContentLength;
122        }
123
124        /**
125         * Called to indicate that bytes have been read.
126         *
127         * @param pBytes Number of bytes, which have been read.
128         */
129        void noteBytesRead(int pBytes) {
130            /* Indicates, that the given number of bytes have been read from
131             * the input stream.
132             */
133            bytesRead += pBytes;
134            notifyListener();
135        }
136
137        /**
138         * Called to indicate, that a new file item has been detected.
139         */
140        void noteItem() {
141            ++items;
142            notifyListener();
143        }
144
145        /**
146         * Called for notifying the listener.
147         */
148        private void notifyListener() {
149            if (listener != null) {
150                listener.update(bytesRead, contentLength, items);
151            }
152        }
153
154    }
155
156    // ----------------------------------------------------- Manifest constants
157
158    /**
159     * The Carriage Return ASCII character value.
160     */
161    public static final byte CR = 0x0D;
162
163    /**
164     * The Line Feed ASCII character value.
165     */
166    public static final byte LF = 0x0A;
167
168    /**
169     * The dash (-) ASCII character value.
170     */
171    public static final byte DASH = 0x2D;
172
173    /**
174     * The maximum length of <code>header-part</code> that will be
175     * processed (10 kilobytes = 10240 bytes.).
176     */
177    public static final int HEADER_PART_SIZE_MAX = 10240;
178
179    /**
180     * The default length of the buffer used for processing a request.
181     */
182    protected static final int DEFAULT_BUFSIZE = 4096;
183
184    /**
185     * A byte sequence that marks the end of <code>header-part</code>
186     * (<code>CRLFCRLF</code>).
187     */
188    protected static final byte[] HEADER_SEPARATOR = {CR, LF, CR, LF};
189
190    /**
191     * A byte sequence that that follows a delimiter that will be
192     * followed by an encapsulation (<code>CRLF</code>).
193     */
194    protected static final byte[] FIELD_SEPARATOR = {CR, LF};
195
196    /**
197     * A byte sequence that that follows a delimiter of the last
198     * encapsulation in the stream (<code>--</code>).
199     */
200    protected static final byte[] STREAM_TERMINATOR = {DASH, DASH};
201
202    /**
203     * A byte sequence that precedes a boundary (<code>CRLF--</code>).
204     */
205    protected static final byte[] BOUNDARY_PREFIX = {CR, LF, DASH, DASH};
206
207    // ----------------------------------------------------------- Data members
208
209    /**
210     * The input stream from which data is read.
211     */
212    private final InputStream input;
213
214    /**
215     * The length of the boundary token plus the leading <code>CRLF--</code>.
216     */
217    private int boundaryLength;
218
219    /**
220     * The amount of data, in bytes, that must be kept in the buffer in order
221     * to detect delimiters reliably.
222     */
223    private final int keepRegion;
224
225    /**
226     * The byte sequence that partitions the stream.
227     */
228    private final byte[] boundary;
229
230    /**
231     * The table for Knuth-Morris-Pratt search algorithm.
232     */
233    private final int[] boundaryTable;
234
235    /**
236     * The length of the buffer used for processing the request.
237     */
238    private final int bufSize;
239
240    /**
241     * The buffer used for processing the request.
242     */
243    private final byte[] buffer;
244
245    /**
246     * The index of first valid character in the buffer.
247     * <br>
248     * 0 <= head < bufSize
249     */
250    private int head;
251
252    /**
253     * The index of last valid character in the buffer + 1.
254     * <br>
255     * 0 <= tail <= bufSize
256     */
257    private int tail;
258
259    /**
260     * The content encoding to use when reading headers.
261     */
262    private String headerEncoding;
263
264    /**
265     * The progress notifier, if any, or null.
266     */
267    private final ProgressNotifier notifier;
268
269    // ----------------------------------------------------------- Constructors
270
271    /**
272     * Creates a new instance.
273     *
274     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int,
275     * ProgressNotifier)}
276     */
277    @Deprecated
278    public MultipartStream() {
279        this(null, null, null);
280    }
281
282    /**
283     * <p> Constructs a <code>MultipartStream</code> with a custom size buffer
284     * and no progress notifier.
285     *
286     * <p> Note that the buffer must be at least big enough to contain the
287     * boundary string, plus 4 characters for CR/LF and double dash, plus at
288     * least one byte of data.  Too small a buffer size setting will degrade
289     * performance.
290     *
291     * @param input    The <code>InputStream</code> to serve as a data source.
292     * @param boundary The token used for dividing the stream into
293     *                 <code>encapsulations</code>.
294     * @param bufSize  The size of the buffer to be used, in bytes.
295     *
296     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int,
297     * ProgressNotifier)}.
298     */
299    @Deprecated
300    public MultipartStream(InputStream input, byte[] boundary, int bufSize) {
301        this(input, boundary, bufSize, null);
302    }
303
304    /**
305     * <p> Constructs a <code>MultipartStream</code> with a custom size buffer.
306     *
307     * <p> Note that the buffer must be at least big enough to contain the
308     * boundary string, plus 4 characters for CR/LF and double dash, plus at
309     * least one byte of data.  Too small a buffer size setting will degrade
310     * performance.
311     *
312     * @param input    The <code>InputStream</code> to serve as a data source.
313     * @param boundary The token used for dividing the stream into
314     *                 <code>encapsulations</code>.
315     * @param bufSize  The size of the buffer to be used, in bytes.
316     * @param pNotifier The notifier, which is used for calling the
317     *                  progress listener, if any.
318     *
319     * @throws IllegalArgumentException If the buffer size is too small
320     *
321     * @since 1.3.1
322     */
323    public MultipartStream(InputStream input,
324            byte[] boundary,
325            int bufSize,
326            ProgressNotifier pNotifier) {
327
328        if (boundary == null) {
329            throw new IllegalArgumentException("boundary may not be null");
330        }
331        // We prepend CR/LF to the boundary to chop trailing CR/LF from
332        // body-data tokens.
333        this.boundaryLength = boundary.length + BOUNDARY_PREFIX.length;
334        if (bufSize < this.boundaryLength + 1) {
335            throw new IllegalArgumentException(
336                    "The buffer size specified for the MultipartStream is too small");
337        }
338
339        this.input = input;
340        this.bufSize = Math.max(bufSize, boundaryLength * 2);
341        this.buffer = new byte[this.bufSize];
342        this.notifier = pNotifier;
343
344        this.boundary = new byte[this.boundaryLength];
345        this.boundaryTable = new int[this.boundaryLength + 1];
346        this.keepRegion = this.boundary.length;
347
348        System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0,
349                BOUNDARY_PREFIX.length);
350        System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length,
351                boundary.length);
352        computeBoundaryTable();
353
354        head = 0;
355        tail = 0;
356    }
357
358    /**
359     * <p> Constructs a <code>MultipartStream</code> with a default size buffer.
360     *
361     * @param input    The <code>InputStream</code> to serve as a data source.
362     * @param boundary The token used for dividing the stream into
363     *                 <code>encapsulations</code>.
364     * @param pNotifier An object for calling the progress listener, if any.
365     *
366     *
367     * @see #MultipartStream(InputStream, byte[], int, ProgressNotifier)
368     */
369    MultipartStream(InputStream input,
370            byte[] boundary,
371            ProgressNotifier pNotifier) {
372        this(input, boundary, DEFAULT_BUFSIZE, pNotifier);
373    }
374
375    /**
376     * <p> Constructs a <code>MultipartStream</code> with a default size buffer.
377     *
378     * @param input    The <code>InputStream</code> to serve as a data source.
379     * @param boundary The token used for dividing the stream into
380     *                 <code>encapsulations</code>.
381     *
382     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int,
383     *  ProgressNotifier)}.
384     */
385    @Deprecated
386    public MultipartStream(InputStream input,
387            byte[] boundary) {
388        this(input, boundary, DEFAULT_BUFSIZE, null);
389    }
390
391    // --------------------------------------------------------- Public methods
392
393    /**
394     * Retrieves the character encoding used when reading the headers of an
395     * individual part. When not specified, or <code>null</code>, the platform
396     * default encoding is used.
397     *
398     * @return The encoding used to read part headers.
399     */
400    public String getHeaderEncoding() {
401        return headerEncoding;
402    }
403
404    /**
405     * Specifies the character encoding to be used when reading the headers of
406     * individual parts. When not specified, or <code>null</code>, the platform
407     * default encoding is used.
408     *
409     * @param encoding The encoding used to read part headers.
410     */
411    public void setHeaderEncoding(String encoding) {
412        headerEncoding = encoding;
413    }
414
415    /**
416     * Reads a byte from the <code>buffer</code>, and refills it as
417     * necessary.
418     *
419     * @return The next byte from the input stream.
420     *
421     * @throws IOException if there is no more data available.
422     */
423    public byte readByte() throws IOException {
424        // Buffer depleted ?
425        if (head == tail) {
426            head = 0;
427            // Refill.
428            tail = input.read(buffer, head, bufSize);
429            if (tail == -1) {
430                // No more data available.
431                throw new IOException("No more data is available");
432            }
433            if (notifier != null) {
434                notifier.noteBytesRead(tail);
435            }
436        }
437        return buffer[head++];
438    }
439
440    /**
441     * Skips a <code>boundary</code> token, and checks whether more
442     * <code>encapsulations</code> are contained in the stream.
443     *
444     * @return <code>true</code> if there are more encapsulations in
445     *         this stream; <code>false</code> otherwise.
446     *
447     * @throws FileUploadIOException if the bytes read from the stream exceeded the size limits
448     * @throws MalformedStreamException if the stream ends unexpectedly or
449     *                                  fails to follow required syntax.
450     */
451    public boolean readBoundary()
452            throws FileUploadIOException, MalformedStreamException {
453        byte[] marker = new byte[2];
454        boolean nextChunk = false;
455
456        head += boundaryLength;
457        try {
458            marker[0] = readByte();
459            if (marker[0] == LF) {
460                // Work around IE5 Mac bug with input type=image.
461                // Because the boundary delimiter, not including the trailing
462                // CRLF, must not appear within any file (RFC 2046, section
463                // 5.1.1), we know the missing CR is due to a buggy browser
464                // rather than a file containing something similar to a
465                // boundary.
466                return true;
467            }
468
469            marker[1] = readByte();
470            if (arrayequals(marker, STREAM_TERMINATOR, 2)) {
471                nextChunk = false;
472            } else if (arrayequals(marker, FIELD_SEPARATOR, 2)) {
473                nextChunk = true;
474            } else {
475                throw new MalformedStreamException(
476                "Unexpected characters follow a boundary");
477            }
478        } catch (FileUploadIOException e) {
479            // wraps a SizeException, re-throw as it will be unwrapped later
480            throw e;
481        } catch (IOException e) {
482            throw new MalformedStreamException("Stream ended unexpectedly");
483        }
484        return nextChunk;
485    }
486
487    /**
488     * <p>Changes the boundary token used for partitioning the stream.
489     *
490     * <p>This method allows single pass processing of nested multipart
491     * streams.
492     *
493     * <p>The boundary token of the nested stream is <code>required</code>
494     * to be of the same length as the boundary token in parent stream.
495     *
496     * <p>Restoring the parent stream boundary token after processing of a
497     * nested stream is left to the application.
498     *
499     * @param boundary The boundary to be used for parsing of the nested
500     *                 stream.
501     *
502     * @throws IllegalBoundaryException if the <code>boundary</code>
503     *                                  has a different length than the one
504     *                                  being currently parsed.
505     */
506    public void setBoundary(byte[] boundary)
507            throws IllegalBoundaryException {
508        if (boundary.length != boundaryLength - BOUNDARY_PREFIX.length) {
509            throw new IllegalBoundaryException(
510            "The length of a boundary token cannot be changed");
511        }
512        System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length,
513                boundary.length);
514        computeBoundaryTable();
515    }
516
517    /**
518     * Compute the table used for Knuth-Morris-Pratt search algorithm.
519     */
520    private void computeBoundaryTable() {
521        int position = 2;
522        int candidate = 0;
523
524        boundaryTable[0] = -1;
525        boundaryTable[1] = 0;
526
527        while (position <= boundaryLength) {
528            if (boundary[position - 1] == boundary[candidate]) {
529                boundaryTable[position] = candidate + 1;
530                candidate++;
531                position++;
532            } else if (candidate > 0) {
533                candidate = boundaryTable[candidate];
534            } else {
535                boundaryTable[position] = 0;
536                position++;
537            }
538        }
539    }
540
541    /**
542     * <p>Reads the <code>header-part</code> of the current
543     * <code>encapsulation</code>.
544     *
545     * <p>Headers are returned verbatim to the input stream, including the
546     * trailing <code>CRLF</code> marker. Parsing is left to the
547     * application.
548     *
549     * <p><strong>TODO</strong> allow limiting maximum header size to
550     * protect against abuse.
551     *
552     * @return The <code>header-part</code> of the current encapsulation.
553     *
554     * @throws FileUploadIOException if the bytes read from the stream exceeded the size limits.
555     * @throws MalformedStreamException if the stream ends unexpectedly.
556     */
557    public String readHeaders() throws FileUploadIOException, MalformedStreamException {
558        int i = 0;
559        byte b;
560        // to support multi-byte characters
561        ByteArrayOutputStream baos = new ByteArrayOutputStream();
562        int size = 0;
563        while (i < HEADER_SEPARATOR.length) {
564            try {
565                b = readByte();
566            } catch (FileUploadIOException e) {
567                // wraps a SizeException, re-throw as it will be unwrapped later
568                throw e;
569            } catch (IOException e) {
570                throw new MalformedStreamException("Stream ended unexpectedly");
571            }
572            if (++size > HEADER_PART_SIZE_MAX) {
573                throw new MalformedStreamException(
574                        format("Header section has more than %s bytes (maybe it is not properly terminated)",
575                               Integer.valueOf(HEADER_PART_SIZE_MAX)));
576            }
577            if (b == HEADER_SEPARATOR[i]) {
578                i++;
579            } else {
580                i = 0;
581            }
582            baos.write(b);
583        }
584
585        String headers = null;
586        if (headerEncoding != null) {
587            try {
588                headers = baos.toString(headerEncoding);
589            } catch (UnsupportedEncodingException e) {
590                // Fall back to platform default if specified encoding is not
591                // supported.
592                headers = baos.toString();
593            }
594        } else {
595            headers = baos.toString();
596        }
597
598        return headers;
599    }
600
601    /**
602     * <p>Reads <code>body-data</code> from the current
603     * <code>encapsulation</code> and writes its contents into the
604     * output <code>Stream</code>.
605     *
606     * <p>Arbitrary large amounts of data can be processed by this
607     * method using a constant size buffer. (see {@link
608     * #MultipartStream(InputStream,byte[],int,
609     *   MultipartStream.ProgressNotifier) constructor}).
610     *
611     * @param output The <code>Stream</code> to write data into. May
612     *               be null, in which case this method is equivalent
613     *               to {@link #discardBodyData()}.
614     *
615     * @return the amount of data written.
616     *
617     * @throws MalformedStreamException if the stream ends unexpectedly.
618     * @throws IOException              if an i/o error occurs.
619     */
620    public int readBodyData(OutputStream output)
621            throws MalformedStreamException, IOException {
622        return (int) Streams.copy(newInputStream(), output, false); // N.B. Streams.copy closes the input stream
623    }
624
625    /**
626     * Creates a new {@link ItemInputStream}.
627     * @return A new instance of {@link ItemInputStream}.
628     */
629    ItemInputStream newInputStream() {
630        return new ItemInputStream();
631    }
632
633    /**
634     * <p> Reads <code>body-data</code> from the current
635     * <code>encapsulation</code> and discards it.
636     *
637     * <p>Use this method to skip encapsulations you don't need or don't
638     * understand.
639     *
640     * @return The amount of data discarded.
641     *
642     * @throws MalformedStreamException if the stream ends unexpectedly.
643     * @throws IOException              if an i/o error occurs.
644     */
645    public int discardBodyData() throws MalformedStreamException, IOException {
646        return readBodyData(null);
647    }
648
649    /**
650     * Finds the beginning of the first <code>encapsulation</code>.
651     *
652     * @return <code>true</code> if an <code>encapsulation</code> was found in
653     *         the stream.
654     *
655     * @throws IOException if an i/o error occurs.
656     */
657    public boolean skipPreamble() throws IOException {
658        // First delimiter may be not preceeded with a CRLF.
659        System.arraycopy(boundary, 2, boundary, 0, boundary.length - 2);
660        boundaryLength = boundary.length - 2;
661        computeBoundaryTable();
662        try {
663            // Discard all data up to the delimiter.
664            discardBodyData();
665
666            // Read boundary - if succeeded, the stream contains an
667            // encapsulation.
668            return readBoundary();
669        } catch (MalformedStreamException e) {
670            return false;
671        } finally {
672            // Restore delimiter.
673            System.arraycopy(boundary, 0, boundary, 2, boundary.length - 2);
674            boundaryLength = boundary.length;
675            boundary[0] = CR;
676            boundary[1] = LF;
677            computeBoundaryTable();
678        }
679    }
680
681    /**
682     * Compares <code>count</code> first bytes in the arrays
683     * <code>a</code> and <code>b</code>.
684     *
685     * @param a     The first array to compare.
686     * @param b     The second array to compare.
687     * @param count How many bytes should be compared.
688     *
689     * @return <code>true</code> if <code>count</code> first bytes in arrays
690     *         <code>a</code> and <code>b</code> are equal.
691     */
692    public static boolean arrayequals(byte[] a,
693            byte[] b,
694            int count) {
695        for (int i = 0; i < count; i++) {
696            if (a[i] != b[i]) {
697                return false;
698            }
699        }
700        return true;
701    }
702
703    /**
704     * Searches for a byte of specified value in the <code>buffer</code>,
705     * starting at the specified <code>position</code>.
706     *
707     * @param value The value to find.
708     * @param pos   The starting position for searching.
709     *
710     * @return The position of byte found, counting from beginning of the
711     *         <code>buffer</code>, or <code>-1</code> if not found.
712     */
713    protected int findByte(byte value,
714            int pos) {
715        for (int i = pos; i < tail; i++) {
716            if (buffer[i] == value) {
717                return i;
718            }
719        }
720
721        return -1;
722    }
723
724    /**
725     * Searches for the <code>boundary</code> in the <code>buffer</code>
726     * region delimited by <code>head</code> and <code>tail</code>.
727     *
728     * @return The position of the boundary found, counting from the
729     *         beginning of the <code>buffer</code>, or <code>-1</code> if
730     *         not found.
731     */
732    protected int findSeparator() {
733
734        int bufferPos = this.head;
735        int tablePos = 0;
736
737        while (bufferPos < this.tail) {
738            while (tablePos >= 0 && buffer[bufferPos] != boundary[tablePos]) {
739                tablePos = boundaryTable[tablePos];
740            }
741            bufferPos++;
742            tablePos++;
743            if (tablePos == boundaryLength) {
744                return bufferPos - boundaryLength;
745            }
746        }
747        return -1;
748    }
749
750    /**
751     * Thrown to indicate that the input stream fails to follow the
752     * required syntax.
753     */
754    public static class MalformedStreamException extends IOException {
755
756        /**
757         * The UID to use when serializing this instance.
758         */
759        private static final long serialVersionUID = 6466926458059796677L;
760
761        /**
762         * Constructs a <code>MalformedStreamException</code> with no
763         * detail message.
764         */
765        public MalformedStreamException() {
766            super();
767        }
768
769        /**
770         * Constructs an <code>MalformedStreamException</code> with
771         * the specified detail message.
772         *
773         * @param message The detail message.
774         */
775        public MalformedStreamException(String message) {
776            super(message);
777        }
778
779    }
780
781    /**
782     * Thrown upon attempt of setting an invalid boundary token.
783     */
784    public static class IllegalBoundaryException extends IOException {
785
786        /**
787         * The UID to use when serializing this instance.
788         */
789        private static final long serialVersionUID = -161533165102632918L;
790
791        /**
792         * Constructs an <code>IllegalBoundaryException</code> with no
793         * detail message.
794         */
795        public IllegalBoundaryException() {
796            super();
797        }
798
799        /**
800         * Constructs an <code>IllegalBoundaryException</code> with
801         * the specified detail message.
802         *
803         * @param message The detail message.
804         */
805        public IllegalBoundaryException(String message) {
806            super(message);
807        }
808
809    }
810
811    /**
812     * An {@link InputStream} for reading an items contents.
813     */
814    public class ItemInputStream extends InputStream implements Closeable {
815
816        /**
817         * The number of bytes, which have been read so far.
818         */
819        private long total;
820
821        /**
822         * The number of bytes, which must be hold, because
823         * they might be a part of the boundary.
824         */
825        private int pad;
826
827        /**
828         * The current offset in the buffer.
829         */
830        private int pos;
831
832        /**
833         * Whether the stream is already closed.
834         */
835        private boolean closed;
836
837        /**
838         * Creates a new instance.
839         */
840        ItemInputStream() {
841            findSeparator();
842        }
843
844        /**
845         * Called for finding the separator.
846         */
847        private void findSeparator() {
848            pos = MultipartStream.this.findSeparator();
849            if (pos == -1) {
850                if (tail - head > keepRegion) {
851                    pad = keepRegion;
852                } else {
853                    pad = tail - head;
854                }
855            }
856        }
857
858        /**
859         * Returns the number of bytes, which have been read
860         * by the stream.
861         *
862         * @return Number of bytes, which have been read so far.
863         */
864        public long getBytesRead() {
865            return total;
866        }
867
868        /**
869         * Returns the number of bytes, which are currently
870         * available, without blocking.
871         *
872         * @throws IOException An I/O error occurs.
873         * @return Number of bytes in the buffer.
874         */
875        @Override
876        public int available() throws IOException {
877            if (pos == -1) {
878                return tail - head - pad;
879            }
880            return pos - head;
881        }
882
883        /**
884         * Offset when converting negative bytes to integers.
885         */
886        private static final int BYTE_POSITIVE_OFFSET = 256;
887
888        /**
889         * Returns the next byte in the stream.
890         *
891         * @return The next byte in the stream, as a non-negative
892         *   integer, or -1 for EOF.
893         * @throws IOException An I/O error occurred.
894         */
895        @Override
896        public int read() throws IOException {
897            if (closed) {
898                throw new FileItemStream.ItemSkippedException();
899            }
900            if (available() == 0 && makeAvailable() == 0) {
901                return -1;
902            }
903            ++total;
904            int b = buffer[head++];
905            if (b >= 0) {
906                return b;
907            }
908            return b + BYTE_POSITIVE_OFFSET;
909        }
910
911        /**
912         * Reads bytes into the given buffer.
913         *
914         * @param b The destination buffer, where to write to.
915         * @param off Offset of the first byte in the buffer.
916         * @param len Maximum number of bytes to read.
917         * @return Number of bytes, which have been actually read,
918         *   or -1 for EOF.
919         * @throws IOException An I/O error occurred.
920         */
921        @Override
922        public int read(byte[] b, int off, int len) throws IOException {
923            if (closed) {
924                throw new FileItemStream.ItemSkippedException();
925            }
926            if (len == 0) {
927                return 0;
928            }
929            int res = available();
930            if (res == 0) {
931                res = makeAvailable();
932                if (res == 0) {
933                    return -1;
934                }
935            }
936            res = Math.min(res, len);
937            System.arraycopy(buffer, head, b, off, res);
938            head += res;
939            total += res;
940            return res;
941        }
942
943        /**
944         * Closes the input stream.
945         *
946         * @throws IOException An I/O error occurred.
947         */
948        @Override
949        public void close() throws IOException {
950            close(false);
951        }
952
953        /**
954         * Closes the input stream.
955         *
956         * @param pCloseUnderlying Whether to close the underlying stream
957         *   (hard close)
958         * @throws IOException An I/O error occurred.
959         */
960        public void close(boolean pCloseUnderlying) throws IOException {
961            if (closed) {
962                return;
963            }
964            if (pCloseUnderlying) {
965                closed = true;
966                input.close();
967            } else {
968                for (;;) {
969                    int av = available();
970                    if (av == 0) {
971                        av = makeAvailable();
972                        if (av == 0) {
973                            break;
974                        }
975                    }
976                    skip(av);
977                }
978            }
979            closed = true;
980        }
981
982        /**
983         * Skips the given number of bytes.
984         *
985         * @param bytes Number of bytes to skip.
986         * @return The number of bytes, which have actually been
987         *   skipped.
988         * @throws IOException An I/O error occurred.
989         */
990        @Override
991        public long skip(long bytes) throws IOException {
992            if (closed) {
993                throw new FileItemStream.ItemSkippedException();
994            }
995            int av = available();
996            if (av == 0) {
997                av = makeAvailable();
998                if (av == 0) {
999                    return 0;
1000                }
1001            }
1002            long res = Math.min(av, bytes);
1003            head += res;
1004            return res;
1005        }
1006
1007        /**
1008         * Attempts to read more data.
1009         *
1010         * @return Number of available bytes
1011         * @throws IOException An I/O error occurred.
1012         */
1013        private int makeAvailable() throws IOException {
1014            if (pos != -1) {
1015                return 0;
1016            }
1017
1018            // Move the data to the beginning of the buffer.
1019            total += tail - head - pad;
1020            System.arraycopy(buffer, tail - pad, buffer, 0, pad);
1021
1022            // Refill buffer with new data.
1023            head = 0;
1024            tail = pad;
1025
1026            for (;;) {
1027                int bytesRead = input.read(buffer, tail, bufSize - tail);
1028                if (bytesRead == -1) {
1029                    // The last pad amount is left in the buffer.
1030                    // Boundary can't be in there so signal an error
1031                    // condition.
1032                    final String msg = "Stream ended unexpectedly";
1033                    throw new MalformedStreamException(msg);
1034                }
1035                if (notifier != null) {
1036                    notifier.noteBytesRead(bytesRead);
1037                }
1038                tail += bytesRead;
1039
1040                findSeparator();
1041                int av = available();
1042
1043                if (av > 0 || pos != -1) {
1044                    return av;
1045                }
1046            }
1047        }
1048
1049        /**
1050         * Returns, whether the stream is closed.
1051         *
1052         * @return True, if the stream is closed, otherwise false.
1053         */
1054        @Override
1055        public boolean isClosed() {
1056            return closed;
1057        }
1058
1059    }
1060
1061}