This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 8.5.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 218ea934fc71a0948c1b2e313e9cf20dede2cc23 Author: Mark Thomas <ma...@apache.org> AuthorDate: Fri Dec 6 15:30:48 2019 +0000 Merge in FileUpload changes to 2317552 (2019-12-06, 2.0-SNAPSHOT) --- MERGE.txt | 2 +- java/org/apache/catalina/connector/Request.java | 6 +- .../util/http/fileupload/FileItemIterator.java | 49 +- .../util/http/fileupload/FileUploadBase.java | 702 +-------------------- .../util/http/fileupload/MultipartStream.java | 10 +- .../util/http/fileupload/disk/DiskFileItem.java | 3 +- .../http/fileupload/impl/FileItemIteratorImpl.java | 339 ++++++++++ .../http/fileupload/impl/FileItemStreamImpl.java | 222 +++++++ .../impl/FileSizeLimitExceededException.java | 94 +++ .../fileupload/impl/FileUploadIOException.java | 63 ++ .../fileupload/impl/IOFileUploadException.java | 62 ++ .../impl/InvalidContentTypeException.java | 62 ++ .../util/http/fileupload/impl/SizeException.java | 75 +++ .../impl/SizeLimitExceededException.java | 43 ++ webapps/docs/changelog.xml | 4 + 15 files changed, 1032 insertions(+), 704 deletions(-) diff --git a/MERGE.txt b/MERGE.txt index b4bd507..893ac89 100644 --- a/MERGE.txt +++ b/MERGE.txt @@ -51,7 +51,7 @@ FileUpload Sub-tree: src/main/java/org/apache/commons/fileupload2 The SHA1 ID for the most recent commit to be merged to Tomcat is: -9958ea2426ec5682a7c929a13372c04426ee3818 (2019-08-01) +2317552993fd5180a84083d599b8cbdb05a07bab (2019-12-06) Note: Tomcat's copy of fileupload also includes classes copied manually from Commons IO. diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java index d4b11d5..5d719c1 100644 --- a/java/org/apache/catalina/connector/Request.java +++ b/java/org/apache/catalina/connector/Request.java @@ -105,10 +105,10 @@ import org.apache.tomcat.util.http.Parameters.FailReason; import org.apache.tomcat.util.http.ServerCookie; import org.apache.tomcat.util.http.ServerCookies; import org.apache.tomcat.util.http.fileupload.FileItem; -import org.apache.tomcat.util.http.fileupload.FileUploadBase; -import org.apache.tomcat.util.http.fileupload.FileUploadBase.InvalidContentTypeException; import org.apache.tomcat.util.http.fileupload.FileUploadException; import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory; +import org.apache.tomcat.util.http.fileupload.impl.InvalidContentTypeException; +import org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException; import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload; import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext; import org.apache.tomcat.util.http.parser.AcceptLanguage; @@ -2928,7 +2928,7 @@ public class Request implements org.apache.catalina.servlet4preview.http.HttpSer } catch (InvalidContentTypeException e) { parameters.setParseFailedReason(FailReason.INVALID_CONTENT_TYPE); partsParseException = new ServletException(e); - } catch (FileUploadBase.SizeException e) { + } catch (SizeLimitExceededException e) { parameters.setParseFailedReason(FailReason.POST_TOO_LARGE); checkSwallowInput(); partsParseException = new IllegalStateException(e); diff --git a/java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java b/java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java index 4f331ad..9665312 100644 --- a/java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java +++ b/java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java @@ -17,12 +17,56 @@ package org.apache.tomcat.util.http.fileupload; import java.io.IOException; +import java.util.List; + +import org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException; +import org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException; /** * An iterator, as returned by * {@link FileUploadBase#getItemIterator(RequestContext)}. */ public interface FileItemIterator { + /** Returns the maximum size of a single file. An {@link FileSizeLimitExceededException} + * will be thrown, if there is an uploaded file, which is exceeding this value. + * By default, this value will be copied from the {@link FileUploadBase#getFileSizeMax() + * FileUploadBase} object, however, the user may replace the default value with a + * request specific value by invoking {@link #setFileSizeMax(long)} on this object. + * @return The maximum size of a single, uploaded file. The value -1 indicates "unlimited". + */ + public long getFileSizeMax(); + + /** Sets the maximum size of a single file. An {@link FileSizeLimitExceededException} + * will be thrown, if there is an uploaded file, which is exceeding this value. + * By default, this value will be copied from the {@link FileUploadBase#getFileSizeMax() + * FileUploadBase} object, however, the user may replace the default value with a + * request specific value by invoking {@link #setFileSizeMax(long)} on this object, so + * there is no need to configure it here. + * <em>Note:</em>Changing this value doesn't affect files, that have already been uploaded. + * @param pFileSizeMax The maximum size of a single, uploaded file. The value -1 indicates "unlimited". + */ + public void setFileSizeMax(long pFileSizeMax); + + /** Returns the maximum size of the complete HTTP request. A {@link SizeLimitExceededException} + * will be thrown, if the HTTP request will exceed this value. + * By default, this value will be copied from the {@link FileUploadBase#getSizeMax() + * FileUploadBase} object, however, the user may replace the default value with a + * request specific value by invoking {@link #setSizeMax(long)} on this object. + * @return The maximum size of the complete HTTP requqest. The value -1 indicates "unlimited". + */ + public long getSizeMax(); + + /** Returns the maximum size of the complete HTTP request. A {@link SizeLimitExceededException} + * will be thrown, if the HTTP request will exceed this value. + * By default, this value will be copied from the {@link FileUploadBase#getSizeMax() + * FileUploadBase} object, however, the user may replace the default value with a + * request specific value by invoking {@link #setSizeMax(long)} on this object. + * <em>Note:</em> Setting the maximum size on this object will work only, if the iterator is not + * yet initialized. In other words: If the methods {@link #hasNext()}, {@link #next()} have not + * yet been invoked. + * @param pSizeMax The maximum size of the complete HTTP request. The value -1 indicates "unlimited". + */ + public void setSizeMax(long pSizeMax); /** * Returns, whether another instance of {@link FileItemStream} @@ -34,7 +78,7 @@ public interface FileItemIterator { * @return True, if one or more additional file items * are available, otherwise false. */ - boolean hasNext() throws FileUploadException, IOException; + public boolean hasNext() throws FileUploadException, IOException; /** * Returns the next available {@link FileItemStream}. @@ -47,6 +91,7 @@ public interface FileItemIterator { * @return FileItemStream instance, which provides * access to the next file item. */ - FileItemStream next() throws FileUploadException, IOException; + public FileItemStream next() throws FileUploadException, IOException; + public List<FileItem> getFileItems() throws FileUploadException, IOException; } diff --git a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java index 486434a..4a68be2 100644 --- a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java +++ b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java @@ -17,19 +17,18 @@ package org.apache.tomcat.util.http.fileupload; import java.io.IOException; -import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.NoSuchElementException; -import org.apache.tomcat.util.http.fileupload.MultipartStream.ItemInputStream; -import org.apache.tomcat.util.http.fileupload.util.Closeable; +import org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl; +import org.apache.tomcat.util.http.fileupload.impl.FileItemStreamImpl; +import org.apache.tomcat.util.http.fileupload.impl.FileUploadIOException; +import org.apache.tomcat.util.http.fileupload.impl.IOFileUploadException; import org.apache.tomcat.util.http.fileupload.util.FileItemHeadersImpl; -import org.apache.tomcat.util.http.fileupload.util.LimitedInputStream; import org.apache.tomcat.util.http.fileupload.util.Streams; @@ -253,7 +252,7 @@ public abstract class FileUploadBase { public FileItemIterator getItemIterator(RequestContext ctx) throws FileUploadException, IOException { try { - return new FileItemIteratorImpl(ctx); + return new FileItemIteratorImpl(this, ctx); } catch (FileUploadIOException e) { // unwrap encapsulated SizeException throw (FileUploadException) e.getCause(); @@ -286,7 +285,7 @@ public abstract class FileUploadBase { while (iter.hasNext()) { final FileItemStream item = iter.next(); // Don't use getName() here to prevent an InvalidFileNameException. - final String fileName = ((FileItemIteratorImpl.FileItemStreamImpl) item).name; + final String fileName = ((FileItemStreamImpl) item).getName(); FileItem fileItem = fac.createItem(item.getFieldName(), item.getContentType(), item.isFormField(), fileName); items.add(fileItem); @@ -363,7 +362,7 @@ public abstract class FileUploadBase { * * @return The boundary, as a byte array. */ - protected byte[] getBoundary(String contentType) { + public byte[] getBoundary(String contentType) { ParameterParser parser = new ParameterParser(); parser.setLowerCaseNames(true); // Parameter parser can handle null input @@ -387,7 +386,7 @@ public abstract class FileUploadBase { * * @return The file name for the current <code>encapsulation</code>. */ - protected String getFileName(FileItemHeaders headers) { + public String getFileName(FileItemHeaders headers) { return getFileName(headers.getHeader(CONTENT_DISPOSITION)); } @@ -429,7 +428,7 @@ public abstract class FileUploadBase { * * @return The field name for the current <code>encapsulation</code>. */ - protected String getFieldName(FileItemHeaders headers) { + public String getFieldName(FileItemHeaders headers) { return getFieldName(headers.getHeader(CONTENT_DISPOSITION)); } @@ -467,7 +466,7 @@ public abstract class FileUploadBase { * * @return A <code>Map</code> containing the parsed HTTP request headers. */ - protected FileItemHeaders getParsedHeaders(String headerPart) { + public FileItemHeaders getParsedHeaders(String headerPart) { final int len = headerPart.length(); FileItemHeadersImpl headers = newFileItemHeaders(); int start = 0; @@ -549,687 +548,6 @@ public abstract class FileUploadBase { } /** - * The iterator, which is returned by - * {@link FileUploadBase#getItemIterator(RequestContext)}. - */ - private class FileItemIteratorImpl implements FileItemIterator { - - /** - * Default implementation of {@link FileItemStream}. - */ - class FileItemStreamImpl implements FileItemStream { - - /** - * The file items content type. - */ - private final String contentType; - - /** - * The file items field name. - */ - private final String fieldName; - - /** - * The file items file name. - */ - private final String name; - - /** - * Whether the file item is a form field. - */ - private final boolean formField; - - /** - * The file items input stream. - */ - private final InputStream stream; - - /** - * The headers, if any. - */ - private FileItemHeaders headers; - - /** - * Creates a new instance. - * - * @param pName The items file name, or null. - * @param pFieldName The items field name. - * @param pContentType The items content type, or null. - * @param pFormField Whether the item is a form field. - * @param pContentLength The items content length, if known, or -1 - * @throws IOException Creating the file item failed. - */ - FileItemStreamImpl(String pName, String pFieldName, - String pContentType, boolean pFormField, - long pContentLength) throws IOException { - name = pName; - fieldName = pFieldName; - contentType = pContentType; - formField = pFormField; - if (fileSizeMax != -1) { // Check if limit is already exceeded - if (pContentLength != -1 - && pContentLength > fileSizeMax) { - FileSizeLimitExceededException e = - new FileSizeLimitExceededException( - String.format("The field %s exceeds its maximum permitted size of %s bytes.", - fieldName, Long.valueOf(fileSizeMax)), - pContentLength, fileSizeMax); - e.setFileName(pName); - e.setFieldName(pFieldName); - throw new FileUploadIOException(e); - } - } - // OK to construct stream now - final ItemInputStream itemStream = multi.newInputStream(); - InputStream istream = itemStream; - if (fileSizeMax != -1) { - istream = new LimitedInputStream(istream, fileSizeMax) { - @Override - protected void raiseError(long pSizeMax, long pCount) - throws IOException { - itemStream.close(true); - FileSizeLimitExceededException e = - new FileSizeLimitExceededException( - String.format("The field %s exceeds its maximum permitted size of %s bytes.", - fieldName, Long.valueOf(pSizeMax)), - pCount, pSizeMax); - e.setFieldName(fieldName); - e.setFileName(name); - throw new FileUploadIOException(e); - } - }; - } - stream = istream; - } - - /** - * Returns the items content type, or null. - * - * @return Content type, if known, or null. - */ - @Override - public String getContentType() { - return contentType; - } - - /** - * Returns the items field name. - * - * @return Field name. - */ - @Override - public String getFieldName() { - return fieldName; - } - - /** - * Returns the items file name. - * - * @return File name, if known, or null. - * @throws InvalidFileNameException The file name contains a NUL character, - * which might be an indicator of a security attack. If you intend to - * use the file name anyways, catch the exception and use - * InvalidFileNameException#getName(). - */ - @Override - public String getName() { - return Streams.checkFileName(name); - } - - /** - * Returns, whether this is a form field. - * - * @return True, if the item is a form field, - * otherwise false. - */ - @Override - public boolean isFormField() { - return formField; - } - - /** - * Returns an input stream, which may be used to - * read the items contents. - * - * @return Opened input stream. - * @throws IOException An I/O error occurred. - */ - @Override - public InputStream openStream() throws IOException { - if (((Closeable) stream).isClosed()) { - throw new FileItemStream.ItemSkippedException(); - } - return stream; - } - - /** - * Closes the file item. - * - * @throws IOException An I/O error occurred. - */ - void close() throws IOException { - stream.close(); - } - - /** - * Returns the file item headers. - * - * @return The items header object - */ - @Override - public FileItemHeaders getHeaders() { - return headers; - } - - /** - * Sets the file item headers. - * - * @param pHeaders The items header object - */ - @Override - public void setHeaders(FileItemHeaders pHeaders) { - headers = pHeaders; - } - - } - - /** - * The multi part stream to process. - */ - private final MultipartStream multi; - - /** - * The notifier, which used for triggering the - * {@link ProgressListener}. - */ - private final MultipartStream.ProgressNotifier notifier; - - /** - * The boundary, which separates the various parts. - */ - private final byte[] boundary; - - /** - * The item, which we currently process. - */ - private FileItemStreamImpl currentItem; - - /** - * The current items field name. - */ - private String currentFieldName; - - /** - * Whether we are currently skipping the preamble. - */ - private boolean skipPreamble; - - /** - * Whether the current item may still be read. - */ - private boolean itemValid; - - /** - * Whether we have seen the end of the file. - */ - private boolean eof; - - /** - * Creates a new instance. - * - * @param ctx The request context. - * @throws FileUploadException An error occurred while - * parsing the request. - * @throws IOException An I/O error occurred. - */ - FileItemIteratorImpl(RequestContext ctx) - throws FileUploadException, IOException { - if (ctx == null) { - throw new NullPointerException("ctx parameter"); - } - - String contentType = ctx.getContentType(); - if ((null == contentType) - || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART))) { - throw new InvalidContentTypeException(String.format( - "the request doesn't contain a %s or %s stream, content type header is %s", - MULTIPART_FORM_DATA, MULTIPART_MIXED, contentType)); - } - - - final long requestSize = ((UploadContext) ctx).contentLength(); - - InputStream input; // N.B. this is eventually closed in MultipartStream processing - if (sizeMax >= 0) { - if (requestSize != -1 && requestSize > sizeMax) { - throw new SizeLimitExceededException(String.format( - "the request was rejected because its size (%s) exceeds the configured maximum (%s)", - Long.valueOf(requestSize), Long.valueOf(sizeMax)), - requestSize, sizeMax); - } - // N.B. this is eventually closed in MultipartStream processing - input = new LimitedInputStream(ctx.getInputStream(), sizeMax) { - @Override - protected void raiseError(long pSizeMax, long pCount) - throws IOException { - FileUploadException ex = new SizeLimitExceededException( - String.format("the request was rejected because its size (%s) exceeds the configured maximum (%s)", - Long.valueOf(pCount), Long.valueOf(pSizeMax)), - pCount, pSizeMax); - throw new FileUploadIOException(ex); - } - }; - } else { - input = ctx.getInputStream(); - } - - String charEncoding = headerEncoding; - if (charEncoding == null) { - charEncoding = ctx.getCharacterEncoding(); - } - - boundary = getBoundary(contentType); - if (boundary == null) { - IOUtils.closeQuietly(input); // avoid possible resource leak - throw new FileUploadException("the request was rejected because no multipart boundary was found"); - } - - notifier = new MultipartStream.ProgressNotifier(listener, requestSize); - try { - multi = new MultipartStream(input, boundary, notifier); - } catch (IllegalArgumentException iae) { - IOUtils.closeQuietly(input); // avoid possible resource leak - throw new InvalidContentTypeException( - String.format("The boundary specified in the %s header is too long", CONTENT_TYPE), iae); - } - multi.setHeaderEncoding(charEncoding); - - skipPreamble = true; - findNextItem(); - } - - /** - * Called for finding the next item, if any. - * - * @return True, if an next item was found, otherwise false. - * @throws IOException An I/O error occurred. - */ - private boolean findNextItem() throws IOException { - if (eof) { - return false; - } - if (currentItem != null) { - currentItem.close(); - currentItem = null; - } - for (;;) { - boolean nextPart; - if (skipPreamble) { - nextPart = multi.skipPreamble(); - } else { - nextPart = multi.readBoundary(); - } - if (!nextPart) { - if (currentFieldName == null) { - // Outer multipart terminated -> No more data - eof = true; - return false; - } - // Inner multipart terminated -> Return to parsing the outer - multi.setBoundary(boundary); - currentFieldName = null; - continue; - } - FileItemHeaders headers = getParsedHeaders(multi.readHeaders()); - if (currentFieldName == null) { - // We're parsing the outer multipart - String fieldName = getFieldName(headers); - if (fieldName != null) { - String subContentType = headers.getHeader(CONTENT_TYPE); - if (subContentType != null - && subContentType.toLowerCase(Locale.ENGLISH) - .startsWith(MULTIPART_MIXED)) { - currentFieldName = fieldName; - // Multiple files associated with this field name - byte[] subBoundary = getBoundary(subContentType); - multi.setBoundary(subBoundary); - skipPreamble = true; - continue; - } - String fileName = getFileName(headers); - currentItem = new FileItemStreamImpl(fileName, - fieldName, headers.getHeader(CONTENT_TYPE), - fileName == null, getContentLength(headers)); - currentItem.setHeaders(headers); - notifier.noteItem(); - itemValid = true; - return true; - } - } else { - String fileName = getFileName(headers); - if (fileName != null) { - currentItem = new FileItemStreamImpl(fileName, - currentFieldName, - headers.getHeader(CONTENT_TYPE), - false, getContentLength(headers)); - currentItem.setHeaders(headers); - notifier.noteItem(); - itemValid = true; - return true; - } - } - multi.discardBodyData(); - } - } - - private long getContentLength(FileItemHeaders pHeaders) { - try { - return Long.parseLong(pHeaders.getHeader(CONTENT_LENGTH)); - } catch (Exception e) { - return -1; - } - } - - /** - * 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. - */ - @Override - public boolean hasNext() throws FileUploadException, IOException { - if (eof) { - return false; - } - if (itemValid) { - return true; - } - try { - return findNextItem(); - } catch (FileUploadIOException e) { - // unwrap encapsulated SizeException - throw (FileUploadException) e.getCause(); - } - } - - /** - * 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. - */ - @Override - public FileItemStream next() throws FileUploadException, IOException { - if (eof || (!itemValid && !hasNext())) { - throw new NoSuchElementException(); - } - itemValid = false; - return currentItem; - } - - } - - /** - * This exception is thrown for hiding an inner - * {@link FileUploadException} in an {@link IOException}. - */ - public static class FileUploadIOException extends IOException { - - private static final long serialVersionUID = -3082868232248803474L; - - public FileUploadIOException() { - super(); - } - - public FileUploadIOException(String message, Throwable cause) { - super(message, cause); - } - - public FileUploadIOException(String message) { - super(message); - } - - public FileUploadIOException(Throwable cause) { - super(cause); - } - } - - /** - * Thrown to indicate that the request is not a multipart request. - */ - public static class InvalidContentTypeException - extends FileUploadException { - - /** - * The exceptions UID, for serializing an instance. - */ - private static final long serialVersionUID = -9073026332015646668L; - - /** - * Constructs a <code>InvalidContentTypeException</code> with no - * detail message. - */ - public InvalidContentTypeException() { - super(); - } - - /** - * Constructs an <code>InvalidContentTypeException</code> with - * the specified detail message. - * - * @param message The detail message. - */ - public InvalidContentTypeException(String message) { - super(message); - } - - /** - * Constructs an <code>InvalidContentTypeException</code> with - * the specified detail message and cause. - * - * @param msg The detail message. - * @param cause the original cause - * - * @since 1.3.1 - */ - public InvalidContentTypeException(String msg, Throwable cause) { - super(msg, cause); - } - } - - /** - * Thrown to indicate an IOException. - */ - public static class IOFileUploadException extends FileUploadException { - - private static final long serialVersionUID = -5858565745868986701L; - - public IOFileUploadException() { - super(); - } - - public IOFileUploadException(String message, Throwable cause) { - super(message, cause); - } - - public IOFileUploadException(String message) { - super(message); - } - - public IOFileUploadException(Throwable cause) { - super(cause); - } - } - - /** - * This exception is thrown, if a requests permitted size - * is exceeded. - */ - public abstract static class SizeException extends FileUploadException { - - /** - * Serial version UID, being used, if serialized. - */ - private static final long serialVersionUID = -8776225574705254126L; - - /** - * The actual size of the request. - */ - private final long actual; - - /** - * The maximum permitted size of the request. - */ - private final long permitted; - - /** - * Creates a new instance. - * - * @param message The detail message. - * @param actual The actual number of bytes in the request. - * @param permitted The requests size limit, in bytes. - */ - protected SizeException(String message, long actual, long permitted) { - super(message); - this.actual = actual; - this.permitted = permitted; - } - - /** - * Retrieves 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. - * - * @return The permitted size of the request. - * @since 1.3 - */ - public long getPermittedSize() { - return permitted; - } - - } - - /** - * Thrown to indicate that the request size exceeds the configured maximum. - */ - public static class SizeLimitExceededException - extends SizeException { - - /** - * The exceptions UID, for serializing an instance. - */ - private static final long serialVersionUID = -2474893167098052828L; - - /** - * Constructs a <code>SizeExceededException</code> 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(String message, long actual, - long permitted) { - super(message, actual, permitted); - } - - } - - /** - * Thrown to indicate that A files size exceeds the configured maximum. - */ - public static class FileSizeLimitExceededException - extends SizeException { - - /** - * The exceptions UID, for serializing an instance. - */ - private static final long serialVersionUID = 8150776562029630058L; - - /** - * File name of the item, which caused the exception. - */ - private String fileName; - - /** - * Field name of the item, which caused the exception. - */ - private String fieldName; - - /** - * Constructs a <code>SizeExceededException</code> 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 FileSizeLimitExceededException(String message, long actual, - long permitted) { - super(message, actual, permitted); - } - - /** - * Returns the file name of the item, which caused the - * exception. - * - * @return File name, if known, or null. - */ - public String getFileName() { - return fileName; - } - - /** - * 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(String pFileName) { - fileName = pFileName; - } - - /** - * Returns the field name of the item, which caused the - * exception. - * - * @return Field name, if known, or null. - */ - public String getFieldName() { - return fieldName; - } - - /** - * 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(String pFieldName) { - fieldName = pFieldName; - } - - } - - /** * Returns the progress listener. * * @return The progress listener, if any, or null. diff --git a/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java b/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java index 351fa02..c3616c3 100644 --- a/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java +++ b/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java @@ -22,7 +22,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; -import org.apache.tomcat.util.http.fileupload.FileUploadBase.FileUploadIOException; +import org.apache.tomcat.util.http.fileupload.impl.FileUploadIOException; import org.apache.tomcat.util.http.fileupload.util.Closeable; import org.apache.tomcat.util.http.fileupload.util.Streams; @@ -115,7 +115,7 @@ public class MultipartStream { * @param pListener The listener to invoke. * @param pContentLength The expected content length. */ - ProgressNotifier(ProgressListener pListener, long pContentLength) { + public ProgressNotifier(ProgressListener pListener, long pContentLength) { listener = pListener; contentLength = pContentLength; } @@ -136,7 +136,7 @@ public class MultipartStream { /** * Called to indicate, that a new file item has been detected. */ - void noteItem() { + public void noteItem() { ++items; notifyListener(); } @@ -332,7 +332,7 @@ public class MultipartStream { * * @see #MultipartStream(InputStream, byte[], int, ProgressNotifier) */ - MultipartStream(InputStream input, + public MultipartStream(InputStream input, byte[] boundary, ProgressNotifier pNotifier) { this(input, boundary, DEFAULT_BUFSIZE, pNotifier); @@ -576,7 +576,7 @@ public class MultipartStream { * Creates a new {@link ItemInputStream}. * @return A new instance of {@link ItemInputStream}. */ - ItemInputStream newInputStream() { + public ItemInputStream newInputStream() { return new ItemInputStream(); } diff --git a/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java b/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java index b94a960..67f5e0c 100644 --- a/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java +++ b/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java @@ -546,7 +546,7 @@ public class DiskFileItem * Removes the file contents from the temporary storage. */ @Override - protected void finalize() { + protected void finalize() throws Throwable { if (dfos == null || dfos.isInMemory()) { return; } @@ -555,6 +555,7 @@ public class DiskFileItem if (outputFile != null && outputFile.exists()) { outputFile.delete(); } + super.finalize(); } /** diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/FileItemIteratorImpl.java b/java/org/apache/tomcat/util/http/fileupload/impl/FileItemIteratorImpl.java new file mode 100644 index 0000000..098e089 --- /dev/null +++ b/java/org/apache/tomcat/util/http/fileupload/impl/FileItemIteratorImpl.java @@ -0,0 +1,339 @@ +/* + * 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.tomcat.util.http.fileupload.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.NoSuchElementException; + +import org.apache.tomcat.util.http.fileupload.FileItem; +import org.apache.tomcat.util.http.fileupload.FileItemHeaders; +import org.apache.tomcat.util.http.fileupload.FileItemIterator; +import org.apache.tomcat.util.http.fileupload.FileItemStream; +import org.apache.tomcat.util.http.fileupload.FileUploadBase; +import org.apache.tomcat.util.http.fileupload.FileUploadException; +import org.apache.tomcat.util.http.fileupload.IOUtils; +import org.apache.tomcat.util.http.fileupload.MultipartStream; +import org.apache.tomcat.util.http.fileupload.ProgressListener; +import org.apache.tomcat.util.http.fileupload.RequestContext; +import org.apache.tomcat.util.http.fileupload.UploadContext; +import org.apache.tomcat.util.http.fileupload.util.LimitedInputStream; + +/** + * The iterator, which is returned by + * {@link FileUploadBase#getItemIterator(RequestContext)}. + */ +public class FileItemIteratorImpl implements FileItemIterator { + private final FileUploadBase fileUploadBase; + private final RequestContext ctx; + private long sizeMax, fileSizeMax; + + + @Override + public long getSizeMax() { + return sizeMax; + } + + @Override + public void setSizeMax(long sizeMax) { + this.sizeMax = sizeMax; + } + + @Override + public long getFileSizeMax() { + return fileSizeMax; + } + + @Override + public void setFileSizeMax(long fileSizeMax) { + this.fileSizeMax = fileSizeMax; + } + + /** + * The multi part stream to process. + */ + private MultipartStream multiPartStream; + + /** + * The notifier, which used for triggering the + * {@link ProgressListener}. + */ + private MultipartStream.ProgressNotifier progressNotifier; + + /** + * The boundary, which separates the various parts. + */ + private byte[] multiPartBoundary; + + /** + * The item, which we currently process. + */ + private FileItemStreamImpl currentItem; + + /** + * The current items field name. + */ + private String currentFieldName; + + /** + * Whether we are currently skipping the preamble. + */ + private boolean skipPreamble; + + /** + * Whether the current item may still be read. + */ + private boolean itemValid; + + /** + * Whether we have seen the end of the file. + */ + private boolean eof; + + /** + * Creates a new instance. + * + * @param pFileUploadBase Upload instance + * @param pRequestContext The request context. + * @throws FileUploadException An error occurred while + * parsing the request. + * @throws IOException An I/O error occurred. + */ + public FileItemIteratorImpl(FileUploadBase pFileUploadBase, RequestContext pRequestContext) + throws FileUploadException, IOException { + fileUploadBase = pFileUploadBase; + sizeMax = fileUploadBase.getSizeMax(); + fileSizeMax = fileUploadBase.getFileSizeMax(); + ctx = pRequestContext; + if (ctx == null) { + throw new NullPointerException("ctx parameter"); + } + + + skipPreamble = true; + findNextItem(); + } + + protected void init(FileUploadBase fileUploadBase, @SuppressWarnings("unused") RequestContext pRequestContext) + throws FileUploadException, IOException { + String contentType = ctx.getContentType(); + if ((null == contentType) + || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(FileUploadBase.MULTIPART))) { + throw new InvalidContentTypeException( + String.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 requestSize = ((UploadContext) ctx).contentLength(); + + InputStream input; // N.B. this is eventually closed in MultipartStream processing + if (sizeMax >= 0) { + if (requestSize != -1 && requestSize > sizeMax) { + throw new SizeLimitExceededException( + String.format("the request was rejected because its size (%s) exceeds the configured maximum (%s)", + Long.valueOf(requestSize), Long.valueOf(sizeMax)), + requestSize, sizeMax); + } + // N.B. this is eventually closed in MultipartStream processing + input = new LimitedInputStream(ctx.getInputStream(), sizeMax) { + @Override + protected void raiseError(long pSizeMax, long pCount) + throws IOException { + FileUploadException ex = new SizeLimitExceededException( + String.format("the request was rejected because its size (%s) exceeds the configured maximum (%s)", + Long.valueOf(pCount), Long.valueOf(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 (IllegalArgumentException iae) { + IOUtils.closeQuietly(input); // avoid possible resource leak + throw new InvalidContentTypeException( + String.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. + * + * @return True, if an next item was found, otherwise false. + * @throws IOException An I/O error occurred. + */ + private boolean findNextItem() throws FileUploadException, IOException { + if (eof) { + return false; + } + if (currentItem != null) { + currentItem.close(); + currentItem = null; + } + final MultipartStream multi = getMultiPartStream(); + for (;;) { + boolean nextPart; + if (skipPreamble) { + nextPart = multi.skipPreamble(); + } else { + nextPart = multi.readBoundary(); + } + if (!nextPart) { + if (currentFieldName == null) { + // Outer multipart terminated -> No more data + eof = true; + return false; + } + // Inner multipart terminated -> Return to parsing the outer + multi.setBoundary(multiPartBoundary); + currentFieldName = null; + continue; + } + FileItemHeaders headers = fileUploadBase.getParsedHeaders(multi.readHeaders()); + if (currentFieldName == null) { + // We're parsing the outer multipart + String fieldName = fileUploadBase.getFieldName(headers); + if (fieldName != null) { + String subContentType = headers.getHeader(FileUploadBase.CONTENT_TYPE); + if (subContentType != null + && subContentType.toLowerCase(Locale.ENGLISH) + .startsWith(FileUploadBase.MULTIPART_MIXED)) { + currentFieldName = fieldName; + // Multiple files associated with this field name + byte[] subBoundary = fileUploadBase.getBoundary(subContentType); + multi.setBoundary(subBoundary); + skipPreamble = true; + continue; + } + String fileName = fileUploadBase.getFileName(headers); + currentItem = new FileItemStreamImpl(this, fileName, + fieldName, headers.getHeader(FileUploadBase.CONTENT_TYPE), + fileName == null, getContentLength(headers)); + currentItem.setHeaders(headers); + progressNotifier.noteItem(); + itemValid = true; + return true; + } + } else { + String fileName = fileUploadBase.getFileName(headers); + if (fileName != null) { + currentItem = new FileItemStreamImpl(this, fileName, + currentFieldName, + headers.getHeader(FileUploadBase.CONTENT_TYPE), + false, getContentLength(headers)); + currentItem.setHeaders(headers); + progressNotifier.noteItem(); + itemValid = true; + return true; + } + } + multi.discardBodyData(); + } + } + + private long getContentLength(FileItemHeaders pHeaders) { + try { + return Long.parseLong(pHeaders.getHeader(FileUploadBase.CONTENT_LENGTH)); + } catch (Exception e) { + return -1; + } + } + + /** + * 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. + */ + @Override + public boolean hasNext() throws FileUploadException, IOException { + if (eof) { + return false; + } + if (itemValid) { + return true; + } + try { + return findNextItem(); + } catch (FileUploadIOException e) { + // unwrap encapsulated SizeException + throw (FileUploadException) e.getCause(); + } + } + + /** + * 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. + */ + @Override + public FileItemStream next() throws FileUploadException, IOException { + if (eof || (!itemValid && !hasNext())) { + throw new NoSuchElementException(); + } + itemValid = false; + return currentItem; + } + + @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; + } + +} \ No newline at end of file diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java b/java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java new file mode 100644 index 0000000..29427e6 --- /dev/null +++ b/java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java @@ -0,0 +1,222 @@ +/* + * 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.tomcat.util.http.fileupload.impl; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.tomcat.util.http.fileupload.FileItemHeaders; +import org.apache.tomcat.util.http.fileupload.FileItemStream; +import org.apache.tomcat.util.http.fileupload.FileUploadException; +import org.apache.tomcat.util.http.fileupload.InvalidFileNameException; +import org.apache.tomcat.util.http.fileupload.MultipartStream.ItemInputStream; +import org.apache.tomcat.util.http.fileupload.util.Closeable; +import org.apache.tomcat.util.http.fileupload.util.LimitedInputStream; +import org.apache.tomcat.util.http.fileupload.util.Streams; + + +/** + * Default implementation of {@link FileItemStream}. + */ +public class FileItemStreamImpl implements FileItemStream { + private final FileItemIteratorImpl fileItemIteratorImpl; + + /** + * The file items content type. + */ + private final String contentType; + + /** + * The file items field name. + */ + private final String fieldName; + + /** + * The file items file name. + */ + final String name; + + /** + * Whether the file item is a form field. + */ + private final boolean formField; + + /** + * The file items input stream. + */ + private final InputStream stream; + + /** + * Whether the file item was already opened. + */ + private boolean opened; + + /** + * The headers, if any. + */ + private FileItemHeaders headers; + + /** + * Creates a new instance. + * @param pFileItemIterator Iterator for all files in this upload + * @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 FileUploadException If an error is encountered processing the request + * @throws IOException Creating the file item failed. + */ + public FileItemStreamImpl(FileItemIteratorImpl pFileItemIterator, String pName, String pFieldName, + String pContentType, boolean pFormField, + long pContentLength) throws FileUploadException, IOException { + fileItemIteratorImpl = pFileItemIterator; + name = pName; + fieldName = pFieldName; + contentType = pContentType; + formField = pFormField; + final long fileSizeMax = fileItemIteratorImpl.getFileSizeMax(); + if (fileSizeMax != -1) { // Check if limit is already exceeded + if (pContentLength != -1 + && pContentLength > fileSizeMax) { + FileSizeLimitExceededException e = + new FileSizeLimitExceededException( + String.format("The field %s exceeds its maximum permitted size of %s bytes.", + fieldName, Long.valueOf(fileSizeMax)), + pContentLength, fileSizeMax); + e.setFileName(pName); + e.setFieldName(pFieldName); + throw new FileUploadIOException(e); + } + } + // OK to construct stream now + final ItemInputStream itemStream = fileItemIteratorImpl.getMultiPartStream().newInputStream(); + InputStream istream = itemStream; + if (fileSizeMax != -1) { + istream = new LimitedInputStream(istream, fileSizeMax) { + @Override + protected void raiseError(long pSizeMax, long pCount) + throws IOException { + itemStream.close(true); + FileSizeLimitExceededException e = + new FileSizeLimitExceededException( + String.format("The field %s exceeds its maximum permitted size of %s bytes.", + fieldName, Long.valueOf(pSizeMax)), + pCount, pSizeMax); + e.setFieldName(fieldName); + e.setFileName(name); + throw new FileUploadIOException(e); + } + }; + } + stream = istream; + } + + /** + * Returns the items content type, or null. + * + * @return Content type, if known, or null. + */ + @Override + public String getContentType() { + return contentType; + } + + /** + * Returns the items field name. + * + * @return Field name. + */ + @Override + public String getFieldName() { + return fieldName; + } + + /** + * Returns the items file name. + * + * @return File name, if known, or null. + * @throws InvalidFileNameException The file name contains a NUL character, + * which might be an indicator of a security attack. If you intend to + * use the file name anyways, catch the exception and use + * InvalidFileNameException#getName(). + */ + @Override + public String getName() { + return Streams.checkFileName(name); + } + + /** + * Returns, whether this is a form field. + * + * @return True, if the item is a form field, + * otherwise false. + */ + @Override + public boolean isFormField() { + return formField; + } + + /** + * Returns an input stream, which may be used to + * read the items contents. + * + * @return Opened input stream. + * @throws IOException An I/O error occurred. + */ + @Override + public InputStream openStream() throws IOException { + if (opened) { + throw new IllegalStateException( + "The stream was already opened."); + } + if (((Closeable) stream).isClosed()) { + throw new FileItemStream.ItemSkippedException(); + } + return stream; + } + + /** + * Closes the file item. + * + * @throws IOException An I/O error occurred. + */ + public void close() throws IOException { + stream.close(); + } + + /** + * Returns the file item headers. + * + * @return The items header object + */ + @Override + public FileItemHeaders getHeaders() { + return headers; + } + + /** + * Sets the file item headers. + * + * @param pHeaders The items header object + */ + @Override + public void setHeaders(FileItemHeaders pHeaders) { + headers = pHeaders; + } + +} \ No newline at end of file diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/FileSizeLimitExceededException.java b/java/org/apache/tomcat/util/http/fileupload/impl/FileSizeLimitExceededException.java new file mode 100644 index 0000000..3eaa9d8 --- /dev/null +++ b/java/org/apache/tomcat/util/http/fileupload/impl/FileSizeLimitExceededException.java @@ -0,0 +1,94 @@ +/* + * 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.tomcat.util.http.fileupload.impl; + +/** + * Thrown to indicate that A files size exceeds the configured maximum. + */ +public class FileSizeLimitExceededException + extends SizeException { + + /** + * The exceptions UID, for serializing an instance. + */ + private static final long serialVersionUID = 8150776562029630058L; + + /** + * File name of the item, which caused the exception. + */ + private String fileName; + + /** + * Field name of the item, which caused the exception. + */ + private String fieldName; + + /** + * Constructs a <code>SizeExceededException</code> 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 FileSizeLimitExceededException(String message, long actual, + long permitted) { + super(message, actual, permitted); + } + + /** + * Returns the file name of the item, which caused the + * exception. + * + * @return File name, if known, or null. + */ + public String getFileName() { + return fileName; + } + + /** + * 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(String pFileName) { + fileName = pFileName; + } + + /** + * Returns the field name of the item, which caused the + * exception. + * + * @return Field name, if known, or null. + */ + public String getFieldName() { + return fieldName; + } + + /** + * 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(String pFieldName) { + fieldName = pFieldName; + } + +} \ No newline at end of file diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/FileUploadIOException.java b/java/org/apache/tomcat/util/http/fileupload/impl/FileUploadIOException.java new file mode 100644 index 0000000..3e71b5c --- /dev/null +++ b/java/org/apache/tomcat/util/http/fileupload/impl/FileUploadIOException.java @@ -0,0 +1,63 @@ +/* + * 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.tomcat.util.http.fileupload.impl; + +import java.io.IOException; + +import org.apache.tomcat.util.http.fileupload.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; + + /** + * 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</code> with the + * given cause. + * + * @param pCause The exceptions cause, if any, or null. + */ + public FileUploadIOException(FileUploadException pCause) { + // We're not doing super(pCause) cause of 1.3 compatibility. + cause = pCause; + } + + /** + * Returns the exceptions cause. + * + * @return The exceptions cause, if any, or null. + */ + @SuppressWarnings("sync-override") // Field is final + @Override + public Throwable getCause() { + return cause; + } + +} \ No newline at end of file diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/IOFileUploadException.java b/java/org/apache/tomcat/util/http/fileupload/impl/IOFileUploadException.java new file mode 100644 index 0000000..90f259d --- /dev/null +++ b/java/org/apache/tomcat/util/http/fileupload/impl/IOFileUploadException.java @@ -0,0 +1,62 @@ +/* + * 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.tomcat.util.http.fileupload.impl; + +import java.io.IOException; + +import org.apache.tomcat.util.http.fileupload.FileUploadException; + +/** + * Thrown to indicate an IOException. + */ +public class IOFileUploadException extends FileUploadException { + + /** + * The exceptions UID, for serializing an instance. + */ + 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(String pMsg, IOException pException) { + super(pMsg); + cause = pException; + } + + /** + * Returns the exceptions cause. + * + * @return The exceptions cause, if any, or null. + */ + @SuppressWarnings("sync-override") // Field is final + @Override + public Throwable getCause() { + return cause; + } + +} \ No newline at end of file diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/InvalidContentTypeException.java b/java/org/apache/tomcat/util/http/fileupload/impl/InvalidContentTypeException.java new file mode 100644 index 0000000..295597b --- /dev/null +++ b/java/org/apache/tomcat/util/http/fileupload/impl/InvalidContentTypeException.java @@ -0,0 +1,62 @@ +/* + * 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.tomcat.util.http.fileupload.impl; + +import org.apache.tomcat.util.http.fileupload.FileUploadException; + +/** + * Thrown to indicate that the request is not a multipart request. + */ +public class InvalidContentTypeException + extends FileUploadException { + + /** + * The exceptions UID, for serializing an instance. + */ + private static final long serialVersionUID = -9073026332015646668L; + + /** + * Constructs a <code>InvalidContentTypeException</code> with no + * detail message. + */ + public InvalidContentTypeException() { + super(); + } + + /** + * Constructs an <code>InvalidContentTypeException</code> with + * the specified detail message. + * + * @param message The detail message. + */ + public InvalidContentTypeException(String message) { + super(message); + } + + /** + * Constructs an <code>InvalidContentTypeException</code> with + * the specified detail message and cause. + * + * @param msg The detail message. + * @param cause the original cause + * + * @since 1.3.1 + */ + public InvalidContentTypeException(String msg, Throwable cause) { + super(msg, cause); + } +} \ No newline at end of file diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/SizeException.java b/java/org/apache/tomcat/util/http/fileupload/impl/SizeException.java new file mode 100644 index 0000000..4852795 --- /dev/null +++ b/java/org/apache/tomcat/util/http/fileupload/impl/SizeException.java @@ -0,0 +1,75 @@ +/* + * 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.tomcat.util.http.fileupload.impl; + +import org.apache.tomcat.util.http.fileupload.FileUploadException; + +/** + * This exception is thrown, if a requests permitted size + * is exceeded. + */ +abstract class SizeException extends FileUploadException { + + /** + * Serial version UID, being used, if serialized. + */ + private static final long serialVersionUID = -8776225574705254126L; + + /** + * The actual size of the request. + */ + private final long actual; + + /** + * The maximum permitted size of the request. + */ + private final long permitted; + + /** + * Creates a new instance. + * + * @param message The detail message. + * @param actual The actual number of bytes in the request. + * @param permitted The requests size limit, in bytes. + */ + protected SizeException(String message, long actual, long permitted) { + super(message); + this.actual = actual; + this.permitted = permitted; + } + + /** + * Retrieves 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. + * + * @return The permitted size of the request. + * @since 1.3 + */ + public long getPermittedSize() { + return permitted; + } + +} \ No newline at end of file diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/SizeLimitExceededException.java b/java/org/apache/tomcat/util/http/fileupload/impl/SizeLimitExceededException.java new file mode 100644 index 0000000..668e99b --- /dev/null +++ b/java/org/apache/tomcat/util/http/fileupload/impl/SizeLimitExceededException.java @@ -0,0 +1,43 @@ +/* + * 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.tomcat.util.http.fileupload.impl; + +/** + * 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</code> 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(String message, long actual, + long permitted) { + super(message, actual, permitted); + } + +} \ No newline at end of file diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 37e01d6..9b8c487 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -209,6 +209,10 @@ Update the internal fork of Apache Commons Codec to 9637dd4 (2019-12-06, 1.14-SNAPSHOT). Code clean-up and a fix for CODEC-265. (markt) </add> + <add> + Update the internal fork of Apache Commons FileUpload to 2317552 + (2019-12-06, 2.0-SNAPSHOT). Refactoring. (markt) + </add> </changelog> </subsection> </section> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org