diff --git a/NuGet.config b/NuGet.config
index 8e21b29e5c5a..0b2629f92cfb 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -4,10 +4,10 @@
-
+
-
+
@@ -26,10 +26,10 @@
-
+
-
+
diff --git a/eng/Baseline.Designer.props b/eng/Baseline.Designer.props
index 93b5cb9b69e8..61d7f2813e8c 100644
--- a/eng/Baseline.Designer.props
+++ b/eng/Baseline.Designer.props
@@ -2,28 +2,28 @@
$(MSBuildAllProjects);$(MSBuildThisFileFullPath)
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
-
-
-
+
+
+
@@ -35,105 +35,105 @@
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
-
+
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
@@ -141,121 +141,121 @@
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
-
+
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
-
+
- 7.0.11
+ 7.0.12
-
-
+
+
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
-
-
+
+
- 7.0.11
+ 7.0.12
-
+
- 7.0.11
+ 7.0.12
-
+
- 7.0.11
+ 7.0.12
-
-
-
+
+
+
- 7.0.11
+ 7.0.12
-
-
+
+
- 7.0.11
+ 7.0.12
-
-
+
+
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
-
-
+
+
@@ -263,7 +263,7 @@
- 7.0.11
+ 7.0.12
@@ -272,50 +272,50 @@
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
-
-
+
+
@@ -325,8 +325,8 @@
-
-
+
+
@@ -334,8 +334,8 @@
-
-
+
+
@@ -346,58 +346,58 @@
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
-
-
+
+
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
-
+
- 7.0.11
+ 7.0.12
@@ -414,7 +414,7 @@
- 7.0.11
+ 7.0.12
@@ -422,71 +422,71 @@
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
-
-
+
+
- 7.0.11
+ 7.0.12
-
-
+
+
- 7.0.11
+ 7.0.12
@@ -502,27 +502,27 @@
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
-
+
- 7.0.11
+ 7.0.12
@@ -531,151 +531,151 @@
- 7.0.11
+ 7.0.12
-
+
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
-
-
+
+
-
-
+
+
-
-
+
+
- 7.0.11
+ 7.0.12
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
-
-
-
-
+
+
+
+
- 7.0.11
+ 7.0.12
@@ -684,60 +684,60 @@
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
-
+
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
@@ -756,7 +756,7 @@
- 7.0.11
+ 7.0.12
@@ -778,7 +778,7 @@
- 7.0.11
+ 7.0.12
@@ -794,46 +794,46 @@
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
-
-
-
+
+
+
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
@@ -843,7 +843,7 @@
- 7.0.11
+ 7.0.12
@@ -852,73 +852,73 @@
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
-
+
-
+
-
+
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
@@ -947,11 +947,11 @@
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
@@ -969,13 +969,13 @@
- 7.0.11
+ 7.0.12
- 7.0.11
+ 7.0.12
-
+
\ No newline at end of file
diff --git a/eng/Baseline.xml b/eng/Baseline.xml
index d8aca8cbfd5b..55daaf5598e6 100644
--- a/eng/Baseline.xml
+++ b/eng/Baseline.xml
@@ -4,109 +4,109 @@ This file contains a list of all the packages and their versions which were rele
Update this list when preparing for a new patch.
-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index e338eb9b5222..5f8c001cb17d 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -9,37 +9,37 @@
-->
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 8133d0c827462d8d84e47b70f294fc060a5d7a84
+ c20ecc79b7df3657e186ac52e7fc050beea36c92
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 8133d0c827462d8d84e47b70f294fc060a5d7a84
+ c20ecc79b7df3657e186ac52e7fc050beea36c92
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 8133d0c827462d8d84e47b70f294fc060a5d7a84
+ c20ecc79b7df3657e186ac52e7fc050beea36c92
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 8133d0c827462d8d84e47b70f294fc060a5d7a84
+ c20ecc79b7df3657e186ac52e7fc050beea36c92
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 8133d0c827462d8d84e47b70f294fc060a5d7a84
+ c20ecc79b7df3657e186ac52e7fc050beea36c92
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 8133d0c827462d8d84e47b70f294fc060a5d7a84
+ c20ecc79b7df3657e186ac52e7fc050beea36c92
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 8133d0c827462d8d84e47b70f294fc060a5d7a84
+ c20ecc79b7df3657e186ac52e7fc050beea36c92
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 8133d0c827462d8d84e47b70f294fc060a5d7a84
+ c20ecc79b7df3657e186ac52e7fc050beea36c92
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -177,9 +177,9 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
d099f075e45d2aa6007a22b71b45a08758559f80
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- ecb34f85ec92e1b3c814edf7da83337e199e7f66
+ 4a824ef37caa51072221584c64cbf15455f406ca
https://github.com/dotnet/source-build-externals
@@ -256,39 +256,39 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- ecb34f85ec92e1b3c814edf7da83337e199e7f66
+ 4a824ef37caa51072221584c64cbf15455f406ca
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
d099f075e45d2aa6007a22b71b45a08758559f80
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- ecb34f85ec92e1b3c814edf7da83337e199e7f66
+ 4a824ef37caa51072221584c64cbf15455f406ca
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- ecb34f85ec92e1b3c814edf7da83337e199e7f66
+ 4a824ef37caa51072221584c64cbf15455f406ca
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- ecb34f85ec92e1b3c814edf7da83337e199e7f66
+ 4a824ef37caa51072221584c64cbf15455f406ca
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- ecb34f85ec92e1b3c814edf7da83337e199e7f66
+ 4a824ef37caa51072221584c64cbf15455f406ca
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- ecb34f85ec92e1b3c814edf7da83337e199e7f66
+ 4a824ef37caa51072221584c64cbf15455f406ca
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- ecb34f85ec92e1b3c814edf7da83337e199e7f66
+ 4a824ef37caa51072221584c64cbf15455f406ca
https://github.com/dotnet/xdt
diff --git a/eng/Versions.props b/eng/Versions.props
index 479a00946d11..71b2fd1ecc49 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -63,12 +63,12 @@
7.0.0
- 7.0.11
- 7.0.11
- 7.0.11
- 7.0.11
- 7.0.11
- 7.0.11-servicing.23424.27
+ 7.0.12
+ 7.0.12
+ 7.0.12
+ 7.0.12
+ 7.0.12
+ 7.0.12-servicing.23477.20
7.0.0
7.0.0
7.0.0
@@ -103,7 +103,7 @@
7.0.0
7.0.1
7.0.0
- 7.0.11-servicing.23424.27
+ 7.0.12-servicing.23477.20
7.0.0
7.0.2
7.0.0
@@ -125,14 +125,14 @@
7.0.4
- 7.0.11
- 7.0.11
- 7.0.11
- 7.0.11
- 7.0.11
- 7.0.11
- 7.0.11
- 7.0.11
+ 7.0.12
+ 7.0.12
+ 7.0.12
+ 7.0.12
+ 7.0.12
+ 7.0.12
+ 7.0.12
+ 7.0.12
7.0.0-beta.23408.3
7.0.0-beta.23408.3
diff --git a/global.json b/global.json
index 9b84a08b6da7..35bdef13e2f2 100644
--- a/global.json
+++ b/global.json
@@ -1,9 +1,9 @@
{
"sdk": {
- "version": "7.0.111"
+ "version": "7.0.112"
},
"tools": {
- "dotnet": "7.0.111",
+ "dotnet": "7.0.112",
"runtimes": {
"dotnet/x86": [
"$(MicrosoftNETCoreBrowserDebugHostTransportVersion)"
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs
index 10c2766507e0..2a12db907c7b 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs
@@ -46,6 +46,31 @@ internal sealed partial class Http2Connection : IHttp2StreamLifetimeHandler, IHt
private const int MaxStreamPoolSize = 100;
private const long StreamPoolExpiryTicks = TimeSpan.TicksPerSecond * 5;
+ private const string MaximumEnhanceYourCalmCountProperty = "Microsoft.AspNetCore.Server.Kestrel.Http2.MaxEnhanceYourCalmCount";
+
+ private static readonly int _enhanceYourCalmMaximumCount = GetMaximumEnhanceYourCalmCount();
+
+ private static int GetMaximumEnhanceYourCalmCount()
+ {
+ var data = AppContext.GetData(MaximumEnhanceYourCalmCountProperty);
+ if (data is int count)
+ {
+ return count;
+ }
+ if (data is string countStr && int.TryParse(countStr, out var parsed))
+ {
+ return parsed;
+ }
+
+ return 20; // Empirically derived
+ }
+
+ // Accumulate _enhanceYourCalmCount over the course of EnhanceYourCalmTickWindowCount ticks.
+ // This should make bursts less likely to trigger disconnects.
+ private const int EnhanceYourCalmTickWindowCount = 5;
+
+ private static bool IsEnhanceYourCalmEnabled => _enhanceYourCalmMaximumCount > 0;
+
private readonly HttpConnectionContext _context;
private readonly Http2FrameWriter _frameWriter;
private readonly Pipe _input;
@@ -74,6 +99,9 @@ internal sealed partial class Http2Connection : IHttp2StreamLifetimeHandler, IHt
private int _clientActiveStreamCount;
private int _serverActiveStreamCount;
+ private int _enhanceYourCalmCount;
+ private int _tickCount;
+
// The following are the only fields that can be modified outside of the ProcessRequestsAsync loop.
private readonly ConcurrentQueue _completedStreams = new ConcurrentQueue();
private readonly StreamCloseAwaitable _streamCompletionAwaitable = new StreamCloseAwaitable();
@@ -361,13 +389,20 @@ public async Task ProcessRequestsAsync(IHttpApplication appl
stream.Abort(new IOException(CoreStrings.Http2StreamAborted, connectionError));
}
- // Use the server _serverActiveStreamCount to drain all requests on the server side.
- // Can't use _clientActiveStreamCount now as we now decrement that count earlier/
- // Can't use _streams.Count as we wait for RST/END_STREAM before removing the stream from the dictionary
- while (_serverActiveStreamCount > 0)
+ // For some reason, this loop doesn't terminate when we're trying to abort.
+ // Since we're making a narrow fix for a patch, we'll bypass it in such scenarios.
+ // TODO: This is probably a bug - something in here should probably detect aborted
+ // connections and short-circuit.
+ if (!IsEnhanceYourCalmEnabled || error is not Http2ConnectionErrorException)
{
- await _streamCompletionAwaitable;
- UpdateCompletedStreams();
+ // Use the server _serverActiveStreamCount to drain all requests on the server side.
+ // Can't use _clientActiveStreamCount now as we now decrement that count earlier/
+ // Can't use _streams.Count as we wait for RST/END_STREAM before removing the stream from the dictionary
+ while (_serverActiveStreamCount > 0)
+ {
+ await _streamCompletionAwaitable;
+ UpdateCompletedStreams();
+ }
}
while (StreamPool.TryPop(out var pooledStream))
@@ -1170,6 +1205,20 @@ private void StartStream()
// Server is getting hit hard with connection resets.
// Tell client to calm down.
// TODO consider making when to send ENHANCE_YOUR_CALM configurable?
+
+ if (IsEnhanceYourCalmEnabled && Interlocked.Increment(ref _enhanceYourCalmCount) > EnhanceYourCalmTickWindowCount * _enhanceYourCalmMaximumCount)
+ {
+ Log.Http2TooManyEnhanceYourCalms(_context.ConnectionId, _enhanceYourCalmMaximumCount);
+
+ // Now that we've logged a useful message, we can put vague text in the exception
+ // messages in case they somehow make it back to the client (not expected)
+
+ // This will close the socket - we want to do that right away
+ Abort(new ConnectionAbortedException(CoreStrings.Http2ConnectionFaulted));
+ // Throwing an exception as well will help us clean up on our end more quickly by (e.g.) skipping processing of already-buffered input
+ throw new Http2ConnectionErrorException(CoreStrings.Http2ConnectionFaulted, Http2ErrorCode.ENHANCE_YOUR_CALM);
+ }
+
throw new Http2StreamErrorException(_currentHeadersStream.StreamId, CoreStrings.Http2TellClientToCalmDown, Http2ErrorCode.ENHANCE_YOUR_CALM);
}
}
@@ -1241,6 +1290,12 @@ private void AbortStream(int streamId, IOException error)
void IRequestProcessor.Tick(DateTimeOffset now)
{
Input.CancelPendingRead();
+ // We count EYCs over a window of a given length to avoid flagging short-lived bursts.
+ // At the end of each window, reset the count.
+ if (IsEnhanceYourCalmEnabled && ++_tickCount % EnhanceYourCalmTickWindowCount == 0)
+ {
+ Interlocked.Exchange(ref _enhanceYourCalmCount, 0);
+ }
}
void IHttp2StreamLifetimeHandler.OnStreamCompleted(Http2Stream stream)
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs
index e8fca0c394b3..f90f728a34fe 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs
@@ -20,6 +20,31 @@ internal sealed class Http2FrameWriter
// This uses C# compiler's ability to refer to static data directly. For more information see https://vcsjones.dev/2019/02/01/csharp-readonly-span-bytes-static
private static ReadOnlySpan ContinueBytes => new byte[] { 0x08, 0x03, (byte)'1', (byte)'0', (byte)'0' };
+ private const string MaximumFlowControlQueueSizeProperty = "Microsoft.AspNetCore.Server.Kestrel.Http2.MaxConnectionFlowControlQueueSize";
+
+ private static readonly int? ConfiguredMaximumFlowControlQueueSize = GetConfiguredMaximumFlowControlQueueSize();
+
+ private static int? GetConfiguredMaximumFlowControlQueueSize()
+ {
+ var data = AppContext.GetData(MaximumFlowControlQueueSizeProperty);
+
+ if (data is int count)
+ {
+ return count;
+ }
+
+ if (data is string countStr && int.TryParse(countStr, out var parsed))
+ {
+ return parsed;
+ }
+
+ return null;
+ }
+
+ private readonly int _maximumFlowControlQueueSize;
+
+ private bool IsMaximumFlowControlQueueSizeEnabled => _maximumFlowControlQueueSize > 0;
+
private readonly object _writeLock = new object();
private readonly Http2Frame _outgoingFrame;
private readonly Http2HeadersEnumerator _headersEnumerator = new Http2HeadersEnumerator();
@@ -79,6 +104,16 @@ public Http2FrameWriter(
_hpackEncoder = new DynamicHPackEncoder(serviceContext.ServerOptions.AllowResponseHeaderCompression);
+ _maximumFlowControlQueueSize = ConfiguredMaximumFlowControlQueueSize is null
+ ? 4 * maxStreamsPerConnection // 4 is a magic number to give us some padding above the expected maximum size
+ : (int)ConfiguredMaximumFlowControlQueueSize;
+
+ if (IsMaximumFlowControlQueueSizeEnabled && _maximumFlowControlQueueSize < maxStreamsPerConnection)
+ {
+ _log.Http2FlowControlQueueMaximumTooLow(_connectionContext.ConnectionId, maxStreamsPerConnection, _maximumFlowControlQueueSize);
+ _maximumFlowControlQueueSize = maxStreamsPerConnection;
+ }
+
// This is bounded by the maximum number of concurrent Http2Streams per Http2Connection.
// This isn't the same as SETTINGS_MAX_CONCURRENT_STREAMS, but typically double (with a floor of 100)
// which is the max number of Http2Streams that can end up in the Http2Connection._streams dictionary.
@@ -101,7 +136,8 @@ public void Schedule(Http2OutputProducer producer)
{
if (!_channel.Writer.TryWrite(producer))
{
- // It should not be possible to exceed the bound of the channel.
+ // This can happen if a client resets streams faster than we can clear them out - we end up with a backlog
+ // exceeding the channel size. Disconnecting seems appropriate in this case.
var ex = new ConnectionAbortedException("HTTP/2 connection exceeded the output operations maximum queue size.");
_log.Http2QueueOperationsExceeded(_connectionId, ex);
_http2Connection.Abort(ex);
@@ -304,7 +340,7 @@ private bool TryQueueProducerForConnectionWindowUpdate(long actual, Http2OutputP
}
else
{
- _waitingForMoreConnectionWindow.Enqueue(producer);
+ EnqueueWaitingForMoreConnectionWindow(producer);
}
return true;
@@ -898,7 +934,7 @@ private void AbortConnectionFlowControl()
_lastWindowConsumer = null;
// Put the consumer of the connection window last
- _waitingForMoreConnectionWindow.Enqueue(producer);
+ EnqueueWaitingForMoreConnectionWindow(producer);
}
while (_waitingForMoreConnectionWindow.TryDequeue(out producer))
@@ -927,7 +963,7 @@ public bool TryUpdateConnectionWindow(int bytes)
_lastWindowConsumer = null;
// Put the consumer of the connection window last
- _waitingForMoreConnectionWindow.Enqueue(producer);
+ EnqueueWaitingForMoreConnectionWindow(producer);
}
while (_waitingForMoreConnectionWindow.TryDequeue(out producer))
@@ -937,4 +973,16 @@ public bool TryUpdateConnectionWindow(int bytes)
}
return true;
}
+
+ private void EnqueueWaitingForMoreConnectionWindow(Http2OutputProducer producer)
+ {
+ _waitingForMoreConnectionWindow.Enqueue(producer);
+ // This is re-entrant because abort will cause a final enqueue.
+ // Easier to check for that condition than to make each enqueuer reason about what to call.
+ if (!_aborted && IsMaximumFlowControlQueueSizeEnabled && _waitingForMoreConnectionWindow.Count > _maximumFlowControlQueueSize)
+ {
+ _log.Http2FlowControlQueueOperationsExceeded(_connectionId, _maximumFlowControlQueueSize);
+ _http2Connection.Abort(new ConnectionAbortedException("HTTP/2 connection exceeded the outgoing flow control maximum queue size."));
+ }
+ }
}
diff --git a/src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelTrace.Http2.cs b/src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelTrace.Http2.cs
index 84a7609f0710..c9c3c9f55b83 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelTrace.Http2.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelTrace.Http2.cs
@@ -85,6 +85,21 @@ public void Http2UnexpectedConnectionQueueError(string connectionId, Exception e
Http2Log.Http2UnexpectedConnectionQueueError(_http2Logger, connectionId, ex);
}
+ public void Http2TooManyEnhanceYourCalms(string connectionId, int count)
+ {
+ Http2Log.Http2TooManyEnhanceYourCalms(_http2Logger, connectionId, count);
+ }
+
+ public void Http2FlowControlQueueOperationsExceeded(string connectionId, int count)
+ {
+ Http2Log.Http2FlowControlQueueOperationsExceeded(_http2Logger, connectionId, count);
+ }
+
+ public void Http2FlowControlQueueMaximumTooLow(string connectionId, int expected, int actual)
+ {
+ Http2Log.Http2FlowControlQueueMaximumTooLow(_http2Logger, connectionId, expected, actual);
+ }
+
private static partial class Http2Log
{
[LoggerMessage(29, LogLevel.Debug, @"Connection id ""{ConnectionId}"": HTTP/2 connection error.", EventName = "Http2ConnectionError")]
@@ -130,5 +145,14 @@ private static partial class Http2Log
public static partial void Http2UnexpectedConnectionQueueError(ILogger logger, string connectionId, Exception ex);
// Highest shared ID is 63. New consecutive IDs start at 64
+
+ [LoggerMessage(64, LogLevel.Debug, @"Connection id ""{ConnectionId}"" aborted since at least {Count} ENHANCE_YOUR_CALM responses were recorded per second.", EventName = "Http2TooManyEnhanceYourCalms")]
+ public static partial void Http2TooManyEnhanceYourCalms(ILogger logger, string connectionId, int count);
+
+ [LoggerMessage(65, LogLevel.Debug, @"Connection id ""{ConnectionId}"" exceeded the output flow control maximum queue size of {Count}.", EventName = "Http2FlowControlQueueOperationsExceeded")]
+ public static partial void Http2FlowControlQueueOperationsExceeded(ILogger logger, string connectionId, int count);
+
+ [LoggerMessage(66, LogLevel.Debug, @"Connection id ""{ConnectionId}"" configured maximum flow control queue size {Actual} is less than the maximum streams per connection {Expected}. Increasing configured value to {Expected}.", EventName = "Http2FlowControlQueueMaximumTooLow")]
+ public static partial void Http2FlowControlQueueMaximumTooLow(ILogger logger, string connectionId, int expected, int actual);
}
}
diff --git a/src/Servers/Kestrel/samples/Http2SampleApp/Http2SampleApp.csproj b/src/Servers/Kestrel/samples/Http2SampleApp/Http2SampleApp.csproj
index cc404533ad8f..d0930e69fee0 100644
--- a/src/Servers/Kestrel/samples/Http2SampleApp/Http2SampleApp.csproj
+++ b/src/Servers/Kestrel/samples/Http2SampleApp/Http2SampleApp.csproj
@@ -1,4 +1,4 @@
-
+
$(DefaultNetCoreTargetFramework)
diff --git a/src/submodules/googletest b/src/submodules/googletest
index e47544ad31cb..7e33b6a1c497 160000
--- a/src/submodules/googletest
+++ b/src/submodules/googletest
@@ -1 +1 @@
-Subproject commit e47544ad31cb3ceecd04cc13e8fe556f8df9fe0b
+Subproject commit 7e33b6a1c497ced1e98fc60175aeb4678419281c