-- Please reply above this line --

            Hi there,

THIS IS AN AUTOMATED MESSAGE. PLEASE RESUBMIT YOUR MESSAGE AT
HTTPS://TRELLO.COM/CONTACT [1]

You've emailed supp...@trello.com [2], which is no longer available
for support.

Trello Support is still here to support you, the same as before, but
through that form.

Thanks very much!


Links:
------
[1] https://trello.com/contact
[2] mailto:supp...@trello.com

All the best,

Trello
The Trello Team

Need priority support for your business? Check out Trello Business
Class [1].
Visit our Trello community [2] to ask other Trello users for how-to's
or advice.


Links:
------
[1]
https://trello.com/business-class?utm_source=support-email&utm_medium=email&utm_term=footer&utm_campaign=support-business-class
[2] https://community.atlassian.com/trello

                                
        > On Tue, Jun 15, 2021 at 3:02 AM EDT, Tomcat Developers List 
<dev@tomcat.apache.org> wrote:
> 
> 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 [1]
> 
> The following commit(s) were added to refs/heads/main by this push:
> new 2538f6d Fix problems with file uploads and HTTP/2
> 2538f6d is described below
> 
> commit 2538f6d74949751901afc5e04014ede4f867152a
> Author: Mark Thomas <ma...@apache.org>
> AuthorDate: Mon Jun 14 21:15:30 2021 +0100
> 
> Fix problems with file uploads and HTTP/2
> 
> Small writes from the user agent were triggering small window updates
> which in turn triggered more small writes. With lots of small writes
> the
> overhead protection code was activated and the connection closed.
> ---
> .../coyote/http2/Http2AsyncUpgradeHandler.java | 30
> ++++++++++++-------
> .../apache/coyote/http2/Http2UpgradeHandler.java | 34
> +++++++++++++++-------
> .../apache/coyote/http2/LocalStrings.properties | 2 ++
> java/org/apache/coyote/http2/Stream.java | 24 +++++++++++++++
> webapps/docs/changelog.xml | 10 +++++++
> 5 files changed, 79 insertions(+), 21 deletions(-)
> 
> diff --git
> a/java/org/apache/coyote/http2/Http2AsyncUpgradeHandler.java
> b/java/org/apache/coyote/http2/Http2AsyncUpgradeHandler.java
> index b77fee6..6d7e3eb 100644
> --- a/java/org/apache/coyote/http2/Http2AsyncUpgradeHandler.java
> +++ b/java/org/apache/coyote/http2/Http2AsyncUpgradeHandler.java
> @@ -231,22 +231,32 @@ public class Http2AsyncUpgradeHandler extends
> Http2UpgradeHandler {
> @Override
> void writeWindowUpdate(AbstractNonZeroStream stream, int increment,
> boolean applicationInitiated)
> throws IOException {
> + if (log.isDebugEnabled()) {
> + log.debug(sm.getString("upgradeHandler.windowUpdateConnection",
> + getConnectionId(), Integer.valueOf(increment)));
> + }
> // Build window update frame for stream 0
> byte[] frame = new byte[13];
> ByteUtil.setThreeBytes(frame, 0, 4);
> frame[3] = FrameType.WINDOW_UPDATE.getIdByte();
> ByteUtil.set31Bits(frame, 9, increment);
> // No need to send update from closed stream
> - if (stream instanceof Stream &
> - ByteUtil.setThreeBytes(frame2, 0, 4);
> - frame2[3] = FrameType.WINDOW_UPDATE.getIdByte();
> - ByteUtil.set31Bits(frame2, 9, increment);
> - ByteUtil.set31Bits(frame2, 5, stream.getIdAsInt());
> - socketWrapper.write(BlockingMode.SEMI_BLOCK,
> protocol.getWriteTimeout(),
> - TimeUnit.MILLISECONDS, null, SocketWrapperBase.COMPLETE_WRITE,
> errorCompletion,
> - ByteBuffer.wrap(frame), ByteBuffer.wrap(frame2));
> + if (stream instanceof Stream &
> + if (streamIncrement > 0) {
> + if (log.isDebugEnabled()) {
> + log.debug(sm.getString("upgradeHandler.windowUpdateStream",
> + getConnectionId(), getIdAsString(),
> Integer.valueOf(streamIncrement)));
> + }
> + byte[] frame2 = new byte[13];
> + ByteUtil.setThreeBytes(frame2, 0, 4);
> + frame2[3] = FrameType.WINDOW_UPDATE.getIdByte();
> + ByteUtil.set31Bits(frame2, 9, streamIncrement);
> + ByteUtil.set31Bits(frame2, 5, stream.getIdAsInt());
> + socketWrapper.write(BlockingMode.SEMI_BLOCK,
> protocol.getWriteTimeout(),
> + TimeUnit.MILLISECONDS, null, SocketWrapperBase.COMPLETE_WRITE,
> errorCompletion,
> + ByteBuffer.wrap(frame), ByteBuffer.wrap(frame2));
> + }
> } else {
> socketWrapper.write(BlockingMode.SEMI_BLOCK,
> protocol.getWriteTimeout(),
> TimeUnit.MILLISECONDS, null, SocketWrapperBase.COMPLETE_WRITE,
> errorCompletion,
> diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java
> b/java/org/apache/coyote/http2/Http2UpgradeHandler.java
> index 994a7cb..fa650b7 100644
> --- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java
> +++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java
> @@ -804,6 +804,10 @@ class Http2UpgradeHandler extends AbstractStream
> implements InternalHttpUpgradeH
> */
> void writeWindowUpdate(AbstractNonZeroStream stream, int increment,
> boolean applicationInitiated)
> throws IOException {
> + if (log.isDebugEnabled()) {
> + log.debug(sm.getString("upgradeHandler.windowUpdateConnection",
> + getConnectionId(), Integer.valueOf(increment)));
> + }
> synchronized (socketWrapper) {
> // Build window update frame for stream 0
> byte[] frame = new byte[13];
> @@ -812,17 +816,25 @@ class Http2UpgradeHandler extends
> AbstractStream implements InternalHttpUpgradeH
> ByteUtil.set31Bits(frame, 9, increment);
> socketWrapper.write(true, frame, 0, frame.length);
> // No need to send update from closed stream
> - if (stream instanceof Stream &
> - try {
> - socketWrapper.write(true, frame, 0, frame.length);
> - socketWrapper.flush(true);
> - } catch (IOException ioe) {
> - if (applicationInitiated) {
> - handleAppInitiatedIOException(ioe);
> - } else {
> - throw ioe;
> + if (stream instanceof Stream &
> + if (streamIncrement > 0) {
> + if (log.isDebugEnabled()) {
> + log.debug(sm.getString("upgradeHandler.windowUpdateStream",
> + getConnectionId(), getIdAsString(),
> Integer.valueOf(streamIncrement)));
> + }
> + // Re-use buffer as connection update has already been written
> + ByteUtil.set31Bits(frame, 5, stream.getIdAsInt());
> + ByteUtil.set31Bits(frame, 9, streamIncrement);
> + try {
> + socketWrapper.write(true, frame, 0, frame.length);
> + socketWrapper.flush(true);
> + } catch (IOException ioe) {
> + if (applicationInitiated) {
> + handleAppInitiatedIOException(ioe);
> + } else {
> + throw ioe;
> + }
> }
> }
> } else {
> diff --git a/java/org/apache/coyote/http2/LocalStrings.properties
> b/java/org/apache/coyote/http2/LocalStrings.properties
> index 3e114d8..25858cb 100644
> --- a/java/org/apache/coyote/http2/LocalStrings.properties
> +++ b/java/org/apache/coyote/http2/LocalStrings.properties
> @@ -158,6 +158,8 @@ upgradeHandler.upgradeDispatch.entry=Entry,
> Connection [{0}], SocketStatus [{1}]
> upgradeHandler.upgradeDispatch.exit=Exit, Connection [{0}],
> SocketState [{1}]
> upgradeHandler.windowSizeReservationInterrupted=Connection [{0}],
> Stream [{1}], reservation for [{2}] bytes
> upgradeHandler.windowSizeTooBig=Connection [{0}], Stream [{1}],
> Window size too big
> +upgradeHandler.windowUpdateConnection=Connection [{0}], Sent window
> update to client increasing window by [{1}] bytes
> +upgradeHandler.windowUpdateStream=Connection [{0}], Stream [{1}],
> Sent window update to client increasing window by [{2}] bytes
> upgradeHandler.writeBody=Connection [{0}], Stream [{1}], Data length
> [{2}], EndOfStream [{3}]
> upgradeHandler.writeHeaders=Connection [{0}], Stream [{1}], Writing
> the headers, EndOfStream [{2}]
> upgradeHandler.writePushHeaders=Connection [{0}], Stream [{1}],
> Pushed stream [{2}], EndOfStream [{3}]
> diff --git a/java/org/apache/coyote/http2/Stream.java
> b/java/org/apache/coyote/http2/Stream.java
> index 28ec14e..8d93d98 100644
> --- a/java/org/apache/coyote/http2/Stream.java
> +++ b/java/org/apache/coyote/http2/Stream.java
> @@ -82,6 +82,9 @@ class Stream extends AbstractNonZeroStream
> implements HeaderEmitter {
> 
> private volatile StringBuilder cookieHeader = null;
> 
> + private Object pendingWindowUpdateForStreamLock = new Object();
> + private int pendingWindowUpdateForStream = 0;
> +
> 
> Stream(Integer identifier, Http2UpgradeHandler handler) {
> this(identifier, handler, null);
> @@ -744,6 +747,27 @@ class Stream extends AbstractNonZeroStream
> implements HeaderEmitter {
> }
> 
> + int getWindowUpdateSizeToWrite(int increment) {
> + int result;
> + int threshold =
> handler.getProtocol().getOverheadWindowUpdateThreshold();
> + synchronized (pendingWindowUpdateForStreamLock) {
> + if (increment > threshold) {
> + result = increment + pendingWindowUpdateForStream;
> + pendingWindowUpdateForStream = 0;
> + } else {
> + pendingWindowUpdateForStream += increment;
> + if (pendingWindowUpdateForStream > threshold) {
> + result = pendingWindowUpdateForStream;
> + pendingWindowUpdateForStream = 0;
> + } else {
> + result = 0;
> + }
> + }
> + }
> + return result;
> + }
> +
> +
> private static void push(final Http2UpgradeHandler handler, final
> Request request,
> final Stream stream) throws IOException {
> if (org.apache.coyote.Constants.IS_SECURITY_ENABLED) {
> diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
> index 41ebbd0..c5dc156 100644
> --- a/webapps/docs/changelog.xml
> +++ b/webapps/docs/changelog.xml
> @@ -112,6 +112,16 @@
> connections. Treat them the same way as clean closes of non-TLS
> connections rather than as unknown errors. (markt)
> </fix>
> + <fix>
> + Modify the HTTP/2 connector not to sent small updates for stream
> flow
> + control windows to the user agent as, depending on how the user
> agent is
> + written, this may trigger small writes from the user agent that in
> turn
> + trigger the overhead protection. Small updates for stream flow
> control
> + windows are now combined with subsequent flow control window
> updates for
> + that stream to ensure that all stream flow control window updates
> sent
> + from Tomcat are larger than
> <code>overheadWindowUpdateThreshold</code>.
> + (markt)
> + </fix>
> </changelog>
> </subsection>
> <subsection name="Other">
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org [2]
> For additional commands, e-mail: dev-h...@tomcat.apache.org [3]
> 
> Links:
> ------
> [1] https://gitbox.apache.org/repos/asf/tomcat.git
> [2] mailto:dev-unsubscr...@tomcat.apache.org
> [3] mailto:dev-h...@tomcat.apache.org
> 
> 
> 
> 

Reply via email to