diff --git a/java/org/apache/coyote/http11/InternalAprInputBuffer.java b/java/org/apache/coyote/http11/InternalAprInputBuffer.java index 6f153a9d6859..4e6a81aeac14 100644 --- a/java/org/apache/coyote/http11/InternalAprInputBuffer.java +++ b/java/org/apache/coyote/http11/InternalAprInputBuffer.java @@ -484,7 +484,7 @@ private boolean parseHeader() throws IOException { headers.removeHeader(headers.size() - 1); skipLine(lineStart, start); return true; - } else if (chr != Constants.HT && HttpParser.isControl(chr)) { + } else if (HttpParser.isControl(chr) && chr != Constants.HT) { // Invalid value // Delete the header (it will be the most recent one) headers.removeHeader(headers.size() - 1); diff --git a/java/org/apache/coyote/http11/InternalInputBuffer.java b/java/org/apache/coyote/http11/InternalInputBuffer.java index c305d3f17f28..2572e7d8dc33 100644 --- a/java/org/apache/coyote/http11/InternalInputBuffer.java +++ b/java/org/apache/coyote/http11/InternalInputBuffer.java @@ -435,7 +435,7 @@ private boolean parseHeader() throws IOException { // Invalid value - also need to delete header skipLine(lineStart, start, true); return true; - } else if (chr != Constants.HT && HttpParser.isControl(chr)) { + } else if (HttpParser.isControl(chr) && chr != Constants.HT) { // Invalid value - also need to delete header skipLine(lineStart, start, true); return true; diff --git a/java/org/apache/coyote/http11/InternalNioInputBuffer.java b/java/org/apache/coyote/http11/InternalNioInputBuffer.java index a0e087790ec9..3fc5c888f6d6 100644 --- a/java/org/apache/coyote/http11/InternalNioInputBuffer.java +++ b/java/org/apache/coyote/http11/InternalNioInputBuffer.java @@ -670,7 +670,7 @@ private HeaderParseStatus parseHeader() } else if (prevChr == Constants.CR) { // Invalid value - also need to delete header return skipLine(true); - } else if (chr != Constants.HT && HttpParser.isControl(chr)) { + } else if (HttpParser.isControl(chr) && chr != Constants.HT) { // Invalid value - also need to delete header return skipLine(true); } else if (chr == Constants.SP || chr == Constants.HT) { diff --git a/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java b/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java index 05e76802c1d2..7f140bc30cd8 100644 --- a/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java +++ b/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java @@ -31,6 +31,7 @@ import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.util.http.parser.HttpParser; /** * Chunked input filter. Parses chunked data according to @@ -500,6 +501,9 @@ private boolean parseHeader() throws IOException { if (chr == Constants.COLON) { colon = true; + } else if (!HttpParser.isToken(chr)) { + // Non-token characters are illegal in header names + throw new IOException(sm.getString("chunkedInputFilter.invalidTrailerHeaderName")); } else { trailingHeaders.append(chr); } @@ -561,7 +565,9 @@ private boolean parseHeader() throws IOException { if (chr == Constants.CR || chr == Constants.LF) { parseCRLF(true); eol = true; - } else if (chr == Constants.SP) { + } else if (HttpParser.isControl(chr) && chr != Constants.HT) { + throw new IOException(sm.getString("chunkedInputFilter.invalidTrailerHeaderValue")); + } else if (chr == Constants.SP || chr == Constants.HT) { trailingHeaders.append(chr); } else { trailingHeaders.append(chr); diff --git a/java/org/apache/coyote/http11/filters/LocalStrings.properties b/java/org/apache/coyote/http11/filters/LocalStrings.properties index c0dc9d1b10f7..65fdbf248d38 100644 --- a/java/org/apache/coyote/http11/filters/LocalStrings.properties +++ b/java/org/apache/coyote/http11/filters/LocalStrings.properties @@ -23,5 +23,6 @@ chunkedInputFilter.invalidCrlfNoData=Invalid end of line sequence (no data avail chunkedInputFilter.invalidHeader=Invalid chunk header chunkedInputFilter.maxExtension=maxExtensionSize exceeded chunkedInputFilter.maxTrailer=maxTrailerSize exceeded - +chunkedInputFilter.invalidTrailerHeaderName=Invalid trailer header name (non-token character in name) +chunkedInputFilter.invalidTrailerHeaderValue=Invalid trailer header value (control character in value) inputFilter.maxSwallow=maxSwallowSize exceeded diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 6c4d150c2ec2..7d374ad28bd8 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -154,6 +154,9 @@ Include the problematic data in the error message when reporting that the provided request line contains an invalid component. (markt) + + Align validation of HTTP trailer fields with standard fields. (markt) +