From 987cc4dc325860a10b079bbbd8c3f6c5745c86a4 Mon Sep 17 00:00:00 2001 From: Mark Thomas Date: Mon, 22 Aug 2016 15:18:50 +0000 Subject: [PATCH] Update the internal fork of Commons FileUpload to afdedc9. This pulls in a fix to improve the performance with large multipart boundaries and some Javadoc improvements. git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc8.5.x/trunk@1757203 13f79535-47bb-0310-9956-ffa450edef68 --- SVN-MERGE.txt => MERGE.txt | 37 +++++++++--- .../util/http/fileupload/MultipartStream.java | 59 ++++++++++++++----- .../fileupload/util/LimitedInputStream.java | 10 ++-- .../util/mime/QuotedPrintableDecoder.java | 2 +- webapps/docs/changelog.xml | 5 ++ 5 files changed, 84 insertions(+), 29 deletions(-) rename SVN-MERGE.txt => MERGE.txt (68%) diff --git a/SVN-MERGE.txt b/MERGE.txt similarity index 68% rename from SVN-MERGE.txt rename to MERGE.txt index 4210204553fc..db3998e6e571 100644 --- a/SVN-MERGE.txt +++ b/MERGE.txt @@ -21,11 +21,15 @@ ideal. These include: - potential conflicts if a web application ships with the same JAR - a large JAR where Tomcat only depends on a small fraction -There are various approaches taken to dealing with this. One of those approaches -is to svn copy the classes to the Tomcat source tree, modify them (always with a -package rename, sometimes with additional changes) and then keep them in sync -with the original via regular svn merges. This file keeps track of these copies -to assist committers in keeping them up to date. + +SVN +=== + +For sources hosted in svn the approache is to svn copy the classes to the Tomcat +source tree, modify them (always with a package rename, sometimes with +additional changes) and then keep them in sync with the original via regular svn +merges. This file keeps track of these copies to assist committers in keeping +them up to date. BCEL org.apache.tomcat.util.bcel is copied from: @@ -40,10 +44,8 @@ org.apache.tomcat.dbcp.pool2 is copied from: /commons/proper/pool/trunk/src/main/java/org/apache/commons/pool2 FileUpload -org.apache.tomcat.util.http.fileupload is copied from: -/commons/proper/fileupload/trunk/src/main/java/org/apache/commons/fileupload -Note: Tomcat's copy of fileupload also includes classes copied manually (rather - than svn copied) from Commons IO. +This used to be hosted in svn. All changes up to the point where FileUpload was +migrated to git have been merged. Codec org.apache.tomcat.util.codec is copied from: @@ -51,3 +53,20 @@ org.apache.tomcat.util.codec is copied from: Note: Only classes required for Base64 encoding/decoding. The rest are removed. +GIT +=== + +Updates from Git are applied manually via patch files. Patch files are generated +using: +git diff : HEAD: > temp.patch +The more recently merged SHA1 for the component below should be updated after +the patch file has been applied and committed + +FileUpload +Sub-tree: +src/main/java/org/apache/commons/fileupload +The SHA1 ID for the most recent commit to be merged to Tomcat is: +86b11bbc1437a12fa64bc1484c4edc0bdd5a0966 + +Note: Tomcat's copy of fileupload also includes classes copied manually (rather + than svn copied) from Commons IO. diff --git a/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java b/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java index 9a3b0a08ae91..19ad36db5a8f 100644 --- a/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java +++ b/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java @@ -225,6 +225,11 @@ private void notifyListener() { */ private final byte[] boundary; + /** + * The table for Knuth-Morris-Pratt search algorithm + */ + private int[] boundaryTable; + /** * The length of the buffer used for processing the request. */ @@ -302,12 +307,14 @@ public MultipartStream(InputStream input, this.notifier = pNotifier; this.boundary = new byte[this.boundaryLength]; + this.boundaryTable = new int[this.boundaryLength + 1]; this.keepRegion = this.boundary.length; System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0, BOUNDARY_PREFIX.length); System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length, boundary.length); + computeBoundaryTable(); head = 0; tail = 0; @@ -453,6 +460,31 @@ public void setBoundary(byte[] boundary) } System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length, boundary.length); + computeBoundaryTable(); + } + + /** + * Compute the table used for Knuth-Morris-Pratt search algorithm. + */ + private void computeBoundaryTable() { + int position = 2; + int candidate = 0; + + boundaryTable[0] = -1; + boundaryTable[1] = 0; + + while (position <= boundaryLength) { + if (boundary[position - 1] == boundary[candidate]) { + boundaryTable[position] = candidate + 1; + candidate++; + position++; + } else if (candidate > 0) { + candidate = boundaryTable[candidate]; + } else { + boundaryTable[position] = 0; + position++; + } + } } /** @@ -575,6 +607,7 @@ public boolean skipPreamble() throws IOException { // First delimiter may be not preceeded with a CRLF. System.arraycopy(boundary, 2, boundary, 0, boundary.length - 2); boundaryLength = boundary.length - 2; + computeBoundaryTable(); try { // Discard all data up to the delimiter. discardBodyData(); @@ -590,6 +623,7 @@ public boolean skipPreamble() throws IOException { boundaryLength = boundary.length; boundary[0] = CR; boundary[1] = LF; + computeBoundaryTable(); } } @@ -645,23 +679,20 @@ protected int findByte(byte value, * not found. */ protected int findSeparator() { - int first; - int match = 0; - int maxpos = tail - boundaryLength; - for (first = head; first <= maxpos && match != boundaryLength; first++) { - first = findByte(boundary[0], first); - if (first == -1 || first > maxpos) { - return -1; + + int bufferPos = this.head; + int tablePos = 0; + + while (bufferPos < this.tail) { + while (tablePos >= 0 && buffer[bufferPos] != boundary[tablePos]) { + tablePos = boundaryTable[tablePos]; } - for (match = 1; match < boundaryLength; match++) { - if (buffer[first + match] != boundary[match]) { - break; - } + bufferPos++; + tablePos++; + if (tablePos == boundaryLength) { + return bufferPos - boundaryLength; } } - if (match == boundaryLength) { - return first - 1; - } return -1; } diff --git a/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java b/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java index e10d1727b02c..f45473169329 100644 --- a/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java +++ b/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java @@ -91,7 +91,7 @@ private void checkLimit() throws IOException { * * @return the next byte of data, or -1 if the end of the * stream is reached. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ @Override @@ -120,11 +120,11 @@ public int read() throws IOException { * @return the total number of bytes read into the buffer, or * -1 if there is no more data because the end of * the stream has been reached. - * @exception NullPointerException If b is null. - * @exception IndexOutOfBoundsException If off is negative, + * @throws NullPointerException If b is null. + * @throws IndexOutOfBoundsException If off is negative, * len is negative, or len is greater than * b.length - off - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ @Override @@ -154,7 +154,7 @@ public boolean isClosed() throws IOException { * This * method simply performs in.close(). * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ @Override 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 bf1f99db8d54..16b7cd0e53f5 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,7 +44,7 @@ private QuotedPrintableDecoder() { * @param out The output stream used to return the decoded data. * * @return the number of bytes produced. - * @exception IOException if aproblem occurs during either decoding or + * @throws IOException if a problem occurs during either decoding or * writing to the stream */ public static int decode(byte[] data, OutputStream out) throws IOException { diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 5430dca80fef..0a7040b11640 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -286,6 +286,11 @@ Update the internal fork of Commons Codec to r1757174. Code formatting changes only. (markt) + + Update the internal fork of Commons FileUpload to afdedc9. This pulls in + a fix to improve the performance with large multipart boundaries. + (markt) +