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:57:54 UTC

[tomcat] branch 9.0.x 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 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 ee021f9  Improve logging of invalid HTTP header lines
ee021f9 is described below

commit ee021f90a88222b2b4475eeb8623a27bbb37a1ea
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 1bc44c3..3848af7 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -8987,6 +8987,10 @@
       <add>
         Add support for HTTP/2 including server push. (markt)
       </add>
+      <add>
+        When reporting / logging invalid HTTP headers encode any non-printing
+        characters using the 0xNN form. (markt)
+      </add>
     </changelog>
   </subsection>
   <subsection name="Tribes">


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org