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