239 lines
8.7 KiB
Diff
239 lines
8.7 KiB
Diff
|
|
From 09e214c09c78a48ea96b0137555b3c2a98a1bfab Mon Sep 17 00:00:00 2001
|
||
|
|
From: Mark Thomas <markt@apache.org>
|
||
|
|
Date: Tue, 31 Mar 2020 14:03:17 +0100
|
||
|
|
Subject: [PATCH] Make the HTTP/2 connection ID and stream Id available to
|
||
|
|
applications
|
||
|
|
Origin: https://github.com/apache/tomcat/commit/09e214c09c78a48ea96b0137555b3c2a98a1bfab
|
||
|
|
|
||
|
|
---
|
||
|
|
java/org/apache/catalina/Globals.java | 16 ++++++++
|
||
|
|
.../apache/catalina/connector/Request.java | 27 +++++++++++++
|
||
|
|
java/org/apache/coyote/AbstractProcessor.java | 39 +++++++++++++++++++
|
||
|
|
java/org/apache/coyote/ActionCode.java | 14 ++++++-
|
||
|
|
.../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 994902b..c19d69c 100644
|
||
|
|
--- a/java/org/apache/catalina/Globals.java
|
||
|
|
+++ b/java/org/apache/catalina/Globals.java
|
||
|
|
@@ -112,6 +112,22 @@ public final class Globals {
|
||
|
|
"org.apache.catalina.NAMED";
|
||
|
|
|
||
|
|
|
||
|
|
+ /**
|
||
|
|
+ * 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 servlet context attribute under which we store a flag used
|
||
|
|
* to mark this request as having been processed by the SSIServlet.
|
||
|
|
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
|
||
|
|
index c4cc26a..94065ef 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;
|
||
|
|
@@ -3487,6 +3488,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 5be2cb8..b351cb7 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;
|
||
|
|
|
||
|
|
@@ -589,6 +590,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;
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -889,6 +904,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 d9c1c82..fd833ec 100644
|
||
|
|
--- a/java/org/apache/coyote/http2/StreamProcessor.java
|
||
|
|
+++ b/java/org/apache/coyote/http2/StreamProcessor.java
|
||
|
|
@@ -300,6 +300,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.
|
||
|
|
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
|
||
|
|
index a97e15d..8837628 100644
|
||
|
|
--- a/webapps/docs/changelog.xml
|
||
|
|
+++ b/webapps/docs/changelog.xml
|
||
|
|
@@ -247,6 +247,11 @@
|
||
|
|
Ensure that the HTTP/1.1 processor is correctly recycled when a direct
|
||
|
|
connection to h2c is made. (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 83b8acd..145a184 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>
|
||
|
|
|
||
|
|
|
||
|
|
--
|
||
|
|
2.33.0
|
||
|
|
|