This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit b19862c87b3a3c163cda60ff839f59297d438983
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Aug 18 15:58:44 2023 +0100

    Add tests for changes in parameter handling
---
 .../servlet/TestServletRequestParameters.java      |  63 ++++++++++
 .../servlet/TestServletRequestParametersBase.java  |  90 ++++++++++++++
 ...TestServletRequestParametersFormUrlEncoded.java | 104 ++++++++++++++++
 ...stServletRequestParametersMultipartEncoded.java | 131 +++++++++++++++++++++
 .../TestServletRequestParametersQueryString.java   | 112 ++++++++++++++++++
 5 files changed, 500 insertions(+)

diff --git a/test/jakarta/servlet/TestServletRequestParameters.java 
b/test/jakarta/servlet/TestServletRequestParameters.java
new file mode 100644
index 0000000000..1f50f4e5dd
--- /dev/null
+++ b/test/jakarta/servlet/TestServletRequestParameters.java
@@ -0,0 +1,63 @@
+/*
+ * 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 jakarta.servlet;
+
+import java.nio.charset.StandardCharsets;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.apache.catalina.startup.SimpleHttpClient.CRLF;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.startup.Tomcat;
+
+public class TestServletRequestParameters extends 
TestServletRequestParametersBase {
+
+    @Test
+    public void testClientDisconnect() throws Exception {
+
+        Tomcat tomcat = getTomcatInstance();
+
+        tomcat.getConnector().setMaxPostSize(20);
+        
Assert.assertTrue(tomcat.getConnector().setProperty("connectionTimeout", 
"1000"));
+
+        // No file system docBase required
+        StandardContext ctx = (StandardContext) tomcat.addContext("", null);
+
+        // Map the test Servlet
+        ParameterParsingServlet parameterParsingServlet = new 
ParameterParsingServlet();
+        Tomcat.addServlet(ctx, "parameterParsingServlet", 
parameterParsingServlet);
+        ctx.addServletMappingDecoded("/", "parameterParsingServlet");
+
+        tomcat.start();
+
+        TestParameterClient client = new TestParameterClient();
+        client.setPort(getPort());
+        client.setRequest(new String[] { "POST / HTTP/1.1" + CRLF + "Host: 
localhost:" + getPort() + CRLF +
+                "Connection: close" + CRLF + "Transfer-Encoding: chunked" + 
CRLF +
+                "Content-Type: application/x-www-form-urlencoded" + CRLF + 
CRLF + "0a" + CRLF + "var1=val1&" + CRLF });
+
+        client.setResponseBodyEncoding(StandardCharsets.UTF_8);
+        client.connect();
+        // Incomplete request will look timeout reading body and behave like a 
client disconnect
+        client.processRequest();
+
+        // Connection should be closed by the server.
+        //readLine() will receive an EOF reading the status line resuting in a 
null
+        Assert.assertNull(client.getResponseLine());
+    }
+}
diff --git a/test/jakarta/servlet/TestServletRequestParametersBase.java 
b/test/jakarta/servlet/TestServletRequestParametersBase.java
new file mode 100644
index 0000000000..fce787175e
--- /dev/null
+++ b/test/jakarta/servlet/TestServletRequestParametersBase.java
@@ -0,0 +1,90 @@
+/*
+ * 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 jakarta.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.startup.SimpleHttpClient;
+import org.apache.catalina.startup.TomcatBaseTest;
+
+public class TestServletRequestParametersBase extends TomcatBaseTest {
+
+    protected Map<String,List<String>> 
parseReportedParameters(SimpleHttpClient client) {
+        Map<String,List<String>> parameters = new LinkedHashMap<>();
+        if (client.isResponse200()) {
+            String[] lines = 
client.getResponseBody().split(System.lineSeparator());
+            for (String line : lines) {
+                // Every line should be name=value
+                int equalsPos = line.indexOf('=');
+                String name = line.substring(0, equalsPos);
+                String value = line.substring(equalsPos + 1);
+
+                List<String> values = parameters.computeIfAbsent(name, k -> 
new ArrayList<>());
+                values.add(value);
+            }
+        }
+        return parameters;
+    }
+
+
+    protected static class ParameterParsingServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
throws ServletException, IOException {
+
+            resp.setContentType("text/plain");
+            resp.setCharacterEncoding(StandardCharsets.UTF_8);
+            PrintWriter pw = resp.getWriter();
+
+            Enumeration<String> names = req.getParameterNames();
+            while (names.hasMoreElements()) {
+                String name = names.nextElement();
+                for (String value : req.getParameterValues(name)) {
+                    pw.print(name + "=" + value + '\n');
+                }
+            }
+        }
+
+        @Override
+        protected void doPost(HttpServletRequest req, HttpServletResponse 
resp) throws ServletException, IOException {
+            // Required parameter processing is the same as for GET
+            doGet(req, resp);
+        }
+    }
+
+
+    protected static class TestParameterClient extends SimpleHttpClient {
+
+        @Override
+        public boolean isResponseBodyOK() {
+            return true;
+        }
+    }
+}
diff --git 
a/test/jakarta/servlet/TestServletRequestParametersFormUrlEncoded.java 
b/test/jakarta/servlet/TestServletRequestParametersFormUrlEncoded.java
new file mode 100644
index 0000000000..4266eef7c6
--- /dev/null
+++ b/test/jakarta/servlet/TestServletRequestParametersFormUrlEncoded.java
@@ -0,0 +1,104 @@
+/*
+ * 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 jakarta.servlet;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+
+import static org.apache.catalina.startup.SimpleHttpClient.CRLF;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.startup.Tomcat;
+
+@RunWith(Parameterized.class)
+public class TestServletRequestParametersFormUrlEncoded extends 
TestServletRequestParametersBase {
+
+    @Parameterized.Parameters(name = "{index}: chunked[{0}]")
+    public static Collection<Object[]> parameters() {
+        List<Object[]> parameterSets = new ArrayList<>();
+
+        for (Boolean chunked : booleans) {
+            parameterSets.add(new Object[] { chunked });
+        }
+
+        return parameterSets;
+    }
+
+    @Parameter(0)
+    public boolean chunked;
+
+
+    @Test
+    public void testBodyTooLarge() throws Exception {
+
+        Tomcat tomcat = getTomcatInstance();
+
+        tomcat.getConnector().setMaxPostSize(20);
+
+        // No file system docBase required
+        StandardContext ctx = (StandardContext) tomcat.addContext("", null);
+
+        // Map the test Servlet
+        ParameterParsingServlet parameterParsingServlet = new 
ParameterParsingServlet();
+        Tomcat.addServlet(ctx, "parameterParsingServlet", 
parameterParsingServlet);
+        ctx.addServletMappingDecoded("/", "parameterParsingServlet");
+
+        tomcat.start();
+
+        TestParameterClient client = new TestParameterClient();
+        client.setPort(getPort());
+        if (chunked) {
+            client.setRequest(new String[] {
+                    "POST / HTTP/1.1" + CRLF +
+                    "Host: localhost:" + getPort() + CRLF +
+                    "Connection: close" + CRLF +
+                    "Transfer-Encoding: chunked" + CRLF +
+                    "Content-Type: application/x-www-form-urlencoded" + CRLF +
+                    CRLF +
+                    "0a" + CRLF +
+                    "var1=val1&" + CRLF +
+                    "0a" + CRLF +
+                    "var2=val2&" + CRLF +
+                    "0a" + CRLF +
+                    "var3=val3&" + CRLF +
+                    "0" + CRLF });
+        } else {
+            client.setRequest(new String[] {
+                    "POST / HTTP/1.1" + CRLF +
+                    "Host: localhost:" + getPort() + CRLF +
+                    "Connection: close" + CRLF +
+                    "Content-Length: 50" + CRLF +
+                    "Content-Type: application/x-www-form-urlencoded" + CRLF +
+                    CRLF +
+                    "01234567890123456789012345678901234567890123456789" });
+        }
+        client.setResponseBodyEncoding(StandardCharsets.UTF_8);
+        client.connect();
+        client.processRequest();
+
+        Assert.assertEquals(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, 
client.getStatusCode());
+    }
+}
diff --git 
a/test/jakarta/servlet/TestServletRequestParametersMultipartEncoded.java 
b/test/jakarta/servlet/TestServletRequestParametersMultipartEncoded.java
new file mode 100644
index 0000000000..ac0941f853
--- /dev/null
+++ b/test/jakarta/servlet/TestServletRequestParametersMultipartEncoded.java
@@ -0,0 +1,131 @@
+/*
+ * 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 jakarta.servlet;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+
+import static org.apache.catalina.startup.SimpleHttpClient.CRLF;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.startup.Tomcat;
+
+@RunWith(Parameterized.class)
+public class TestServletRequestParametersMultipartEncoded extends 
TestServletRequestParametersBase {
+
+    @Parameterized.Parameters(name = "{index}: chunked[{0}]")
+    public static Collection<Object[]> parameters() {
+        List<Object[]> parameterSets = new ArrayList<>();
+
+        for (Boolean chunked : booleans) {
+            parameterSets.add(new Object[] { chunked });
+        }
+
+        return parameterSets;
+    }
+
+    @Parameter(0)
+    public boolean chunked;
+
+
+    @Test
+    public void testBodyTooLarge() throws Exception {
+
+        Tomcat tomcat = getTomcatInstance();
+
+        tomcat.getConnector().setMaxPostSize(50);
+
+        // No file system docBase required
+        StandardContext ctx = (StandardContext) tomcat.addContext("", null);
+        ctx.setAllowCasualMultipartParsing(true);
+
+        // Map the test Servlet
+        ParameterParsingServlet parameterParsingServlet = new 
ParameterParsingServlet();
+        Tomcat.addServlet(ctx, "parameterParsingServlet", 
parameterParsingServlet);
+        ctx.addServletMappingDecoded("/", "parameterParsingServlet");
+
+        tomcat.start();
+
+        TestParameterClient client = new TestParameterClient();
+        client.setPort(getPort());
+        if (chunked) {
+            client.setRequest(new String[] {
+                    "POST / HTTP/1.1" + CRLF +
+                    "Host: localhost:" + getPort() + CRLF +
+                    "Connection: close" + CRLF +
+                    "Transfer-Encoding: chunked" + CRLF +
+                    "Content-Type: multipart/form-data; boundary=AaBbCc" + 
CRLF +
+                    CRLF +
+                    "3f" + CRLF +
+                    "--AaBbCc" + CRLF +
+                    "Content-Disposition: form-data; name=\"var1\"" + CRLF +
+                    CRLF +
+                    "val1" + CRLF +
+                    CRLF +
+                    "3f" + CRLF +
+                    "--AaBbCc" + CRLF +
+                    "Content-Disposition: form-data; name=\"var2\"" + CRLF +
+                    CRLF +
+                    "val2" + CRLF +
+                    CRLF +
+                    "3f" + CRLF +
+                    "--AaBbCc" + CRLF +
+                    "Content-Disposition: form-data; name=\"var3\"" + CRLF +
+                    CRLF +
+                    "val3" + CRLF +
+                    CRLF +
+                    "0a" + CRLF +
+                    "--AaBbCc--" + CRLF +
+                    "0" + CRLF});
+        } else {
+            client.setRequest(new String[] {
+                    "POST / HTTP/1.1" + CRLF +
+                    "Host: localhost:" + getPort() + CRLF +
+                    "Connection: close" + CRLF +
+                    "Content-Length: 199" + CRLF +
+                    "Content-Type: multipart/form-data; boundary=AaBbCc" + 
CRLF +
+                    CRLF +
+                    "--AaBbCc" + CRLF +
+                    "Content-Disposition: form-data; name=\"var1\"" + CRLF +
+                    CRLF +
+                    "val1" + CRLF +
+                    "--AaBbCc" + CRLF +
+                    "Content-Disposition: form-data; name=\"var2\"" + CRLF +
+                    CRLF +
+                    "val2" + CRLF +
+                    "--AaBbCc" + CRLF +
+                    "Content-Disposition: form-data; name=\"var3\"" + CRLF +
+                    CRLF +
+                    "val3" + CRLF +
+                    "--AaBbCc--"});
+        }
+        client.setResponseBodyEncoding(StandardCharsets.UTF_8);
+        client.connect();
+        client.processRequest();
+
+        Assert.assertEquals(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, 
client.getStatusCode());
+    }
+}
diff --git a/test/jakarta/servlet/TestServletRequestParametersQueryString.java 
b/test/jakarta/servlet/TestServletRequestParametersQueryString.java
new file mode 100644
index 0000000000..037bdd55cc
--- /dev/null
+++ b/test/jakarta/servlet/TestServletRequestParametersQueryString.java
@@ -0,0 +1,112 @@
+/*
+ * 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 jakarta.servlet;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+
+import static org.apache.catalina.startup.SimpleHttpClient.CRLF;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.startup.Tomcat;
+
+@RunWith(Parameterized.class)
+public class TestServletRequestParametersQueryString extends 
TestServletRequestParametersBase {
+
+    private static final Integer SC_OK = 
Integer.valueOf(HttpServletResponse.SC_OK);
+    private static final Integer SC_BAD_REQUEST = 
Integer.valueOf(HttpServletResponse.SC_BAD_REQUEST);
+    private static final Integer ZERO = Integer.valueOf(0);
+    private static final Integer TWO = Integer.valueOf(2);
+
+    @Parameterized.Parameters(name = "{index}: queryString[{0}], 
expectedStatusCode[{1}]")
+    public static Collection<Object[]> parameters() {
+        List<Object[]> parameterSets = new ArrayList<>();
+
+        // Empty parameter
+        parameterSets.add(new Object[] { "before=aaa&&after=zzz", SC_OK, TWO} 
);
+
+        // Invalid parameter
+        parameterSets.add(new Object[] { "before=aaa&=value&after=zzz", 
SC_BAD_REQUEST, ZERO} );
+
+        // Invalid %nn encoding
+        parameterSets.add(new Object[] { "before=aaa&test=val%GGue&after=zzz", 
SC_BAD_REQUEST, ZERO} );
+
+        // Invalid UTF-8 byte
+        parameterSets.add(new Object[] { "before=aaa&test=val%FFue&after=zzz", 
SC_BAD_REQUEST, ZERO} );
+
+        // There are no unmappable UTF-8 code points
+
+        // Too many parameters
+        parameterSets.add(new Object[] { 
"before=aaa&test=value&after=zzz&extra=yyy", SC_BAD_REQUEST, ZERO} );
+
+        return parameterSets;
+    }
+
+    @Parameter(0)
+    public String queryString;
+
+    @Parameter(1)
+    public int expectedStatusCode;
+
+    @Parameter(2)
+    public int expectedValidParameterCount;
+
+
+    @Test
+    public void testParameterParsing() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        tomcat.getConnector().setMaxParameterCount(3);
+
+        // No file system docBase required
+        StandardContext ctx = (StandardContext) tomcat.addContext("", null);
+
+        // Map the test Servlet
+        ParameterParsingServlet parameterParsingServlet = new 
ParameterParsingServlet();
+        Tomcat.addServlet(ctx, "parameterParsingServlet", 
parameterParsingServlet);
+        ctx.addServletMappingDecoded("/", "parameterParsingServlet");
+
+        tomcat.start();
+
+        TestParameterClient client = new TestParameterClient();
+        client.setPort(getPort());
+        client.setRequest(new String[] {
+                "GET /?" + queryString +" HTTP/1.1" + CRLF +
+                "Host: localhost:" + getPort() + CRLF +
+                "Connection: close" + CRLF +
+                CRLF });
+        client.setResponseBodyEncoding(StandardCharsets.UTF_8);
+        client.connect();
+        client.processRequest();
+
+        Assert.assertEquals(expectedStatusCode, client.getStatusCode());
+
+        Map<String,List<String>> parameters = parseReportedParameters(client);
+
+        Assert.assertEquals(expectedValidParameterCount, parameters.size());
+    }
+}
\ No newline at end of file


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

Reply via email to