This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/9.0.x by this push: new 2a5d0b0 Update Tomcat's internal fork of Commons FileUpload 2a5d0b0 is described below commit 2a5d0b00ad426f9888453a9987d6ce889be7cb6b Author: Mark Thomas <ma...@apache.org> AuthorDate: Wed Sep 1 17:12:12 2021 +0100 Update Tomcat's internal fork of Commons FileUpload --- MERGE.txt | 2 +- java/org/apache/catalina/connector/Request.java | 3 +- java/org/apache/catalina/core/ApplicationPart.java | 2 +- .../tomcat/util/http/fileupload/FileItem.java | 8 +- .../tomcat/util/http/fileupload/FileUpload.java | 2 +- .../util/http/fileupload/FileUploadBase.java | 18 +--- .../util/http/fileupload/MultipartStream.java | 4 +- .../util/http/fileupload/ParameterParser.java | 12 +-- .../util/http/fileupload/disk/DiskFileItem.java | 116 ++++++++++----------- .../http/fileupload/impl/FileItemIteratorImpl.java | 22 +++- .../http/fileupload/impl/FileItemStreamImpl.java | 29 +++--- .../ParseException.java => impl/package-info.java} | 21 +--- .../http/fileupload/servlet/ServletFileUpload.java | 2 +- .../http/fileupload/util/FileItemHeadersImpl.java | 6 +- .../tomcat/util/http/fileupload/util/Streams.java | 16 +-- .../http/fileupload/util/mime/MimeUtility.java | 35 ++++--- .../http/fileupload/util/mime/ParseException.java | 2 +- .../util/mime/QuotedPrintableDecoder.java | 3 +- .../http/fileupload/util/mime/RFC2231Utility.java | 44 ++++++-- webapps/docs/changelog.xml | 4 + 20 files changed, 176 insertions(+), 175 deletions(-) diff --git a/MERGE.txt b/MERGE.txt index 7b10d6a..73ecd41 100644 --- a/MERGE.txt +++ b/MERGE.txt @@ -51,7 +51,7 @@ FileUpload Sub-tree: src/main/java/org/apache/commons/fileupload2 The SHA1 ID / tag for the most recent commit to be merged to Tomcat is: -ee0a7131b6b87586b28542de354951414dedac3f (2021-01-15) +33d2d79230bb851642435821b380904d24752ee1 (2021-09-01) 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 e1a0e77..40445e0 100644 --- a/java/org/apache/catalina/connector/Request.java +++ b/java/org/apache/catalina/connector/Request.java @@ -107,7 +107,6 @@ 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.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.SizeException; @@ -2962,7 +2961,7 @@ public class Request implements HttpServletRequest { parameters.setParseFailedReason(FailReason.POST_TOO_LARGE); checkSwallowInput(); partsParseException = new IllegalStateException(e); - } catch (FileUploadException e) { + } catch (IOException e) { parameters.setParseFailedReason(FailReason.IO_ERROR); partsParseException = new IOException(e); } catch (IllegalStateException e) { diff --git a/java/org/apache/catalina/core/ApplicationPart.java b/java/org/apache/catalina/core/ApplicationPart.java index d6400b5..5c6cc0c 100644 --- a/java/org/apache/catalina/core/ApplicationPart.java +++ b/java/org/apache/catalina/core/ApplicationPart.java @@ -123,7 +123,7 @@ public class ApplicationPart implements Part { } } - public String getString(String encoding) throws UnsupportedEncodingException { + public String getString(String encoding) throws UnsupportedEncodingException, IOException { return fileItem.getString(encoding); } diff --git a/java/org/apache/tomcat/util/http/fileupload/FileItem.java b/java/org/apache/tomcat/util/http/fileupload/FileItem.java index 29aa496..d1e0523 100644 --- a/java/org/apache/tomcat/util/http/fileupload/FileItem.java +++ b/java/org/apache/tomcat/util/http/fileupload/FileItem.java @@ -20,6 +20,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.UncheckedIOException; import java.io.UnsupportedEncodingException; /** @@ -104,8 +105,10 @@ public interface FileItem extends FileItemHeadersSupport { * Returns the contents of the file item as an array of bytes. * * @return The contents of the file item as an array of bytes. + * + * @throws UncheckedIOException if an I/O error occurs */ - byte[] get(); + byte[] get() throws UncheckedIOException; /** * Returns the contents of the file item as a String, using the specified @@ -118,8 +121,9 @@ public interface FileItem extends FileItemHeadersSupport { * * @throws UnsupportedEncodingException if the requested character * encoding is not available. + * @throws IOException if an I/O error occurs */ - String getString(String encoding) throws UnsupportedEncodingException; + String getString(String encoding) throws UnsupportedEncodingException, IOException; /** * Returns the contents of the file item as a String, using the default diff --git a/java/org/apache/tomcat/util/http/fileupload/FileUpload.java b/java/org/apache/tomcat/util/http/fileupload/FileUpload.java index 9be9caa..f0cfebc 100644 --- a/java/org/apache/tomcat/util/http/fileupload/FileUpload.java +++ b/java/org/apache/tomcat/util/http/fileupload/FileUpload.java @@ -43,7 +43,7 @@ public class FileUpload // ----------------------------------------------------------- Constructors /** - * Constructs an uninitialised instance of this class. + * Constructs an uninitialized instance of this class. * * A factory must be * configured, using {@code setFileItemFactory()}, before attempting diff --git a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java index 30a582c..7d678c2 100644 --- a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java +++ b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java @@ -26,7 +26,6 @@ import java.util.Map; import java.util.Objects; 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; @@ -70,10 +69,7 @@ public abstract class FileUploadBase { if (contentType == null) { return false; } - if (contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART)) { - return true; - } - return false; + return contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART); } // ----------------------------------------------------- Manifest constants @@ -278,12 +274,13 @@ 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()) { final FileItemStream item = iter.next(); // Don't use getName() here to prevent an InvalidFileNameException. - final String fileName = ((FileItemStreamImpl) item).getName(); + final String fileName = item.getName(); final FileItem fileItem = fileItemFactory.createItem(item.getFieldName(), item.getContentType(), item.isFormField(), fileName); items.add(fileItem); @@ -337,12 +334,7 @@ public abstract class FileUploadBase { for (final FileItem fileItem : items) { final String fieldName = fileItem.getFieldName(); - List<FileItem> mappedItems = itemsMap.get(fieldName); - - if (mappedItems == null) { - mappedItems = new ArrayList<>(); - itemsMap.put(fieldName, mappedItems); - } + List<FileItem> mappedItems = itemsMap.computeIfAbsent(fieldName, k -> new ArrayList<>()); mappedItems.add(fileItem); } diff --git a/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java b/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java index 595a975..ab6e8e5 100644 --- a/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java +++ b/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java @@ -401,7 +401,7 @@ public class MultipartStream { public boolean readBoundary() throws FileUploadIOException, MalformedStreamException { final byte[] marker = new byte[2]; - boolean nextChunk = false; + boolean nextChunk; head += boundaryLength; try { @@ -532,7 +532,7 @@ public class MultipartStream { baos.write(b); } - String headers = null; + String headers; if (headerEncoding != null) { try { headers = baos.toString(headerEncoding); diff --git a/java/org/apache/tomcat/util/http/fileupload/ParameterParser.java b/java/org/apache/tomcat/util/http/fileupload/ParameterParser.java index d5b90c2..91a97ae 100644 --- a/java/org/apache/tomcat/util/http/fileupload/ParameterParser.java +++ b/java/org/apache/tomcat/util/http/fileupload/ParameterParser.java @@ -233,8 +233,8 @@ public class ParameterParser { char separator = separators[0]; if (str != null) { int idx = str.length(); - for (char separator2 : separators) { - int tmp = str.indexOf(separator2); + for (final char separator2 : separators) { + final int tmp = str.indexOf(separator2); if (tmp != -1 && tmp < idx) { idx = tmp; separator = separator2; @@ -299,12 +299,12 @@ public class ParameterParser { return new HashMap<>(); } final HashMap<String, String> params = new HashMap<>(); - this.chars = charArray; + this.chars = charArray.clone(); this.pos = offset; this.len = length; - String paramName = null; - String paramValue = null; + String paramName; + String paramValue; while (hasChar()) { paramName = parseToken(new char[] { '=', separator }); @@ -326,7 +326,7 @@ public class ParameterParser { if (hasChar() && (charArray[pos] == separator)) { pos++; // skip separator } - if ((paramName != null) && (paramName.length() > 0)) { + if ((paramName != null) && !paramName.isEmpty()) { paramName = RFC2231Utility.stripDelimiter(paramName); if (this.lowerCaseNames) { paramName = paramName.toLowerCase(Locale.ENGLISH); 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 2f2c25d..4dcc3d9 100644 --- a/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java +++ b/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java @@ -25,7 +25,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.UncheckedIOException; import java.io.UnsupportedEncodingException; +import java.nio.file.Files; import java.util.Map; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; @@ -191,7 +193,7 @@ public class DiskFileItem public InputStream getInputStream() throws IOException { if (!isInMemory()) { - return new FileInputStream(dfos.getFile()); + return Files.newInputStream(dfos.getFile().toPath()); } if (cachedContent == null) { @@ -268,13 +270,14 @@ public class DiskFileItem public long getSize() { if (size >= 0) { return size; - } else if (cachedContent != null) { + } + if (cachedContent != null) { return cachedContent.length; - } else if (dfos.isInMemory()) { + } + if (dfos.isInMemory()) { return dfos.getData().length; - } else { - return dfos.getFile().length(); } + return dfos.getFile().length(); } /** @@ -284,28 +287,25 @@ public class DiskFileItem * * @return The contents of the file as an array of bytes * or {@code null} if the data cannot be read + * + * @throws UncheckedIOException if an I/O error occurs */ @Override - public byte[] get() { + public byte[] get() throws UncheckedIOException { if (isInMemory()) { if (cachedContent == null && dfos != null) { cachedContent = dfos.getData(); } - return cachedContent; + return cachedContent != null ? cachedContent.clone() : new byte[0]; } byte[] fileData = new byte[(int) getSize()]; - InputStream fis = null; - try { - fis = new FileInputStream(dfos.getFile()); + try (InputStream fis = Files.newInputStream(dfos.getFile().toPath())) { IOUtils.readFully(fis, fileData); - } catch (final IOException e) { - fileData = null; - } finally { - IOUtils.closeQuietly(fis); + } catch (IOException e) { + throw new UncheckedIOException(e); } - return fileData; } @@ -323,7 +323,7 @@ public class DiskFileItem */ @Override public String getString(final String charset) - throws UnsupportedEncodingException { + throws UnsupportedEncodingException, IOException { return new String(get(), charset); } @@ -338,15 +338,15 @@ public class DiskFileItem */ @Override public String getString() { - final byte[] rawdata = get(); - String charset = getCharSet(); - if (charset == null) { - charset = defaultCharset; - } try { - return new String(rawdata, charset); - } catch (final UnsupportedEncodingException e) { - return new String(rawdata); + byte[] rawData = get(); + String charset = getCharSet(); + if (charset == null) { + charset = defaultCharset; + } + return new String(rawData, charset); + } catch (final IOException e) { + return new String(new byte[0]); } } @@ -373,46 +373,14 @@ public class DiskFileItem @Override public void write(final File file) throws Exception { if (isInMemory()) { - FileOutputStream fout = null; - try { - fout = new FileOutputStream(file); + try (OutputStream fout = Files.newOutputStream(file.toPath())) { fout.write(get()); - fout.close(); - } finally { - IOUtils.closeQuietly(fout); + } catch (IOException e) { + throw new IOException("Unexpected output data"); } } else { final File outputFile = getStoreLocation(); - if (outputFile != null) { - // 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()) { - if (!file.delete()) { - throw new FileUploadException( - "Cannot write uploaded file to disk!"); - } - } - if (!outputFile.renameTo(file)) { - BufferedInputStream in = null; - BufferedOutputStream out = null; - try { - in = new BufferedInputStream( - new FileInputStream(outputFile)); - out = new BufferedOutputStream( - new FileOutputStream(file)); - IOUtils.copy(in, out); - out.close(); - } finally { - IOUtils.closeQuietly(in); - IOUtils.closeQuietly(out); - } - } - } else { + if (outputFile == null) { /* * For whatever reason we cannot write the * file to disk. @@ -420,6 +388,30 @@ public class DiskFileItem 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!"); + } + if (!outputFile.renameTo(file)) { + BufferedInputStream in = null; + BufferedOutputStream out = null; + try { + in = new BufferedInputStream(new FileInputStream(outputFile)); + out = new BufferedOutputStream(new FileOutputStream(file)); + IOUtils.copy(in, out); + out.close(); + } finally { + IOUtils.closeQuietly(in); + IOUtils.closeQuietly(out); + } + } } } @@ -503,11 +495,9 @@ public class DiskFileItem * @return An {@link java.io.OutputStream OutputStream} that can be used * for storing the contents of the file. * - * @throws IOException if an error occurs. */ @Override - public OutputStream getOutputStream() - throws IOException { + public OutputStream getOutputStream() { if (dfos == null) { final File outputFile = getTempFile(); dfos = new DeferredFileOutputStream(sizeThreshold, outputFile); diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/FileItemIteratorImpl.java b/java/org/apache/tomcat/util/http/fileupload/impl/FileItemIteratorImpl.java index 6e2d574..29e89f6 100644 --- a/java/org/apache/tomcat/util/http/fileupload/impl/FileItemIteratorImpl.java +++ b/java/org/apache/tomcat/util/http/fileupload/impl/FileItemIteratorImpl.java @@ -42,9 +42,24 @@ import org.apache.tomcat.util.http.fileupload.util.LimitedInputStream; * {@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; - private long sizeMax, fileSizeMax; + /** + * The maximum allowed size of a complete request. + */ + private long sizeMax; + /** + * The maximum allowed size of a single uploaded file. + */ + private long fileSizeMax; @Override @@ -326,10 +341,11 @@ 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; } -} \ 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 index dd02e6d..bab5d98 100644 --- a/java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java +++ b/java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java @@ -33,6 +33,11 @@ import org.apache.tomcat.util.http.fileupload.util.Streams; * Default implementation of {@link FileItemStream}. */ public class FileItemStreamImpl implements FileItemStream { + /** + * The File Item iterator implementation. + * + * @see FileItemIteratorImpl + */ private final FileItemIteratorImpl fileItemIteratorImpl; /** @@ -48,7 +53,7 @@ public class FileItemStreamImpl implements FileItemStream { /** * The file items file name. */ - final String name; + private final String name; /** * Whether the file item is a form field. @@ -87,18 +92,16 @@ public class FileItemStreamImpl implements FileItemStream { contentType = pContentType; formField = pFormField; final long fileSizeMax = fileItemIteratorImpl.getFileSizeMax(); - if (fileSizeMax != -1) { // Check if limit is already exceeded - if (pContentLength != -1 - && pContentLength > fileSizeMax) { - final 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); - } + if (fileSizeMax != -1 && pContentLength != -1 + && pContentLength > fileSizeMax) { + final 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(); diff --git a/java/org/apache/tomcat/util/http/fileupload/util/mime/ParseException.java b/java/org/apache/tomcat/util/http/fileupload/impl/package-info.java similarity index 62% copy from java/org/apache/tomcat/util/http/fileupload/util/mime/ParseException.java copy to java/org/apache/tomcat/util/http/fileupload/impl/package-info.java index ea102a9..134a3f6 100644 --- a/java/org/apache/tomcat/util/http/fileupload/util/mime/ParseException.java +++ b/java/org/apache/tomcat/util/http/fileupload/impl/package-info.java @@ -14,25 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.tomcat.util.http.fileupload.util.mime; /** - * @since 1.3 + * Implementations and exceptions utils. */ -final class ParseException extends Exception { - - /** - * The UID to use when serializing this instance. - */ - private static final long serialVersionUID = 5355281266579392077L; - - /** - * Constructs a new exception with the specified detail message. - * - * @param message the detail message. - */ - public ParseException(final String message) { - super(message); - } - -} +package org.apache.tomcat.util.http.fileupload.impl; diff --git a/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java b/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java index 98dec64..268bad8 100644 --- a/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java +++ b/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java @@ -73,7 +73,7 @@ public class ServletFileUpload extends FileUpload { // ----------------------------------------------------------- Constructors /** - * Constructs an uninitialised instance of this class. A factory must be + * Constructs an uninitialized instance of this class. A factory must be * configured, using {@code setFileItemFactory()}, before attempting * to parse requests. * diff --git a/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java b/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java index 1047dc3..ebf1fec 100644 --- a/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java +++ b/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java @@ -87,11 +87,7 @@ public class FileItemHeadersImpl implements FileItemHeaders, Serializable { */ public synchronized void addHeader(final String name, final String value) { final String nameLower = name.toLowerCase(Locale.ENGLISH); - List<String> headerValueList = headerNameToValueListMap.get(nameLower); - if (null == headerValueList) { - headerValueList = new ArrayList<>(); - headerNameToValueListMap.put(nameLower, headerValueList); - } + List<String> headerValueList = headerNameToValueListMap.computeIfAbsent(nameLower, k -> new ArrayList<>()); headerValueList.add(value); } diff --git a/java/org/apache/tomcat/util/http/fileupload/util/Streams.java b/java/org/apache/tomcat/util/http/fileupload/util/Streams.java index 1ba6106..03c1f90 100644 --- a/java/org/apache/tomcat/util/http/fileupload/util/Streams.java +++ b/java/org/apache/tomcat/util/http/fileupload/util/Streams.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import org.apache.tomcat.util.http.fileupload.IOUtils; import org.apache.tomcat.util.http.fileupload.InvalidFileNameException; /** @@ -63,7 +62,8 @@ 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) + public static long copy(final InputStream inputStream, final OutputStream outputStream, + final boolean closeOutputStream) throws IOException { return copy(inputStream, outputStream, closeOutputStream, new byte[DEFAULT_BUFFER_SIZE]); } @@ -90,9 +90,8 @@ public final class Streams { final OutputStream outputStream, final boolean closeOutputStream, final byte[] buffer) throws IOException { - OutputStream out = outputStream; - InputStream in = inputStream; - try { + try (OutputStream out = outputStream; + InputStream in = inputStream) { long total = 0; for (;;) { final int res = in.read(buffer); @@ -112,16 +111,9 @@ public final class Streams { } else { out.flush(); } - out = null; } in.close(); - in = null; return total; - } finally { - IOUtils.closeQuietly(in); - if (closeOutputStream) { - IOUtils.closeQuietly(out); - } } } diff --git a/java/org/apache/tomcat/util/http/fileupload/util/mime/MimeUtility.java b/java/org/apache/tomcat/util/http/fileupload/util/mime/MimeUtility.java index a4da181..70a4fb3 100644 --- a/java/org/apache/tomcat/util/http/fileupload/util/mime/MimeUtility.java +++ b/java/org/apache/tomcat/util/http/fileupload/util/mime/MimeUtility.java @@ -19,6 +19,7 @@ package org.apache.tomcat.util.http.fileupload.util.mime; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -33,11 +34,6 @@ import org.apache.tomcat.util.codec.binary.Base64; public final class MimeUtility { /** - * The {@code US-ASCII} charset identifier constant. - */ - private static final String US_ASCII_CHARSET = "US-ASCII"; - - /** * The marker to indicate text is encoded with BASE64 algorithm. */ private static final String BASE64_ENCODING_MARKER = "B"; @@ -68,8 +64,15 @@ public final class MimeUtility { private static final Map<String, String> MIME2JAVA = new HashMap<>(); static { + MIME2JAVA.put("iso-2022-cn", "ISO2022CN"); + MIME2JAVA.put("iso-2022-kr", "ISO2022KR"); + MIME2JAVA.put("utf-8", "UTF8"); + MIME2JAVA.put("utf8", "UTF8"); MIME2JAVA.put("ja_jp.iso2022-7", "ISO2022JP"); MIME2JAVA.put("ja_jp.eucjp", "EUCJIS"); + MIME2JAVA.put("euc-kr", "KSC5601"); + MIME2JAVA.put("euckr", "KSC5601"); + MIME2JAVA.put("us-ascii", "ISO-8859-1"); MIME2JAVA.put("x-us-ascii", "ISO-8859-1"); } @@ -117,14 +120,13 @@ public final class MimeUtility { while (offset < endOffset) { // step over the white space characters. ch = text.charAt(offset); - if (LINEAR_WHITESPACE.indexOf(ch) != -1) { // whitespace found - offset++; - } else { + if (LINEAR_WHITESPACE.indexOf(ch) == -1) { // record the location of the first non lwsp and drop down to process the // token characters. endWhiteSpace = offset; break; } + offset++; } } else { // we have a word token. We need to scan over the word and then try to parse it. @@ -133,11 +135,10 @@ public final class MimeUtility { while (offset < endOffset) { // step over the non white space characters. ch = text.charAt(offset); - if (LINEAR_WHITESPACE.indexOf(ch) == -1) { // not white space - offset++; - } else { + if (LINEAR_WHITESPACE.indexOf(ch) != -1) { break; } + offset++; //NB: Trailing whitespace on these header strings will just be discarded. } @@ -151,7 +152,7 @@ public final class MimeUtility { // are any whitespace characters significant? Append 'em if we've got 'em. if (!previousTokenEncoded && startWhiteSpace != -1) { - decodedText.append(text.substring(startWhiteSpace, endWhiteSpace)); + decodedText.append(text, startWhiteSpace, endWhiteSpace); startWhiteSpace = -1; } // this is definitely a decoded token. @@ -169,7 +170,7 @@ public final class MimeUtility { // this is a normal token, so it doesn't matter what the previous token was. Add the white space // if we have it. if (startWhiteSpace != -1) { - decodedText.append(text.substring(startWhiteSpace, endWhiteSpace)); + decodedText.append(text, startWhiteSpace, endWhiteSpace); startWhiteSpace = -1; } // this is not a decoded token. @@ -190,8 +191,8 @@ public final class MimeUtility { * @param word The possibly encoded word value. * * @return The decoded word. - * @throws ParseException - * @throws UnsupportedEncodingException + * @throws ParseException in case of a parse error of the RFC 2047 + * @throws UnsupportedEncodingException Thrown when Invalid RFC 2047 encoding was found */ private static String decodeWord(final String word) throws ParseException, UnsupportedEncodingException { // encoded words start with the characters "=?". If this not an encoded word, we throw a @@ -226,7 +227,7 @@ public final class MimeUtility { final String encodedText = word.substring(encodingPos + 1, encodedTextPos); // seems a bit silly to encode a null string, but easy to deal with. - if (encodedText.length() == 0) { + if (encodedText.isEmpty()) { return ""; } @@ -239,7 +240,7 @@ public final class MimeUtility { if (encoding.equals(BASE64_ENCODING_MARKER)) { decodedData = Base64.decodeBase64(encodedText); } else if (encoding.equals(QUOTEDPRINTABLE_ENCODING_MARKER)) { // maybe quoted printable. - byte[] encodedData = encodedText.getBytes(US_ASCII_CHARSET); + byte[] encodedData = encodedText.getBytes(StandardCharsets.US_ASCII); QuotedPrintableDecoder.decode(encodedData, out); decodedData = out.toByteArray(); } else { diff --git a/java/org/apache/tomcat/util/http/fileupload/util/mime/ParseException.java b/java/org/apache/tomcat/util/http/fileupload/util/mime/ParseException.java index ea102a9..bf31a53 100644 --- a/java/org/apache/tomcat/util/http/fileupload/util/mime/ParseException.java +++ b/java/org/apache/tomcat/util/http/fileupload/util/mime/ParseException.java @@ -31,7 +31,7 @@ final class ParseException extends Exception { * * @param message the detail message. */ - public ParseException(final String message) { + ParseException(final String message) { super(message); } diff --git a/java/org/apache/tomcat/util/http/fileupload/util/mime/QuotedPrintableDecoder.java b/java/org/apache/tomcat/util/http/fileupload/util/mime/QuotedPrintableDecoder.java index b7a75de..3a563b9 100644 --- a/java/org/apache/tomcat/util/http/fileupload/util/mime/QuotedPrintableDecoder.java +++ b/java/org/apache/tomcat/util/http/fileupload/util/mime/QuotedPrintableDecoder.java @@ -44,8 +44,7 @@ final class QuotedPrintableDecoder { * @param out The output stream used to return the decoded data. * * @return the number of bytes produced. - * @throws IOException if a problem occurs during either decoding or - * writing to the stream + * @throws IOException if an IO error occurs */ public static int decode(final byte[] data, final OutputStream out) throws IOException { int off = 0; diff --git a/java/org/apache/tomcat/util/http/fileupload/util/mime/RFC2231Utility.java b/java/org/apache/tomcat/util/http/fileupload/util/mime/RFC2231Utility.java index 99333f4..c15bb20 100644 --- a/java/org/apache/tomcat/util/http/fileupload/util/mime/RFC2231Utility.java +++ b/java/org/apache/tomcat/util/http/fileupload/util/mime/RFC2231Utility.java @@ -22,7 +22,8 @@ import java.io.UnsupportedEncodingException; * Utility class to decode/encode character set on HTTP Header fields based on RFC 2231. * This implementation adheres to RFC 5987 in particular, which was defined for HTTP headers * - * RFC 5987 builds on RFC 2231, but has lesser scope like <a href="https://tools.ietf.org/html/rfc5987#section-3.2">mandatory charset definition</a> + * RFC 5987 builds on RFC 2231, but has lesser scope like + * <a href="https://tools.ietf.org/html/rfc5987#section-3.2">mandatory charset definition</a> * and <a href="https://tools.ietf.org/html/rfc5987#section-4">no parameter continuation</a> * * <p> @@ -30,10 +31,22 @@ import java.io.UnsupportedEncodingException; * @see <a href="https://tools.ietf.org/html/rfc5987">RFC 5987</a> */ public final class RFC2231Utility { - + /** + * The Hexadecimal values char array. + */ private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray(); - - private static final byte[] HEX_DECODE = new byte[0x80]; + /** + * The Hexadecimal representation of 127. + */ + private static final byte MASK = 0x7f; + /** + * The Hexadecimal representation of 128. + */ + private static final int MASK_128 = 0x80; + /** + * The Hexadecimal decode value. + */ + private static final byte[] HEX_DECODE = new byte[MASK_128]; // create a ASCII decoded array of Hexadecimal values static { @@ -44,8 +57,15 @@ 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 + * 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 */ @@ -58,7 +78,7 @@ public final class RFC2231Utility { /** * If {@code paramName} has Asterisk (*) at the end, it will be stripped off, - * else the passed value will be returned + * else the passed value will be returned. * @param paramName The parameter, which is being inspected. * @return stripped {@code paramName} of Asterisk (*), if RFC2231 encoded */ @@ -83,7 +103,8 @@ public final class RFC2231Utility { * <b>Eg 3.</b> {@code UTF-8''%c2%a3%20and%20%e2%82%ac%20rates} * will be decoded to {@code £ and € rates}. * - * @param encodedText - Text to be decoded has a format of {@code <charset>'<language>'<encoded_value>} and ASCII only + * @param encodedText - Text to be decoded has a format of {@code <charset>'<language>'<encoded_value>} + * and ASCII only * @return Decoded text based on charset encoding * @throws UnsupportedEncodingException The requested character set wasn't found. */ @@ -104,11 +125,12 @@ public final class RFC2231Utility { } /** - * Convert {@code text} to their corresponding Hex value + * Convert {@code text} to their corresponding Hex value. * @param text - ASCII text input * @return Byte array of characters decoded from ASCII table */ private static byte[] fromHex(final String text) { + final int shift = 4; final ByteArrayOutputStream out = new ByteArrayOutputStream(text.length()); for (int i = 0; i < text.length();) { final char c = text.charAt(i++); @@ -116,9 +138,9 @@ public final class RFC2231Utility { if (i > text.length() - 2) { break; // unterminated sequence } - final byte b1 = HEX_DECODE[text.charAt(i++) & 0x7f]; - final byte b2 = HEX_DECODE[text.charAt(i++) & 0x7f]; - out.write((b1 << 4) | b2); + final byte b1 = HEX_DECODE[text.charAt(i++) & MASK]; + final byte b2 = HEX_DECODE[text.charAt(i++) & MASK]; + out.write((b1 << shift) | b2); } else { out.write((byte) c); } diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index abb2055..cf33647 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -211,6 +211,10 @@ Add Apache Derby 10.14.2.0 to the testsuite dependencies, for JDBC and DataSource testing. (remm) </update> + <add> + Update the internal fork of Apache Commons FileUpload to 33d2d79 + (2021-09-01, 2.0-SNAPSHOT). Refactoring and code clean-up. (markt) + </add> </changelog> </subsection> </section> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org