You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2020/01/21 22:56:28 UTC
[tomcat] branch master updated: Improve logging of invalid HTTP
header lines
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 a363b53 Improve logging of invalid HTTP header lines
a363b53 is described below
commit a363b5329b9cfa9bf3e25daed5c6434aa4adb52e
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Jan 21 22:24:37 2020 +0000
Improve logging of invalid HTTP header lines
---
.../apache/coyote/http11/Http11InputBuffer.java | 12 +++-
java/org/apache/tomcat/util/http/HeaderUtil.java | 53 ++++++++++++++
.../util/http/TestHeaderUtiltoPrintableString.java | 83 ++++++++++++++++++++++
webapps/docs/changelog.xml | 4 ++
4 files changed, 149 insertions(+), 3 deletions(-)
diff --git a/java/org/apache/coyote/http11/Http11InputBuffer.java b/java/org/apache/coyote/http11/Http11InputBuffer.java
index 5632de2..7eb0669 100644
--- a/java/org/apache/coyote/http11/Http11InputBuffer.java
+++ b/java/org/apache/coyote/http11/Http11InputBuffer.java
@@ -28,6 +28,7 @@ import org.apache.coyote.Request;
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.HeaderUtil;
import org.apache.tomcat.util.http.MimeHeaders;
import org.apache.tomcat.util.http.parser.HttpParser;
import org.apache.tomcat.util.net.ApplicationBufferHandler;
@@ -787,6 +788,7 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
if (headerParsePos == HeaderParsePosition.HEADER_START) {
// Mark the current buffer position
headerData.start = byteBuffer.position();
+ headerData.lineStart = headerData.start;
headerParsePos = HeaderParsePosition.HEADER_NAME;
}
@@ -955,9 +957,8 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
}
if (rejectIllegalHeaderName || log.isDebugEnabled()) {
String message = sm.getString("iib.invalidheader",
- new String(byteBuffer.array(), headerData.start,
- headerData.lastSignificantChar - headerData.start + 1,
- StandardCharsets.ISO_8859_1));
+ HeaderUtil.toPrintableString(byteBuffer.array(), headerData.lineStart,
+ headerData.lastSignificantChar - headerData.lineStart + 1));
if (rejectIllegalHeaderName) {
throw new IllegalArgumentException(message);
}
@@ -1018,6 +1019,10 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
private static class HeaderParseData {
/**
+ * The first character of the header line.
+ */
+ int lineStart = 0;
+ /**
* When parsing header name: first character of the header.<br>
* When skipping broken header line: first character of the header.<br>
* When parsing header value: first character after ':'.
@@ -1045,6 +1050,7 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
*/
MessageBytes headerValue = null;
public void recycle() {
+ lineStart = 0;
start = 0;
realPos = 0;
lastSignificantChar = 0;
diff --git a/java/org/apache/tomcat/util/http/HeaderUtil.java b/java/org/apache/tomcat/util/http/HeaderUtil.java
new file mode 100644
index 0000000..cb40cab
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/HeaderUtil.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+public class HeaderUtil {
+
+ /**
+ * Converts an HTTP header line in byte form to a printable String.
+ * Bytes corresponding to visible ASCII characters will converted to those
+ * characters. All other bytes (0x00 to 0x1F, 0x7F to OxFF) will be
+ * represented in 0xNN form.
+ *
+ * @param bytes Contains an HTTP header line
+ * @param offset The start position of the header line in the array
+ * @param len The length of the HTTP header line
+ *
+ * @return A String with non-printing characters replaced by the 0xNN
+ * equivalent
+ */
+ public static String toPrintableString(byte[] bytes, int offset, int len) {
+ StringBuilder result = new StringBuilder();
+ for (int i = offset; i < offset + len; i++) {
+ char c = (char) (bytes[i] & 0xFF);
+ if (c < 0x20 || c > 0x7E) {
+ result.append("0x");
+ result.append(Character.forDigit((c >> 4) & 0xF, 16));
+ result.append(Character.forDigit((c) & 0xF, 16));
+ } else {
+ result.append(c);
+ }
+ }
+ return result.toString();
+ }
+
+
+ private HeaderUtil() {
+ // Utility class. Hide default constructor.
+ }
+}
diff --git a/test/org/apache/tomcat/util/http/TestHeaderUtiltoPrintableString.java b/test/org/apache/tomcat/util/http/TestHeaderUtiltoPrintableString.java
new file mode 100644
index 0000000..71da5e4
--- /dev/null
+++ b/test/org/apache/tomcat/util/http/TestHeaderUtiltoPrintableString.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+
+@RunWith(Parameterized.class)
+public class TestHeaderUtiltoPrintableString {
+
+ @Parameterized.Parameters(name = "{index}: expected[{1}]")
+ public static Collection<Object[]> parameters() {
+ List<Object[]> parameterSets = new ArrayList<>();
+
+ parameterSets.add(new String[] { "", "" });
+
+ parameterSets.add(new String[] { "abcd", "abcd" });
+
+ parameterSets.add(new String[] { "\u0000abcd", "0x00abcd" });
+ parameterSets.add(new String[] { "ab\u0000cd", "ab0x00cd" });
+ parameterSets.add(new String[] { "abcd\u0000", "abcd0x00" });
+
+ parameterSets.add(new String[] { "\tabcd", "0x09abcd" });
+ parameterSets.add(new String[] { "ab\tcd", "ab0x09cd" });
+ parameterSets.add(new String[] { "abcd\t", "abcd0x09" });
+
+ parameterSets.add(new String[] { " abcd", " abcd" });
+ parameterSets.add(new String[] { "ab cd", "ab cd" });
+ parameterSets.add(new String[] { "abcd ", "abcd " });
+
+ parameterSets.add(new String[] { "~abcd", "~abcd" });
+ parameterSets.add(new String[] { "ab~cd", "ab~cd" });
+ parameterSets.add(new String[] { "abcd~", "abcd~" });
+
+ parameterSets.add(new String[] { "\u007fabcd", "0x7fabcd" });
+ parameterSets.add(new String[] { "ab\u007fcd", "ab0x7fcd" });
+ parameterSets.add(new String[] { "abcd\u007f", "abcd0x7f" });
+
+ parameterSets.add(new String[] { "\u00a3abcd", "0xa3abcd" });
+ parameterSets.add(new String[] { "ab\u00a3cd", "ab0xa3cd" });
+ parameterSets.add(new String[] { "abcd\u00a3", "abcd0xa3" });
+
+ return parameterSets;
+ }
+
+
+ @Parameter(0)
+ public String input;
+ @Parameter(1)
+ public String expected;
+
+
+ @Test
+ public void doTest() {
+ byte[] bytes = input.getBytes(StandardCharsets.ISO_8859_1);
+
+ String result = HeaderUtil.toPrintableString(bytes, 0, bytes.length);
+
+ Assert.assertEquals(expected, result);
+ }
+}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index d7324e1..940a2ff 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -76,6 +76,10 @@
When using an AJP Connector, convert Java Servlet specific request
attributes to the Jakarta Servlet equivalent. (markt)
</add>
+ <add>
+ When reporting / logging invalid HTTP headers encode any non-printing
+ characters using the 0xNN form. (markt)
+ </add>
</changelog>
</subsection>
<subsection name="Other">
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org