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

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


The following commit(s) were added to refs/heads/main by this push:
     new 4d63ed3463 Add tests for OPTIONS behaviour
4d63ed3463 is described below

commit 4d63ed3463bcef02edbc712a2b452dd85fdc86bb
Author: Mark Thomas <[email protected]>
AuthorDate: Fri Oct 23 19:56:45 2026 +0100

    Add tests for OPTIONS behaviour
    
    Co-authored by: Claude / Sonnet 5.5
---
 test/jakarta/servlet/http/TestHttpServlet.java     |  21 +++
 .../TestDefaultServletMethodNotAllowed.java        | 158 +++++++++++++++++++++
 2 files changed, 179 insertions(+)

diff --git a/test/jakarta/servlet/http/TestHttpServlet.java 
b/test/jakarta/servlet/http/TestHttpServlet.java
index eb4d3cc546..1fb3816c3b 100644
--- a/test/jakarta/servlet/http/TestHttpServlet.java
+++ b/test/jakarta/servlet/http/TestHttpServlet.java
@@ -243,6 +243,15 @@ public class TestHttpServlet extends TomcatBaseTest {
     }
 
 
+    /*
+     * An Allow header set by the application before the default doPut() 
implementation is called must not be replaced.
+     */
+    @Test
+    public void testMethodNotAllowedExistingAllow() throws Exception {
+        doTestMethodNotAllowed(new AllowServlet(), "FOO");
+    }
+
+
     @Test
     public void testQueryMethod() throws Exception {
         Tomcat tomcat = getTomcatInstance();
@@ -739,6 +748,18 @@ public class TestHttpServlet extends TomcatBaseTest {
     }
 
 
+    private static class AllowServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doPut(HttpServletRequest req, HttpServletResponse resp) 
throws ServletException, IOException {
+            resp.setHeader("Allow", "FOO");
+            super.doPut(req, resp);
+        }
+    }
+
+
     private static class OptionsServletQuery extends OptionsServlet {
 
         private static final long serialVersionUID = 1L;
diff --git 
a/test/org/apache/catalina/servlets/TestDefaultServletMethodNotAllowed.java 
b/test/org/apache/catalina/servlets/TestDefaultServletMethodNotAllowed.java
new file mode 100644
index 0000000000..77c4a34d0c
--- /dev/null
+++ b/test/org/apache/catalina/servlets/TestDefaultServletMethodNotAllowed.java
@@ -0,0 +1,158 @@
+/*
+ * 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.catalina.servlets;
+
+import java.io.File;
+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;
+import org.junit.runners.Parameterized.Parameters;
+
+import static org.apache.catalina.startup.SimpleHttpClient.CRLF;
+import org.apache.catalina.Context;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.startup.SimpleHttpClient;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.tomcat.util.http.Method;
+
+/**
+ * Methods that the {@link DefaultServlet} does not support (PATCH and QUERY) 
must be rejected with a 405 response that
+ * contains an Allow header that reflects the configuration of the {@link 
DefaultServlet}, not the one derived from the
+ * methods that the {@link DefaultServlet} overrides.
+ */
+@RunWith(Parameterized.class)
+public class TestDefaultServletMethodNotAllowed extends TomcatBaseTest {
+
+    @Parameters(name = "{index}: readonly[{0}], trace[{1}], method[{2}]")
+    public static Collection<Object[]> parameters() {
+        String[] methods = new String[] { Method.PATCH, Method.QUERY };
+
+        List<Object[]> parameterSets = new ArrayList<>();
+        for (Boolean readOnly : booleans) {
+            for (Boolean trace : booleans) {
+                for (String method : methods) {
+                    parameterSets.add(new Object[] { readOnly, trace, method 
});
+                }
+            }
+        }
+        return parameterSets;
+    }
+
+
+    @Parameter(0)
+    public boolean readOnly;
+
+    @Parameter(1)
+    public boolean trace;
+
+    @Parameter(2)
+    public String method;
+
+
+    @Test
+    public void testHttp11() throws Exception {
+        AllowClient client = doRequest("1.1");
+
+        Assert.assertTrue(client.getResponseLine(), client.isResponse405());
+
+        StringBuilder expected = new StringBuilder("OPTIONS, GET, HEAD");
+        if (!readOnly) {
+            expected.append(", PUT, DELETE");
+        }
+        if (trace) {
+            expected.append(", TRACE");
+        }
+        Assert.assertEquals(expected.toString(), client.getAllow());
+    }
+
+
+    /*
+     * 405 is not defined for HTTP/1.0 so a 400 is expected instead.
+     */
+    @Test
+    public void testHttp10() throws Exception {
+        AllowClient client = doRequest("1.0");
+
+        Assert.assertTrue(client.getResponseLine(), client.isResponse400());
+    }
+
+
+    private AllowClient doRequest(String httpVersion) throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        tomcat.getConnector().setAllowTrace(trace);
+
+        // A writable docBase is required else the resources are read-only 
whatever the servlet is configured to do
+        File docBase = new File(getTemporaryDirectory(), 
"default-method-not-allowed");
+        Assert.assertTrue(docBase.mkdirs());
+        addDeleteOnTearDown(docBase);
+
+        Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
+
+        Wrapper w = Tomcat.addServlet(ctx, "default", new DefaultServlet());
+        w.addInitParameter("readonly", Boolean.toString(readOnly));
+        w.addInitParameter("allowPostAsGet", "false");
+        ctx.addServletMapping("/", "default");
+
+        tomcat.start();
+
+        AllowClient client = new AllowClient();
+        client.setPort(getPort());
+        // @formatter:off
+        client.setRequest(new String[] {
+                method + " /test HTTP/" + httpVersion + CRLF +
+                    "Host: localhost:" + getPort() + CRLF +
+                    // QUERY requests without a Content-Type are rejected by 
the CoyoteAdapter
+                    "Content-Type: text/plain" + CRLF +
+                    "Content-Length: 0" + CRLF +
+                    "Connection: close" + CRLF +
+                    CRLF
+                });
+        // @formatter:on
+
+        client.connect();
+        client.processRequest();
+        client.disconnect();
+
+        return client;
+    }
+
+
+    private static class AllowClient extends SimpleHttpClient {
+
+        @Override
+        public boolean isResponseBodyOK() {
+            return true;
+        }
+
+        public String getAllow() {
+            for (String header : getResponseHeaders()) {
+                if (header.startsWith("Allow:")) {
+                    return header.substring("Allow:".length()).trim();
+                }
+            }
+            return null;
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to