You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2024/07/19 16:23:41 UTC

(tomcat) branch 10.1.x updated (f631975606 -> 6df40af33c)

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

markt pushed a change to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


    from f631975606 Refactor SimpleHTTPClient to read body as-is rather than via readLine()
     new 95ea8ac12f Rename method that performs commit to commit()
     new 158410dce4 Refactor writing of the status code
     new 573560e980 Refactoring writing of HTTP headers to separate method
     new 2922f53f7d Implement early hints for HTTP/1.1
     new 67cbac5094 AJP doesn't support 1xx responses.
     new ae22fadba4 Add HTTP/2 support for early hints
     new 6df40af33c Add a changelog entry

The 7 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../apache/catalina/connector/OutputBuffer.java    |  2 +-
 java/org/apache/catalina/connector/Response.java   | 14 +++++
 .../apache/catalina/connector/ResponseFacade.java  |  4 ++
 java/org/apache/coyote/AbstractProcessor.java      | 11 ++++
 java/org/apache/coyote/ActionCode.java             |  7 ++-
 java/org/apache/coyote/Response.java               | 11 ++++
 java/org/apache/coyote/ajp/AjpProcessor.java       |  6 ++
 .../apache/coyote/http11/Http11OutputBuffer.java   | 17 +++++-
 java/org/apache/coyote/http11/Http11Processor.java | 23 ++++++--
 .../org/apache/coyote/http2/Http2OutputBuffer.java |  2 +-
 java/org/apache/coyote/http2/Stream.java           | 16 ++++++
 java/org/apache/coyote/http2/StreamProcessor.java  |  6 ++
 .../apache/coyote/http11/TestHttp11Processor.java  | 49 ++++++++++++++++
 .../apache/coyote/http2/TestStreamProcessor.java   | 66 ++++++++++++++++++++++
 webapps/docs/changelog.xml                         | 12 ++++
 15 files changed, 237 insertions(+), 9 deletions(-)


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


(tomcat) 05/07: AJP doesn't support 1xx responses.

Posted by ma...@apache.org.
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 67cbac50947cea05294d59bfa924fb10a6ce7b3b
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Jul 4 16:09:33 2024 +0100

    AJP doesn't support 1xx responses.
---
 java/org/apache/coyote/ajp/AjpProcessor.java | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/java/org/apache/coyote/ajp/AjpProcessor.java b/java/org/apache/coyote/ajp/AjpProcessor.java
