From 5f534ebfc3efbc60ca7ee8e6ef17d521a1a45f7b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marie=20P=C3=ADchov=C3=A1?= <11718369+ManickaP@users.noreply.github.com> Date: Thu, 12 Aug 2021 20:43:20 +0200 Subject: [PATCH] Fixed sending FIN flag with the last write. (#57284) --- .../Http/SocketsHttpHandler/Http3RequestStream.cs | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs index 115f2b9..aa5f754 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs @@ -147,13 +147,10 @@ namespace System.Net.Http // Ideally, headers will be sent out in a gathered write inside of SendContentAsync(). // If we don't have content, or we are doing Expect 100 Continue, then we can't rely on // this and must send our headers immediately. - await FlushSendBufferAsync(requestCancellationSource.Token).ConfigureAwait(false); - // End the stream writing if there's no content to send. - if (_request.Content == null) - { - _stream.Shutdown(); - } + // End the stream writing if there's no content to send, do it as part of the write so that the FIN flag isn't send in an empty QUIC frame. + // Note that there's no need to call Shutdown separately since the FIN flag in the last write is the same thing. + await FlushSendBufferAsync(endStream: _request.Content == null, requestCancellationSource.Token).ConfigureAwait(false); } // If using duplex content, the content will continue sending after this method completes. @@ -370,12 +367,15 @@ namespace System.Net.Http if (_sendBuffer.ActiveLength != 0) { - // Our initial send buffer, which has our headers, are normally sent out on the first write to the Http3WriteStream. + // Our initial send buffer, which has our headers, is normally sent out on the first write to the Http3WriteStream. // If we get here, it means the content didn't actually do any writing. Send out the headers now. - await FlushSendBufferAsync(cancellationToken).ConfigureAwait(false); + // Also send the FIN flag, since this is the last write. No need to call Shutdown separately. + await FlushSendBufferAsync(endStream: true, cancellationToken).ConfigureAwait(false); + } + else + { + _stream.Shutdown(); } - - _stream.Shutdown(); } private async ValueTask WriteRequestContentAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken) @@ -432,9 +432,9 @@ namespace System.Net.Http } } - private async ValueTask FlushSendBufferAsync(CancellationToken cancellationToken) + private async ValueTask FlushSendBufferAsync(bool endStream, CancellationToken cancellationToken) { - await _stream.WriteAsync(_sendBuffer.ActiveMemory, cancellationToken).ConfigureAwait(false); + await _stream.WriteAsync(_sendBuffer.ActiveMemory, endStream, cancellationToken).ConfigureAwait(false); _sendBuffer.Discard(_sendBuffer.ActiveLength); await _stream.FlushAsync(cancellationToken).ConfigureAwait(false); @@ -1348,7 +1348,7 @@ namespace System.Net.Http return Task.FromException(new ObjectDisposedException(nameof(Http3WriteStream))); } - return _stream.FlushSendBufferAsync(cancellationToken).AsTask(); + return _stream.FlushSendBufferAsync(endStream: false, cancellationToken).AsTask(); } } -- 2.7.4