You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2023/04/02 15:47:05 UTC

[commons-fileupload] branch master updated (1457bee -> 786d994)

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

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


    from 1457bee  Bump actions/setup-java from 3.10.0 to 3.11.0 (#210)
     new bd3f130  Sort members
     new c1cadad  Better parameter name
     new ae6e903  Propagate exception cause
     new 355d264  Rework exceptions to use propagated exception causes (introduced in Java 1.4)
     new 54a850b  Remove deprecated fields, methods, and constructors
     new 86a7e59  Organize imports
     new 90de20c  Fix Javadoc warning
     new 786d994  Remove unused exceptions from test method signature

The 8 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:
 src/changes/changes.xml                            |   15 +
 src/checkstyle/fileupload_checks.xml               |    3 +-
 .../org/apache/commons/fileupload2/FileItem.java   |  138 +--
 .../commons/fileupload2/FileItemHeaders.java       |   22 +-
 .../commons/fileupload2/FileItemIterator.java      |   55 +-
 .../apache/commons/fileupload2/FileItemStream.java |   42 +-
 .../apache/commons/fileupload2/FileUploadBase.java |  612 ++++-----
 .../commons/fileupload2/FileUploadException.java   |   77 +-
 .../commons/fileupload2/MultipartStream.java       | 1293 +++++++++-----------
 .../commons/fileupload2/ParameterParser.java       |  258 ++--
 .../commons/fileupload2/ProgressListener.java      |   14 +-
 .../apache/commons/fileupload2/RequestContext.java |   17 +-
 .../commons/fileupload2/disk/DiskFileItem.java     |  502 ++++----
 .../fileupload2/disk/DiskFileItemFactory.java      |  124 +-
 .../fileupload2/impl/FileItemIteratorImpl.java     |  259 ++--
 .../fileupload2/impl/FileItemStreamImpl.java       |  129 +-
 .../fileupload2/jaksrvlt/JakSrvltFileCleaner.java  |   22 +-
 .../fileupload2/jaksrvlt/JakSrvltFileUpload.java   |   30 +-
 .../jaksrvlt/JakSrvltRequestContext.java           |   50 +-
 .../fileupload2/portlet/PortletFileUpload.java     |   28 +-
 .../fileupload2/portlet/PortletRequestContext.java |   52 +-
 .../pub/FileCountLimitExceededException.java       |   53 -
 ...java => FileUploadByteCountLimitException.java} |   58 +-
 ...on.java => FileUploadContentTypeException.java} |   39 +-
 ...java => FileUploadFileCountLimitException.java} |   21 +-
 .../fileupload2/pub/FileUploadIOException.java     |   62 -
 ...Exception.java => FileUploadSizeException.java} |   29 +-
 .../fileupload2/pub/IOFileUploadException.java     |   61 -
 .../pub/SizeLimitExceededException.java            |   43 -
 .../fileupload2/servlet/FileCleanerCleanup.java    |   24 +-
 .../fileupload2/servlet/ServletFileUpload.java     |   33 +-
 .../fileupload2/servlet/ServletRequestContext.java |   46 +-
 .../fileupload2/util/FileItemHeadersImpl.java      |   26 +-
 .../fileupload2/util/LimitedInputStream.java       |   82 +-
 .../apache/commons/fileupload2/util/Streams.java   |  146 ++-
 .../fileupload2/util/mime/Base64Decoder.java       |   14 +-
 .../commons/fileupload2/util/mime/MimeUtility.java |   14 +-
 .../util/mime/QuotedPrintableDecoder.java          |   14 +-
 .../fileupload2/util/mime/RFC2231Utility.java      |   70 +-
 .../fileupload2/DiskFileItemSerializeTest.java     |  260 ++--
 .../apache/commons/fileupload2/FileUploadTest.java |  313 +++--
 .../fileupload2/HttpServletRequestFactory.java     |   14 +-
 .../fileupload2/MockHttpServletRequest.java        |  388 +++---
 .../commons/fileupload2/MultipartStreamTest.java   |   30 +-
 .../commons/fileupload2/ParameterParserTest.java   |  106 +-
 .../commons/fileupload2/ProgressListenerTest.java  |   64 +-
 .../org/apache/commons/fileupload2/SizesTest.java  |  113 +-
 .../apache/commons/fileupload2/StreamingTest.java  |  250 ++--
 .../java/org/apache/commons/fileupload2/Util.java  |   23 +-
 .../jaksrvlt/JakSrvltFileUploadTest.java           |   50 +-
 .../jaksrvlt/MockJakSrvltHttpRequest.java          |  535 ++++----
 .../portlet/MockPortletActionRequest.java          |   50 +-
 .../fileupload2/portlet/PortletFileUploadTest.java |   10 +-
 .../fileupload2/servlet/ServletFileUploadTest.java |   46 +-
 .../util/mime/Base64DecoderTestCase.java           |  152 ++-
 .../fileupload2/util/mime/MimeUtilityTestCase.java |   28 +-
 .../util/mime/QuotedPrintableDecoderTestCase.java  |   90 +-
 .../util/mime/RFC2231UtilityTestCase.java          |   50 +-
 58 files changed, 3259 insertions(+), 3890 deletions(-)
 delete mode 100644 src/main/java/org/apache/commons/fileupload2/pub/FileCountLimitExceededException.java
 rename src/main/java/org/apache/commons/fileupload2/pub/{FileSizeLimitExceededException.java => FileUploadByteCountLimitException.java} (51%)
 rename src/main/java/org/apache/commons/fileupload2/pub/{InvalidContentTypeException.java => FileUploadContentTypeException.java} (51%)
 copy src/main/java/org/apache/commons/fileupload2/pub/{package-info.java => FileUploadFileCountLimitException.java} (57%)
 delete mode 100644 src/main/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java
 rename src/main/java/org/apache/commons/fileupload2/pub/{SizeException.java => FileUploadSizeException.java} (65%)
 delete mode 100644 src/main/java/org/apache/commons/fileupload2/pub/IOFileUploadException.java
 delete mode 100644 src/main/java/org/apache/commons/fileupload2/pub/SizeLimitExceededException.java


[commons-fileupload] 05/08: Remove deprecated fields, methods, and constructors

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

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

commit 54a850b4427cd3bd4866557409c8bc7448005f31
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Apr 2 11:39:32 2023 -0400

    Remove deprecated fields, methods, and constructors
    
    - Constructors in MultipartStream
    - RequestContext.getContentLength()
    - JakSrvltRequestContext.getContentLength()
    - PortletRequestContext.getContentLength()
    - ServletRequestContext.getContentLength()
    - FileUploadBase.MAX_HEADER_SIZE
    - FileUploadBase.createItem(Map<String, String>, boolean)
    - FileUploadBase.getFieldName(Map<String, String>)
    - FileUploadBase.getFileName(Map<String, String>)
    - FileUploadBase.getHeader(Map<String, String>, String)
    - FileUploadBase.parseHeaders(String)
---
 src/changes/changes.xml                            |  12 +++
 .../apache/commons/fileupload2/FileUploadBase.java | 115 ---------------------
 .../commons/fileupload2/MultipartStream.java       |  43 +-------
 .../apache/commons/fileupload2/RequestContext.java |  15 +--
 .../jaksrvlt/JakSrvltRequestContext.java           |  12 ---
 .../fileupload2/portlet/PortletRequestContext.java |  20 ----
 .../fileupload2/servlet/ServletRequestContext.java |  12 ---
 7 files changed, 16 insertions(+), 213 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index a5a7461..1c2cc94 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -59,6 +59,18 @@ The <action> type attribute can be add,update,fix,remove.
       <action                        dev="jochen" type="add">Add the package org.apache.fileupload2.jaksrvlt, for compliance with Jakarta Servlet API 5.0.</action>
       <action                        dev="jochen" type="add">Making FileUploadException a subclass of IOException. (Mibor API simplification.)</action>
       <action                        dev="markt" type="add">Add a configurable limit (disabled by default) for the number of files to upload per request.</action>
+      <!-- REMOVE -->
+      <action                        dev="ggregory" type="remove" due-to="Gary Gregory">Remove deprecated constructors in MultipartStream.</action>
+      <action                        dev="ggregory" type="remove" due-to="Gary Gregory">Remove deprecated RequestContext.getContentLength().</action>
+      <action                        dev="ggregory" type="remove" due-to="Gary Gregory">Remove deprecated JakSrvltRequestContext.getContentLength().</action>
+      <action                        dev="ggregory" type="remove" due-to="Gary Gregory">Remove deprecated PortletRequestContext.getContentLength().</action>
+      <action                        dev="ggregory" type="remove" due-to="Gary Gregory">Remove deprecated ServletRequestContext.getContentLength().</action>
+      <action                        dev="ggregory" type="remove" due-to="Gary Gregory">Remove deprecated FileUploadBase.MAX_HEADER_SIZE.</action>
+      <action                        dev="ggregory" type="remove" due-to="Gary Gregory">Remove deprecated FileUploadBase.createItem(Map, boolean).</action>
+      <action                        dev="ggregory" type="remove" due-to="Gary Gregory">Remove deprecated FileUploadBase.getFieldName(Map).</action>
+      <action                        dev="ggregory" type="remove" due-to="Gary Gregory">Remove deprecated FileUploadBase.getFileName(Map).</action>
+      <action                        dev="ggregory" type="remove" due-to="Gary Gregory">Remove deprecated FileUploadBase.getHeader(Map, String).</action>
+      <action                        dev="ggregory" type="remove" due-to="Gary Gregory">Remove deprecated FileUploadBase.parseHeaders(String).</action>
       <!-- UPDATE -->
       <action                        dev="ggregory" type="update" due-to="Dependabot, Gary Gregory">Bump actions/cache from 2.1.6 to 3.0.8 #128, #140.</action>
       <action                        dev="ggregory" type="update" due-to="Dependabot, Gary Gregory">Bump actions/checkout from 2.3.4 to 3.0.2 #125.</action>
diff --git a/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java b/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
index 193a0b8..58cb26f 100644
--- a/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
+++ b/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
@@ -22,7 +22,6 @@ import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -93,16 +92,6 @@ public abstract class FileUploadBase {
      */
     public static final String MULTIPART_MIXED = "multipart/mixed";
 
-    /**
-     * The maximum length of a single header line that will be parsed
-     * (1024 bytes).
-     * @deprecated This constant is no longer used. As of commons-fileupload
-     *   1.2, the only applicable limit is the total size of a parts headers,
-     *   {@link MultipartStream#HEADER_PART_SIZE_MAX}.
-     */
-    @Deprecated
-    public static final int MAX_HEADER_SIZE = 1024;
-
     /**
      * <p>Utility method that determines whether the request contains multipart
      * content.</p>
@@ -155,32 +144,6 @@ public abstract class FileUploadBase {
      */
     private ProgressListener listener;
 
-    // ----------------------------------------------------- Property accessors
-
-    /**
-     * Creates a new {@link FileItem} instance.
-     *
-     * @param headers       A {@code Map} containing the HTTP request
-     *                      headers.
-     * @param isFormField   Whether or not this item is a form field, as
-     *                      opposed to a file.
-     *
-     * @return A newly created {@code FileItem} instance.
-     *
-     * @throws FileUploadException if an error occurs.
-     * @deprecated 1.2 This method is no longer used in favour of
-     *   internally created instances of {@link FileItem}.
-     */
-    @Deprecated
-    protected FileItem createItem(final Map<String, String> headers,
-                                  final boolean isFormField)
-        throws FileUploadException {
-        return getFileItemFactory().createItem(getFieldName(headers),
-                getHeader(headers, CONTENT_TYPE),
-                isFormField,
-                getFileName(headers));
-    }
-
     /**
      * Retrieves the boundary from the {@code Content-type} header.
      *
@@ -216,20 +179,6 @@ public abstract class FileUploadBase {
         return getFieldName(headers.getHeader(CONTENT_DISPOSITION));
     }
 
-    /**
-     * Retrieves the field name from the {@code Content-disposition}
-     * header.
-     *
-     * @param headers A {@code Map} containing the HTTP request headers.
-     *
-     * @return The field name for the current {@code encapsulation}.
-     * @deprecated 1.2.1 Use {@link #getFieldName(FileItemHeaders)}.
-     */
-    @Deprecated
-    protected String getFieldName(final Map<String, String> headers) {
-        return getFieldName(getHeader(headers, CONTENT_DISPOSITION));
-    }
-
     /**
      * Returns the field name, which is given by the content-disposition
      * header.
@@ -280,20 +229,6 @@ public abstract class FileUploadBase {
         return getFileName(headers.getHeader(CONTENT_DISPOSITION));
     }
 
-    /**
-     * Retrieves the file name from the {@code Content-disposition}
-     * header.
-     *
-     * @param headers A {@code Map} containing the HTTP request headers.
-     *
-     * @return The file name for the current {@code encapsulation}.
-     * @deprecated 1.2.1 Use {@link #getFileName(FileItemHeaders)}.
-     */
-    @Deprecated
-    protected String getFileName(final Map<String, String> headers) {
-        return getFileName(getHeader(headers, CONTENT_DISPOSITION));
-    }
-
     /**
      * Returns the given content-disposition headers file name.
      * @param pContentDisposition The content-disposition headers value.
@@ -324,8 +259,6 @@ public abstract class FileUploadBase {
         return fileName;
     }
 
-    // --------------------------------------------------------- Public methods
-
     /**
      * Returns the maximum allowed size of a single uploaded file,
      * as opposed to {@link #getSizeMax()}.
@@ -337,23 +270,6 @@ public abstract class FileUploadBase {
         return fileSizeMax;
     }
 
-    /**
-     * Returns the header with the specified name from the supplied map. The
-     * header lookup is case-insensitive.
-     *
-     * @param headers A {@code Map} containing the HTTP request headers.
-     * @param name    The name of the header to return.
-     *
-     * @return The value of specified header, or a comma-separated list if
-     *         there were multiple headers of that name.
-     * @deprecated 1.2.1 Use {@link FileItemHeaders#getHeader(String)}.
-     */
-    @Deprecated
-    protected final String getHeader(final Map<String, String> headers,
-            final String name) {
-        return headers.get(name.toLowerCase(Locale.ENGLISH));
-    }
-
     /**
      * Retrieves the character encoding used when reading the headers of an
      * individual part. When not specified, or {@code null}, the request
@@ -366,8 +282,6 @@ public abstract class FileUploadBase {
         return headerEncoding;
     }
 
-    // ------------------------------------------------------ Protected methods
-
     /**
      * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
      * compliant {@code multipart/form-data} stream.
@@ -504,35 +418,6 @@ public abstract class FileUploadBase {
         headers.addHeader(headerName, headerValue);
     }
 
-    /**
-     * <p> Parses the {@code header-part} and returns as key/value
-     * pairs.
-     *
-     * <p> If there are multiple headers of the same names, the name
-     * will map to a comma-separated list containing the values.
-     *
-     * @param headerPart The {@code header-part} of the current
-     *                   {@code encapsulation}.
-     *
-     * @return A {@code Map} containing the parsed HTTP request headers.
-     * @deprecated 1.2.1 Use {@link #getParsedHeaders(String)}
-     */
-    @Deprecated
-    protected Map<String, String> parseHeaders(final String headerPart) {
-        final FileItemHeaders headers = getParsedHeaders(headerPart);
-        final Map<String, String> result = new HashMap<>();
-        for (final Iterator<String> iter = headers.getHeaderNames();  iter.hasNext();) {
-            final String headerName = iter.next();
-            final Iterator<String> iter2 = headers.getHeaders(headerName);
-            final StringBuilder headerValue = new StringBuilder(iter2.next());
-            while (iter2.hasNext()) {
-                headerValue.append(",").append(iter2.next());
-            }
-            result.put(headerName, headerValue.toString());
-        }
-        return result;
-    }
-
     /**
      * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
      * compliant {@code multipart/form-data} stream.
diff --git a/src/main/java/org/apache/commons/fileupload2/MultipartStream.java b/src/main/java/org/apache/commons/fileupload2/MultipartStream.java
index b5168e1..61f8fab 100644
--- a/src/main/java/org/apache/commons/fileupload2/MultipartStream.java
+++ b/src/main/java/org/apache/commons/fileupload2/MultipartStream.java
@@ -570,50 +570,9 @@ public class MultipartStream {
      */
     private final ProgressNotifier notifier;
 
-    /**
-     * Creates a new instance.
-     *
-     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int, ProgressNotifier)}
-     */
-    @Deprecated
-    public MultipartStream() {
-        this(null, null, null);
-    }
-
-    // --------------------------------------------------------- Public methods
 
-    /**
-     * <p>
-     * Constructs a {@code MultipartStream} with a default size buffer.
-     *
-     * @param input    The {@code InputStream} to serve as a data source.
-     * @param boundary The token used for dividing the stream into {@code encapsulations}.
-     *
-     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int, ProgressNotifier)}.
-     */
-    @Deprecated
-    public MultipartStream(final InputStream input, final byte[] boundary) {
-        this(input, boundary, DEFAULT_BUFSIZE, null);
-    }
 
-    /**
-     * <p>
-     * Constructs a {@code MultipartStream} with a custom size buffer and no progress notifier.
-     *
-     * <p>
-     * 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
-     * data. Too small a buffer size setting will degrade performance.
-     *
-     * @param input    The {@code InputStream} to serve as a data source.
-     * @param boundary The token used for dividing the stream into {@code encapsulations}.
-     * @param bufSize  The size of the buffer to be used, in bytes.
-     *
-     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int, ProgressNotifier)}.
-     */
-    @Deprecated
-    public MultipartStream(final InputStream input, final byte[] boundary, final int bufSize) {
-        this(input, boundary, bufSize, null);
-    }
+    // --------------------------------------------------------- Public methods
 
     /**
      * <p>
diff --git a/src/main/java/org/apache/commons/fileupload2/RequestContext.java b/src/main/java/org/apache/commons/fileupload2/RequestContext.java
index 9f4a8d1..8a0e501 100644
--- a/src/main/java/org/apache/commons/fileupload2/RequestContext.java
+++ b/src/main/java/org/apache/commons/fileupload2/RequestContext.java
@@ -29,30 +29,21 @@ import java.io.IOException;
 public interface RequestContext {
 
     /**
-     * Retrieve the character encoding for the request.
+     * Gets the character encoding for the request.
      *
      * @return The character encoding for the request.
      */
     String getCharacterEncoding();
 
     /**
-     * Retrieve the content length of the request.
-     *
-     * @return The content length of the request.
-     * @deprecated 1.3 Use {@link UploadContext#contentLength()} instead
-     */
-    @Deprecated
-    int getContentLength();
-
-    /**
-     * Retrieve the content type of the request.
+     * Gets the content type of the request.
      *
      * @return The content type of the request.
      */
     String getContentType();
 
     /**
-     * Retrieve the input stream for the request.
+     * Gets the input stream for the request.
      *
      * @return The input stream for the request.
      *
diff --git a/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java b/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java
index b0ad720..4a84fc9 100644
--- a/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java
+++ b/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java
@@ -81,18 +81,6 @@ public class JakSrvltRequestContext implements UploadContext {
         return request.getCharacterEncoding();
     }
 
-    /**
-     * Retrieve the content length of the request.
-     *
-     * @return The content length of the request.
-     * @deprecated 1.3 Use {@link #contentLength()} instead
-     */
-    @Override
-    @Deprecated
-    public int getContentLength() {
-        return request.getContentLength();
-    }
-
     /**
      * Retrieve the content type of the request.
      *
diff --git a/src/main/java/org/apache/commons/fileupload2/portlet/PortletRequestContext.java b/src/main/java/org/apache/commons/fileupload2/portlet/PortletRequestContext.java
index 796dfc5..eac6510 100644
--- a/src/main/java/org/apache/commons/fileupload2/portlet/PortletRequestContext.java
+++ b/src/main/java/org/apache/commons/fileupload2/portlet/PortletRequestContext.java
@@ -34,16 +34,11 @@ import org.apache.commons.fileupload2.UploadContext;
  */
 public class PortletRequestContext implements UploadContext {
 
-    // ----------------------------------------------------- Instance Variables
-
     /**
      * The request for which the context is being provided.
      */
     private final ActionRequest request;
 
-
-    // ----------------------------------------------------------- Constructors
-
     /**
      * Construct a context for this request.
      *
@@ -53,9 +48,6 @@ public class PortletRequestContext implements UploadContext {
         this.request = request;
     }
 
-
-    // --------------------------------------------------------- Public Methods
-
     /**
      * Retrieve the content length of the request.
      *
@@ -83,18 +75,6 @@ public class PortletRequestContext implements UploadContext {
         return request.getCharacterEncoding();
     }
 
-    /**
-     * Retrieve the content length of the request.
-     *
-     * @return The content length of the request.
-     * @deprecated 1.3 Use {@link #contentLength()} instead
-     */
-    @Override
-    @Deprecated
-    public int getContentLength() {
-        return request.getContentLength();
-    }
-
     /**
      * Retrieve the content type of the request.
      *
diff --git a/src/main/java/org/apache/commons/fileupload2/servlet/ServletRequestContext.java b/src/main/java/org/apache/commons/fileupload2/servlet/ServletRequestContext.java
index 6919f49..6066294 100644
--- a/src/main/java/org/apache/commons/fileupload2/servlet/ServletRequestContext.java
+++ b/src/main/java/org/apache/commons/fileupload2/servlet/ServletRequestContext.java
@@ -81,18 +81,6 @@ public class ServletRequestContext implements UploadContext {
         return request.getCharacterEncoding();
     }
 
-    /**
-     * Retrieve the content length of the request.
-     *
-     * @return The content length of the request.
-     * @deprecated 1.3 Use {@link #contentLength()} instead
-     */
-    @Override
-    @Deprecated
-    public int getContentLength() {
-        return request.getContentLength();
-    }
-
     /**
      * Retrieve the content type of the request.
      *


[commons-fileupload] 03/08: Propagate exception cause

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

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

commit ae6e9039ba2d2c831fb4ea12638195a43ad02f3f
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Apr 2 10:05:08 2023 -0400

    Propagate exception cause
---
 .../fileupload2/pub/FileUploadIOException.java     | 20 +----------------
 .../fileupload2/pub/IOFileUploadException.java     | 26 ++++------------------
 2 files changed, 5 insertions(+), 41 deletions(-)

diff --git a/src/main/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java b/src/main/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java
index 3dc6e6c..cb3d876 100644
--- a/src/main/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java
+++ b/src/main/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java
@@ -31,13 +31,6 @@ public class FileUploadIOException extends IOException {
      */
     private static final long serialVersionUID = -7047616958165584154L;
 
-    /**
-     * The exceptions cause; we overwrite the parent
-     * classes field, which is available since Java
-     * 1.4 only.
-     */
-    private final FileUploadException cause;
-
     /**
      * Creates a {@code FileUploadIOException} with the
      * given cause.
@@ -45,18 +38,7 @@ public class FileUploadIOException extends IOException {
      * @param cause The exceptions cause, if any, or null.
      */
     public FileUploadIOException(final FileUploadException cause) {
-        // We're not doing super(pCause) cause of 1.3 compatibility.
-        this.cause = cause;
-    }
-
-    /**
-     * Returns the exceptions cause.
-     *
-     * @return The exceptions cause, if any, or null.
-     */
-    @Override
-    public Throwable getCause() {
-        return cause;
+        super(cause);
     }
 
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/pub/IOFileUploadException.java b/src/main/java/org/apache/commons/fileupload2/pub/IOFileUploadException.java
index b93566d..9bdc450 100644
--- a/src/main/java/org/apache/commons/fileupload2/pub/IOFileUploadException.java
+++ b/src/main/java/org/apache/commons/fileupload2/pub/IOFileUploadException.java
@@ -30,32 +30,14 @@ public class IOFileUploadException extends FileUploadException {
      */
     private static final long serialVersionUID = 1749796615868477269L;
 
-    /**
-     * The exceptions cause; we overwrite the parent
-     * classes field, which is available since Java
-     * 1.4 only.
-     */
-    private final IOException cause;
-
     /**
      * Creates a new instance with the given cause.
      *
-     * @param pMsg The detail message.
-     * @param pException The exceptions cause.
-     */
-    public IOFileUploadException(final String pMsg, final IOException pException) {
-        super(pMsg);
-        cause = pException;
-    }
-
-    /**
-     * Returns the exceptions cause.
-     *
-     * @return The exceptions cause, if any, or null.
+     * @param message The detail message.
+     * @param cause The exceptions cause.
      */
-    @Override
-    public Throwable getCause() {
-        return cause;
+    public IOFileUploadException(final String message, final IOException cause) {
+        super(message, cause);
     }
 
 }


[commons-fileupload] 07/08: Fix Javadoc warning

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

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

commit 90de20c933b2f6dc99ea941c84a20baec7d830d2
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Apr 2 11:44:07 2023 -0400

    Fix Javadoc warning
---
 src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java b/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java
index 8b8e00f..134e41f 100644
--- a/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java
@@ -69,7 +69,6 @@ public class ParameterParserTest {
 
     /**
      * Test for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-274">FILEUPLOAD-274</a>
-     * @throws UnsupportedEncodingException
      */
     @Test
     public void testFileUpload274() {


[commons-fileupload] 02/08: Better parameter name

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

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

commit c1cadad09069e46c07384bb1cdb5412892786398
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Apr 2 09:45:28 2023 -0400

    Better parameter name
---
 .../org/apache/commons/fileupload2/pub/FileUploadIOException.java   | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/main/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java b/src/main/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java
index 7f25d7c..3dc6e6c 100644
--- a/src/main/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java
+++ b/src/main/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java
@@ -42,11 +42,11 @@ public class FileUploadIOException extends IOException {
      * Creates a {@code FileUploadIOException} with the
      * given cause.
      *
-     * @param pCause The exceptions cause, if any, or null.
+     * @param cause The exceptions cause, if any, or null.
      */
-    public FileUploadIOException(final FileUploadException pCause) {
+    public FileUploadIOException(final FileUploadException cause) {
         // We're not doing super(pCause) cause of 1.3 compatibility.
-        cause = pCause;
+        this.cause = cause;
     }
 
     /**


[commons-fileupload] 06/08: Organize imports

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

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

commit 86a7e59ddbc1f37e0c182b0e4d49dc8f3ef775fa
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Apr 2 11:39:42 2023 -0400

    Organize imports
---
 src/main/java/org/apache/commons/fileupload2/RequestContext.java      | 2 +-
 .../org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java     | 2 +-
 .../org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUpload.java   | 4 ++--
 .../apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java   | 4 ++--
 .../org/apache/commons/fileupload2/servlet/FileCleanerCleanup.java    | 2 +-
 src/test/java/org/apache/commons/fileupload2/SizesTest.java           | 2 +-
 .../apache/commons/fileupload2/jaksrvlt/JakSrvltFileUploadTest.java   | 4 ++--
 .../apache/commons/fileupload2/jaksrvlt/MockJakSrvltHttpRequest.java  | 1 -
 .../commons/fileupload2/util/mime/QuotedPrintableDecoderTestCase.java | 2 +-
 9 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/src/main/java/org/apache/commons/fileupload2/RequestContext.java b/src/main/java/org/apache/commons/fileupload2/RequestContext.java
index 8a0e501..fa7bed1 100644
--- a/src/main/java/org/apache/commons/fileupload2/RequestContext.java
+++ b/src/main/java/org/apache/commons/fileupload2/RequestContext.java
@@ -16,8 +16,8 @@
  */
 package org.apache.commons.fileupload2;
 
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 
 /**
  * <p>Abstracts access to the request information needed for file uploads. This
diff --git a/src/main/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java b/src/main/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java
index 9bb2e57..4976387 100644
--- a/src/main/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java
+++ b/src/main/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java
@@ -36,8 +36,8 @@ import org.apache.commons.fileupload2.MultipartStream;
 import org.apache.commons.fileupload2.ProgressListener;
 import org.apache.commons.fileupload2.RequestContext;
 import org.apache.commons.fileupload2.UploadContext;
-import org.apache.commons.fileupload2.pub.FileUploadSizeException;
 import org.apache.commons.fileupload2.pub.FileUploadContentTypeException;
+import org.apache.commons.fileupload2.pub.FileUploadSizeException;
 import org.apache.commons.fileupload2.util.LimitedInputStream;
 import org.apache.commons.io.IOUtils;
 
diff --git a/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUpload.java b/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUpload.java
index 48689c5..088918d 100644
--- a/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUpload.java
+++ b/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUpload.java
@@ -20,8 +20,6 @@ import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 
-import jakarta.servlet.http.HttpServletRequest;
-
 import org.apache.commons.fileupload2.FileItem;
 import org.apache.commons.fileupload2.FileItemFactory;
 import org.apache.commons.fileupload2.FileItemIterator;
@@ -29,6 +27,8 @@ import org.apache.commons.fileupload2.FileUpload;
 import org.apache.commons.fileupload2.FileUploadBase;
 import org.apache.commons.fileupload2.FileUploadException;
 
+import jakarta.servlet.http.HttpServletRequest;
+
 /**
  * <p>High level API for processing file uploads.</p>
  *
diff --git a/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java b/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java
index 4a84fc9..cb40ab7 100644
--- a/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java
+++ b/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java
@@ -21,11 +21,11 @@ import static java.lang.String.format;
 import java.io.IOException;
 import java.io.InputStream;
 
-import jakarta.servlet.http.HttpServletRequest;
-
 import org.apache.commons.fileupload2.FileUploadBase;
 import org.apache.commons.fileupload2.UploadContext;
 
+import jakarta.servlet.http.HttpServletRequest;
+
 /**
  * <p>Provides access to the request information needed for a request made to
  * an HTTP servlet.</p>
diff --git a/src/main/java/org/apache/commons/fileupload2/servlet/FileCleanerCleanup.java b/src/main/java/org/apache/commons/fileupload2/servlet/FileCleanerCleanup.java
index 3854226..f429b2d 100644
--- a/src/main/java/org/apache/commons/fileupload2/servlet/FileCleanerCleanup.java
+++ b/src/main/java/org/apache/commons/fileupload2/servlet/FileCleanerCleanup.java
@@ -17,8 +17,8 @@
 package org.apache.commons.fileupload2.servlet;
 
 import javax.servlet.ServletContext;
-import javax.servlet.ServletContextListener;
 import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
 
 import org.apache.commons.io.FileCleaningTracker;
 
diff --git a/src/test/java/org/apache/commons/fileupload2/SizesTest.java b/src/test/java/org/apache/commons/fileupload2/SizesTest.java
index 574f35c..398b87d 100644
--- a/src/test/java/org/apache/commons/fileupload2/SizesTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/SizesTest.java
@@ -31,8 +31,8 @@ import java.util.List;
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.commons.fileupload2.disk.DiskFileItemFactory;
-import org.apache.commons.fileupload2.pub.FileUploadSizeException;
 import org.apache.commons.fileupload2.pub.FileUploadByteCountLimitException;
+import org.apache.commons.fileupload2.pub.FileUploadSizeException;
 import org.apache.commons.fileupload2.servlet.ServletFileUpload;
 import org.apache.commons.fileupload2.util.Streams;
 import org.junit.jupiter.api.Test;
diff --git a/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUploadTest.java b/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUploadTest.java
index db0eb55..0fe2339 100644
--- a/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUploadTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUploadTest.java
@@ -23,14 +23,14 @@ import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Map;
 
-import jakarta.servlet.http.HttpServletRequest;
-
 import org.apache.commons.fileupload2.Constants;
 import org.apache.commons.fileupload2.FileItem;
 import org.apache.commons.fileupload2.FileUploadTest;
 import org.apache.commons.fileupload2.disk.DiskFileItemFactory;
 import org.junit.jupiter.api.Test;
 
+import jakarta.servlet.http.HttpServletRequest;
+
 /**
  * Test for {@link org.apache.commons.fileupload2.servlet.ServletFileUpload}.
  *
diff --git a/src/test/java/org/apache/commons/fileupload2/jaksrvlt/MockJakSrvltHttpRequest.java b/src/test/java/org/apache/commons/fileupload2/jaksrvlt/MockJakSrvltHttpRequest.java
index fe4e230..f8a5982 100644
--- a/src/test/java/org/apache/commons/fileupload2/jaksrvlt/MockJakSrvltHttpRequest.java
+++ b/src/test/java/org/apache/commons/fileupload2/jaksrvlt/MockJakSrvltHttpRequest.java
@@ -27,7 +27,6 @@ import java.util.Enumeration;
 import java.util.Locale;
 import java.util.Map;
 
-
 import org.apache.commons.fileupload2.FileUploadBase;
 
 import jakarta.servlet.AsyncContext;
diff --git a/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoderTestCase.java b/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoderTestCase.java
index 8e4df90..f685a06 100644
--- a/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoderTestCase.java
+++ b/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoderTestCase.java
@@ -18,8 +18,8 @@ package org.apache.commons.fileupload2.util.mime;
 
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.fail;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;


[commons-fileupload] 04/08: Rework exceptions to use propagated exception causes (introduced in Java 1.4)

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

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

commit 355d264689c8430a4ee7bd8dfd36fcf8d9459bcf
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Apr 2 11:23:58 2023 -0400

    Rework exceptions to use propagated exception causes (introduced in Java
    1.4)
    
    - All custom exception extend FileUploadException
    - Simplify and clarify exception hierarchy
    - All custom exceptions serialVersionUID value is now 2.
---
 src/changes/changes.xml                            |   3 +
 src/checkstyle/fileupload_checks.xml               |   3 +-
 .../commons/fileupload2/FileItemIterator.java      |   9 +-
 .../apache/commons/fileupload2/FileUploadBase.java |  29 +-
 .../commons/fileupload2/FileUploadException.java   |  77 +---
 .../commons/fileupload2/MultipartStream.java       | 408 +++++++++------------
 .../commons/fileupload2/ProgressListener.java      |  14 +-
 .../fileupload2/impl/FileItemIteratorImpl.java     | 115 +++---
 .../fileupload2/impl/FileItemStreamImpl.java       |  93 ++---
 .../pub/FileCountLimitExceededException.java       |  53 ---
 ...java => FileUploadByteCountLimitException.java} |  52 +--
 ...on.java => FileUploadContentTypeException.java} |  39 +-
 ...java => FileUploadFileCountLimitException.java} |  80 ++--
 .../fileupload2/pub/FileUploadIOException.java     |  44 ---
 ...Exception.java => FileUploadSizeException.java} |  29 +-
 .../pub/SizeLimitExceededException.java            |  43 ---
 .../fileupload2/servlet/ServletFileUpload.java     |  13 +-
 .../fileupload2/util/LimitedInputStream.java       |  12 +-
 .../apache/commons/fileupload2/util/Streams.java   |   8 +-
 .../org/apache/commons/fileupload2/SizesTest.java  |  25 +-
 .../apache/commons/fileupload2/StreamingTest.java  |   4 +-
 21 files changed, 393 insertions(+), 760 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index f077bc4..a5a7461 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -51,6 +51,9 @@ The <action> type attribute can be add,update,fix,remove.
       <action                        dev="ggregory" type="fix" due-to="Emmanuel Lécharny">Slight optim: resuse the index position instead of recomputing it #49.</action>
       <action issue="FILEUPLOAD-340" dev="mgrigorov" type="fix">Make commons-fileupload2 a JPMS module by adding module-info.class.</action>
       <action issue="FILEUPLOAD-341" dev="jochen" type="fix" due-to="Martin Grigorov">Move Exception classes out of the impl package.</action>
+      <action                        dev="ggregory" type="fix" due-to="Gary Gregory">Rework exceptions to use propagated exception causes (introduced in Java 1.4).</action>
+      <action                        dev="ggregory" type="fix" due-to="Gary Gregory">All custom exception extend FileUploadException.</action>
+      <action                        dev="ggregory" type="fix" due-to="Gary Gregory">All custom exceptions serialVersionUID value is now 2.</action>
       <!-- ADD -->
       <action                        dev="ggregory" type="add" due-to="Gary Gregory">Add github/codeql-action from #144.</action>
       <action                        dev="jochen" type="add">Add the package org.apache.fileupload2.jaksrvlt, for compliance with Jakarta Servlet API 5.0.</action>
diff --git a/src/checkstyle/fileupload_checks.xml b/src/checkstyle/fileupload_checks.xml
index de07ed9..686e015 100644
--- a/src/checkstyle/fileupload_checks.xml
+++ b/src/checkstyle/fileupload_checks.xml
@@ -90,7 +90,7 @@
 
     <!-- Begin Custom for FileUpload -->
     <module name="LineLength">
-        <property name="max" value="120"/>
+        <property name="max" value="160"/>
         <property name="ignorePattern" value="^ \* @version .*$"/>
     </module>
 
@@ -168,7 +168,6 @@
         <!-- Checks for whitespace                               -->
         <!-- See http://checkstyle.sf.net/config_whitespace.html -->
         <module name="EmptyForIteratorPad"/>
-        <module name="NoWhitespaceAfter"/>
         <module name="NoWhitespaceBefore"/>
         <module name="OperatorWrap"/>
         <module name="ParenPad"/>
diff --git a/src/main/java/org/apache/commons/fileupload2/FileItemIterator.java b/src/main/java/org/apache/commons/fileupload2/FileItemIterator.java
index 129442e..1fa5f5d 100644
--- a/src/main/java/org/apache/commons/fileupload2/FileItemIterator.java
+++ b/src/main/java/org/apache/commons/fileupload2/FileItemIterator.java
@@ -19,8 +19,9 @@ package org.apache.commons.fileupload2;
 import java.io.IOException;
 import java.util.List;
 
-import org.apache.commons.fileupload2.pub.FileSizeLimitExceededException;
-import org.apache.commons.fileupload2.pub.SizeLimitExceededException;
+import javax.naming.SizeLimitExceededException;
+
+import org.apache.commons.fileupload2.pub.FileUploadByteCountLimitException;
 
 /**
  * An iterator, as returned by
@@ -29,7 +30,7 @@ import org.apache.commons.fileupload2.pub.SizeLimitExceededException;
 public interface FileItemIterator {
     List<FileItem> getFileItems() throws FileUploadException, IOException;
 
-    /** Returns the maximum size of a single file. An {@link FileSizeLimitExceededException}
+    /** Returns the maximum size of a single file. An {@link FileUploadByteCountLimitException}
      * 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
@@ -72,7 +73,7 @@ public interface FileItemIterator {
      */
     FileItemStream next() throws FileUploadException, IOException;
 
-    /** Sets the maximum size of a single file. An {@link FileSizeLimitExceededException}
+    /** Sets the maximum size of a single file. An {@link FileUploadByteCountLimitException}
      * 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
diff --git a/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java b/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
index e62af9b..193a0b8 100644
--- a/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
+++ b/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
@@ -29,9 +29,7 @@ import java.util.Map;
 import java.util.Objects;
 
 import org.apache.commons.fileupload2.impl.FileItemIteratorImpl;
-import org.apache.commons.fileupload2.pub.FileCountLimitExceededException;
-import org.apache.commons.fileupload2.pub.FileUploadIOException;
-import org.apache.commons.fileupload2.pub.IOFileUploadException;
+import org.apache.commons.fileupload2.pub.FileUploadFileCountLimitException;
 import org.apache.commons.fileupload2.util.FileItemHeadersImpl;
 import org.apache.commons.fileupload2.util.Streams;
 
@@ -386,14 +384,8 @@ public abstract class FileUploadBase {
      *   error while communicating with the client or a problem while
      *   storing the uploaded content.
      */
-    public FileItemIterator getItemIterator(final RequestContext ctx)
-    throws FileUploadException, IOException {
-        try {
-            return new FileItemIteratorImpl(this, ctx);
-        } catch (final FileUploadIOException e) {
-            // unwrap encapsulated SizeException
-            throw (FileUploadException) e.getCause();
-        }
+    public FileItemIterator getItemIterator(final RequestContext ctx) throws FileUploadException, IOException {
+        return new FileItemIteratorImpl(this, ctx);
     }
 
     /**
@@ -587,27 +579,24 @@ public abstract class FileUploadBase {
         boolean successful = false;
         try {
             final FileItemIterator iter = getItemIterator(ctx);
-            final FileItemFactory fileItemFactory = Objects.requireNonNull(getFileItemFactory(),
-                    "No FileItemFactory has been set.");
+            final FileItemFactory fileItemFactory = Objects.requireNonNull(getFileItemFactory(), "No FileItemFactory has been set.");
             final byte[] buffer = new byte[Streams.DEFAULT_BUFFER_SIZE];
             while (iter.hasNext()) {
                 if (items.size() == fileCountMax) {
                     // The next item will exceed the limit.
-                    throw new FileCountLimitExceededException(ATTACHMENT, getFileCountMax());
+                    throw new FileUploadFileCountLimitException(ATTACHMENT, getFileCountMax(), items.size());
                 }
                 final FileItemStream item = iter.next();
                 // Don't use getName() here to prevent an InvalidFileNameException.
                 final String fileName = item.getName();
-                final FileItem fileItem = fileItemFactory.createItem(item.getFieldName(), item.getContentType(),
-                                                   item.isFormField(), fileName);
+                final FileItem fileItem = fileItemFactory.createItem(item.getFieldName(), item.getContentType(), item.isFormField(), fileName);
                 items.add(fileItem);
                 try {
                     Streams.copy(item.openStream(), fileItem.getOutputStream(), true, buffer);
-                } catch (final FileUploadIOException e) {
-                    throw (FileUploadException) e.getCause();
+                } catch (final FileUploadException e) {
+                    throw e;
                 } catch (final IOException e) {
-                    throw new IOFileUploadException(format("Processing of %s request failed. %s",
-                                                           MULTIPART_FORM_DATA, e.getMessage()), e);
+                    throw new FileUploadException(format("Processing of %s request failed. %s", MULTIPART_FORM_DATA, e.getMessage()), e);
                 }
                 final FileItemHeaders fih = item.getHeaders();
                 fileItem.setHeaders(fih);
diff --git a/src/main/java/org/apache/commons/fileupload2/FileUploadException.java b/src/main/java/org/apache/commons/fileupload2/FileUploadException.java
index 1ca5f91..5a54592 100644
--- a/src/main/java/org/apache/commons/fileupload2/FileUploadException.java
+++ b/src/main/java/org/apache/commons/fileupload2/FileUploadException.java
@@ -17,90 +17,41 @@
 package org.apache.commons.fileupload2;
 
 import java.io.IOException;
-import java.io.PrintStream;
-import java.io.PrintWriter;
 
 /**
- * Exception for errors encountered while processing the request.
+ * Signals errors encountered while processing the request.
  */
 public class FileUploadException extends IOException {
 
     /**
-     * Serial version UID, being used, if the exception
-     * is serialized.
+     * Serial version UID, being used, if the exception is serialized.
      */
-    private static final long serialVersionUID = 8881893724388807504L;
+    private static final long serialVersionUID = 2;
 
     /**
-     * The exceptions cause. We overwrite the cause of
-     * the super class, which isn't available in Java 1.3.
-     */
-    private final Throwable cause;
-
-    /**
-     * Constructs a new {@code FileUploadException} without message.
+     * Constructs a new instance.
      */
     public FileUploadException() {
-        this(null, null);
-    }
-
-    /**
-     * Constructs a new {@code FileUploadException} with specified detail
-     * message.
-     *
-     * @param msg the error message.
-     */
-    public FileUploadException(final String msg) {
-        this(msg, null);
-    }
-
-    /**
-     * Creates a new {@code FileUploadException} with the given
-     * detail message and cause.
-     *
-     * @param msg The exceptions detail message.
-     * @param cause The exceptions cause.
-     */
-    public FileUploadException(final String msg, final Throwable cause) {
-        super(msg);
-        this.cause = cause;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Throwable getCause() {
-        return cause;
     }
 
     /**
-     * Prints this throwable and its backtrace to the specified print stream.
+     * Constructs an instance with a given detail message.
      *
-     * @param stream {@code PrintStream} to use for output
+     * @param message The detail message (which is saved for later retrieval by the {@link #getMessage()} method)
      */
-    @Override
-    public void printStackTrace(final PrintStream stream) {
-        super.printStackTrace(stream);
-        if (cause != null) {
-            stream.println("Caused by:");
-            cause.printStackTrace(stream);
-        }
+    public FileUploadException(final String message) {
+        super(message);
     }
 
     /**
-     * Prints this throwable and its backtrace to the specified
-     * print writer.
+     * Constructs an instance with the given detail message and cause.
      *
-     * @param writer {@code PrintWriter} to use for output
+     * @param message The detail message (which is saved for later retrieval by the {@link #getMessage()} method)
+     * @param cause   The cause (which is saved for later retrieval by the {@link #getCause()} method). (A null value is permitted, and indicates that the cause
+     *                is nonexistent or unknown.)
      */
-    @Override
-    public void printStackTrace(final PrintWriter writer) {
-        super.printStackTrace(writer);
-        if (cause != null) {
-            writer.println("Caused by:");
-            cause.printStackTrace(writer);
-        }
+    public FileUploadException(final String message, final Throwable cause) {
+        super(message, cause);
     }
 
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/MultipartStream.java b/src/main/java/org/apache/commons/fileupload2/MultipartStream.java
index c9e3288..b5168e1 100644
--- a/src/main/java/org/apache/commons/fileupload2/MultipartStream.java
+++ b/src/main/java/org/apache/commons/fileupload2/MultipartStream.java
@@ -24,20 +24,20 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 
-import org.apache.commons.fileupload2.pub.FileUploadIOException;
+import org.apache.commons.fileupload2.pub.FileUploadSizeException;
 import org.apache.commons.fileupload2.util.Closeable;
 import org.apache.commons.fileupload2.util.Streams;
 
 /**
- * <p> Low level API for processing file uploads.
+ * <p>
+ * Signals low-level API for processing file uploads.
  *
- * <p> 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 1867</a>. Arbitrarily
- * large amounts of data in the stream can be processed under constant
- * memory usage.
+ * <p>
+ * 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
+ * 1867</a>. Arbitrarily large amounts of data in the stream can be processed under constant memory usage.
  *
- * <p> The format of the stream is defined in the following way:<br>
+ * <p>
+ * The format of the stream is defined in the following way:<br>
  *
  * <code>
  *   multipart-body := preamble 1*encapsulation close-delimiter epilogue<br>
@@ -54,31 +54,30 @@ import org.apache.commons.fileupload2.util.Streams;
  *   body-data := &lt;arbitrary data&gt;<br>
  * </code>
  *
- * <p>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 <strong>required</strong> to have a
- * boundary token of the same length as the parent stream (see {@link
- * #setBoundary(byte[])}).
+ * <p>
+ * 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
+ * <strong>required</strong> to have a boundary token of the same length as the parent stream (see {@link #setBoundary(byte[])}).
  *
- * <p>Here is an example of usage of this class.<br>
+ * <p>
+ * Here is an example of usage of this class.<br>
  *
  * <pre>
- *   try {
+ * try {
  *     MultipartStream multipartStream = new MultipartStream(input, boundary);
  *     boolean nextPart = multipartStream.skipPreamble();
  *     OutputStream output;
- *     while(nextPart) {
- *       String header = multipartStream.readHeaders();
- *       // process headers
- *       // create some output stream
- *       multipartStream.readBodyData(output);
- *       nextPart = multipartStream.readBoundary();
+ *     while (nextPart) {
+ *         String header = multipartStream.readHeaders();
+ *         // process headers
+ *         // create some output stream
+ *         multipartStream.readBodyData(output);
+ *         nextPart = multipartStream.readBoundary();
  *     }
- *   } catch(MultipartStream.MalformedStreamException e) {
+ * } catch (MultipartStream.MalformedStreamException e) {
  *     // the stream failed to follow required syntax
- *   } catch(IOException e) {
+ * } catch (IOException e) {
  *     // a read or write error occurred
- *   }
+ * }
  * </pre>
  */
 public class MultipartStream {
@@ -86,34 +85,24 @@ public class MultipartStream {
     /**
      * Thrown upon attempt of setting an invalid boundary token.
      */
-    public static class IllegalBoundaryException extends IOException {
+    public static class FileUploadBoundaryException extends FileUploadException {
 
         /**
          * The UID to use when serializing this instance.
          */
-        private static final long serialVersionUID = -161533165102632918L;
+        private static final long serialVersionUID = 2;
 
         /**
-         * Constructs an {@code IllegalBoundaryException} with no
-         * detail message.
-         */
-        public IllegalBoundaryException() {
-        }
-
-        /**
-         * Constructs an {@code IllegalBoundaryException} with
-         * the specified detail message.
+         * Constructs an instance with the specified detail message.
          *
-         * @param message The detail message.
+         * @param message The detail message (which is saved for later retrieval by the {@link #getMessage()} method)
          */
-        public IllegalBoundaryException(final String message) {
+        public FileUploadBoundaryException(final String message) {
             super(message);
         }
 
     }
 
-    // ----------------------------------------------------- Manifest constants
-
     /**
      * An {@link InputStream} for reading an items contents.
      */
@@ -130,8 +119,7 @@ public class MultipartStream {
         private long total;
 
         /**
-         * The number of bytes, which must be hold, because
-         * they might be a part of the boundary.
+         * The number of bytes, which must be hold, because they might be a part of the boundary.
          */
         private int pad;
 
@@ -153,8 +141,7 @@ public class MultipartStream {
         }
 
         /**
-         * Returns the number of bytes, which are currently
-         * available, without blocking.
+         * Returns the number of bytes, which are currently available, without blocking.
          *
          * @throws IOException An I/O error occurs.
          * @return Number of bytes in the buffer.
@@ -180,8 +167,7 @@ public class MultipartStream {
         /**
          * Closes the input stream.
          *
-         * @param pCloseUnderlying Whether to close the underlying stream
-         *   (hard close)
+         * @param pCloseUnderlying Whether to close the underlying stream (hard close)
          * @throws IOException An I/O error occurred.
          */
         public void close(final boolean pCloseUnderlying) throws IOException {
@@ -221,8 +207,7 @@ public class MultipartStream {
         }
 
         /**
-         * Returns the number of bytes, which have been read
-         * by the stream.
+         * Returns the number of bytes, which have been read by the stream.
          *
          * @return Number of bytes, which have been read so far.
          */
@@ -285,8 +270,7 @@ public class MultipartStream {
         /**
          * Returns the next byte in the stream.
          *
-         * @return The next byte in the stream, as a non-negative
-         *   integer, or -1 for EOF.
+         * @return The next byte in the stream, as a non-negative integer, or -1 for EOF.
          * @throws IOException An I/O error occurred.
          */
         @Override
@@ -308,11 +292,10 @@ public class MultipartStream {
         /**
          * Reads bytes into the given buffer.
          *
-         * @param b The destination buffer, where to write to.
+         * @param b   The destination buffer, where to write to.
          * @param off Offset of the first byte in the buffer.
          * @param len Maximum number of bytes to read.
-         * @return Number of bytes, which have been actually read,
-         *   or -1 for EOF.
+         * @return Number of bytes, which have been actually read, or -1 for EOF.
          * @throws IOException An I/O error occurred.
          */
         @Override
@@ -341,8 +324,7 @@ public class MultipartStream {
          * Skips the given number of bytes.
          *
          * @param bytes Number of bytes to skip.
-         * @return The number of bytes, which have actually been
-         *   skipped.
+         * @return The number of bytes, which have actually been skipped.
          * @throws IOException An I/O error occurred.
          */
         @Override
@@ -365,8 +347,7 @@ public class MultipartStream {
     }
 
     /**
-     * Thrown to indicate that the input stream fails to follow the
-     * required syntax.
+     * Thrown to indicate that the input stream fails to follow the required syntax.
      */
     public static class MalformedStreamException extends IOException {
 
@@ -376,34 +357,36 @@ public class MultipartStream {
         private static final long serialVersionUID = 6466926458059796677L;
 
         /**
-         * Constructs a {@code MalformedStreamException} with no
-         * detail message.
+         * Constructs an {@code MalformedStreamException} with the specified detail message.
+         *
+         * @param message The detail message.
          */
-        public MalformedStreamException() {
+        public MalformedStreamException(final String message) {
+            super(message);
         }
 
         /**
-         * Constructs an {@code MalformedStreamException} with
-         * the specified detail message.
+         * Constructs an {@code MalformedStreamException} with the specified detail message.
          *
          * @param message The detail message.
+         * @param cause   The cause (which is saved for later retrieval by the {@link #getCause()} method). (A null value is permitted, and indicates that the
+         *                cause is nonexistent or unknown.)
          */
-        public MalformedStreamException(final String message) {
-            super(message);
+        public MalformedStreamException(final String message, final Throwable cause) {
+            super(message, cause);
         }
 
     }
 
     /**
-     * Internal class, which is used to invoke the
-     * {@link ProgressListener}.
+     * Internal class, which is used to invoke the {@link ProgressListener}.
      */
     public static class ProgressNotifier {
 
         /**
          * The listener to invoke.
          */
-        private final ProgressListener listener;
+        private final ProgressListener progressListener;
 
         /**
          * Number of expected bytes, if known, or -1.
@@ -421,15 +404,14 @@ public class MultipartStream {
         private int items;
 
         /**
-         * Creates a new instance with the given listener
-         * and content length.
+         * Creates a new instance with the given listener and content length.
          *
-         * @param pListener The listener to invoke.
-         * @param pContentLength The expected content length.
+         * @param progressListener      The listener to invoke.
+         * @param contentLength The expected content length.
          */
-        public ProgressNotifier(final ProgressListener pListener, final long pContentLength) {
-            listener = pListener;
-            contentLength = pContentLength;
+        public ProgressNotifier(final ProgressListener progressListener, final long contentLength) {
+            this.progressListener = progressListener;
+            this.contentLength = contentLength;
         }
 
         /**
@@ -438,8 +420,8 @@ public class MultipartStream {
          * @param pBytes Number of bytes, which have been read.
          */
         void noteBytesRead(final int pBytes) {
-            /* Indicates, that the given number of bytes have been read from
-             * the input stream.
+            /*
+             * Indicates, that the given number of bytes have been read from the input stream.
              */
             bytesRead += pBytes;
             notifyListener();
@@ -457,8 +439,8 @@ public class MultipartStream {
          * Called for notifying the listener.
          */
         private void notifyListener() {
-            if (listener != null) {
-                listener.update(bytesRead, contentLength, items);
+            if (progressListener != null) {
+                progressListener.update(bytesRead, contentLength, items);
             }
         }
 
@@ -480,8 +462,7 @@ public class MultipartStream {
     public static final byte DASH = 0x2D;
 
     /**
-     * The maximum length of {@code header-part} that will be
-     * processed (10 kilobytes = 10240 bytes.).
+     * The maximum length of {@code header-part} that will be processed (10 kilobytes = 10240 bytes.).
      */
     public static final int HEADER_PART_SIZE_MAX = 10240;
 
@@ -491,44 +472,37 @@ public class MultipartStream {
     protected static final int DEFAULT_BUFSIZE = 4096;
 
     /**
-     * A byte sequence that marks the end of {@code header-part}
-     * ({@code CRLFCRLF}).
+     * A byte sequence that marks the end of {@code header-part} ({@code CRLFCRLF}).
      */
-    protected static final byte[] HEADER_SEPARATOR = {CR, LF, CR, LF};
+    protected static final byte[] HEADER_SEPARATOR = { CR, LF, CR, LF };
 
     // ----------------------------------------------------------- Data members
 
     /**
-     * A byte sequence that that follows a delimiter that will be
-     * followed by an encapsulation ({@code CRLF}).
+     * A byte sequence that that follows a delimiter that will be followed by an encapsulation ({@code CRLF}).
      */
-    protected static final byte[] FIELD_SEPARATOR = {CR, LF};
+    protected static final byte[] FIELD_SEPARATOR = { CR, LF };
 
     /**
-     * A byte sequence that that follows a delimiter of the last
-     * encapsulation in the stream ({@code --}).
+     * A byte sequence that that follows a delimiter of the last encapsulation in the stream ({@code --}).
      */
-    protected static final byte[] STREAM_TERMINATOR = {DASH, DASH};
+    protected static final byte[] STREAM_TERMINATOR = { DASH, DASH };
 
     /**
      * A byte sequence that precedes a boundary ({@code CRLF--}).
      */
-    protected static final byte[] BOUNDARY_PREFIX = {CR, LF, DASH, DASH};
+    protected static final byte[] BOUNDARY_PREFIX = { CR, LF, DASH, DASH };
 
     /**
-     * Compares {@code count} first bytes in the arrays
-     * {@code a} and {@code b}.
+     * Compares {@code count} first bytes in the arrays {@code a} and {@code b}.
      *
      * @param a     The first array to compare.
      * @param b     The second array to compare.
      * @param count How many bytes should be compared.
      *
-     * @return {@code true} if {@code count} first bytes in arrays
-     *         {@code a} and {@code b} are equal.
+     * @return {@code true} if {@code count} first bytes in arrays {@code a} and {@code b} are equal.
      */
-    public static boolean arrayequals(final byte[] a,
-            final byte[] b,
-            final int count) {
+    public static boolean arrayequals(final byte[] a, final byte[] b, final int count) {
         for (int i = 0; i < count; i++) {
             if (a[i] != b[i]) {
                 return false;
@@ -548,8 +522,7 @@ public class MultipartStream {
     private int boundaryLength;
 
     /**
-     * The amount of data, in bytes, that must be kept in the buffer in order
-     * to detect delimiters reliably.
+     * The amount of data, in bytes, that must be kept in the buffer in order to detect delimiters reliably.
      */
     private final int keepRegion;
 
@@ -576,15 +549,13 @@ public class MultipartStream {
     // ----------------------------------------------------------- Constructors
 
     /**
-     * The index of first valid character in the buffer.
-     * <br>
+     * The index of first valid character in the buffer. <br>
      * 0 <= head < bufSize
      */
     private int head;
 
     /**
-     * The index of last valid character in the buffer + 1.
-     * <br>
+     * The index of last valid character in the buffer + 1. <br>
      * 0 <= tail <= bufSize
      */
     private int tail;
@@ -602,8 +573,7 @@ public class MultipartStream {
     /**
      * Creates a new instance.
      *
-     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int,
-     * ProgressNotifier)}
+     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int, ProgressNotifier)}
      */
     @Deprecated
     public MultipartStream() {
@@ -613,37 +583,32 @@ public class MultipartStream {
     // --------------------------------------------------------- Public methods
 
     /**
-     * <p> Constructs a {@code MultipartStream} with a default size buffer.
+     * <p>
+     * Constructs a {@code MultipartStream} with a default size buffer.
      *
      * @param input    The {@code InputStream} to serve as a data source.
-     * @param boundary The token used for dividing the stream into
-     *                 {@code encapsulations}.
+     * @param boundary The token used for dividing the stream into {@code encapsulations}.
      *
-     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int,
-     *  ProgressNotifier)}.
+     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int, ProgressNotifier)}.
      */
     @Deprecated
-    public MultipartStream(final InputStream input,
-            final byte[] boundary) {
+    public MultipartStream(final InputStream input, final byte[] boundary) {
         this(input, boundary, DEFAULT_BUFSIZE, null);
     }
 
     /**
-     * <p> Constructs a {@code MultipartStream} with a custom size buffer
-     * and no progress notifier.
+     * <p>
+     * Constructs a {@code MultipartStream} with a custom size buffer and no progress notifier.
      *
-     * <p> 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 data.  Too small a buffer size setting will degrade
-     * performance.
+     * <p>
+     * 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
+     * data. Too small a buffer size setting will degrade performance.
      *
      * @param input    The {@code InputStream} to serve as a data source.
-     * @param boundary The token used for dividing the stream into
-     *                 {@code encapsulations}.
+     * @param boundary The token used for dividing the stream into {@code encapsulations}.
      * @param bufSize  The size of the buffer to be used, in bytes.
      *
-     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int,
-     * ProgressNotifier)}.
+     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int, ProgressNotifier)}.
      */
     @Deprecated
     public MultipartStream(final InputStream input, final byte[] boundary, final int bufSize) {
@@ -651,28 +616,21 @@ public class MultipartStream {
     }
 
     /**
-     * <p> Constructs a {@code MultipartStream} with a custom size buffer.
-     *
-     * <p> 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 data.  Too small a buffer size setting will degrade
-     * performance.
-     *
-     * @param input    The {@code InputStream} to serve as a data source.
-     * @param boundary The token used for dividing the stream into
-     *                 {@code encapsulations}.
-     * @param bufSize  The size of the buffer to be used, in bytes.
-     * @param pNotifier The notifier, which is used for calling the
-     *                  progress listener, if any.
+     * <p>
+     * Constructs a {@code MultipartStream} with a custom size buffer.
      *
-     * @throws IllegalArgumentException If the buffer size is too small
+     * <p>
+     * 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
+     * data. Too small a buffer size setting will degrade performance.
      *
+     * @param input     The {@code InputStream} to serve as a data source.
+     * @param boundary  The token used for dividing the stream into {@code encapsulations}.
+     * @param bufferSize   The size of the buffer to be used, in bytes.
+     * @param pNotifier The notifier, which is used for calling the progress listener, if any.
+     * @throws IllegalArgumentException If the buffer size is too small.
      * @since 1.3.1
      */
-    public MultipartStream(final InputStream input,
-            final byte[] boundary,
-            final int bufSize,
-            final ProgressNotifier pNotifier) {
+    public MultipartStream(final InputStream input, final byte[] boundary, final int bufferSize, final ProgressNotifier pNotifier) {
 
         if (boundary == null) {
             throw new IllegalArgumentException("boundary may not be null");
@@ -680,13 +638,12 @@ public class MultipartStream {
         // We prepend CR/LF to the boundary to chop trailing CR/LF from
         // body-data tokens.
         this.boundaryLength = boundary.length + BOUNDARY_PREFIX.length;
-        if (bufSize < this.boundaryLength + 1) {
-            throw new IllegalArgumentException(
-                    "The buffer size specified for the MultipartStream is too small");
+        if (bufferSize < this.boundaryLength + 1) {
+            throw new IllegalArgumentException("The buffer size specified for the MultipartStream is too small");
         }
 
         this.input = input;
-        this.bufSize = Math.max(bufSize, boundaryLength * 2);
+        this.bufSize = Math.max(bufferSize, boundaryLength * 2);
         this.buffer = new byte[this.bufSize];
         this.notifier = pNotifier;
 
@@ -694,10 +651,8 @@ public class MultipartStream {
         this.boundaryTable = new int[this.boundaryLength + 1];
         this.keepRegion = this.boundary.length;
 
-        System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0,
-                BOUNDARY_PREFIX.length);
-        System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length,
-                boundary.length);
+        System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0, BOUNDARY_PREFIX.length);
+        System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length, boundary.length);
         computeBoundaryTable();
 
         head = 0;
@@ -705,20 +660,16 @@ public class MultipartStream {
     }
 
     /**
-     * <p> Constructs a {@code MultipartStream} with a default size buffer.
-     *
-     * @param input    The {@code InputStream} to serve as a data source.
-     * @param boundary The token used for dividing the stream into
-     *                 {@code encapsulations}.
-     * @param pNotifier An object for calling the progress listener, if any.
-     *
+     * <p>
+     * Constructs a {@code MultipartStream} with a default size buffer.
      *
+     * @param input     The {@code InputStream} to serve as a data source.
+     * @param boundary  The token used for dividing the stream into {@code encapsulations}.
+     * @param progressNotifier An object for calling the progress listener, if any.
      * @see #MultipartStream(InputStream, byte[], int, ProgressNotifier)
      */
-    public MultipartStream(final InputStream input,
-            final byte[] boundary,
-            final ProgressNotifier pNotifier) {
-        this(input, boundary, DEFAULT_BUFSIZE, pNotifier);
+    public MultipartStream(final InputStream input, final byte[] boundary, final ProgressNotifier progressNotifier) {
+        this(input, boundary, DEFAULT_BUFSIZE, progressNotifier);
     }
 
     /**
@@ -746,11 +697,11 @@ public class MultipartStream {
     }
 
     /**
-     * <p> Reads {@code body-data} from the current
-     * {@code encapsulation} and discards it.
+     * <p>
+     * Reads {@code body-data} from the current {@code encapsulation} and discards it.
      *
-     * <p>Use this method to skip encapsulations you don't need or don't
-     * understand.
+     * <p>
+     * Use this method to skip encapsulations you don't need or don't understand.
      *
      * @return The amount of data discarded.
      *
@@ -762,17 +713,14 @@ public class MultipartStream {
     }
 
     /**
-     * Searches for a byte of specified value in the {@code buffer},
-     * starting at the specified {@code position}.
+     * Searches for a byte of specified value in the {@code buffer}, starting at the specified {@code position}.
      *
      * @param value The value to find.
      * @param pos   The starting position for searching.
      *
-     * @return The position of byte found, counting from beginning of the
-     *         {@code buffer}, or {@code -1} if not found.
+     * @return The position of byte found, counting from beginning of the {@code buffer}, or {@code -1} if not found.
      */
-    protected int findByte(final byte value,
-            final int pos) {
+    protected int findByte(final byte value, final int pos) {
         for (int i = pos; i < tail; i++) {
             if (buffer[i] == value) {
                 return i;
@@ -783,12 +731,9 @@ public class MultipartStream {
     }
 
     /**
-     * Searches for the {@code boundary} in the {@code buffer}
-     * region delimited by {@code head} and {@code tail}.
+     * Searches for the {@code boundary} in the {@code buffer} region delimited by {@code head} and {@code tail}.
      *
-     * @return The position of the boundary found, counting from the
-     *         beginning of the {@code buffer}, or {@code -1} if
-     *         not found.
+     * @return The position of the boundary found, counting from the beginning of the {@code buffer}, or {@code -1} if not found.
      */
     protected int findSeparator() {
 
@@ -809,9 +754,8 @@ public class MultipartStream {
     }
 
     /**
-     * Retrieves the character encoding used when reading the headers of an
-     * individual part. When not specified, or {@code null}, the platform
-     * default encoding is used.
+     * Retrieves the character encoding used when reading the headers of an individual part. When not specified, or {@code null}, the platform default encoding
+     * is used.
      *
      * @return The encoding used to read part headers.
      */
@@ -821,6 +765,7 @@ public class MultipartStream {
 
     /**
      * Creates a new {@link ItemInputStream}.
+     *
      * @return A new instance of {@link ItemInputStream}.
      */
     public ItemInputStream newInputStream() {
@@ -828,42 +773,33 @@ public class MultipartStream {
     }
 
     /**
-     * <p>Reads {@code body-data} from the current
-     * {@code encapsulation} and writes its contents into the
-     * output {@code Stream}.
+     * <p>
+     * Reads {@code body-data} from the current {@code encapsulation} and writes its contents into the output {@code Stream}.
      *
-     * <p>Arbitrary large amounts of data can be processed by this
-     * method using a constant size buffer. (see {@link
-     * #MultipartStream(InputStream,byte[],int,
-     *   MultipartStream.ProgressNotifier) constructor}).
+     * <p>
+     * Arbitrary large amounts of data can be processed by this method using a constant size buffer. (see
+     * {@link #MultipartStream(InputStream,byte[],int, MultipartStream.ProgressNotifier) constructor}).
      *
-     * @param output The {@code Stream} to write data into. May
-     *               be null, in which case this method is equivalent
-     *               to {@link #discardBodyData()}.
+     * @param output The {@code Stream} to write data into. May be null, in which case this method is equivalent to {@link #discardBodyData()}.
      *
      * @return the amount of data written.
      *
      * @throws MalformedStreamException if the stream ends unexpectedly.
      * @throws IOException              if an i/o error occurs.
      */
-    public int readBodyData(final OutputStream output)
-            throws MalformedStreamException, IOException {
+    public int readBodyData(final OutputStream output) throws MalformedStreamException, IOException {
         return (int) Streams.copy(newInputStream(), output, false); // N.B. Streams.copy closes the input stream
     }
 
     /**
-     * Skips a {@code boundary} token, and checks whether more
-     * {@code encapsulations} are contained in the stream.
+     * Skips a {@code boundary} token, and checks whether more {@code encapsulations} are contained in the stream.
      *
-     * @return {@code true} if there are more encapsulations in
-     *         this stream; {@code false} otherwise.
+     * @return {@code true} if there are more encapsulations in this stream; {@code false} otherwise.
      *
-     * @throws FileUploadIOException if the bytes read from the stream exceeded the size limits
-     * @throws MalformedStreamException if the stream ends unexpectedly or
-     *                                  fails to follow required syntax.
+     * @throws FileUploadSizeException  if the bytes read from the stream exceeded the size limits
+     * @throws MalformedStreamException if the stream ends unexpectedly or fails to follow required syntax.
      */
-    public boolean readBoundary()
-            throws FileUploadIOException, MalformedStreamException {
+    public boolean readBoundary() throws FileUploadException, MalformedStreamException {
         final byte[] marker = new byte[2];
         final boolean nextChunk;
 
@@ -886,21 +822,19 @@ public class MultipartStream {
             } else if (arrayequals(marker, FIELD_SEPARATOR, 2)) {
                 nextChunk = true;
             } else {
-                throw new MalformedStreamException(
-                "Unexpected characters follow a boundary");
+                throw new MalformedStreamException("Unexpected characters follow a boundary");
             }
-        } catch (final FileUploadIOException e) {
-            // wraps a SizeException, re-throw as it will be unwrapped later
+        } catch (final FileUploadSizeException e) {
+            // wraps a FileUploadSizeException, re-throw as it will be unwrapped later?
             throw e;
         } catch (final IOException e) {
-            throw new MalformedStreamException("Stream ended unexpectedly");
+            throw new MalformedStreamException("Stream ended unexpectedly", e);
         }
         return nextChunk;
     }
 
     /**
-     * Reads a byte from the {@code buffer}, and refills it as
-     * necessary.
+     * Reads a byte from the {@code buffer}, and refills it as necessary.
      *
      * @return The next byte from the input stream.
      *
@@ -924,22 +858,21 @@ public class MultipartStream {
     }
 
     /**
-     * <p>Reads the {@code header-part} of the current
-     * {@code encapsulation}.
+     * <p>
+     * Reads the {@code header-part} of the current {@code encapsulation}.
      *
-     * <p>Headers are returned verbatim to the input stream, including the
-     * trailing {@code CRLF} marker. Parsing is left to the
-     * application.
+     * <p>
+     * Headers are returned verbatim to the input stream, including the trailing {@code CRLF} marker. Parsing is left to the application.
      *
-     * <p><strong>TODO</strong> allow limiting maximum header size to
-     * protect against abuse.
+     * <p>
+     * <strong>TODO</strong> allow limiting maximum header size to protect against abuse.
      *
      * @return The {@code header-part} of the current encapsulation.
      *
-     * @throws FileUploadIOException if the bytes read from the stream exceeded the size limits.
+     * @throws FileUploadSizeException  if the bytes read from the stream exceeded the size limits.
      * @throws MalformedStreamException if the stream ends unexpectedly.
      */
-    public String readHeaders() throws FileUploadIOException, MalformedStreamException {
+    public String readHeaders() throws FileUploadSizeException, MalformedStreamException {
         int i = 0;
         byte b;
         // to support multi-byte characters
@@ -948,16 +881,14 @@ public class MultipartStream {
         while (i < HEADER_SEPARATOR.length) {
             try {
                 b = readByte();
-            } catch (final FileUploadIOException e) {
-                // wraps a SizeException, re-throw as it will be unwrapped later
+            } catch (final FileUploadSizeException e) {
+                // wraps a FileUploadSizeException, re-throw as it will be unwrapped later
                 throw e;
             } catch (final IOException e) {
-                throw new MalformedStreamException("Stream ended unexpectedly");
+                throw new MalformedStreamException("Stream ended unexpectedly", e);
             }
             if (++size > HEADER_PART_SIZE_MAX) {
-                throw new MalformedStreamException(
-                        format("Header section has more than %s bytes (maybe it is not properly terminated)",
-                                HEADER_PART_SIZE_MAX));
+                throw new MalformedStreamException(format("Header section has more than %s bytes (maybe it is not properly terminated)", HEADER_PART_SIZE_MAX));
             }
             if (b == HEADER_SEPARATOR[i]) {
                 i++;
@@ -984,39 +915,33 @@ public class MultipartStream {
     }
 
     /**
-     * <p>Changes the boundary token used for partitioning the stream.
+     * <p>
+     * Changes the boundary token used for partitioning the stream.
      *
-     * <p>This method allows single pass processing of nested multipart
-     * streams.
+     * <p>
+     * This method allows single pass processing of nested multipart streams.
      *
-     * <p>The boundary token of the nested stream is {@code required}
-     * to be of the same length as the boundary token in parent stream.
+     * <p>
+     * The boundary token of the nested stream is {@code required} to be of the same length as the boundary token in parent stream.
      *
-     * <p>Restoring the parent stream boundary token after processing of a
-     * nested stream is left to the application.
+     * <p>
+     * Restoring the parent stream boundary token after processing of a nested stream is left to the application.
      *
-     * @param boundary The boundary to be used for parsing of the nested
-     *                 stream.
+     * @param boundary The boundary to be used for parsing of the nested stream.
      *
-     * @throws IllegalBoundaryException if the {@code boundary}
-     *                                  has a different length than the one
-     *                                  being currently parsed.
+     * @throws FileUploadBoundaryException if the {@code boundary} has a different length than the one being currently parsed.
      */
-    public void setBoundary(final byte[] boundary)
-            throws IllegalBoundaryException {
+    public void setBoundary(final byte[] boundary) throws FileUploadBoundaryException {
         if (boundary.length != boundaryLength - BOUNDARY_PREFIX.length) {
-            throw new IllegalBoundaryException(
-            "The length of a boundary token cannot be changed");
+            throw new FileUploadBoundaryException("The length of a boundary token cannot be changed");
         }
-        System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length,
-                boundary.length);
+        System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length, boundary.length);
         computeBoundaryTable();
     }
 
     /**
-     * Specifies the character encoding to be used when reading the headers of
-     * individual parts. When not specified, or {@code null}, the platform
-     * default encoding is used.
+     * Specifies the character encoding to be used when reading the headers of individual parts. When not specified, or {@code null}, the platform default
+     * encoding is used.
      *
      * @param encoding The encoding used to read part headers.
      */
@@ -1027,8 +952,7 @@ public class MultipartStream {
     /**
      * Finds the beginning of the first {@code encapsulation}.
      *
-     * @return {@code true} if an {@code encapsulation} was found in
-     *         the stream.
+     * @return {@code true} if an {@code encapsulation} was found in the stream.
      *
      * @throws IOException if an i/o error occurs.
      */
diff --git a/src/main/java/org/apache/commons/fileupload2/ProgressListener.java b/src/main/java/org/apache/commons/fileupload2/ProgressListener.java
index 0288b8e..5acc770 100644
--- a/src/main/java/org/apache/commons/fileupload2/ProgressListener.java
+++ b/src/main/java/org/apache/commons/fileupload2/ProgressListener.java
@@ -17,21 +17,17 @@
 package org.apache.commons.fileupload2;
 
 /**
- * The {@link ProgressListener} may be used to display a progress bar
- * or do stuff like that.
+ * The {@link ProgressListener} may be used to display a progress bar.
  */
 public interface ProgressListener {
 
     /**
      * Updates the listeners status information.
      *
-     * @param pBytesRead The total number of bytes, which have been read
-     *   so far.
-     * @param pContentLength The total number of bytes, which are being
-     *   read. May be -1, if this number is unknown.
-     * @param pItems The number of the field, which is currently being
-     *   read. (0 = no item so far, 1 = first item is being read, ...)
+     * @param bytesRead     The total number of bytes, which have been read so far.
+     * @param contentLength The total number of bytes, which are being read. May be -1, if this number is unknown.
+     * @param items         The number of the field, which is currently being read. (0 = no item so far, 1 = first item is being read, ...)
      */
-    void update(long pBytesRead, long pContentLength, int pItems);
+    void update(long bytesRead, long contentLength, int items);
 
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java b/src/main/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java
index 23635cd..9bb2e57 100644
--- a/src/main/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java
+++ b/src/main/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java
@@ -36,24 +36,24 @@ import org.apache.commons.fileupload2.MultipartStream;
 import org.apache.commons.fileupload2.ProgressListener;
 import org.apache.commons.fileupload2.RequestContext;
 import org.apache.commons.fileupload2.UploadContext;
-import org.apache.commons.fileupload2.pub.FileUploadIOException;
-import org.apache.commons.fileupload2.pub.InvalidContentTypeException;
-import org.apache.commons.fileupload2.pub.SizeLimitExceededException;
+import org.apache.commons.fileupload2.pub.FileUploadSizeException;
+import org.apache.commons.fileupload2.pub.FileUploadContentTypeException;
 import org.apache.commons.fileupload2.util.LimitedInputStream;
 import org.apache.commons.io.IOUtils;
 
 /**
- * The iterator, which is returned by
- * {@link FileUploadBase#getItemIterator(RequestContext)}.
+ * The iterator, which is returned by {@link FileUploadBase#getItemIterator(RequestContext)}.
  */
 public class FileItemIteratorImpl implements FileItemIterator {
     /**
      * The file uploads processing utility.
+     *
      * @see FileUploadBase
      */
     private final FileUploadBase fileUploadBase;
     /**
      * The request context.
+     *
      * @see RequestContext
      */
     private final RequestContext ctx;
@@ -66,15 +66,13 @@ public class FileItemIteratorImpl implements FileItemIterator {
      */
     private long fileSizeMax;
 
-
     /**
      * The multi part stream to process.
      */
     private MultipartStream multiPartStream;
 
     /**
-     * The notifier, which used for triggering the
-     * {@link ProgressListener}.
+     * The notifier, which used for triggering the {@link ProgressListener}.
      */
     private MultipartStream.ProgressNotifier progressNotifier;
 
@@ -113,17 +111,15 @@ public class FileItemIteratorImpl implements FileItemIterator {
      *
      * @param fileUploadBase Main processor.
      * @param requestContext The request context.
-     * @throws FileUploadException An error occurred while
-     *   parsing the request.
-     * @throws IOException An I/O error occurred.
+     * @throws FileUploadException An error occurred while parsing the request.
+     * @throws IOException         An I/O error occurred.
      */
-    public FileItemIteratorImpl(final FileUploadBase fileUploadBase, final RequestContext requestContext)
-        throws FileUploadException, IOException {
+    public FileItemIteratorImpl(final FileUploadBase fileUploadBase, final RequestContext requestContext) throws FileUploadException, IOException {
         this.fileUploadBase = fileUploadBase;
-        sizeMax = fileUploadBase.getSizeMax();
-        fileSizeMax = fileUploadBase.getFileSizeMax();
-        ctx = Objects.requireNonNull(requestContext, "requestContext");
-        skipPreamble = true;
+        this.sizeMax = fileUploadBase.getSizeMax();
+        this.fileSizeMax = fileUploadBase.getFileSizeMax();
+        this.ctx = Objects.requireNonNull(requestContext, "requestContext");
+        this.skipPreamble = true;
         findNextItem();
     }
 
@@ -166,9 +162,7 @@ public class FileItemIteratorImpl implements FileItemIterator {
                 final String fieldName = fileUploadBase.getFieldName(headers);
                 if (fieldName != null) {
                     final String subContentType = headers.getHeader(FileUploadBase.CONTENT_TYPE);
-                    if (subContentType != null
-                            &&  subContentType.toLowerCase(Locale.ENGLISH)
-                                    .startsWith(FileUploadBase.MULTIPART_MIXED)) {
+                    if (subContentType != null && subContentType.toLowerCase(Locale.ENGLISH).startsWith(FileUploadBase.MULTIPART_MIXED)) {
                         currentFieldName = fieldName;
                         // Multiple files associated with this field name
                         final byte[] subBoundary = fileUploadBase.getBoundary(subContentType);
@@ -177,9 +171,8 @@ public class FileItemIteratorImpl implements FileItemIterator {
                         continue;
                     }
                     final String fileName = fileUploadBase.getFileName(headers);
-                    currentItem = new FileItemStreamImpl(this, fileName,
-                            fieldName, headers.getHeader(FileUploadBase.CONTENT_TYPE),
-                            fileName == null, getContentLength(headers));
+                    currentItem = new FileItemStreamImpl(this, fileName, fieldName, headers.getHeader(FileUploadBase.CONTENT_TYPE), fileName == null,
+                            getContentLength(headers));
                     currentItem.setHeaders(headers);
                     progressNotifier.noteItem();
                     itemValid = true;
@@ -188,10 +181,8 @@ public class FileItemIteratorImpl implements FileItemIterator {
             } else {
                 final String fileName = fileUploadBase.getFileName(headers);
                 if (fileName != null) {
-                    currentItem = new FileItemStreamImpl(this, fileName,
-                            currentFieldName,
-                            headers.getHeader(FileUploadBase.CONTENT_TYPE),
-                            false, getContentLength(headers));
+                    currentItem = new FileItemStreamImpl(this, fileName, currentFieldName, headers.getHeader(FileUploadBase.CONTENT_TYPE), false,
+                            getContentLength(headers));
                     currentItem.setHeaders(headers);
                     progressNotifier.noteItem();
                     itemValid = true;
@@ -215,8 +206,7 @@ public class FileItemIteratorImpl implements FileItemIterator {
         final List<FileItem> items = new ArrayList<>();
         while (hasNext()) {
             final FileItemStream fis = next();
-            final FileItem fi = fileUploadBase.getFileItemFactory().createItem(fis.getFieldName(),
-                    fis.getContentType(), fis.isFormField(), fis.getName());
+            final FileItem fi = fileUploadBase.getFileItemFactory().createItem(fis.getFieldName(), fis.getContentType(), fis.isFormField(), fis.getName());
             items.add(fi);
         }
         return items;
@@ -240,14 +230,11 @@ public class FileItemIteratorImpl implements FileItemIterator {
     }
 
     /**
-     * Returns, whether another instance of {@link FileItemStream}
-     * is available.
+     * 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.
+     * @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.
      */
     @Override
     public boolean hasNext() throws FileUploadException, IOException {
@@ -257,48 +244,36 @@ public class FileItemIteratorImpl implements FileItemIterator {
         if (itemValid) {
             return true;
         }
-        try {
-            return findNextItem();
-        } catch (final FileUploadIOException e) {
-            // unwrap encapsulated SizeException
-            throw (FileUploadException) e.getCause();
-        }
+        return findNextItem();
     }
 
-    protected void init(final FileUploadBase fileUploadBase, final RequestContext pRequestContext)
-            throws FileUploadException, IOException {
+    protected void init(final FileUploadBase fileUploadBase, final RequestContext pRequestContext) throws FileUploadException, IOException {
         final String contentType = ctx.getContentType();
-        if ((null == contentType)
-                || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(FileUploadBase.MULTIPART))) {
-            throw new InvalidContentTypeException(
-                    format("the request doesn't contain a %s or %s stream, content type header is %s",
-                           FileUploadBase.MULTIPART_FORM_DATA, FileUploadBase.MULTIPART_MIXED, contentType));
+        if ((null == contentType) || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(FileUploadBase.MULTIPART))) {
+            throw new FileUploadContentTypeException(format("the request doesn't contain a %s or %s stream, content type header is %s",
+                    FileUploadBase.MULTIPART_FORM_DATA, FileUploadBase.MULTIPART_MIXED, contentType), contentType);
         }
         final long contentLengthInt = ((UploadContext) ctx).contentLength();
+        // @formatter:off
         final long requestSize = UploadContext.class.isAssignableFrom(ctx.getClass())
                                  // Inline conditional is OK here CHECKSTYLE:OFF
                                  ? ((UploadContext) ctx).contentLength()
                                  : contentLengthInt;
                                  // CHECKSTYLE:ON
-
+        // @formatter:on
         final InputStream input; // N.B. this is eventually closed in MultipartStream processing
         if (sizeMax >= 0) {
             if (requestSize != -1 && requestSize > sizeMax) {
-                throw new SizeLimitExceededException(
-                    format("the request was rejected because its size (%s) exceeds the configured maximum (%s)",
-                            requestSize, sizeMax),
-                           requestSize, sizeMax);
+                throw new FileUploadSizeException(
+                        format("the request was rejected because its size (%s) exceeds the configured maximum (%s)", requestSize, sizeMax), sizeMax,
+                        requestSize);
             }
             // N.B. this is eventually closed in MultipartStream processing
             input = new LimitedInputStream(ctx.getInputStream(), sizeMax) {
                 @Override
-                protected void raiseError(final long pSizeMax, final long pCount)
-                        throws IOException {
-                    final FileUploadException ex = new SizeLimitExceededException(
-                    format("the request was rejected because its size (%s) exceeds the configured maximum (%s)",
-                            pCount, pSizeMax),
-                           pCount, pSizeMax);
-                    throw new FileUploadIOException(ex);
+                protected void raiseError(final long pSizeMax, final long pCount) throws IOException {
+                    throw new FileUploadSizeException(
+                            format("The request was rejected because its size (%s) exceeds the configured maximum (%s)", pCount, pSizeMax), pSizeMax, pCount);
                 }
             };
         } else {
@@ -319,10 +294,9 @@ public class FileItemIteratorImpl implements FileItemIterator {
         progressNotifier = new MultipartStream.ProgressNotifier(fileUploadBase.getProgressListener(), requestSize);
         try {
             multiPartStream = new MultipartStream(input, multiPartBoundary, progressNotifier);
-        } catch (final IllegalArgumentException iae) {
+        } catch (final IllegalArgumentException e) {
             IOUtils.closeQuietly(input); // avoid possible resource leak
-            throw new InvalidContentTypeException(
-                    format("The boundary specified in the %s header is too long", FileUploadBase.CONTENT_TYPE), iae);
+            throw new FileUploadContentTypeException(format("The boundary specified in the %s header is too long", FileUploadBase.CONTENT_TYPE), e);
         }
         multiPartStream.setHeaderEncoding(charEncoding);
     }
@@ -330,17 +304,14 @@ public class FileItemIteratorImpl implements FileItemIterator {
     /**
      * 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.
+     * @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.
      */
     @Override
     public FileItemStream next() throws FileUploadException, IOException {
-        if (eof  ||  (!itemValid && !hasNext())) {
+        if (eof || (!itemValid && !hasNext())) {
             throw new NoSuchElementException();
         }
         itemValid = false;
diff --git a/src/main/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java b/src/main/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java
index ca23a5b..0d3d260 100644
--- a/src/main/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java
+++ b/src/main/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java
@@ -26,13 +26,11 @@ import org.apache.commons.fileupload2.FileItemStream;
 import org.apache.commons.fileupload2.FileUploadException;
 import org.apache.commons.fileupload2.InvalidFileNameException;
 import org.apache.commons.fileupload2.MultipartStream.ItemInputStream;
-import org.apache.commons.fileupload2.pub.FileSizeLimitExceededException;
-import org.apache.commons.fileupload2.pub.FileUploadIOException;
+import org.apache.commons.fileupload2.pub.FileUploadByteCountLimitException;
 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}.
  */
@@ -57,7 +55,7 @@ public class FileItemStreamImpl implements FileItemStream {
     /**
      * The file items file name.
      */
-    private final String name;
+    private final String fileName;
 
     /**
      * Whether the file item is a form field.
@@ -67,7 +65,7 @@ public class FileItemStreamImpl implements FileItemStream {
     /**
      * The file items input stream.
      */
-    private final InputStream stream;
+    private final InputStream inputStream;
 
     /**
      * The headers, if any.
@@ -77,57 +75,42 @@ public class FileItemStreamImpl implements FileItemStream {
     /**
      * Creates a new instance.
      *
-     * @param pFileItemIterator The {@link FileItemIteratorImpl iterator}, which returned this file
-     * item.
-     * @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.
+     * @param fileItemIterator The {@link FileItemIteratorImpl iterator}, which returned this file item.
+     * @param pFileName             The items file name, or null.
+     * @param pFieldName        The items field name.
+     * @param contentType      The items content type, or null.
+     * @param formField        Whether the item is a form field.
+     * @param contentLength    The items content length, if known, or -1
+     * @throws IOException         Creating the file item failed.
      * @throws FileUploadException Parsing the incoming data stream failed.
      */
-    public FileItemStreamImpl(final FileItemIteratorImpl pFileItemIterator, final String pName, final String pFieldName,
-            final String pContentType, final boolean pFormField,
-            final long pContentLength) throws FileUploadException, IOException {
-        fileItemIteratorImpl = pFileItemIterator;
-        name = pName;
-        fieldName = pFieldName;
-        contentType = pContentType;
-        formField = pFormField;
+    public FileItemStreamImpl(final FileItemIteratorImpl fileItemIterator, final String pFileName, final String pFieldName, final String contentType,
+            final boolean formField, final long contentLength) throws FileUploadException, IOException {
+        this.fileItemIteratorImpl = fileItemIterator;
+        this.fileName = pFileName;
+        this.fieldName = pFieldName;
+        this.contentType = contentType;
+        this.formField = formField;
         final long fileSizeMax = fileItemIteratorImpl.getFileSizeMax();
-        if (fileSizeMax != -1 && pContentLength != -1
-                && pContentLength > fileSizeMax) {
-            final FileSizeLimitExceededException e =
-                    new FileSizeLimitExceededException(
-                            format("The field %s exceeds its maximum permitted size of %s bytes.",
-                                    fieldName, fileSizeMax),
-                            pContentLength, fileSizeMax);
-            e.setFileName(pName);
-            e.setFieldName(pFieldName);
-            throw new FileUploadIOException(e);
+        if (fileSizeMax != -1 && contentLength != -1 && contentLength > fileSizeMax) {
+            throw new FileUploadByteCountLimitException(
+                    format("The field %s exceeds its maximum permitted size of %s bytes.", fieldName, fileSizeMax), contentLength, fileSizeMax, pFileName,
+                    pFieldName);
         }
         // OK to construct stream now
-        final ItemInputStream itemStream = fileItemIteratorImpl.getMultiPartStream().newInputStream();
-        InputStream istream = itemStream;
+        final ItemInputStream itemInputStream = fileItemIteratorImpl.getMultiPartStream().newInputStream();
+        InputStream istream = itemInputStream;
         if (fileSizeMax != -1) {
             istream = new LimitedInputStream(istream, fileSizeMax) {
                 @Override
-                protected void raiseError(final long pSizeMax, final long pCount)
-                        throws IOException {
-                    itemStream.close(true);
-                    final FileSizeLimitExceededException e =
-                        new FileSizeLimitExceededException(
-                            format("The field %s exceeds its maximum permitted size of %s bytes.",
-                                   fieldName, pSizeMax),
-                            pCount, pSizeMax);
-                    e.setFieldName(fieldName);
-                    e.setFileName(name);
-                    throw new FileUploadIOException(e);
+                protected void raiseError(final long sizeMax, final long count) throws IOException {
+                    itemInputStream.close(true);
+                    throw new FileUploadByteCountLimitException(
+                            format("The field %s exceeds its maximum permitted size of %s bytes.", fieldName, sizeMax), count, sizeMax, fileName, fieldName);
                 }
             };
         }
-        stream = istream;
+        this.inputStream = istream;
     }
 
     /**
@@ -136,7 +119,7 @@ public class FileItemStreamImpl implements FileItemStream {
      * @throws IOException An I/O error occurred.
      */
     public void close() throws IOException {
-        stream.close();
+        inputStream.close();
     }
 
     /**
@@ -173,21 +156,18 @@ public class FileItemStreamImpl implements FileItemStream {
      * 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().
+     * @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);
+        return Streams.checkFileName(fileName);
     }
 
     /**
      * Returns, whether this is a form field.
      *
-     * @return True, if the item is a form field,
-     *   otherwise false.
+     * @return True, if the item is a form field, otherwise false.
      */
     @Override
     public boolean isFormField() {
@@ -195,18 +175,17 @@ public class FileItemStreamImpl implements FileItemStream {
     }
 
     /**
-     * Returns an input stream, which may be used to
-     * read the items contents.
+     * 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 (((Closeable) stream).isClosed()) {
+        if (((Closeable) inputStream).isClosed()) {
             throw new FileItemStream.ItemSkippedException();
         }
-        return stream;
+        return inputStream;
     }
 
     /**
diff --git a/src/main/java/org/apache/commons/fileupload2/pub/FileCountLimitExceededException.java b/src/main/java/org/apache/commons/fileupload2/pub/FileCountLimitExceededException.java
deleted file mode 100644
index ac22341..0000000
--- a/src/main/java/org/apache/commons/fileupload2/pub/FileCountLimitExceededException.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.pub;
-
-import org.apache.commons.fileupload2.FileUploadException;
-
-/**
- * This exception is thrown if a request contains more files than the specified
- * limit.
- */
-public class FileCountLimitExceededException extends FileUploadException {
-
-    private static final long serialVersionUID = 2408766352570556046L;
-
-    /**
-     * The limit that was exceeded.
-     */
-    private final long limit;
-
-    /**
-     * Creates a new instance.
-     *
-     * @param message The detail message
-     * @param limit The limit that was exceeded
-     */
-    public FileCountLimitExceededException(final String message, final long limit) {
-        super(message);
-        this.limit = limit;
-    }
-
-    /**
-     * Retrieves the limit that was exceeded.
-     *
-     * @return The limit that was exceeded by the request
-     */
-    public long getLimit() {
-        return limit;
-    }
-}
diff --git a/src/main/java/org/apache/commons/fileupload2/pub/FileSizeLimitExceededException.java b/src/main/java/org/apache/commons/fileupload2/pub/FileUploadByteCountLimitException.java
similarity index 51%
rename from src/main/java/org/apache/commons/fileupload2/pub/FileSizeLimitExceededException.java
rename to src/main/java/org/apache/commons/fileupload2/pub/FileUploadByteCountLimitException.java
index d459532..2060233 100644
--- a/src/main/java/org/apache/commons/fileupload2/pub/FileSizeLimitExceededException.java
+++ b/src/main/java/org/apache/commons/fileupload2/pub/FileUploadByteCountLimitException.java
@@ -17,42 +17,42 @@
 package org.apache.commons.fileupload2.pub;
 
 /**
- * Thrown to indicate that A files size exceeds the configured maximum.
+ * Signals that a file size exceeds the configured maximum.
  */
-public class FileSizeLimitExceededException
-        extends SizeException {
+public class FileUploadByteCountLimitException extends FileUploadSizeException {
 
     /**
      * The exceptions UID, for serializing an instance.
      */
-    private static final long serialVersionUID = 8150776562029630058L;
+    private static final long serialVersionUID = 2;
 
     /**
      * File name of the item, which caused the exception.
      */
-    private String fileName;
+    private final String fileName;
 
     /**
      * Field name of the item, which caused the exception.
      */
-    private String fieldName;
+    private final String fieldName;
 
     /**
-     * Constructs a {@code SizeExceededException} with
-     * the specified detail message, and actual and permitted sizes.
+     * Constructs an instance with the specified detail message, and actual and permitted sizes.
      *
-     * @param message   The detail message.
+     * @param message   The detail message (which is saved for later retrieval by the {@link #getMessage()} method)
      * @param actual    The actual request size.
      * @param permitted The maximum permitted request size.
+     * @param fileName  File name of the item, which caused the exception.
+     * @param fieldName Field name of the item, which caused the exception.
      */
-    public FileSizeLimitExceededException(final String message, final long actual,
-            final long permitted) {
-        super(message, actual, permitted);
+    public FileUploadByteCountLimitException(final String message, final long actual, final long permitted, final String fileName, final String fieldName) {
+        super(message, permitted, actual);
+        this.fileName = fieldName;
+        this.fieldName = fieldName;
     }
 
     /**
-     * Returns the field name of the item, which caused the
-     * exception.
+     * Gets the field name of the item, which caused the exception.
      *
      * @return Field name, if known, or null.
      */
@@ -61,8 +61,7 @@ public class FileSizeLimitExceededException
     }
 
     /**
-     * Returns the file name of the item, which caused the
-     * exception.
+     * Gets the file name of the item, which caused the exception.
      *
      * @return File name, if known, or null.
      */
@@ -70,25 +69,4 @@ public class FileSizeLimitExceededException
         return fileName;
     }
 
-    /**
-     * Sets the field name of the item, which caused the
-     * exception.
-     *
-     * @param pFieldName the field name of the item,
-     *        which caused the exception.
-     */
-    public void setFieldName(final String pFieldName) {
-        fieldName = pFieldName;
-    }
-
-    /**
-     * Sets the file name of the item, which caused the
-     * exception.
-     *
-     * @param pFileName the file name of the item, which caused the exception.
-     */
-    public void setFileName(final String pFileName) {
-        fileName = pFileName;
-    }
-
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/pub/InvalidContentTypeException.java b/src/main/java/org/apache/commons/fileupload2/pub/FileUploadContentTypeException.java
similarity index 51%
rename from src/main/java/org/apache/commons/fileupload2/pub/InvalidContentTypeException.java
rename to src/main/java/org/apache/commons/fileupload2/pub/FileUploadContentTypeException.java
index 5fbb9c7..5c4b221 100644
--- a/src/main/java/org/apache/commons/fileupload2/pub/InvalidContentTypeException.java
+++ b/src/main/java/org/apache/commons/fileupload2/pub/FileUploadContentTypeException.java
@@ -19,43 +19,44 @@ package org.apache.commons.fileupload2.pub;
 import org.apache.commons.fileupload2.FileUploadException;
 
 /**
- * Thrown to indicate that the request is not a multipart request.
+ * Signals that a request is not a multipart request.
  */
-public class InvalidContentTypeException
-        extends FileUploadException {
+public class FileUploadContentTypeException extends FileUploadException {
 
     /**
      * The exceptions UID, for serializing an instance.
      */
-    private static final long serialVersionUID = -9073026332015646668L;
+    private static final long serialVersionUID = 2;
 
     /**
-     * Constructs a {@code InvalidContentTypeException} with no
-     * detail message.
+     * The guilty content type.
      */
-    public InvalidContentTypeException() {
-    }
+    private String contentType;
 
     /**
-     * Constructs an {@code InvalidContentTypeException} with
-     * the specified detail message.
+     * Constructs an instance with the specified detail message.
      *
-     * @param message The detail message.
+     * @param message The detail message (which is saved for later retrieval by the {@link #getMessage()} method)
+     * @param contentType The guilty content type.
      */
-    public InvalidContentTypeException(final String message) {
+    public FileUploadContentTypeException(final String message, final String contentType) {
         super(message);
+        this.contentType = contentType;
     }
 
     /**
-     * Constructs an {@code InvalidContentTypeException} with
-     * the specified detail message and cause.
+     * Constructs an instance with the specified detail message and cause.
      *
-     * @param msg The detail message.
+     * @param message
+     *        The detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method)
      * @param cause the original cause
-     *
-     * @since 1.3.1
      */
-    public InvalidContentTypeException(final String msg, final Throwable cause) {
-        super(msg, cause);
+    public FileUploadContentTypeException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    public String getContentType() {
+        return contentType;
     }
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/pub/IOFileUploadException.java b/src/main/java/org/apache/commons/fileupload2/pub/FileUploadFileCountLimitException.java
similarity index 58%
rename from src/main/java/org/apache/commons/fileupload2/pub/IOFileUploadException.java
rename to src/main/java/org/apache/commons/fileupload2/pub/FileUploadFileCountLimitException.java
index 9bdc450..666a92b 100644
--- a/src/main/java/org/apache/commons/fileupload2/pub/IOFileUploadException.java
+++ b/src/main/java/org/apache/commons/fileupload2/pub/FileUploadFileCountLimitException.java
@@ -1,43 +1,37 @@
-/*
- * 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.pub;
-
-import java.io.IOException;
-
-import org.apache.commons.fileupload2.FileUploadException;
-
-/**
- * Thrown to indicate an IOException.
- */
-public class IOFileUploadException extends FileUploadException {
-
-    /**
-     * The exceptions UID, for serializing an instance.
-     */
-    private static final long serialVersionUID = 1749796615868477269L;
-
-    /**
-     * Creates a new instance with the given cause.
-     *
-     * @param message The detail message.
-     * @param cause The exceptions cause.
-     */
-    public IOFileUploadException(final String message, final IOException cause) {
-        super(message, cause);
-    }
-
-}
+/*
+ * 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.pub;
+
+/**
+ * Signals that a request contains more files than the specified limit.
+ */
+public class FileUploadFileCountLimitException extends FileUploadSizeException {
+
+    private static final long serialVersionUID = 2;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param message The detail message (which is saved for later retrieval by the {@link #getMessage()} method)
+     * @param limit   The limit that was exceeded.
+     * @param actual  The actual value.
+     */
+    public FileUploadFileCountLimitException(final String message, final long limit, final long actual) {
+        super(message, limit, actual);
+    }
+
+}
diff --git a/src/main/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java b/src/main/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java
deleted file mode 100644
index cb3d876..0000000
--- a/src/main/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.pub;
-
-import java.io.IOException;
-
-import org.apache.commons.fileupload2.FileUploadException;
-
-/**
- * This exception is thrown for hiding an inner
- * {@link FileUploadException} in an {@link IOException}.
- */
-public class FileUploadIOException extends IOException {
-
-    /**
-     * The exceptions UID, for serializing an instance.
-     */
-    private static final long serialVersionUID = -7047616958165584154L;
-
-    /**
-     * Creates a {@code FileUploadIOException} with the
-     * given cause.
-     *
-     * @param cause The exceptions cause, if any, or null.
-     */
-    public FileUploadIOException(final FileUploadException cause) {
-        super(cause);
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/fileupload2/pub/SizeException.java b/src/main/java/org/apache/commons/fileupload2/pub/FileUploadSizeException.java
similarity index 65%
rename from src/main/java/org/apache/commons/fileupload2/pub/SizeException.java
rename to src/main/java/org/apache/commons/fileupload2/pub/FileUploadSizeException.java
index f1cc963..b33fa56 100644
--- a/src/main/java/org/apache/commons/fileupload2/pub/SizeException.java
+++ b/src/main/java/org/apache/commons/fileupload2/pub/FileUploadSizeException.java
@@ -19,15 +19,14 @@ package org.apache.commons.fileupload2.pub;
 import org.apache.commons.fileupload2.FileUploadException;
 
 /**
- * This exception is thrown, if a requests permitted size
- * is exceeded.
+ * Signals that a requests permitted size is exceeded.
  */
-abstract class SizeException extends FileUploadException {
+public class FileUploadSizeException extends FileUploadException {
 
     /**
      * Serial version UID, being used, if serialized.
      */
-    private static final long serialVersionUID = -8776225574705254126L;
+    private static final long serialVersionUID = 2;
 
     /**
      * The actual size of the request.
@@ -40,35 +39,33 @@ abstract class SizeException extends FileUploadException {
     private final long permitted;
 
     /**
-     * Creates a new instance.
+     * Constructs an instance.
      *
-     * @param message The detail message.
-     * @param actual The actual number of bytes in the request.
-     * @param permitted The requests size limit, in bytes.
+     * @param message   The detail message (which is saved for later retrieval by the {@link #getMessage()} method)
+     * @param permitted The requests size limit.
+     * @param actual    The actual values for the request.
      */
-    protected SizeException(final String message, final long actual, final long permitted) {
+    public FileUploadSizeException(final String message, final long permitted, final long actual) {
         super(message);
-        this.actual = actual;
         this.permitted = permitted;
+        this.actual = actual;
     }
 
     /**
-     * Retrieves the actual size of the request.
+     * Gets the actual size of the request.
      *
      * @return The actual size of the request.
-     * @since 1.3
      */
     public long getActualSize() {
         return actual;
     }
 
     /**
-     * Retrieves the permitted size of the request.
+     * Gets the limit size of the request.
      *
-     * @return The permitted size of the request.
-     * @since 1.3
+     * @return The limit size of the request.
      */
-    public long getPermittedSize() {
+    public long getPermitted() {
         return permitted;
     }
 
diff --git a/src/main/java/org/apache/commons/fileupload2/pub/SizeLimitExceededException.java b/src/main/java/org/apache/commons/fileupload2/pub/SizeLimitExceededException.java
deleted file mode 100644
index c9c7343..0000000
--- a/src/main/java/org/apache/commons/fileupload2/pub/SizeLimitExceededException.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.pub;
-
-/**
- * Thrown to indicate that the request size exceeds the configured maximum.
- */
-public class SizeLimitExceededException
-        extends SizeException {
-
-    /**
-     * The exceptions UID, for serializing an instance.
-     */
-    private static final long serialVersionUID = -2474893167098052828L;
-
-    /**
-     * Constructs a {@code SizeExceededException} with
-     * the specified detail message, and actual and permitted sizes.
-     *
-     * @param message   The detail message.
-     * @param actual    The actual request size.
-     * @param permitted The maximum permitted request size.
-     */
-    public SizeLimitExceededException(final String message, final long actual,
-            final long permitted) {
-        super(message, actual, permitted);
-    }
-
-}
diff --git a/src/main/java/org/apache/commons/fileupload2/servlet/ServletFileUpload.java b/src/main/java/org/apache/commons/fileupload2/servlet/ServletFileUpload.java
index 24e03dd..c7fdf57 100644
--- a/src/main/java/org/apache/commons/fileupload2/servlet/ServletFileUpload.java
+++ b/src/main/java/org/apache/commons/fileupload2/servlet/ServletFileUpload.java
@@ -50,8 +50,6 @@ public class ServletFileUpload extends FileUpload {
      */
     private static final String POST_METHOD = "POST";
 
-    // ---------------------------------------------------------- Class methods
-
     /**
      * Utility method that determines whether the request contains multipart
      * content.
@@ -69,8 +67,6 @@ public class ServletFileUpload extends FileUpload {
         return FileUploadBase.isMultipartContent(new ServletRequestContext(request));
     }
 
-    // ----------------------------------------------------------- Constructors
-
     /**
      * Constructs an uninitialized instance of this class. A factory must be
      * configured, using {@code setFileItemFactory()}, before attempting
@@ -110,8 +106,7 @@ public class ServletFileUpload extends FileUpload {
      *   error while communicating with the client or a problem while
      *   storing the uploaded content.
      */
-    public FileItemIterator getItemIterator(final HttpServletRequest request)
-    throws FileUploadException, IOException {
+    public FileItemIterator getItemIterator(final HttpServletRequest request) throws FileUploadException, IOException {
         return super.getItemIterator(new ServletRequestContext(request));
     }
 
@@ -128,8 +123,7 @@ public class ServletFileUpload extends FileUpload {
      *
      * @since 1.3
      */
-    public Map<String, List<FileItem>> parseParameterMap(final HttpServletRequest request)
-            throws FileUploadException {
+    public Map<String, List<FileItem>> parseParameterMap(final HttpServletRequest request) throws FileUploadException {
         return parseParameterMap(new ServletRequestContext(request));
     }
 
@@ -145,8 +139,7 @@ public class ServletFileUpload extends FileUpload {
      * @throws FileUploadException if there are problems reading/parsing
      *                             the request or storing files.
      */
-    public List<FileItem> parseRequest(final HttpServletRequest request)
-    throws FileUploadException {
+    public List<FileItem> parseRequest(final HttpServletRequest request) throws FileUploadException {
         return parseRequest(new ServletRequestContext(request));
     }
 
diff --git a/src/main/java/org/apache/commons/fileupload2/util/LimitedInputStream.java b/src/main/java/org/apache/commons/fileupload2/util/LimitedInputStream.java
index 13ed38e..ab02cd9 100644
--- a/src/main/java/org/apache/commons/fileupload2/util/LimitedInputStream.java
+++ b/src/main/java/org/apache/commons/fileupload2/util/LimitedInputStream.java
@@ -45,12 +45,12 @@ public abstract class LimitedInputStream extends FilterInputStream implements Cl
      * Creates a new instance.
      *
      * @param inputStream The input stream, which shall be limited.
-     * @param pSizeMax The limit; no more than this number of bytes
+     * @param sizeMax The limit; no more than this number of bytes
      *   shall be returned by the source stream.
      */
-    public LimitedInputStream(final InputStream inputStream, final long pSizeMax) {
+    public LimitedInputStream(final InputStream inputStream, final long sizeMax) {
         super(inputStream);
-        sizeMax = pSizeMax;
+        this.sizeMax = sizeMax;
     }
 
     /**
@@ -95,12 +95,12 @@ public abstract class LimitedInputStream extends FilterInputStream implements Cl
      * Called to indicate, that the input streams limit has
      * been exceeded.
      *
-     * @param pSizeMax The input streams limit, in bytes.
-     * @param pCount The actual number of bytes.
+     * @param sizeMax The input streams limit, in bytes.
+     * @param count The actual number of bytes.
      * @throws IOException The called method is expected
      *   to raise an IOException.
      */
-    protected abstract void raiseError(long pSizeMax, long pCount)
+    protected abstract void raiseError(long sizeMax, long count)
             throws IOException;
 
     /**
diff --git a/src/main/java/org/apache/commons/fileupload2/util/Streams.java b/src/main/java/org/apache/commons/fileupload2/util/Streams.java
index e2c925e..0927a72 100644
--- a/src/main/java/org/apache/commons/fileupload2/util/Streams.java
+++ b/src/main/java/org/apache/commons/fileupload2/util/Streams.java
@@ -144,12 +144,10 @@ public final class Streams {
      * @return Number of bytes, which have been copied.
      * @throws IOException An I/O error occurred.
      */
-    public static long copy(final InputStream inputStream,
-            final OutputStream outputStream, final boolean closeOutputStream,
-            final byte[] buffer)
-    throws IOException {
+    public static long copy(final InputStream inputStream, final OutputStream outputStream, final boolean closeOutputStream, final byte[] buffer)
+            throws IOException {
         try (OutputStream out = outputStream;
-              InputStream in = inputStream) {
+                InputStream in = inputStream) {
             long total = 0;
             for (;;) {
                 final int res = in.read(buffer);
diff --git a/src/test/java/org/apache/commons/fileupload2/SizesTest.java b/src/test/java/org/apache/commons/fileupload2/SizesTest.java
index 5db2156..574f35c 100644
--- a/src/test/java/org/apache/commons/fileupload2/SizesTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/SizesTest.java
@@ -31,9 +31,8 @@ import java.util.List;
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.commons.fileupload2.disk.DiskFileItemFactory;
-import org.apache.commons.fileupload2.pub.FileSizeLimitExceededException;
-import org.apache.commons.fileupload2.pub.FileUploadIOException;
-import org.apache.commons.fileupload2.pub.SizeLimitExceededException;
+import org.apache.commons.fileupload2.pub.FileUploadSizeException;
+import org.apache.commons.fileupload2.pub.FileUploadByteCountLimitException;
 import org.apache.commons.fileupload2.servlet.ServletFileUpload;
 import org.apache.commons.fileupload2.util.Streams;
 import org.junit.jupiter.api.Test;
@@ -80,8 +79,8 @@ public class SizesTest {
         try {
             upload.parseRequest(req);
             fail("Expected exception.");
-        } catch (final FileSizeLimitExceededException e) {
-            assertEquals(30, e.getPermittedSize());
+        } catch (final FileUploadByteCountLimitException e) {
+            assertEquals(30, e.getPermitted());
         }
     }
 
@@ -124,8 +123,8 @@ public class SizesTest {
         try {
             upload.parseRequest(req);
             fail("Expected exception.");
-        } catch (final FileSizeLimitExceededException e) {
-            assertEquals(5, e.getPermittedSize());
+        } catch (final FileUploadByteCountLimitException e) {
+            assertEquals(5, e.getPermitted());
         }
 
         // provided Content-Length is wrong, actual content is larger -> handled by LimitedInputStream
@@ -135,8 +134,8 @@ public class SizesTest {
         try {
             upload.parseRequest(req);
             fail("Expected exception.");
-        } catch (final FileSizeLimitExceededException e) {
-            assertEquals(15, e.getPermittedSize());
+        } catch (final FileUploadByteCountLimitException e) {
+            assertEquals(15, e.getPermitted());
         }
     }
 
@@ -214,8 +213,8 @@ public class SizesTest {
         try {
             upload.parseRequest(req);
             fail("Expected exception.");
-        } catch (final SizeLimitExceededException e) {
-            assertEquals(200, e.getPermittedSize());
+        } catch (final FileUploadSizeException e) {
+            assertEquals(200, e.getPermitted());
         }
     }
 
@@ -269,7 +268,7 @@ public class SizesTest {
         try {
             // the header is still within size max -> this shall still succeed
             assertTrue(it.hasNext());
-        } catch (final SizeLimitExceededException e) {
+        } catch (final FileUploadSizeException e) {
             fail();
         }
 
@@ -280,7 +279,7 @@ public class SizesTest {
             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
             Streams.copy(stream, baos, true);
             fail();
-        } catch (final FileUploadIOException e) {
+        } catch (final FileUploadException e) {
             // expected
         }
     }
diff --git a/src/test/java/org/apache/commons/fileupload2/StreamingTest.java b/src/test/java/org/apache/commons/fileupload2/StreamingTest.java
index d621ba1..f76c9b7 100644
--- a/src/test/java/org/apache/commons/fileupload2/StreamingTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/StreamingTest.java
@@ -29,10 +29,10 @@ import java.io.OutputStreamWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.Iterator;
 import java.util.List;
+
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.commons.fileupload2.disk.DiskFileItemFactory;
-import org.apache.commons.fileupload2.pub.IOFileUploadException;
 import org.apache.commons.fileupload2.servlet.ServletFileUpload;
 import org.apache.commons.fileupload2.servlet.ServletRequestContext;
 import org.junit.jupiter.api.Test;
@@ -186,7 +186,7 @@ public class StreamingTest {
         try {
             parseUpload(invalidRequest);
             fail("Expected EndOfStreamException");
-        } catch (final IOFileUploadException e) {
+        } catch (final FileUploadException e) {
             assertTrue(e.getCause() instanceof MultipartStream.MalformedStreamException);
         }
     }


[commons-fileupload] 01/08: Sort members

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

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

commit bd3f130ebab1348099a80f598e8d9df9a18f781a
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Apr 2 09:36:50 2023 -0400

    Sort members
---
 .../org/apache/commons/fileupload2/FileItem.java   |  138 +--
 .../commons/fileupload2/FileItemHeaders.java       |   22 +-
 .../commons/fileupload2/FileItemIterator.java      |   48 +-
 .../apache/commons/fileupload2/FileItemStream.java |   42 +-
 .../apache/commons/fileupload2/FileUploadBase.java |  728 ++++++------
 .../commons/fileupload2/FileUploadException.java   |   16 +-
 .../commons/fileupload2/MultipartStream.java       | 1160 ++++++++++----------
 .../commons/fileupload2/ParameterParser.java       |  258 ++---
 .../apache/commons/fileupload2/RequestContext.java |   14 +-
 .../commons/fileupload2/disk/DiskFileItem.java     |  502 ++++-----
 .../fileupload2/disk/DiskFileItemFactory.java      |  124 +--
 .../fileupload2/impl/FileItemIteratorImpl.java     |  196 ++--
 .../fileupload2/impl/FileItemStreamImpl.java       |   38 +-
 .../fileupload2/jaksrvlt/JakSrvltFileCleaner.java  |   22 +-
 .../fileupload2/jaksrvlt/JakSrvltFileUpload.java   |   26 +-
 .../jaksrvlt/JakSrvltRequestContext.java           |   38 +-
 .../fileupload2/portlet/PortletFileUpload.java     |   28 +-
 .../fileupload2/portlet/PortletRequestContext.java |   38 +-
 .../pub/FileSizeLimitExceededException.java        |   34 +-
 .../fileupload2/servlet/FileCleanerCleanup.java    |   22 +-
 .../fileupload2/servlet/ServletFileUpload.java     |   28 +-
 .../fileupload2/servlet/ServletRequestContext.java |   38 +-
 .../fileupload2/util/FileItemHeadersImpl.java      |   26 +-
 .../fileupload2/util/LimitedInputStream.java       |   76 +-
 .../apache/commons/fileupload2/util/Streams.java   |  138 +--
 .../fileupload2/util/mime/Base64Decoder.java       |   14 +-
 .../commons/fileupload2/util/mime/MimeUtility.java |   14 +-
 .../util/mime/QuotedPrintableDecoder.java          |   14 +-
 .../fileupload2/util/mime/RFC2231Utility.java      |   70 +-
 .../fileupload2/DiskFileItemSerializeTest.java     |  260 ++---
 .../apache/commons/fileupload2/FileUploadTest.java |  312 +++---
 .../fileupload2/HttpServletRequestFactory.java     |   14 +-
 .../fileupload2/MockHttpServletRequest.java        |  388 +++----
 .../commons/fileupload2/MultipartStreamTest.java   |   30 +-
 .../commons/fileupload2/ParameterParserTest.java   |  104 +-
 .../commons/fileupload2/ProgressListenerTest.java  |   64 +-
 .../org/apache/commons/fileupload2/SizesTest.java  |   88 +-
 .../apache/commons/fileupload2/StreamingTest.java  |  248 ++---
 .../java/org/apache/commons/fileupload2/Util.java  |   20 +-
 .../jaksrvlt/JakSrvltFileUploadTest.java           |   46 +-
 .../jaksrvlt/MockJakSrvltHttpRequest.java          |  512 ++++-----
 .../portlet/MockPortletActionRequest.java          |   50 +-
 .../fileupload2/portlet/PortletFileUploadTest.java |   10 +-
 .../fileupload2/servlet/ServletFileUploadTest.java |   46 +-
 .../util/mime/Base64DecoderTestCase.java           |  152 +--
 .../fileupload2/util/mime/MimeUtilityTestCase.java |   28 +-
 .../util/mime/QuotedPrintableDecoderTestCase.java  |   88 +-
 .../util/mime/RFC2231UtilityTestCase.java          |   50 +-
 48 files changed, 3211 insertions(+), 3211 deletions(-)

diff --git a/src/main/java/org/apache/commons/fileupload2/FileItem.java b/src/main/java/org/apache/commons/fileupload2/FileItem.java
index 342550a..49df5c6 100644
--- a/src/main/java/org/apache/commons/fileupload2/FileItem.java
+++ b/src/main/java/org/apache/commons/fileupload2/FileItem.java
@@ -50,15 +50,22 @@ public interface FileItem extends FileItemHeadersSupport {
     // ------------------------------- Methods from javax.activation.DataSource
 
     /**
-     * Returns an {@link java.io.InputStream InputStream} that can be
-     * used to retrieve the contents of the file.
+     * Deletes the underlying storage for a file item, including deleting any
+     * associated temporary disk file. Although this storage will be deleted
+     * automatically when the {@code FileItem} instance is garbage
+     * collected, this method can be used to ensure that this is done at an
+     * earlier time, thus preserving system resources.
+     */
+    void delete();
+
+    /**
+     * Returns the contents of the file item as an array of bytes.
      *
-     * @return An {@link java.io.InputStream InputStream} that can be
-     *         used to retrieve the contents of the file.
+     * @return The contents of the file item as an array of bytes.
      *
-     * @throws IOException if an error occurs.
+     * @throws UncheckedIOException if an I/O error occurs
      */
-    InputStream getInputStream() throws IOException;
+    byte[] get() throws UncheckedIOException;
 
     /**
      * Returns the content type passed by the browser or {@code null} if
@@ -69,6 +76,27 @@ public interface FileItem extends FileItemHeadersSupport {
      */
     String getContentType();
 
+    // ------------------------------------------------------- FileItem methods
+
+    /**
+     * Returns the name of the field in the multipart form corresponding to
+     * this file item.
+     *
+     * @return The name of the form field.
+     */
+    String getFieldName();
+
+    /**
+     * Returns an {@link java.io.InputStream InputStream} that can be
+     * used to retrieve the contents of the file.
+     *
+     * @return An {@link java.io.InputStream InputStream} that can be
+     *         used to retrieve the contents of the file.
+     *
+     * @throws IOException if an error occurs.
+     */
+    InputStream getInputStream() throws IOException;
+
     /**
      * Returns the original file name in the client's file system, as provided by
      * the browser (or other client software). In most cases, this will be the
@@ -83,16 +111,16 @@ public interface FileItem extends FileItemHeadersSupport {
      */
     String getName();
 
-    // ------------------------------------------------------- FileItem methods
-
     /**
-     * Provides a hint as to whether or not the file contents will be read
-     * from memory.
+     * Returns an {@link java.io.OutputStream OutputStream} that can
+     * be used for storing the contents of the file.
      *
-     * @return {@code true} if the file contents will be read from memory;
-     *         {@code false} otherwise.
+     * @return An {@link java.io.OutputStream OutputStream} that can be used
+     *         for storing the contents of the file.
+     *
+     * @throws IOException if an error occurs.
      */
-    boolean isInMemory();
+    OutputStream getOutputStream() throws IOException;
 
     /**
      * Returns the size of the file item.
@@ -102,13 +130,13 @@ public interface FileItem extends FileItemHeadersSupport {
     long getSize();
 
     /**
-     * Returns the contents of the file item as an array of bytes.
-     *
-     * @return The contents of the file item as an array of bytes.
+     * Returns the contents of the file item as a String, using the default
+     * character encoding.  This method uses {@link #get()} to retrieve the
+     * contents of the item.
      *
-     * @throws UncheckedIOException if an I/O error occurs
+     * @return The contents of the item, as a string.
      */
-    byte[] get() throws UncheckedIOException;
+    String getString();
 
     /**
      * Returns the contents of the file item as a String, using the specified
@@ -126,48 +154,22 @@ public interface FileItem extends FileItemHeadersSupport {
     String getString(String encoding) throws UnsupportedEncodingException, IOException;
 
     /**
-     * Returns the contents of the file item as a String, using the default
-     * character encoding.  This method uses {@link #get()} to retrieve the
-     * contents of the item.
-     *
-     * @return The contents of the item, as a string.
-     */
-    String getString();
-
-    /**
-     * A convenience method to write an uploaded item to disk. The client code
-     * is not concerned with whether or not the item is stored in memory, or on
-     * disk in a temporary location. They just want to write the uploaded item
-     * to a file.
-     * <p>
-     * This method is not guaranteed to succeed if called more than once for
-     * the same item. This allows a particular implementation to use, for
-     * example, file renaming, where possible, rather than copying all of the
-     * underlying data, thus gaining a significant performance benefit.
-     *
-     * @param file The {@code File} into which the uploaded item should
-     *             be stored.
+     * Determines whether or not a {@code FileItem} instance represents
+     * a simple form field.
      *
-     * @throws Exception if an error occurs.
-     */
-    void write(File file) throws Exception;
-
-    /**
-     * Deletes the underlying storage for a file item, including deleting any
-     * associated temporary disk file. Although this storage will be deleted
-     * automatically when the {@code FileItem} instance is garbage
-     * collected, this method can be used to ensure that this is done at an
-     * earlier time, thus preserving system resources.
+     * @return {@code true} if the instance represents a simple form
+     *         field; {@code false} if it represents an uploaded file.
      */
-    void delete();
+    boolean isFormField();
 
     /**
-     * Returns the name of the field in the multipart form corresponding to
-     * this file item.
+     * Provides a hint as to whether or not the file contents will be read
+     * from memory.
      *
-     * @return The name of the form field.
+     * @return {@code true} if the file contents will be read from memory;
+     *         {@code false} otherwise.
      */
-    String getFieldName();
+    boolean isInMemory();
 
     /**
      * Sets the field name used to reference this file item.
@@ -176,15 +178,6 @@ public interface FileItem extends FileItemHeadersSupport {
      */
     void setFieldName(String name);
 
-    /**
-     * Determines whether or not a {@code FileItem} instance represents
-     * a simple form field.
-     *
-     * @return {@code true} if the instance represents a simple form
-     *         field; {@code false} if it represents an uploaded file.
-     */
-    boolean isFormField();
-
     /**
      * Specifies whether or not a {@code FileItem} instance represents
      * a simple form field.
@@ -195,14 +188,21 @@ public interface FileItem extends FileItemHeadersSupport {
     void setFormField(boolean state);
 
     /**
-     * Returns an {@link java.io.OutputStream OutputStream} that can
-     * be used for storing the contents of the file.
+     * A convenience method to write an uploaded item to disk. The client code
+     * is not concerned with whether or not the item is stored in memory, or on
+     * disk in a temporary location. They just want to write the uploaded item
+     * to a file.
+     * <p>
+     * This method is not guaranteed to succeed if called more than once for
+     * the same item. This allows a particular implementation to use, for
+     * example, file renaming, where possible, rather than copying all of the
+     * underlying data, thus gaining a significant performance benefit.
      *
-     * @return An {@link java.io.OutputStream OutputStream} that can be used
-     *         for storing the contents of the file.
+     * @param file The {@code File} into which the uploaded item should
+     *             be stored.
      *
-     * @throws IOException if an error occurs.
+     * @throws Exception if an error occurs.
      */
-    OutputStream getOutputStream() throws IOException;
+    void write(File file) throws Exception;
 
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/FileItemHeaders.java b/src/main/java/org/apache/commons/fileupload2/FileItemHeaders.java
index 907ffbf..d41b7fc 100644
--- a/src/main/java/org/apache/commons/fileupload2/FileItemHeaders.java
+++ b/src/main/java/org/apache/commons/fileupload2/FileItemHeaders.java
@@ -42,6 +42,17 @@ public interface FileItemHeaders {
      */
     String getHeader(String name);
 
+    /**
+     * <p>
+     * Returns an {@code Iterator} of all the header names.
+     * </p>
+     *
+     * @return an {@code Iterator} containing all of the names of
+     *         headers provided with this file item. If the item does not have
+     *         any headers return an empty {@code Iterator}
+     */
+    Iterator<String> getHeaderNames();
+
     /**
      * <p>
      * Returns all the values of the specified item header as an
@@ -60,15 +71,4 @@ public interface FileItemHeaders {
      */
     Iterator<String> getHeaders(String name);
 
-    /**
-     * <p>
-     * Returns an {@code Iterator} of all the header names.
-     * </p>
-     *
-     * @return an {@code Iterator} containing all of the names of
-     *         headers provided with this file item. If the item does not have
-     *         any headers return an empty {@code Iterator}
-     */
-    Iterator<String> getHeaderNames();
-
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/FileItemIterator.java b/src/main/java/org/apache/commons/fileupload2/FileItemIterator.java
index bae9532..129442e 100644
--- a/src/main/java/org/apache/commons/fileupload2/FileItemIterator.java
+++ b/src/main/java/org/apache/commons/fileupload2/FileItemIterator.java
@@ -27,6 +27,8 @@ import org.apache.commons.fileupload2.pub.SizeLimitExceededException;
  * {@link FileUploadBase#getItemIterator(RequestContext)}.
  */
 public interface FileItemIterator {
+    List<FileItem> getFileItems() throws FileUploadException, IOException;
+
     /** 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()
@@ -36,17 +38,6 @@ public interface FileItemIterator {
      */
     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".
-     */
-    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()
@@ -56,18 +47,6 @@ public interface FileItemIterator {
      */
     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".
-     */
-    void setSizeMax(long pSizeMax);
-
     /**
      * Returns, whether another instance of {@link FileItemStream}
      * is available.
@@ -93,5 +72,26 @@ public interface FileItemIterator {
      */
     FileItemStream next() throws FileUploadException, IOException;
 
-    List<FileItem> getFileItems() throws FileUploadException, IOException;
+    /** 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".
+     */
+    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.
+     * <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".
+     */
+    void setSizeMax(long pSizeMax);
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/FileItemStream.java b/src/main/java/org/apache/commons/fileupload2/FileItemStream.java
index 4b31185..02b9bd6 100644
--- a/src/main/java/org/apache/commons/fileupload2/FileItemStream.java
+++ b/src/main/java/org/apache/commons/fileupload2/FileItemStream.java
@@ -50,19 +50,6 @@ public interface FileItemStream extends FileItemHeadersSupport {
 
     }
 
-    /**
-     * Creates an {@link InputStream}, which allows to read the
-     * items contents.
-     *
-     * @return The input stream, from which the items data may
-     *   be read.
-     * @throws IllegalStateException The method was already invoked on
-     * this item. It is not possible to recreate the data stream.
-     * @throws IOException An I/O error occurred.
-     * @see ItemSkippedException
-     */
-    InputStream openStream() throws IOException;
-
     /**
      * Returns the content type passed by the browser or {@code null} if
      * not defined.
@@ -72,6 +59,14 @@ public interface FileItemStream extends FileItemHeadersSupport {
      */
     String getContentType();
 
+    /**
+     * Returns the name of the field in the multipart form corresponding to
+     * this file item.
+     *
+     * @return The name of the form field.
+     */
+    String getFieldName();
+
     /**
      * Returns the original file name in the client's file system, as provided by
      * the browser (or other client software). In most cases, this will be the
@@ -82,14 +77,6 @@ public interface FileItemStream extends FileItemHeadersSupport {
      */
     String getName();
 
-    /**
-     * Returns the name of the field in the multipart form corresponding to
-     * this file item.
-     *
-     * @return The name of the form field.
-     */
-    String getFieldName();
-
     /**
      * Determines whether or not a {@code FileItem} instance represents
      * a simple form field.
@@ -99,4 +86,17 @@ public interface FileItemStream extends FileItemHeadersSupport {
      */
     boolean isFormField();
 
+    /**
+     * Creates an {@link InputStream}, which allows to read the
+     * items contents.
+     *
+     * @return The input stream, from which the items data may
+     *   be read.
+     * @throws IllegalStateException The method was already invoked on
+     * this item. It is not possible to recreate the data stream.
+     * @throws IOException An I/O error occurred.
+     * @see ItemSkippedException
+     */
+    InputStream openStream() throws IOException;
+
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java b/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
index 0c49ca1..e62af9b 100644
--- a/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
+++ b/src/main/java/org/apache/commons/fileupload2/FileUploadBase.java
@@ -53,35 +53,13 @@ public abstract class FileUploadBase {
 
     // ---------------------------------------------------------- Class methods
 
-    /**
-     * <p>Utility method that determines whether the request contains multipart
-     * content.</p>
-     *
-     * <p><strong>NOTE:</strong>This method will be moved to the
-     * {@code ServletFileUpload} class after the FileUpload 1.1 release.
-     * Unfortunately, since this method is static, it is not possible to
-     * provide its replacement until this method is removed.</p>
-     *
-     * @param ctx The request context to be evaluated. Must be non-null.
-     *
-     * @return {@code true} if the request is multipart;
-     *         {@code false} otherwise.
-     */
-    public static final boolean isMultipartContent(final RequestContext ctx) {
-        final String contentType = ctx.getContentType();
-        if (contentType == null) {
-            return false;
-        }
-        return contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART);
-    }
-
-    // ----------------------------------------------------- Manifest constants
-
     /**
      * HTTP content type header name.
      */
     public static final String CONTENT_TYPE = "Content-type";
 
+    // ----------------------------------------------------- Manifest constants
+
     /**
      * HTTP content disposition header name.
      */
@@ -127,6 +105,28 @@ public abstract class FileUploadBase {
     @Deprecated
     public static final int MAX_HEADER_SIZE = 1024;
 
+    /**
+     * <p>Utility method that determines whether the request contains multipart
+     * content.</p>
+     *
+     * <p><strong>NOTE:</strong>This method will be moved to the
+     * {@code ServletFileUpload} class after the FileUpload 1.1 release.
+     * Unfortunately, since this method is static, it is not possible to
+     * provide its replacement until this method is removed.</p>
+     *
+     * @param ctx The request context to be evaluated. Must be non-null.
+     *
+     * @return {@code true} if the request is multipart;
+     *         {@code false} otherwise.
+     */
+    public static final boolean isMultipartContent(final RequestContext ctx) {
+        final String contentType = ctx.getContentType();
+        if (contentType == null) {
+            return false;
+        }
+        return contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART);
+    }
+
     // ----------------------------------------------------------- Data members
 
     /**
@@ -160,67 +160,98 @@ public abstract class FileUploadBase {
     // ----------------------------------------------------- Property accessors
 
     /**
-     * Returns the factory class used when creating file items.
+     * Creates a new {@link FileItem} instance.
      *
-     * @return The factory class for new file items.
-     */
-    public abstract FileItemFactory getFileItemFactory();
-
-    /**
-     * Sets the factory class to use when creating file items.
+     * @param headers       A {@code Map} containing the HTTP request
+     *                      headers.
+     * @param isFormField   Whether or not this item is a form field, as
+     *                      opposed to a file.
      *
-     * @param factory The factory class for new file items.
+     * @return A newly created {@code FileItem} instance.
+     *
+     * @throws FileUploadException if an error occurs.
+     * @deprecated 1.2 This method is no longer used in favour of
+     *   internally created instances of {@link FileItem}.
      */
-    public abstract void setFileItemFactory(FileItemFactory factory);
+    @Deprecated
+    protected FileItem createItem(final Map<String, String> headers,
+                                  final boolean isFormField)
+        throws FileUploadException {
+        return getFileItemFactory().createItem(getFieldName(headers),
+                getHeader(headers, CONTENT_TYPE),
+                isFormField,
+                getFileName(headers));
+    }
 
     /**
-     * Returns the maximum allowed size of a complete request, as opposed
-     * to {@link #getFileSizeMax()}.
-     *
-     * @return The maximum allowed size, in bytes. The default value of
-     *   -1 indicates, that there is no limit.
+     * Retrieves the boundary from the {@code Content-type} header.
      *
-     * @see #setSizeMax(long)
+     * @param contentType The value of the content type header from which to
+     *                    extract the boundary value.
      *
+     * @return The boundary, as a byte array.
      */
-    public long getSizeMax() {
-        return sizeMax;
+    public byte[] getBoundary(final String contentType) {
+        final ParameterParser parser = new ParameterParser();
+        parser.setLowerCaseNames(true);
+        // Parameter parser can handle null input
+        final Map<String, String> params = parser.parse(contentType, new char[] {';', ','});
+        final String boundaryStr = params.get("boundary");
+
+        if (boundaryStr == null) {
+            return null;
+        }
+        final byte[] boundary;
+        boundary = boundaryStr.getBytes(StandardCharsets.ISO_8859_1);
+        return boundary;
     }
 
     /**
-     * Sets the maximum allowed size of a complete request, as opposed
-     * to {@link #setFileSizeMax(long)}.
-     *
-     * @param sizeMax The maximum allowed size, in bytes. The default value of
-     *   -1 indicates, that there is no limit.
+     * Retrieves the field name from the {@code Content-disposition}
+     * header.
      *
-     * @see #getSizeMax()
+     * @param headers A {@code Map} containing the HTTP request headers.
      *
+     * @return The field name for the current {@code encapsulation}.
      */
-    public void setSizeMax(final long sizeMax) {
-        this.sizeMax = sizeMax;
+    public String getFieldName(final FileItemHeaders headers) {
+        return getFieldName(headers.getHeader(CONTENT_DISPOSITION));
     }
 
     /**
-     * Returns the maximum allowed size of a single uploaded file,
-     * as opposed to {@link #getSizeMax()}.
+     * Retrieves the field name from the {@code Content-disposition}
+     * header.
      *
-     * @see #setFileSizeMax(long)
-     * @return Maximum size of a single uploaded file.
+     * @param headers A {@code Map} containing the HTTP request headers.
+     *
+     * @return The field name for the current {@code encapsulation}.
+     * @deprecated 1.2.1 Use {@link #getFieldName(FileItemHeaders)}.
      */
-    public long getFileSizeMax() {
-        return fileSizeMax;
+    @Deprecated
+    protected String getFieldName(final Map<String, String> headers) {
+        return getFieldName(getHeader(headers, CONTENT_DISPOSITION));
     }
 
     /**
-     * Sets the maximum allowed size of a single uploaded file,
-     * as opposed to {@link #getSizeMax()}.
-     *
-     * @see #getFileSizeMax()
-     * @param fileSizeMax Maximum size of a single uploaded file.
+     * Returns the field name, which is given by the content-disposition
+     * header.
+     * @param pContentDisposition The content-dispositions header value.
+     * @return The field jake
      */
-    public void setFileSizeMax(final long fileSizeMax) {
-        this.fileSizeMax = fileSizeMax;
+    private String getFieldName(final String pContentDisposition) {
+        String fieldName = null;
+        if (pContentDisposition != null
+                && pContentDisposition.toLowerCase(Locale.ENGLISH).startsWith(FORM_DATA)) {
+            final ParameterParser parser = new ParameterParser();
+            parser.setLowerCaseNames(true);
+            // Parameter parser can handle null input
+            final Map<String, String> params = parser.parse(pContentDisposition, ';');
+            fieldName = params.get("name");
+            if (fieldName != null) {
+                fieldName = fieldName.trim();
+            }
+        }
+        return fieldName;
     }
 
     /**
@@ -233,307 +264,136 @@ public abstract class FileUploadBase {
     }
 
     /**
-     * Sets the maximum number of files allowed per request.
+     * Returns the factory class used when creating file items.
      *
-     * @param fileCountMax The new limit. {@code -1} means no limit.
+     * @return The factory class for new file items.
      */
-    public void setFileCountMax(final long fileCountMax) {
-        this.fileCountMax = fileCountMax;
-    }
+    public abstract FileItemFactory getFileItemFactory();
 
     /**
-     * Retrieves the character encoding used when reading the headers of an
-     * individual part. When not specified, or {@code null}, the request
-     * encoding is used. If that is also not specified, or {@code null},
-     * the platform default encoding is used.
+     * Retrieves the file name from the {@code Content-disposition}
+     * header.
      *
-     * @return The encoding used to read part headers.
+     * @param headers The HTTP headers object.
+     *
+     * @return The file name for the current {@code encapsulation}.
      */
-    public String getHeaderEncoding() {
-        return headerEncoding;
+    public String getFileName(final FileItemHeaders headers) {
+        return getFileName(headers.getHeader(CONTENT_DISPOSITION));
     }
 
     /**
-     * Specifies the character encoding to be used when reading the headers of
-     * individual part. When not specified, or {@code null}, the request
-     * encoding is used. If that is also not specified, or {@code null},
-     * the platform default encoding is used.
+     * Retrieves the file name from the {@code Content-disposition}
+     * header.
      *
-     * @param encoding The encoding used to read part headers.
+     * @param headers A {@code Map} containing the HTTP request headers.
+     *
+     * @return The file name for the current {@code encapsulation}.
+     * @deprecated 1.2.1 Use {@link #getFileName(FileItemHeaders)}.
      */
-    public void setHeaderEncoding(final String encoding) {
-        headerEncoding = encoding;
+    @Deprecated
+    protected String getFileName(final Map<String, String> headers) {
+        return getFileName(getHeader(headers, CONTENT_DISPOSITION));
+    }
+
+    /**
+     * Returns the given content-disposition headers file name.
+     * @param pContentDisposition The content-disposition headers value.
+     * @return The file name
+     */
+    private String getFileName(final String pContentDisposition) {
+        String fileName = null;
+        if (pContentDisposition != null) {
+            final String cdl = pContentDisposition.toLowerCase(Locale.ENGLISH);
+            if (cdl.startsWith(FORM_DATA) || cdl.startsWith(ATTACHMENT)) {
+                final ParameterParser parser = new ParameterParser();
+                parser.setLowerCaseNames(true);
+                // Parameter parser can handle null input
+                final Map<String, String> params = parser.parse(pContentDisposition, ';');
+                if (params.containsKey("filename")) {
+                    fileName = params.get("filename");
+                    if (fileName != null) {
+                        fileName = fileName.trim();
+                    } else {
+                        // Even if there is no value, the parameter is present,
+                        // so we return an empty file name rather than no file
+                        // name.
+                        fileName = "";
+                    }
+                }
+            }
+        }
+        return fileName;
     }
 
     // --------------------------------------------------------- Public methods
 
     /**
-     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
-     * compliant {@code multipart/form-data} stream.
-     *
-     * @param ctx The context for the request to be parsed.
-     *
-     * @return An iterator to instances of {@code FileItemStream}
-     *         parsed from the request, in the order that they were
-     *         transmitted.
+     * Returns the maximum allowed size of a single uploaded file,
+     * as opposed to {@link #getSizeMax()}.
      *
-     * @throws FileUploadException if there are problems reading/parsing
-     *                             the request or storing files.
-     * @throws IOException An I/O error occurred. This may be a network
-     *   error while communicating with the client or a problem while
-     *   storing the uploaded content.
+     * @see #setFileSizeMax(long)
+     * @return Maximum size of a single uploaded file.
      */
-    public FileItemIterator getItemIterator(final RequestContext ctx)
-    throws FileUploadException, IOException {
-        try {
-            return new FileItemIteratorImpl(this, ctx);
-        } catch (final FileUploadIOException e) {
-            // unwrap encapsulated SizeException
-            throw (FileUploadException) e.getCause();
-        }
+    public long getFileSizeMax() {
+        return fileSizeMax;
     }
 
     /**
-     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
-     * compliant {@code multipart/form-data} stream.
-     *
-     * @param ctx The context for the request to be parsed.
-     *
-     * @return A list of {@code FileItem} instances parsed from the
-     *         request, in the order that they were transmitted.
-     *
-     * @throws FileUploadException if there are problems reading/parsing
-     *                             the request or storing files.
-     */
-    public List<FileItem> parseRequest(final RequestContext ctx)
-            throws FileUploadException {
-        final List<FileItem> items = new ArrayList<>();
-        boolean successful = false;
-        try {
-            final FileItemIterator iter = getItemIterator(ctx);
-            final FileItemFactory fileItemFactory = Objects.requireNonNull(getFileItemFactory(),
-                    "No FileItemFactory has been set.");
-            final byte[] buffer = new byte[Streams.DEFAULT_BUFFER_SIZE];
-            while (iter.hasNext()) {
-                if (items.size() == fileCountMax) {
-                    // The next item will exceed the limit.
-                    throw new FileCountLimitExceededException(ATTACHMENT, getFileCountMax());
-                }
-                final FileItemStream item = iter.next();
-                // Don't use getName() here to prevent an InvalidFileNameException.
-                final String fileName = item.getName();
-                final FileItem fileItem = fileItemFactory.createItem(item.getFieldName(), item.getContentType(),
-                                                   item.isFormField(), fileName);
-                items.add(fileItem);
-                try {
-                    Streams.copy(item.openStream(), fileItem.getOutputStream(), true, buffer);
-                } catch (final FileUploadIOException e) {
-                    throw (FileUploadException) e.getCause();
-                } catch (final IOException e) {
-                    throw new IOFileUploadException(format("Processing of %s request failed. %s",
-                                                           MULTIPART_FORM_DATA, e.getMessage()), e);
-                }
-                final FileItemHeaders fih = item.getHeaders();
-                fileItem.setHeaders(fih);
-            }
-            successful = true;
-            return items;
-        } catch (final FileUploadException e) {
-            throw e;
-        } catch (final IOException e) {
-            throw new FileUploadException(e.getMessage(), e);
-        } finally {
-            if (!successful) {
-                for (final FileItem fileItem : items) {
-                    try {
-                        fileItem.delete();
-                    } catch (final Exception ignored) {
-                        // ignored TODO perhaps add to tracker delete failure list somehow?
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
-     * compliant {@code multipart/form-data} stream.
-     *
-     * @param ctx The context for the request to be parsed.
-     *
-     * @return A map of {@code FileItem} instances parsed from the request.
-     *
-     * @throws FileUploadException if there are problems reading/parsing
-     *                             the request or storing files.
-     *
-     * @since 1.3
-     */
-    public Map<String, List<FileItem>> parseParameterMap(final RequestContext ctx)
-            throws FileUploadException {
-        final List<FileItem> items = parseRequest(ctx);
-        final Map<String, List<FileItem>> itemsMap = new HashMap<>(items.size());
-
-        for (final FileItem fileItem : items) {
-            final String fieldName = fileItem.getFieldName();
-            final List<FileItem> mappedItems = itemsMap.computeIfAbsent(fieldName, k -> new ArrayList<>());
-
-            mappedItems.add(fileItem);
-        }
-
-        return itemsMap;
-    }
-
-    // ------------------------------------------------------ Protected methods
-
-    /**
-     * Retrieves the boundary from the {@code Content-type} header.
-     *
-     * @param contentType The value of the content type header from which to
-     *                    extract the boundary value.
-     *
-     * @return The boundary, as a byte array.
-     */
-    public byte[] getBoundary(final String contentType) {
-        final ParameterParser parser = new ParameterParser();
-        parser.setLowerCaseNames(true);
-        // Parameter parser can handle null input
-        final Map<String, String> params = parser.parse(contentType, new char[] {';', ','});
-        final String boundaryStr = params.get("boundary");
-
-        if (boundaryStr == null) {
-            return null;
-        }
-        final byte[] boundary;
-        boundary = boundaryStr.getBytes(StandardCharsets.ISO_8859_1);
-        return boundary;
-    }
-
-    /**
-     * Retrieves the file name from the {@code Content-disposition}
-     * header.
+     * Returns the header with the specified name from the supplied map. The
+     * header lookup is case-insensitive.
      *
      * @param headers A {@code Map} containing the HTTP request headers.
+     * @param name    The name of the header to return.
      *
-     * @return The file name for the current {@code encapsulation}.
-     * @deprecated 1.2.1 Use {@link #getFileName(FileItemHeaders)}.
+     * @return The value of specified header, or a comma-separated list if
+     *         there were multiple headers of that name.
+     * @deprecated 1.2.1 Use {@link FileItemHeaders#getHeader(String)}.
      */
     @Deprecated
-    protected String getFileName(final Map<String, String> headers) {
-        return getFileName(getHeader(headers, CONTENT_DISPOSITION));
-    }
-
-    /**
-     * Retrieves the file name from the {@code Content-disposition}
-     * header.
-     *
-     * @param headers The HTTP headers object.
-     *
-     * @return The file name for the current {@code encapsulation}.
-     */
-    public String getFileName(final FileItemHeaders headers) {
-        return getFileName(headers.getHeader(CONTENT_DISPOSITION));
-    }
-
-    /**
-     * Returns the given content-disposition headers file name.
-     * @param pContentDisposition The content-disposition headers value.
-     * @return The file name
-     */
-    private String getFileName(final String pContentDisposition) {
-        String fileName = null;
-        if (pContentDisposition != null) {
-            final String cdl = pContentDisposition.toLowerCase(Locale.ENGLISH);
-            if (cdl.startsWith(FORM_DATA) || cdl.startsWith(ATTACHMENT)) {
-                final ParameterParser parser = new ParameterParser();
-                parser.setLowerCaseNames(true);
-                // Parameter parser can handle null input
-                final Map<String, String> params = parser.parse(pContentDisposition, ';');
-                if (params.containsKey("filename")) {
-                    fileName = params.get("filename");
-                    if (fileName != null) {
-                        fileName = fileName.trim();
-                    } else {
-                        // Even if there is no value, the parameter is present,
-                        // so we return an empty file name rather than no file
-                        // name.
-                        fileName = "";
-                    }
-                }
-            }
-        }
-        return fileName;
+    protected final String getHeader(final Map<String, String> headers,
+            final String name) {
+        return headers.get(name.toLowerCase(Locale.ENGLISH));
     }
 
     /**
-     * Retrieves the field name from the {@code Content-disposition}
-     * header.
-     *
-     * @param headers A {@code Map} containing the HTTP request headers.
+     * Retrieves the character encoding used when reading the headers of an
+     * individual part. When not specified, or {@code null}, the request
+     * encoding is used. If that is also not specified, or {@code null},
+     * the platform default encoding is used.
      *
-     * @return The field name for the current {@code encapsulation}.
-     */
-    public String getFieldName(final FileItemHeaders headers) {
-        return getFieldName(headers.getHeader(CONTENT_DISPOSITION));
-    }
-
-    /**
-     * Returns the field name, which is given by the content-disposition
-     * header.
-     * @param pContentDisposition The content-dispositions header value.
-     * @return The field jake
+     * @return The encoding used to read part headers.
      */
-    private String getFieldName(final String pContentDisposition) {
-        String fieldName = null;
-        if (pContentDisposition != null
-                && pContentDisposition.toLowerCase(Locale.ENGLISH).startsWith(FORM_DATA)) {
-            final ParameterParser parser = new ParameterParser();
-            parser.setLowerCaseNames(true);
-            // Parameter parser can handle null input
-            final Map<String, String> params = parser.parse(pContentDisposition, ';');
-            fieldName = params.get("name");
-            if (fieldName != null) {
-                fieldName = fieldName.trim();
-            }
-        }
-        return fieldName;
+    public String getHeaderEncoding() {
+        return headerEncoding;
     }
 
-    /**
-     * Retrieves the field name from the {@code Content-disposition}
-     * header.
-     *
-     * @param headers A {@code Map} containing the HTTP request headers.
-     *
-     * @return The field name for the current {@code encapsulation}.
-     * @deprecated 1.2.1 Use {@link #getFieldName(FileItemHeaders)}.
-     */
-    @Deprecated
-    protected String getFieldName(final Map<String, String> headers) {
-        return getFieldName(getHeader(headers, CONTENT_DISPOSITION));
-    }
+    // ------------------------------------------------------ Protected methods
 
     /**
-     * Creates a new {@link FileItem} instance.
+     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
+     * compliant {@code multipart/form-data} stream.
      *
-     * @param headers       A {@code Map} containing the HTTP request
-     *                      headers.
-     * @param isFormField   Whether or not this item is a form field, as
-     *                      opposed to a file.
+     * @param ctx The context for the request to be parsed.
      *
-     * @return A newly created {@code FileItem} instance.
+     * @return An iterator to instances of {@code FileItemStream}
+     *         parsed from the request, in the order that they were
+     *         transmitted.
      *
-     * @throws FileUploadException if an error occurs.
-     * @deprecated 1.2 This method is no longer used in favour of
-     *   internally created instances of {@link FileItem}.
+     * @throws FileUploadException if there are problems reading/parsing
+     *                             the request or storing files.
+     * @throws IOException An I/O error occurred. This may be a network
+     *   error while communicating with the client or a problem while
+     *   storing the uploaded content.
      */
-    @Deprecated
-    protected FileItem createItem(final Map<String, String> headers,
-                                  final boolean isFormField)
-        throws FileUploadException {
-        return getFileItemFactory().createItem(getFieldName(headers),
-                getHeader(headers, CONTENT_TYPE),
-                isFormField,
-                getFileName(headers));
+    public FileItemIterator getItemIterator(final RequestContext ctx)
+    throws FileUploadException, IOException {
+        try {
+            return new FileItemIteratorImpl(this, ctx);
+        } catch (final FileUploadIOException e) {
+            // unwrap encapsulated SizeException
+            throw (FileUploadException) e.getCause();
+        }
     }
 
     /**
@@ -582,40 +442,34 @@ public abstract class FileUploadBase {
     }
 
     /**
-     * Creates a new instance of {@link FileItemHeaders}.
-     * @return The new instance.
+     * Returns the progress listener.
+     *
+     * @return The progress listener, if any, or null.
      */
-    protected FileItemHeadersImpl newFileItemHeaders() {
-        return new FileItemHeadersImpl();
+    public ProgressListener getProgressListener() {
+        return listener;
     }
 
     /**
-     * <p> Parses the {@code header-part} and returns as key/value
-     * pairs.
+     * Returns the maximum allowed size of a complete request, as opposed
+     * to {@link #getFileSizeMax()}.
      *
-     * <p> If there are multiple headers of the same names, the name
-     * will map to a comma-separated list containing the values.
+     * @return The maximum allowed size, in bytes. The default value of
+     *   -1 indicates, that there is no limit.
      *
-     * @param headerPart The {@code header-part} of the current
-     *                   {@code encapsulation}.
+     * @see #setSizeMax(long)
      *
-     * @return A {@code Map} containing the parsed HTTP request headers.
-     * @deprecated 1.2.1 Use {@link #getParsedHeaders(String)}
      */
-    @Deprecated
-    protected Map<String, String> parseHeaders(final String headerPart) {
-        final FileItemHeaders headers = getParsedHeaders(headerPart);
-        final Map<String, String> result = new HashMap<>();
-        for (final Iterator<String> iter = headers.getHeaderNames();  iter.hasNext();) {
-            final String headerName = iter.next();
-            final Iterator<String> iter2 = headers.getHeaders(headerName);
-            final StringBuilder headerValue = new StringBuilder(iter2.next());
-            while (iter2.hasNext()) {
-                headerValue.append(",").append(iter2.next());
-            }
-            result.put(headerName, headerValue.toString());
-        }
-        return result;
+    public long getSizeMax() {
+        return sizeMax;
+    }
+
+    /**
+     * Creates a new instance of {@link FileItemHeaders}.
+     * @return The new instance.
+     */
+    protected FileItemHeadersImpl newFileItemHeaders() {
+        return new FileItemHeadersImpl();
     }
 
     /**
@@ -659,29 +513,161 @@ public abstract class FileUploadBase {
     }
 
     /**
-     * Returns the header with the specified name from the supplied map. The
-     * header lookup is case-insensitive.
+     * <p> Parses the {@code header-part} and returns as key/value
+     * pairs.
      *
-     * @param headers A {@code Map} containing the HTTP request headers.
-     * @param name    The name of the header to return.
+     * <p> If there are multiple headers of the same names, the name
+     * will map to a comma-separated list containing the values.
      *
-     * @return The value of specified header, or a comma-separated list if
-     *         there were multiple headers of that name.
-     * @deprecated 1.2.1 Use {@link FileItemHeaders#getHeader(String)}.
+     * @param headerPart The {@code header-part} of the current
+     *                   {@code encapsulation}.
+     *
+     * @return A {@code Map} containing the parsed HTTP request headers.
+     * @deprecated 1.2.1 Use {@link #getParsedHeaders(String)}
      */
     @Deprecated
-    protected final String getHeader(final Map<String, String> headers,
-            final String name) {
-        return headers.get(name.toLowerCase(Locale.ENGLISH));
+    protected Map<String, String> parseHeaders(final String headerPart) {
+        final FileItemHeaders headers = getParsedHeaders(headerPart);
+        final Map<String, String> result = new HashMap<>();
+        for (final Iterator<String> iter = headers.getHeaderNames();  iter.hasNext();) {
+            final String headerName = iter.next();
+            final Iterator<String> iter2 = headers.getHeaders(headerName);
+            final StringBuilder headerValue = new StringBuilder(iter2.next());
+            while (iter2.hasNext()) {
+                headerValue.append(",").append(iter2.next());
+            }
+            result.put(headerName, headerValue.toString());
+        }
+        return result;
     }
 
     /**
-     * Returns the progress listener.
+     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
+     * compliant {@code multipart/form-data} stream.
      *
-     * @return The progress listener, if any, or null.
+     * @param ctx The context for the request to be parsed.
+     *
+     * @return A map of {@code FileItem} instances parsed from the request.
+     *
+     * @throws FileUploadException if there are problems reading/parsing
+     *                             the request or storing files.
+     *
+     * @since 1.3
      */
-    public ProgressListener getProgressListener() {
-        return listener;
+    public Map<String, List<FileItem>> parseParameterMap(final RequestContext ctx)
+            throws FileUploadException {
+        final List<FileItem> items = parseRequest(ctx);
+        final Map<String, List<FileItem>> itemsMap = new HashMap<>(items.size());
+
+        for (final FileItem fileItem : items) {
+            final String fieldName = fileItem.getFieldName();
+            final List<FileItem> mappedItems = itemsMap.computeIfAbsent(fieldName, k -> new ArrayList<>());
+
+            mappedItems.add(fileItem);
+        }
+
+        return itemsMap;
+    }
+
+    /**
+     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
+     * compliant {@code multipart/form-data} stream.
+     *
+     * @param ctx The context for the request to be parsed.
+     *
+     * @return A list of {@code FileItem} instances parsed from the
+     *         request, in the order that they were transmitted.
+     *
+     * @throws FileUploadException if there are problems reading/parsing
+     *                             the request or storing files.
+     */
+    public List<FileItem> parseRequest(final RequestContext ctx)
+            throws FileUploadException {
+        final List<FileItem> items = new ArrayList<>();
+        boolean successful = false;
+        try {
+            final FileItemIterator iter = getItemIterator(ctx);
+            final FileItemFactory fileItemFactory = Objects.requireNonNull(getFileItemFactory(),
+                    "No FileItemFactory has been set.");
+            final byte[] buffer = new byte[Streams.DEFAULT_BUFFER_SIZE];
+            while (iter.hasNext()) {
+                if (items.size() == fileCountMax) {
+                    // The next item will exceed the limit.
+                    throw new FileCountLimitExceededException(ATTACHMENT, getFileCountMax());
+                }
+                final FileItemStream item = iter.next();
+                // Don't use getName() here to prevent an InvalidFileNameException.
+                final String fileName = item.getName();
+                final FileItem fileItem = fileItemFactory.createItem(item.getFieldName(), item.getContentType(),
+                                                   item.isFormField(), fileName);
+                items.add(fileItem);
+                try {
+                    Streams.copy(item.openStream(), fileItem.getOutputStream(), true, buffer);
+                } catch (final FileUploadIOException e) {
+                    throw (FileUploadException) e.getCause();
+                } catch (final IOException e) {
+                    throw new IOFileUploadException(format("Processing of %s request failed. %s",
+                                                           MULTIPART_FORM_DATA, e.getMessage()), e);
+                }
+                final FileItemHeaders fih = item.getHeaders();
+                fileItem.setHeaders(fih);
+            }
+            successful = true;
+            return items;
+        } catch (final FileUploadException e) {
+            throw e;
+        } catch (final IOException e) {
+            throw new FileUploadException(e.getMessage(), e);
+        } finally {
+            if (!successful) {
+                for (final FileItem fileItem : items) {
+                    try {
+                        fileItem.delete();
+                    } catch (final Exception ignored) {
+                        // ignored TODO perhaps add to tracker delete failure list somehow?
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets the maximum number of files allowed per request.
+     *
+     * @param fileCountMax The new limit. {@code -1} means no limit.
+     */
+    public void setFileCountMax(final long fileCountMax) {
+        this.fileCountMax = fileCountMax;
+    }
+
+    /**
+     * Sets the factory class to use when creating file items.
+     *
+     * @param factory The factory class for new file items.
+     */
+    public abstract void setFileItemFactory(FileItemFactory factory);
+
+    /**
+     * Sets the maximum allowed size of a single uploaded file,
+     * as opposed to {@link #getSizeMax()}.
+     *
+     * @see #getFileSizeMax()
+     * @param fileSizeMax Maximum size of a single uploaded file.
+     */
+    public void setFileSizeMax(final long fileSizeMax) {
+        this.fileSizeMax = fileSizeMax;
+    }
+
+    /**
+     * Specifies the character encoding to be used when reading the headers of
+     * individual part. When not specified, or {@code null}, the request
+     * encoding is used. If that is also not specified, or {@code null},
+     * the platform default encoding is used.
+     *
+     * @param encoding The encoding used to read part headers.
+     */
+    public void setHeaderEncoding(final String encoding) {
+        headerEncoding = encoding;
     }
 
     /**
@@ -693,4 +679,18 @@ public abstract class FileUploadBase {
         listener = pListener;
     }
 
+    /**
+     * Sets the maximum allowed size of a complete request, as opposed
+     * to {@link #setFileSizeMax(long)}.
+     *
+     * @param sizeMax The maximum allowed size, in bytes. The default value of
+     *   -1 indicates, that there is no limit.
+     *
+     * @see #getSizeMax()
+     *
+     */
+    public void setSizeMax(final long sizeMax) {
+        this.sizeMax = sizeMax;
+    }
+
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/FileUploadException.java b/src/main/java/org/apache/commons/fileupload2/FileUploadException.java
index a945c17..1ca5f91 100644
--- a/src/main/java/org/apache/commons/fileupload2/FileUploadException.java
+++ b/src/main/java/org/apache/commons/fileupload2/FileUploadException.java
@@ -66,6 +66,14 @@ public class FileUploadException extends IOException {
         this.cause = cause;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Throwable getCause() {
+        return cause;
+    }
+
     /**
      * Prints this throwable and its backtrace to the specified print stream.
      *
@@ -95,12 +103,4 @@ public class FileUploadException extends IOException {
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Throwable getCause() {
-        return cause;
-    }
-
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/MultipartStream.java b/src/main/java/org/apache/commons/fileupload2/MultipartStream.java
index 0584466..c9e3288 100644
--- a/src/main/java/org/apache/commons/fileupload2/MultipartStream.java
+++ b/src/main/java/org/apache/commons/fileupload2/MultipartStream.java
@@ -84,128 +84,459 @@ import org.apache.commons.fileupload2.util.Streams;
 public class MultipartStream {
 
     /**
-     * Internal class, which is used to invoke the
-     * {@link ProgressListener}.
+     * Thrown upon attempt of setting an invalid boundary token.
      */
-    public static class ProgressNotifier {
+    public static class IllegalBoundaryException extends IOException {
 
         /**
-         * The listener to invoke.
+         * The UID to use when serializing this instance.
          */
-        private final ProgressListener listener;
+        private static final long serialVersionUID = -161533165102632918L;
 
         /**
-         * Number of expected bytes, if known, or -1.
+         * Constructs an {@code IllegalBoundaryException} with no
+         * detail message.
          */
-        private final long contentLength;
+        public IllegalBoundaryException() {
+        }
 
         /**
-         * Number of bytes, which have been read so far.
+         * Constructs an {@code IllegalBoundaryException} with
+         * the specified detail message.
+         *
+         * @param message The detail message.
          */
-        private long bytesRead;
+        public IllegalBoundaryException(final String message) {
+            super(message);
+        }
+
+    }
+
+    // ----------------------------------------------------- Manifest constants
+
+    /**
+     * An {@link InputStream} for reading an items contents.
+     */
+    public class ItemInputStream extends InputStream implements Closeable {
 
         /**
-         * Number of items, which have been read so far.
+         * Offset when converting negative bytes to integers.
          */
-        private int items;
+        private static final int BYTE_POSITIVE_OFFSET = 256;
 
         /**
-         * Creates a new instance with the given listener
-         * and content length.
-         *
-         * @param pListener The listener to invoke.
-         * @param pContentLength The expected content length.
+         * The number of bytes, which have been read so far.
          */
-        public ProgressNotifier(final ProgressListener pListener, final long pContentLength) {
-            listener = pListener;
-            contentLength = pContentLength;
+        private long total;
+
+        /**
+         * The number of bytes, which must be hold, because
+         * they might be a part of the boundary.
+         */
+        private int pad;
+
+        /**
+         * The current offset in the buffer.
+         */
+        private int pos;
+
+        /**
+         * Whether the stream is already closed.
+         */
+        private boolean closed;
+
+        /**
+         * Creates a new instance.
+         */
+        ItemInputStream() {
+            findSeparator();
         }
 
         /**
-         * Called to indicate that bytes have been read.
+         * Returns the number of bytes, which are currently
+         * available, without blocking.
          *
-         * @param pBytes Number of bytes, which have been read.
+         * @throws IOException An I/O error occurs.
+         * @return Number of bytes in the buffer.
          */
-        void noteBytesRead(final int pBytes) {
-            /* Indicates, that the given number of bytes have been read from
-             * the input stream.
-             */
-            bytesRead += pBytes;
-            notifyListener();
+        @Override
+        public int available() throws IOException {
+            if (pos == -1) {
+                return tail - head - pad;
+            }
+            return pos - head;
         }
 
         /**
-         * Called to indicate, that a new file item has been detected.
+         * Closes the input stream.
+         *
+         * @throws IOException An I/O error occurred.
          */
-        public void noteItem() {
-            ++items;
-            notifyListener();
+        @Override
+        public void close() throws IOException {
+            close(false);
         }
 
         /**
-         * Called for notifying the listener.
+         * Closes the input stream.
+         *
+         * @param pCloseUnderlying Whether to close the underlying stream
+         *   (hard close)
+         * @throws IOException An I/O error occurred.
          */
-        private void notifyListener() {
-            if (listener != null) {
-                listener.update(bytesRead, contentLength, items);
+        public void close(final boolean pCloseUnderlying) throws IOException {
+            if (closed) {
+                return;
+            }
+            if (pCloseUnderlying) {
+                closed = true;
+                input.close();
+            } else {
+                for (;;) {
+                    int av = available();
+                    if (av == 0) {
+                        av = makeAvailable();
+                        if (av == 0) {
+                            break;
+                        }
+                    }
+                    skip(av);
+                }
             }
+            closed = true;
         }
 
-    }
+        /**
+         * Called for finding the separator.
+         */
+        private void findSeparator() {
+            pos = MultipartStream.this.findSeparator();
+            if (pos == -1) {
+                if (tail - head > keepRegion) {
+                    pad = keepRegion;
+                } else {
+                    pad = tail - head;
+                }
+            }
+        }
 
-    // ----------------------------------------------------- Manifest constants
+        /**
+         * Returns the number of bytes, which have been read
+         * by the stream.
+         *
+         * @return Number of bytes, which have been read so far.
+         */
+        public long getBytesRead() {
+            return total;
+        }
 
-    /**
-     * The Carriage Return ASCII character value.
-     */
-    public static final byte CR = 0x0D;
+        /**
+         * Returns, whether the stream is closed.
+         *
+         * @return True, if the stream is closed, otherwise false.
+         */
+        @Override
+        public boolean isClosed() {
+            return closed;
+        }
 
-    /**
-     * The Line Feed ASCII character value.
-     */
-    public static final byte LF = 0x0A;
+        /**
+         * Attempts to read more data.
+         *
+         * @return Number of available bytes
+         * @throws IOException An I/O error occurred.
+         */
+        private int makeAvailable() throws IOException {
+            if (pos != -1) {
+                return 0;
+            }
 
-    /**
-     * The dash (-) ASCII character value.
-     */
-    public static final byte DASH = 0x2D;
+            // Move the data to the beginning of the buffer.
+            total += tail - head - pad;
+            System.arraycopy(buffer, tail - pad, buffer, 0, pad);
 
-    /**
-     * The maximum length of {@code header-part} that will be
-     * processed (10 kilobytes = 10240 bytes.).
-     */
-    public static final int HEADER_PART_SIZE_MAX = 10240;
+            // Refill buffer with new data.
+            head = 0;
+            tail = pad;
 
-    /**
-     * The default length of the buffer used for processing a request.
-     */
-    protected static final int DEFAULT_BUFSIZE = 4096;
+            for (;;) {
+                final int bytesRead = input.read(buffer, tail, bufSize - tail);
+                if (bytesRead == -1) {
+                    // The last pad amount is left in the buffer.
+                    // Boundary can't be in there so signal an error
+                    // condition.
+                    final String msg = "Stream ended unexpectedly";
+                    throw new MalformedStreamException(msg);
+                }
+                if (notifier != null) {
+                    notifier.noteBytesRead(bytesRead);
+                }
+                tail += bytesRead;
 
-    /**
-     * A byte sequence that marks the end of {@code header-part}
-     * ({@code CRLFCRLF}).
-     */
-    protected static final byte[] HEADER_SEPARATOR = {CR, LF, CR, LF};
+                findSeparator();
+                final int av = available();
 
-    /**
-     * A byte sequence that that follows a delimiter that will be
-     * followed by an encapsulation ({@code CRLF}).
-     */
-    protected static final byte[] FIELD_SEPARATOR = {CR, LF};
+                if (av > 0 || pos != -1) {
+                    return av;
+                }
+            }
+        }
 
-    /**
-     * A byte sequence that that follows a delimiter of the last
-     * encapsulation in the stream ({@code --}).
-     */
-    protected static final byte[] STREAM_TERMINATOR = {DASH, DASH};
+        /**
+         * Returns the next byte in the stream.
+         *
+         * @return The next byte in the stream, as a non-negative
+         *   integer, or -1 for EOF.
+         * @throws IOException An I/O error occurred.
+         */
+        @Override
+        public int read() throws IOException {
+            if (closed) {
+                throw new FileItemStream.ItemSkippedException();
+            }
+            if (available() == 0 && makeAvailable() == 0) {
+                return -1;
+            }
+            ++total;
+            final int b = buffer[head++];
+            if (b >= 0) {
+                return b;
+            }
+            return b + BYTE_POSITIVE_OFFSET;
+        }
 
-    /**
-     * A byte sequence that precedes a boundary ({@code CRLF--}).
-     */
-    protected static final byte[] BOUNDARY_PREFIX = {CR, LF, DASH, DASH};
+        /**
+         * Reads bytes into the given buffer.
+         *
+         * @param b The destination buffer, where to write to.
+         * @param off Offset of the first byte in the buffer.
+         * @param len Maximum number of bytes to read.
+         * @return Number of bytes, which have been actually read,
+         *   or -1 for EOF.
+         * @throws IOException An I/O error occurred.
+         */
+        @Override
+        public int read(final byte[] b, final int off, final int len) throws IOException {
+            if (closed) {
+                throw new FileItemStream.ItemSkippedException();
+            }
+            if (len == 0) {
+                return 0;
+            }
+            int res = available();
+            if (res == 0) {
+                res = makeAvailable();
+                if (res == 0) {
+                    return -1;
+                }
+            }
+            res = Math.min(res, len);
+            System.arraycopy(buffer, head, b, off, res);
+            head += res;
+            total += res;
+            return res;
+        }
+
+        /**
+         * Skips the given number of bytes.
+         *
+         * @param bytes Number of bytes to skip.
+         * @return The number of bytes, which have actually been
+         *   skipped.
+         * @throws IOException An I/O error occurred.
+         */
+        @Override
+        public long skip(final long bytes) throws IOException {
+            if (closed) {
+                throw new FileItemStream.ItemSkippedException();
+            }
+            int av = available();
+            if (av == 0) {
+                av = makeAvailable();
+                if (av == 0) {
+                    return 0;
+                }
+            }
+            final long res = Math.min(av, bytes);
+            head += res;
+            return res;
+        }
+
+    }
+
+    /**
+     * Thrown to indicate that the input stream fails to follow the
+     * required syntax.
+     */
+    public static class MalformedStreamException extends IOException {
+
+        /**
+         * The UID to use when serializing this instance.
+         */
+        private static final long serialVersionUID = 6466926458059796677L;
+
+        /**
+         * Constructs a {@code MalformedStreamException} with no
+         * detail message.
+         */
+        public MalformedStreamException() {
+        }
+
+        /**
+         * Constructs an {@code MalformedStreamException} with
+         * the specified detail message.
+         *
+         * @param message The detail message.
+         */
+        public MalformedStreamException(final String message) {
+            super(message);
+        }
+
+    }
+
+    /**
+     * Internal class, which is used to invoke the
+     * {@link ProgressListener}.
+     */
+    public static class ProgressNotifier {
+
+        /**
+         * The listener to invoke.
+         */
+        private final ProgressListener listener;
+
+        /**
+         * Number of expected bytes, if known, or -1.
+         */
+        private final long contentLength;
+
+        /**
+         * Number of bytes, which have been read so far.
+         */
+        private long bytesRead;
+
+        /**
+         * Number of items, which have been read so far.
+         */
+        private int items;
+
+        /**
+         * Creates a new instance with the given listener
+         * and content length.
+         *
+         * @param pListener The listener to invoke.
+         * @param pContentLength The expected content length.
+         */
+        public ProgressNotifier(final ProgressListener pListener, final long pContentLength) {
+            listener = pListener;
+            contentLength = pContentLength;
+        }
+
+        /**
+         * Called to indicate that bytes have been read.
+         *
+         * @param pBytes Number of bytes, which have been read.
+         */
+        void noteBytesRead(final int pBytes) {
+            /* Indicates, that the given number of bytes have been read from
+             * the input stream.
+             */
+            bytesRead += pBytes;
+            notifyListener();
+        }
+
+        /**
+         * Called to indicate, that a new file item has been detected.
+         */
+        public void noteItem() {
+            ++items;
+            notifyListener();
+        }
+
+        /**
+         * Called for notifying the listener.
+         */
+        private void notifyListener() {
+            if (listener != null) {
+                listener.update(bytesRead, contentLength, items);
+            }
+        }
+
+    }
+
+    /**
+     * The Carriage Return ASCII character value.
+     */
+    public static final byte CR = 0x0D;
+
+    /**
+     * The Line Feed ASCII character value.
+     */
+    public static final byte LF = 0x0A;
+
+    /**
+     * The dash (-) ASCII character value.
+     */
+    public static final byte DASH = 0x2D;
+
+    /**
+     * The maximum length of {@code header-part} that will be
+     * processed (10 kilobytes = 10240 bytes.).
+     */
+    public static final int HEADER_PART_SIZE_MAX = 10240;
+
+    /**
+     * The default length of the buffer used for processing a request.
+     */
+    protected static final int DEFAULT_BUFSIZE = 4096;
+
+    /**
+     * A byte sequence that marks the end of {@code header-part}
+     * ({@code CRLFCRLF}).
+     */
+    protected static final byte[] HEADER_SEPARATOR = {CR, LF, CR, LF};
 
     // ----------------------------------------------------------- Data members
 
+    /**
+     * A byte sequence that that follows a delimiter that will be
+     * followed by an encapsulation ({@code CRLF}).
+     */
+    protected static final byte[] FIELD_SEPARATOR = {CR, LF};
+
+    /**
+     * A byte sequence that that follows a delimiter of the last
+     * encapsulation in the stream ({@code --}).
+     */
+    protected static final byte[] STREAM_TERMINATOR = {DASH, DASH};
+
+    /**
+     * A byte sequence that precedes a boundary ({@code CRLF--}).
+     */
+    protected static final byte[] BOUNDARY_PREFIX = {CR, LF, DASH, DASH};
+
+    /**
+     * Compares {@code count} first bytes in the arrays
+     * {@code a} and {@code b}.
+     *
+     * @param a     The first array to compare.
+     * @param b     The second array to compare.
+     * @param count How many bytes should be compared.
+     *
+     * @return {@code true} if {@code count} first bytes in arrays
+     *         {@code a} and {@code b} are equal.
+     */
+    public static boolean arrayequals(final byte[] a,
+            final byte[] b,
+            final int count) {
+        for (int i = 0; i < count; i++) {
+            if (a[i] != b[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /**
      * The input stream from which data is read.
      */
@@ -242,6 +573,8 @@ public class MultipartStream {
      */
     private final byte[] buffer;
 
+    // ----------------------------------------------------------- Constructors
+
     /**
      * The index of first valid character in the buffer.
      * <br>
@@ -266,8 +599,6 @@ public class MultipartStream {
      */
     private final ProgressNotifier notifier;
 
-    // ----------------------------------------------------------- Constructors
-
     /**
      * Creates a new instance.
      *
@@ -279,6 +610,24 @@ public class MultipartStream {
         this(null, null, null);
     }
 
+    // --------------------------------------------------------- Public methods
+
+    /**
+     * <p> Constructs a {@code MultipartStream} with a default size buffer.
+     *
+     * @param input    The {@code InputStream} to serve as a data source.
+     * @param boundary The token used for dividing the stream into
+     *                 {@code encapsulations}.
+     *
+     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int,
+     *  ProgressNotifier)}.
+     */
+    @Deprecated
+    public MultipartStream(final InputStream input,
+            final byte[] boundary) {
+        this(input, boundary, DEFAULT_BUFSIZE, null);
+    }
+
     /**
      * <p> Constructs a {@code MultipartStream} with a custom size buffer
      * and no progress notifier.
@@ -373,22 +722,91 @@ public class MultipartStream {
     }
 
     /**
-     * <p> Constructs a {@code MultipartStream} with a default size buffer.
-     *
-     * @param input    The {@code InputStream} to serve as a data source.
-     * @param boundary The token used for dividing the stream into
-     *                 {@code encapsulations}.
+     * Compute the table used for Knuth-Morris-Pratt search algorithm.
+     */
+    private void computeBoundaryTable() {
+        int position = 2;
+        int candidate = 0;
+
+        boundaryTable[0] = -1;
+        boundaryTable[1] = 0;
+
+        while (position <= boundaryLength) {
+            if (boundary[position - 1] == boundary[candidate]) {
+                boundaryTable[position] = candidate + 1;
+                candidate++;
+                position++;
+            } else if (candidate > 0) {
+                candidate = boundaryTable[candidate];
+            } else {
+                boundaryTable[position] = 0;
+                position++;
+            }
+        }
+    }
+
+    /**
+     * <p> Reads {@code body-data} from the current
+     * {@code encapsulation} and discards it.
      *
-     * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int,
-     *  ProgressNotifier)}.
+     * <p>Use this method to skip encapsulations you don't need or don't
+     * understand.
+     *
+     * @return The amount of data discarded.
+     *
+     * @throws MalformedStreamException if the stream ends unexpectedly.
+     * @throws IOException              if an i/o error occurs.
      */
-    @Deprecated
-    public MultipartStream(final InputStream input,
-            final byte[] boundary) {
-        this(input, boundary, DEFAULT_BUFSIZE, null);
+    public int discardBodyData() throws MalformedStreamException, IOException {
+        return readBodyData(null);
     }
 
-    // --------------------------------------------------------- Public methods
+    /**
+     * Searches for a byte of specified value in the {@code buffer},
+     * starting at the specified {@code position}.
+     *
+     * @param value The value to find.
+     * @param pos   The starting position for searching.
+     *
+     * @return The position of byte found, counting from beginning of the
+     *         {@code buffer}, or {@code -1} if not found.
+     */
+    protected int findByte(final byte value,
+            final int pos) {
+        for (int i = pos; i < tail; i++) {
+            if (buffer[i] == value) {
+                return i;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Searches for the {@code boundary} in the {@code buffer}
+     * region delimited by {@code head} and {@code tail}.
+     *
+     * @return The position of the boundary found, counting from the
+     *         beginning of the {@code buffer}, or {@code -1} if
+     *         not found.
+     */
+    protected int findSeparator() {
+
+        int bufferPos = this.head;
+        int tablePos = 0;
+
+        while (bufferPos < this.tail) {
+            while (tablePos >= 0 && buffer[bufferPos] != boundary[tablePos]) {
+                tablePos = boundaryTable[tablePos];
+            }
+            bufferPos++;
+            tablePos++;
+            if (tablePos == boundaryLength) {
+                return bufferPos - boundaryLength;
+            }
+        }
+        return -1;
+    }
 
     /**
      * Retrieves the character encoding used when reading the headers of an
@@ -402,39 +820,35 @@ public class MultipartStream {
     }
 
     /**
-     * Specifies the character encoding to be used when reading the headers of
-     * individual parts. When not specified, or {@code null}, the platform
-     * default encoding is used.
-     *
-     * @param encoding The encoding used to read part headers.
+     * Creates a new {@link ItemInputStream}.
+     * @return A new instance of {@link ItemInputStream}.
      */
-    public void setHeaderEncoding(final String encoding) {
-        headerEncoding = encoding;
+    public ItemInputStream newInputStream() {
+        return new ItemInputStream();
     }
 
     /**
-     * Reads a byte from the {@code buffer}, and refills it as
-     * necessary.
+     * <p>Reads {@code body-data} from the current
+     * {@code encapsulation} and writes its contents into the
+     * output {@code Stream}.
      *
-     * @return The next byte from the input stream.
+     * <p>Arbitrary large amounts of data can be processed by this
+     * method using a constant size buffer. (see {@link
+     * #MultipartStream(InputStream,byte[],int,
+     *   MultipartStream.ProgressNotifier) constructor}).
      *
-     * @throws IOException if there is no more data available.
+     * @param output The {@code Stream} to write data into. May
+     *               be null, in which case this method is equivalent
+     *               to {@link #discardBodyData()}.
+     *
+     * @return the amount of data written.
+     *
+     * @throws MalformedStreamException if the stream ends unexpectedly.
+     * @throws IOException              if an i/o error occurs.
      */
-    public byte readByte() throws IOException {
-        // Buffer depleted ?
-        if (head == tail) {
-            head = 0;
-            // Refill.
-            tail = input.read(buffer, head, bufSize);
-            if (tail == -1) {
-                // No more data available.
-                throw new IOException("No more data is available");
-            }
-            if (notifier != null) {
-                notifier.noteBytesRead(tail);
-            }
-        }
-        return buffer[head++];
+    public int readBodyData(final OutputStream output)
+            throws MalformedStreamException, IOException {
+        return (int) Streams.copy(newInputStream(), output, false); // N.B. Streams.copy closes the input stream
     }
 
     /**
@@ -485,57 +899,28 @@ public class MultipartStream {
     }
 
     /**
-     * <p>Changes the boundary token used for partitioning the stream.
-     *
-     * <p>This method allows single pass processing of nested multipart
-     * streams.
-     *
-     * <p>The boundary token of the nested stream is {@code required}
-     * to be of the same length as the boundary token in parent stream.
-     *
-     * <p>Restoring the parent stream boundary token after processing of a
-     * nested stream is left to the application.
+     * Reads a byte from the {@code buffer}, and refills it as
+     * necessary.
      *
-     * @param boundary The boundary to be used for parsing of the nested
-     *                 stream.
+     * @return The next byte from the input stream.
      *
-     * @throws IllegalBoundaryException if the {@code boundary}
-     *                                  has a different length than the one
-     *                                  being currently parsed.
-     */
-    public void setBoundary(final byte[] boundary)
-            throws IllegalBoundaryException {
-        if (boundary.length != boundaryLength - BOUNDARY_PREFIX.length) {
-            throw new IllegalBoundaryException(
-            "The length of a boundary token cannot be changed");
-        }
-        System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length,
-                boundary.length);
-        computeBoundaryTable();
-    }
-
-    /**
-     * Compute the table used for Knuth-Morris-Pratt search algorithm.
+     * @throws IOException if there is no more data available.
      */
-    private void computeBoundaryTable() {
-        int position = 2;
-        int candidate = 0;
-
-        boundaryTable[0] = -1;
-        boundaryTable[1] = 0;
-
-        while (position <= boundaryLength) {
-            if (boundary[position - 1] == boundary[candidate]) {
-                boundaryTable[position] = candidate + 1;
-                candidate++;
-                position++;
-            } else if (candidate > 0) {
-                candidate = boundaryTable[candidate];
-            } else {
-                boundaryTable[position] = 0;
-                position++;
+    public byte readByte() throws IOException {
+        // Buffer depleted ?
+        if (head == tail) {
+            head = 0;
+            // Refill.
+            tail = input.read(buffer, head, bufSize);
+            if (tail == -1) {
+                // No more data available.
+                throw new IOException("No more data is available");
+            }
+            if (notifier != null) {
+                notifier.noteBytesRead(tail);
             }
         }
+        return buffer[head++];
     }
 
     /**
@@ -599,58 +984,51 @@ public class MultipartStream {
     }
 
     /**
-     * <p>Reads {@code body-data} from the current
-     * {@code encapsulation} and writes its contents into the
-     * output {@code Stream}.
+     * <p>Changes the boundary token used for partitioning the stream.
      *
-     * <p>Arbitrary large amounts of data can be processed by this
-     * method using a constant size buffer. (see {@link
-     * #MultipartStream(InputStream,byte[],int,
-     *   MultipartStream.ProgressNotifier) constructor}).
+     * <p>This method allows single pass processing of nested multipart
+     * streams.
      *
-     * @param output The {@code Stream} to write data into. May
-     *               be null, in which case this method is equivalent
-     *               to {@link #discardBodyData()}.
+     * <p>The boundary token of the nested stream is {@code required}
+     * to be of the same length as the boundary token in parent stream.
      *
-     * @return the amount of data written.
+     * <p>Restoring the parent stream boundary token after processing of a
+     * nested stream is left to the application.
      *
-     * @throws MalformedStreamException if the stream ends unexpectedly.
-     * @throws IOException              if an i/o error occurs.
+     * @param boundary The boundary to be used for parsing of the nested
+     *                 stream.
+     *
+     * @throws IllegalBoundaryException if the {@code boundary}
+     *                                  has a different length than the one
+     *                                  being currently parsed.
      */
-    public int readBodyData(final OutputStream output)
-            throws MalformedStreamException, IOException {
-        return (int) Streams.copy(newInputStream(), output, false); // N.B. Streams.copy closes the input stream
+    public void setBoundary(final byte[] boundary)
+            throws IllegalBoundaryException {
+        if (boundary.length != boundaryLength - BOUNDARY_PREFIX.length) {
+            throw new IllegalBoundaryException(
+            "The length of a boundary token cannot be changed");
+        }
+        System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length,
+                boundary.length);
+        computeBoundaryTable();
     }
 
     /**
-     * Creates a new {@link ItemInputStream}.
-     * @return A new instance of {@link ItemInputStream}.
+     * Specifies the character encoding to be used when reading the headers of
+     * individual parts. When not specified, or {@code null}, the platform
+     * default encoding is used.
+     *
+     * @param encoding The encoding used to read part headers.
      */
-    public ItemInputStream newInputStream() {
-        return new ItemInputStream();
+    public void setHeaderEncoding(final String encoding) {
+        headerEncoding = encoding;
     }
 
     /**
-     * <p> Reads {@code body-data} from the current
-     * {@code encapsulation} and discards it.
+     * Finds the beginning of the first {@code encapsulation}.
      *
-     * <p>Use this method to skip encapsulations you don't need or don't
-     * understand.
-     *
-     * @return The amount of data discarded.
-     *
-     * @throws MalformedStreamException if the stream ends unexpectedly.
-     * @throws IOException              if an i/o error occurs.
-     */
-    public int discardBodyData() throws MalformedStreamException, IOException {
-        return readBodyData(null);
-    }
-
-    /**
-     * Finds the beginning of the first {@code encapsulation}.
-     *
-     * @return {@code true} if an {@code encapsulation} was found in
-     *         the stream.
+     * @return {@code true} if an {@code encapsulation} was found in
+     *         the stream.
      *
      * @throws IOException if an i/o error occurs.
      */
@@ -678,382 +1056,4 @@ public class MultipartStream {
         }
     }
 
-    /**
-     * Compares {@code count} first bytes in the arrays
-     * {@code a} and {@code b}.
-     *
-     * @param a     The first array to compare.
-     * @param b     The second array to compare.
-     * @param count How many bytes should be compared.
-     *
-     * @return {@code true} if {@code count} first bytes in arrays
-     *         {@code a} and {@code b} are equal.
-     */
-    public static boolean arrayequals(final byte[] a,
-            final byte[] b,
-            final int count) {
-        for (int i = 0; i < count; i++) {
-            if (a[i] != b[i]) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Searches for a byte of specified value in the {@code buffer},
-     * starting at the specified {@code position}.
-     *
-     * @param value The value to find.
-     * @param pos   The starting position for searching.
-     *
-     * @return The position of byte found, counting from beginning of the
-     *         {@code buffer}, or {@code -1} if not found.
-     */
-    protected int findByte(final byte value,
-            final int pos) {
-        for (int i = pos; i < tail; i++) {
-            if (buffer[i] == value) {
-                return i;
-            }
-        }
-
-        return -1;
-    }
-
-    /**
-     * Searches for the {@code boundary} in the {@code buffer}
-     * region delimited by {@code head} and {@code tail}.
-     *
-     * @return The position of the boundary found, counting from the
-     *         beginning of the {@code buffer}, or {@code -1} if
-     *         not found.
-     */
-    protected int findSeparator() {
-
-        int bufferPos = this.head;
-        int tablePos = 0;
-
-        while (bufferPos < this.tail) {
-            while (tablePos >= 0 && buffer[bufferPos] != boundary[tablePos]) {
-                tablePos = boundaryTable[tablePos];
-            }
-            bufferPos++;
-            tablePos++;
-            if (tablePos == boundaryLength) {
-                return bufferPos - boundaryLength;
-            }
-        }
-        return -1;
-    }
-
-    /**
-     * Thrown to indicate that the input stream fails to follow the
-     * required syntax.
-     */
-    public static class MalformedStreamException extends IOException {
-
-        /**
-         * The UID to use when serializing this instance.
-         */
-        private static final long serialVersionUID = 6466926458059796677L;
-
-        /**
-         * Constructs a {@code MalformedStreamException} with no
-         * detail message.
-         */
-        public MalformedStreamException() {
-        }
-
-        /**
-         * Constructs an {@code MalformedStreamException} with
-         * the specified detail message.
-         *
-         * @param message The detail message.
-         */
-        public MalformedStreamException(final String message) {
-            super(message);
-        }
-
-    }
-
-    /**
-     * Thrown upon attempt of setting an invalid boundary token.
-     */
-    public static class IllegalBoundaryException extends IOException {
-
-        /**
-         * The UID to use when serializing this instance.
-         */
-        private static final long serialVersionUID = -161533165102632918L;
-
-        /**
-         * Constructs an {@code IllegalBoundaryException} with no
-         * detail message.
-         */
-        public IllegalBoundaryException() {
-        }
-
-        /**
-         * Constructs an {@code IllegalBoundaryException} with
-         * the specified detail message.
-         *
-         * @param message The detail message.
-         */
-        public IllegalBoundaryException(final String message) {
-            super(message);
-        }
-
-    }
-
-    /**
-     * An {@link InputStream} for reading an items contents.
-     */
-    public class ItemInputStream extends InputStream implements Closeable {
-
-        /**
-         * The number of bytes, which have been read so far.
-         */
-        private long total;
-
-        /**
-         * The number of bytes, which must be hold, because
-         * they might be a part of the boundary.
-         */
-        private int pad;
-
-        /**
-         * The current offset in the buffer.
-         */
-        private int pos;
-
-        /**
-         * Whether the stream is already closed.
-         */
-        private boolean closed;
-
-        /**
-         * Creates a new instance.
-         */
-        ItemInputStream() {
-            findSeparator();
-        }
-
-        /**
-         * Called for finding the separator.
-         */
-        private void findSeparator() {
-            pos = MultipartStream.this.findSeparator();
-            if (pos == -1) {
-                if (tail - head > keepRegion) {
-                    pad = keepRegion;
-                } else {
-                    pad = tail - head;
-                }
-            }
-        }
-
-        /**
-         * Returns the number of bytes, which have been read
-         * by the stream.
-         *
-         * @return Number of bytes, which have been read so far.
-         */
-        public long getBytesRead() {
-            return total;
-        }
-
-        /**
-         * Returns the number of bytes, which are currently
-         * available, without blocking.
-         *
-         * @throws IOException An I/O error occurs.
-         * @return Number of bytes in the buffer.
-         */
-        @Override
-        public int available() throws IOException {
-            if (pos == -1) {
-                return tail - head - pad;
-            }
-            return pos - head;
-        }
-
-        /**
-         * Offset when converting negative bytes to integers.
-         */
-        private static final int BYTE_POSITIVE_OFFSET = 256;
-
-        /**
-         * Returns the next byte in the stream.
-         *
-         * @return The next byte in the stream, as a non-negative
-         *   integer, or -1 for EOF.
-         * @throws IOException An I/O error occurred.
-         */
-        @Override
-        public int read() throws IOException {
-            if (closed) {
-                throw new FileItemStream.ItemSkippedException();
-            }
-            if (available() == 0 && makeAvailable() == 0) {
-                return -1;
-            }
-            ++total;
-            final int b = buffer[head++];
-            if (b >= 0) {
-                return b;
-            }
-            return b + BYTE_POSITIVE_OFFSET;
-        }
-
-        /**
-         * Reads bytes into the given buffer.
-         *
-         * @param b The destination buffer, where to write to.
-         * @param off Offset of the first byte in the buffer.
-         * @param len Maximum number of bytes to read.
-         * @return Number of bytes, which have been actually read,
-         *   or -1 for EOF.
-         * @throws IOException An I/O error occurred.
-         */
-        @Override
-        public int read(final byte[] b, final int off, final int len) throws IOException {
-            if (closed) {
-                throw new FileItemStream.ItemSkippedException();
-            }
-            if (len == 0) {
-                return 0;
-            }
-            int res = available();
-            if (res == 0) {
-                res = makeAvailable();
-                if (res == 0) {
-                    return -1;
-                }
-            }
-            res = Math.min(res, len);
-            System.arraycopy(buffer, head, b, off, res);
-            head += res;
-            total += res;
-            return res;
-        }
-
-        /**
-         * Closes the input stream.
-         *
-         * @throws IOException An I/O error occurred.
-         */
-        @Override
-        public void close() throws IOException {
-            close(false);
-        }
-
-        /**
-         * Closes the input stream.
-         *
-         * @param pCloseUnderlying Whether to close the underlying stream
-         *   (hard close)
-         * @throws IOException An I/O error occurred.
-         */
-        public void close(final boolean pCloseUnderlying) throws IOException {
-            if (closed) {
-                return;
-            }
-            if (pCloseUnderlying) {
-                closed = true;
-                input.close();
-            } else {
-                for (;;) {
-                    int av = available();
-                    if (av == 0) {
-                        av = makeAvailable();
-                        if (av == 0) {
-                            break;
-                        }
-                    }
-                    skip(av);
-                }
-            }
-            closed = true;
-        }
-
-        /**
-         * Skips the given number of bytes.
-         *
-         * @param bytes Number of bytes to skip.
-         * @return The number of bytes, which have actually been
-         *   skipped.
-         * @throws IOException An I/O error occurred.
-         */
-        @Override
-        public long skip(final long bytes) throws IOException {
-            if (closed) {
-                throw new FileItemStream.ItemSkippedException();
-            }
-            int av = available();
-            if (av == 0) {
-                av = makeAvailable();
-                if (av == 0) {
-                    return 0;
-                }
-            }
-            final long res = Math.min(av, bytes);
-            head += res;
-            return res;
-        }
-
-        /**
-         * Attempts to read more data.
-         *
-         * @return Number of available bytes
-         * @throws IOException An I/O error occurred.
-         */
-        private int makeAvailable() throws IOException {
-            if (pos != -1) {
-                return 0;
-            }
-
-            // Move the data to the beginning of the buffer.
-            total += tail - head - pad;
-            System.arraycopy(buffer, tail - pad, buffer, 0, pad);
-
-            // Refill buffer with new data.
-            head = 0;
-            tail = pad;
-
-            for (;;) {
-                final int bytesRead = input.read(buffer, tail, bufSize - tail);
-                if (bytesRead == -1) {
-                    // The last pad amount is left in the buffer.
-                    // Boundary can't be in there so signal an error
-                    // condition.
-                    final String msg = "Stream ended unexpectedly";
-                    throw new MalformedStreamException(msg);
-                }
-                if (notifier != null) {
-                    notifier.noteBytesRead(bytesRead);
-                }
-                tail += bytesRead;
-
-                findSeparator();
-                final int av = available();
-
-                if (av > 0 || pos != -1) {
-                    return av;
-                }
-            }
-        }
-
-        /**
-         * Returns, whether the stream is closed.
-         *
-         * @return True, if the stream is closed, otherwise false.
-         */
-        @Override
-        public boolean isClosed() {
-            return closed;
-        }
-
-    }
-
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/ParameterParser.java b/src/main/java/org/apache/commons/fileupload2/ParameterParser.java
index 22f2328..4eba2f1 100644
--- a/src/main/java/org/apache/commons/fileupload2/ParameterParser.java
+++ b/src/main/java/org/apache/commons/fileupload2/ParameterParser.java
@@ -73,16 +73,6 @@ public class ParameterParser {
     public ParameterParser() {
     }
 
-    /**
-     * Are there any characters left to parse?
-     *
-     * @return {@code true} if there are unparsed characters,
-     *         {@code false} otherwise.
-     */
-    private boolean hasChar() {
-        return this.pos < this.len;
-    }
-
     /**
      * A helper method to process the parsed token. This method removes
      * leading and trailing blanks as well as enclosing quotation marks,
@@ -117,79 +107,13 @@ public class ParameterParser {
     }
 
     /**
-     * Tests if the given character is present in the array of characters.
-     *
-     * @param ch the character to test for presence in the array of characters
-     * @param charray the array of characters to test against
-     *
-     * @return {@code true} if the character is present in the array of
-     *   characters, {@code false} otherwise.
-     */
-    private boolean isOneOf(final char ch, final char[] charray) {
-        boolean result = false;
-        for (final char element : charray) {
-            if (ch == element) {
-                result = true;
-                break;
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Parses out a token until any of the given terminators
-     * is encountered.
-     *
-     * @param terminators the array of terminating characters. Any of these
-     * characters when encountered signify the end of the token
-     *
-     * @return the token
-     */
-    private String parseToken(final char[] terminators) {
-        char ch;
-        i1 = pos;
-        i2 = pos;
-        while (hasChar()) {
-            ch = chars[pos];
-            if (isOneOf(ch, terminators)) {
-                break;
-            }
-            i2++;
-            pos++;
-        }
-        return getToken(false);
-    }
-
-    /**
-     * Parses out a token until any of the given terminators
-     * is encountered outside the quotation marks.
-     *
-     * @param terminators the array of terminating characters. Any of these
-     * characters when encountered outside the quotation marks signify the end
-     * of the token
+     * Are there any characters left to parse?
      *
-     * @return the token
+     * @return {@code true} if there are unparsed characters,
+     *         {@code false} otherwise.
      */
-    private String parseQuotedToken(final char[] terminators) {
-        char ch;
-        i1 = pos;
-        i2 = pos;
-        boolean quoted = false;
-        boolean charEscaped = false;
-        while (hasChar()) {
-            ch = chars[pos];
-            if (!quoted && isOneOf(ch, terminators)) {
-                break;
-            }
-            if (!charEscaped && ch == '"') {
-                quoted = !quoted;
-            }
-            charEscaped = (!charEscaped && ch == '\\');
-            i2++;
-            pos++;
-
-        }
-        return getToken(true);
+    private boolean hasChar() {
+        return this.pos < this.len;
     }
 
     /**
@@ -205,59 +129,23 @@ public class ParameterParser {
     }
 
     /**
-     * Sets the flag if parameter names are to be converted to lower case when
-     * name/value pairs are parsed.
-     *
-     * @param b {@code true} if parameter names are to be
-     * converted to lower case when name/value pairs are parsed.
-     * {@code false} otherwise.
-     */
-    public void setLowerCaseNames(final boolean b) {
-        this.lowerCaseNames = b;
-    }
-
-    /**
-     * Extracts a map of name/value pairs from the given string. Names are
-     * expected to be unique. Multiple separators may be specified and
-     * the earliest found in the input string is used.
+     * Tests if the given character is present in the array of characters.
      *
-     * @param str the string that contains a sequence of name/value pairs
-     * @param separators the name/value pairs separators
+     * @param ch the character to test for presence in the array of characters
+     * @param charray the array of characters to test against
      *
-     * @return a map of name/value pairs
+     * @return {@code true} if the character is present in the array of
+     *   characters, {@code false} otherwise.
      */
-    public Map<String, String> parse(final String str, final char[] separators) {
-        if (separators == null || separators.length == 0) {
-            return new HashMap<>();
-        }
-        char separator = separators[0];
-        if (str != null) {
-            int idx = str.length();
-            for (final char separator2 : separators) {
-                final int tmp = str.indexOf(separator2);
-                if (tmp != -1 && tmp < idx) {
-                    idx = tmp;
-                    separator = separator2;
-                }
+    private boolean isOneOf(final char ch, final char[] charray) {
+        boolean result = false;
+        for (final char element : charray) {
+            if (ch == element) {
+                result = true;
+                break;
             }
         }
-        return parse(str, separator);
-    }
-
-    /**
-     * Extracts a map of name/value pairs from the given string. Names are
-     * expected to be unique.
-     *
-     * @param str the string that contains a sequence of name/value pairs
-     * @param separator the name/value pairs separator
-     *
-     * @return a map of name/value pairs
-     */
-    public Map<String, String> parse(final String str, final char separator) {
-        if (str == null) {
-            return new HashMap<>();
-        }
-        return parse(str.toCharArray(), separator);
+        return result;
     }
 
     /**
@@ -337,4 +225,116 @@ public class ParameterParser {
         return params;
     }
 
+    /**
+     * Extracts a map of name/value pairs from the given string. Names are
+     * expected to be unique.
+     *
+     * @param str the string that contains a sequence of name/value pairs
+     * @param separator the name/value pairs separator
+     *
+     * @return a map of name/value pairs
+     */
+    public Map<String, String> parse(final String str, final char separator) {
+        if (str == null) {
+            return new HashMap<>();
+        }
+        return parse(str.toCharArray(), separator);
+    }
+
+    /**
+     * Extracts a map of name/value pairs from the given string. Names are
+     * expected to be unique. Multiple separators may be specified and
+     * the earliest found in the input string is used.
+     *
+     * @param str the string that contains a sequence of name/value pairs
+     * @param separators the name/value pairs separators
+     *
+     * @return a map of name/value pairs
+     */
+    public Map<String, String> parse(final String str, final char[] separators) {
+        if (separators == null || separators.length == 0) {
+            return new HashMap<>();
+        }
+        char separator = separators[0];
+        if (str != null) {
+            int idx = str.length();
+            for (final char separator2 : separators) {
+                final int tmp = str.indexOf(separator2);
+                if (tmp != -1 && tmp < idx) {
+                    idx = tmp;
+                    separator = separator2;
+                }
+            }
+        }
+        return parse(str, separator);
+    }
+
+    /**
+     * Parses out a token until any of the given terminators
+     * is encountered outside the quotation marks.
+     *
+     * @param terminators the array of terminating characters. Any of these
+     * characters when encountered outside the quotation marks signify the end
+     * of the token
+     *
+     * @return the token
+     */
+    private String parseQuotedToken(final char[] terminators) {
+        char ch;
+        i1 = pos;
+        i2 = pos;
+        boolean quoted = false;
+        boolean charEscaped = false;
+        while (hasChar()) {
+            ch = chars[pos];
+            if (!quoted && isOneOf(ch, terminators)) {
+                break;
+            }
+            if (!charEscaped && ch == '"') {
+                quoted = !quoted;
+            }
+            charEscaped = (!charEscaped && ch == '\\');
+            i2++;
+            pos++;
+
+        }
+        return getToken(true);
+    }
+
+    /**
+     * Parses out a token until any of the given terminators
+     * is encountered.
+     *
+     * @param terminators the array of terminating characters. Any of these
+     * characters when encountered signify the end of the token
+     *
+     * @return the token
+     */
+    private String parseToken(final char[] terminators) {
+        char ch;
+        i1 = pos;
+        i2 = pos;
+        while (hasChar()) {
+            ch = chars[pos];
+            if (isOneOf(ch, terminators)) {
+                break;
+            }
+            i2++;
+            pos++;
+        }
+        return getToken(false);
+    }
+
+    /**
+     * Sets the flag if parameter names are to be converted to lower case when
+     * name/value pairs are parsed.
+     *
+     * @param b {@code true} if parameter names are to be
+     * converted to lower case when name/value pairs are parsed.
+     * {@code false} otherwise.
+     */
+    public void setLowerCaseNames(final boolean b) {
+        this.lowerCaseNames = b;
+    }
+
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/RequestContext.java b/src/main/java/org/apache/commons/fileupload2/RequestContext.java
index cdb1504..9f4a8d1 100644
--- a/src/main/java/org/apache/commons/fileupload2/RequestContext.java
+++ b/src/main/java/org/apache/commons/fileupload2/RequestContext.java
@@ -35,13 +35,6 @@ public interface RequestContext {
      */
     String getCharacterEncoding();
 
-    /**
-     * Retrieve the content type of the request.
-     *
-     * @return The content type of the request.
-     */
-    String getContentType();
-
     /**
      * Retrieve the content length of the request.
      *
@@ -51,6 +44,13 @@ public interface RequestContext {
     @Deprecated
     int getContentLength();
 
+    /**
+     * Retrieve the content type of the request.
+     *
+     * @return The content type of the request.
+     */
+    String getContentType();
+
     /**
      * Retrieve the input stream for the request.
      *
diff --git a/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItem.java b/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItem.java
index b3f4bac..90af239 100644
--- a/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItem.java
+++ b/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItem.java
@@ -94,6 +94,25 @@ public class DiskFileItem
      */
     private static final AtomicInteger COUNTER = new AtomicInteger(0);
 
+    /**
+     * Returns an identifier that is unique within the class loader used to
+     * load this class, but does not have random-like appearance.
+     *
+     * @return A String with the non-random looking instance identifier.
+     */
+    private static String getUniqueId() {
+        final int limit = 100000000;
+        final int current = COUNTER.getAndIncrement();
+        String id = Integer.toString(current);
+
+        // If you manage to get more than 100 million of ids, you'll
+        // start getting ids longer than 8 characters.
+        if (current < limit) {
+            id = ("00000000" + id).substring(id.length());
+        }
+        return id;
+    }
+
     /**
      * The name of the form field as provided by the browser.
      */
@@ -115,13 +134,13 @@ public class DiskFileItem
      */
     private final String fileName;
 
+
     /**
      * The size of the item, in bytes. This is used to cache the size when a
      * file item is moved from its original location.
      */
     private long size = -1;
 
-
     /**
      * The threshold above which uploads will be stored on disk.
      */
@@ -152,13 +171,15 @@ public class DiskFileItem
      */
     private FileItemHeaders headers;
 
+    // ----------------------------------------------------------- Constructors
+
     /**
      * Default content charset to be used when no explicit charset
      * parameter is provided by the sender.
      */
     private String defaultCharset = DEFAULT_CHARSET;
 
-    // ----------------------------------------------------------- Constructors
+    // ------------------------------- Methods from javax.activation.DataSource
 
     /**
      * Constructs a new {@code DiskFileItem} instance.
@@ -188,105 +209,20 @@ public class DiskFileItem
         this.repository = repository;
     }
 
-    // ------------------------------- Methods from javax.activation.DataSource
-
-    /**
-     * Returns an {@link java.io.InputStream InputStream} that can be
-     * used to retrieve the contents of the file.
-     *
-     * @return An {@link java.io.InputStream InputStream} that can be
-     *         used to retrieve the contents of the file.
-     *
-     * @throws IOException if an error occurs.
-     */
-    @Override
-    public InputStream getInputStream()
-        throws IOException {
-        if (!isInMemory()) {
-            return Files.newInputStream(dfos.getFile().toPath());
-        }
-
-        if (cachedContent == null) {
-            cachedContent = dfos.getData();
-        }
-        return new ByteArrayInputStream(cachedContent);
-    }
-
-    /**
-     * Returns the content type passed by the agent or {@code null} if
-     * not defined.
-     *
-     * @return The content type passed by the agent or {@code null} if
-     *         not defined.
-     */
-    @Override
-    public String getContentType() {
-        return contentType;
-    }
-
-    /**
-     * Returns the content charset passed by the agent or {@code null} if
-     * not defined.
-     *
-     * @return The content charset passed by the agent or {@code null} if
-     *         not defined.
-     */
-    public String getCharSet() {
-        final ParameterParser parser = new ParameterParser();
-        parser.setLowerCaseNames(true);
-        // Parameter parser can handle null input
-        final Map<String, String> params = parser.parse(getContentType(), ';');
-        return params.get("charset");
-    }
-
-    /**
-     * Returns the original file name in the client's file system.
-     *
-     * @return The original file name in the client's file system.
-     * @throws org.apache.commons.fileupload2.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
-     *   {@link org.apache.commons.fileupload2.InvalidFileNameException#getName()}.
-     */
-    @Override
-    public String getName() {
-        return Streams.checkFileName(fileName);
-    }
-
-    // ------------------------------------------------------- FileItem methods
-
     /**
-     * Provides a hint as to whether or not the file contents will be read
-     * from memory.
-     *
-     * @return {@code true} if the file contents will be read
-     *         from memory; {@code false} otherwise.
-     */
-    @Override
-    public boolean isInMemory() {
-        if (cachedContent != null) {
-            return true;
-        }
-        return dfos.isInMemory();
-    }
-
-    /**
-     * Returns the size of the file.
-     *
-     * @return The size of the file, in bytes.
+     * Deletes the underlying storage for a file item, including deleting any associated temporary disk file.
+     * This method can be used to ensure that this is done at an earlier time, thus preserving system resources.
      */
     @Override
-    public long getSize() {
-        if (size >= 0) {
-            return size;
-        }
-        if (cachedContent != null) {
-            return cachedContent.length;
-        }
-        if (dfos.isInMemory()) {
-            return dfos.getData().length;
+    public void delete() {
+        cachedContent = null;
+        final File outputFile = getStoreLocation();
+        if (outputFile != null && !isInMemory() && outputFile.exists()) {
+            if (!outputFile.delete()) {
+                final String desc = "Cannot delete " + outputFile.toString();
+                throw new UncheckedIOException(desc, new IOException(desc));
+            }
         }
-        return dfos.getFile().length();
     }
 
     /**
@@ -319,113 +255,41 @@ public class DiskFileItem
     }
 
     /**
-     * Returns the contents of the file as a String, using the specified
-     * encoding.  This method uses {@link #get()} to retrieve the
-     * contents of the file.
-     *
-     * @param charset The charset to use.
-     *
-     * @return The contents of the file, as a string.
+     * Returns the content charset passed by the agent or {@code null} if
+     * not defined.
      *
-     * @throws UnsupportedEncodingException if the requested character
-     *                                      encoding is not available.
+     * @return The content charset passed by the agent or {@code null} if
+     *         not defined.
      */
-    @Override
-    public String getString(final String charset)
-        throws UnsupportedEncodingException, IOException {
-        return new String(get(), charset);
+    public String getCharSet() {
+        final ParameterParser parser = new ParameterParser();
+        parser.setLowerCaseNames(true);
+        // Parameter parser can handle null input
+        final Map<String, String> params = parser.parse(getContentType(), ';');
+        return params.get("charset");
     }
 
-    /**
-     * Returns the contents of the file as a String, using the default
-     * character encoding.  This method uses {@link #get()} to retrieve the
-     * contents of the file.
-     *
-     * <b>TODO</b> Consider making this method throw UnsupportedEncodingException.
-     *
-     * @return The contents of the file, as a string.
-     */
-    @Override
-    public String getString() {
-        try {
-            final byte[] rawData = get();
-            String charset = getCharSet();
-            if (charset == null) {
-                charset = defaultCharset;
-            }
-            return new String(rawData, charset);
-        } catch (final IOException e) {
-            return "";
-        }
-    }
+    // ------------------------------------------------------- FileItem methods
 
     /**
-     * A convenience method to write an uploaded item to disk. The client code
-     * is not concerned with whether or not the item is stored in memory, or on
-     * disk in a temporary location. They just want to write the uploaded item
-     * to a file.
-     * <p>
-     * This implementation first attempts to rename the uploaded item to the
-     * specified destination file, if the item was originally written to disk.
-     * Otherwise, the data will be copied to the specified file.
-     * <p>
-     * This method is only guaranteed to work <em>once</em>, the first time it
-     * is invoked for a particular item. This is because, in the event that the
-     * method renames a temporary file, that file will no longer be available
-     * to copy or rename again at a later time.
-     *
-     * @param file The {@code File} into which the uploaded item should
-     *             be stored.
+     * Returns the content type passed by the agent or {@code null} if
+     * not defined.
      *
-     * @throws Exception if an error occurs.
+     * @return The content type passed by the agent or {@code null} if
+     *         not defined.
      */
     @Override
-    public void write(final File file) throws Exception {
-        if (isInMemory()) {
-            try (OutputStream fout = Files.newOutputStream(file.toPath())) {
-                fout.write(get());
-            } catch (final IOException e) {
-                throw new IOException("Unexpected output data");
-            }
-        } else {
-            final File outputFile = getStoreLocation();
-            if (outputFile == null) {
-                /*
-                 * For whatever reason we cannot write the
-                 * file to disk.
-                 */
-                throw new FileUploadException(
-                    "Cannot write uploaded file to disk!");
-            }
-            // Save the length of the file
-            size = outputFile.length();
-            /*
-             * The uploaded file is being stored on disk
-             * in a temporary location so move it to the
-             * desired file.
-             */
-            if (file.exists() && !file.delete()) {
-                throw new FileUploadException(
-                        "Cannot write uploaded file to disk!");
-            }
-            FileUtils.moveFile(outputFile, file);
-        }
+    public String getContentType() {
+        return contentType;
     }
 
     /**
-     * Deletes the underlying storage for a file item, including deleting any associated temporary disk file.
-     * This method can be used to ensure that this is done at an earlier time, thus preserving system resources.
+     * Returns the default charset for use when no explicit charset
+     * parameter is provided by the sender.
+     * @return the default charset
      */
-    @Override
-    public void delete() {
-        cachedContent = null;
-        final File outputFile = getStoreLocation();
-        if (outputFile != null && !isInMemory() && outputFile.exists()) {
-            if (!outputFile.delete()) {
-                final String desc = "Cannot delete " + outputFile.toString();
-                throw new UncheckedIOException(desc, new IOException(desc));
-            }
-        }
+    public String getDefaultCharset() {
+        return defaultCharset;
     }
 
     /**
@@ -443,46 +307,48 @@ public class DiskFileItem
     }
 
     /**
-     * Sets the field name used to reference this file item.
-     *
-     * @param fieldName The name of the form field.
-     *
-     * @see #getFieldName()
-     *
+     * Returns the file item headers.
+     * @return The file items headers.
      */
     @Override
-    public void setFieldName(final String fieldName) {
-        this.fieldName = fieldName;
+    public FileItemHeaders getHeaders() {
+        return headers;
     }
 
     /**
-     * Determines whether or not a {@code FileItem} instance represents
-     * a simple form field.
-     *
-     * @return {@code true} if the instance represents a simple form
-     *         field; {@code false} if it represents an uploaded file.
+     * Returns an {@link java.io.InputStream InputStream} that can be
+     * used to retrieve the contents of the file.
      *
-     * @see #setFormField(boolean)
+     * @return An {@link java.io.InputStream InputStream} that can be
+     *         used to retrieve the contents of the file.
      *
+     * @throws IOException if an error occurs.
      */
     @Override
-    public boolean isFormField() {
-        return isFormField;
+    public InputStream getInputStream()
+        throws IOException {
+        if (!isInMemory()) {
+            return Files.newInputStream(dfos.getFile().toPath());
+        }
+
+        if (cachedContent == null) {
+            cachedContent = dfos.getData();
+        }
+        return new ByteArrayInputStream(cachedContent);
     }
 
     /**
-     * Specifies whether or not a {@code FileItem} instance represents
-     * a simple form field.
-     *
-     * @param state {@code true} if the instance represents a simple form
-     *              field; {@code false} if it represents an uploaded file.
-     *
-     * @see #isFormField()
+     * Returns the original file name in the client's file system.
      *
+     * @return The original file name in the client's file system.
+     * @throws org.apache.commons.fileupload2.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
+     *   {@link org.apache.commons.fileupload2.InvalidFileNameException#getName()}.
      */
     @Override
-    public void setFormField(final boolean state) {
-        isFormField = state;
+    public String getName() {
+        return Streams.checkFileName(fileName);
     }
 
     /**
@@ -502,7 +368,24 @@ public class DiskFileItem
         return dfos;
     }
 
-    // --------------------------------------------------------- Public methods
+    /**
+     * Returns the size of the file.
+     *
+     * @return The size of the file, in bytes.
+     */
+    @Override
+    public long getSize() {
+        if (size >= 0) {
+            return size;
+        }
+        if (cachedContent != null) {
+            return cachedContent.length;
+        }
+        if (dfos.isInMemory()) {
+            return dfos.getData().length;
+        }
+        return dfos.getFile().length();
+    }
 
     /**
      * Returns the {@link java.io.File} object for the {@code FileItem}'s
@@ -527,7 +410,46 @@ public class DiskFileItem
         return dfos.getFile();
     }
 
-    // ------------------------------------------------------ Protected methods
+    /**
+     * Returns the contents of the file as a String, using the default
+     * character encoding.  This method uses {@link #get()} to retrieve the
+     * contents of the file.
+     *
+     * <b>TODO</b> Consider making this method throw UnsupportedEncodingException.
+     *
+     * @return The contents of the file, as a string.
+     */
+    @Override
+    public String getString() {
+        try {
+            final byte[] rawData = get();
+            String charset = getCharSet();
+            if (charset == null) {
+                charset = defaultCharset;
+            }
+            return new String(rawData, charset);
+        } catch (final IOException e) {
+            return "";
+        }
+    }
+
+    /**
+     * Returns the contents of the file as a String, using the specified
+     * encoding.  This method uses {@link #get()} to retrieve the
+     * contents of the file.
+     *
+     * @param charset The charset to use.
+     *
+     * @return The contents of the file, as a string.
+     *
+     * @throws UnsupportedEncodingException if the requested character
+     *                                      encoding is not available.
+     */
+    @Override
+    public String getString(final String charset)
+        throws UnsupportedEncodingException, IOException {
+        return new String(get(), charset);
+    }
 
     /**
      * Creates and returns a {@link java.io.File File} representing a uniquely
@@ -554,46 +476,77 @@ public class DiskFileItem
         return tempFile;
     }
 
-    // -------------------------------------------------------- Private methods
+    // --------------------------------------------------------- Public methods
 
     /**
-     * Returns an identifier that is unique within the class loader used to
-     * load this class, but does not have random-like appearance.
+     * Determines whether or not a {@code FileItem} instance represents
+     * a simple form field.
+     *
+     * @return {@code true} if the instance represents a simple form
+     *         field; {@code false} if it represents an uploaded file.
+     *
+     * @see #setFormField(boolean)
      *
-     * @return A String with the non-random looking instance identifier.
      */
-    private static String getUniqueId() {
-        final int limit = 100000000;
-        final int current = COUNTER.getAndIncrement();
-        String id = Integer.toString(current);
+    @Override
+    public boolean isFormField() {
+        return isFormField;
+    }
 
-        // If you manage to get more than 100 million of ids, you'll
-        // start getting ids longer than 8 characters.
-        if (current < limit) {
-            id = ("00000000" + id).substring(id.length());
+    // ------------------------------------------------------ Protected methods
+
+    /**
+     * Provides a hint as to whether or not the file contents will be read
+     * from memory.
+     *
+     * @return {@code true} if the file contents will be read
+     *         from memory; {@code false} otherwise.
+     */
+    @Override
+    public boolean isInMemory() {
+        if (cachedContent != null) {
+            return true;
         }
-        return id;
+        return dfos.isInMemory();
     }
 
+    // -------------------------------------------------------- Private methods
+
     /**
-     * Returns a string representation of this object.
+     * Sets the default charset for use when no explicit charset
+     * parameter is provided by the sender.
+     * @param charset the default charset
+     */
+    public void setDefaultCharset(final String charset) {
+        defaultCharset = charset;
+    }
+
+    /**
+     * Sets the field name used to reference this file item.
+     *
+     * @param fieldName The name of the form field.
+     *
+     * @see #getFieldName()
      *
-     * @return a string representation of this object.
      */
     @Override
-    public String toString() {
-        return format("name=%s, StoreLocation=%s, size=%s bytes, isFormField=%s, FieldName=%s",
-                      getName(), getStoreLocation(), getSize(),
-                isFormField(), getFieldName());
+    public void setFieldName(final String fieldName) {
+        this.fieldName = fieldName;
     }
 
     /**
-     * Returns the file item headers.
-     * @return The file items headers.
+     * Specifies whether or not a {@code FileItem} instance represents
+     * a simple form field.
+     *
+     * @param state {@code true} if the instance represents a simple form
+     *              field; {@code false} if it represents an uploaded file.
+     *
+     * @see #isFormField()
+     *
      */
     @Override
-    public FileItemHeaders getHeaders() {
-        return headers;
+    public void setFormField(final boolean state) {
+        isFormField = state;
     }
 
     /**
@@ -606,20 +559,67 @@ public class DiskFileItem
     }
 
     /**
-     * Returns the default charset for use when no explicit charset
-     * parameter is provided by the sender.
-     * @return the default charset
+     * Returns a string representation of this object.
+     *
+     * @return a string representation of this object.
      */
-    public String getDefaultCharset() {
-        return defaultCharset;
+    @Override
+    public String toString() {
+        return format("name=%s, StoreLocation=%s, size=%s bytes, isFormField=%s, FieldName=%s",
+                      getName(), getStoreLocation(), getSize(),
+                isFormField(), getFieldName());
     }
 
     /**
-     * Sets the default charset for use when no explicit charset
-     * parameter is provided by the sender.
-     * @param charset the default charset
+     * A convenience method to write an uploaded item to disk. The client code
+     * is not concerned with whether or not the item is stored in memory, or on
+     * disk in a temporary location. They just want to write the uploaded item
+     * to a file.
+     * <p>
+     * This implementation first attempts to rename the uploaded item to the
+     * specified destination file, if the item was originally written to disk.
+     * Otherwise, the data will be copied to the specified file.
+     * <p>
+     * This method is only guaranteed to work <em>once</em>, the first time it
+     * is invoked for a particular item. This is because, in the event that the
+     * method renames a temporary file, that file will no longer be available
+     * to copy or rename again at a later time.
+     *
+     * @param file The {@code File} into which the uploaded item should
+     *             be stored.
+     *
+     * @throws Exception if an error occurs.
      */
-    public void setDefaultCharset(final String charset) {
-        defaultCharset = charset;
+    @Override
+    public void write(final File file) throws Exception {
+        if (isInMemory()) {
+            try (OutputStream fout = Files.newOutputStream(file.toPath())) {
+                fout.write(get());
+            } catch (final IOException e) {
+                throw new IOException("Unexpected output data");
+            }
+        } else {
+            final File outputFile = getStoreLocation();
+            if (outputFile == null) {
+                /*
+                 * For whatever reason we cannot write the
+                 * file to disk.
+                 */
+                throw new FileUploadException(
+                    "Cannot write uploaded file to disk!");
+            }
+            // Save the length of the file
+            size = outputFile.length();
+            /*
+             * The uploaded file is being stored on disk
+             * in a temporary location so move it to the
+             * desired file.
+             */
+            if (file.exists() && !file.delete()) {
+                throw new FileUploadException(
+                        "Cannot write uploaded file to disk!");
+            }
+            FileUtils.moveFile(outputFile, file);
+        }
     }
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItemFactory.java b/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItemFactory.java
index dc1342a..2943f37 100644
--- a/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItemFactory.java
+++ b/src/main/java/org/apache/commons/fileupload2/disk/DiskFileItemFactory.java
@@ -128,58 +128,6 @@ public class DiskFileItemFactory implements FileItemFactory {
 
     // ------------------------------------------------------------- Properties
 
-    /**
-     * Returns the directory used to temporarily store files that are larger
-     * than the configured size threshold.
-     *
-     * @return The directory in which temporary files will be located.
-     *
-     * @see #setRepository(java.io.File)
-     *
-     */
-    public File getRepository() {
-        return repository;
-    }
-
-    /**
-     * Sets the directory used to temporarily store files that are larger
-     * than the configured size threshold.
-     *
-     * @param repository The directory in which temporary files will be located.
-     *
-     * @see #getRepository()
-     *
-     */
-    public void setRepository(final File repository) {
-        this.repository = repository;
-    }
-
-    /**
-     * Returns the size threshold beyond which files are written directly to
-     * disk. The default value is 10240 bytes.
-     *
-     * @return The size threshold, in bytes.
-     *
-     * @see #setSizeThreshold(int)
-     */
-    public int getSizeThreshold() {
-        return sizeThreshold;
-    }
-
-    /**
-     * Sets the size threshold beyond which files are written directly to disk.
-     *
-     * @param sizeThreshold The size threshold, in bytes.
-     *
-     * @see #getSizeThreshold()
-     *
-     */
-    public void setSizeThreshold(final int sizeThreshold) {
-        this.sizeThreshold = sizeThreshold;
-    }
-
-    // --------------------------------------------------------- Public Methods
-
     /**
      * Create a new {@link org.apache.commons.fileupload2.disk.DiskFileItem}
      * instance from the supplied parameters and the local factory
@@ -207,6 +155,15 @@ public class DiskFileItemFactory implements FileItemFactory {
         return result;
     }
 
+    /**
+     * Returns the default charset for use when no explicit charset
+     * parameter is provided by the sender.
+     * @return the default charset
+     */
+    public String getDefaultCharset() {
+        return defaultCharset;
+    }
+
     /**
      * Returns the tracker, which is responsible for deleting temporary
      * files.
@@ -218,6 +175,42 @@ public class DiskFileItemFactory implements FileItemFactory {
         return fileCleaningTracker;
     }
 
+    /**
+     * Returns the directory used to temporarily store files that are larger
+     * than the configured size threshold.
+     *
+     * @return The directory in which temporary files will be located.
+     *
+     * @see #setRepository(java.io.File)
+     *
+     */
+    public File getRepository() {
+        return repository;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Returns the size threshold beyond which files are written directly to
+     * disk. The default value is 10240 bytes.
+     *
+     * @return The size threshold, in bytes.
+     *
+     * @see #setSizeThreshold(int)
+     */
+    public int getSizeThreshold() {
+        return sizeThreshold;
+    }
+
+    /**
+     * Sets the default charset for use when no explicit charset
+     * parameter is provided by the sender.
+     * @param pCharset the default charset
+     */
+    public void setDefaultCharset(final String pCharset) {
+        defaultCharset = pCharset;
+    }
+
     /**
      * Sets the tracker, which is responsible for deleting temporary
      * files.
@@ -231,20 +224,27 @@ public class DiskFileItemFactory implements FileItemFactory {
     }
 
     /**
-     * Returns the default charset for use when no explicit charset
-     * parameter is provided by the sender.
-     * @return the default charset
+     * Sets the directory used to temporarily store files that are larger
+     * than the configured size threshold.
+     *
+     * @param repository The directory in which temporary files will be located.
+     *
+     * @see #getRepository()
+     *
      */
-    public String getDefaultCharset() {
-        return defaultCharset;
+    public void setRepository(final File repository) {
+        this.repository = repository;
     }
 
     /**
-     * Sets the default charset for use when no explicit charset
-     * parameter is provided by the sender.
-     * @param pCharset the default charset
+     * Sets the size threshold beyond which files are written directly to disk.
+     *
+     * @param sizeThreshold The size threshold, in bytes.
+     *
+     * @see #getSizeThreshold()
+     *
      */
-    public void setDefaultCharset(final String pCharset) {
-        defaultCharset = pCharset;
+    public void setSizeThreshold(final int sizeThreshold) {
+        this.sizeThreshold = sizeThreshold;
     }
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java b/src/main/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java
index 7783630..23635cd 100644
--- a/src/main/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java
+++ b/src/main/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java
@@ -67,26 +67,6 @@ public class FileItemIteratorImpl implements FileItemIterator {
     private long fileSizeMax;
 
 
-    @Override
-    public long getSizeMax() {
-        return sizeMax;
-    }
-
-    @Override
-    public void setSizeMax(final long sizeMax) {
-        this.sizeMax = sizeMax;
-    }
-
-    @Override
-    public long getFileSizeMax() {
-        return fileSizeMax;
-    }
-
-    @Override
-    public void setFileSizeMax(final long fileSizeMax) {
-        this.fileSizeMax = fileSizeMax;
-    }
-
     /**
      * The multi part stream to process.
      */
@@ -147,75 +127,6 @@ public class FileItemIteratorImpl implements FileItemIterator {
         findNextItem();
     }
 
-    protected void init(final FileUploadBase fileUploadBase, final RequestContext pRequestContext)
-            throws FileUploadException, IOException {
-        final String contentType = ctx.getContentType();
-        if ((null == contentType)
-                || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(FileUploadBase.MULTIPART))) {
-            throw new InvalidContentTypeException(
-                    format("the request doesn't contain a %s or %s stream, content type header is %s",
-                           FileUploadBase.MULTIPART_FORM_DATA, FileUploadBase.MULTIPART_MIXED, contentType));
-        }
-        final long contentLengthInt = ((UploadContext) ctx).contentLength();
-        final long requestSize = UploadContext.class.isAssignableFrom(ctx.getClass())
-                                 // Inline conditional is OK here CHECKSTYLE:OFF
-                                 ? ((UploadContext) ctx).contentLength()
-                                 : contentLengthInt;
-                                 // CHECKSTYLE:ON
-
-        final InputStream input; // N.B. this is eventually closed in MultipartStream processing
-        if (sizeMax >= 0) {
-            if (requestSize != -1 && requestSize > sizeMax) {
-                throw new SizeLimitExceededException(
-                    format("the request was rejected because its size (%s) exceeds the configured maximum (%s)",
-                            requestSize, sizeMax),
-                           requestSize, sizeMax);
-            }
-            // N.B. this is eventually closed in MultipartStream processing
-            input = new LimitedInputStream(ctx.getInputStream(), sizeMax) {
-                @Override
-                protected void raiseError(final long pSizeMax, final long pCount)
-                        throws IOException {
-                    final FileUploadException ex = new SizeLimitExceededException(
-                    format("the request was rejected because its size (%s) exceeds the configured maximum (%s)",
-                            pCount, pSizeMax),
-                           pCount, pSizeMax);
-                    throw new FileUploadIOException(ex);
-                }
-            };
-        } else {
-            input = ctx.getInputStream();
-        }
-
-        String charEncoding = fileUploadBase.getHeaderEncoding();
-        if (charEncoding == null) {
-            charEncoding = ctx.getCharacterEncoding();
-        }
-
-        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");
-        }
-
-        progressNotifier = new MultipartStream.ProgressNotifier(fileUploadBase.getProgressListener(), requestSize);
-        try {
-            multiPartStream = new MultipartStream(input, multiPartBoundary, progressNotifier);
-        } catch (final IllegalArgumentException iae) {
-            IOUtils.closeQuietly(input); // avoid possible resource leak
-            throw new InvalidContentTypeException(
-                    format("The boundary specified in the %s header is too long", FileUploadBase.CONTENT_TYPE), iae);
-        }
-        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.
      *
@@ -299,6 +210,35 @@ public class FileItemIteratorImpl implements FileItemIterator {
         }
     }
 
+    @Override
+    public List<FileItem> getFileItems() throws FileUploadException, IOException {
+        final List<FileItem> items = new ArrayList<>();
+        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;
+    }
+
+    @Override
+    public long getFileSizeMax() {
+        return fileSizeMax;
+    }
+
+    public MultipartStream getMultiPartStream() throws FileUploadException, IOException {
+        if (multiPartStream == null) {
+            init(fileUploadBase, ctx);
+        }
+        return multiPartStream;
+    }
+
+    @Override
+    public long getSizeMax() {
+        return sizeMax;
+    }
+
     /**
      * Returns, whether another instance of {@link FileItemStream}
      * is available.
@@ -325,6 +265,68 @@ public class FileItemIteratorImpl implements FileItemIterator {
         }
     }
 
+    protected void init(final FileUploadBase fileUploadBase, final RequestContext pRequestContext)
+            throws FileUploadException, IOException {
+        final String contentType = ctx.getContentType();
+        if ((null == contentType)
+                || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(FileUploadBase.MULTIPART))) {
+            throw new InvalidContentTypeException(
+                    format("the request doesn't contain a %s or %s stream, content type header is %s",
+                           FileUploadBase.MULTIPART_FORM_DATA, FileUploadBase.MULTIPART_MIXED, contentType));
+        }
+        final long contentLengthInt = ((UploadContext) ctx).contentLength();
+        final long requestSize = UploadContext.class.isAssignableFrom(ctx.getClass())
+                                 // Inline conditional is OK here CHECKSTYLE:OFF
+                                 ? ((UploadContext) ctx).contentLength()
+                                 : contentLengthInt;
+                                 // CHECKSTYLE:ON
+
+        final InputStream input; // N.B. this is eventually closed in MultipartStream processing
+        if (sizeMax >= 0) {
+            if (requestSize != -1 && requestSize > sizeMax) {
+                throw new SizeLimitExceededException(
+                    format("the request was rejected because its size (%s) exceeds the configured maximum (%s)",
+                            requestSize, sizeMax),
+                           requestSize, sizeMax);
+            }
+            // N.B. this is eventually closed in MultipartStream processing
+            input = new LimitedInputStream(ctx.getInputStream(), sizeMax) {
+                @Override
+                protected void raiseError(final long pSizeMax, final long pCount)
+                        throws IOException {
+                    final FileUploadException ex = new SizeLimitExceededException(
+                    format("the request was rejected because its size (%s) exceeds the configured maximum (%s)",
+                            pCount, pSizeMax),
+                           pCount, pSizeMax);
+                    throw new FileUploadIOException(ex);
+                }
+            };
+        } else {
+            input = ctx.getInputStream();
+        }
+
+        String charEncoding = fileUploadBase.getHeaderEncoding();
+        if (charEncoding == null) {
+            charEncoding = ctx.getCharacterEncoding();
+        }
+
+        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");
+        }
+
+        progressNotifier = new MultipartStream.ProgressNotifier(fileUploadBase.getProgressListener(), requestSize);
+        try {
+            multiPartStream = new MultipartStream(input, multiPartBoundary, progressNotifier);
+        } catch (final IllegalArgumentException iae) {
+            IOUtils.closeQuietly(input); // avoid possible resource leak
+            throw new InvalidContentTypeException(
+                    format("The boundary specified in the %s header is too long", FileUploadBase.CONTENT_TYPE), iae);
+        }
+        multiPartStream.setHeaderEncoding(charEncoding);
+    }
+
     /**
      * Returns the next available {@link FileItemStream}.
      *
@@ -346,15 +348,13 @@ public class FileItemIteratorImpl implements FileItemIterator {
     }
 
     @Override
-    public List<FileItem> getFileItems() throws FileUploadException, IOException {
-        final List<FileItem> items = new ArrayList<>();
-        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;
+    public void setFileSizeMax(final long fileSizeMax) {
+        this.fileSizeMax = fileSizeMax;
+    }
+
+    @Override
+    public void setSizeMax(final long sizeMax) {
+        this.sizeMax = sizeMax;
     }
 
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java b/src/main/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java
index 6bae29a..ca23a5b 100644
--- a/src/main/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java
+++ b/src/main/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java
@@ -130,6 +130,15 @@ public class FileItemStreamImpl implements FileItemStream {
         stream = istream;
     }
 
+    /**
+     * Closes the file item.
+     *
+     * @throws IOException An I/O error occurred.
+     */
+    public void close() throws IOException {
+        stream.close();
+    }
+
     /**
      * Returns the items content type, or null.
      *
@@ -150,6 +159,16 @@ public class FileItemStreamImpl implements FileItemStream {
         return fieldName;
     }
 
+    /**
+     * Returns the file item headers.
+     *
+     * @return The items header object
+     */
+    @Override
+    public FileItemHeaders getHeaders() {
+        return headers;
+    }
+
     /**
      * Returns the items file name.
      *
@@ -190,25 +209,6 @@ public class FileItemStreamImpl implements FileItemStream {
         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.
      *
diff --git a/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileCleaner.java b/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileCleaner.java
index 3686bd1..d483f4d 100644
--- a/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileCleaner.java
+++ b/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileCleaner.java
@@ -63,27 +63,27 @@ public class JakSrvltFileCleaner implements ServletContextListener {
     }
 
     /**
-     * Called when the web application is initialized. Does
-     * nothing.
+     * Called when the web application is being destroyed.
+     * Calls {@link FileCleaningTracker#exitWhenFinished()}.
      *
      * @param sce The servlet context, used for calling
-     *   {@link #setFileCleaningTracker(ServletContext, FileCleaningTracker)}.
+     *     {@link #getFileCleaningTracker(ServletContext)}.
      */
     @Override
-    public void contextInitialized(final ServletContextEvent sce) {
-        setFileCleaningTracker(sce.getServletContext(),
-                new FileCleaningTracker());
+    public void contextDestroyed(final ServletContextEvent sce) {
+        getFileCleaningTracker(sce.getServletContext()).exitWhenFinished();
     }
 
     /**
-     * Called when the web application is being destroyed.
-     * Calls {@link FileCleaningTracker#exitWhenFinished()}.
+     * Called when the web application is initialized. Does
+     * nothing.
      *
      * @param sce The servlet context, used for calling
-     *     {@link #getFileCleaningTracker(ServletContext)}.
+     *   {@link #setFileCleaningTracker(ServletContext, FileCleaningTracker)}.
      */
     @Override
-    public void contextDestroyed(final ServletContextEvent sce) {
-        getFileCleaningTracker(sce.getServletContext()).exitWhenFinished();
+    public void contextInitialized(final ServletContextEvent sce) {
+        setFileCleaningTracker(sce.getServletContext(),
+                new FileCleaningTracker());
     }
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUpload.java b/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUpload.java
index 8f57753..48689c5 100644
--- a/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUpload.java
+++ b/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUpload.java
@@ -100,14 +100,19 @@ public class JakSrvltFileUpload extends FileUpload {
      *
      * @param request The servlet request to be parsed.
      *
-     * @return A list of {@code FileItem} instances parsed from the
-     *         request, in the order that they were transmitted.
+     * @return An iterator to instances of {@code FileItemStream}
+     *         parsed from the request, in the order that they were
+     *         transmitted.
      *
      * @throws FileUploadException if there are problems reading/parsing
      *                             the request or storing files.
+     * @throws IOException An I/O error occurred. This may be a network
+     *   error while communicating with the client or a problem while
+     *   storing the uploaded content.
      */
-    public List<FileItem> parseRequest(final HttpServletRequest request) throws FileUploadException {
-        return parseRequest(new JakSrvltRequestContext(request));
+    public FileItemIterator getItemIterator(final HttpServletRequest request)
+    throws FileUploadException, IOException {
+        return super.getItemIterator(new JakSrvltRequestContext(request));
     }
 
     /**
@@ -134,19 +139,14 @@ public class JakSrvltFileUpload extends FileUpload {
      *
      * @param request The servlet request to be parsed.
      *
-     * @return An iterator to instances of {@code FileItemStream}
-     *         parsed from the request, in the order that they were
-     *         transmitted.
+     * @return A list of {@code FileItem} instances parsed from the
+     *         request, in the order that they were transmitted.
      *
      * @throws FileUploadException if there are problems reading/parsing
      *                             the request or storing files.
-     * @throws IOException An I/O error occurred. This may be a network
-     *   error while communicating with the client or a problem while
-     *   storing the uploaded content.
      */
-    public FileItemIterator getItemIterator(final HttpServletRequest request)
-    throws FileUploadException, IOException {
-        return super.getItemIterator(new JakSrvltRequestContext(request));
+    public List<FileItem> parseRequest(final HttpServletRequest request) throws FileUploadException {
+        return parseRequest(new JakSrvltRequestContext(request));
     }
 
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java b/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java
index dd19043..b0ad720 100644
--- a/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java
+++ b/src/main/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java
@@ -55,23 +55,30 @@ public class JakSrvltRequestContext implements UploadContext {
     // --------------------------------------------------------- Public Methods
 
     /**
-     * Retrieve the character encoding for the request.
+     * Retrieve the content length of the request.
      *
-     * @return The character encoding for the request.
+     * @return The content length of the request.
+     * @since 1.3
      */
     @Override
-    public String getCharacterEncoding() {
-        return request.getCharacterEncoding();
+    public long contentLength() {
+        long size;
+        try {
+            size = Long.parseLong(request.getHeader(FileUploadBase.CONTENT_LENGTH));
+        } catch (final NumberFormatException e) {
+            size = request.getContentLength();
+        }
+        return size;
     }
 
     /**
-     * Retrieve the content type of the request.
+     * Retrieve the character encoding for the request.
      *
-     * @return The content type of the request.
+     * @return The character encoding for the request.
      */
     @Override
-    public String getContentType() {
-        return request.getContentType();
+    public String getCharacterEncoding() {
+        return request.getCharacterEncoding();
     }
 
     /**
@@ -87,20 +94,13 @@ public class JakSrvltRequestContext implements UploadContext {
     }
 
     /**
-     * Retrieve the content length of the request.
+     * Retrieve the content type of the request.
      *
-     * @return The content length of the request.
-     * @since 1.3
+     * @return The content type of the request.
      */
     @Override
-    public long contentLength() {
-        long size;
-        try {
-            size = Long.parseLong(request.getHeader(FileUploadBase.CONTENT_LENGTH));
-        } catch (final NumberFormatException e) {
-            size = request.getContentLength();
-        }
-        return size;
+    public String getContentType() {
+        return request.getContentType();
     }
 
     /**
diff --git a/src/main/java/org/apache/commons/fileupload2/portlet/PortletFileUpload.java b/src/main/java/org/apache/commons/fileupload2/portlet/PortletFileUpload.java
index 7bfcd0c..c356334 100644
--- a/src/main/java/org/apache/commons/fileupload2/portlet/PortletFileUpload.java
+++ b/src/main/java/org/apache/commons/fileupload2/portlet/PortletFileUpload.java
@@ -95,15 +95,19 @@ public class PortletFileUpload extends FileUpload {
      *
      * @param request The portlet request to be parsed.
      *
-     * @return A list of {@code FileItem} instances parsed from the
-     *         request, in the order that they were transmitted.
+     * @return An iterator to instances of {@code FileItemStream}
+     *         parsed from the request, in the order that they were
+     *         transmitted.
      *
      * @throws FileUploadException if there are problems reading/parsing
      *                             the request or storing files.
+     * @throws IOException An I/O error occurred. This may be a network
+     *   error while communicating with the client or a problem while
+     *   storing the uploaded content.
      */
-    public List<FileItem> parseRequest(final ActionRequest request)
-            throws FileUploadException {
-        return parseRequest(new PortletRequestContext(request));
+    public FileItemIterator getItemIterator(final ActionRequest request)
+            throws FileUploadException, IOException {
+        return super.getItemIterator(new PortletRequestContext(request));
     }
 
     /**
@@ -130,19 +134,15 @@ public class PortletFileUpload extends FileUpload {
      *
      * @param request The portlet request to be parsed.
      *
-     * @return An iterator to instances of {@code FileItemStream}
-     *         parsed from the request, in the order that they were
-     *         transmitted.
+     * @return A list of {@code FileItem} instances parsed from the
+     *         request, in the order that they were transmitted.
      *
      * @throws FileUploadException if there are problems reading/parsing
      *                             the request or storing files.
-     * @throws IOException An I/O error occurred. This may be a network
-     *   error while communicating with the client or a problem while
-     *   storing the uploaded content.
      */
-    public FileItemIterator getItemIterator(final ActionRequest request)
-            throws FileUploadException, IOException {
-        return super.getItemIterator(new PortletRequestContext(request));
+    public List<FileItem> parseRequest(final ActionRequest request)
+            throws FileUploadException {
+        return parseRequest(new PortletRequestContext(request));
     }
 
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/portlet/PortletRequestContext.java b/src/main/java/org/apache/commons/fileupload2/portlet/PortletRequestContext.java
index 4e6887c..796dfc5 100644
--- a/src/main/java/org/apache/commons/fileupload2/portlet/PortletRequestContext.java
+++ b/src/main/java/org/apache/commons/fileupload2/portlet/PortletRequestContext.java
@@ -57,23 +57,30 @@ public class PortletRequestContext implements UploadContext {
     // --------------------------------------------------------- Public Methods
 
     /**
-     * Retrieve the character encoding for the request.
+     * Retrieve the content length of the request.
      *
-     * @return The character encoding for the request.
+     * @return The content length of the request.
+     * @since 1.3
      */
     @Override
-    public String getCharacterEncoding() {
-        return request.getCharacterEncoding();
+    public long contentLength() {
+        long size;
+        try {
+            size = Long.parseLong(request.getProperty(FileUploadBase.CONTENT_LENGTH));
+        } catch (final NumberFormatException e) {
+            size = request.getContentLength();
+        }
+        return size;
     }
 
     /**
-     * Retrieve the content type of the request.
+     * Retrieve the character encoding for the request.
      *
-     * @return The content type of the request.
+     * @return The character encoding for the request.
      */
     @Override
-    public String getContentType() {
-        return request.getContentType();
+    public String getCharacterEncoding() {
+        return request.getCharacterEncoding();
     }
 
     /**
@@ -89,20 +96,13 @@ public class PortletRequestContext implements UploadContext {
     }
 
     /**
-     * Retrieve the content length of the request.
+     * Retrieve the content type of the request.
      *
-     * @return The content length of the request.
-     * @since 1.3
+     * @return The content type of the request.
      */
     @Override
-    public long contentLength() {
-        long size;
-        try {
-            size = Long.parseLong(request.getProperty(FileUploadBase.CONTENT_LENGTH));
-        } catch (final NumberFormatException e) {
-            size = request.getContentLength();
-        }
-        return size;
+    public String getContentType() {
+        return request.getContentType();
     }
 
     /**
diff --git a/src/main/java/org/apache/commons/fileupload2/pub/FileSizeLimitExceededException.java b/src/main/java/org/apache/commons/fileupload2/pub/FileSizeLimitExceededException.java
index bb45be0..d459532 100644
--- a/src/main/java/org/apache/commons/fileupload2/pub/FileSizeLimitExceededException.java
+++ b/src/main/java/org/apache/commons/fileupload2/pub/FileSizeLimitExceededException.java
@@ -51,44 +51,44 @@ public class FileSizeLimitExceededException
     }
 
     /**
-     * Returns the file name of the item, which caused the
+     * Returns the field name of the item, which caused the
      * exception.
      *
-     * @return File name, if known, or null.
+     * @return Field name, if known, or null.
      */
-    public String getFileName() {
-        return fileName;
+    public String getFieldName() {
+        return fieldName;
     }
 
     /**
-     * Sets the file name of the item, which caused the
+     * Returns the file name of the item, which caused the
      * exception.
      *
-     * @param pFileName the file name of the item, which caused the exception.
+     * @return File name, if known, or null.
      */
-    public void setFileName(final String pFileName) {
-        fileName = pFileName;
+    public String getFileName() {
+        return fileName;
     }
 
     /**
-     * Returns the field name of the item, which caused the
+     * Sets the field name of the item, which caused the
      * exception.
      *
-     * @return Field name, if known, or null.
+     * @param pFieldName the field name of the item,
+     *        which caused the exception.
      */
-    public String getFieldName() {
-        return fieldName;
+    public void setFieldName(final String pFieldName) {
+        fieldName = pFieldName;
     }
 
     /**
-     * Sets the field name of the item, which caused the
+     * Sets the file name of the item, which caused the
      * exception.
      *
-     * @param pFieldName the field name of the item,
-     *        which caused the exception.
+     * @param pFileName the file name of the item, which caused the exception.
      */
-    public void setFieldName(final String pFieldName) {
-        fieldName = pFieldName;
+    public void setFileName(final String pFileName) {
+        fileName = pFileName;
     }
 
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/servlet/FileCleanerCleanup.java b/src/main/java/org/apache/commons/fileupload2/servlet/FileCleanerCleanup.java
index e5ee1b0..3854226 100644
--- a/src/main/java/org/apache/commons/fileupload2/servlet/FileCleanerCleanup.java
+++ b/src/main/java/org/apache/commons/fileupload2/servlet/FileCleanerCleanup.java
@@ -62,28 +62,28 @@ public class FileCleanerCleanup implements ServletContextListener {
     }
 
     /**
-     * Called when the web application is initialized. Does
-     * nothing.
+     * Called when the web application is being destroyed.
+     * Calls {@link FileCleaningTracker#exitWhenFinished()}.
      *
      * @param sce The servlet context, used for calling
-     *   {@link #setFileCleaningTracker(ServletContext, FileCleaningTracker)}.
+     *     {@link #getFileCleaningTracker(ServletContext)}.
      */
     @Override
-    public void contextInitialized(final ServletContextEvent sce) {
-        setFileCleaningTracker(sce.getServletContext(),
-                new FileCleaningTracker());
+    public void contextDestroyed(final ServletContextEvent sce) {
+        getFileCleaningTracker(sce.getServletContext()).exitWhenFinished();
     }
 
     /**
-     * Called when the web application is being destroyed.
-     * Calls {@link FileCleaningTracker#exitWhenFinished()}.
+     * Called when the web application is initialized. Does
+     * nothing.
      *
      * @param sce The servlet context, used for calling
-     *     {@link #getFileCleaningTracker(ServletContext)}.
+     *   {@link #setFileCleaningTracker(ServletContext, FileCleaningTracker)}.
      */
     @Override
-    public void contextDestroyed(final ServletContextEvent sce) {
-        getFileCleaningTracker(sce.getServletContext()).exitWhenFinished();
+    public void contextInitialized(final ServletContextEvent sce) {
+        setFileCleaningTracker(sce.getServletContext(),
+                new FileCleaningTracker());
     }
 
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/servlet/ServletFileUpload.java b/src/main/java/org/apache/commons/fileupload2/servlet/ServletFileUpload.java
index 3831ad8..24e03dd 100644
--- a/src/main/java/org/apache/commons/fileupload2/servlet/ServletFileUpload.java
+++ b/src/main/java/org/apache/commons/fileupload2/servlet/ServletFileUpload.java
@@ -100,15 +100,19 @@ public class ServletFileUpload extends FileUpload {
      *
      * @param request The servlet request to be parsed.
      *
-     * @return A list of {@code FileItem} instances parsed from the
-     *         request, in the order that they were transmitted.
+     * @return An iterator to instances of {@code FileItemStream}
+     *         parsed from the request, in the order that they were
+     *         transmitted.
      *
      * @throws FileUploadException if there are problems reading/parsing
      *                             the request or storing files.
+     * @throws IOException An I/O error occurred. This may be a network
+     *   error while communicating with the client or a problem while
+     *   storing the uploaded content.
      */
-    public List<FileItem> parseRequest(final HttpServletRequest request)
-    throws FileUploadException {
-        return parseRequest(new ServletRequestContext(request));
+    public FileItemIterator getItemIterator(final HttpServletRequest request)
+    throws FileUploadException, IOException {
+        return super.getItemIterator(new ServletRequestContext(request));
     }
 
     /**
@@ -135,19 +139,15 @@ public class ServletFileUpload extends FileUpload {
      *
      * @param request The servlet request to be parsed.
      *
-     * @return An iterator to instances of {@code FileItemStream}
-     *         parsed from the request, in the order that they were
-     *         transmitted.
+     * @return A list of {@code FileItem} instances parsed from the
+     *         request, in the order that they were transmitted.
      *
      * @throws FileUploadException if there are problems reading/parsing
      *                             the request or storing files.
-     * @throws IOException An I/O error occurred. This may be a network
-     *   error while communicating with the client or a problem while
-     *   storing the uploaded content.
      */
-    public FileItemIterator getItemIterator(final HttpServletRequest request)
-    throws FileUploadException, IOException {
-        return super.getItemIterator(new ServletRequestContext(request));
+    public List<FileItem> parseRequest(final HttpServletRequest request)
+    throws FileUploadException {
+        return parseRequest(new ServletRequestContext(request));
     }
 
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/servlet/ServletRequestContext.java b/src/main/java/org/apache/commons/fileupload2/servlet/ServletRequestContext.java
index 5a0010f..6919f49 100644
--- a/src/main/java/org/apache/commons/fileupload2/servlet/ServletRequestContext.java
+++ b/src/main/java/org/apache/commons/fileupload2/servlet/ServletRequestContext.java
@@ -55,23 +55,30 @@ public class ServletRequestContext implements UploadContext {
     // --------------------------------------------------------- Public Methods
 
     /**
-     * Retrieve the character encoding for the request.
+     * Retrieve the content length of the request.
      *
-     * @return The character encoding for the request.
+     * @return The content length of the request.
+     * @since 1.3
      */
     @Override
-    public String getCharacterEncoding() {
-        return request.getCharacterEncoding();
+    public long contentLength() {
+        long size;
+        try {
+            size = Long.parseLong(request.getHeader(FileUploadBase.CONTENT_LENGTH));
+        } catch (final NumberFormatException e) {
+            size = request.getContentLength();
+        }
+        return size;
     }
 
     /**
-     * Retrieve the content type of the request.
+     * Retrieve the character encoding for the request.
      *
-     * @return The content type of the request.
+     * @return The character encoding for the request.
      */
     @Override
-    public String getContentType() {
-        return request.getContentType();
+    public String getCharacterEncoding() {
+        return request.getCharacterEncoding();
     }
 
     /**
@@ -87,20 +94,13 @@ public class ServletRequestContext implements UploadContext {
     }
 
     /**
-     * Retrieve the content length of the request.
+     * Retrieve the content type of the request.
      *
-     * @return The content length of the request.
-     * @since 1.3
+     * @return The content type of the request.
      */
     @Override
-    public long contentLength() {
-        long size;
-        try {
-            size = Long.parseLong(request.getHeader(FileUploadBase.CONTENT_LENGTH));
-        } catch (final NumberFormatException e) {
-            size = request.getContentLength();
-        }
-        return size;
+    public String getContentType() {
+        return request.getContentType();
     }
 
     /**
diff --git a/src/main/java/org/apache/commons/fileupload2/util/FileItemHeadersImpl.java b/src/main/java/org/apache/commons/fileupload2/util/FileItemHeadersImpl.java
index e68a89e..45909d2 100644
--- a/src/main/java/org/apache/commons/fileupload2/util/FileItemHeadersImpl.java
+++ b/src/main/java/org/apache/commons/fileupload2/util/FileItemHeadersImpl.java
@@ -45,6 +45,19 @@ public class FileItemHeadersImpl implements FileItemHeaders, Serializable {
      */
     private final Map<String, List<String>> headerNameToValueListMap = new LinkedHashMap<>();
 
+    /**
+     * Method to add header values to this instance.
+     *
+     * @param name name of this header
+     * @param value value of this header
+     */
+    public synchronized void addHeader(final String name, final String value) {
+        final String nameLower = name.toLowerCase(Locale.ENGLISH);
+        final List<String> headerValueList = headerNameToValueListMap.
+                computeIfAbsent(nameLower, k -> new ArrayList<>());
+        headerValueList.add(value);
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -79,17 +92,4 @@ public class FileItemHeadersImpl implements FileItemHeaders, Serializable {
         return headerValueList.iterator();
     }
 
-    /**
-     * Method to add header values to this instance.
-     *
-     * @param name name of this header
-     * @param value value of this header
-     */
-    public synchronized void addHeader(final String name, final String value) {
-        final String nameLower = name.toLowerCase(Locale.ENGLISH);
-        final List<String> headerValueList = headerNameToValueListMap.
-                computeIfAbsent(nameLower, k -> new ArrayList<>());
-        headerValueList.add(value);
-    }
-
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/util/LimitedInputStream.java b/src/main/java/org/apache/commons/fileupload2/util/LimitedInputStream.java
index a5cffca..13ed38e 100644
--- a/src/main/java/org/apache/commons/fileupload2/util/LimitedInputStream.java
+++ b/src/main/java/org/apache/commons/fileupload2/util/LimitedInputStream.java
@@ -53,18 +53,6 @@ public abstract class LimitedInputStream extends FilterInputStream implements Cl
         sizeMax = pSizeMax;
     }
 
-    /**
-     * Called to indicate, that the input streams limit has
-     * been exceeded.
-     *
-     * @param pSizeMax The input streams limit, in bytes.
-     * @param pCount The actual number of bytes.
-     * @throws IOException The called method is expected
-     *   to raise an IOException.
-     */
-    protected abstract void raiseError(long pSizeMax, long pCount)
-            throws IOException;
-
     /**
      * Called to check, whether the input streams
      * limit is reached.
@@ -77,6 +65,44 @@ public abstract class LimitedInputStream extends FilterInputStream implements Cl
         }
     }
 
+    /**
+     * Closes this input stream and releases any system resources
+     * associated with the stream.
+     * This
+     * method simply performs {@code in.close()}.
+     *
+     * @throws  IOException  if an I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    @Override
+    public void close() throws IOException {
+        closed = true;
+        super.close();
+    }
+
+    /**
+     * Returns, whether this stream is already closed.
+     *
+     * @return True, if the stream is closed, otherwise false.
+     * @throws IOException An I/O error occurred.
+     */
+    @Override
+    public boolean isClosed() throws IOException {
+        return closed;
+    }
+
+    /**
+     * Called to indicate, that the input streams limit has
+     * been exceeded.
+     *
+     * @param pSizeMax The input streams limit, in bytes.
+     * @param pCount The actual number of bytes.
+     * @throws IOException The called method is expected
+     *   to raise an IOException.
+     */
+    protected abstract void raiseError(long pSizeMax, long pCount)
+            throws IOException;
+
     /**
      * Reads the next byte of data from this input stream. The value
      * byte is returned as an {@code int} in the range
@@ -137,30 +163,4 @@ public abstract class LimitedInputStream extends FilterInputStream implements Cl
         return res;
     }
 
-    /**
-     * Returns, whether this stream is already closed.
-     *
-     * @return True, if the stream is closed, otherwise false.
-     * @throws IOException An I/O error occurred.
-     */
-    @Override
-    public boolean isClosed() throws IOException {
-        return closed;
-    }
-
-    /**
-     * Closes this input stream and releases any system resources
-     * associated with the stream.
-     * This
-     * method simply performs {@code in.close()}.
-     *
-     * @throws  IOException  if an I/O error occurs.
-     * @see        java.io.FilterInputStream#in
-     */
-    @Override
-    public void close() throws IOException {
-        closed = true;
-        super.close();
-    }
-
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/util/Streams.java b/src/main/java/org/apache/commons/fileupload2/util/Streams.java
index 2aa1302..e2c925e 100644
--- a/src/main/java/org/apache/commons/fileupload2/util/Streams.java
+++ b/src/main/java/org/apache/commons/fileupload2/util/Streams.java
@@ -29,18 +29,76 @@ import org.apache.commons.fileupload2.InvalidFileNameException;
 public final class Streams {
 
     /**
-     * Private constructor, to prevent instantiation.
-     * This class has only static methods.
+     * Default buffer size for use in
+     * {@link #copy(InputStream, OutputStream, boolean)}.
      */
-    private Streams() {
-        // Does nothing
+    public static final int DEFAULT_BUFFER_SIZE = 8192;
+
+    /**
+     * This convenience method allows to read a
+     * {@link org.apache.commons.fileupload2.FileItemStream}'s
+     * content into a string. The platform's default character encoding
+     * is used for converting bytes into characters.
+     *
+     * @param inputStream The input stream to read.
+     * @see #asString(InputStream, String)
+     * @return The streams contents, as a string.
+     * @throws IOException An I/O error occurred.
+     */
+    public static String asString(final InputStream inputStream) throws IOException {
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        copy(inputStream, baos, true);
+        return baos.toString();
     }
 
     /**
-     * Default buffer size for use in
-     * {@link #copy(InputStream, OutputStream, boolean)}.
+     * This convenience method allows to read a
+     * {@link org.apache.commons.fileupload2.FileItemStream}'s
+     * content into a string, using the given character encoding.
+     *
+     * @param inputStream The input stream to read.
+     * @param encoding The character encoding, typically "UTF-8".
+     * @see #asString(InputStream)
+     * @return The streams contents, as a string.
+     * @throws IOException An I/O error occurred.
      */
-    public static final int DEFAULT_BUFFER_SIZE = 8192;
+    public static String asString(final InputStream inputStream, final String encoding)
+            throws IOException {
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        copy(inputStream, baos, true);
+        return baos.toString(encoding);
+    }
+
+    /**
+     * Checks, whether the given file name is valid in the sense,
+     * that it doesn't contain any NUL characters. If the file name
+     * is valid, it will be returned without any modifications. Otherwise,
+     * an {@link InvalidFileNameException} is raised.
+     *
+     * @param fileName The file name to check
+     * @return Unmodified file name, if valid.
+     * @throws InvalidFileNameException The file name was found to be invalid.
+     */
+    public static String checkFileName(final String fileName) {
+        if (fileName != null  &&  fileName.indexOf('\u0000') != -1) {
+            // pFileName.replace("\u0000", "\\0")
+            final StringBuilder sb = new StringBuilder();
+            for (int i = 0;  i < fileName.length();  i++) {
+                final char c = fileName.charAt(i);
+                switch (c) {
+                    case 0:
+                        sb.append("\\0");
+                        break;
+                    default:
+                        sb.append(c);
+                        break;
+                }
+            }
+            throw new InvalidFileNameException(fileName,
+                    "Invalid file name: " + sb);
+        }
+        return fileName;
+    }
 
     /**
      * Copies the contents of the given {@link InputStream}
@@ -118,69 +176,11 @@ public final class Streams {
     }
 
     /**
-     * This convenience method allows to read a
-     * {@link org.apache.commons.fileupload2.FileItemStream}'s
-     * content into a string. The platform's default character encoding
-     * is used for converting bytes into characters.
-     *
-     * @param inputStream The input stream to read.
-     * @see #asString(InputStream, String)
-     * @return The streams contents, as a string.
-     * @throws IOException An I/O error occurred.
-     */
-    public static String asString(final InputStream inputStream) throws IOException {
-        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        copy(inputStream, baos, true);
-        return baos.toString();
-    }
-
-    /**
-     * This convenience method allows to read a
-     * {@link org.apache.commons.fileupload2.FileItemStream}'s
-     * content into a string, using the given character encoding.
-     *
-     * @param inputStream The input stream to read.
-     * @param encoding The character encoding, typically "UTF-8".
-     * @see #asString(InputStream)
-     * @return The streams contents, as a string.
-     * @throws IOException An I/O error occurred.
-     */
-    public static String asString(final InputStream inputStream, final String encoding)
-            throws IOException {
-        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        copy(inputStream, baos, true);
-        return baos.toString(encoding);
-    }
-
-    /**
-     * Checks, whether the given file name is valid in the sense,
-     * that it doesn't contain any NUL characters. If the file name
-     * is valid, it will be returned without any modifications. Otherwise,
-     * an {@link InvalidFileNameException} is raised.
-     *
-     * @param fileName The file name to check
-     * @return Unmodified file name, if valid.
-     * @throws InvalidFileNameException The file name was found to be invalid.
+     * Private constructor, to prevent instantiation.
+     * This class has only static methods.
      */
-    public static String checkFileName(final String fileName) {
-        if (fileName != null  &&  fileName.indexOf('\u0000') != -1) {
-            // pFileName.replace("\u0000", "\\0")
-            final StringBuilder sb = new StringBuilder();
-            for (int i = 0;  i < fileName.length();  i++) {
-                final char c = fileName.charAt(i);
-                switch (c) {
-                    case 0:
-                        sb.append("\\0");
-                        break;
-                    default:
-                        sb.append(c);
-                        break;
-                }
-            }
-            throw new InvalidFileNameException(fileName,
-                    "Invalid file name: " + sb);
-        }
-        return fileName;
+    private Streams() {
+        // Does nothing
     }
 
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/util/mime/Base64Decoder.java b/src/main/java/org/apache/commons/fileupload2/util/mime/Base64Decoder.java
index 9b32d2d..5222e8f 100644
--- a/src/main/java/org/apache/commons/fileupload2/util/mime/Base64Decoder.java
+++ b/src/main/java/org/apache/commons/fileupload2/util/mime/Base64Decoder.java
@@ -85,13 +85,6 @@ final class Base64Decoder {
         DECODING_TABLE[PADDING] = PAD_BYTE;
     }
 
-    /**
-     * Hidden constructor, this class must not be instantiated.
-     */
-    private Base64Decoder() {
-        // do nothing
-    }
-
     /**
      * Decode the base 64 encoded byte data writing it to the given output stream,
      * whitespace characters will be ignored.
@@ -148,4 +141,11 @@ final class Base64Decoder {
         }
         return outLen;
     }
+
+    /**
+     * Hidden constructor, this class must not be instantiated.
+     */
+    private Base64Decoder() {
+        // do nothing
+    }
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/util/mime/MimeUtility.java b/src/main/java/org/apache/commons/fileupload2/util/mime/MimeUtility.java
index 57a3319..9f56fec 100644
--- a/src/main/java/org/apache/commons/fileupload2/util/mime/MimeUtility.java
+++ b/src/main/java/org/apache/commons/fileupload2/util/mime/MimeUtility.java
@@ -74,13 +74,6 @@ public final class MimeUtility {
         MIME2JAVA.put("x-us-ascii", "ISO-8859-1");
     }
 
-    /**
-     * Hidden constructor, this class must not be instantiated.
-     */
-    private MimeUtility() {
-        // do nothing
-    }
-
     /**
      * Decode a string of text obtained from a mail header into
      * its proper form.  The text generally will consist of a
@@ -274,4 +267,11 @@ public final class MimeUtility {
         return mappedCharset;
     }
 
+    /**
+     * Hidden constructor, this class must not be instantiated.
+     */
+    private MimeUtility() {
+        // do nothing
+    }
+
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoder.java b/src/main/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoder.java
index 34af14d..9d91b76 100644
--- a/src/main/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoder.java
+++ b/src/main/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoder.java
@@ -30,13 +30,6 @@ final class QuotedPrintableDecoder {
      */
     private static final int UPPER_NIBBLE_SHIFT = Byte.SIZE / 2;
 
-    /**
-     * Hidden constructor, this class must not be instantiated.
-     */
-    private QuotedPrintableDecoder() {
-        // do nothing
-    }
-
     /**
      * Decode the encoded byte data writing it to the given output stream.
      *
@@ -109,4 +102,11 @@ final class QuotedPrintableDecoder {
         return i;
     }
 
+    /**
+     * Hidden constructor, this class must not be instantiated.
+     */
+    private QuotedPrintableDecoder() {
+        // do nothing
+    }
+
 }
diff --git a/src/main/java/org/apache/commons/fileupload2/util/mime/RFC2231Utility.java b/src/main/java/org/apache/commons/fileupload2/util/mime/RFC2231Utility.java
index 25704b2..49b6a8a 100644
--- a/src/main/java/org/apache/commons/fileupload2/util/mime/RFC2231Utility.java
+++ b/src/main/java/org/apache/commons/fileupload2/util/mime/RFC2231Utility.java
@@ -56,41 +56,6 @@ public final class RFC2231Utility {
         }
     }
 
-    /**
-     * Private constructor so that no instances can be created. This class
-     * contains only static utility methods.
-     */
-    private RFC2231Utility() {
-    }
-
-    /**
-     * Checks if Asterisk (*) at the end of parameter name to indicate,
-     * if it has charset and language information to decode the value.
-     * @param paramName The parameter, which is being checked.
-     * @return {@code true}, if encoded as per RFC 2231, {@code false} otherwise
-     */
-    public static boolean hasEncodedValue(final String paramName) {
-        if (paramName != null) {
-            return paramName.lastIndexOf('*') == (paramName.length() - 1);
-        }
-        return false;
-    }
-
-    /**
-     * If {@code paramName} has Asterisk (*) at the end, it will be stripped off,
-     * else the passed value will be returned.
-     * @param paramName The parameter, which is being inspected.
-     * @return stripped {@code paramName} of Asterisk (*), if RFC2231 encoded
-     */
-    public static String stripDelimiter(final String paramName) {
-        if (hasEncodedValue(paramName)) {
-            final StringBuilder paramBuilder = new StringBuilder(paramName);
-            paramBuilder.deleteCharAt(paramName.lastIndexOf('*'));
-            return paramBuilder.toString();
-        }
-        return paramName;
-    }
-
     /**
      * Decode a string of text obtained from a HTTP header as per RFC 2231
      *
@@ -152,4 +117,39 @@ public final class RFC2231Utility {
         // good enough for standard values
         return mimeCharset;
     }
+
+    /**
+     * Checks if Asterisk (*) at the end of parameter name to indicate,
+     * if it has charset and language information to decode the value.
+     * @param paramName The parameter, which is being checked.
+     * @return {@code true}, if encoded as per RFC 2231, {@code false} otherwise
+     */
+    public static boolean hasEncodedValue(final String paramName) {
+        if (paramName != null) {
+            return paramName.lastIndexOf('*') == (paramName.length() - 1);
+        }
+        return false;
+    }
+
+    /**
+     * If {@code paramName} has Asterisk (*) at the end, it will be stripped off,
+     * else the passed value will be returned.
+     * @param paramName The parameter, which is being inspected.
+     * @return stripped {@code paramName} of Asterisk (*), if RFC2231 encoded
+     */
+    public static String stripDelimiter(final String paramName) {
+        if (hasEncodedValue(paramName)) {
+            final StringBuilder paramBuilder = new StringBuilder(paramName);
+            paramBuilder.deleteCharAt(paramName.lastIndexOf('*'));
+            return paramBuilder.toString();
+        }
+        return paramName;
+    }
+
+    /**
+     * Private constructor so that no instances can be created. This class
+     * contains only static utility methods.
+     */
+    private RFC2231Utility() {
+    }
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/DiskFileItemSerializeTest.java b/src/test/java/org/apache/commons/fileupload2/DiskFileItemSerializeTest.java
index 2166979..e04c7ec 100644
--- a/src/test/java/org/apache/commons/fileupload2/DiskFileItemSerializeTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/DiskFileItemSerializeTest.java
@@ -47,22 +47,6 @@ public class DiskFileItemSerializeTest {
     // Use a private repo to catch any files left over by tests
     private static final File REPO = new File(System.getProperty("java.io.tmpdir"), "diskfileitemrepo");
 
-    @BeforeEach
-    public void setUp() throws Exception {
-        if (REPO.exists()) {
-            FileUtils.deleteDirectory(REPO);
-        }
-        FileUtils.forceMkdir(REPO);
-    }
-
-    @AfterEach
-    public void tearDown() throws IOException {
-        for(final File file : FileUtils.listFiles(REPO, null, true)) {
-            System.out.println("Found leftover file " + file);
-        }
-        FileUtils.deleteDirectory(REPO);
-    }
-
     /**
      * Content type for regular form items.
      */
@@ -74,65 +58,104 @@ public class DiskFileItemSerializeTest {
     private static final int THRESHOLD = 16;
 
     /**
-     * Helper method to test creation of a field when a repository is used.
+     * Compare content bytes.
      */
-    public void testInMemoryObject(final byte[] testFieldValueBytes, final File repository) {
-        final FileItem item = createFileItem(testFieldValueBytes, repository);
-
-        // Check state is as expected
-        assertTrue(item.isInMemory(), "Initial: in memory");
-        assertEquals(item.getSize(), testFieldValueBytes.length, "Initial: size");
-        try {
-            compareBytes("Initial", item.get(), testFieldValueBytes);
-        } catch (UncheckedIOException e) {
-            fail("Unexpected IOException", e);
+    private void compareBytes(final String text, final byte[] origBytes, final byte[] newBytes) {
+        assertNotNull(origBytes, "origBytes must not be null");
+        assertNotNull(newBytes, "newBytes must not be null");
+        assertEquals(origBytes.length, newBytes.length, text + " byte[] length");
+        for (int i = 0; i < origBytes.length; i++) {
+            assertEquals(origBytes[i], newBytes[i], text + " byte[" + i + "]");
         }
-        testWritingToFile(item, testFieldValueBytes);
-        item.delete();
     }
 
     /**
-     * Helper method to test writing item contents to a file.
+     * Create content bytes of a specified size.
      */
-    public void testWritingToFile(final FileItem item, final byte[] testFieldValueBytes) {
-        try {
-            final File temp = File.createTempFile("fileupload", null);
-            // Note that the file exists and is initially empty;
-            // write() must be able to handle that.
-            item.write(temp);
-            compareBytes("Initial", FileUtils.readFileToByteArray(temp), testFieldValueBytes);
-        } catch (Exception e) {
-            fail("Unexpected Exception", e);
+    private byte[] createContentBytes(final int size) {
+        final StringBuilder buffer = new StringBuilder(size);
+        byte count = 0;
+        for (int i = 0; i < size; i++) {
+            buffer.append(count + "");
+            count++;
+            if (count > 9) {
+                count = 0;
+            }
         }
+        return buffer.toString().getBytes();
     }
 
     /**
-     * Helper method to test creation of a field.
+     * Create a FileItem with the specfied content bytes.
      */
-    private void testInMemoryObject(final byte[] testFieldValueBytes) {
-        testInMemoryObject(testFieldValueBytes, REPO);
+    private FileItem createFileItem(final byte[] contentBytes) {
+        return createFileItem(contentBytes, REPO);
     }
 
     /**
-     * Test creation of a field for which the amount of data falls below the
-     * configured threshold.
+     * Create a FileItem with the specfied content bytes and repository.
      */
-    @Test
-    public void testBelowThreshold() {
-        // Create the FileItem
-        final byte[] testFieldValueBytes = createContentBytes(THRESHOLD - 1);
-        testInMemoryObject(testFieldValueBytes);
+    private FileItem createFileItem(final byte[] contentBytes, final File repository) {
+        final FileItemFactory factory = new DiskFileItemFactory(THRESHOLD, repository);
+        final String textFieldName = "textField";
+
+        final FileItem item = factory.createItem(
+                textFieldName,
+                TEXT_CONTENT_TYPE,
+                true,
+                "My File Name"
+        );
+        try {
+            final OutputStream os = item.getOutputStream();
+            os.write(contentBytes);
+            os.close();
+        } catch (final IOException e) {
+            fail("Unexpected IOException" + e);
+        }
+
+        return item;
+
     }
 
     /**
-     * Test creation of a field for which the amount of data equals the
-     * configured threshold.
+     * Do deserialization
      */
-    @Test
-    public void testThreshold() {
-        // Create the FileItem
-        final byte[] testFieldValueBytes = createContentBytes(THRESHOLD);
-        testInMemoryObject(testFieldValueBytes);
+    private Object deserialize(final ByteArrayOutputStream baos) throws Exception {
+        final ByteArrayInputStream bais =
+                new ByteArrayInputStream(baos.toByteArray());
+        final ObjectInputStream ois = new ObjectInputStream(bais);
+        final Object result = ois.readObject();
+        bais.close();
+
+        return result;
+    }
+
+    /**
+     * Do serialization
+     */
+    private ByteArrayOutputStream serialize(final Object target) throws Exception {
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        final ObjectOutputStream oos = new ObjectOutputStream(baos);
+        oos.writeObject(target);
+        oos.flush();
+        oos.close();
+        return baos;
+    }
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        if (REPO.exists()) {
+            FileUtils.deleteDirectory(REPO);
+        }
+        FileUtils.forceMkdir(REPO);
+    }
+
+    @AfterEach
+    public void tearDown() throws IOException {
+        for(final File file : FileUtils.listFiles(REPO, null, true)) {
+            System.out.println("Found leftover file " + file);
+        }
+        FileUtils.deleteDirectory(REPO);
     }
 
     /**
@@ -159,15 +182,41 @@ public class DiskFileItemSerializeTest {
     }
 
     /**
-     * Test serialization and deserialization when repository is not null.
+     * Test creation of a field for which the amount of data falls below the
+     * configured threshold.
      */
     @Test
-    public void testValidRepository() {
+    public void testBelowThreshold() {
         // Create the FileItem
-        final byte[] testFieldValueBytes = createContentBytes(THRESHOLD);
+        final byte[] testFieldValueBytes = createContentBytes(THRESHOLD - 1);
+        testInMemoryObject(testFieldValueBytes);
+    }
+
+    /**
+     * Helper method to test creation of a field.
+     */
+    private void testInMemoryObject(final byte[] testFieldValueBytes) {
         testInMemoryObject(testFieldValueBytes, REPO);
     }
 
+    /**
+     * Helper method to test creation of a field when a repository is used.
+     */
+    public void testInMemoryObject(final byte[] testFieldValueBytes, final File repository) {
+        final FileItem item = createFileItem(testFieldValueBytes, repository);
+
+        // Check state is as expected
+        assertTrue(item.isInMemory(), "Initial: in memory");
+        assertEquals(item.getSize(), testFieldValueBytes.length, "Initial: size");
+        try {
+            compareBytes("Initial", item.get(), testFieldValueBytes);
+        } catch (UncheckedIOException e) {
+            fail("Unexpected IOException", e);
+        }
+        testWritingToFile(item, testFieldValueBytes);
+        item.delete();
+    }
+
     /**
      * Test deserialization fails when repository is not valid.
      */
@@ -193,87 +242,38 @@ public class DiskFileItemSerializeTest {
     }
 
     /**
-     * Compare content bytes.
+     * Test creation of a field for which the amount of data equals the
+     * configured threshold.
      */
-    private void compareBytes(final String text, final byte[] origBytes, final byte[] newBytes) {
-        assertNotNull(origBytes, "origBytes must not be null");
-        assertNotNull(newBytes, "newBytes must not be null");
-        assertEquals(origBytes.length, newBytes.length, text + " byte[] length");
-        for (int i = 0; i < origBytes.length; i++) {
-            assertEquals(origBytes[i], newBytes[i], text + " byte[" + i + "]");
-        }
+    @Test
+    public void testThreshold() {
+        // Create the FileItem
+        final byte[] testFieldValueBytes = createContentBytes(THRESHOLD);
+        testInMemoryObject(testFieldValueBytes);
     }
 
     /**
-     * Create content bytes of a specified size.
+     * Test serialization and deserialization when repository is not null.
      */
-    private byte[] createContentBytes(final int size) {
-        final StringBuilder buffer = new StringBuilder(size);
-        byte count = 0;
-        for (int i = 0; i < size; i++) {
-            buffer.append(count + "");
-            count++;
-            if (count > 9) {
-                count = 0;
-            }
-        }
-        return buffer.toString().getBytes();
+    @Test
+    public void testValidRepository() {
+        // Create the FileItem
+        final byte[] testFieldValueBytes = createContentBytes(THRESHOLD);
+        testInMemoryObject(testFieldValueBytes, REPO);
     }
 
     /**
-     * Create a FileItem with the specfied content bytes and repository.
+     * Helper method to test writing item contents to a file.
      */
-    private FileItem createFileItem(final byte[] contentBytes, final File repository) {
-        final FileItemFactory factory = new DiskFileItemFactory(THRESHOLD, repository);
-        final String textFieldName = "textField";
-
-        final FileItem item = factory.createItem(
-                textFieldName,
-                TEXT_CONTENT_TYPE,
-                true,
-                "My File Name"
-        );
+    public void testWritingToFile(final FileItem item, final byte[] testFieldValueBytes) {
         try {
-            final OutputStream os = item.getOutputStream();
-            os.write(contentBytes);
-            os.close();
-        } catch (final IOException e) {
-            fail("Unexpected IOException" + e);
+            final File temp = File.createTempFile("fileupload", null);
+            // Note that the file exists and is initially empty;
+            // write() must be able to handle that.
+            item.write(temp);
+            compareBytes("Initial", FileUtils.readFileToByteArray(temp), testFieldValueBytes);
+        } catch (Exception e) {
+            fail("Unexpected Exception", e);
         }
-
-        return item;
-
-    }
-
-    /**
-     * Create a FileItem with the specfied content bytes.
-     */
-    private FileItem createFileItem(final byte[] contentBytes) {
-        return createFileItem(contentBytes, REPO);
-    }
-
-    /**
-     * Do serialization
-     */
-    private ByteArrayOutputStream serialize(final Object target) throws Exception {
-        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        final ObjectOutputStream oos = new ObjectOutputStream(baos);
-        oos.writeObject(target);
-        oos.flush();
-        oos.close();
-        return baos;
-    }
-
-    /**
-     * Do deserialization
-     */
-    private Object deserialize(final ByteArrayOutputStream baos) throws Exception {
-        final ByteArrayInputStream bais =
-                new ByteArrayInputStream(baos.toByteArray());
-        final ObjectInputStream ois = new ObjectInputStream(bais);
-        final Object result = ois.readObject();
-        bais.close();
-
-        return result;
     }
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/FileUploadTest.java b/src/test/java/org/apache/commons/fileupload2/FileUploadTest.java
index 42dd106..ddc6b99 100644
--- a/src/test/java/org/apache/commons/fileupload2/FileUploadTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/FileUploadTest.java
@@ -52,6 +52,97 @@ public class FileUploadTest {
 
     // --- Test methods common to all implementations of a FileUpload
 
+    private void assertHeaders(final String[] pHeaderNames, final String[] pHeaderValues,
+            final FileItem pItem, final int pIndex) {
+        for (int i = 0; i < pHeaderNames.length; i++) {
+            final String value = pItem.getHeaders().getHeader(pHeaderNames[i]);
+            if (i == pIndex) {
+                assertEquals(pHeaderValues[i], value);
+            } else {
+                assertNull(value);
+            }
+        }
+    }
+
+    /**
+     * Test for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-239">FILEUPLOAD-239</a>
+     */
+    @ParameterizedTest
+    @MethodSource("data")
+    public void testContentTypeAttachment(final FileUpload upload)
+            throws IOException, FileUploadException {
+        final List<FileItem> fileItems = Util.parseUpload(upload,
+                "-----1234\r\n" +
+                "content-disposition: form-data; name=\"field1\"\r\n" +
+                "\r\n" +
+                "Joe Blow\r\n" +
+                "-----1234\r\n" +
+                "content-disposition: form-data; name=\"pics\"\r\n" +
+                "Content-type: multipart/mixed, boundary=---9876\r\n" +
+                "\r\n" +
+                "-----9876\r\n" +
+                "Content-disposition: attachment; filename=\"file1.txt\"\r\n" +
+                "Content-Type: text/plain\r\n" +
+                "\r\n" +
+                "... contents of file1.txt ...\r\n" +
+                "-----9876--\r\n" +
+                "-----1234--\r\n");
+        assertEquals(2, fileItems.size());
+
+        final FileItem field = fileItems.get(0);
+        assertEquals("field1", field.getFieldName());
+        assertTrue(field.isFormField());
+        assertEquals("Joe Blow", field.getString());
+
+        final FileItem file = fileItems.get(1);
+        assertEquals("pics", file.getFieldName());
+        assertFalse(file.isFormField());
+        assertEquals("... contents of file1.txt ...", file.getString());
+        assertEquals("text/plain", file.getContentType());
+        assertEquals("file1.txt", file.getName());
+    }
+
+    /**
+     * This is what the browser does if you submit the form without choosing a file.
+     */
+    @ParameterizedTest
+    @MethodSource("data")
+    public void testEmptyFile(final FileUpload upload)
+            throws UnsupportedEncodingException, FileUploadException {
+        final List<FileItem> fileItems = Util.parseUpload (upload,
+                                                "-----1234\r\n" +
+                                                "Content-Disposition: form-data; name=\"file\"; filename=\"\"\r\n" +
+                                                "\r\n" +
+                                                "\r\n" +
+                                                "-----1234--\r\n");
+        assertEquals(1, fileItems.size());
+
+        final FileItem file = fileItems.get(0);
+        assertFalse(file.isFormField());
+        assertEquals("", file.getString());
+        assertEquals("", file.getName());
+    }
+
+    @ParameterizedTest
+    @MethodSource("data")
+    public void testFilenameCaseSensitivity(final FileUpload upload)
+            throws IOException, FileUploadException {
+        final List<FileItem> fileItems = Util.parseUpload(upload,
+                                               "-----1234\r\n" +
+                                               "Content-Disposition: form-data; "
+                                             + "name=\"FiLe\"; filename=\"FOO.tab\"\r\n" +
+                                               "Content-Type: text/whatever\r\n" +
+                                               "\r\n" +
+                                               "This is the content of the file\n" +
+                                               "\r\n" +
+                                               "-----1234--\r\n");
+        assertEquals(1, fileItems.size());
+
+        final FileItem file = fileItems.get(0);
+        assertEquals("FiLe", file.getFieldName());
+        assertEquals("FOO.tab", file.getName());
+    }
+
     @ParameterizedTest
     @MethodSource("data")
     public void testFileUpload(final FileUpload upload)
@@ -102,96 +193,59 @@ public class FileUploadTest {
         assertEquals("value2", multi1.getString());
     }
 
+    /**
+     * Test case for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-130">
+     */
     @ParameterizedTest
     @MethodSource("data")
-    public void testFilenameCaseSensitivity(final FileUpload upload)
-            throws IOException, FileUploadException {
+    public void testFileUpload130(final FileUpload upload)
+            throws Exception {
+        final String[] headerNames = {
+            "SomeHeader", "OtherHeader", "YetAnotherHeader", "WhatAHeader"
+        };
+        final String[] headerValues = {
+            "present", "Is there", "Here", "Is That"
+        };
         final List<FileItem> fileItems = Util.parseUpload(upload,
                                                "-----1234\r\n" +
-                                               "Content-Disposition: form-data; "
-                                             + "name=\"FiLe\"; filename=\"FOO.tab\"\r\n" +
+                                               "Content-Disposition: form-data; name=\"file\"; "
+                                             + "filename=\"foo.tab\"\r\n" +
                                                "Content-Type: text/whatever\r\n" +
+                                               headerNames[0] + ": " + headerValues[0] + "\r\n" +
                                                "\r\n" +
                                                "This is the content of the file\n" +
                                                "\r\n" +
-                                               "-----1234--\r\n");
-        assertEquals(1, fileItems.size());
-
-        final FileItem file = fileItems.get(0);
-        assertEquals("FiLe", file.getFieldName());
-        assertEquals("FOO.tab", file.getName());
-    }
-
-    /**
-     * This is what the browser does if you submit the form without choosing a file.
-     */
-    @ParameterizedTest
-    @MethodSource("data")
-    public void testEmptyFile(final FileUpload upload)
-            throws UnsupportedEncodingException, FileUploadException {
-        final List<FileItem> fileItems = Util.parseUpload (upload,
-                                                "-----1234\r\n" +
-                                                "Content-Disposition: form-data; name=\"file\"; filename=\"\"\r\n" +
-                                                "\r\n" +
-                                                "\r\n" +
-                                                "-----1234--\r\n");
-        assertEquals(1, fileItems.size());
-
-        final FileItem file = fileItems.get(0);
-        assertFalse(file.isFormField());
-        assertEquals("", file.getString());
-        assertEquals("", file.getName());
-    }
-
-    /**
-     * Internet Explorer 5 for the Mac has a bug where the carriage
-     * return is missing on any boundary line immediately preceding
-     * an input with type=image. (type=submit does not have the bug.)
-     */
-    @ParameterizedTest
-    @MethodSource("data")
-    public void testIE5MacBug(final FileUpload upload)
-            throws UnsupportedEncodingException, FileUploadException {
-        final List<FileItem> fileItems = Util.parseUpload(upload,
                                                "-----1234\r\n" +
-                                               "Content-Disposition: form-data; name=\"field1\"\r\n" +
+                                               "Content-Disposition: form-data; \r\n" +
+                                               "\tname=\"field\"\r\n" +
+                                               headerNames[1] + ": " + headerValues[1] + "\r\n" +
                                                "\r\n" +
                                                "fieldValue\r\n" +
-                                               "-----1234\n" + // NOTE \r missing
-                                               "Content-Disposition: form-data; name=\"submitName.x\"\r\n" +
-                                               "\r\n" +
-                                               "42\r\n" +
-                                               "-----1234\n" + // NOTE \r missing
-                                               "Content-Disposition: form-data; name=\"submitName.y\"\r\n" +
+                                               "-----1234\r\n" +
+                                               "Content-Disposition: form-data;\r\n" +
+                                               "     name=\"multi\"\r\n" +
+                                               headerNames[2] + ": " + headerValues[2] + "\r\n" +
                                                "\r\n" +
-                                               "21\r\n" +
+                                               "value1\r\n" +
                                                "-----1234\r\n" +
-                                               "Content-Disposition: form-data; name=\"field2\"\r\n" +
+                                               "Content-Disposition: form-data; name=\"multi\"\r\n" +
+                                               headerNames[3] + ": " + headerValues[3] + "\r\n" +
                                                "\r\n" +
-                                               "fieldValue2\r\n" +
+                                               "value2\r\n" +
                                                "-----1234--\r\n");
-
         assertEquals(4, fileItems.size());
 
-        final FileItem field1 = fileItems.get(0);
-        assertEquals("field1", field1.getFieldName());
-        assertTrue(field1.isFormField());
-        assertEquals("fieldValue", field1.getString());
+        final FileItem file = fileItems.get(0);
+        assertHeaders(headerNames, headerValues, file, 0);
 
-        final FileItem submitX = fileItems.get(1);
-        assertEquals("submitName.x", submitX.getFieldName());
-        assertTrue(submitX.isFormField());
-        assertEquals("42", submitX.getString());
+        final FileItem field = fileItems.get(1);
+        assertHeaders(headerNames, headerValues, field, 1);
 
-        final FileItem submitY = fileItems.get(2);
-        assertEquals("submitName.y", submitY.getFieldName());
-        assertTrue(submitY.isFormField());
-        assertEquals("21", submitY.getString());
+        final FileItem multi0 = fileItems.get(2);
+        assertHeaders(headerNames, headerValues, multi0, 2);
 
-        final FileItem field2 = fileItems.get(3);
-        assertEquals("field2", field2.getFieldName());
-        assertTrue(field2.isFormField());
-        assertEquals("fieldValue2", field2.getString());
+        final FileItem multi1 = fileItems.get(3);
+        assertHeaders(headerNames, headerValues, multi1, 3);
     }
 
     /**
@@ -294,107 +348,53 @@ public class FileUploadTest {
     }
 
     /**
-     * Test case for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-130">
+     * Internet Explorer 5 for the Mac has a bug where the carriage
+     * return is missing on any boundary line immediately preceding
+     * an input with type=image. (type=submit does not have the bug.)
      */
     @ParameterizedTest
     @MethodSource("data")
-    public void testFileUpload130(final FileUpload upload)
-            throws Exception {
-        final String[] headerNames = {
-            "SomeHeader", "OtherHeader", "YetAnotherHeader", "WhatAHeader"
-        };
-        final String[] headerValues = {
-            "present", "Is there", "Here", "Is That"
-        };
+    public void testIE5MacBug(final FileUpload upload)
+            throws UnsupportedEncodingException, FileUploadException {
         final List<FileItem> fileItems = Util.parseUpload(upload,
                                                "-----1234\r\n" +
-                                               "Content-Disposition: form-data; name=\"file\"; "
-                                             + "filename=\"foo.tab\"\r\n" +
-                                               "Content-Type: text/whatever\r\n" +
-                                               headerNames[0] + ": " + headerValues[0] + "\r\n" +
-                                               "\r\n" +
-                                               "This is the content of the file\n" +
-                                               "\r\n" +
-                                               "-----1234\r\n" +
-                                               "Content-Disposition: form-data; \r\n" +
-                                               "\tname=\"field\"\r\n" +
-                                               headerNames[1] + ": " + headerValues[1] + "\r\n" +
+                                               "Content-Disposition: form-data; name=\"field1\"\r\n" +
                                                "\r\n" +
                                                "fieldValue\r\n" +
-                                               "-----1234\r\n" +
-                                               "Content-Disposition: form-data;\r\n" +
-                                               "     name=\"multi\"\r\n" +
-                                               headerNames[2] + ": " + headerValues[2] + "\r\n" +
+                                               "-----1234\n" + // NOTE \r missing
+                                               "Content-Disposition: form-data; name=\"submitName.x\"\r\n" +
                                                "\r\n" +
-                                               "value1\r\n" +
+                                               "42\r\n" +
+                                               "-----1234\n" + // NOTE \r missing
+                                               "Content-Disposition: form-data; name=\"submitName.y\"\r\n" +
+                                               "\r\n" +
+                                               "21\r\n" +
                                                "-----1234\r\n" +
-                                               "Content-Disposition: form-data; name=\"multi\"\r\n" +
-                                               headerNames[3] + ": " + headerValues[3] + "\r\n" +
+                                               "Content-Disposition: form-data; name=\"field2\"\r\n" +
                                                "\r\n" +
-                                               "value2\r\n" +
+                                               "fieldValue2\r\n" +
                                                "-----1234--\r\n");
-        assertEquals(4, fileItems.size());
-
-        final FileItem file = fileItems.get(0);
-        assertHeaders(headerNames, headerValues, file, 0);
-
-        final FileItem field = fileItems.get(1);
-        assertHeaders(headerNames, headerValues, field, 1);
 
-        final FileItem multi0 = fileItems.get(2);
-        assertHeaders(headerNames, headerValues, multi0, 2);
-
-        final FileItem multi1 = fileItems.get(3);
-        assertHeaders(headerNames, headerValues, multi1, 3);
-    }
+        assertEquals(4, fileItems.size());
 
-    /**
-     * Test for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-239">FILEUPLOAD-239</a>
-     */
-    @ParameterizedTest
-    @MethodSource("data")
-    public void testContentTypeAttachment(final FileUpload upload)
-            throws IOException, FileUploadException {
-        final List<FileItem> fileItems = Util.parseUpload(upload,
-                "-----1234\r\n" +
-                "content-disposition: form-data; name=\"field1\"\r\n" +
-                "\r\n" +
-                "Joe Blow\r\n" +
-                "-----1234\r\n" +
-                "content-disposition: form-data; name=\"pics\"\r\n" +
-                "Content-type: multipart/mixed, boundary=---9876\r\n" +
-                "\r\n" +
-                "-----9876\r\n" +
-                "Content-disposition: attachment; filename=\"file1.txt\"\r\n" +
-                "Content-Type: text/plain\r\n" +
-                "\r\n" +
-                "... contents of file1.txt ...\r\n" +
-                "-----9876--\r\n" +
-                "-----1234--\r\n");
-        assertEquals(2, fileItems.size());
+        final FileItem field1 = fileItems.get(0);
+        assertEquals("field1", field1.getFieldName());
+        assertTrue(field1.isFormField());
+        assertEquals("fieldValue", field1.getString());
 
-        final FileItem field = fileItems.get(0);
-        assertEquals("field1", field.getFieldName());
-        assertTrue(field.isFormField());
-        assertEquals("Joe Blow", field.getString());
+        final FileItem submitX = fileItems.get(1);
+        assertEquals("submitName.x", submitX.getFieldName());
+        assertTrue(submitX.isFormField());
+        assertEquals("42", submitX.getString());
 
-        final FileItem file = fileItems.get(1);
-        assertEquals("pics", file.getFieldName());
-        assertFalse(file.isFormField());
-        assertEquals("... contents of file1.txt ...", file.getString());
-        assertEquals("text/plain", file.getContentType());
-        assertEquals("file1.txt", file.getName());
-    }
+        final FileItem submitY = fileItems.get(2);
+        assertEquals("submitName.y", submitY.getFieldName());
+        assertTrue(submitY.isFormField());
+        assertEquals("21", submitY.getString());
 
-    private void assertHeaders(final String[] pHeaderNames, final String[] pHeaderValues,
-            final FileItem pItem, final int pIndex) {
-        for (int i = 0; i < pHeaderNames.length; i++) {
-            final String value = pItem.getHeaders().getHeader(pHeaderNames[i]);
-            if (i == pIndex) {
-                assertEquals(pHeaderValues[i], value);
-            } else {
-                assertNull(value);
-            }
-        }
+        final FileItem field2 = fileItems.get(3);
+        assertEquals("field2", field2.getFieldName());
+        assertTrue(field2.isFormField());
+        assertEquals("fieldValue2", field2.getString());
     }
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/HttpServletRequestFactory.java b/src/test/java/org/apache/commons/fileupload2/HttpServletRequestFactory.java
index e66cd57..174b563 100644
--- a/src/test/java/org/apache/commons/fileupload2/HttpServletRequestFactory.java
+++ b/src/test/java/org/apache/commons/fileupload2/HttpServletRequestFactory.java
@@ -27,6 +27,13 @@ final class HttpServletRequestFactory {
                             null);
     }
 
+    static public HttpServletRequest createInvalidHttpServletRequest() {
+        final byte[] requestData = "foobar".getBytes();
+        return new MockHttpServletRequest(
+                            requestData,
+                            FileUploadBase.MULTIPART_FORM_DATA);
+    }
+
     public static HttpServletRequest createValidHttpServletRequest(
             final String[] strFileNames) {
         // todo - provide a real implementation
@@ -44,11 +51,4 @@ final class HttpServletRequestFactory {
                             FileUploadBase.MULTIPART_FORM_DATA);
     }
 
-    static public HttpServletRequest createInvalidHttpServletRequest() {
-        final byte[] requestData = "foobar".getBytes();
-        return new MockHttpServletRequest(
-                            requestData,
-                            FileUploadBase.MULTIPART_FORM_DATA);
-    }
-
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/MockHttpServletRequest.java b/src/test/java/org/apache/commons/fileupload2/MockHttpServletRequest.java
index b43e231..d50f2ab 100644
--- a/src/test/java/org/apache/commons/fileupload2/MockHttpServletRequest.java
+++ b/src/test/java/org/apache/commons/fileupload2/MockHttpServletRequest.java
@@ -34,6 +34,36 @@ import javax.servlet.http.HttpSession;
 
 public class MockHttpServletRequest implements HttpServletRequest {
 
+    private static class MyServletInputStream
+        extends javax.servlet.ServletInputStream {
+
+        private final InputStream in;
+        private final int readLimit;
+
+        /**
+         * Creates a new instance, which returns the given
+         * streams data.
+         */
+        public MyServletInputStream(final InputStream pStream, final int readLimit) {
+            in = pStream;
+            this.readLimit = readLimit;
+        }
+
+        @Override
+        public int read() throws IOException {
+            return in.read();
+        }
+
+        @Override
+        public int read(final byte[] b, final int off, final int len) throws IOException {
+            if (readLimit > 0) {
+                return in.read(b, off, Math.min(readLimit, len));
+            }
+            return in.read(b, off, len);
+        }
+
+    }
+
     private final InputStream mmRequestData;
 
     private long length;
@@ -70,328 +100,324 @@ public class MockHttpServletRequest implements HttpServletRequest {
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getAuthType()
+     * @see javax.servlet.ServletRequest#getAttribute(String)
      */
     @Override
-    public String getAuthType() {
+    public Object getAttribute(final String arg0) {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getCookies()
+     * @see javax.servlet.ServletRequest#getAttributeNames()
      */
     @Override
-    public Cookie[] getCookies() {
+    public Enumeration<String> getAttributeNames() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getDateHeader(String)
-     */
-    @Override
-    public long getDateHeader(final String arg0) {
-        return 0;
-    }
-
-    /**
-     * @see javax.servlet.http.HttpServletRequest#getHeader(String)
+     * @see javax.servlet.http.HttpServletRequest#getAuthType()
      */
     @Override
-    public String getHeader(final String headerName) {
-        return mHeaders.get(headerName);
+    public String getAuthType() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getHeaders(String)
+     * @see javax.servlet.ServletRequest#getCharacterEncoding()
      */
     @Override
-    public Enumeration<String> getHeaders(final String arg0) {
-        // todo - implement
+    public String getCharacterEncoding() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getHeaderNames()
+     * @see javax.servlet.ServletRequest#getContentLength()
      */
     @Override
-    public Enumeration<String> getHeaderNames() {
-        // todo - implement
-        return null;
+    public int getContentLength() {
+        int iLength;
+
+        if (null == mmRequestData) {
+            iLength = -1;
+        } else {
+            if (length > Integer.MAX_VALUE) {
+                throw new RuntimeException("Value '" + length + "' is too large to be converted to int");
+            }
+            iLength = (int) length;
+        }
+        return iLength;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getIntHeader(String)
+     * @see javax.servlet.ServletRequest#getContentType()
      */
     @Override
-    public int getIntHeader(final String arg0) {
-        return 0;
+    public String getContentType() {
+        return mStrContentType;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getMethod()
+     * @see javax.servlet.http.HttpServletRequest#getContextPath()
      */
     @Override
-    public String getMethod() {
+    public String getContextPath() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getPathInfo()
+     * @see javax.servlet.http.HttpServletRequest#getCookies()
      */
     @Override
-    public String getPathInfo() {
+    public Cookie[] getCookies() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getPathTranslated()
+     * @see javax.servlet.http.HttpServletRequest#getDateHeader(String)
      */
     @Override
-    public String getPathTranslated() {
-        return null;
+    public long getDateHeader(final String arg0) {
+        return 0;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getContextPath()
+     * @see javax.servlet.http.HttpServletRequest#getHeader(String)
      */
     @Override
-    public String getContextPath() {
-        return null;
+    public String getHeader(final String headerName) {
+        return mHeaders.get(headerName);
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getQueryString()
+     * @see javax.servlet.http.HttpServletRequest#getHeaderNames()
      */
     @Override
-    public String getQueryString() {
+    public Enumeration<String> getHeaderNames() {
+        // todo - implement
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getRemoteUser()
+     * @see javax.servlet.http.HttpServletRequest#getHeaders(String)
      */
     @Override
-    public String getRemoteUser() {
+    public Enumeration<String> getHeaders(final String arg0) {
+        // todo - implement
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#isUserInRole(String)
+     * @see javax.servlet.ServletRequest#getInputStream()
      */
     @Override
-    public boolean isUserInRole(final String arg0) {
-        return false;
+    public ServletInputStream getInputStream() throws IOException {
+        return new MyServletInputStream(mmRequestData, readLimit);
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
+     * @see javax.servlet.http.HttpServletRequest#getIntHeader(String)
      */
     @Override
-    public Principal getUserPrincipal() {
-        return null;
+    public int getIntHeader(final String arg0) {
+        return 0;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getRequestedSessionId()
+     * @see javax.servlet.ServletRequest#getLocalAddr()
      */
     @Override
-    public String getRequestedSessionId() {
+    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
+    public String getLocalAddr() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getRequestURI()
+     * @see javax.servlet.ServletRequest#getLocale()
      */
     @Override
-    public String getRequestURI() {
+    public Locale getLocale() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getRequestURL()
+     * @see javax.servlet.ServletRequest#getLocales()
      */
     @Override
-    public StringBuffer getRequestURL() {
+    public Enumeration<Locale> getLocales() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getServletPath()
+     * @see javax.servlet.ServletRequest#getLocalName()
      */
     @Override
-    public String getServletPath() {
+    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
+    public String getLocalName() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getSession(boolean)
+     * @see javax.servlet.ServletRequest#getLocalPort()
      */
     @Override
-    public HttpSession getSession(final boolean arg0) {
-        return null;
+    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
+    public int getLocalPort() {
+        return 0;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getSession()
+     * @see javax.servlet.http.HttpServletRequest#getMethod()
      */
     @Override
-    public HttpSession getSession() {
+    public String getMethod() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid()
+     * @see javax.servlet.ServletRequest#getParameter(String)
      */
     @Override
-    public boolean isRequestedSessionIdValid() {
-        return false;
+    public String getParameter(final String arg0) {
+        return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromCookie()
+     * @see javax.servlet.ServletRequest#getParameterMap()
      */
     @Override
-    public boolean isRequestedSessionIdFromCookie() {
-        return false;
+    public Map<String, String[]> getParameterMap() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromURL()
+     * @see javax.servlet.ServletRequest#getParameterNames()
      */
     @Override
-    public boolean isRequestedSessionIdFromURL() {
-        return false;
+    public Enumeration<String> getParameterNames() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromUrl()
-     * @deprecated
+     * @see javax.servlet.ServletRequest#getParameterValues(String)
      */
     @Override
-    @Deprecated
-    public boolean isRequestedSessionIdFromUrl() {
-        return false;
+    public String[] getParameterValues(final String arg0) {
+        return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getAttribute(String)
+     * @see javax.servlet.http.HttpServletRequest#getPathInfo()
      */
     @Override
-    public Object getAttribute(final String arg0) {
+    public String getPathInfo() {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getAttributeNames()
+     * @see javax.servlet.http.HttpServletRequest#getPathTranslated()
      */
     @Override
-    public Enumeration<String> getAttributeNames() {
+    public String getPathTranslated() {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getCharacterEncoding()
+     * @see javax.servlet.ServletRequest#getProtocol()
      */
     @Override
-    public String getCharacterEncoding() {
+    public String getProtocol() {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#setCharacterEncoding(String)
+     * @see javax.servlet.http.HttpServletRequest#getQueryString()
      */
     @Override
-    public void setCharacterEncoding(final String arg0)
-        throws UnsupportedEncodingException {
+    public String getQueryString() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getContentLength()
+     * @see javax.servlet.ServletRequest#getReader()
      */
     @Override
-    public int getContentLength() {
-        int iLength;
-
-        if (null == mmRequestData) {
-            iLength = -1;
-        } else {
-            if (length > Integer.MAX_VALUE) {
-                throw new RuntimeException("Value '" + length + "' is too large to be converted to int");
-            }
-            iLength = (int) length;
-        }
-        return iLength;
+    public BufferedReader getReader() throws IOException {
+        return null;
     }
 
     /**
-     * For testing attack scenarios in SizesTest.
+     * @see javax.servlet.ServletRequest#getRealPath(String)
+     * @deprecated
      */
-    public void setContentLength(final long length) {
-        this.length = length;
+    @Override
+    @Deprecated
+    public String getRealPath(final String arg0) {
+        return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getContentType()
+     * @see javax.servlet.ServletRequest#getRemoteAddr()
      */
     @Override
-    public String getContentType() {
-        return mStrContentType;
+    public String getRemoteAddr() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getInputStream()
+     * @see javax.servlet.ServletRequest#getRemoteHost()
      */
     @Override
-    public ServletInputStream getInputStream() throws IOException {
-        return new MyServletInputStream(mmRequestData, readLimit);
+    public String getRemoteHost() {
+        return null;
     }
 
     /**
-     * Sets the read limit. This can be used to limit the number of bytes to read ahead.
-     *
-     * @param readLimit the read limit to use
+     * @see javax.servlet.ServletRequest#getRemotePort()
      */
-    public void setReadLimit(final int readLimit) {
-        this.readLimit = readLimit;
+    @Override
+    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
+    public int getRemotePort() {
+        return 0;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getParameter(String)
+     * @see javax.servlet.http.HttpServletRequest#getRemoteUser()
      */
     @Override
-    public String getParameter(final String arg0) {
+    public String getRemoteUser() {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getParameterNames()
+     * @see javax.servlet.ServletRequest#getRequestDispatcher(String)
      */
     @Override
-    public Enumeration<String> getParameterNames() {
+    public RequestDispatcher getRequestDispatcher(final String arg0) {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getParameterValues(String)
+     * @see javax.servlet.http.HttpServletRequest#getRequestedSessionId()
      */
     @Override
-    public String[] getParameterValues(final String arg0) {
+    public String getRequestedSessionId() {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getParameterMap()
+     * @see javax.servlet.http.HttpServletRequest#getRequestURI()
      */
     @Override
-    public Map<String, String[]> getParameterMap() {
+    public String getRequestURI() {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getProtocol()
+     * @see javax.servlet.http.HttpServletRequest#getRequestURL()
      */
     @Override
-    public String getProtocol() {
+    public StringBuffer getRequestURL() {
         return null;
     }
 
@@ -411,15 +437,6 @@ public class MockHttpServletRequest implements HttpServletRequest {
         return null;
     }
 
-    /**
-     * @see javax.servlet.ServletRequest#getLocalName()
-     */
-    @Override
-    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
-    public String getLocalName() {
-        return null;
-    }
-
     /**
      * @see javax.servlet.ServletRequest#getServerPort()
      */
@@ -429,140 +446,123 @@ public class MockHttpServletRequest implements HttpServletRequest {
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getLocalPort()
+     * @see javax.servlet.http.HttpServletRequest#getServletPath()
      */
     @Override
-    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
-    public int getLocalPort() {
-        return 0;
+    public String getServletPath() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getRemotePort()
+     * @see javax.servlet.http.HttpServletRequest#getSession()
      */
     @Override
-    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
-    public int getRemotePort() {
-        return 0;
+    public HttpSession getSession() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getReader()
+     * @see javax.servlet.http.HttpServletRequest#getSession(boolean)
      */
     @Override
-    public BufferedReader getReader() throws IOException {
+    public HttpSession getSession(final boolean arg0) {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getRemoteAddr()
+     * @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
      */
     @Override
-    public String getRemoteAddr() {
+    public Principal getUserPrincipal() {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getLocalAddr()
+     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromCookie()
      */
     @Override
-    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
-    public String getLocalAddr() {
-        return null;
+    public boolean isRequestedSessionIdFromCookie() {
+        return false;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getRemoteHost()
+     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromUrl()
+     * @deprecated
      */
     @Override
-    public String getRemoteHost() {
-        return null;
+    @Deprecated
+    public boolean isRequestedSessionIdFromUrl() {
+        return false;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#setAttribute(String, Object)
+     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromURL()
      */
     @Override
-    public void setAttribute(final String arg0, final Object arg1) {
+    public boolean isRequestedSessionIdFromURL() {
+        return false;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#removeAttribute(String)
+     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid()
      */
     @Override
-    public void removeAttribute(final String arg0) {
+    public boolean isRequestedSessionIdValid() {
+        return false;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getLocale()
+     * @see javax.servlet.ServletRequest#isSecure()
      */
     @Override
-    public Locale getLocale() {
-        return null;
+    public boolean isSecure() {
+        return false;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getLocales()
+     * @see javax.servlet.http.HttpServletRequest#isUserInRole(String)
      */
     @Override
-    public Enumeration<Locale> getLocales() {
-        return null;
+    public boolean isUserInRole(final String arg0) {
+        return false;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#isSecure()
+     * @see javax.servlet.ServletRequest#removeAttribute(String)
      */
     @Override
-    public boolean isSecure() {
-        return false;
+    public void removeAttribute(final String arg0) {
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getRequestDispatcher(String)
+     * @see javax.servlet.ServletRequest#setAttribute(String, Object)
      */
     @Override
-    public RequestDispatcher getRequestDispatcher(final String arg0) {
-        return null;
+    public void setAttribute(final String arg0, final Object arg1) {
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getRealPath(String)
-     * @deprecated
+     * @see javax.servlet.ServletRequest#setCharacterEncoding(String)
      */
     @Override
-    @Deprecated
-    public String getRealPath(final String arg0) {
-        return null;
+    public void setCharacterEncoding(final String arg0)
+        throws UnsupportedEncodingException {
     }
 
-    private static class MyServletInputStream
-        extends javax.servlet.ServletInputStream {
-
-        private final InputStream in;
-        private final int readLimit;
-
-        /**
-         * Creates a new instance, which returns the given
-         * streams data.
-         */
-        public MyServletInputStream(final InputStream pStream, final int readLimit) {
-            in = pStream;
-            this.readLimit = readLimit;
-        }
-
-        @Override
-        public int read() throws IOException {
-            return in.read();
-        }
-
-        @Override
-        public int read(final byte[] b, final int off, final int len) throws IOException {
-            if (readLimit > 0) {
-                return in.read(b, off, Math.min(readLimit, len));
-            }
-            return in.read(b, off, len);
-        }
+    /**
+     * For testing attack scenarios in SizesTest.
+     */
+    public void setContentLength(final long length) {
+        this.length = length;
+    }
 
+    /**
+     * Sets the read limit. This can be used to limit the number of bytes to read ahead.
+     *
+     * @param readLimit the read limit to use
+     */
+    public void setReadLimit(final int readLimit) {
+        this.readLimit = readLimit;
     }
 
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/MultipartStreamTest.java b/src/test/java/org/apache/commons/fileupload2/MultipartStreamTest.java
index 57eaae4..5b354cc 100644
--- a/src/test/java/org/apache/commons/fileupload2/MultipartStreamTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/MultipartStreamTest.java
@@ -31,6 +31,21 @@ public class MultipartStreamTest {
 
     static private final String BOUNDARY_TEXT = "myboundary";
 
+    @Test
+    public void testSmallBuffer() {
+        final String strData = "foobar";
+        final byte[] contents = strData.getBytes();
+        final InputStream input = new ByteArrayInputStream(contents);
+        final byte[] boundary = BOUNDARY_TEXT.getBytes();
+        final int iBufSize = 1;
+        assertThrows(IllegalArgumentException.class,
+                () -> new MultipartStream(
+                        input,
+                        boundary,
+                        iBufSize,
+                        new MultipartStream.ProgressNotifier(null, contents.length)));
+    }
+
     @Test
     public void testThreeParamConstructor() throws Exception {
         final String strData = "foobar";
@@ -47,21 +62,6 @@ public class MultipartStreamTest {
         assertNotNull(ms);
     }
 
-    @Test
-    public void testSmallBuffer() {
-        final String strData = "foobar";
-        final byte[] contents = strData.getBytes();
-        final InputStream input = new ByteArrayInputStream(contents);
-        final byte[] boundary = BOUNDARY_TEXT.getBytes();
-        final int iBufSize = 1;
-        assertThrows(IllegalArgumentException.class,
-                () -> new MultipartStream(
-                        input,
-                        boundary,
-                        iBufSize,
-                        new MultipartStream.ProgressNotifier(null, contents.length)));
-    }
-
     @Test
     public void testTwoParamConstructor() throws Exception {
         final String strData = "foobar";
diff --git a/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java b/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java
index 1edbfda..8b8e00f 100644
--- a/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java
@@ -29,43 +29,6 @@ import org.junit.jupiter.api.Test;
  */
 public class ParameterParserTest {
 
-    @Test
-    public void testParsing() {
-        String s =
-            "test; test1 =  stuff   ; test2 =  \"stuff; stuff\"; test3=\"stuff";
-        final ParameterParser parser = new ParameterParser();
-        Map<String, String> params = parser.parse(s, ';');
-        assertNull(params.get("test"));
-        assertEquals("stuff", params.get("test1"));
-        assertEquals("stuff; stuff", params.get("test2"));
-        assertEquals("\"stuff", params.get("test3"));
-
-        params = parser.parse(s, new char[] {',', ';' });
-        assertNull(params.get("test"));
-        assertEquals("stuff", params.get("test1"));
-        assertEquals("stuff; stuff", params.get("test2"));
-        assertEquals("\"stuff", params.get("test3"));
-
-        s = "  test  , test1=stuff   ,  , test2=, test3, ";
-        params = parser.parse(s, ',');
-        assertNull(params.get("test"));
-        assertEquals("stuff", params.get("test1"));
-        assertNull(params.get("test2"));
-        assertNull(params.get("test3"));
-
-        s = "  test";
-        params = parser.parse(s, ';');
-        assertNull(params.get("test"));
-
-        s = "  ";
-        params = parser.parse(s, ';');
-        assertEquals(0, params.size());
-
-        s = " = stuff ";
-        params = parser.parse(s, ';');
-        assertEquals(0, params.size());
-    }
-
     @Test
     public void testContentTypeParsing() {
         final String s = "text/plain; Charset=UTF-8";
@@ -75,21 +38,6 @@ public class ParameterParserTest {
         assertEquals("UTF-8", params.get("charset"));
     }
 
-    @Test
-    public void testParsingEscapedChars() {
-        String s = "param = \"stuff\\\"; more stuff\"";
-        final ParameterParser parser = new ParameterParser();
-        Map<String, String> params = parser.parse(s, ';');
-        assertEquals(1, params.size());
-        assertEquals("stuff\\\"; more stuff", params.get("param"));
-
-        s = "param = \"stuff\\\\\"; anotherparam";
-        params = parser.parse(s, ';');
-        assertEquals(2, params.size());
-        assertEquals("stuff\\\\", params.get("param"));
-        assertNull(params.get("anotherparam"));
-    }
-
     // See: https://issues.apache.org/jira/browse/FILEUPLOAD-139
     @Test
     public void testFileUpload139() {
@@ -154,4 +102,56 @@ public class ParameterParserTest {
         assertEquals("a'b'c", params.get("filename"));
     }
 
+    @Test
+    public void testParsing() {
+        String s =
+            "test; test1 =  stuff   ; test2 =  \"stuff; stuff\"; test3=\"stuff";
+        final ParameterParser parser = new ParameterParser();
+        Map<String, String> params = parser.parse(s, ';');
+        assertNull(params.get("test"));
+        assertEquals("stuff", params.get("test1"));
+        assertEquals("stuff; stuff", params.get("test2"));
+        assertEquals("\"stuff", params.get("test3"));
+
+        params = parser.parse(s, new char[] {',', ';' });
+        assertNull(params.get("test"));
+        assertEquals("stuff", params.get("test1"));
+        assertEquals("stuff; stuff", params.get("test2"));
+        assertEquals("\"stuff", params.get("test3"));
+
+        s = "  test  , test1=stuff   ,  , test2=, test3, ";
+        params = parser.parse(s, ',');
+        assertNull(params.get("test"));
+        assertEquals("stuff", params.get("test1"));
+        assertNull(params.get("test2"));
+        assertNull(params.get("test3"));
+
+        s = "  test";
+        params = parser.parse(s, ';');
+        assertNull(params.get("test"));
+
+        s = "  ";
+        params = parser.parse(s, ';');
+        assertEquals(0, params.size());
+
+        s = " = stuff ";
+        params = parser.parse(s, ';');
+        assertEquals(0, params.size());
+    }
+
+    @Test
+    public void testParsingEscapedChars() {
+        String s = "param = \"stuff\\\"; more stuff\"";
+        final ParameterParser parser = new ParameterParser();
+        Map<String, String> params = parser.parse(s, ';');
+        assertEquals(1, params.size());
+        assertEquals("stuff\\\"; more stuff", params.get("param"));
+
+        s = "param = \"stuff\\\\\"; anotherparam";
+        params = parser.parse(s, ';');
+        assertEquals(2, params.size());
+        assertEquals("stuff\\\\", params.get("param"));
+        assertNull(params.get("anotherparam"));
+    }
+
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/ProgressListenerTest.java b/src/test/java/org/apache/commons/fileupload2/ProgressListenerTest.java
index 59e5683..c603dea 100644
--- a/src/test/java/org/apache/commons/fileupload2/ProgressListenerTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/ProgressListenerTest.java
@@ -48,6 +48,11 @@ public class ProgressListenerTest {
             expectedItems = pItems;
         }
 
+        void checkFinished() {
+            assertEquals(expectedContentLength, bytesRead.longValue());
+            assertEquals(expectedItems, items.intValue());
+        }
+
         @Override
         public void update(final long pBytesRead, final long pContentLength, final int pItems) {
             assertTrue(pBytesRead >= 0  &&  pBytesRead <= expectedContentLength);
@@ -60,11 +65,34 @@ public class ProgressListenerTest {
             items = Integer.valueOf(pItems);
         }
 
-        void checkFinished() {
-            assertEquals(expectedContentLength, bytesRead.longValue());
-            assertEquals(expectedItems, items.intValue());
-        }
+    }
 
+    private void runTest(final int NUM_ITEMS, final long pContentLength, final MockHttpServletRequest request) throws FileUploadException, IOException {
+        final ServletFileUpload upload = new ServletFileUpload();
+        final ProgressListenerImpl listener = new ProgressListenerImpl(pContentLength, NUM_ITEMS);
+        upload.setProgressListener(listener);
+        final FileItemIterator iter = upload.getItemIterator(request);
+        for (int i = 0;  i < NUM_ITEMS;  i++) {
+            final FileItemStream stream = iter.next();
+            final InputStream istream = stream.openStream();
+            for (int j = 0;  j < 16384 + i;  j++) {
+                /**
+                 * This used to be
+                 *     assertEquals((byte) j, (byte) istream.read());
+                 * but this seems to trigger a bug in JRockit, so
+                 * we express the same like this:
+                 */
+                final byte b1 = (byte) j;
+                final byte b2 = (byte) istream.read();
+                if (b1 != b2) {
+                    fail("Expected " + b1 + ", got " + b2);
+                }
+            }
+            assertEquals(-1, istream.read());
+            istream.close();
+        }
+        assertTrue(!iter.hasNext());
+        listener.checkFinished();
     }
 
     /**
@@ -98,32 +126,4 @@ public class ProgressListenerTest {
         runTest(NUM_ITEMS, contents.length, request);
     }
 
-    private void runTest(final int NUM_ITEMS, final long pContentLength, final MockHttpServletRequest request) throws FileUploadException, IOException {
-        final ServletFileUpload upload = new ServletFileUpload();
-        final ProgressListenerImpl listener = new ProgressListenerImpl(pContentLength, NUM_ITEMS);
-        upload.setProgressListener(listener);
-        final FileItemIterator iter = upload.getItemIterator(request);
-        for (int i = 0;  i < NUM_ITEMS;  i++) {
-            final FileItemStream stream = iter.next();
-            final InputStream istream = stream.openStream();
-            for (int j = 0;  j < 16384 + i;  j++) {
-                /**
-                 * This used to be
-                 *     assertEquals((byte) j, (byte) istream.read());
-                 * but this seems to trigger a bug in JRockit, so
-                 * we express the same like this:
-                 */
-                final byte b1 = (byte) j;
-                final byte b2 = (byte) istream.read();
-                if (b1 != b2) {
-                    fail("Expected " + b1 + ", got " + b2);
-                }
-            }
-            assertEquals(-1, istream.read());
-            istream.close();
-        }
-        assertTrue(!iter.hasNext());
-        listener.checkFinished();
-    }
-
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/SizesTest.java b/src/test/java/org/apache/commons/fileupload2/SizesTest.java
index 7dd1916..5db2156 100644
--- a/src/test/java/org/apache/commons/fileupload2/SizesTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/SizesTest.java
@@ -43,50 +43,6 @@ import org.junit.jupiter.api.Test;
  */
 public class SizesTest {
 
-    /**
-     * Runs a test with varying file sizes.
-     */
-    @Test
-    public void testFileUpload()
-            throws IOException, FileUploadException {
-        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        int add = 16;
-        int num = 0;
-        for (int i = 0;  i < 16384;  i += add) {
-            if (++add == 32) {
-                add = 16;
-            }
-            final String header = "-----1234\r\n"
-                + "Content-Disposition: form-data; name=\"field" + (num++) + "\"\r\n"
-                + "\r\n";
-            baos.write(header.getBytes(StandardCharsets.US_ASCII));
-            for (int j = 0;  j < i;  j++) {
-                baos.write((byte) j);
-            }
-            baos.write("\r\n".getBytes(StandardCharsets.US_ASCII));
-        }
-        baos.write("-----1234--\r\n".getBytes(StandardCharsets.US_ASCII));
-
-        final List<FileItem> fileItems =
-                Util.parseUpload(new ServletFileUpload(new DiskFileItemFactory()), baos.toByteArray());
-        final Iterator<FileItem> fileIter = fileItems.iterator();
-        add = 16;
-        num = 0;
-        for (int i = 0;  i < 16384;  i += add) {
-            if (++add == 32) {
-                add = 16;
-            }
-            final FileItem item = fileIter.next();
-            assertEquals("field" + (num++), item.getFieldName());
-            final byte[] bytes = item.get();
-            assertEquals(i, bytes.length);
-            for (int j = 0;  j < i;  j++) {
-                assertEquals((byte) j, bytes[j]);
-            }
-        }
-        assertTrue(!fileIter.hasNext());
-    }
-
     /** Checks, whether limiting the file size works.
      */
     @Test
@@ -184,6 +140,50 @@ public class SizesTest {
         }
     }
 
+    /**
+     * Runs a test with varying file sizes.
+     */
+    @Test
+    public void testFileUpload()
+            throws IOException, FileUploadException {
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        int add = 16;
+        int num = 0;
+        for (int i = 0;  i < 16384;  i += add) {
+            if (++add == 32) {
+                add = 16;
+            }
+            final String header = "-----1234\r\n"
+                + "Content-Disposition: form-data; name=\"field" + (num++) + "\"\r\n"
+                + "\r\n";
+            baos.write(header.getBytes(StandardCharsets.US_ASCII));
+            for (int j = 0;  j < i;  j++) {
+                baos.write((byte) j);
+            }
+            baos.write("\r\n".getBytes(StandardCharsets.US_ASCII));
+        }
+        baos.write("-----1234--\r\n".getBytes(StandardCharsets.US_ASCII));
+
+        final List<FileItem> fileItems =
+                Util.parseUpload(new ServletFileUpload(new DiskFileItemFactory()), baos.toByteArray());
+        final Iterator<FileItem> fileIter = fileItems.iterator();
+        add = 16;
+        num = 0;
+        for (int i = 0;  i < 16384;  i += add) {
+            if (++add == 32) {
+                add = 16;
+            }
+            final FileItem item = fileIter.next();
+            assertEquals("field" + (num++), item.getFieldName());
+            final byte[] bytes = item.get();
+            assertEquals(i, bytes.length);
+            for (int j = 0;  j < i;  j++) {
+                assertEquals((byte) j, bytes[j]);
+            }
+        }
+        assertTrue(!fileIter.hasNext());
+    }
+
     /** Checks, whether the maxSize works.
      */
     @Test
diff --git a/src/test/java/org/apache/commons/fileupload2/StreamingTest.java b/src/test/java/org/apache/commons/fileupload2/StreamingTest.java
index 2e21147..d621ba1 100644
--- a/src/test/java/org/apache/commons/fileupload2/StreamingTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/StreamingTest.java
@@ -42,6 +42,77 @@ import org.junit.jupiter.api.Test;
  */
 public class StreamingTest {
 
+    private String getFooter() {
+        return "-----1234--\r\n";
+    }
+
+    private String getHeader(final String pField) {
+        return "-----1234\r\n"
+            + "Content-Disposition: form-data; name=\"" + pField + "\"\r\n"
+            + "\r\n";
+
+    }
+
+    private byte[] newRequest() throws IOException {
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        final OutputStreamWriter osw = new OutputStreamWriter(baos, StandardCharsets.US_ASCII);
+        int add = 16;
+        int num = 0;
+        for (int i = 0;  i < 16384;  i += add) {
+            if (++add == 32) {
+                add = 16;
+            }
+            osw.write(getHeader("field" + (num++)));
+            osw.flush();
+            for (int j = 0;  j < i;  j++) {
+                baos.write((byte) j);
+            }
+            osw.write("\r\n");
+        }
+        osw.write(getFooter());
+        osw.close();
+        return baos.toByteArray();
+    }
+
+    private byte[] newShortRequest() throws IOException {
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        final OutputStreamWriter osw = new OutputStreamWriter(baos, StandardCharsets.US_ASCII);
+        osw.write(getHeader("field"));
+        osw.write("123");
+        osw.write("\r\n");
+        osw.write(getFooter());
+        osw.close();
+        return baos.toByteArray();
+    }
+
+    private List<FileItem> parseUpload(final byte[] bytes) throws FileUploadException {
+        return parseUpload(new ByteArrayInputStream(bytes), bytes.length);
+    }
+
+    private List<FileItem> parseUpload(final InputStream pStream, final int pLength)
+            throws FileUploadException {
+        final String contentType = "multipart/form-data; boundary=---1234";
+
+        final FileUploadBase upload = new ServletFileUpload();
+        upload.setFileItemFactory(new DiskFileItemFactory());
+        final HttpServletRequest request = new MockHttpServletRequest(pStream,
+                pLength, contentType);
+
+        return upload.parseRequest(new ServletRequestContext(request));
+    }
+
+    private FileItemIterator parseUpload(final int pLength, final InputStream pStream)
+            throws FileUploadException, IOException {
+        final String contentType = "multipart/form-data; boundary=---1234";
+
+        final FileUploadBase upload = new ServletFileUpload();
+        upload.setFileItemFactory(new DiskFileItemFactory());
+        final HttpServletRequest request = new MockHttpServletRequest(pStream,
+                pLength, contentType);
+
+        return upload.getItemIterator(new ServletRequestContext(request));
+    }
+
     /**
      * Tests a file upload with varying file sizes.
      */
@@ -68,62 +139,6 @@ public class StreamingTest {
         assertTrue(!fileIter.hasNext());
     }
 
-    /**
-     * Tests, whether an invalid request throws a proper
-     * exception.
-     */
-    @Test
-    public void testFileUploadException()
-            throws IOException, FileUploadException {
-        final byte[] request = newRequest();
-        final byte[] invalidRequest = new byte[request.length - 11];
-        System.arraycopy(request, 0, invalidRequest, 0, request.length - 11);
-        try {
-            parseUpload(invalidRequest);
-            fail("Expected EndOfStreamException");
-        } catch (final IOFileUploadException e) {
-            assertTrue(e.getCause() instanceof MultipartStream.MalformedStreamException);
-        }
-    }
-
-    /**
-     * Tests, whether an IOException is properly delegated.
-     */
-    @Test
-    public void testIOException()
-            throws IOException {
-        final byte[] request = newRequest();
-        final InputStream stream = new FilterInputStream(new ByteArrayInputStream(request)) {
-            private int num;
-            @Override
-            public int read() throws IOException {
-                if (++num > 123) {
-                    throw new IOException("123");
-                }
-                return super.read();
-            }
-            @Override
-            public int read(final byte[] pB, final int pOff, final int pLen)
-                    throws IOException {
-                for (int i = 0;  i < pLen;  i++) {
-                    final int res = read();
-                    if (res == -1) {
-                        return i == 0 ? -1 : i;
-                    }
-                    pB[pOff + i] = (byte) res;
-                }
-                return pLen;
-            }
-        };
-        try {
-            parseUpload(stream, request.length);
-            fail("Expected IOException");
-        } catch (final FileUploadException e) {
-            assertTrue(e.getCause() instanceof IOException);
-            assertEquals("123", e.getCause().getMessage());
-        }
-    }
-
     /**
      * Test for FILEUPLOAD-135
      */
@@ -158,75 +173,22 @@ public class StreamingTest {
         assertTrue(!fileIter.hasNext());
     }
 
-    private List<FileItem> parseUpload(final byte[] bytes) throws FileUploadException {
-        return parseUpload(new ByteArrayInputStream(bytes), bytes.length);
-    }
-
-    private FileItemIterator parseUpload(final int pLength, final InputStream pStream)
-            throws FileUploadException, IOException {
-        final String contentType = "multipart/form-data; boundary=---1234";
-
-        final FileUploadBase upload = new ServletFileUpload();
-        upload.setFileItemFactory(new DiskFileItemFactory());
-        final HttpServletRequest request = new MockHttpServletRequest(pStream,
-                pLength, contentType);
-
-        return upload.getItemIterator(new ServletRequestContext(request));
-    }
-
-    private List<FileItem> parseUpload(final InputStream pStream, final int pLength)
-            throws FileUploadException {
-        final String contentType = "multipart/form-data; boundary=---1234";
-
-        final FileUploadBase upload = new ServletFileUpload();
-        upload.setFileItemFactory(new DiskFileItemFactory());
-        final HttpServletRequest request = new MockHttpServletRequest(pStream,
-                pLength, contentType);
-
-        return upload.parseRequest(new ServletRequestContext(request));
-    }
-
-    private String getHeader(final String pField) {
-        return "-----1234\r\n"
-            + "Content-Disposition: form-data; name=\"" + pField + "\"\r\n"
-            + "\r\n";
-
-    }
-
-    private String getFooter() {
-        return "-----1234--\r\n";
-    }
-
-    private byte[] newShortRequest() throws IOException {
-        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        final OutputStreamWriter osw = new OutputStreamWriter(baos, StandardCharsets.US_ASCII);
-        osw.write(getHeader("field"));
-        osw.write("123");
-        osw.write("\r\n");
-        osw.write(getFooter());
-        osw.close();
-        return baos.toByteArray();
-    }
-
-    private byte[] newRequest() throws IOException {
-        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        final OutputStreamWriter osw = new OutputStreamWriter(baos, StandardCharsets.US_ASCII);
-        int add = 16;
-        int num = 0;
-        for (int i = 0;  i < 16384;  i += add) {
-            if (++add == 32) {
-                add = 16;
-            }
-            osw.write(getHeader("field" + (num++)));
-            osw.flush();
-            for (int j = 0;  j < i;  j++) {
-                baos.write((byte) j);
-            }
-            osw.write("\r\n");
+    /**
+     * Tests, whether an invalid request throws a proper
+     * exception.
+     */
+    @Test
+    public void testFileUploadException()
+            throws IOException, FileUploadException {
+        final byte[] request = newRequest();
+        final byte[] invalidRequest = new byte[request.length - 11];
+        System.arraycopy(request, 0, invalidRequest, 0, request.length - 11);
+        try {
+            parseUpload(invalidRequest);
+            fail("Expected EndOfStreamException");
+        } catch (final IOFileUploadException e) {
+            assertTrue(e.getCause() instanceof MultipartStream.MalformedStreamException);
         }
-        osw.write(getFooter());
-        osw.close();
-        return baos.toByteArray();
     }
 
     /**
@@ -278,4 +240,42 @@ public class StreamingTest {
         }
     }
 
+    /**
+     * Tests, whether an IOException is properly delegated.
+     */
+    @Test
+    public void testIOException()
+            throws IOException {
+        final byte[] request = newRequest();
+        final InputStream stream = new FilterInputStream(new ByteArrayInputStream(request)) {
+            private int num;
+            @Override
+            public int read() throws IOException {
+                if (++num > 123) {
+                    throw new IOException("123");
+                }
+                return super.read();
+            }
+            @Override
+            public int read(final byte[] pB, final int pOff, final int pLen)
+                    throws IOException {
+                for (int i = 0;  i < pLen;  i++) {
+                    final int res = read();
+                    if (res == -1) {
+                        return i == 0 ? -1 : i;
+                    }
+                    pB[pOff + i] = (byte) res;
+                }
+                return pLen;
+            }
+        };
+        try {
+            parseUpload(stream, request.length);
+            fail("Expected IOException");
+        } catch (final FileUploadException e) {
+            assertTrue(e.getCause() instanceof IOException);
+            assertEquals("123", e.getCause().getMessage());
+        }
+    }
+
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/Util.java b/src/test/java/org/apache/commons/fileupload2/Util.java
index 19b85fb..9b3aa24 100644
--- a/src/test/java/org/apache/commons/fileupload2/Util.java
+++ b/src/test/java/org/apache/commons/fileupload2/Util.java
@@ -35,6 +35,16 @@ import org.apache.commons.fileupload2.servlet.ServletRequestContext;
  */
 public class Util {
 
+    /**
+     * Return a list of {@link FileUpload} implementations for parameterized tests.
+     * @return a list of {@link FileUpload} implementations
+     */
+    public static List<FileUpload> fileUploadImplementations() {
+        return Arrays.asList(
+                new ServletFileUpload(new DiskFileItemFactory()),
+                new PortletFileUpload(new DiskFileItemFactory()));
+    }
+
     public static List<FileItem> parseUpload(final FileUpload upload, final byte[] bytes) throws FileUploadException {
         return parseUpload(upload, bytes, Constants.CONTENT_TYPE);
     }
@@ -50,14 +60,4 @@ public class Util {
         final byte[] bytes = content.getBytes(StandardCharsets.US_ASCII);
         return parseUpload(upload, bytes, Constants.CONTENT_TYPE);
     }
-
-    /**
-     * Return a list of {@link FileUpload} implementations for parameterized tests.
-     * @return a list of {@link FileUpload} implementations
-     */
-    public static List<FileUpload> fileUploadImplementations() {
-        return Arrays.asList(
-                new ServletFileUpload(new DiskFileItemFactory()),
-                new PortletFileUpload(new DiskFileItemFactory()));
-    }
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUploadTest.java b/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUploadTest.java
index f1efb16..db0eb55 100644
--- a/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUploadTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUploadTest.java
@@ -39,6 +39,29 @@ import org.junit.jupiter.api.Test;
  */
 public class JakSrvltFileUploadTest {
 
+    @Test
+    public void parseImpliedUtf8()
+        throws Exception {
+        // utf8 encoded form-data without explicit content-type encoding
+        final String text = "-----1234\r\n" +
+                "Content-Disposition: form-data; name=\"utf8Html\"\r\n" +
+                "\r\n" +
+                "Thís ís the coñteñt of the fíle\n" +
+                "\r\n" +
+                "-----1234--\r\n";
+
+        final byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
+        final HttpServletRequest request = new MockJakSrvltHttpRequest(bytes, Constants.CONTENT_TYPE);
+
+        final DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
+        fileItemFactory.setDefaultCharset("UTF-8");
+        final JakSrvltFileUpload upload = new JakSrvltFileUpload(fileItemFactory);
+        final List<FileItem> fileItems = upload.parseRequest(request);
+        final FileItem fileItem = fileItems.get(0);
+        assertTrue(fileItem.getString().contains("coñteñt"), fileItem.getString());
+    }
+
+
     /**
      * Test case for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-210">
      */
@@ -78,27 +101,4 @@ public class JakSrvltFileUploadTest {
         assertTrue(mappedParameters.containsKey("multi"));
         assertEquals(2, mappedParameters.get("multi").size());
     }
-
-
-    @Test
-    public void parseImpliedUtf8()
-        throws Exception {
-        // utf8 encoded form-data without explicit content-type encoding
-        final String text = "-----1234\r\n" +
-                "Content-Disposition: form-data; name=\"utf8Html\"\r\n" +
-                "\r\n" +
-                "Thís ís the coñteñt of the fíle\n" +
-                "\r\n" +
-                "-----1234--\r\n";
-
-        final byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
-        final HttpServletRequest request = new MockJakSrvltHttpRequest(bytes, Constants.CONTENT_TYPE);
-
-        final DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
-        fileItemFactory.setDefaultCharset("UTF-8");
-        final JakSrvltFileUpload upload = new JakSrvltFileUpload(fileItemFactory);
-        final List<FileItem> fileItems = upload.parseRequest(request);
-        final FileItem fileItem = fileItems.get(0);
-        assertTrue(fileItem.getString().contains("coñteñt"), fileItem.getString());
-    }
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/jaksrvlt/MockJakSrvltHttpRequest.java b/src/test/java/org/apache/commons/fileupload2/jaksrvlt/MockJakSrvltHttpRequest.java
index 31ecaec..fe4e230 100644
--- a/src/test/java/org/apache/commons/fileupload2/jaksrvlt/MockJakSrvltHttpRequest.java
+++ b/src/test/java/org/apache/commons/fileupload2/jaksrvlt/MockJakSrvltHttpRequest.java
@@ -48,6 +48,51 @@ import jakarta.servlet.http.Part;
 
 public class MockJakSrvltHttpRequest implements HttpServletRequest {
 
+    private static class MyServletInputStream
+        extends jakarta.servlet.ServletInputStream {
+
+        private final InputStream in;
+        private final int readLimit;
+
+        /**
+         * Creates a new instance, which returns the given
+         * streams data.
+         */
+        public MyServletInputStream(final InputStream pStream, final int readLimit) {
+            in = pStream;
+            this.readLimit = readLimit;
+        }
+
+        @Override
+        public boolean isFinished() {
+            return false;
+        }
+
+        @Override
+        public boolean isReady() {
+            return false;
+        }
+
+        @Override
+        public int read() throws IOException {
+            return in.read();
+        }
+
+        @Override
+        public int read(final byte[] b, final int off, final int len) throws IOException {
+            if (readLimit > 0) {
+                return in.read(b, off, Math.min(readLimit, len));
+            }
+            return in.read(b, off, len);
+        }
+
+        @Override
+        public void setReadListener(final ReadListener readListener) {
+            throw new IllegalStateException("Not implemented");
+        }
+
+    }
+
     private final InputStream mRequestData;
 
     private long length;
@@ -83,329 +128,355 @@ public class MockJakSrvltHttpRequest implements HttpServletRequest {
         mHeaders.put(FileUploadBase.CONTENT_TYPE, strContentType);
     }
 
-    /**
-     * @see javax.servlet.http.HttpServletRequest#getAuthType()
-     */
     @Override
-    public String getAuthType() {
+    public boolean authenticate(final HttpServletResponse response) throws IOException, ServletException {
+        return false;
+    }
+
+    @Override
+    public String changeSessionId() {
+        return null;
+    }
+
+    @Override
+    public AsyncContext getAsyncContext() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getCookies()
+     * @see javax.servlet.ServletRequest#getAttribute(String)
      */
     @Override
-    public Cookie[] getCookies() {
+    public Object getAttribute(final String arg0) {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getDateHeader(String)
+     * @see javax.servlet.ServletRequest#getAttributeNames()
      */
     @Override
-    public long getDateHeader(final String arg0) {
-        return 0;
+    public Enumeration<String> getAttributeNames() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getHeader(String)
+     * @see javax.servlet.http.HttpServletRequest#getAuthType()
      */
     @Override
-    public String getHeader(final String headerName) {
-        return mHeaders.get(headerName);
+    public String getAuthType() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getHeaders(String)
+     * @see javax.servlet.ServletRequest#getCharacterEncoding()
      */
     @Override
-    public Enumeration<String> getHeaders(final String arg0) {
-        // todo - implement
+    public String getCharacterEncoding() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getHeaderNames()
+     * @see javax.servlet.ServletRequest#getContentLength()
      */
     @Override
-    public Enumeration<String> getHeaderNames() {
-        // todo - implement
-        return null;
+    public int getContentLength() {
+        int iLength;
+
+        if (null == mRequestData) {
+            iLength = -1;
+        } else {
+            if (length > Integer.MAX_VALUE) {
+                throw new RuntimeException("Value '" + length + "' is too large to be converted to int");
+            }
+            iLength = (int) length;
+        }
+        return iLength;
+    }
+
+    @Override
+    public long getContentLengthLong() {
+        return getContentLength();
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getIntHeader(String)
+     * @see javax.servlet.ServletRequest#getContentType()
      */
     @Override
-    public int getIntHeader(final String arg0) {
-        return 0;
+    public String getContentType() {
+        return mStrContentType;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getMethod()
+     * @see javax.servlet.http.HttpServletRequest#getContextPath()
      */
     @Override
-    public String getMethod() {
+    public String getContextPath() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getPathInfo()
+     * @see javax.servlet.http.HttpServletRequest#getCookies()
      */
     @Override
-    public String getPathInfo() {
+    public Cookie[] getCookies() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getPathTranslated()
+     * @see javax.servlet.http.HttpServletRequest#getDateHeader(String)
      */
     @Override
-    public String getPathTranslated() {
+    public long getDateHeader(final String arg0) {
+        return 0;
+    }
+
+    @Override
+    public DispatcherType getDispatcherType() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getContextPath()
+     * @see javax.servlet.http.HttpServletRequest#getHeader(String)
      */
     @Override
-    public String getContextPath() {
-        return null;
+    public String getHeader(final String headerName) {
+        return mHeaders.get(headerName);
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getQueryString()
+     * @see javax.servlet.http.HttpServletRequest#getHeaderNames()
      */
     @Override
-    public String getQueryString() {
+    public Enumeration<String> getHeaderNames() {
+        // todo - implement
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getRemoteUser()
+     * @see javax.servlet.http.HttpServletRequest#getHeaders(String)
      */
     @Override
-    public String getRemoteUser() {
+    public Enumeration<String> getHeaders(final String arg0) {
+        // todo - implement
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#isUserInRole(String)
+     * @see javax.servlet.ServletRequest#getInputStream()
      */
     @Override
-    public boolean isUserInRole(final String arg0) {
-        return false;
+    public ServletInputStream getInputStream() throws IOException {
+        return new MyServletInputStream(mRequestData, readLimit);
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
+     * @see javax.servlet.http.HttpServletRequest#getIntHeader(String)
      */
     @Override
-    public Principal getUserPrincipal() {
-        return null;
+    public int getIntHeader(final String arg0) {
+        return 0;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getRequestedSessionId()
+     * @see javax.servlet.ServletRequest#getLocalAddr()
      */
     @Override
-    public String getRequestedSessionId() {
+    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
+    public String getLocalAddr() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getRequestURI()
+     * @see javax.servlet.ServletRequest#getLocale()
      */
     @Override
-    public String getRequestURI() {
+    public Locale getLocale() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getRequestURL()
+     * @see javax.servlet.ServletRequest#getLocales()
      */
     @Override
-    public StringBuffer getRequestURL() {
+    public Enumeration<Locale> getLocales() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getServletPath()
+     * @see javax.servlet.ServletRequest#getLocalName()
      */
     @Override
-    public String getServletPath() {
+    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
+    public String getLocalName() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getSession(boolean)
+     * @see javax.servlet.ServletRequest#getLocalPort()
      */
     @Override
-    public HttpSession getSession(final boolean arg0) {
-        return null;
+    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
+    public int getLocalPort() {
+        return 0;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#getSession()
+     * @see javax.servlet.http.HttpServletRequest#getMethod()
      */
     @Override
-    public HttpSession getSession() {
+    public String getMethod() {
         return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid()
+     * @see javax.servlet.ServletRequest#getParameter(String)
      */
     @Override
-    public boolean isRequestedSessionIdValid() {
-        return false;
+    public String getParameter(final String arg0) {
+        return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromCookie()
+     * @see javax.servlet.ServletRequest#getParameterMap()
      */
     @Override
-    public boolean isRequestedSessionIdFromCookie() {
-        return false;
+    public Map<String, String[]> getParameterMap() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromURL()
+     * @see javax.servlet.ServletRequest#getParameterNames()
      */
     @Override
-    public boolean isRequestedSessionIdFromURL() {
-        return false;
+    public Enumeration<String> getParameterNames() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromUrl()
-     * @deprecated
+     * @see javax.servlet.ServletRequest#getParameterValues(String)
      */
     @Override
-    @Deprecated
-    public boolean isRequestedSessionIdFromUrl() {
-        return false;
+    public String[] getParameterValues(final String arg0) {
+        return null;
     }
 
-    /**
-     * @see javax.servlet.ServletRequest#getAttribute(String)
-     */
     @Override
-    public Object getAttribute(final String arg0) {
+    public Part getPart(final String name) throws IOException, ServletException {
+        return null;
+    }
+
+    @Override
+    public Collection<Part> getParts() throws IOException, ServletException {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getAttributeNames()
+     * @see javax.servlet.http.HttpServletRequest#getPathInfo()
      */
     @Override
-    public Enumeration<String> getAttributeNames() {
+    public String getPathInfo() {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getCharacterEncoding()
+     * @see javax.servlet.http.HttpServletRequest#getPathTranslated()
      */
     @Override
-    public String getCharacterEncoding() {
+    public String getPathTranslated() {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#setCharacterEncoding(String)
+     * @see javax.servlet.ServletRequest#getProtocol()
      */
     @Override
-    public void setCharacterEncoding(final String arg0)
-        throws UnsupportedEncodingException {
+    public String getProtocol() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getContentLength()
+     * @see javax.servlet.http.HttpServletRequest#getQueryString()
      */
     @Override
-    public int getContentLength() {
-        int iLength;
-
-        if (null == mRequestData) {
-            iLength = -1;
-        } else {
-            if (length > Integer.MAX_VALUE) {
-                throw new RuntimeException("Value '" + length + "' is too large to be converted to int");
-            }
-            iLength = (int) length;
-        }
-        return iLength;
+    public String getQueryString() {
+        return null;
     }
 
     /**
-     * For testing attack scenarios in SizesTest.
+     * @see javax.servlet.ServletRequest#getReader()
      */
-    public void setContentLength(final long length) {
-        this.length = length;
+    @Override
+    public BufferedReader getReader() throws IOException {
+        return null;
+    }
+
+    @Override
+    public String getRealPath(final String path) {
+        return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getContentType()
+     * @see javax.servlet.ServletRequest#getRemoteAddr()
      */
     @Override
-    public String getContentType() {
-        return mStrContentType;
+    public String getRemoteAddr() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getInputStream()
+     * @see javax.servlet.ServletRequest#getRemoteHost()
      */
     @Override
-    public ServletInputStream getInputStream() throws IOException {
-        return new MyServletInputStream(mRequestData, readLimit);
+    public String getRemoteHost() {
+        return null;
     }
 
     /**
-     * Sets the read limit. This can be used to limit the number of bytes to read ahead.
-     *
-     * @param readLimit the read limit to use
+     * @see javax.servlet.ServletRequest#getRemotePort()
      */
-    public void setReadLimit(final int readLimit) {
-        this.readLimit = readLimit;
+    @Override
+    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
+    public int getRemotePort() {
+        return 0;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getParameter(String)
+     * @see javax.servlet.http.HttpServletRequest#getRemoteUser()
      */
     @Override
-    public String getParameter(final String arg0) {
+    public String getRemoteUser() {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getParameterNames()
+     * @see javax.servlet.ServletRequest#getRequestDispatcher(String)
      */
     @Override
-    public Enumeration<String> getParameterNames() {
+    public RequestDispatcher getRequestDispatcher(final String arg0) {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getParameterValues(String)
+     * @see javax.servlet.http.HttpServletRequest#getRequestedSessionId()
      */
     @Override
-    public String[] getParameterValues(final String arg0) {
+    public String getRequestedSessionId() {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getParameterMap()
+     * @see javax.servlet.http.HttpServletRequest#getRequestURI()
      */
     @Override
-    public Map<String, String[]> getParameterMap() {
+    public String getRequestURI() {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getProtocol()
+     * @see javax.servlet.http.HttpServletRequest#getRequestURL()
      */
     @Override
-    public String getProtocol() {
+    public StringBuffer getRequestURL() {
         return null;
     }
 
@@ -425,15 +496,6 @@ public class MockJakSrvltHttpRequest implements HttpServletRequest {
         return null;
     }
 
-    /**
-     * @see javax.servlet.ServletRequest#getLocalName()
-     */
-    @Override
-    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
-    public String getLocalName() {
-        return null;
-    }
-
     /**
      * @see javax.servlet.ServletRequest#getServerPort()
      */
@@ -442,85 +504,89 @@ public class MockJakSrvltHttpRequest implements HttpServletRequest {
         return 0;
     }
 
-    /**
-     * @see javax.servlet.ServletRequest#getLocalPort()
-     */
     @Override
-    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
-    public int getLocalPort() {
-        return 0;
+    public ServletContext getServletContext() {
+        final HttpSession session = getSession();
+        if (session == null) {
+            return null;
+        }
+      return session.getServletContext();
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getRemotePort()
+     * @see javax.servlet.http.HttpServletRequest#getServletPath()
      */
     @Override
-    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
-    public int getRemotePort() {
-        return 0;
+    public String getServletPath() {
+        return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getReader()
+     * @see javax.servlet.http.HttpServletRequest#getSession()
      */
     @Override
-    public BufferedReader getReader() throws IOException {
+    public HttpSession getSession() {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getRemoteAddr()
+     * @see javax.servlet.http.HttpServletRequest#getSession(boolean)
      */
     @Override
-    public String getRemoteAddr() {
+    public HttpSession getSession(final boolean arg0) {
         return null;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getLocalAddr()
+     * @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
      */
     @Override
-    @SuppressWarnings("javadoc") // This is a Servlet 2.4 method
-    public String getLocalAddr() {
+    public Principal getUserPrincipal() {
         return null;
     }
 
-    /**
-     * @see javax.servlet.ServletRequest#getRemoteHost()
-     */
     @Override
-    public String getRemoteHost() {
-        return null;
+    public boolean isAsyncStarted() {
+        return false;
+    }
+
+    @Override
+    public boolean isAsyncSupported() {
+        return false;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#setAttribute(String, Object)
+     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromCookie()
      */
     @Override
-    public void setAttribute(final String arg0, final Object arg1) {
+    public boolean isRequestedSessionIdFromCookie() {
+        return false;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#removeAttribute(String)
+     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromUrl()
+     * @deprecated
      */
     @Override
-    public void removeAttribute(final String arg0) {
+    @Deprecated
+    public boolean isRequestedSessionIdFromUrl() {
+        return false;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getLocale()
+     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromURL()
      */
     @Override
-    public Locale getLocale() {
-        return null;
+    public boolean isRequestedSessionIdFromURL() {
+        return false;
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getLocales()
+     * @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid()
      */
     @Override
-    public Enumeration<Locale> getLocales() {
-        return null;
+    public boolean isRequestedSessionIdValid() {
+        return false;
     }
 
     /**
@@ -532,140 +598,74 @@ public class MockJakSrvltHttpRequest implements HttpServletRequest {
     }
 
     /**
-     * @see javax.servlet.ServletRequest#getRequestDispatcher(String)
+     * @see javax.servlet.http.HttpServletRequest#isUserInRole(String)
      */
     @Override
-    public RequestDispatcher getRequestDispatcher(final String arg0) {
-        return null;
-    }
-
-    private static class MyServletInputStream
-        extends jakarta.servlet.ServletInputStream {
-
-        private final InputStream in;
-        private final int readLimit;
-
-        /**
-         * Creates a new instance, which returns the given
-         * streams data.
-         */
-        public MyServletInputStream(final InputStream pStream, final int readLimit) {
-            in = pStream;
-            this.readLimit = readLimit;
-        }
-
-        @Override
-        public int read() throws IOException {
-            return in.read();
-        }
-
-        @Override
-        public int read(final byte[] b, final int off, final int len) throws IOException {
-            if (readLimit > 0) {
-                return in.read(b, off, Math.min(readLimit, len));
-            }
-            return in.read(b, off, len);
-        }
-
-        @Override
-        public boolean isFinished() {
-            return false;
-        }
-
-        @Override
-        public boolean isReady() {
-            return false;
-        }
-
-        @Override
-        public void setReadListener(final ReadListener readListener) {
-            throw new IllegalStateException("Not implemented");
-        }
-
-    }
-
-    @Override
-    public long getContentLengthLong() {
-        return getContentLength();
-    }
-
-    @Override
-    public ServletContext getServletContext() {
-        final HttpSession session = getSession();
-        if (session == null) {
-            return null;
-        }
-      return session.getServletContext();
+    public boolean isUserInRole(final String arg0) {
+        return false;
     }
 
     @Override
-    public AsyncContext startAsync() throws IllegalStateException {
+    public void login(final String username, final String password) throws ServletException {
         throw new IllegalStateException("Not implemented");
     }
 
     @Override
-    public AsyncContext startAsync(final ServletRequest servletRequest, final ServletResponse servletResponse)
-            throws IllegalStateException {
+    public void logout() throws ServletException {
         throw new IllegalStateException("Not implemented");
     }
 
+    /**
+     * @see javax.servlet.ServletRequest#removeAttribute(String)
+     */
     @Override
-    public boolean isAsyncStarted() {
-        return false;
-    }
-
-    @Override
-    public boolean isAsyncSupported() {
-        return false;
+    public void removeAttribute(final String arg0) {
     }
 
+    /**
+     * @see javax.servlet.ServletRequest#setAttribute(String, Object)
+     */
     @Override
-    public AsyncContext getAsyncContext() {
-        return null;
+    public void setAttribute(final String arg0, final Object arg1) {
     }
 
+    /**
+     * @see javax.servlet.ServletRequest#setCharacterEncoding(String)
+     */
     @Override
-    public DispatcherType getDispatcherType() {
-        return null;
+    public void setCharacterEncoding(final String arg0)
+        throws UnsupportedEncodingException {
     }
 
-    @Override
-    public String changeSessionId() {
-        return null;
+    /**
+     * For testing attack scenarios in SizesTest.
+     */
+    public void setContentLength(final long length) {
+        this.length = length;
     }
 
-    @Override
-    public boolean authenticate(final HttpServletResponse response) throws IOException, ServletException {
-        return false;
+    /**
+     * Sets the read limit. This can be used to limit the number of bytes to read ahead.
+     *
+     * @param readLimit the read limit to use
+     */
+    public void setReadLimit(final int readLimit) {
+        this.readLimit = readLimit;
     }
 
     @Override
-    public void login(final String username, final String password) throws ServletException {
+    public AsyncContext startAsync() throws IllegalStateException {
         throw new IllegalStateException("Not implemented");
     }
 
     @Override
-    public void logout() throws ServletException {
+    public AsyncContext startAsync(final ServletRequest servletRequest, final ServletResponse servletResponse)
+            throws IllegalStateException {
         throw new IllegalStateException("Not implemented");
     }
 
-    @Override
-    public Collection<Part> getParts() throws IOException, ServletException {
-        return null;
-    }
-
-    @Override
-    public Part getPart(final String name) throws IOException, ServletException {
-        return null;
-    }
-
     @Override
     public <T extends HttpUpgradeHandler> T upgrade(final Class<T> handlerClass) throws IOException, ServletException {
         throw new IllegalStateException("Not implemented");
     }
-
-    @Override
-    public String getRealPath(final String path) {
-        return null;
-    }
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/portlet/MockPortletActionRequest.java b/src/test/java/org/apache/commons/fileupload2/portlet/MockPortletActionRequest.java
index d390caf..82d938f 100644
--- a/src/test/java/org/apache/commons/fileupload2/portlet/MockPortletActionRequest.java
+++ b/src/test/java/org/apache/commons/fileupload2/portlet/MockPortletActionRequest.java
@@ -84,6 +84,21 @@ public class MockPortletActionRequest implements ActionRequest {
         return null;
     }
 
+    @Override
+    public String getCharacterEncoding() {
+        return characterEncoding;
+    }
+
+    @Override
+    public int getContentLength() {
+        return length;
+    }
+
+    @Override
+    public String getContentType() {
+        return contentType;
+    }
+
     @Override
     public String getContextPath() {
         return null;
@@ -124,6 +139,11 @@ public class MockPortletActionRequest implements ActionRequest {
         return null;
     }
 
+    @Override
+    public InputStream getPortletInputStream() throws IOException {
+        return requestData;
+    }
+
     @Override
     public PortletMode getPortletMode() {
         return null;
@@ -159,6 +179,11 @@ public class MockPortletActionRequest implements ActionRequest {
         return null;
     }
 
+    @Override
+    public BufferedReader getReader() throws UnsupportedEncodingException, IOException {
+        return null;
+    }
+
     @Override
     public String getRemoteUser() {
         return null;
@@ -239,31 +264,6 @@ public class MockPortletActionRequest implements ActionRequest {
         attributes.put(key, value);
     }
 
-    @Override
-    public String getCharacterEncoding() {
-        return characterEncoding;
-    }
-
-    @Override
-    public int getContentLength() {
-        return length;
-    }
-
-    @Override
-    public String getContentType() {
-        return contentType;
-    }
-
-    @Override
-    public InputStream getPortletInputStream() throws IOException {
-        return requestData;
-    }
-
-    @Override
-    public BufferedReader getReader() throws UnsupportedEncodingException, IOException {
-        return null;
-    }
-
     @Override
     public void setCharacterEncoding(final String characterEncoding) throws UnsupportedEncodingException {
         this.characterEncoding = characterEncoding;
diff --git a/src/test/java/org/apache/commons/fileupload2/portlet/PortletFileUploadTest.java b/src/test/java/org/apache/commons/fileupload2/portlet/PortletFileUploadTest.java
index a4db94c..311c737 100644
--- a/src/test/java/org/apache/commons/fileupload2/portlet/PortletFileUploadTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/portlet/PortletFileUploadTest.java
@@ -42,11 +42,6 @@ public class PortletFileUploadTest {
 
     private PortletFileUpload upload;
 
-    @BeforeEach
-    public void setUp() {
-        upload = new PortletFileUpload(new DiskFileItemFactory());
-    }
-
     @Test
     public void parseParameterMap()
             throws Exception {
@@ -83,4 +78,9 @@ public class PortletFileUploadTest {
         assertEquals(2, mappedParameters.get("multi").size());
     }
 
+    @BeforeEach
+    public void setUp() {
+        upload = new PortletFileUpload(new DiskFileItemFactory());
+    }
+
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/servlet/ServletFileUploadTest.java b/src/test/java/org/apache/commons/fileupload2/servlet/ServletFileUploadTest.java
index 769bf13..f683a1b 100644
--- a/src/test/java/org/apache/commons/fileupload2/servlet/ServletFileUploadTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/servlet/ServletFileUploadTest.java
@@ -40,6 +40,29 @@ import org.junit.jupiter.api.Test;
  */
 public class ServletFileUploadTest {
 
+    @Test
+    public void parseImpliedUtf8()
+        throws Exception {
+        // utf8 encoded form-data without explicit content-type encoding
+        final String text = "-----1234\r\n" +
+                "Content-Disposition: form-data; name=\"utf8Html\"\r\n" +
+                "\r\n" +
+                "Thís ís the coñteñt of the fíle\n" +
+                "\r\n" +
+                "-----1234--\r\n";
+
+        final byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
+        final HttpServletRequest request = new MockHttpServletRequest(bytes, Constants.CONTENT_TYPE);
+
+        final DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
+        fileItemFactory.setDefaultCharset("UTF-8");
+        final ServletFileUpload upload = new ServletFileUpload(fileItemFactory);
+        final List<FileItem> fileItems = upload.parseRequest(request);
+        final FileItem fileItem = fileItems.get(0);
+        assertTrue(fileItem.getString().contains("coñteñt"), fileItem.getString());
+    }
+
+
     /**
      * Test case for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-210">
      */
@@ -79,27 +102,4 @@ public class ServletFileUploadTest {
         assertTrue(mappedParameters.containsKey("multi"));
         assertEquals(2, mappedParameters.get("multi").size());
     }
-
-
-    @Test
-    public void parseImpliedUtf8()
-        throws Exception {
-        // utf8 encoded form-data without explicit content-type encoding
-        final String text = "-----1234\r\n" +
-                "Content-Disposition: form-data; name=\"utf8Html\"\r\n" +
-                "\r\n" +
-                "Thís ís the coñteñt of the fíle\n" +
-                "\r\n" +
-                "-----1234--\r\n";
-
-        final byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
-        final HttpServletRequest request = new MockHttpServletRequest(bytes, Constants.CONTENT_TYPE);
-
-        final DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
-        fileItemFactory.setDefaultCharset("UTF-8");
-        final ServletFileUpload upload = new ServletFileUpload(fileItemFactory);
-        final List<FileItem> fileItems = upload.parseRequest(request);
-        final FileItem fileItem = fileItems.get(0);
-        assertTrue(fileItem.getString().contains("coñteñt"), fileItem.getString());
-    }
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/util/mime/Base64DecoderTestCase.java b/src/test/java/org/apache/commons/fileupload2/util/mime/Base64DecoderTestCase.java
index 5becdf0..857bd90 100644
--- a/src/test/java/org/apache/commons/fileupload2/util/mime/Base64DecoderTestCase.java
+++ b/src/test/java/org/apache/commons/fileupload2/util/mime/Base64DecoderTestCase.java
@@ -33,58 +33,51 @@ import org.junit.jupiter.api.Test;
  */
 public final class Base64DecoderTestCase {
 
-    /**
-     * Tests RFC 4648 section 10 test vectors.
-     * <ul>
-     * <li>BASE64("") = ""</li>
-     * <li>BASE64("f") = "Zg=="</li>
-     * <li>BASE64("fo") = "Zm8="</li>
-     * <li>BASE64("foo") = "Zm9v"</li>
-     * <li>BASE64("foob") = "Zm9vYg=="</li>
-     * <li>BASE64("fooba") = "Zm9vYmE="</li>
-     * <li>BASE64("foobar") = "Zm9vYmFy"</li>
-     * </ul>
-     *
-     * @see <a href="http://tools.ietf.org/html/rfc4648">http://tools.ietf.org/html/rfc4648</a>
-     */
-    @Test
-    public void rfc4648Section10Decode() throws Exception {
-        assertEncoded("", "");
-        assertEncoded("f", "Zg==");
-        assertEncoded("fo", "Zm8=");
-        assertEncoded("foo", "Zm9v");
-        assertEncoded("foob", "Zm9vYg==");
-        assertEncoded("fooba", "Zm9vYmE=");
-        assertEncoded("foobar", "Zm9vYmFy");
+    private static void assertEncoded(final String clearText, final String encoded) throws Exception {
+        final byte[] expected = clearText.getBytes(StandardCharsets.US_ASCII);
+
+        final ByteArrayOutputStream out = new ByteArrayOutputStream(encoded.length());
+        final byte[] encodedData = encoded.getBytes(StandardCharsets.US_ASCII);
+        Base64Decoder.decode(encodedData, out);
+        final byte[] actual = out.toByteArray();
+
+        assertArrayEquals(expected, actual);
     }
 
-    /**
-     * Test our decode with pad character in the middle.
-     * Continues provided that the padding is in the correct place,
-     * i.e. concatenated valid strings decode OK.
-     */
+    private static void assertIOException(final String messageText, final String encoded)
+            throws UnsupportedEncodingException {
+        final ByteArrayOutputStream out = new ByteArrayOutputStream(encoded.length());
+        final byte[] encodedData = encoded.getBytes(StandardCharsets.US_ASCII);
+        try {
+            Base64Decoder.decode(encodedData, out);
+            fail("Expected IOException");
+        } catch (final IOException e) {
+            final String em = e.getMessage();
+            assertTrue(em.contains(messageText), "Expected to find " + messageText + " in '" + em + "'");
+        }
+    }
+
+    // This input causes java.lang.ArrayIndexOutOfBoundsException: 1
+    // in the Java 6 method DatatypeConverter.parseBase64Binary(String)
+    // currently reported as truncated (the last chunk consists just of '=')
     @Test
-    public void decodeWithInnerPad() throws Exception {
-        assertEncoded("Hello WorldHello World", "SGVsbG8gV29ybGQ=SGVsbG8gV29ybGQ=");
+    public void badLength() throws Exception {
+        assertIOException("truncated", "Zm8==");
     }
 
-    /**
-     * Ignores non-BASE64 bytes.
-     */
     @Test
-    public void nonBase64Bytes() throws Exception {
-        assertEncoded("Hello World", "S?G!V%sbG 8g\rV\t\n29ybGQ*=");
+    public void badPadding() throws Exception {
+        assertIOException("incorrect padding, 4th byte", "Zg=a");
     }
 
     @Test
-    public void truncatedString() {
-        final byte[] x = {'n'};
-        assertThrows(IOException.class, () -> Base64Decoder.decode(x, new ByteArrayOutputStream()));
+    public void badPaddingLeading1() throws Exception {
+        assertIOException("incorrect padding, first two bytes cannot be padding", "=A==");
     }
 
     @Test
-    public void decodeTrailingJunk() throws Exception {
-        assertEncoded("foobar", "Zm9vYmFy!!!");
+    public void badPaddingLeading2() throws Exception {
+        assertIOException("incorrect padding, first two bytes cannot be padding", "====");
     }
 
     // If there are valid trailing Base64 chars, complain
@@ -106,26 +99,18 @@ public final class Base64DecoderTestCase {
     }
 
     @Test
-    public void badPadding() throws Exception {
-        assertIOException("incorrect padding, 4th byte", "Zg=a");
-    }
-
-    @Test
-    public void badPaddingLeading1() throws Exception {
-        assertIOException("incorrect padding, first two bytes cannot be padding", "=A==");
-    }
-
-    @Test
-    public void badPaddingLeading2() throws Exception {
-        assertIOException("incorrect padding, first two bytes cannot be padding", "====");
+    public void decodeTrailingJunk() throws Exception {
+        assertEncoded("foobar", "Zm9vYmFy!!!");
     }
 
-    // This input causes java.lang.ArrayIndexOutOfBoundsException: 1
-    // in the Java 6 method DatatypeConverter.parseBase64Binary(String)
-    // currently reported as truncated (the last chunk consists just of '=')
+    /**
+     * Test our decode with pad character in the middle.
+     * Continues provided that the padding is in the correct place,
+     * i.e. concatenated valid strings decode OK.
+     */
     @Test
-    public void badLength() throws Exception {
-        assertIOException("truncated", "Zm8==");
+    public void decodeWithInnerPad() throws Exception {
+        assertEncoded("Hello WorldHello World", "SGVsbG8gV29ybGQ=SGVsbG8gV29ybGQ=");
     }
 
     // These inputs cause java.lang.ArrayIndexOutOfBoundsException
@@ -137,28 +122,43 @@ public final class Base64DecoderTestCase {
         assertEncoded("f", "Zg=\u0100=");
     }
 
-    private static void assertEncoded(final String clearText, final String encoded) throws Exception {
-        final byte[] expected = clearText.getBytes(StandardCharsets.US_ASCII);
-
-        final ByteArrayOutputStream out = new ByteArrayOutputStream(encoded.length());
-        final byte[] encodedData = encoded.getBytes(StandardCharsets.US_ASCII);
-        Base64Decoder.decode(encodedData, out);
-        final byte[] actual = out.toByteArray();
+    /**
+     * Ignores non-BASE64 bytes.
+     */
+    @Test
+    public void nonBase64Bytes() throws Exception {
+        assertEncoded("Hello World", "S?G!V%sbG 8g\rV\t\n29ybGQ*=");
+    }
 
-        assertArrayEquals(expected, actual);
+    /**
+     * Tests RFC 4648 section 10 test vectors.
+     * <ul>
+     * <li>BASE64("") = ""</li>
+     * <li>BASE64("f") = "Zg=="</li>
+     * <li>BASE64("fo") = "Zm8="</li>
+     * <li>BASE64("foo") = "Zm9v"</li>
+     * <li>BASE64("foob") = "Zm9vYg=="</li>
+     * <li>BASE64("fooba") = "Zm9vYmE="</li>
+     * <li>BASE64("foobar") = "Zm9vYmFy"</li>
+     * </ul>
+     *
+     * @see <a href="http://tools.ietf.org/html/rfc4648">http://tools.ietf.org/html/rfc4648</a>
+     */
+    @Test
+    public void rfc4648Section10Decode() throws Exception {
+        assertEncoded("", "");
+        assertEncoded("f", "Zg==");
+        assertEncoded("fo", "Zm8=");
+        assertEncoded("foo", "Zm9v");
+        assertEncoded("foob", "Zm9vYg==");
+        assertEncoded("fooba", "Zm9vYmE=");
+        assertEncoded("foobar", "Zm9vYmFy");
     }
 
-    private static void assertIOException(final String messageText, final String encoded)
-            throws UnsupportedEncodingException {
-        final ByteArrayOutputStream out = new ByteArrayOutputStream(encoded.length());
-        final byte[] encodedData = encoded.getBytes(StandardCharsets.US_ASCII);
-        try {
-            Base64Decoder.decode(encodedData, out);
-            fail("Expected IOException");
-        } catch (final IOException e) {
-            final String em = e.getMessage();
-            assertTrue(em.contains(messageText), "Expected to find " + messageText + " in '" + em + "'");
-        }
+    @Test
+    public void truncatedString() {
+        final byte[] x = {'n'};
+        assertThrows(IOException.class, () -> Base64Decoder.decode(x, new ByteArrayOutputStream()));
     }
 
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/util/mime/MimeUtilityTestCase.java b/src/test/java/org/apache/commons/fileupload2/util/mime/MimeUtilityTestCase.java
index 8043c86..c5f9d2b 100644
--- a/src/test/java/org/apache/commons/fileupload2/util/mime/MimeUtilityTestCase.java
+++ b/src/test/java/org/apache/commons/fileupload2/util/mime/MimeUtilityTestCase.java
@@ -31,19 +31,13 @@ import org.junit.jupiter.api.Test;
  */
 public final class MimeUtilityTestCase {
 
-    @Test
-    public void noNeedToDecode() throws Exception {
-        assertEncoded("abc", "abc");
-    }
-
-    @Test
-    public void decodeUtf8QuotedPrintableEncoded() throws Exception {
-        assertEncoded(" h\u00e9! \u00e0\u00e8\u00f4u !!!", "=?UTF-8?Q?_h=C3=A9!_=C3=A0=C3=A8=C3=B4u_!!!?=");
+    private static void assertEncoded(final String expected, final String encoded) throws Exception {
+        assertEquals(expected, MimeUtility.decodeText(encoded));
     }
 
     @Test
-    public void decodeUtf8Base64Encoded() throws Exception {
-        assertEncoded(" h\u00e9! \u00e0\u00e8\u00f4u !!!", "=?UTF-8?B?IGjDqSEgw6DDqMO0dSAhISE=?=");
+    public void decodeInvalidEncoding() {
+        assertThrows(UnsupportedEncodingException.class, () -> MimeUtility.decodeText("=?invalid?B?xyz-?="));
     }
 
     @Test
@@ -60,12 +54,18 @@ public final class MimeUtilityTestCase {
                       + "2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=\"\r\n");
     }
 
-    private static void assertEncoded(final String expected, final String encoded) throws Exception {
-        assertEquals(expected, MimeUtility.decodeText(encoded));
+    @Test
+    public void decodeUtf8Base64Encoded() throws Exception {
+        assertEncoded(" h\u00e9! \u00e0\u00e8\u00f4u !!!", "=?UTF-8?B?IGjDqSEgw6DDqMO0dSAhISE=?=");
     }
 
     @Test
-    public void decodeInvalidEncoding() {
-        assertThrows(UnsupportedEncodingException.class, () -> MimeUtility.decodeText("=?invalid?B?xyz-?="));
+    public void decodeUtf8QuotedPrintableEncoded() throws Exception {
+        assertEncoded(" h\u00e9! \u00e0\u00e8\u00f4u !!!", "=?UTF-8?Q?_h=C3=A9!_=C3=A0=C3=A8=C3=B4u_!!!?=");
+    }
+
+    @Test
+    public void noNeedToDecode() throws Exception {
+        assertEncoded("abc", "abc");
     }
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoderTestCase.java b/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoderTestCase.java
index fe135fb..8e4df90 100644
--- a/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoderTestCase.java
+++ b/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoderTestCase.java
@@ -33,16 +33,28 @@ import org.junit.jupiter.api.Test;
  */
 public final class QuotedPrintableDecoderTestCase {
 
-    @Test
-    public void emptyDecode() throws Exception {
-        assertEncoded("", "");
+    private static void assertEncoded(final String clearText, final String encoded) throws Exception {
+        final byte[] expected = clearText.getBytes(StandardCharsets.US_ASCII);
+
+        final ByteArrayOutputStream out = new ByteArrayOutputStream(encoded.length());
+        final byte[] encodedData = encoded.getBytes(StandardCharsets.US_ASCII);
+        QuotedPrintableDecoder.decode(encodedData, out);
+        final byte[] actual = out.toByteArray();
+
+        assertArrayEquals(expected, actual);
     }
 
-    @Test
-    public void plainDecode() throws Exception {
-        // spaces are allowed in encoded data
-        // There are special rules for trailing spaces; these are not currently implemented.
-        assertEncoded("The quick brown fox jumps over the lazy dog.", "The quick brown fox jumps over the lazy dog.");
+    private static void assertIOException(final String messageText, final String encoded)
+            throws UnsupportedEncodingException {
+        final ByteArrayOutputStream out = new ByteArrayOutputStream(encoded.length());
+        final byte[] encodedData = encoded.getBytes(StandardCharsets.US_ASCII);
+        try {
+            QuotedPrintableDecoder.decode(encodedData, out);
+            fail("Expected IOException");
+        } catch (final IOException e) {
+            final String em = e.getMessage();
+            assertTrue(em.contains(messageText), "Expected to find " + messageText + " in '" + em + "'");
+        }
     }
 
     @Test
@@ -50,24 +62,36 @@ public final class QuotedPrintableDecoderTestCase {
         assertEncoded("= Hello there =\r\n", "=3D Hello there =3D=0D=0A");
     }
 
+    @Test
+    public void emptyDecode() throws Exception {
+        assertEncoded("", "");
+    }
+
+    @Test
+    public void invalidCharDecode() {
+        assertThrows(IOException.class, () -> assertEncoded("=\r\n", "=3D=XD=XA"));
+    }
+
     @Test
     public void invalidQuotedPrintableEncoding() throws Exception {
         assertIOException("truncated escape sequence", "YWJjMTIzXy0uKn4hQCMkJV4mKCkre31cIlxcOzpgLC9bXQ==");
     }
 
     @Test
-    public void unsafeDecode() throws Exception {
-        assertEncoded("=\r\n", "=3D=0D=0A");
+    public void invalidSoftBreak1() throws Exception {
+        assertIOException("CR must be followed by LF", "=\r\r");
     }
 
     @Test
-    public void unsafeDecodeLowerCase() throws Exception {
-        assertEncoded("=\r\n", "=3d=0d=0a");
+    public void invalidSoftBreak2() throws Exception {
+        assertIOException("CR must be followed by LF", "=\rn");
     }
 
     @Test
-    public void invalidCharDecode() {
-        assertThrows(IOException.class, () -> assertEncoded("=\r\n", "=3D=XD=XA"));
+    public void plainDecode() throws Exception {
+        // spaces are allowed in encoded data
+        // There are special rules for trailing spaces; these are not currently implemented.
+        assertEncoded("The quick brown fox jumps over the lazy dog.", "The quick brown fox jumps over the lazy dog.");
     }
 
     /**
@@ -83,43 +107,19 @@ public final class QuotedPrintableDecoderTestCase {
                         + "surely=20=\r\nmathematics is the most beautiful branch of philosophy.");
     }
 
-    @Test
-    public void invalidSoftBreak1() throws Exception {
-        assertIOException("CR must be followed by LF", "=\r\r");
-    }
-
-    @Test
-    public void invalidSoftBreak2() throws Exception {
-        assertIOException("CR must be followed by LF", "=\rn");
-    }
-
     @Test
     public void truncatedEscape() throws Exception {
         assertIOException("truncated", "=1");
     }
 
-    private static void assertEncoded(final String clearText, final String encoded) throws Exception {
-        final byte[] expected = clearText.getBytes(StandardCharsets.US_ASCII);
-
-        final ByteArrayOutputStream out = new ByteArrayOutputStream(encoded.length());
-        final byte[] encodedData = encoded.getBytes(StandardCharsets.US_ASCII);
-        QuotedPrintableDecoder.decode(encodedData, out);
-        final byte[] actual = out.toByteArray();
-
-        assertArrayEquals(expected, actual);
+    @Test
+    public void unsafeDecode() throws Exception {
+        assertEncoded("=\r\n", "=3D=0D=0A");
     }
 
-    private static void assertIOException(final String messageText, final String encoded)
-            throws UnsupportedEncodingException {
-        final ByteArrayOutputStream out = new ByteArrayOutputStream(encoded.length());
-        final byte[] encodedData = encoded.getBytes(StandardCharsets.US_ASCII);
-        try {
-            QuotedPrintableDecoder.decode(encodedData, out);
-            fail("Expected IOException");
-        } catch (final IOException e) {
-            final String em = e.getMessage();
-            assertTrue(em.contains(messageText), "Expected to find " + messageText + " in '" + em + "'");
-        }
+    @Test
+    public void unsafeDecodeLowerCase() throws Exception {
+        assertEncoded("=\r\n", "=3d=0d=0a");
     }
 
 }
diff --git a/src/test/java/org/apache/commons/fileupload2/util/mime/RFC2231UtilityTestCase.java b/src/test/java/org/apache/commons/fileupload2/util/mime/RFC2231UtilityTestCase.java
index fbda22f..409373d 100644
--- a/src/test/java/org/apache/commons/fileupload2/util/mime/RFC2231UtilityTestCase.java
+++ b/src/test/java/org/apache/commons/fileupload2/util/mime/RFC2231UtilityTestCase.java
@@ -33,6 +33,31 @@ import org.junit.jupiter.api.Test;
  */
 public final class RFC2231UtilityTestCase {
 
+    private static void assertEncoded(final String expected, final String encoded) throws Exception {
+        assertEquals(expected, RFC2231Utility.decodeText(encoded));
+    }
+
+    @Test
+    public void decodeInvalidEncoding() throws Exception {
+        assertThrows(UnsupportedEncodingException.class, () -> RFC2231Utility.decodeText("abc'en'hello"));
+    }
+
+    @Test
+    public void decodeIso88591() throws Exception {
+        assertEncoded("\u00A3 rate", "iso-8859-1'en'%A3%20rate"); //"£ rate"
+    }
+
+    @Test
+    public void decodeUtf8() throws Exception {
+        assertEncoded("\u00a3 \u0061\u006e\u0064 \u20ac \u0072\u0061\u0074\u0065\u0073",
+                "UTF-8''%c2%a3%20and%20%e2%82%ac%20rates"); //"£ and € rates"
+    }
+
+    @Test
+    public void noNeedToDecode() throws Exception {
+        assertEncoded("abc", "abc");
+    }
+
     @Test
     public void testHasEncodedValue() {
         final String nameWithAsteriskAtEnd = "paramname*";
@@ -59,29 +84,4 @@ public final class RFC2231UtilityTestCase {
         final String nameWithoutAsterisk = "paramname";
         assertEquals("paramname", RFC2231Utility.stripDelimiter(nameWithoutAsterisk));
     }
-
-    @Test
-    public void noNeedToDecode() throws Exception {
-        assertEncoded("abc", "abc");
-    }
-
-    @Test
-    public void decodeUtf8() throws Exception {
-        assertEncoded("\u00a3 \u0061\u006e\u0064 \u20ac \u0072\u0061\u0074\u0065\u0073",
-                "UTF-8''%c2%a3%20and%20%e2%82%ac%20rates"); //"£ and € rates"
-    }
-
-    @Test
-    public void decodeIso88591() throws Exception {
-        assertEncoded("\u00A3 rate", "iso-8859-1'en'%A3%20rate"); //"£ rate"
-    }
-
-    @Test
-    public void decodeInvalidEncoding() throws Exception {
-        assertThrows(UnsupportedEncodingException.class, () -> RFC2231Utility.decodeText("abc'en'hello"));
-    }
-
-    private static void assertEncoded(final String expected, final String encoded) throws Exception {
-        assertEquals(expected, RFC2231Utility.decodeText(encoded));
-    }
 }


[commons-fileupload] 08/08: Remove unused exceptions from test method signature

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

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

commit 786d994212c06ff31d84083beb759b6c57382776
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Apr 2 11:46:01 2023 -0400

    Remove unused exceptions from test method signature
---
 src/test/java/org/apache/commons/fileupload2/FileUploadTest.java     | 5 ++---
 .../java/org/apache/commons/fileupload2/ParameterParserTest.java     | 1 -
 src/test/java/org/apache/commons/fileupload2/Util.java               | 3 +--
 .../apache/commons/fileupload2/util/mime/Base64DecoderTestCase.java  | 4 +---
 .../fileupload2/util/mime/QuotedPrintableDecoderTestCase.java        | 4 +---
 5 files changed, 5 insertions(+), 12 deletions(-)

diff --git a/src/test/java/org/apache/commons/fileupload2/FileUploadTest.java b/src/test/java/org/apache/commons/fileupload2/FileUploadTest.java
index ddc6b99..461e065 100644
--- a/src/test/java/org/apache/commons/fileupload2/FileUploadTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/FileUploadTest.java
@@ -22,7 +22,6 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.stream.Stream;
@@ -108,7 +107,7 @@ public class FileUploadTest {
     @ParameterizedTest
     @MethodSource("data")
     public void testEmptyFile(final FileUpload upload)
-            throws UnsupportedEncodingException, FileUploadException {
+            throws FileUploadException {
         final List<FileItem> fileItems = Util.parseUpload (upload,
                                                 "-----1234\r\n" +
                                                 "Content-Disposition: form-data; name=\"file\"; filename=\"\"\r\n" +
@@ -355,7 +354,7 @@ public class FileUploadTest {
     @ParameterizedTest
     @MethodSource("data")
     public void testIE5MacBug(final FileUpload upload)
-            throws UnsupportedEncodingException, FileUploadException {
+            throws FileUploadException {
         final List<FileItem> fileItems = Util.parseUpload(upload,
                                                "-----1234\r\n" +
                                                "Content-Disposition: form-data; name=\"field1\"\r\n" +
diff --git a/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java b/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java
index 134e41f..d59286d 100644
--- a/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java
+++ b/src/test/java/org/apache/commons/fileupload2/ParameterParserTest.java
@@ -19,7 +19,6 @@ package org.apache.commons.fileupload2;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 
-import java.io.UnsupportedEncodingException;
 import java.util.Map;
 
 import org.junit.jupiter.api.Test;
diff --git a/src/test/java/org/apache/commons/fileupload2/Util.java b/src/test/java/org/apache/commons/fileupload2/Util.java
index 9b3aa24..b35a517 100644
--- a/src/test/java/org/apache/commons/fileupload2/Util.java
+++ b/src/test/java/org/apache/commons/fileupload2/Util.java
@@ -16,7 +16,6 @@
  */
 package org.apache.commons.fileupload2;
 
-import java.io.UnsupportedEncodingException;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.List;
@@ -56,7 +55,7 @@ public class Util {
     }
 
     public static List<FileItem> parseUpload(final FileUpload upload, final String content)
-        throws UnsupportedEncodingException, FileUploadException {
+        throws FileUploadException {
         final byte[] bytes = content.getBytes(StandardCharsets.US_ASCII);
         return parseUpload(upload, bytes, Constants.CONTENT_TYPE);
     }
diff --git a/src/test/java/org/apache/commons/fileupload2/util/mime/Base64DecoderTestCase.java b/src/test/java/org/apache/commons/fileupload2/util/mime/Base64DecoderTestCase.java
index 857bd90..ead3263 100644
--- a/src/test/java/org/apache/commons/fileupload2/util/mime/Base64DecoderTestCase.java
+++ b/src/test/java/org/apache/commons/fileupload2/util/mime/Base64DecoderTestCase.java
@@ -23,7 +23,6 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
 import java.nio.charset.StandardCharsets;
 
 import org.junit.jupiter.api.Test;
@@ -44,8 +43,7 @@ public final class Base64DecoderTestCase {
         assertArrayEquals(expected, actual);
     }
 
-    private static void assertIOException(final String messageText, final String encoded)
-            throws UnsupportedEncodingException {
+    private static void assertIOException(final String messageText, final String encoded) {
         final ByteArrayOutputStream out = new ByteArrayOutputStream(encoded.length());
         final byte[] encodedData = encoded.getBytes(StandardCharsets.US_ASCII);
         try {
diff --git a/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoderTestCase.java b/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoderTestCase.java
index f685a06..c8831f6 100644
--- a/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoderTestCase.java
+++ b/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoderTestCase.java
@@ -23,7 +23,6 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
 import java.nio.charset.StandardCharsets;
 
 import org.junit.jupiter.api.Test;
@@ -44,8 +43,7 @@ public final class QuotedPrintableDecoderTestCase {
         assertArrayEquals(expected, actual);
     }
 
-    private static void assertIOException(final String messageText, final String encoded)
-            throws UnsupportedEncodingException {
+    private static void assertIOException(final String messageText, final String encoded) {
         final ByteArrayOutputStream out = new ByteArrayOutputStream(encoded.length());
         final byte[] encodedData = encoded.getBytes(StandardCharsets.US_ASCII);
         try {