This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 09e214c09c78a48ea96b0137555b3c2a98a1bfab Author: Mark Thomas <ma...@apache.org> AuthorDate: Tue Mar 31 14:03:17 2020 +0100 Make the HTTP/2 connection ID and stream Id available to applications --- java/org/apache/catalina/Globals.java | 16 ++++++++++ java/org/apache/catalina/connector/Request.java | 27 ++++++++++++++++ java/org/apache/coyote/AbstractProcessor.java | 39 +++++++++++++++++++++++ java/org/apache/coyote/ActionCode.java | 14 +++++++- java/org/apache/coyote/http2/StreamProcessor.java | 12 +++++++ webapps/docs/changelog.xml | 5 +++ webapps/docs/config/http2.xml | 9 ++++++ 7 files changed, 121 insertions(+), 1 deletion(-) diff --git a/java/org/apache/catalina/Globals.java b/java/org/apache/catalina/Globals.java index 144a028..312d78b 100644 --- a/java/org/apache/catalina/Globals.java +++ b/java/org/apache/catalina/Globals.java @@ -51,6 +51,22 @@ public final class Globals { /** + * The request attribute used to expose the current connection ID associated + * with the request, if any. Used with multiplexing protocols such as + * HTTTP/2. + */ + public static final String CONNECTION_ID = "org.apache.coyote.connectionID"; + + + /** + * The request attribute used to expose the current stream ID associated + * with the request, if any. Used with multiplexing protocols such as + * HTTTP/2. + */ + public static final String STREAM_ID = "org.apache.coyote.streamID"; + + + /** * The request attribute that is set to {@code Boolean.TRUE} if some request * parameters have been ignored during request parameters parsing. It can * happen, for example, if there is a limit on the total count of parseable diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java index 7f27bdd..705b609 100644 --- a/java/org/apache/catalina/connector/Request.java +++ b/java/org/apache/catalina/connector/Request.java @@ -40,6 +40,7 @@ import java.util.TimeZone; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import javax.naming.NamingException; import javax.security.auth.Subject; @@ -3523,6 +3524,32 @@ public class Request implements HttpServletRequest { // NO-OP } }); + specialAttributes.put(Globals.CONNECTION_ID, + new SpecialAttributeAdapter() { + @Override + public Object get(Request request, String name) { + AtomicReference<Object> result = new AtomicReference<>(); + request.getCoyoteRequest().action(ActionCode.CONNECTION_ID, result); + return result.get(); + } + @Override + public void set(Request request, String name, Object value) { + // NO-OP + } + }); + specialAttributes.put(Globals.STREAM_ID, + new SpecialAttributeAdapter() { + @Override + public Object get(Request request, String name) { + AtomicReference<Object> result = new AtomicReference<>(); + request.getCoyoteRequest().action(ActionCode.STREAM_ID, result); + return result.get(); + } + @Override + public void set(Request request, String name, Object value) { + // NO-OP + } + }); for (SimpleDateFormat sdf : formatsTemplate) { sdf.setTimeZone(GMT_ZONE); diff --git a/java/org/apache/coyote/AbstractProcessor.java b/java/org/apache/coyote/AbstractProcessor.java index 80335a7..87d504a 100644 --- a/java/org/apache/coyote/AbstractProcessor.java +++ b/java/org/apache/coyote/AbstractProcessor.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import java.util.Iterator; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import javax.servlet.RequestDispatcher; @@ -619,6 +620,20 @@ public abstract class AbstractProcessor extends AbstractProcessorLight implement result.set(isTrailerFieldsSupported()); break; } + + // Identifiers associated with multiplexing protocols like HTTP/2 + case CONNECTION_ID: { + @SuppressWarnings("unchecked") + AtomicReference<Object> result = (AtomicReference<Object>) param; + result.set(getConnectionID()); + break; + } + case STREAM_ID: { + @SuppressWarnings("unchecked") + AtomicReference<Object> result = (AtomicReference<Object>) param; + result.set(getStreamID()); + break; + } } } @@ -955,6 +970,30 @@ public abstract class AbstractProcessor extends AbstractProcessorLight implement /** + * Protocols that support multiplexing (e.g. HTTP/2) should override this + * method and return the appropriate ID. + * + * @return The stream ID associated with this request or {@code null} if a + * multiplexing protocol is not being used + */ + protected Object getConnectionID() { + return null; + } + + + /** + * Protocols that support multiplexing (e.g. HTTP/2) should override this + * method and return the appropriate ID. + * + * @return The stream ID associated with this request or {@code null} if a + * multiplexing protocol is not being used + */ + protected Object getStreamID() { + return null; + } + + + /** * Flush any pending writes. Used during non-blocking writes to flush any * remaining data from a previous incomplete write. * diff --git a/java/org/apache/coyote/ActionCode.java b/java/org/apache/coyote/ActionCode.java index 3ff4c21..5c5af4f 100644 --- a/java/org/apache/coyote/ActionCode.java +++ b/java/org/apache/coyote/ActionCode.java @@ -265,5 +265,17 @@ public enum ActionCode { * once an HTTP/1.1 response has been committed, it will no longer support * trailer fields. */ - IS_TRAILER_FIELDS_SUPPORTED + IS_TRAILER_FIELDS_SUPPORTED, + + /** + * Obtain the connection identifier for the request. Used with multiplexing + * protocols such as HTTP/2. + */ + CONNECTION_ID, + + /** + * Obtain the stream identifier for the request. Used with multiplexing + * protocols such as HTTP/2. + */ + STREAM_ID } diff --git a/java/org/apache/coyote/http2/StreamProcessor.java b/java/org/apache/coyote/http2/StreamProcessor.java index 99e2d78..15bfcab 100644 --- a/java/org/apache/coyote/http2/StreamProcessor.java +++ b/java/org/apache/coyote/http2/StreamProcessor.java @@ -339,6 +339,18 @@ class StreamProcessor extends AbstractProcessor { @Override + protected Object getConnectionID() { + return stream.getConnectionId(); + } + + + @Override + protected Object getStreamID() { + return stream.getIdentifier().toString(); + } + + + @Override public final void recycle() { // StreamProcessor instances are not re-used. // Clear fields that can be cleared to aid GC and trigger NPEs if this diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index b03142f..b9abb21 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -92,6 +92,11 @@ data on the request line after the URI are treated consistently. Such requests will now always be treated as HTTP/1.1. (markt) </fix> + <add> + Expose the HTTP/2 connection ID and stream ID to applications via the + request attributes <code>org.apache.coyote.connectionID</code> and + <code>org.apache.coyote.streamID</code> respectively. (markt) + </add> </changelog> </subsection> <subsection name="Jasper"> diff --git a/webapps/docs/config/http2.xml b/webapps/docs/config/http2.xml index 00f75cb..ddd7b5e 100644 --- a/webapps/docs/config/http2.xml +++ b/webapps/docs/config/http2.xml @@ -44,6 +44,15 @@ the Servlet API is fundamentally blocking, each HTTP/2 stream requires a dedicated container thread for the duration of that stream.</p> + <p>Requests processed using HTTP/2 will have the following additional request + attributes available:</p> + <ul> + <li><code>org.apache.coyote.connectionID</code> will return the HTTP/2 + connection ID</li> + <li><code>org.apache.coyote.streamID</code> will return the HTTP/2 stream + ID</li> + </ul> + </section> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org