This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 11.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/11.0.x by this push: new a5bc1e4841 Add support for server and serverRemoveAppProvidedValues to h2 a5bc1e4841 is described below commit a5bc1e484144f940e060381217c8b27772bdcfc2 Author: Mark Thomas <ma...@apache.org> AuthorDate: Thu Sep 26 11:42:38 2024 +0100 Add support for server and serverRemoveAppProvidedValues to h2 These configuration properties are inherited from the parent HTTP/1.1 connector. --- java/org/apache/coyote/http2/StreamProcessor.java | 13 ++ .../apache/coyote/http2/TestStreamProcessor.java | 146 +++++++++++++++++++++ webapps/docs/changelog.xml | 5 + webapps/docs/config/http2.xml | 2 + 4 files changed, 166 insertions(+) diff --git a/java/org/apache/coyote/http2/StreamProcessor.java b/java/org/apache/coyote/http2/StreamProcessor.java index 6bde60d921..72c86020fd 100644 --- a/java/org/apache/coyote/http2/StreamProcessor.java +++ b/java/org/apache/coyote/http2/StreamProcessor.java @@ -242,6 +242,19 @@ class StreamProcessor extends AbstractProcessor { headers.addValue("date").setString(FastHttpDateFormat.getCurrentDate()); } + // Server header + if (protocol != null) { + String server = protocol.getHttp11Protocol().getServer(); + if (server == null) { + if (protocol.getHttp11Protocol().getServerRemoveAppProvidedValues()) { + headers.removeHeader("server"); + } + } else { + // server always overrides anything the app might set + headers.setValue("Server").setString(server); + } + } + // Exclude some HTTP header fields where the value is determined only // while generating the content as per section 9.3.2 of RFC 9110. if (coyoteRequest != null && coyoteRequest.method().equals("HEAD")) { diff --git a/test/org/apache/coyote/http2/TestStreamProcessor.java b/test/org/apache/coyote/http2/TestStreamProcessor.java index 4208ff5954..bfc4d8595b 100644 --- a/test/org/apache/coyote/http2/TestStreamProcessor.java +++ b/test/org/apache/coyote/http2/TestStreamProcessor.java @@ -653,4 +653,150 @@ public class TestStreamProcessor extends Http2TestBase { resp.getWriter().write("OK"); } } + + + @Test + public void testServerHeaderDefault() throws Exception { + enableHttp2(); + + Tomcat tomcat = getTomcatInstance(); + + Context ctxt = getProgrammaticRootContext(); + Tomcat.addServlet(ctxt, "simple", new SimpleServlet()); + ctxt.addServletMappingDecoded("/simple", "simple"); + Tomcat.addServlet(ctxt, "server", new ServerHeaderServlet()); + ctxt.addServletMappingDecoded("/server", "server"); + tomcat.start(); + + openClientConnection(); + doHttpUpgrade(); + sendClientPreface(); + validateHttp2InitialResponse(); + + // Disable overhead protection for window update as it breaks some tests + http2Protocol.setOverheadWindowUpdateThreshold(0); + + byte[] headersFrameHeader = new byte[9]; + ByteBuffer headersPayload = ByteBuffer.allocate(128); + + buildGetRequest(headersFrameHeader, headersPayload, null, 3, "/server"); + + // Write the headers + writeFrame(headersFrameHeader, headersPayload); + + parser.readFrame(); + parser.readFrame(); + + Assert.assertEquals("3-HeadersStart\n" + "3-Header-[:status]-[200]\n" + + "3-Header-[server]-[TestServerApp]\n" + + "3-Header-[content-type]-[text/plain;charset=UTF-8]\n" + + "3-Header-[content-length]-[2]\n" + + "3-Header-[date]-[" + DEFAULT_DATE + "]\n" + "3-HeadersEnd\n" + "3-Body-2\n" + "3-EndOfStream\n", + output.getTrace()); + } + + + @Test + public void testServerHeaderRemove() throws Exception { + enableHttp2(); + + Tomcat tomcat = getTomcatInstance(); + + tomcat.getConnector().setProperty("serverRemoveAppProvidedValues", "true"); + + Context ctxt = getProgrammaticRootContext(); + Tomcat.addServlet(ctxt, "simple", new SimpleServlet()); + ctxt.addServletMappingDecoded("/simple", "simple"); + Tomcat.addServlet(ctxt, "server", new ServerHeaderServlet()); + ctxt.addServletMappingDecoded("/server", "server"); + tomcat.start(); + + openClientConnection(); + doHttpUpgrade(); + sendClientPreface(); + validateHttp2InitialResponse(); + + // Disable overhead protection for window update as it breaks some tests + http2Protocol.setOverheadWindowUpdateThreshold(0); + + byte[] headersFrameHeader = new byte[9]; + ByteBuffer headersPayload = ByteBuffer.allocate(128); + + buildGetRequest(headersFrameHeader, headersPayload, null, 3, "/server"); + + // Write the headers + writeFrame(headersFrameHeader, headersPayload); + + parser.readFrame(); + parser.readFrame(); + + Assert.assertEquals("3-HeadersStart\n" + "3-Header-[:status]-[200]\n" + + "3-Header-[content-type]-[text/plain;charset=UTF-8]\n" + + "3-Header-[content-length]-[2]\n" + + "3-Header-[date]-[" + DEFAULT_DATE + "]\n" + "3-HeadersEnd\n" + "3-Body-2\n" + "3-EndOfStream\n", + output.getTrace()); + } + + + @Test + public void testServerHeaderForce() throws Exception { + enableHttp2(); + + Tomcat tomcat = getTomcatInstance(); + + Context ctxt = getProgrammaticRootContext(); + Tomcat.addServlet(ctxt, "simple", new SimpleServlet()); + ctxt.addServletMappingDecoded("/simple", "simple"); + Tomcat.addServlet(ctxt, "server", new ServerHeaderServlet()); + ctxt.addServletMappingDecoded("/server", "server"); + tomcat.start(); + + openClientConnection(); + doHttpUpgrade(); + sendClientPreface(); + validateHttp2InitialResponse(); + + /* + * This adds the server header to every response. Set this after the initial response has been validated to + * avoid having to update the validation code to account for the additional server header. + */ + tomcat.getConnector().setProperty("server", "TestServerForce"); + + // Disable overhead protection for window update as it breaks some tests + http2Protocol.setOverheadWindowUpdateThreshold(0); + + byte[] headersFrameHeader = new byte[9]; + ByteBuffer headersPayload = ByteBuffer.allocate(128); + + buildGetRequest(headersFrameHeader, headersPayload, null, 3, "/server"); + + // Write the headers + writeFrame(headersFrameHeader, headersPayload); + + parser.readFrame(); + parser.readFrame(); + + Assert.assertEquals("3-HeadersStart\n" + "3-Header-[:status]-[200]\n" + + "3-Header-[server]-[TestServerForce]\n" + + "3-Header-[content-type]-[text/plain;charset=UTF-8]\n" + + "3-Header-[content-length]-[2]\n" + + "3-Header-[date]-[" + DEFAULT_DATE + "]\n" + "3-HeadersEnd\n" + "3-Body-2\n" + "3-EndOfStream\n", + output.getTrace()); + } + + + private static class ServerHeaderServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + resp.addHeader("server", "TestServerApp"); + + resp.setCharacterEncoding(StandardCharsets.UTF_8); + resp.setContentType("text/plain"); + + resp.getWriter().write("OK"); + } + } } diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 1130159b5c..ef38a12290 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -157,6 +157,11 @@ Request start time may not have been accurately recorded for HTTP/1.1 requests preceded by a large number of blank lines. (markt) </fix> + <add> + Add <code>server</code> and <code>serverRemoveAppProvidedValues</code> + to the list of attributes the HTTP/2 protocol will inherit from the + HTTP/1.1 connector it is nested within. + </add> </changelog> </subsection> <subsection name="Jasper"> diff --git a/webapps/docs/config/http2.xml b/webapps/docs/config/http2.xml index e3b763656c..8d918a5db9 100644 --- a/webapps/docs/config/http2.xml +++ b/webapps/docs/config/http2.xml @@ -244,6 +244,8 @@ <li>maxSavePostSize</li> <li>maxTrailerSize</li> <li>noCompressionUserAgents</li> + <li>server</li> + <li>serverRemoveAppProvidedValues</li> </ul> </subsection> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org