This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/master by this push: new c41fe3b Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=63829 c41fe3b is described below commit c41fe3b64d0caed36cc3a76c872e272290473a4f Author: Mark Thomas <ma...@apache.org> AuthorDate: Wed Oct 23 08:50:11 2019 +0200 Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=63829 Improve the check of the Content-Encoding header when looking to see if Tomcat is serving pre-compressed content. Ensure that only a full token is matched and that the match is case insensitive. --- java/org/apache/coyote/CompressionConfig.java | 28 ++++++++++++++++++---- java/org/apache/coyote/LocalStrings.properties | 2 ++ java/org/apache/coyote/http11/Http11Processor.java | 18 ++------------ .../apache/tomcat/util/http/parser/TokenList.java | 24 ++++++++++++++++++- webapps/docs/changelog.xml | 6 +++++ 5 files changed, 57 insertions(+), 21 deletions(-) diff --git a/java/org/apache/coyote/CompressionConfig.java b/java/org/apache/coyote/CompressionConfig.java index fd0652e..520ed2e 100644 --- a/java/org/apache/coyote/CompressionConfig.java +++ b/java/org/apache/coyote/CompressionConfig.java @@ -20,17 +20,26 @@ import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.StringTokenizer; import java.util.regex.Pattern; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.http.ResponseUtil; import org.apache.tomcat.util.http.parser.AcceptEncoding; +import org.apache.tomcat.util.http.parser.TokenList; +import org.apache.tomcat.util.res.StringManager; public class CompressionConfig { + private static final Log log = LogFactory.getLog(CompressionConfig.class); + private static final StringManager sm = StringManager.getManager(CompressionConfig.class); + private int compressionLevel = 0; private Pattern noCompressionUserAgents = null; private String compressibleMimeType = "text/html,text/xml,text/plain,text/css," + @@ -193,10 +202,21 @@ public class CompressionConfig { // Check if content is not already compressed MessageBytes contentEncodingMB = responseHeaders.getValue("Content-Encoding"); - if (contentEncodingMB != null && - (contentEncodingMB.indexOf("gzip") != -1 || - contentEncodingMB.indexOf("br") != -1)) { - return false; + if (contentEncodingMB != null) { + // Content-Encoding values are ordered but order is not important + // for this check so use a Set rather than a List + Set<String> tokens = new HashSet<>(); + try { + TokenList.parseTokenList(responseHeaders.values("Content-Encoding"), tokens); + } catch (IOException e) { + // Because we are using StringReader, any exception here is a + // Tomcat bug. + log.warn(sm.getString("compressionConfig.ContentEncodingParseFail"), e); + return false; + } + if (tokens.contains("gzip") || tokens.contains("br")) { + return false; + } } // If force mode, the length and MIME type checks are skipped diff --git a/java/org/apache/coyote/LocalStrings.properties b/java/org/apache/coyote/LocalStrings.properties index b14fc2c..90159d3 100644 --- a/java/org/apache/coyote/LocalStrings.properties +++ b/java/org/apache/coyote/LocalStrings.properties @@ -46,6 +46,8 @@ abstractProtocolHandler.stop=Stopping ProtocolHandler [{0}] asyncStateMachine.invalidAsyncState=Calling [{0}] is not valid for a request with Async state [{1}] +compressionConfig.ContentEncodingParseFail=Failed to parse Content-Encoding header when chekcing to see if compression was already in use + request.notAsync=It is only valid to switch to non-blocking IO within async processing or HTTP upgrade processing request.nullReadListener=The listener passed to setReadListener() may not be null request.readListenerSet=The non-blocking read listener has already been set diff --git a/java/org/apache/coyote/http11/Http11Processor.java b/java/org/apache/coyote/http11/Http11Processor.java index 6df04cc..7be52d0 100644 --- a/java/org/apache/coyote/http11/Http11Processor.java +++ b/java/org/apache/coyote/http11/Http11Processor.java @@ -18,10 +18,7 @@ package org.apache.coyote.http11; import java.io.IOException; import java.io.InterruptedIOException; -import java.io.StringReader; import java.nio.ByteBuffer; -import java.util.Collection; -import java.util.Enumeration; import java.util.HashSet; import java.util.Locale; import java.util.Set; @@ -566,7 +563,7 @@ public class Http11Processor extends AbstractProcessor { MessageBytes connectionValueMB = headers.getValue(Constants.CONNECTION); if (connectionValueMB != null && !connectionValueMB.isNull()) { Set<String> tokens = new HashSet<>(); - parseConnectionTokens(headers, tokens); + TokenList.parseTokenList(headers.values(Constants.CONNECTION), tokens); if (tokens.contains(Constants.CLOSE)) { keepAlive = false; } else if (tokens.contains(Constants.KEEPALIVE)) { @@ -960,22 +957,11 @@ public class Http11Processor extends AbstractProcessor { } Set<String> tokens = new HashSet<>(); - parseConnectionTokens(headers, tokens); + TokenList.parseTokenList(headers.values(Constants.CONNECTION), tokens); return tokens.contains(token); } - private static void parseConnectionTokens(MimeHeaders headers, Collection<String> tokens) throws IOException { - Enumeration<String> values = headers.values(Constants.CONNECTION); - while (values.hasMoreElements()) { - String nextHeaderValue = values.nextElement(); - if (nextHeaderValue != null) { - TokenList.parseTokenList(new StringReader(nextHeaderValue), tokens); - } - } - } - - private void prepareSendfile(OutputFilter[] outputFilters) { String fileName = (String) request.getAttribute( org.apache.coyote.Constants.SENDFILE_FILENAME_ATTR); diff --git a/java/org/apache/tomcat/util/http/parser/TokenList.java b/java/org/apache/tomcat/util/http/parser/TokenList.java index ca5e153..db40877 100644 --- a/java/org/apache/tomcat/util/http/parser/TokenList.java +++ b/java/org/apache/tomcat/util/http/parser/TokenList.java @@ -18,7 +18,9 @@ package org.apache.tomcat.util.http.parser; import java.io.IOException; import java.io.Reader; +import java.io.StringReader; import java.util.Collection; +import java.util.Enumeration; import java.util.Locale; public class TokenList { @@ -29,12 +31,32 @@ public class TokenList { /** + * Parses an enumeration of header values of the form 1#token, forcing all + * parsed values to lower case. + * + * @param inputs The headers to parse + * @param result The Collection (usually a list of a set) to which the + * parsed tokens should be added + * + * @throws IOException If an I/O error occurs reading the header + */ + public static void parseTokenList(Enumeration<String> inputs, Collection<String> result) throws IOException { + while (inputs.hasMoreElements()) { + String nextHeaderValue = inputs.nextElement(); + if (nextHeaderValue != null) { + TokenList.parseTokenList(new StringReader(nextHeaderValue), result); + } + } + } + + + /** * Parses a header of the form 1#token, forcing all parsed values to lower * case. This is typically used when header values are case-insensitive. * * @param input The header to parse * @param result The Collection (usually a list of a set) to which the - * parsed token should be added + * parsed tokens should be added * * @throws IOException If an I/O error occurs reading the header */ diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index fec9c7f..e0c6146 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -77,6 +77,12 @@ <code>Connection</code> HTTP headers looking for a specific token, be stricter in ensuring that the exact token is present. (markt) </fix> + <fix> + <bug>63829</bug>: Improve the check of the <code>Content-Encoding</code> + header when looking to see if Tomcat is serving pre-compressed content. + Ensure that only a full token is matched and that the match is case + insensitive. (markt) + </fix> </changelog> </subsection> <subsection name="Other"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org