index f879a3f84d..fd1bdc1e24 100644
--- a/java/org/apache/coyote/ajp/AjpProcessor.java
+++ b/java/org/apache/coyote/ajp/AjpProcessor.java
@@ -1056,8 +1056,7 @@ public class AjpProcessor extends AbstractProcessor {
 
     @Override
     protected void earlyHints() throws IOException {
-        // TODO Auto-generated method stub
-        // NO-OP for now
+        // NO-OP for AJP
     }
 
 


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


(tomcat) 02/07: Refactor writing of the status code

Posted by ma...@apache.org.
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 158410dce411399bd2d19697579878de7480f7f1
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Jul 4 14:15:50 2024 +0100

    Refactor writing of the status code
    
    This refactoring is part of the preparation for RFC 8297 (Early Hints)
    support.
---
 java/org/apache/coyote/http11/Http11OutputBuffer.java | 14 +++++++++++++-
 java/org/apache/coyote/http11/Http11Processor.java    |  4 ++--
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/java/org/apache/coyote/http11/Http11OutputBuffer.java b/java/org/apache/coyote/http11/Http11OutputBuffer.java
index 128f327cdb..2c51cdfb45 100644
--- a/java/org/apache/coyote/http11/Http11OutputBuffer.java
+++ b/java/org/apache/coyote/http11/Http11OutputBuffer.java
@@ -320,14 +320,26 @@ public class Http11OutputBuffer implements HttpOutputBuffer {
 
     /**
      * Send the response status line.
+     *
+     * @deprecated Unused. Will be removed in Tomcat 11. Use {@link #sendStatus(int)}.
      */
+    @Deprecated
     public void sendStatus() {
+        sendStatus(response.getStatus());
+    }
+
+
+    /**
+     * Send the response status line.
+     *
+     * @param status The HTTP status code to include in the status line
+     */
+    public void sendStatus(int status) {
         // Write protocol name
         write(Constants.HTTP_11_BYTES);
         headerBuffer.put(Constants.SP);
 
         // Write status code
-        int status = response.getStatus();
         switch (status) {
             case 200:
                 write(Constants._200_BYTES);
diff --git a/java/org/apache/coyote/http11/Http11Processor.java b/java/org/apache/coyote/http11/Http11Processor.java
index f1f3fb9501..cf872a09be 100644
--- a/java/org/apache/coyote/http11/Http11Processor.java
+++ b/java/org/apache/coyote/http11/Http11Processor.java
@@ -1039,7 +1039,7 @@ public class Http11Processor extends AbstractProcessor {
 
         // Build the response header
         try {
-            outputBuffer.sendStatus();
+            outputBuffer.sendStatus(response.getStatus());
 
             int size = headers.size();
             for (int i = 0; i < size; i++) {
@@ -1056,7 +1056,7 @@ public class Http11Processor extends AbstractProcessor {
                     outputBuffer.resetHeaderBuffer();
                     // -1 as it will be incremented at the start of the loop and header indexes start at 0.
                     i = -1;
-                    outputBuffer.sendStatus();
+                    outputBuffer.sendStatus(response.getStatus());
                 }
             }
             outputBuffer.endHeaders();


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


(tomcat) 01/07: Rename method that performs commit to commit()

Posted by ma...@apache.org.
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 95ea8ac12f5df68ae7df273372766e344548d515
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Jul 4 13:50:37 2024 +0100

    Rename method that performs commit to commit()
    
    This refactoring is in preparation for RFC 8293 (Early Hints) support.
    That will introduce a method that writes headers without a commit. This
    rename will reduce potential confusion between writeHeaders() and
    sendHeaders().
---
 java/org/apache/catalina/connector/OutputBuffer.java |  2 +-
 java/org/apache/coyote/Response.java                 | 11 +++++++++++
 java/org/apache/coyote/http2/Http2OutputBuffer.java  |  2 +-
 3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/java/org/apache/catalina/connector/OutputBuffer.java b/java/org/apache/catalina/connector/OutputBuffer.java
index de6dbd35fd..ede9343c65 100644
--- a/java/org/apache/catalina/connector/OutputBuffer.java
+++ b/java/org/apache/catalina/connector/OutputBuffer.java
@@ -282,7 +282,7 @@ public class OutputBuffer extends Writer {
         try {
             doFlush = true;
             if (initial) {
-                coyoteResponse.sendHeaders();
+                coyoteResponse.commit();
                 initial = false;
             }
             if (cb.remaining() > 0) {
diff --git a/java/org/apache/coyote/Response.java b/java/org/apache/coyote/Response.java
index a7eddfd7ff..01815ce936 100644
--- a/java/org/apache/coyote/Response.java
+++ b/java/org/apache/coyote/Response.java
@@ -448,8 +448,19 @@ public final class Response {
 
     /**
      * Signal that we're done with the headers, and body will follow.
+     *
+     * @deprecated Unused. Will be removed in Tomcat 11 onwards. Use {@link #commit()}.
      */
+    @Deprecated
     public void sendHeaders() {
+        commit();
+    }
+
+
+    /**
+     * Signal that we're done with the headers, and body will follow.
+     */
+    public void commit() {
         action(ActionCode.COMMIT, this);
         setCommitted(true);
     }
diff --git a/java/org/apache/coyote/http2/Http2OutputBuffer.java b/java/org/apache/coyote/http2/Http2OutputBuffer.java
index 1de4569900..3d4d6b96c5 100644
--- a/java/org/apache/coyote/http2/Http2OutputBuffer.java
+++ b/java/org/apache/coyote/http2/Http2OutputBuffer.java
@@ -52,7 +52,7 @@ public class Http2OutputBuffer implements HttpOutputBuffer {
     @Override
     public int doWrite(ByteBuffer chunk) throws IOException {
         if (!coyoteResponse.isCommitted()) {
-            coyoteResponse.sendHeaders();
+            coyoteResponse.commit();
         }
         return next.doWrite(chunk);
     }


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


Re: (tomcat) 06/07: Add HTTP/2 support for early hints

Posted by Mark Thomas <ma...@apache.org>.
On 19/07/2024 16:19, Koteswararao Gundapaneni wrote:
> Hi Mark,
> 
> 
> OpenclientConnection should be ftp rather than tcpip
> 
> Re
> Koti

And the above complete and utter nonsense is the point where my patience 
is exhausted. Any more posts like this and a ban will be applied without 
further comment or warning.

Mark


> 
> 
> 
> 
> On Fri, 19 Jul 2024, 21:56 , <ma...@apache.org> wrote:
> 
>> 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-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: dev-help@tomcat.apache.org
>>
>>
> 

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


Re: (tomcat) 06/07: Add HTTP/2 support for early hints

Posted by Koteswararao Gundapaneni <ap...@gmail.com>.
Hi Mark,


OpenclientConnection should be ftp rather than tcpip

Re
Koti




On Fri, 19 Jul 2024, 21:56 , <ma...@apache.org> wrote:

> 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-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: dev-help@tomcat.apache.org
>
>

(tomcat) 06/07: Add HTTP/2 support for early hints

Posted by ma...@apache.org.
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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


(tomcat) 07/07: Add a changelog entry

Posted by ma...@apache.org.
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 6df40af33c51fa29b7d9e2a56d98c39b551428c6
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Jul 19 12:44:17 2024 +0100

    Add a changelog entry
---
 webapps/docs/changelog.xml | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index a4366c857e..9511034e32 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -105,6 +105,18 @@
   issues do not "pop up" wrt. others).
 -->
 <section name="Tomcat 10.1.27 (schultz)" rtext="in development">
+  <subsection name="Catalina">
+    <changelog>
+      <add>
+        Add support for RFC 8297 (Early Hints). Applications can use this
+        feature by casting the <code>HttpServletResponse</code> to
+        <code>org.apache.catalina.connector.Reponse</code> and then calling the
+        method <code>void sendEarlyHints()</code>. This method will be added to
+        the Servlet API (removing the need for the cast) in Servlet 6.2 onwards.
+        (markt)
+      </add>
+    </changelog>
+  </subsection>
   <subsection name="Other">
     <changelog>
       <fix>


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


(tomcat) 04/07: Implement early hints for HTTP/1.1

Posted by ma...@apache.org.
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 2922f53f7d2257b30c009fbda7d1817c549ef59c
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Jul 4 15:48:18 2024 +0100

    Implement early hints for HTTP/1.1
---
 java/org/apache/catalina/connector/Response.java   | 14 +++++++
 .../apache/catalina/connector/ResponseFacade.java  |  4 ++
 java/org/apache/coyote/AbstractProcessor.java      | 11 +++++
 java/org/apache/coyote/ActionCode.java             |  7 +++-
 java/org/apache/coyote/ajp/AjpProcessor.java       |  7 ++++
 .../apache/coyote/http11/Http11OutputBuffer.java   |  3 ++
 java/org/apache/coyote/http11/Http11Processor.java |  8 ++++
 java/org/apache/coyote/http2/StreamProcessor.java  |  7 ++++
 .../apache/coyote/http11/TestHttp11Processor.java  | 49 ++++++++++++++++++++++
 9 files changed, 109 insertions(+), 1 deletion(-)

diff --git a/java/org/apache/catalina/connector/Response.java b/java/org/apache/catalina/connector/Response.java
index b5906ed7f8..44a94ace51 100644
--- a/java/org/apache/catalina/connector/Response.java
+++ b/java/org/apache/catalina/connector/Response.java
@@ -1061,6 +1061,20 @@ public class Response implements HttpServletResponse {
     }
 
 
+    public void sendEarlyHints() {
+        if (isCommitted()) {
+            return;
+        }
+
+        // Ignore any call from an included servlet
+        if (included) {
+            return;
+        }
+
+        getCoyoteResponse().action(ActionCode.EARLY_HINTS, null);
+    }
+
+
     @Override
     public void sendError(int status) throws IOException {
         sendError(status, null);
diff --git a/java/org/apache/catalina/connector/ResponseFacade.java b/java/org/apache/catalina/connector/ResponseFacade.java
index 5ad4c0778b..8bed33742c 100644
--- a/java/org/apache/catalina/connector/ResponseFacade.java
+++ b/java/org/apache/catalina/connector/ResponseFacade.java
@@ -324,6 +324,10 @@ public class ResponseFacade implements HttpServletResponse {
     }
 
 
+    public void sendEarlyHints() {
+        response.sendEarlyHints();
+    }
+
     @Override
     public void sendError(int sc, String msg) throws IOException {
         checkCommitted("coyoteResponse.sendError.ise");
diff --git a/java/org/apache/coyote/AbstractProcessor.java b/java/org/apache/coyote/AbstractProcessor.java
index 49a7882712..8a731014bd 100644
--- a/java/org/apache/coyote/AbstractProcessor.java
+++ b/java/org/apache/coyote/AbstractProcessor.java
@@ -394,6 +394,14 @@ public abstract class AbstractProcessor extends AbstractProcessorLight implement
                 ack((ContinueResponseTiming) param);
                 break;
             }
+            case EARLY_HINTS: {
+                try {
+                    earlyHints();
+                } catch (IOException e) {
+                    handleIOException(e);
+                }
+                break;
+            }
             case CLIENT_FLUSH: {
                 action(ActionCode.COMMIT, null);
                 try {
@@ -742,6 +750,9 @@ public abstract class AbstractProcessor extends AbstractProcessorLight implement
     protected abstract void ack(ContinueResponseTiming continueResponseTiming);
 
 
+    protected abstract void earlyHints() throws IOException;
+
+
     /**
      * Callback to write data from the buffer.
      * @throws IOException IO exception during the write
diff --git a/java/org/apache/coyote/ActionCode.java b/java/org/apache/coyote/ActionCode.java
index 6a24345ed2..62d236633a 100644
--- a/java/org/apache/coyote/ActionCode.java
+++ b/java/org/apache/coyote/ActionCode.java
@@ -275,5 +275,10 @@ public enum ActionCode {
     /**
      * Obtain the servlet connection instance for the network connection supporting the current request.
      */
-    SERVLET_CONNECTION
+    SERVLET_CONNECTION,
+
+    /**
+     * Send an RFC 8297 Early Hints informational response.
+     */
+    EARLY_HINTS
 }
diff --git a/java/org/apache/coyote/ajp/AjpProcessor.java b/java/org/apache/coyote/ajp/AjpProcessor.java
index caf2d5700e..f879a3f84d 100644
--- a/java/org/apache/coyote/ajp/AjpProcessor.java
+++ b/java/org/apache/coyote/ajp/AjpProcessor.java
@@ -1054,6 +1054,13 @@ public class AjpProcessor extends AbstractProcessor {
     }
 
 
+    @Override
+    protected void earlyHints() throws IOException {
+        // TODO Auto-generated method stub
+        // NO-OP for now
+    }
+
+
     @Override
     protected final int available(boolean doRead) {
         if (endOfStream) {
diff --git a/java/org/apache/coyote/http11/Http11OutputBuffer.java b/java/org/apache/coyote/http11/Http11OutputBuffer.java
index 2c51cdfb45..6967c30996 100644
--- a/java/org/apache/coyote/http11/Http11OutputBuffer.java
+++ b/java/org/apache/coyote/http11/Http11OutputBuffer.java
@@ -300,7 +300,10 @@ public class Http11OutputBuffer implements HttpOutputBuffer {
      */
     protected void commit() throws IOException {
         response.setCommitted(true);
+        writeHeaders();
+    }
 
+    protected void writeHeaders() throws IOException {
         if (headerBuffer.position() > 0) {
             // Sending the response header buffer
             headerBuffer.flip();
diff --git a/java/org/apache/coyote/http11/Http11Processor.java b/java/org/apache/coyote/http11/Http11Processor.java
index 3542625fb7..7522962304 100644
--- a/java/org/apache/coyote/http11/Http11Processor.java
+++ b/java/org/apache/coyote/http11/Http11Processor.java
@@ -1244,6 +1244,14 @@ public class Http11Processor extends AbstractProcessor {
     }
 
 
+    @Override
+    protected void earlyHints() throws IOException {
+        writeHeaders(103, response.getMimeHeaders());
+        outputBuffer.writeHeaders();
+        outputBuffer.resetHeaderBuffer();
+    }
+
+
     @Override
     protected final void flush() throws IOException {
         outputBuffer.flush();
diff --git a/java/org/apache/coyote/http2/StreamProcessor.java b/java/org/apache/coyote/http2/StreamProcessor.java
index 4e5645736e..3f3cde6f50 100644
--- a/java/org/apache/coyote/http2/StreamProcessor.java
+++ b/java/org/apache/coyote/http2/StreamProcessor.java
@@ -261,6 +261,13 @@ class StreamProcessor extends AbstractProcessor {
     }
 
 
+    @Override
+    protected void earlyHints() throws IOException {
+        // TODO Auto-generated method stub
+        // NO-OP for now
+    }
+
+
     @Override
     protected final void flush() throws IOException {
         stream.getOutputBuffer().flush();
diff --git a/test/org/apache/coyote/http11/TestHttp11Processor.java b/test/org/apache/coyote/http11/TestHttp11Processor.java
index 857d51185d..492df00050 100644
--- a/test/org/apache/coyote/http11/TestHttp11Processor.java
+++ b/test/org/apache/coyote/http11/TestHttp11Processor.java
@@ -53,6 +53,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.SimpleHttpClient;
 import org.apache.catalina.startup.TesterServlet;
 import org.apache.catalina.startup.Tomcat;
@@ -1912,4 +1913,52 @@ public class TestHttp11Processor extends TomcatBaseTest {
 
         }
     }
+
+
+    @Test
+    public void testEarlyHints() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        // No file system docBase required
+        Context ctx = getProgrammaticRootContext();
+
+        // Add servlet
+        Tomcat.addServlet(ctx, "EarlyHintsServlet", new EarlyHintsServlet());
+        ctx.addServletMappingDecoded("/ehs", "EarlyHintsServlet");
+
+        tomcat.start();
+
+        String request = "GET /ehs HTTP/1.1" + SimpleHttpClient.CRLF +
+                "Host: localhost:" + getPort() + SimpleHttpClient.CRLF +
+                SimpleHttpClient.CRLF;
+
+        Client client = new Client(tomcat.getConnector().getLocalPort());
+        client.setRequest(new String[] { request });
+
+        client.connect(600000, 600000);
+        client.processRequest(false);
+
+        Assert.assertEquals(103, client.getStatusCode());
+
+        client.readResponse(false);
+        Assert.assertEquals(HttpServletResponse.SC_OK, client.getStatusCode());
+    }
+
+
+    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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


(tomcat) 03/07: Refactoring writing of HTTP headers to separate method

Posted by ma...@apache.org.
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 573560e980a9e74a6c219a56dec5a4bc47d35ea5
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Jul 4 14:18:16 2024 +0100

    Refactoring writing of HTTP headers to separate method
    
    This in preparation for RFC 8297 (Early Hints) support that will need to
    write the current headers without committing the response.
---
 java/org/apache/coyote/http11/Http11Processor.java | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/java/org/apache/coyote/http11/Http11Processor.java b/java/org/apache/coyote/http11/Http11Processor.java
index cf872a09be..3542625fb7 100644
--- a/java/org/apache/coyote/http11/Http11Processor.java
+++ b/java/org/apache/coyote/http11/Http11Processor.java
@@ -1037,9 +1037,15 @@ public class Http11Processor extends AbstractProcessor {
             headers.setValue("Server").setString(server);
         }
 
-        // Build the response header
+        writeHeaders(response.getStatus(), headers);
+
+        outputBuffer.commit();
+    }
+
+
+    private void writeHeaders(int status, MimeHeaders headers) {
         try {
-            outputBuffer.sendStatus(response.getStatus());
+            outputBuffer.sendStatus(status);
 
             int size = headers.size();
             for (int i = 0; i < size; i++) {
@@ -1056,7 +1062,7 @@ public class Http11Processor extends AbstractProcessor {
                     outputBuffer.resetHeaderBuffer();
                     // -1 as it will be incremented at the start of the loop and header indexes start at 0.
                     i = -1;
-                    outputBuffer.sendStatus(response.getStatus());
+                    outputBuffer.sendStatus(status);
                 }
             }
             outputBuffer.endHeaders();
@@ -1067,10 +1073,9 @@ public class Http11Processor extends AbstractProcessor {
             outputBuffer.resetHeaderBuffer();
             throw t;
         }
-
-        outputBuffer.commit();
     }
 
+
     private static boolean isConnectionToken(MimeHeaders headers, String token) throws IOException {
         MessageBytes connection = headers.getValue(Constants.CONNECTION);
         if (connection == null) {


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