[Bug 69355] an enhanced exact rate limit control mechanism
https://bz.apache.org/bugzilla/show_bug.cgi?id=69355 --- Comment #3 from Remy Maucherat --- I see a trend in the PRs that you are submitting. Trying to be as precise as possible is a commendable goal, but the problem is that this exactitude does not make much sense in the context of Tomcat since the randomness of network transport is always present. As a result, it can be better to be as efficient as possible and accept deviating a few % off target. Q: Are you using a tool to identify these issues ? Finding them by yourself on your own would be very impressive. -- You are receiving this mail because: You are the assignee for the bug. - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
(tomcat) 01/03: Refactor HTTP/2 trailer testing to create trailers separately
This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git commit 55e79890bfc392a4e7c1312f250cba64896cd48f Author: Mark Thomas AuthorDate: Mon Sep 30 11:49:48 2024 +0100 Refactor HTTP/2 trailer testing to create trailers separately This will allow other requests to be multiplexed between the headers and trailers of the stream using trailers. --- test/org/apache/coyote/http2/Http2TestBase.java | 21 +++-- .../apache/coyote/http2/TestAsyncReadListener.java | 3 ++- .../apache/coyote/http2/TestCancelledUpload.java| 4 ++-- .../apache/coyote/http2/TestHttp2AccessLogs.java| 3 ++- test/org/apache/coyote/http2/TestHttp2Limits.java | 4 ++-- .../apache/coyote/http2/TestHttp2Section_8_1.java | 6 +++--- test/org/apache/coyote/http2/TestHttpServlet.java | 2 +- test/org/apache/coyote/http2/TestLargeUpload.java | 4 ++-- 8 files changed, 25 insertions(+), 22 deletions(-) diff --git a/test/org/apache/coyote/http2/Http2TestBase.java b/test/org/apache/coyote/http2/Http2TestBase.java index dc9c22cb34..e9d3a5de81 100644 --- a/test/org/apache/coyote/http2/Http2TestBase.java +++ b/test/org/apache/coyote/http2/Http2TestBase.java @@ -348,7 +348,7 @@ public abstract class Http2TestBase extends TomcatBaseTest { ByteBuffer dataPayload = ByteBuffer.allocate(128); buildPostRequest(headersFrameHeader, headersPayload, useExpectation, "application/x-www-form-urlencoded", -contentLength, "/parameter", dataFrameHeader, dataPayload, padding, null, null, streamId); +contentLength, "/parameter", dataFrameHeader, dataPayload, padding, false, streamId); writeFrame(headersFrameHeader, headersPayload); if (body != null) { dataPayload.put(body.getBytes(StandardCharsets.ISO_8859_1)); @@ -360,19 +360,18 @@ public abstract class Http2TestBase extends TomcatBaseTest { protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, boolean useExpectation, byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, int streamId) { buildPostRequest(headersFrameHeader, headersPayload, useExpectation, dataFrameHeader, dataPayload, padding, -null, null, streamId); +false, streamId); } protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, boolean useExpectation, -byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, byte[] trailersFrameHeader, -ByteBuffer trailersPayload, int streamId) { +byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, boolean withTrailers, int streamId) { buildPostRequest(headersFrameHeader, headersPayload, useExpectation, null, -1, "/simple", dataFrameHeader, -dataPayload, padding, trailersFrameHeader, trailersPayload, streamId); +dataPayload, padding, withTrailers, streamId); } protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, boolean useExpectation, String contentType, long contentLength, String path, byte[] dataFrameHeader, ByteBuffer dataPayload, -byte[] padding, byte[] trailersFrameHeader, ByteBuffer trailersPayload, int streamId) { +byte[] padding, boolean withTrailers, int streamId) { MimeHeaders headers = new MimeHeaders(); headers.addValue(":method").setString("POST"); @@ -419,17 +418,19 @@ public abstract class Http2TestBase extends TomcatBaseTest { ByteUtil.setThreeBytes(dataFrameHeader, 0, dataPayload.limit()); // Data is type 0 // Flags: End of stream 1, Padding 8 -if (trailersPayload == null) { -dataFrameHeader[4] = 0x01; -} else { +if (withTrailers) { dataFrameHeader[4] = 0x00; +} else { +dataFrameHeader[4] = 0x01; } if (padding != null) { dataFrameHeader[4] += 0x08; } ByteUtil.set31Bits(dataFrameHeader, 5, streamId); +} + -// Trailers +protected void buildTrailerHeaders(byte[] trailersFrameHeader, ByteBuffer trailersPayload, int streamId) { if (trailersPayload != null) { MimeHeaders trailerHeaders = new MimeHeaders(); trailerHeaders.addValue(TRAILER_HEADER_NAME).setString(TRAILER_HEADER_VALUE); diff --git a/test/org/apache/coyote/http2/TestAsyncReadListener.java b/test/org/apache/coyote/http2/TestAsyncReadListener.java index 2c02223770..614e487b46 100644 --- a/test/org/apache/coyote/http2/TestAsyncReadListener.java +++ b/test/org/apache/coyote/http2/TestAsyncReadListener.java @@ -77,7 +77,8 @@ public class TestAsyncReadListener extends Http2TestBase { buildPostRequest(headersFrameHeader, headersPayload, false,
(tomcat) 03/04: Improve HTTP/2 handling of trailer headers when connector is paused
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 commit c821b8b44278ed348b6ea6a8ad4c7277bddbe3fe Author: Mark Thomas AuthorDate: Mon Sep 30 16:01:47 2024 +0100 Improve HTTP/2 handling of trailer headers when connector is paused Prior to this change trailer headers for an existing stream would have been swallowed if received when the connector was paused. --- .../apache/coyote/http2/Http2UpgradeHandler.java | 38 +-- .../apache/coyote/http2/TestHttp2Section_6_8.java | 75 ++ 2 files changed, 95 insertions(+), 18 deletions(-) diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java b/java/org/apache/coyote/http2/Http2UpgradeHandler.java index 925f20be78..f01678c455 100644 --- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java +++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java @@ -1528,14 +1528,15 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH @Override public HeaderEmitter headersStart(int streamId, boolean headersEndStream) throws Http2Exception, IOException { -// Check the pause state before processing headers since the pause state -// determines if a new stream is created or if this stream is ignored. -checkPauseState(); - -if (connectionState.get().isNewStreamAllowed()) { -Stream stream = getStream(streamId, false); -if (stream == null) { -// New stream +Stream stream = getStream(streamId, false); +if (stream == null) { +// New stream + +// Check the pause state before processing headers since the pause state +// determines if a new stream is created or if this stream is ignored. +checkPauseState(); + +if (connectionState.get().isNewStreamAllowed()) { if (streamId > maxActiveRemoteStreamId) { stream = createRemoteStream(streamId); activeRemoteStreamCount.incrementAndGet(); @@ -1545,18 +1546,19 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH throw new ConnectionException(sm.getString("upgradeHandler.stream.old", Integer.valueOf(streamId), Integer.valueOf(maxActiveRemoteStreamId)), Http2Error.PROTOCOL_ERROR); } +} else { +if (log.isTraceEnabled()) { +log.trace(sm.getString("upgradeHandler.noNewStreams", connectionId, Integer.toString(streamId))); +} +reduceOverheadCount(FrameType.HEADERS); +// Stateless so a static can be used to save on GC +return HEADER_SINK; } -stream.checkState(FrameType.HEADERS); -stream.receivedStartOfHeaders(headersEndStream); -return stream; -} else { -if (log.isTraceEnabled()) { -log.trace(sm.getString("upgradeHandler.noNewStreams", connectionId, Integer.toString(streamId))); -} -reduceOverheadCount(FrameType.HEADERS); -// Stateless so a static can be used to save on GC -return HEADER_SINK; } + +stream.checkState(FrameType.HEADERS); +stream.receivedStartOfHeaders(headersEndStream); +return stream; } diff --git a/test/org/apache/coyote/http2/TestHttp2Section_6_8.java b/test/org/apache/coyote/http2/TestHttp2Section_6_8.java index ae245ca418..8b7ec1a6e2 100644 --- a/test/org/apache/coyote/http2/TestHttp2Section_6_8.java +++ b/test/org/apache/coyote/http2/TestHttp2Section_6_8.java @@ -16,9 +16,13 @@ */ package org.apache.coyote.http2; +import java.nio.ByteBuffer; + import org.junit.Assert; import org.junit.Test; +import org.apache.coyote.http11.AbstractHttp11Protocol; + /** * Unit tests for Section 6.8 of https://tools.ietf.org/html/rfc7540";>RFC 7540. * The order of tests in this class is aligned with the order of the requirements in the RFC. @@ -68,6 +72,77 @@ public class TestHttp2Section_6_8 extends Http2TestBase { } +@Test +public void testGoawayIgnoreNewStreamsAllowTrailers() throws Exception { +setPingAckDelayMillis(PING_ACK_DELAY_MS); + +http2Connect(); + +http2Protocol.setMaxConcurrentStreams(200); +// Ensure we see all the Window updates +http2Protocol.setOverheadWindowUpdateThreshold(0); +// Enable trailer headers +((AbstractHttp11Protocol) http2Protocol.getHttp11Protocol()).setAllowedTrailerHeaders(TRAILER_HEADER_NAME); + +Thread.sleep(PING_ACK_DELAY_MS + TIMING_MARGIN_MS); + +getTomcatInstance().getConnector().pause(); + +// Go away +parser.readFrame(); +Assert.assertEquals("0-Goaway-[2147483647]-[0]-[nul
(tomcat) 01/04: Refactor HTTP/2 trailer testing to create trailers separately
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 commit a8f8b00afa4603ba3457522a6ba73de38d7dc260 Author: Mark Thomas AuthorDate: Mon Sep 30 11:49:48 2024 +0100 Refactor HTTP/2 trailer testing to create trailers separately This will allow other requests to be multiplexed between the headers and trailers of the stream using trailers. --- test/org/apache/coyote/http2/Http2TestBase.java | 21 +++-- .../apache/coyote/http2/TestAsyncReadListener.java | 3 ++- .../apache/coyote/http2/TestCancelledUpload.java| 4 ++-- .../apache/coyote/http2/TestHttp2AccessLogs.java| 3 ++- test/org/apache/coyote/http2/TestHttp2Limits.java | 4 ++-- .../apache/coyote/http2/TestHttp2Section_8_1.java | 6 +++--- test/org/apache/coyote/http2/TestHttpServlet.java | 2 +- test/org/apache/coyote/http2/TestLargeUpload.java | 4 ++-- 8 files changed, 25 insertions(+), 22 deletions(-) diff --git a/test/org/apache/coyote/http2/Http2TestBase.java b/test/org/apache/coyote/http2/Http2TestBase.java index dc9c22cb34..e9d3a5de81 100644 --- a/test/org/apache/coyote/http2/Http2TestBase.java +++ b/test/org/apache/coyote/http2/Http2TestBase.java @@ -348,7 +348,7 @@ public abstract class Http2TestBase extends TomcatBaseTest { ByteBuffer dataPayload = ByteBuffer.allocate(128); buildPostRequest(headersFrameHeader, headersPayload, useExpectation, "application/x-www-form-urlencoded", -contentLength, "/parameter", dataFrameHeader, dataPayload, padding, null, null, streamId); +contentLength, "/parameter", dataFrameHeader, dataPayload, padding, false, streamId); writeFrame(headersFrameHeader, headersPayload); if (body != null) { dataPayload.put(body.getBytes(StandardCharsets.ISO_8859_1)); @@ -360,19 +360,18 @@ public abstract class Http2TestBase extends TomcatBaseTest { protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, boolean useExpectation, byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, int streamId) { buildPostRequest(headersFrameHeader, headersPayload, useExpectation, dataFrameHeader, dataPayload, padding, -null, null, streamId); +false, streamId); } protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, boolean useExpectation, -byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, byte[] trailersFrameHeader, -ByteBuffer trailersPayload, int streamId) { +byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, boolean withTrailers, int streamId) { buildPostRequest(headersFrameHeader, headersPayload, useExpectation, null, -1, "/simple", dataFrameHeader, -dataPayload, padding, trailersFrameHeader, trailersPayload, streamId); +dataPayload, padding, withTrailers, streamId); } protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, boolean useExpectation, String contentType, long contentLength, String path, byte[] dataFrameHeader, ByteBuffer dataPayload, -byte[] padding, byte[] trailersFrameHeader, ByteBuffer trailersPayload, int streamId) { +byte[] padding, boolean withTrailers, int streamId) { MimeHeaders headers = new MimeHeaders(); headers.addValue(":method").setString("POST"); @@ -419,17 +418,19 @@ public abstract class Http2TestBase extends TomcatBaseTest { ByteUtil.setThreeBytes(dataFrameHeader, 0, dataPayload.limit()); // Data is type 0 // Flags: End of stream 1, Padding 8 -if (trailersPayload == null) { -dataFrameHeader[4] = 0x01; -} else { +if (withTrailers) { dataFrameHeader[4] = 0x00; +} else { +dataFrameHeader[4] = 0x01; } if (padding != null) { dataFrameHeader[4] += 0x08; } ByteUtil.set31Bits(dataFrameHeader, 5, streamId); +} + -// Trailers +protected void buildTrailerHeaders(byte[] trailersFrameHeader, ByteBuffer trailersPayload, int streamId) { if (trailersPayload != null) { MimeHeaders trailerHeaders = new MimeHeaders(); trailerHeaders.addValue(TRAILER_HEADER_NAME).setString(TRAILER_HEADER_VALUE); diff --git a/test/org/apache/coyote/http2/TestAsyncReadListener.java b/test/org/apache/coyote/http2/TestAsyncReadListener.java index 2c02223770..614e487b46 100644 --- a/test/org/apache/coyote/http2/TestAsyncReadListener.java +++ b/test/org/apache/coyote/http2/TestAsyncReadListener.java @@ -77,7 +77,8 @@ public class TestAsyncReadListener extends Http2TestBase { buildPostRequest(headersFrameHeader, headersPayload, fals
(tomcat) 04/04: s
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 commit 96e0e8cb7d5f2bbe803d18defaf3d8a2e4d3eba5 Author: Mark Thomas AuthorDate: Mon Sep 30 16:24:02 2024 +0100 s --- webapps/docs/changelog.xml | 6 ++ 1 file changed, 6 insertions(+) diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 22ad5ab0e3..fe8db70b64 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -167,6 +167,12 @@ destroying SSLContext objects through GC after APR has been terminated. (remm) + +Improve HTTP/2 handling of trailer fields for requests. Trailer fields +no longer need to be recieved before the headers of the subsequent +stream nor are trailer fields for an in progress stream swallowed if the +Connector is paused before the trailer fields are received. (markt) + - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
(tomcat) 03/03: Improve HTTP/2 handling of trailer headers when connector is paused
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 9d2559b156778fc8576d419ab534d10808f014b1 Author: Mark Thomas AuthorDate: Mon Sep 30 16:01:47 2024 +0100 Improve HTTP/2 handling of trailer headers when connector is paused Prior to this change trailer headers for an existing stream would have been swallowed if received when the connector was paused. --- .../apache/coyote/http2/Http2UpgradeHandler.java | 38 +-- .../apache/coyote/http2/TestHttp2Section_6_8.java | 75 ++ webapps/docs/changelog.xml | 6 ++ 3 files changed, 101 insertions(+), 18 deletions(-) diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java b/java/org/apache/coyote/http2/Http2UpgradeHandler.java index 340621d931..04bb9e0be9 100644 --- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java +++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java @@ -1589,14 +1589,15 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH @Override public HeaderEmitter headersStart(int streamId, boolean headersEndStream) throws Http2Exception, IOException { -// Check the pause state before processing headers since the pause state -// determines if a new stream is created or if this stream is ignored. -checkPauseState(); - -if (connectionState.get().isNewStreamAllowed()) { -Stream stream = getStream(streamId, false); -if (stream == null) { -// New stream +Stream stream = getStream(streamId, false); +if (stream == null) { +// New stream + +// Check the pause state before processing headers since the pause state +// determines if a new stream is created or if this stream is ignored. +checkPauseState(); + +if (connectionState.get().isNewStreamAllowed()) { if (streamId > maxActiveRemoteStreamId) { stream = createRemoteStream(streamId); activeRemoteStreamCount.incrementAndGet(); @@ -1606,18 +1607,19 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH throw new ConnectionException(sm.getString("upgradeHandler.stream.old", Integer.valueOf(streamId), Integer.valueOf(maxActiveRemoteStreamId)), Http2Error.PROTOCOL_ERROR); } +} else { +if (log.isTraceEnabled()) { +log.trace(sm.getString("upgradeHandler.noNewStreams", connectionId, Integer.toString(streamId))); +} +reduceOverheadCount(FrameType.HEADERS); +// Stateless so a static can be used to save on GC +return HEADER_SINK; } -stream.checkState(FrameType.HEADERS); -stream.receivedStartOfHeaders(headersEndStream); -return stream; -} else { -if (log.isTraceEnabled()) { -log.trace(sm.getString("upgradeHandler.noNewStreams", connectionId, Integer.toString(streamId))); -} -reduceOverheadCount(FrameType.HEADERS); -// Stateless so a static can be used to save on GC -return HEADER_SINK; } + +stream.checkState(FrameType.HEADERS); +stream.receivedStartOfHeaders(headersEndStream); +return stream; } diff --git a/test/org/apache/coyote/http2/TestHttp2Section_6_8.java b/test/org/apache/coyote/http2/TestHttp2Section_6_8.java index ae245ca418..8b7ec1a6e2 100644 --- a/test/org/apache/coyote/http2/TestHttp2Section_6_8.java +++ b/test/org/apache/coyote/http2/TestHttp2Section_6_8.java @@ -16,9 +16,13 @@ */ package org.apache.coyote.http2; +import java.nio.ByteBuffer; + import org.junit.Assert; import org.junit.Test; +import org.apache.coyote.http11.AbstractHttp11Protocol; + /** * Unit tests for Section 6.8 of https://tools.ietf.org/html/rfc7540";>RFC 7540. * The order of tests in this class is aligned with the order of the requirements in the RFC. @@ -68,6 +72,77 @@ public class TestHttp2Section_6_8 extends Http2TestBase { } +@Test +public void testGoawayIgnoreNewStreamsAllowTrailers() throws Exception { +setPingAckDelayMillis(PING_ACK_DELAY_MS); + +http2Connect(); + +http2Protocol.setMaxConcurrentStreams(200); +// Ensure we see all the Window updates +http2Protocol.setOverheadWindowUpdateThreshold(0); +// Enable trailer headers +((AbstractHttp11Protocol) http2Protocol.getHttp11Protocol()).setAllowedTrailerHeaders(TRAILER_HEADER_NAME); + +Thread.sleep(PING_ACK_DELAY_MS + TIMING_MARGIN_MS); + +getTomcatInstance().getConnector().pause(); + +// Go away +parser.readFrame();
(tomcat) branch 10.1.x updated (ad1162bcd2 -> 9d2559b156)
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 ad1162bcd2 Fix IDE warnings new f4dd7560ea Refactor HTTP/2 trailer testing to create trailers separately new 043d6581b8 Improve HTTP/2 handling of trailer headers new 9d2559b156 Improve HTTP/2 handling of trailer headers when connector is paused The 3 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/coyote/http2/Http2UpgradeHandler.java | 66 +-- test/org/apache/coyote/http2/Http2TestBase.java| 21 +++--- .../apache/coyote/http2/TestAsyncReadListener.java | 3 +- .../apache/coyote/http2/TestCancelledUpload.java | 4 +- .../apache/coyote/http2/TestHttp2AccessLogs.java | 3 +- test/org/apache/coyote/http2/TestHttp2Limits.java | 4 +- .../apache/coyote/http2/TestHttp2Section_6_8.java | 75 ++ .../apache/coyote/http2/TestHttp2Section_8_1.java | 42 ++-- test/org/apache/coyote/http2/TestHttpServlet.java | 2 +- test/org/apache/coyote/http2/TestLargeUpload.java | 4 +- webapps/docs/changelog.xml | 6 ++ 11 files changed, 167 insertions(+), 63 deletions(-) - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
(tomcat) 02/03: Improve HTTP/2 handling of trailer headers
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 043d6581b86af0e553391965771f6715d79ca54c Author: Mark Thomas AuthorDate: Mon Sep 30 12:37:45 2024 +0100 Improve HTTP/2 handling of trailer headers Prior to this change, trailers for a stream had to be received before any headers of a subsequent stream. This commit removes that limitation. The idle stream handling is removed since Tomcat never creates streams in the idle state without immediately transitioning them to open. --- .../apache/coyote/http2/Http2UpgradeHandler.java | 34 +++ .../apache/coyote/http2/TestHttp2Section_8_1.java | 38 +++--- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java b/java/org/apache/coyote/http2/Http2UpgradeHandler.java index d44982fc82..340621d931 100644 --- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java +++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java @@ -118,8 +118,7 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH private final ConcurrentNavigableMap streams = new ConcurrentSkipListMap<>(); protected final AtomicInteger activeRemoteStreamCount = new AtomicInteger(0); -// Start at -1 so the 'add 2' logic in closeIdleStreams() works -private volatile int maxActiveRemoteStreamId = -1; +private volatile int maxActiveRemoteStreamId = 0; private volatile int maxProcessedStreamId; private final AtomicInteger nextLocalStreamId = new AtomicInteger(2); private final PingManager pingManager = getPingManager(); @@ -178,7 +177,7 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH Integer key = Integer.valueOf(1); Stream stream = new Stream(key, this, coyoteRequest); streams.put(key, stream); -maxActiveRemoteStreamId = 1; +maxActiveRemoteStreamId = 0; activeRemoteStreamCount.set(1); maxProcessedStreamId = 1; } @@ -1597,16 +1596,19 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH if (connectionState.get().isNewStreamAllowed()) { Stream stream = getStream(streamId, false); if (stream == null) { -stream = createRemoteStream(streamId); -activeRemoteStreamCount.incrementAndGet(); -} -if (streamId < maxActiveRemoteStreamId) { -throw new ConnectionException(sm.getString("upgradeHandler.stream.old", Integer.valueOf(streamId), -Integer.valueOf(maxActiveRemoteStreamId)), Http2Error.PROTOCOL_ERROR); +// New stream +if (streamId > maxActiveRemoteStreamId) { +stream = createRemoteStream(streamId); +activeRemoteStreamCount.incrementAndGet(); +maxActiveRemoteStreamId = streamId; +} else { +// ID for new stream must always be greater than any previous stream +throw new ConnectionException(sm.getString("upgradeHandler.stream.old", Integer.valueOf(streamId), +Integer.valueOf(maxActiveRemoteStreamId)), Http2Error.PROTOCOL_ERROR); +} } stream.checkState(FrameType.HEADERS); stream.receivedStartOfHeaders(headersEndStream); -closeIdleStreams(streamId); return stream; } else { if (log.isTraceEnabled()) { @@ -1619,18 +1621,6 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH } -private void closeIdleStreams(int newMaxActiveRemoteStreamId) { -final ConcurrentNavigableMap subMap = streams.subMap( -Integer.valueOf(maxActiveRemoteStreamId), false, Integer.valueOf(newMaxActiveRemoteStreamId), false); -for (AbstractNonZeroStream stream : subMap.values()) { -if (stream instanceof Stream) { -((Stream) stream).closeIfIdle(); -} -} -maxActiveRemoteStreamId = newMaxActiveRemoteStreamId; -} - - /** * Unused - NO-OP. * diff --git a/test/org/apache/coyote/http2/TestHttp2Section_8_1.java b/test/org/apache/coyote/http2/TestHttp2Section_8_1.java index 278f266474..45a6864f09 100644 --- a/test/org/apache/coyote/http2/TestHttp2Section_8_1.java +++ b/test/org/apache/coyote/http2/TestHttp2Section_8_1.java @@ -64,19 +64,24 @@ public class TestHttp2Section_8_1 extends Http2TestBase { ByteBuffer trailerPayload = ByteBuffer.allocate(256); buildPostRequest(headersFrameHeader, headersPayload, false, dataFrameHeader, dataPayload, null, true, 3); -buildTrailerHeaders(trailerFrame
(tomcat) 01/03: Refactor HTTP/2 trailer testing to create trailers separately
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 f4dd7560ea5b8e384047f2b163c258f4b45c9f23 Author: Mark Thomas AuthorDate: Mon Sep 30 11:49:48 2024 +0100 Refactor HTTP/2 trailer testing to create trailers separately This will allow other requests to be multiplexed between the headers and trailers of the stream using trailers. --- test/org/apache/coyote/http2/Http2TestBase.java | 21 +++-- .../apache/coyote/http2/TestAsyncReadListener.java | 3 ++- .../apache/coyote/http2/TestCancelledUpload.java| 4 ++-- .../apache/coyote/http2/TestHttp2AccessLogs.java| 3 ++- test/org/apache/coyote/http2/TestHttp2Limits.java | 4 ++-- .../apache/coyote/http2/TestHttp2Section_8_1.java | 6 +++--- test/org/apache/coyote/http2/TestHttpServlet.java | 2 +- test/org/apache/coyote/http2/TestLargeUpload.java | 4 ++-- 8 files changed, 25 insertions(+), 22 deletions(-) diff --git a/test/org/apache/coyote/http2/Http2TestBase.java b/test/org/apache/coyote/http2/Http2TestBase.java index da7dc94ab1..cf7cc9f364 100644 --- a/test/org/apache/coyote/http2/Http2TestBase.java +++ b/test/org/apache/coyote/http2/Http2TestBase.java @@ -348,7 +348,7 @@ public abstract class Http2TestBase extends TomcatBaseTest { ByteBuffer dataPayload = ByteBuffer.allocate(128); buildPostRequest(headersFrameHeader, headersPayload, useExpectation, "application/x-www-form-urlencoded", -contentLength, "/parameter", dataFrameHeader, dataPayload, padding, null, null, streamId); +contentLength, "/parameter", dataFrameHeader, dataPayload, padding, false, streamId); writeFrame(headersFrameHeader, headersPayload); if (body != null) { dataPayload.put(body.getBytes(StandardCharsets.ISO_8859_1)); @@ -360,19 +360,18 @@ public abstract class Http2TestBase extends TomcatBaseTest { protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, boolean useExpectation, byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, int streamId) { buildPostRequest(headersFrameHeader, headersPayload, useExpectation, dataFrameHeader, dataPayload, padding, -null, null, streamId); +false, streamId); } protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, boolean useExpectation, -byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, byte[] trailersFrameHeader, -ByteBuffer trailersPayload, int streamId) { +byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, boolean withTrailers, int streamId) { buildPostRequest(headersFrameHeader, headersPayload, useExpectation, null, -1, "/simple", dataFrameHeader, -dataPayload, padding, trailersFrameHeader, trailersPayload, streamId); +dataPayload, padding, withTrailers, streamId); } protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, boolean useExpectation, String contentType, long contentLength, String path, byte[] dataFrameHeader, ByteBuffer dataPayload, -byte[] padding, byte[] trailersFrameHeader, ByteBuffer trailersPayload, int streamId) { +byte[] padding, boolean withTrailers, int streamId) { MimeHeaders headers = new MimeHeaders(); headers.addValue(":method").setString("POST"); @@ -419,17 +418,19 @@ public abstract class Http2TestBase extends TomcatBaseTest { ByteUtil.setThreeBytes(dataFrameHeader, 0, dataPayload.limit()); // Data is type 0 // Flags: End of stream 1, Padding 8 -if (trailersPayload == null) { -dataFrameHeader[4] = 0x01; -} else { +if (withTrailers) { dataFrameHeader[4] = 0x00; +} else { +dataFrameHeader[4] = 0x01; } if (padding != null) { dataFrameHeader[4] += 0x08; } ByteUtil.set31Bits(dataFrameHeader, 5, streamId); +} + -// Trailers +protected void buildTrailerHeaders(byte[] trailersFrameHeader, ByteBuffer trailersPayload, int streamId) { if (trailersPayload != null) { MimeHeaders trailerHeaders = new MimeHeaders(); trailerHeaders.addValue(TRAILER_HEADER_NAME).setString(TRAILER_HEADER_VALUE); diff --git a/test/org/apache/coyote/http2/TestAsyncReadListener.java b/test/org/apache/coyote/http2/TestAsyncReadListener.java index 2c02223770..614e487b46 100644 --- a/test/org/apache/coyote/http2/TestAsyncReadListener.java +++ b/test/org/apache/coyote/http2/TestAsyncReadListener.java @@ -77,7 +77,8 @@ public class TestAsyncReadListener extends Http2TestBase { buildPostRequest(headersFrameHeader, headersPayload, fals
(tomcat) branch 11.0.x updated (3c83e17392 -> 96e0e8cb7d)
This is an automated email from the ASF dual-hosted git repository. markt pushed a change to branch 11.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git from 3c83e17392 Fix IDE warnings new a8f8b00afa Refactor HTTP/2 trailer testing to create trailers separately new fc9ec9590f Improve HTTP/2 handling of trailer headers new c821b8b442 Improve HTTP/2 handling of trailer headers when connector is paused new 96e0e8cb7d s The 4 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/coyote/http2/Http2UpgradeHandler.java | 66 +-- test/org/apache/coyote/http2/Http2TestBase.java| 21 +++--- .../apache/coyote/http2/TestAsyncReadListener.java | 3 +- .../apache/coyote/http2/TestCancelledUpload.java | 4 +- .../apache/coyote/http2/TestHttp2AccessLogs.java | 3 +- test/org/apache/coyote/http2/TestHttp2Limits.java | 4 +- .../apache/coyote/http2/TestHttp2Section_6_8.java | 75 ++ .../apache/coyote/http2/TestHttp2Section_8_1.java | 42 ++-- test/org/apache/coyote/http2/TestHttpServlet.java | 2 +- test/org/apache/coyote/http2/TestLargeUpload.java | 4 +- webapps/docs/changelog.xml | 6 ++ 11 files changed, 167 insertions(+), 63 deletions(-) - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
(tomcat) 02/04: Improve HTTP/2 handling of trailer headers
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 commit fc9ec9590f8459dd862fe38e8eb1f6ba1ee8554c Author: Mark Thomas AuthorDate: Mon Sep 30 12:37:45 2024 +0100 Improve HTTP/2 handling of trailer headers Prior to this change, trailers for a stream had to be received before any headers of a subsequent stream. This commit removes that limitation. The idle stream handling is removed since Tomcat never creates streams in the idle state without immediately transitioning them to open. --- .../apache/coyote/http2/Http2UpgradeHandler.java | 34 +++ .../apache/coyote/http2/TestHttp2Section_8_1.java | 38 +++--- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java b/java/org/apache/coyote/http2/Http2UpgradeHandler.java index 53a2fbddf3..925f20be78 100644 --- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java +++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java @@ -118,8 +118,7 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH private final ConcurrentNavigableMap streams = new ConcurrentSkipListMap<>(); protected final AtomicInteger activeRemoteStreamCount = new AtomicInteger(0); -// Start at -1 so the 'add 2' logic in closeIdleStreams() works -private volatile int maxActiveRemoteStreamId = -1; +private volatile int maxActiveRemoteStreamId = 0; private volatile int maxProcessedStreamId; private final PingManager pingManager = getPingManager(); private volatile int newStreamsSinceLastPrune = 0; @@ -177,7 +176,7 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH Integer key = Integer.valueOf(1); Stream stream = new Stream(key, this, coyoteRequest); streams.put(key, stream); -maxActiveRemoteStreamId = 1; +maxActiveRemoteStreamId = 0; activeRemoteStreamCount.set(1); maxProcessedStreamId = 1; } @@ -1536,16 +1535,19 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH if (connectionState.get().isNewStreamAllowed()) { Stream stream = getStream(streamId, false); if (stream == null) { -stream = createRemoteStream(streamId); -activeRemoteStreamCount.incrementAndGet(); -} -if (streamId < maxActiveRemoteStreamId) { -throw new ConnectionException(sm.getString("upgradeHandler.stream.old", Integer.valueOf(streamId), -Integer.valueOf(maxActiveRemoteStreamId)), Http2Error.PROTOCOL_ERROR); +// New stream +if (streamId > maxActiveRemoteStreamId) { +stream = createRemoteStream(streamId); +activeRemoteStreamCount.incrementAndGet(); +maxActiveRemoteStreamId = streamId; +} else { +// ID for new stream must always be greater than any previous stream +throw new ConnectionException(sm.getString("upgradeHandler.stream.old", Integer.valueOf(streamId), +Integer.valueOf(maxActiveRemoteStreamId)), Http2Error.PROTOCOL_ERROR); +} } stream.checkState(FrameType.HEADERS); stream.receivedStartOfHeaders(headersEndStream); -closeIdleStreams(streamId); return stream; } else { if (log.isTraceEnabled()) { @@ -1558,18 +1560,6 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH } -private void closeIdleStreams(int newMaxActiveRemoteStreamId) { -final ConcurrentNavigableMap subMap = streams.subMap( -Integer.valueOf(maxActiveRemoteStreamId), false, Integer.valueOf(newMaxActiveRemoteStreamId), false); -for (AbstractNonZeroStream stream : subMap.values()) { -if (stream instanceof Stream) { -((Stream) stream).closeIfIdle(); -} -} -maxActiveRemoteStreamId = newMaxActiveRemoteStreamId; -} - - @Override public void headersContinue(int payloadSize, boolean endOfHeaders) { // Generally, continuation frames don't impact the overhead count but if diff --git a/test/org/apache/coyote/http2/TestHttp2Section_8_1.java b/test/org/apache/coyote/http2/TestHttp2Section_8_1.java index 278f266474..45a6864f09 100644 --- a/test/org/apache/coyote/http2/TestHttp2Section_8_1.java +++ b/test/org/apache/coyote/http2/TestHttp2Section_8_1.java @@ -64,19 +64,24 @@ public class TestHttp2Section_8_1 extends Http2TestBase { ByteBuffer trailerPayload = ByteBuffer.allocate(256); buildPostRequest(headersFrameHeader,
(tomcat) branch 9.0.x updated (372f3cefe6 -> db10251f41)
This is an automated email from the ASF dual-hosted git repository. markt pushed a change to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git from 372f3cefe6 Fix IDE warnings new 94b41fac58 Refactor HTTP/2 trailer testing to create trailers separately new 53f1f6eed8 Improve HTTP/2 handling of trailer headers new cb34cc741b Improve HTTP/2 handling of trailer headers when connector is paused new db10251f41 Remove trailing space The 4 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/coyote/http2/Http2UpgradeHandler.java | 66 +-- test/org/apache/coyote/http2/Http2TestBase.java| 21 +++--- .../apache/coyote/http2/TestAsyncReadListener.java | 3 +- .../apache/coyote/http2/TestCancelledUpload.java | 4 +- .../apache/coyote/http2/TestHttp2AccessLogs.java | 3 +- test/org/apache/coyote/http2/TestHttp2Limits.java | 4 +- .../apache/coyote/http2/TestHttp2Section_6_8.java | 75 ++ .../apache/coyote/http2/TestHttp2Section_8_1.java | 42 ++-- test/org/apache/coyote/http2/TestHttpServlet.java | 2 +- test/org/apache/coyote/http2/TestLargeUpload.java | 4 +- webapps/docs/changelog.xml | 6 ++ 11 files changed, 167 insertions(+), 63 deletions(-) - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
(tomcat) 04/04: Remove trailing space
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 db10251f41d95f18bbb4e8e941083d138b2f5dff Author: Mark Thomas AuthorDate: Mon Sep 30 16:28:20 2024 +0100 Remove trailing space --- webapps/docs/changelog.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index f37e978573..fd9af8e75e 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -161,7 +161,7 @@ Improve HTTP/2 handling of trailer fields for requests. Trailer fields no longer need to be recieved before the headers of the subsequent -stream nor are trailer fields for an in progress stream swallowed if the +stream nor are trailer fields for an in progress stream swallowed if the Connector is paused before the trailer fields are received. (markt) - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
(tomcat) 02/04: Improve HTTP/2 handling of trailer headers
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 53f1f6eed8f993fec7ee86e6a2876667cfee1003 Author: Mark Thomas AuthorDate: Mon Sep 30 12:37:45 2024 +0100 Improve HTTP/2 handling of trailer headers Prior to this change, trailers for a stream had to be received before any headers of a subsequent stream. This commit removes that limitation. The idle stream handling is removed since Tomcat never creates streams in the idle state without immediately transitioning them to open. --- .../apache/coyote/http2/Http2UpgradeHandler.java | 34 +++ .../apache/coyote/http2/TestHttp2Section_8_1.java | 38 +++--- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java b/java/org/apache/coyote/http2/Http2UpgradeHandler.java index d6e5f83c66..a61c4bcbf1 100644 --- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java +++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java @@ -118,8 +118,7 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH private final ConcurrentNavigableMap streams = new ConcurrentSkipListMap<>(); protected final AtomicInteger activeRemoteStreamCount = new AtomicInteger(0); -// Start at -1 so the 'add 2' logic in closeIdleStreams() works -private volatile int maxActiveRemoteStreamId = -1; +private volatile int maxActiveRemoteStreamId = 0; private volatile int maxProcessedStreamId; private final AtomicInteger nextLocalStreamId = new AtomicInteger(2); private final PingManager pingManager = getPingManager(); @@ -175,7 +174,7 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH Integer key = Integer.valueOf(1); Stream stream = new Stream(key, this, coyoteRequest); streams.put(key, stream); -maxActiveRemoteStreamId = 1; +maxActiveRemoteStreamId = 0; activeRemoteStreamCount.set(1); maxProcessedStreamId = 1; } @@ -1594,16 +1593,19 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH if (connectionState.get().isNewStreamAllowed()) { Stream stream = getStream(streamId, false); if (stream == null) { -stream = createRemoteStream(streamId); -activeRemoteStreamCount.incrementAndGet(); -} -if (streamId < maxActiveRemoteStreamId) { -throw new ConnectionException(sm.getString("upgradeHandler.stream.old", Integer.valueOf(streamId), -Integer.valueOf(maxActiveRemoteStreamId)), Http2Error.PROTOCOL_ERROR); +// New stream +if (streamId > maxActiveRemoteStreamId) { +stream = createRemoteStream(streamId); +activeRemoteStreamCount.incrementAndGet(); +maxActiveRemoteStreamId = streamId; +} else { +// ID for new stream must always be greater than any previous stream +throw new ConnectionException(sm.getString("upgradeHandler.stream.old", Integer.valueOf(streamId), +Integer.valueOf(maxActiveRemoteStreamId)), Http2Error.PROTOCOL_ERROR); +} } stream.checkState(FrameType.HEADERS); stream.receivedStartOfHeaders(headersEndStream); -closeIdleStreams(streamId); return stream; } else { if (log.isTraceEnabled()) { @@ -1616,18 +1618,6 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH } -private void closeIdleStreams(int newMaxActiveRemoteStreamId) { -final ConcurrentNavigableMap subMap = streams.subMap( -Integer.valueOf(maxActiveRemoteStreamId), false, Integer.valueOf(newMaxActiveRemoteStreamId), false); -for (AbstractNonZeroStream stream : subMap.values()) { -if (stream instanceof Stream) { -((Stream) stream).closeIfIdle(); -} -} -maxActiveRemoteStreamId = newMaxActiveRemoteStreamId; -} - - /** * Unused - NO-OP. * diff --git a/test/org/apache/coyote/http2/TestHttp2Section_8_1.java b/test/org/apache/coyote/http2/TestHttp2Section_8_1.java index 28386ece2e..099af7d069 100644 --- a/test/org/apache/coyote/http2/TestHttp2Section_8_1.java +++ b/test/org/apache/coyote/http2/TestHttp2Section_8_1.java @@ -62,19 +62,24 @@ public class TestHttp2Section_8_1 extends Http2TestBase { ByteBuffer trailerPayload = ByteBuffer.allocate(256); buildPostRequest(headersFrameHeader, headersPayload, false, dataFrameHeader, dataPayload, null, true, 3); -buildTrailerHeaders(trailerFrameH
(tomcat) 01/04: Refactor HTTP/2 trailer testing to create trailers separately
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 94b41fac58157a2ba258bac2668d8e5810edecd2 Author: Mark Thomas AuthorDate: Mon Sep 30 11:49:48 2024 +0100 Refactor HTTP/2 trailer testing to create trailers separately This will allow other requests to be multiplexed between the headers and trailers of the stream using trailers. --- test/org/apache/coyote/http2/Http2TestBase.java | 21 +++-- .../apache/coyote/http2/TestAsyncReadListener.java | 3 ++- .../apache/coyote/http2/TestCancelledUpload.java| 4 ++-- .../apache/coyote/http2/TestHttp2AccessLogs.java| 3 ++- test/org/apache/coyote/http2/TestHttp2Limits.java | 4 ++-- .../apache/coyote/http2/TestHttp2Section_8_1.java | 6 +++--- test/org/apache/coyote/http2/TestHttpServlet.java | 2 +- test/org/apache/coyote/http2/TestLargeUpload.java | 4 ++-- 8 files changed, 25 insertions(+), 22 deletions(-) diff --git a/test/org/apache/coyote/http2/Http2TestBase.java b/test/org/apache/coyote/http2/Http2TestBase.java index 42def01e9b..e5d4a4ee0d 100644 --- a/test/org/apache/coyote/http2/Http2TestBase.java +++ b/test/org/apache/coyote/http2/Http2TestBase.java @@ -346,7 +346,7 @@ public abstract class Http2TestBase extends TomcatBaseTest { ByteBuffer dataPayload = ByteBuffer.allocate(128); buildPostRequest(headersFrameHeader, headersPayload, useExpectation, "application/x-www-form-urlencoded", -contentLength, "/parameter", dataFrameHeader, dataPayload, padding, null, null, streamId); +contentLength, "/parameter", dataFrameHeader, dataPayload, padding, false, streamId); writeFrame(headersFrameHeader, headersPayload); if (body != null) { dataPayload.put(body.getBytes(StandardCharsets.ISO_8859_1)); @@ -358,19 +358,18 @@ public abstract class Http2TestBase extends TomcatBaseTest { protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, boolean useExpectation, byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, int streamId) { buildPostRequest(headersFrameHeader, headersPayload, useExpectation, dataFrameHeader, dataPayload, padding, -null, null, streamId); +false, streamId); } protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, boolean useExpectation, -byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, byte[] trailersFrameHeader, -ByteBuffer trailersPayload, int streamId) { +byte[] dataFrameHeader, ByteBuffer dataPayload, byte[] padding, boolean withTrailers, int streamId) { buildPostRequest(headersFrameHeader, headersPayload, useExpectation, null, -1, "/simple", dataFrameHeader, -dataPayload, padding, trailersFrameHeader, trailersPayload, streamId); +dataPayload, padding, withTrailers, streamId); } protected void buildPostRequest(byte[] headersFrameHeader, ByteBuffer headersPayload, boolean useExpectation, String contentType, long contentLength, String path, byte[] dataFrameHeader, ByteBuffer dataPayload, -byte[] padding, byte[] trailersFrameHeader, ByteBuffer trailersPayload, int streamId) { +byte[] padding, boolean withTrailers, int streamId) { MimeHeaders headers = new MimeHeaders(); headers.addValue(":method").setString("POST"); @@ -417,17 +416,19 @@ public abstract class Http2TestBase extends TomcatBaseTest { ByteUtil.setThreeBytes(dataFrameHeader, 0, dataPayload.limit()); // Data is type 0 // Flags: End of stream 1, Padding 8 -if (trailersPayload == null) { -dataFrameHeader[4] = 0x01; -} else { +if (withTrailers) { dataFrameHeader[4] = 0x00; +} else { +dataFrameHeader[4] = 0x01; } if (padding != null) { dataFrameHeader[4] += 0x08; } ByteUtil.set31Bits(dataFrameHeader, 5, streamId); +} + -// Trailers +protected void buildTrailerHeaders(byte[] trailersFrameHeader, ByteBuffer trailersPayload, int streamId) { if (trailersPayload != null) { MimeHeaders trailerHeaders = new MimeHeaders(); trailerHeaders.addValue(TRAILER_HEADER_NAME).setString(TRAILER_HEADER_VALUE); diff --git a/test/org/apache/coyote/http2/TestAsyncReadListener.java b/test/org/apache/coyote/http2/TestAsyncReadListener.java index a6f77f8e7e..2046b4621f 100644 --- a/test/org/apache/coyote/http2/TestAsyncReadListener.java +++ b/test/org/apache/coyote/http2/TestAsyncReadListener.java @@ -77,7 +77,8 @@ public class TestAsyncReadListener extends Http2TestBase { buildPostRequest(headersFrameHeader, headersPayload, false
(tomcat) 03/04: Improve HTTP/2 handling of trailer headers when connector is paused
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 cb34cc741baca31216e164dfcc263a4b7e219b3a Author: Mark Thomas AuthorDate: Mon Sep 30 16:01:47 2024 +0100 Improve HTTP/2 handling of trailer headers when connector is paused Prior to this change trailer headers for an existing stream would have been swallowed if received when the connector was paused. --- .../apache/coyote/http2/Http2UpgradeHandler.java | 38 +-- .../apache/coyote/http2/TestHttp2Section_6_8.java | 75 ++ webapps/docs/changelog.xml | 6 ++ 3 files changed, 101 insertions(+), 18 deletions(-) diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java b/java/org/apache/coyote/http2/Http2UpgradeHandler.java index a61c4bcbf1..1c08a277cc 100644 --- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java +++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java @@ -1586,14 +1586,15 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH @Override public HeaderEmitter headersStart(int streamId, boolean headersEndStream) throws Http2Exception, IOException { -// Check the pause state before processing headers since the pause state -// determines if a new stream is created or if this stream is ignored. -checkPauseState(); - -if (connectionState.get().isNewStreamAllowed()) { -Stream stream = getStream(streamId, false); -if (stream == null) { -// New stream +Stream stream = getStream(streamId, false); +if (stream == null) { +// New stream + +// Check the pause state before processing headers since the pause state +// determines if a new stream is created or if this stream is ignored. +checkPauseState(); + +if (connectionState.get().isNewStreamAllowed()) { if (streamId > maxActiveRemoteStreamId) { stream = createRemoteStream(streamId); activeRemoteStreamCount.incrementAndGet(); @@ -1603,18 +1604,19 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH throw new ConnectionException(sm.getString("upgradeHandler.stream.old", Integer.valueOf(streamId), Integer.valueOf(maxActiveRemoteStreamId)), Http2Error.PROTOCOL_ERROR); } +} else { +if (log.isTraceEnabled()) { +log.trace(sm.getString("upgradeHandler.noNewStreams", connectionId, Integer.toString(streamId))); +} +reduceOverheadCount(FrameType.HEADERS); +// Stateless so a static can be used to save on GC +return HEADER_SINK; } -stream.checkState(FrameType.HEADERS); -stream.receivedStartOfHeaders(headersEndStream); -return stream; -} else { -if (log.isTraceEnabled()) { -log.trace(sm.getString("upgradeHandler.noNewStreams", connectionId, Integer.toString(streamId))); -} -reduceOverheadCount(FrameType.HEADERS); -// Stateless so a static can be used to save on GC -return HEADER_SINK; } + +stream.checkState(FrameType.HEADERS); +stream.receivedStartOfHeaders(headersEndStream); +return stream; } diff --git a/test/org/apache/coyote/http2/TestHttp2Section_6_8.java b/test/org/apache/coyote/http2/TestHttp2Section_6_8.java index ae245ca418..8b7ec1a6e2 100644 --- a/test/org/apache/coyote/http2/TestHttp2Section_6_8.java +++ b/test/org/apache/coyote/http2/TestHttp2Section_6_8.java @@ -16,9 +16,13 @@ */ package org.apache.coyote.http2; +import java.nio.ByteBuffer; + import org.junit.Assert; import org.junit.Test; +import org.apache.coyote.http11.AbstractHttp11Protocol; + /** * Unit tests for Section 6.8 of https://tools.ietf.org/html/rfc7540";>RFC 7540. * The order of tests in this class is aligned with the order of the requirements in the RFC. @@ -68,6 +72,77 @@ public class TestHttp2Section_6_8 extends Http2TestBase { } +@Test +public void testGoawayIgnoreNewStreamsAllowTrailers() throws Exception { +setPingAckDelayMillis(PING_ACK_DELAY_MS); + +http2Connect(); + +http2Protocol.setMaxConcurrentStreams(200); +// Ensure we see all the Window updates +http2Protocol.setOverheadWindowUpdateThreshold(0); +// Enable trailer headers +((AbstractHttp11Protocol) http2Protocol.getHttp11Protocol()).setAllowedTrailerHeaders(TRAILER_HEADER_NAME); + +Thread.sleep(PING_ACK_DELAY_MS + TIMING_MARGIN_MS); + +getTomcatInstance().getConnector().pause(); + +// Go away +parser.readFrame();
(tomcat) branch 11.0.x updated: Remove trailing space
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 c994d6fbd9 Remove trailing space c994d6fbd9 is described below commit c994d6fbd9d0e7662a2cebeee984aa7d8f6b1db9 Author: Mark Thomas AuthorDate: Mon Sep 30 16:28:20 2024 +0100 Remove trailing space --- webapps/docs/changelog.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index fe8db70b64..408776f2ce 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -170,7 +170,7 @@ Improve HTTP/2 handling of trailer fields for requests. Trailer fields no longer need to be recieved before the headers of the subsequent -stream nor are trailer fields for an in progress stream swallowed if the +stream nor are trailer fields for an in progress stream swallowed if the Connector is paused before the trailer fields are received. (markt) - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
(tomcat) branch 10.1.x updated: Remove trailing space
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 The following commit(s) were added to refs/heads/10.1.x by this push: new 108c5a6722 Remove trailing space 108c5a6722 is described below commit 108c5a672294781ca2dd74ca7f2ce6c2f545bf09 Author: Mark Thomas AuthorDate: Mon Sep 30 16:28:20 2024 +0100 Remove trailing space --- webapps/docs/changelog.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index b31b2dfb2f..3724839299 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -170,7 +170,7 @@ Improve HTTP/2 handling of trailer fields for requests. Trailer fields no longer need to be recieved before the headers of the subsequent -stream nor are trailer fields for an in progress stream swallowed if the +stream nor are trailer fields for an in progress stream swallowed if the Connector is paused before the trailer fields are received. (markt) - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
Buildbot failure in on tomcat-9.0.x
Build status: BUILD FAILED: failed compile (failure) Worker used: bb_worker2_ubuntu URL: https://ci2.apache.org/#builders/37/builds/1100 Blamelist: Mark Thomas Build Text: failed compile (failure) Status Detected: new failure Build Source Stamp: [branch 9.0.x] db10251f41d95f18bbb4e8e941083d138b2f5dff Steps: worker_preparation: 0 git: 0 shell: 0 shell_1: 0 shell_2: 0 shell_3: 0 shell_4: 0 shell_5: 0 compile: 1 shell_6: 0 shell_7: 0 shell_8: 0 shell_9: 0 Rsync docs to nightlies.apache.org: 0 shell_10: 0 Rsync RAT to nightlies.apache.org: 0 compile_1: 2 shell_11: 0 Rsync Logs to nightlies.apache.org: 0 -- ASF Buildbot - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
(tomcat) 02/03: Improve HTTP/2 handling of trailer headers
This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git commit 557907253d784683e43665052ae28348a9e200eb Author: Mark Thomas AuthorDate: Mon Sep 30 12:37:45 2024 +0100 Improve HTTP/2 handling of trailer headers Prior to this change, trailers for a stream had to be received before any headers of a subsequent stream. This commit removes that limitation. The idle stream handling is removed since Tomcat never creates streams in the idle state without immediately transitioning them to open. --- .../apache/coyote/http2/Http2UpgradeHandler.java | 34 +++ .../apache/coyote/http2/TestHttp2Section_8_1.java | 38 +++--- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java b/java/org/apache/coyote/http2/Http2UpgradeHandler.java index 53a2fbddf3..925f20be78 100644 --- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java +++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java @@ -118,8 +118,7 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH private final ConcurrentNavigableMap streams = new ConcurrentSkipListMap<>(); protected final AtomicInteger activeRemoteStreamCount = new AtomicInteger(0); -// Start at -1 so the 'add 2' logic in closeIdleStreams() works -private volatile int maxActiveRemoteStreamId = -1; +private volatile int maxActiveRemoteStreamId = 0; private volatile int maxProcessedStreamId; private final PingManager pingManager = getPingManager(); private volatile int newStreamsSinceLastPrune = 0; @@ -177,7 +176,7 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH Integer key = Integer.valueOf(1); Stream stream = new Stream(key, this, coyoteRequest); streams.put(key, stream); -maxActiveRemoteStreamId = 1; +maxActiveRemoteStreamId = 0; activeRemoteStreamCount.set(1); maxProcessedStreamId = 1; } @@ -1536,16 +1535,19 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH if (connectionState.get().isNewStreamAllowed()) { Stream stream = getStream(streamId, false); if (stream == null) { -stream = createRemoteStream(streamId); -activeRemoteStreamCount.incrementAndGet(); -} -if (streamId < maxActiveRemoteStreamId) { -throw new ConnectionException(sm.getString("upgradeHandler.stream.old", Integer.valueOf(streamId), -Integer.valueOf(maxActiveRemoteStreamId)), Http2Error.PROTOCOL_ERROR); +// New stream +if (streamId > maxActiveRemoteStreamId) { +stream = createRemoteStream(streamId); +activeRemoteStreamCount.incrementAndGet(); +maxActiveRemoteStreamId = streamId; +} else { +// ID for new stream must always be greater than any previous stream +throw new ConnectionException(sm.getString("upgradeHandler.stream.old", Integer.valueOf(streamId), +Integer.valueOf(maxActiveRemoteStreamId)), Http2Error.PROTOCOL_ERROR); +} } stream.checkState(FrameType.HEADERS); stream.receivedStartOfHeaders(headersEndStream); -closeIdleStreams(streamId); return stream; } else { if (log.isTraceEnabled()) { @@ -1558,18 +1560,6 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH } -private void closeIdleStreams(int newMaxActiveRemoteStreamId) { -final ConcurrentNavigableMap subMap = streams.subMap( -Integer.valueOf(maxActiveRemoteStreamId), false, Integer.valueOf(newMaxActiveRemoteStreamId), false); -for (AbstractNonZeroStream stream : subMap.values()) { -if (stream instanceof Stream) { -((Stream) stream).closeIfIdle(); -} -} -maxActiveRemoteStreamId = newMaxActiveRemoteStreamId; -} - - @Override public void headersContinue(int payloadSize, boolean endOfHeaders) { // Generally, continuation frames don't impact the overhead count but if diff --git a/test/org/apache/coyote/http2/TestHttp2Section_8_1.java b/test/org/apache/coyote/http2/TestHttp2Section_8_1.java index 278f266474..45a6864f09 100644 --- a/test/org/apache/coyote/http2/TestHttp2Section_8_1.java +++ b/test/org/apache/coyote/http2/TestHttp2Section_8_1.java @@ -64,19 +64,24 @@ public class TestHttp2Section_8_1 extends Http2TestBase { ByteBuffer trailerPayload = ByteBuffer.allocate(256); buildPostRequest(headersFrameHeader, h
(tomcat) 03/03: Improve HTTP/2 handling of trailer headers when connector is paused
This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git commit 5269b89bebc1b1461d76d18272cb58b072a85e6a Author: Mark Thomas AuthorDate: Mon Sep 30 16:01:47 2024 +0100 Improve HTTP/2 handling of trailer headers when connector is paused Prior to this change trailer headers for an existing stream would have been swallowed if received when the connector was paused. --- .../apache/coyote/http2/Http2UpgradeHandler.java | 38 +-- .../apache/coyote/http2/TestHttp2Section_6_8.java | 75 ++ 2 files changed, 95 insertions(+), 18 deletions(-) diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java b/java/org/apache/coyote/http2/Http2UpgradeHandler.java index 925f20be78..f01678c455 100644 --- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java +++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java @@ -1528,14 +1528,15 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH @Override public HeaderEmitter headersStart(int streamId, boolean headersEndStream) throws Http2Exception, IOException { -// Check the pause state before processing headers since the pause state -// determines if a new stream is created or if this stream is ignored. -checkPauseState(); - -if (connectionState.get().isNewStreamAllowed()) { -Stream stream = getStream(streamId, false); -if (stream == null) { -// New stream +Stream stream = getStream(streamId, false); +if (stream == null) { +// New stream + +// Check the pause state before processing headers since the pause state +// determines if a new stream is created or if this stream is ignored. +checkPauseState(); + +if (connectionState.get().isNewStreamAllowed()) { if (streamId > maxActiveRemoteStreamId) { stream = createRemoteStream(streamId); activeRemoteStreamCount.incrementAndGet(); @@ -1545,18 +1546,19 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH throw new ConnectionException(sm.getString("upgradeHandler.stream.old", Integer.valueOf(streamId), Integer.valueOf(maxActiveRemoteStreamId)), Http2Error.PROTOCOL_ERROR); } +} else { +if (log.isTraceEnabled()) { +log.trace(sm.getString("upgradeHandler.noNewStreams", connectionId, Integer.toString(streamId))); +} +reduceOverheadCount(FrameType.HEADERS); +// Stateless so a static can be used to save on GC +return HEADER_SINK; } -stream.checkState(FrameType.HEADERS); -stream.receivedStartOfHeaders(headersEndStream); -return stream; -} else { -if (log.isTraceEnabled()) { -log.trace(sm.getString("upgradeHandler.noNewStreams", connectionId, Integer.toString(streamId))); -} -reduceOverheadCount(FrameType.HEADERS); -// Stateless so a static can be used to save on GC -return HEADER_SINK; } + +stream.checkState(FrameType.HEADERS); +stream.receivedStartOfHeaders(headersEndStream); +return stream; } diff --git a/test/org/apache/coyote/http2/TestHttp2Section_6_8.java b/test/org/apache/coyote/http2/TestHttp2Section_6_8.java index ae245ca418..8b7ec1a6e2 100644 --- a/test/org/apache/coyote/http2/TestHttp2Section_6_8.java +++ b/test/org/apache/coyote/http2/TestHttp2Section_6_8.java @@ -16,9 +16,13 @@ */ package org.apache.coyote.http2; +import java.nio.ByteBuffer; + import org.junit.Assert; import org.junit.Test; +import org.apache.coyote.http11.AbstractHttp11Protocol; + /** * Unit tests for Section 6.8 of https://tools.ietf.org/html/rfc7540";>RFC 7540. * The order of tests in this class is aligned with the order of the requirements in the RFC. @@ -68,6 +72,77 @@ public class TestHttp2Section_6_8 extends Http2TestBase { } +@Test +public void testGoawayIgnoreNewStreamsAllowTrailers() throws Exception { +setPingAckDelayMillis(PING_ACK_DELAY_MS); + +http2Connect(); + +http2Protocol.setMaxConcurrentStreams(200); +// Ensure we see all the Window updates +http2Protocol.setOverheadWindowUpdateThreshold(0); +// Enable trailer headers +((AbstractHttp11Protocol) http2Protocol.getHttp11Protocol()).setAllowedTrailerHeaders(TRAILER_HEADER_NAME); + +Thread.sleep(PING_ACK_DELAY_MS + TIMING_MARGIN_MS); + +getTomcatInstance().getConnector().pause(); + +// Go away +parser.readFrame(); +Assert.assertEquals("0-Goaway-[2147483647]-[0]-[null]
(tomcat) branch main updated (2276ee88f2 -> 5269b89beb)
This is an automated email from the ASF dual-hosted git repository. markt pushed a change to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git from 2276ee88f2 Fix IDE warnings new 55e79890bf Refactor HTTP/2 trailer testing to create trailers separately new 557907253d Improve HTTP/2 handling of trailer headers new 5269b89beb Improve HTTP/2 handling of trailer headers when connector is paused The 3 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/coyote/http2/Http2UpgradeHandler.java | 66 +-- test/org/apache/coyote/http2/Http2TestBase.java| 21 +++--- .../apache/coyote/http2/TestAsyncReadListener.java | 3 +- .../apache/coyote/http2/TestCancelledUpload.java | 4 +- .../apache/coyote/http2/TestHttp2AccessLogs.java | 3 +- test/org/apache/coyote/http2/TestHttp2Limits.java | 4 +- .../apache/coyote/http2/TestHttp2Section_6_8.java | 75 ++ .../apache/coyote/http2/TestHttp2Section_8_1.java | 42 ++-- test/org/apache/coyote/http2/TestHttpServlet.java | 2 +- test/org/apache/coyote/http2/TestLargeUpload.java | 4 +- 10 files changed, 161 insertions(+), 63 deletions(-) - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
(tomcat) branch 9.0.x updated: Fix backport - HTTP/2 has separate trailer settings for 9.0.x
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 The following commit(s) were added to refs/heads/9.0.x by this push: new 3ad19d91da Fix backport - HTTP/2 has separate trailer settings for 9.0.x 3ad19d91da is described below commit 3ad19d91da9bdd7f4350823bcec73b2abefa0848 Author: Mark Thomas AuthorDate: Mon Sep 30 20:27:20 2024 +0100 Fix backport - HTTP/2 has separate trailer settings for 9.0.x --- test/org/apache/coyote/http2/TestHttp2Section_6_8.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/org/apache/coyote/http2/TestHttp2Section_6_8.java b/test/org/apache/coyote/http2/TestHttp2Section_6_8.java index 8b7ec1a6e2..e19fcb2f0f 100644 --- a/test/org/apache/coyote/http2/TestHttp2Section_6_8.java +++ b/test/org/apache/coyote/http2/TestHttp2Section_6_8.java @@ -21,8 +21,6 @@ import java.nio.ByteBuffer; import org.junit.Assert; import org.junit.Test; -import org.apache.coyote.http11.AbstractHttp11Protocol; - /** * Unit tests for Section 6.8 of https://tools.ietf.org/html/rfc7540";>RFC 7540. * The order of tests in this class is aligned with the order of the requirements in the RFC. @@ -82,7 +80,7 @@ public class TestHttp2Section_6_8 extends Http2TestBase { // Ensure we see all the Window updates http2Protocol.setOverheadWindowUpdateThreshold(0); // Enable trailer headers -((AbstractHttp11Protocol) http2Protocol.getHttp11Protocol()).setAllowedTrailerHeaders(TRAILER_HEADER_NAME); +http2Protocol.setAllowedTrailerHeaders(TRAILER_HEADER_NAME); Thread.sleep(PING_ACK_DELAY_MS + TIMING_MARGIN_MS); - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org
Buildbot success in on tomcat-9.0.x
Build status: Build succeeded! Worker used: bb_worker2_ubuntu URL: https://ci2.apache.org/#builders/37/builds/1101 Blamelist: Mark Thomas Build Text: build successful Status Detected: restored build Build Source Stamp: [branch 9.0.x] 3ad19d91da9bdd7f4350823bcec73b2abefa0848 Steps: worker_preparation: 0 git: 0 shell: 0 shell_1: 0 shell_2: 0 shell_3: 0 shell_4: 0 shell_5: 0 compile: 1 shell_6: 0 shell_7: 0 shell_8: 0 shell_9: 0 Rsync docs to nightlies.apache.org: 0 shell_10: 0 Rsync RAT to nightlies.apache.org: 0 compile_1: 1 shell_11: 0 Rsync Logs to nightlies.apache.org: 0 -- ASF Buildbot - To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org