You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by jo...@apache.org on 2019/09/23 13:30:16 UTC

[commons-fileupload] branch master updated (f4cab57 -> e0bfe29)

This is an automated email from the ASF dual-hosted git repository.

jochen pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/commons-fileupload.git.


    from f4cab57  Call super.finalize() in a finalize() implementation. (As suggested by Fortify static code analysis.)
     new de1a197  PR: FILEUPLOAD-300
     new e0bfe29  PR: FILEUPLOAD-300

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../commons/fileupload2/FileItemIterator.java      | 148 +++++++----
 .../apache/commons/fileupload2/FileUploadBase.java | 288 ++++++---------------
 .../commons/fileupload2/MultipartStream.java       |   2 +-
 .../fileupload2/impl/FileItemStreamImpl.java       | 228 ++++++++++++++++
 4 files changed, 400 insertions(+), 266 deletions(-)
 create mode 100644 src/main/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java


[commons-fileupload] 01/02: PR: FILEUPLOAD-300

Posted by jo...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jochen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-fileupload.git

commit de1a19730600bd295a9f2c5c3bf83b0d0c20dc32
Author: Jochen Wiedmann <jo...@gmail.com>
AuthorDate: Mon Sep 23 15:15:17 2019 +0200

    PR: FILEUPLOAD-300
    
    Making FileItemIteratorImpl, and FileItemStreamImpl static, as a
    preparation for moving them out.
---
 .../commons/fileupload2/FileItemIterator.java      | 148 +++++++++++++--------
 .../apache/commons/fileupload2/FileUploadBase.java | 116 +++++++++++-----
 2 files changed, 181 insertions(+), 83 deletions(-)

