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 58fd47f  Allow for relaxed validation of path and query characters in 
HTTP/2
58fd47f is described below

commit 58fd47f3c7488865c2185dc75b4ab4469b5f70c1
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Sat Jan 8 16:37:52 2022 +0000

    Allow for relaxed validation of path and query characters in HTTP/2
    
    Follow-up to https://bz.apache.org/bugzilla/show_bug.cgi?id=65785
---
 java/org/apache/coyote/http2/StreamProcessor.java  |  9 ++++-
 .../apache/coyote/http2/TestStreamProcessor.java   | 45 ++++++++++++++++++++++
 2 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/java/org/apache/coyote/http2/StreamProcessor.java 
b/java/org/apache/coyote/http2/StreamProcessor.java
index ae2b7b5..9b4b62f 100644
--- a/java/org/apache/coyote/http2/StreamProcessor.java
+++ b/java/org/apache/coyote/http2/StreamProcessor.java
@@ -32,6 +32,7 @@ import org.apache.coyote.ErrorState;
 import org.apache.coyote.Request;
 import org.apache.coyote.RequestGroupInfo;
 import org.apache.coyote.Response;
+import org.apache.coyote.http11.AbstractHttp11Protocol;
 import org.apache.coyote.http11.filters.GzipOutputFilter;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
@@ -465,6 +466,10 @@ class StreamProcessor extends AbstractProcessor {
      * The checks performed below are based on the checks in Http11InputBuffer.
      */
     private boolean validateRequest() {
+        HttpParser httpParser = new HttpParser(
+                ((AbstractHttp11Protocol<?>) 
handler.getProtocol().getHttp11Protocol()).getRelaxedPathChars(),
+                ((AbstractHttp11Protocol<?>) 
handler.getProtocol().getHttp11Protocol()).getRelaxedQueryChars());
+
         // Method name must be a token
         String method = request.method().toString();
         if (!HttpParser.isToken(method)) {
@@ -475,7 +480,7 @@ class StreamProcessor extends AbstractProcessor {
         // (other checks such as valid %nn happen later)
         ByteChunk bc = request.requestURI().getByteChunk();
         for (int i = bc.getStart(); i < bc.getEnd(); i++) {
-            if (HttpParser.isNotRequestTarget(bc.getBuffer()[i])) {
+            if (httpParser.isNotRequestTargetRelaxed(bc.getBuffer()[i])) {
                 return false;
             }
         }
@@ -485,7 +490,7 @@ class StreamProcessor extends AbstractProcessor {
         String qs = request.queryString().toString();
         if (qs != null) {
             for (char c : qs.toCharArray()) {
-                if (!HttpParser.isQuery(c)) {
+                if (!httpParser.isQueryRelaxed(c)) {
                     return false;
                 }
             }
diff --git a/test/org/apache/coyote/http2/TestStreamProcessor.java 
b/test/org/apache/coyote/http2/TestStreamProcessor.java
index 997b99c..97bf548 100644
--- a/test/org/apache/coyote/http2/TestStreamProcessor.java
+++ b/test/org/apache/coyote/http2/TestStreamProcessor.java
@@ -347,6 +347,51 @@ public class TestStreamProcessor extends Http2TestBase {
     }
 
 
+    @Test
+    public void testValidateRequestQueryStringRelaxed() throws Exception {
+        enableHttp2();
+
+        Tomcat tomcat = getTomcatInstance();
+
+        File appDir = new File("test/webapp");
+        Context ctxt = tomcat.addWebapp(null, "", appDir.getAbsolutePath());
+
+        Tomcat.addServlet(ctxt, "simple", new SimpleServlet());
+        ctxt.addServletMappingDecoded("/simple", "simple");
+
+        tomcat.getConnector().setProperty("relaxedQueryChars", "[]");
+
+        tomcat.start();
+
+        openClientConnection();
+        doHttpUpgrade();
+        sendClientPreface();
+        validateHttp2InitialResponse();
+
+        byte[] frameHeader = new byte[9];
+        ByteBuffer headersPayload = ByteBuffer.allocate(128);
+
+        List<Header> headers = new ArrayList<>(4);
+        headers.add(new Header(":method", "GET"));
+        headers.add(new Header(":scheme", "http"));
+        headers.add(new Header(":path", "/index.html?foo=[]"));
+        headers.add(new Header(":authority", "localhost:" + getPort()));
+
+        buildGetRequest(frameHeader, headersPayload, null, headers, 3);
+
+        writeFrame(frameHeader, headersPayload);
+
+        parser.readFrame(true);
+
+        StringBuilder expected = new StringBuilder();
+        expected.append("3-HeadersStart\n");
+        expected.append("3-Header-[:status]-[200]\n");
+
+        // The status code is the most important thing to test
+        Assert.assertTrue(output.getTrace().startsWith(expected.toString()));
+    }
+
+
     private static final class AsyncComplete extends HttpServlet {
 
         private static final long serialVersionUID = 1L;

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

Reply via email to