This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit ae22fadba4b94152fa5cc1d015ed2058f21e3164 Author: Mark Thomas <ma...@apache.org> AuthorDate: Thu Jul 4 16:53:21 2024 +0100 Add HTTP/2 support for early hints --- java/org/apache/coyote/http2/Stream.java | 16 ++++++ java/org/apache/coyote/http2/StreamProcessor.java | 3 +- .../apache/coyote/http2/TestStreamProcessor.java | 66 ++++++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/java/org/apache/coyote/http2/Stream.java b/java/org/apache/coyote/http2/Stream.java index a72bba3a7b..3e621e82a8 100644 --- a/java/org/apache/coyote/http2/Stream.java +++ b/java/org/apache/coyote/http2/Stream.java @@ -597,6 +597,22 @@ class Stream extends AbstractNonZeroStream implements HeaderEmitter { } + final void writeEarlyHints() throws IOException { + MimeHeaders headers = coyoteResponse.getMimeHeaders(); + String originalStatus = headers.getHeader(":status"); + headers.setValue(":status").setString("103"); + try { + handler.writeHeaders(this, 0, headers, false, Constants.DEFAULT_HEADERS_FRAME_SIZE); + } finally { + if (originalStatus == null) { + headers.removeHeader(":status"); + } else { + headers.setValue(":status").setString(originalStatus); + } + } + } + + @Override final String getConnectionId() { return handler.getConnectionId(); diff --git a/java/org/apache/coyote/http2/StreamProcessor.java b/java/org/apache/coyote/http2/StreamProcessor.java index 3f3cde6f50..b7d6e9e6ce 100644 --- a/java/org/apache/coyote/http2/StreamProcessor.java +++ b/java/org/apache/coyote/http2/StreamProcessor.java @@ -263,8 +263,7 @@ class StreamProcessor extends AbstractProcessor { @Override protected void earlyHints() throws IOException { - // TODO Auto-generated method stub - // NO-OP for now + stream.writeEarlyHints(); } diff --git a/test/org/apache/coyote/http2/TestStreamProcessor.java b/test/org/apache/coyote/http2/TestStreamProcessor.java index ac362c6e30..5082349a6e 100644 --- a/test/org/apache/coyote/http2/TestStreamProcessor.java +++ b/test/org/apache/coyote/http2/TestStreamProcessor.java @@ -36,6 +36,7 @@ import org.junit.Test; import org.apache.catalina.Context; import org.apache.catalina.Wrapper; import org.apache.catalina.connector.Connector; +import org.apache.catalina.connector.ResponseFacade; import org.apache.catalina.startup.Tomcat; import org.apache.tomcat.util.compat.JrePlatform; import org.apache.tomcat.util.http.FastHttpDateFormat; @@ -586,4 +587,69 @@ public class TestStreamProcessor extends Http2TestBase { String trace = output.getTrace(); Assert.assertTrue(trace, trace.contains("3-Header-[:status]-[501]")); } + + + @Test + public void testEarlyHints() throws Exception { + enableHttp2(); + + Tomcat tomcat = getTomcatInstance(); + + Context ctxt = getProgrammaticRootContext(); + Tomcat.addServlet(ctxt, "simple", new SimpleServlet()); + ctxt.addServletMappingDecoded("/simple", "simple"); + Tomcat.addServlet(ctxt, "ehs", new EarlyHintsServlet()); + ctxt.addServletMappingDecoded("/ehs", "ehs"); + 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, "/ehs"); + + // Write the headers + writeFrame(headersFrameHeader, headersPayload); + + parser.readFrame(); + + Assert.assertEquals("3-HeadersStart\n" + "3-Header-[:status]-[103]\n" + + "3-Header-[link]-[</style.css>; rel=preload; as=style]\n" + "3-HeadersEnd\n", output.getTrace()); + output.clearTrace(); + + parser.readFrame(); + parser.readFrame(); + + Assert.assertEquals("3-HeadersStart\n" + "3-Header-[:status]-[200]\n" + + "3-Header-[link]-[</style.css>; rel=preload; as=style]\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 EarlyHintsServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + resp.addHeader("Link", "</style.css>; rel=preload; as=style"); + + ((ResponseFacade) resp).sendEarlyHints(); + + resp.setCharacterEncoding("UTF-8"); + resp.setContentType("text/plain"); + + resp.getWriter().write("OK"); + } + } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org