diff --git a/src/main/java/org/apache/commons/fileupload2/FileItemIterator.java b/src/main/java/org/apache/commons/fileupload2/FileItemIterator.java
index ac630df..b56706d 100644
--- a/src/main/java/org/apache/commons/fileupload2/FileItemIterator.java
+++ b/src/main/java/org/apache/commons/fileupload2/FileItemIterator.java
@@ -1,52 +1,96 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.fileupload2;
-
-import java.io.IOException;
-
-/**
- * An iterator, as returned by
- * {@link FileUploadBase#getItemIterator(RequestContext)}.
- */
-public interface FileItemIterator {
-
-    /**
-     * Returns, whether another instance of {@link FileItemStream}
-     * is available.
-     *
-     * @throws FileUploadException Parsing or processing the
-     *   file item failed.
-     * @throws IOException Reading the file item failed.
-     * @return True, if one or more additional file items
-     *   are available, otherwise false.
-     */
-    boolean hasNext() throws FileUploadException, IOException;
-
-    /**
-     * Returns the next available {@link FileItemStream}.
-     *
-     * @throws java.util.NoSuchElementException No more items are available. Use
-     * {@link #hasNext()} to prevent this exception.
-     * @throws FileUploadException Parsing or processing the
-     *   file item failed.
-     * @throws IOException Reading the file item failed.
-     * @return FileItemStream instance, which provides
-     *   access to the next file item.
-     */
-    FileItemStream next() throws FileUploadException, IOException;
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.fileupload2;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.fileupload2.FileUploadBase.FileSizeLimitExceededException;
+
+/**
+ * An iterator, as returned by
+ * {@link FileUploadBase#getItemIterator(RequestContext)}.
+ */
+public interface FileItemIterator {
+	/** Returns the maximum size of a single file. An {@link FileSizeLimitExceededException}
+	 * will be thrown, if there is an uploaded file, which is exceeding this value.
+	 * By default, this value will be copied from the {@link FileUploadBase#getFileSizeMax()
+	 * FileUploadBase} object, however, the user may replace the default value with a
+	 * request specific value by invoking {@link #setFileSizeMax(long)} on this object.
+	 * @return The maximum size of a single, uploaded file. The value -1 indicates "unlimited".
+	 */
+	public long getFileSizeMax();
+	
+	/** Sets the maximum size of a single file. An {@link FileSizeLimitExceededException}
+	 * will be thrown, if there is an uploaded file, which is exceeding this value.
+	 * By default, this value will be copied from the {@link FileUploadBase#getFileSizeMax()
+	 * FileUploadBase} object, however, the user may replace the default value with a
+	 * request specific value by invoking {@link #setFileSizeMax(long)} on this object, so
+	 * there is no need to configure it here.
+	 * <em>Note:</em>Changing this value doesn't affect files, that have already been uploaded.
+	 * @param pFileSizeMax The maximum size of a single, uploaded file. The value -1 indicates "unlimited".
+	 */
+	public void setFileSizeMax(long pFileSizeMax);
+
+	/** Returns the maximum size of the complete HTTP request. A {@link SizeLimitExceededException}
+	 * will be thrown, if the HTTP request will exceed this value.
+	 * By default, this value will be copied from the {@link FileUploadBase#getSizeMax()
+	 * FileUploadBase} object, however, the user may replace the default value with a
+	 * request specific value by invoking {@link #setSizeMax(long)} on this object.
+	 * @return The maximum size of the complete HTTP requqest. The value -1 indicates "unlimited".
+	 */
+	public long getSizeMax();
+	
+	/** Returns the maximum size of the complete HTTP request. A {@link SizeLimitExceededException}
+	 * will be thrown, if the HTTP request will exceed this value.
+	 * By default, this value will be copied from the {@link FileUploadBase#getSizeMax()
+	 * FileUploadBase} object, however, the user may replace the default value with a
+	 * request specific value by invoking {@link #setSizeMax(long)} on this object.
+	 * <em>Note:</em> Setting the maximum size on this object will work only, if the iterator is not
+	 * yet initialized. In other words: If the methods {@link #hasNext()}, {@link #next()} have not
+	 * yet been invoked.
+	 * @param pSizeMax The maximum size of the complete HTTP request. The value -1 indicates "unlimited".
+	 */
+	public void setSizeMax(long pSizeMax);
+
+    /**
+     * Returns, whether another instance of {@link FileItemStream}
+     * is available.
+     *
+     * @throws FileUploadException Parsing or processing the
+     *   file item failed.
+     * @throws IOException Reading the file item failed.
+     * @return True, if one or more additional file items
+     *   are available, otherwise false.
+     */
+    public boolean hasNext() throws FileUploadException, IOException;
+
+    /**
+     * Returns the next available {@link FileItemStream}.
+     *
+     * @throws java.util.NoSuchElementException No more items are available. Use
+     * {@link #hasNext()} to prevent this exception.
+     * @throws FileUploadException Parsing or processing the
+     *   file item failed.
+     * @throws IOException Reading the file item failed.
+     * @return FileItemStream instance, which provides
+     *   access to the next file item.
+     */
+    public FileItemStream next() throws FileUploadException, IOException;
+
+    public List<FileItem> getFileItems() throws FileUploadException, IOException;
+}
diff --git a/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java b/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
index 777f34d..c15b0f9 100644
--- a/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
+++ b/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
@@ -306,7 +306,7 @@ public abstract class FileUploadBase {
     public FileItemIterator getItemIterator(RequestContext ctx)
     throws FileUploadException, IOException {
         try {
-            return new FileItemIteratorImpl(ctx);
+            return new FileItemIteratorImpl(this, ctx);
         } catch (FileUploadIOException e) {
             // unwrap encapsulated SizeException
             throw (FileUploadException) e.getCause();
@@ -706,12 +706,37 @@ public abstract class FileUploadBase {
      * The iterator, which is returned by
      * {@link FileUploadBase#getItemIterator(RequestContext)}.
      */
-    private class FileItemIteratorImpl implements FileItemIterator {
+    private static class FileItemIteratorImpl implements FileItemIterator {
+    	private final FileUploadBase fileUploadBase;
+    	private final RequestContext ctx;
+    	private long sizeMax, fileSizeMax;
 
-        /**
+
+    	@Override
+    	public long getSizeMax() {
+			return sizeMax;
+		}
+
+    	@Override
+		public void setSizeMax(long sizeMax) {
+			this.sizeMax = sizeMax;
+		}
+
+    	@Override
+		public long getFileSizeMax() {
+			return fileSizeMax;
+		}
+
+    	@Override
+		public void setFileSizeMax(long fileSizeMax) {
+			this.fileSizeMax = fileSizeMax;
+		}
+
+		/**
          * Default implementation of {@link FileItemStream}.
          */
-        class FileItemStreamImpl implements FileItemStream {
+        public static class FileItemStreamImpl implements FileItemStream {
+        	private final FileItemIteratorImpl fileItemIteratorImpl;
 
             /**
              * The file items content type.
@@ -758,13 +783,15 @@ public abstract class FileUploadBase {
              * @param pContentLength The items content length, if known, or -1
              * @throws IOException Creating the file item failed.
              */
-            FileItemStreamImpl(String pName, String pFieldName,
+            FileItemStreamImpl(FileItemIteratorImpl pFileItemIterator, String pName, String pFieldName,
                     String pContentType, boolean pFormField,
-                    long pContentLength) throws IOException {
+                    long pContentLength) throws FileUploadException, IOException {
+            	fileItemIteratorImpl = pFileItemIterator;
                 name = pName;
                 fieldName = pFieldName;
                 contentType = pContentType;
                 formField = pFormField;
+                final long fileSizeMax = fileItemIteratorImpl.getFileSizeMax();
                 if (fileSizeMax != -1) { // Check if limit is already exceeded
                     if (pContentLength != -1
                             && pContentLength > fileSizeMax) {
@@ -779,7 +806,7 @@ public abstract class FileUploadBase {
                     }
                 }
                 // OK to construct stream now
-                final ItemInputStream itemStream = multi.newInputStream();
+                final ItemInputStream itemStream = fileItemIteratorImpl.getMultiPartStream().newInputStream();
                 InputStream istream = itemStream;
                 if (fileSizeMax != -1) {
                     istream = new LimitedInputStream(istream, fileSizeMax) {
@@ -899,18 +926,18 @@ public abstract class FileUploadBase {
         /**
          * The multi part stream to process.
          */
-        private final MultipartStream multi;
+        private MultipartStream multiPartStream;
 
         /**
          * The notifier, which used for triggering the
          * {@link ProgressListener}.
          */
-        private final MultipartStream.ProgressNotifier notifier;
+        private MultipartStream.ProgressNotifier progressNotifier;
 
         /**
          * The boundary, which separates the various parts.
          */
-        private final byte[] boundary;
+        private byte[] multiPartBoundary;
 
         /**
          * The item, which we currently process.
@@ -945,12 +972,23 @@ public abstract class FileUploadBase {
          *   parsing the request.
          * @throws IOException An I/O error occurred.
          */
-        FileItemIteratorImpl(RequestContext ctx)
+        FileItemIteratorImpl(FileUploadBase pFileUploadBase, RequestContext pRequestContext)
                 throws FileUploadException, IOException {
+        	fileUploadBase = pFileUploadBase;
+        	sizeMax = fileUploadBase.getSizeMax();
+        	fileSizeMax = fileUploadBase.getFileSizeMax();
+        	ctx = pRequestContext;
             if (ctx == null) {
                 throw new NullPointerException("ctx parameter");
             }
 
+
+            skipPreamble = true;
+            findNextItem();
+        }
+
+        protected void init(FileUploadBase fileUploadBase, RequestContext pRequestContext)
+                throws FileUploadException, IOException {
             String contentType = ctx.getContentType();
             if ((null == contentType)
                     || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART))) {
@@ -993,38 +1031,42 @@ public abstract class FileUploadBase {
                 input = ctx.getInputStream();
             }
 
-            String charEncoding = headerEncoding;
+            String charEncoding = fileUploadBase.getHeaderEncoding();
             if (charEncoding == null) {
                 charEncoding = ctx.getCharacterEncoding();
             }
 
-            boundary = getBoundary(contentType);
-            if (boundary == null) {
+            multiPartBoundary = fileUploadBase.getBoundary(contentType);
+            if (multiPartBoundary == null) {
                 IOUtils.closeQuietly(input); // avoid possible resource leak
                 throw new FileUploadException("the request was rejected because no multipart boundary was found");
             }
 
-            notifier = new MultipartStream.ProgressNotifier(listener, requestSize);
+            progressNotifier = new MultipartStream.ProgressNotifier(fileUploadBase.getProgressListener(), requestSize);
             try {
-                multi = new MultipartStream(input, boundary, notifier);
+                multiPartStream = new MultipartStream(input, multiPartBoundary, progressNotifier);
             } catch (IllegalArgumentException iae) {
                 IOUtils.closeQuietly(input); // avoid possible resource leak
                 throw new InvalidContentTypeException(
                         format("The boundary specified in the %s header is too long", CONTENT_TYPE), iae);
             }
-            multi.setHeaderEncoding(charEncoding);
-
-            skipPreamble = true;
-            findNextItem();
+            multiPartStream.setHeaderEncoding(charEncoding);
         }
 
+        public MultipartStream getMultiPartStream() throws FileUploadException, IOException {
+        	if (multiPartStream == null) {
+        		init(fileUploadBase, ctx);
+        	}
+        	return multiPartStream;
+        }
+ 
         /**
          * Called for finding the next item, if any.
          *
          * @return True, if an next item was found, otherwise false.
          * @throws IOException An I/O error occurred.
          */
-        private boolean findNextItem() throws IOException {
+        private boolean findNextItem() throws FileUploadException, IOException {
             if (eof) {
                 return false;
             }
@@ -1032,6 +1074,7 @@ public abstract class FileUploadBase {
                 currentItem.close();
                 currentItem = null;
             }
+            final MultipartStream multi = getMultiPartStream();
             for (;;) {
                 boolean nextPart;
                 if (skipPreamble) {
@@ -1046,14 +1089,14 @@ public abstract class FileUploadBase {
                         return false;
                     }
                     // Inner multipart terminated -> Return to parsing the outer
-                    multi.setBoundary(boundary);
+                    multi.setBoundary(multiPartBoundary);
                     currentFieldName = null;
                     continue;
                 }
-                FileItemHeaders headers = getParsedHeaders(multi.readHeaders());
+                FileItemHeaders headers = fileUploadBase.getParsedHeaders(multi.readHeaders());
                 if (currentFieldName == null) {
                     // We're parsing the outer multipart
-                    String fieldName = getFieldName(headers);
+                    String fieldName = fileUploadBase.getFieldName(headers);
                     if (fieldName != null) {
                         String subContentType = headers.getHeader(CONTENT_TYPE);
                         if (subContentType != null
@@ -1061,29 +1104,29 @@ public abstract class FileUploadBase {
                                         .startsWith(MULTIPART_MIXED)) {
                             currentFieldName = fieldName;
                             // Multiple files associated with this field name
-                            byte[] subBoundary = getBoundary(subContentType);
+                            byte[] subBoundary = fileUploadBase.getBoundary(subContentType);
                             multi.setBoundary(subBoundary);
                             skipPreamble = true;
                             continue;
                         }
-                        String fileName = getFileName(headers);
-                        currentItem = new FileItemStreamImpl(fileName,
+                        String fileName = fileUploadBase.getFileName(headers);
+                        currentItem = new FileItemStreamImpl(this, fileName,
                                 fieldName, headers.getHeader(CONTENT_TYPE),
                                 fileName == null, getContentLength(headers));
                         currentItem.setHeaders(headers);
-                        notifier.noteItem();
+                        progressNotifier.noteItem();
                         itemValid = true;
                         return true;
                     }
                 } else {
-                    String fileName = getFileName(headers);
+                    String fileName = fileUploadBase.getFileName(headers);
                     if (fileName != null) {
-                        currentItem = new FileItemStreamImpl(fileName,
+                        currentItem = new FileItemStreamImpl(this, fileName,
                                 currentFieldName,
                                 headers.getHeader(CONTENT_TYPE),
                                 false, getContentLength(headers));
                         currentItem.setHeaders(headers);
-                        notifier.noteItem();
+                        progressNotifier.noteItem();
                         itemValid = true;
                         return true;
                     }
@@ -1146,6 +1189,17 @@ public abstract class FileUploadBase {
             return currentItem;
         }
 
+		@Override
+		public List<FileItem> getFileItems() throws FileUploadException, IOException {
+			final List<FileItem> items = new ArrayList<FileItem>();
+			while (hasNext()) {
+				final FileItemStream fis = next();
+				final FileItem fi = fileUploadBase.getFileItemFactory().createItem(fis.getFieldName(), fis.getContentType(), fis.isFormField(), fis.getName());
+				items.add(fi);
+			}
+			return items;
+		}
+
     }
 
     /**


[commons-fileupload] 02/02: PR: FILEUPLOAD-300

Posted by jo...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jochen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-fileupload.git

commit e0bfe29d200975e78982db4b276829c4318100e1
Author: Jochen Wiedmann <jo...@gmail.com>
AuthorDate: Mon Sep 23 15:22:48 2019 +0200

    PR: FILEUPLOAD-300
    
    Move FileItemStreamImpl class out of FileUploadBase to the impl
    package.
---
 .../apache/commons/fileupload2/FileUploadBase.java | 198 +-----------------
 .../commons/fileupload2/MultipartStream.java       |   2 +-
 .../fileupload2/impl/FileItemStreamImpl.java       | 228 +++++++++++++++++++++
 3 files changed, 232 insertions(+), 196 deletions(-)

diff --git a/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java b/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
index c15b0f9..0a3a19b 100644
--- a/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
+++ b/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
@@ -31,10 +31,9 @@ import java.util.NoSuchElementException;
 
 import javax.servlet.http.HttpServletRequest;
 
-import org.apache.commons.fileupload2.MultipartStream.ItemInputStream;
+import org.apache.commons.fileupload2.impl.FileItemStreamImpl;
 import org.apache.commons.fileupload2.servlet.ServletFileUpload;
 import org.apache.commons.fileupload2.servlet.ServletRequestContext;
-import org.apache.commons.fileupload2.util.Closeable;
 import org.apache.commons.fileupload2.util.FileItemHeadersImpl;
 import org.apache.commons.fileupload2.util.LimitedInputStream;
 import org.apache.commons.fileupload2.util.Streams;
@@ -339,7 +338,7 @@ public abstract class FileUploadBase {
             while (iter.hasNext()) {
                 final FileItemStream item = iter.next();
                 // Don't use getName() here to prevent an InvalidFileNameException.
-                final String fileName = ((FileItemIteratorImpl.FileItemStreamImpl) item).name;
+                final String fileName = ((FileItemStreamImpl) item).getName();
                 FileItem fileItem = fac.createItem(item.getFieldName(), item.getContentType(),
                                                    item.isFormField(), fileName);
                 items.add(fileItem);
@@ -706,7 +705,7 @@ public abstract class FileUploadBase {
      * The iterator, which is returned by
      * {@link FileUploadBase#getItemIterator(RequestContext)}.
      */
-    private static class FileItemIteratorImpl implements FileItemIterator {
+    public static class FileItemIteratorImpl implements FileItemIterator {
     	private final FileUploadBase fileUploadBase;
     	private final RequestContext ctx;
     	private long sizeMax, fileSizeMax;
@@ -733,197 +732,6 @@ public abstract class FileUploadBase {
 		}
 
 		/**
-         * Default implementation of {@link FileItemStream}.
-         */
-        public static class FileItemStreamImpl implements FileItemStream {
-        	private final FileItemIteratorImpl fileItemIteratorImpl;
-
-            /**
-             * The file items content type.
-             */
-            private final String contentType;
-
-            /**
-             * The file items field name.
-             */
-            private final String fieldName;
-
-            /**
-             * The file items file name.
-             */
-            private final String name;
-
-            /**
-             * Whether the file item is a form field.
-             */
-            private final boolean formField;
-
-            /**
-             * The file items input stream.
-             */
-            private final InputStream stream;
-
-            /**
-             * Whether the file item was already opened.
-             */
-            private boolean opened;
-
-            /**
-             * The headers, if any.
-             */
-            private FileItemHeaders headers;
-
-            /**
-             * Creates a new instance.
-             *
-             * @param pName The items file name, or null.
-             * @param pFieldName The items field name.
-             * @param pContentType The items content type, or null.
-             * @param pFormField Whether the item is a form field.
-             * @param pContentLength The items content length, if known, or -1
-             * @throws IOException Creating the file item failed.
-             */
-            FileItemStreamImpl(FileItemIteratorImpl pFileItemIterator, String pName, String pFieldName,
-                    String pContentType, boolean pFormField,
-                    long pContentLength) throws FileUploadException, IOException {
-            	fileItemIteratorImpl = pFileItemIterator;
-                name = pName;
-                fieldName = pFieldName;
-                contentType = pContentType;
-                formField = pFormField;
-                final long fileSizeMax = fileItemIteratorImpl.getFileSizeMax();
-                if (fileSizeMax != -1) { // Check if limit is already exceeded
-                    if (pContentLength != -1
-                            && pContentLength > fileSizeMax) {
-                        FileSizeLimitExceededException e =
-                                new FileSizeLimitExceededException(
-                                        format("The field %s exceeds its maximum permitted size of %s bytes.",
-                                                fieldName, Long.valueOf(fileSizeMax)),
-                                        pContentLength, fileSizeMax);
-                        e.setFileName(pName);
-                        e.setFieldName(pFieldName);
-                        throw new FileUploadIOException(e);
-                    }
-                }
-                // OK to construct stream now
-                final ItemInputStream itemStream = fileItemIteratorImpl.getMultiPartStream().newInputStream();
-                InputStream istream = itemStream;
-                if (fileSizeMax != -1) {
-                    istream = new LimitedInputStream(istream, fileSizeMax) {
-                        @Override
-                        protected void raiseError(long pSizeMax, long pCount)
-                                throws IOException {
-                            itemStream.close(true);
-                            FileSizeLimitExceededException e =
-                                new FileSizeLimitExceededException(
-                                    format("The field %s exceeds its maximum permitted size of %s bytes.",
-                                           fieldName, Long.valueOf(pSizeMax)),
-                                    pCount, pSizeMax);
-                            e.setFieldName(fieldName);
-                            e.setFileName(name);
-                            throw new FileUploadIOException(e);
-                        }
-                    };
-                }
-                stream = istream;
-            }
-
-            /**
-             * Returns the items content type, or null.
-             *
-             * @return Content type, if known, or null.
-             */
-            @Override
-            public String getContentType() {
-                return contentType;
-            }
-
-            /**
-             * Returns the items field name.
-             *
-             * @return Field name.
-             */
-            @Override
-            public String getFieldName() {
-                return fieldName;
-            }
-
-            /**
-             * Returns the items file name.
-             *
-             * @return File name, if known, or null.
-             * @throws InvalidFileNameException The file name contains a NUL character,
-             *   which might be an indicator of a security attack. If you intend to
-             *   use the file name anyways, catch the exception and use
-             *   InvalidFileNameException#getName().
-             */
-            @Override
-            public String getName() {
-                return Streams.checkFileName(name);
-            }
-
-            /**
-             * Returns, whether this is a form field.
-             *
-             * @return True, if the item is a form field,
-             *   otherwise false.
-             */
-            @Override
-            public boolean isFormField() {
-                return formField;
-            }
-
-            /**
-             * Returns an input stream, which may be used to
-             * read the items contents.
-             *
-             * @return Opened input stream.
-             * @throws IOException An I/O error occurred.
-             */
-            @Override
-            public InputStream openStream() throws IOException {
-                if (opened) {
-                    throw new IllegalStateException(
-                            "The stream was already opened.");
-                }
-                if (((Closeable) stream).isClosed()) {
-                    throw new FileItemStream.ItemSkippedException();
-                }
-                return stream;
-            }
-
-            /**
-             * Closes the file item.
-             *
-             * @throws IOException An I/O error occurred.
-             */
-            void close() throws IOException {
-                stream.close();
-            }
-
-            /**
-             * Returns the file item headers.
-             *
-             * @return The items header object
-             */
-            @Override
-            public FileItemHeaders getHeaders() {
-                return headers;
-            }
-
-            /**
-             * Sets the file item headers.
-             *
-             * @param pHeaders The items header object
-             */
-            @Override
-            public void setHeaders(FileItemHeaders pHeaders) {
-                headers = pHeaders;
-            }
-
-        }
-
-        /**
          * The multi part stream to process.
          */
         private MultipartStream multiPartStream;
diff --git a/src/main/java/org/apache/commons/fileupload2/MultipartStream.java b/src/main/java/org/apache/commons/fileupload2/MultipartStream.java
index 77f1f34..05f344a 100644
--- a/src/main/java/org/apache/commons/fileupload2/MultipartStream.java
+++ b/src/main/java/org/apache/commons/fileupload2/MultipartStream.java
@@ -626,7 +626,7 @@ public class MultipartStream {
      * Creates a new {@link ItemInputStream}.
      * @return A new instance of {@link ItemInputStream}.
      */
-    ItemInputStream newInputStream() {
+    public ItemInputStream newInputStream() {
         return new ItemInputStream();
     }
 
diff --git a/src/main/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java b/src/main/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java
new file mode 100644
index 0000000..be48435
--- /dev/null
+++ b/src/main/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.fileupload2.impl;
+
+import static java.lang.String.format;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.fileupload2.FileItemHeaders;
+import org.apache.commons.fileupload2.FileItemStream;
+import org.apache.commons.fileupload2.FileUploadBase;
+import org.apache.commons.fileupload2.FileUploadException;
+import org.apache.commons.fileupload2.InvalidFileNameException;
+import org.apache.commons.fileupload2.MultipartStream;
+import org.apache.commons.fileupload2.FileItemStream.ItemSkippedException;
+import org.apache.commons.fileupload2.FileUploadBase.FileSizeLimitExceededException;
+import org.apache.commons.fileupload2.FileUploadBase.FileUploadIOException;
+import org.apache.commons.fileupload2.MultipartStream.ItemInputStream;
+import org.apache.commons.fileupload2.util.Closeable;
+import org.apache.commons.fileupload2.util.LimitedInputStream;
+import org.apache.commons.fileupload2.util.Streams;
+
+
+/**
+ * Default implementation of {@link FileItemStream}.
+ */
+public class FileItemStreamImpl implements FileItemStream {
+	private final FileUploadBase.FileItemIteratorImpl fileItemIteratorImpl;
+
+    /**
+     * The file items content type.
+     */
+    private final String contentType;
+
+    /**
+     * The file items field name.
+     */
+    private final String fieldName;
+
+    /**
+     * The file items file name.
+     */
+    final String name;
+
+    /**
+     * Whether the file item is a form field.
+     */
+    private final boolean formField;
+
+    /**
+     * The file items input stream.
+     */
+    private final InputStream stream;
+
+    /**
+     * Whether the file item was already opened.
+     */
+    private boolean opened;
+
+    /**
+     * The headers, if any.
+     */
+    private FileItemHeaders headers;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param pName The items file name, or null.
+     * @param pFieldName The items field name.
+     * @param pContentType The items content type, or null.
+     * @param pFormField Whether the item is a form field.
+     * @param pContentLength The items content length, if known, or -1
+     * @throws IOException Creating the file item failed.
+     */
+    public FileItemStreamImpl(FileUploadBase.FileItemIteratorImpl pFileItemIterator, String pName, String pFieldName,
+            String pContentType, boolean pFormField,
+            long pContentLength) throws FileUploadException, IOException {
+    	fileItemIteratorImpl = pFileItemIterator;
+        name = pName;
+        fieldName = pFieldName;
+        contentType = pContentType;
+        formField = pFormField;
+        final long fileSizeMax = fileItemIteratorImpl.getFileSizeMax();
+        if (fileSizeMax != -1) { // Check if limit is already exceeded
+            if (pContentLength != -1
+                    && pContentLength > fileSizeMax) {
+                FileUploadBase.FileSizeLimitExceededException e =
+                        new FileSizeLimitExceededException(
+                                format("The field %s exceeds its maximum permitted size of %s bytes.",
+                                        fieldName, Long.valueOf(fileSizeMax)),
+                                pContentLength, fileSizeMax);
+                e.setFileName(pName);
+                e.setFieldName(pFieldName);
+                throw new FileUploadIOException(e);
+            }
+        }
+        // OK to construct stream now
+        final ItemInputStream itemStream = fileItemIteratorImpl.getMultiPartStream().newInputStream();
+        InputStream istream = itemStream;
+        if (fileSizeMax != -1) {
+            istream = new LimitedInputStream(istream, fileSizeMax) {
+                @Override
+                protected void raiseError(long pSizeMax, long pCount)
+                        throws IOException {
+                    itemStream.close(true);
+                    FileUploadBase.FileSizeLimitExceededException e =
+                        new FileSizeLimitExceededException(
+                            format("The field %s exceeds its maximum permitted size of %s bytes.",
+                                   fieldName, Long.valueOf(pSizeMax)),
+                            pCount, pSizeMax);
+                    e.setFieldName(fieldName);
+                    e.setFileName(name);
+                    throw new FileUploadIOException(e);
+                }
+            };
+        }
+        stream = istream;
+    }
+
+    /**
+     * Returns the items content type, or null.
+     *
+     * @return Content type, if known, or null.
+     */
+    @Override
+    public String getContentType() {
+        return contentType;
+    }
+
+    /**
+     * Returns the items field name.
+     *
+     * @return Field name.
+     */
+    @Override
+    public String getFieldName() {
+        return fieldName;
+    }
+
+    /**
+     * Returns the items file name.
+     *
+     * @return File name, if known, or null.
+     * @throws InvalidFileNameException The file name contains a NUL character,
+     *   which might be an indicator of a security attack. If you intend to
+     *   use the file name anyways, catch the exception and use
+     *   InvalidFileNameException#getName().
+     */
+    @Override
+    public String getName() {
+        return Streams.checkFileName(name);
+    }
+
+    /**
+     * Returns, whether this is a form field.
+     *
+     * @return True, if the item is a form field,
+     *   otherwise false.
+     */
+    @Override
+    public boolean isFormField() {
+        return formField;
+    }
+
+    /**
+     * Returns an input stream, which may be used to
+     * read the items contents.
+     *
+     * @return Opened input stream.
+     * @throws IOException An I/O error occurred.
+     */
+    @Override
+    public InputStream openStream() throws IOException {
+        if (opened) {
+            throw new IllegalStateException(
+                    "The stream was already opened.");
+        }
+        if (((Closeable) stream).isClosed()) {
+            throw new FileItemStream.ItemSkippedException();
+        }
+        return stream;
+    }
+
+    /**
+     * Closes the file item.
+     *
+     * @throws IOException An I/O error occurred.
+     */
+    public void close() throws IOException {
+        stream.close();
+    }
+
+    /**
+     * Returns the file item headers.
+     *
+     * @return The items header object
+     */
+    @Override
+    public FileItemHeaders getHeaders() {
+        return headers;
+    }
+
+    /**
+     * Sets the file item headers.
+     *
+     * @param pHeaders The items header object
+     */
+    @Override
+    public void setHeaders(FileItemHeaders pHeaders) {
+        headers = pHeaders;
+    }
+
+}
\ No newline at end of file