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