| File: KestrelServerLimits.cs | Web Access |
| Project: src\aspnetcore\src\Servers\Kestrel\Core\src\Microsoft.AspNetCore.Server.Kestrel.Core.csproj (Microsoft.AspNetCore.Server.Kestrel.Core) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel.Core.Features; namespace Microsoft.AspNetCore.Server.Kestrel.Core; /// <summary> /// Limits for <see cref="KestrelServer"/>. /// </summary> public class KestrelServerLimits { // Matches the non-configurable default response buffer size for Kestrel in 1.0.0 private long? _maxResponseBufferSize = 64 * 1024; // Matches the default client_max_body_size in nginx. // Also large enough that most requests should be under the limit. private long? _maxRequestBufferSize = 1024 * 1024; // Matches the default large_client_header_buffers in nginx. private int _maxRequestLineSize = 8 * 1024; // Matches the default large_client_header_buffers in nginx. private int _maxRequestHeadersTotalSize = 32 * 1024; // Matches the default maxAllowedContentLength in IIS (~28.6 MB) // https://www.iis.net/configreference/system.webserver/security/requestfiltering/requestlimits#005 private long? _maxRequestBodySize = 30000000; // Matches the default LimitRequestFields in Apache httpd. private int _maxRequestHeaderCount = 100; // Slightly more than SocketHttpHandler's old PooledConnectionIdleTimeout of 2 minutes. // https://github.com/dotnet/runtime/issues/52267 private TimeSpan _keepAliveTimeout = TimeSpan.FromSeconds(130); private TimeSpan _requestHeadersTimeout = TimeSpan.FromSeconds(30); // Unlimited connections are allowed by default. private long? _maxConcurrentConnections; private long? _maxConcurrentUpgradedConnections; /// <summary> /// Gets or sets the maximum size of the response buffer before write /// calls begin to block or return tasks that don't complete until the /// buffer size drops below the configured limit. /// Defaults to 65,536 bytes (64 KB). /// </summary> /// <remarks> /// When set to null, the size of the response buffer is unlimited. /// When set to zero, all write calls will block or return tasks that /// don't complete until the entire response buffer is flushed. /// </remarks> public long? MaxResponseBufferSize { get => _maxResponseBufferSize; set { if (value.HasValue && value.Value < 0) { throw new ArgumentOutOfRangeException(nameof(value), CoreStrings.NonNegativeNumberOrNullRequired); } _maxResponseBufferSize = value; } } /// <summary> /// Gets or sets the maximum size of the request buffer. /// Defaults to 1,048,576 bytes (1 MB). /// </summary> /// <remarks> /// When set to null, the size of the request buffer is unlimited. /// </remarks> public long? MaxRequestBufferSize { get => _maxRequestBufferSize; set { if (value.HasValue && value.Value <= 0) { throw new ArgumentOutOfRangeException(nameof(value), CoreStrings.PositiveNumberOrNullRequired); } _maxRequestBufferSize = value; } } /// <summary> /// Gets or sets the maximum allowed size for the HTTP request line. /// Defaults to 8,192 bytes (8 KB). /// </summary> /// <remarks> /// For HTTP/2 and HTTP/3 this measures the total size of the required pseudo headers /// :method, :scheme, :authority, and :path. /// </remarks> public int MaxRequestLineSize { get => _maxRequestLineSize; set { if (value <= 0) { throw new ArgumentOutOfRangeException(nameof(value), CoreStrings.PositiveNumberRequired); } _maxRequestLineSize = value; } } /// <summary> /// Gets or sets the maximum allowed size for the HTTP request headers. /// Defaults to 32,768 bytes (32 KB). /// </summary> /// <remarks> /// </remarks> public int MaxRequestHeadersTotalSize { get => _maxRequestHeadersTotalSize; set { if (value <= 0) { throw new ArgumentOutOfRangeException(nameof(value), CoreStrings.PositiveNumberRequired); } _maxRequestHeadersTotalSize = value; } } /// <summary> /// Gets or sets the maximum allowed number of headers per HTTP request. /// Defaults to 100. /// </summary> /// <remarks> /// </remarks> public int MaxRequestHeaderCount { get => _maxRequestHeaderCount; set { if (value <= 0) { throw new ArgumentOutOfRangeException(nameof(value), CoreStrings.PositiveNumberRequired); } _maxRequestHeaderCount = value; } } /// <summary> /// Gets or sets the maximum allowed size of any request body in bytes. /// When set to null, the maximum request body size is unlimited. /// This limit has no effect on upgraded connections which are always unlimited. /// This can be overridden per-request via <see cref="IHttpMaxRequestBodySizeFeature"/>. /// Defaults to 30,000,000 bytes, which is approximately 28.6MB. /// </summary> /// <remarks> /// </remarks> public long? MaxRequestBodySize { get => _maxRequestBodySize; set { if (value < 0) { throw new ArgumentOutOfRangeException(nameof(value), CoreStrings.NonNegativeNumberOrNullRequired); } _maxRequestBodySize = value; } } /// <summary> /// Gets or sets the keep-alive timeout. /// Defaults to 130 seconds. /// </summary> /// <remarks> /// </remarks> public TimeSpan KeepAliveTimeout { get => _keepAliveTimeout; set { if (value <= TimeSpan.Zero && value != Timeout.InfiniteTimeSpan) { throw new ArgumentOutOfRangeException(nameof(value), CoreStrings.PositiveTimeSpanRequired); } _keepAliveTimeout = value != Timeout.InfiniteTimeSpan ? value : TimeSpan.MaxValue; } } /// <summary> /// Gets or sets the maximum amount of time the server will spend receiving request headers. /// Defaults to 30 seconds. /// </summary> /// <remarks> /// </remarks> public TimeSpan RequestHeadersTimeout { get => _requestHeadersTimeout; set { if (value <= TimeSpan.Zero && value != Timeout.InfiniteTimeSpan) { throw new ArgumentOutOfRangeException(nameof(value), CoreStrings.PositiveTimeSpanRequired); } _requestHeadersTimeout = value != Timeout.InfiniteTimeSpan ? value : TimeSpan.MaxValue; } } /// <summary> /// Gets or sets the maximum number of open connections. When set to null, the number of connections is unlimited. /// <para> /// Defaults to null. /// </para> /// </summary> /// <remarks> /// <para> /// When a connection is upgraded to another protocol, such as WebSockets, its connection is counted against the /// <see cref="MaxConcurrentUpgradedConnections" /> limit instead of <see cref="MaxConcurrentConnections" />. /// </para> /// </remarks> public long? MaxConcurrentConnections { get => _maxConcurrentConnections; set { if (value.HasValue && value <= 0) { throw new ArgumentOutOfRangeException(nameof(value), CoreStrings.PositiveNumberOrNullRequired); } _maxConcurrentConnections = value; } } /// <summary> /// Gets or sets the maximum number of open, upgraded connections. When set to null, the number of upgraded connections is unlimited. /// An upgraded connection is one that has been switched from HTTP to another protocol, such as WebSockets. /// <para> /// Defaults to null. /// </para> /// </summary> /// <remarks> /// <para> /// When a connection is upgraded to another protocol, such as WebSockets, its connection is counted against the /// <see cref="MaxConcurrentUpgradedConnections" /> limit instead of <see cref="MaxConcurrentConnections" />. /// </para> /// </remarks> public long? MaxConcurrentUpgradedConnections { get => _maxConcurrentUpgradedConnections; set { if (value.HasValue && value < 0) { throw new ArgumentOutOfRangeException(nameof(value), CoreStrings.NonNegativeNumberOrNullRequired); } _maxConcurrentUpgradedConnections = value; } } internal void Serialize(Utf8JsonWriter writer) { writer.WriteString(nameof(KeepAliveTimeout), KeepAliveTimeout.ToString()); writer.WritePropertyName(nameof(MaxConcurrentConnections)); if (MaxConcurrentConnections is null) { writer.WriteNullValue(); } else { writer.WriteNumberValue(MaxConcurrentConnections.Value); } writer.WritePropertyName(nameof(MaxConcurrentUpgradedConnections)); if (MaxConcurrentUpgradedConnections is null) { writer.WriteNullValue(); } else { writer.WriteNumberValue(MaxConcurrentUpgradedConnections.Value); } writer.WritePropertyName(nameof(MaxRequestBodySize)); if (MaxRequestBodySize is null) { writer.WriteNullValue(); } else { writer.WriteNumberValue(MaxRequestBodySize.Value); } writer.WritePropertyName(nameof(MaxRequestBufferSize)); if (MaxRequestBufferSize is null) { writer.WriteNullValue(); } else { writer.WriteNumberValue(MaxRequestBufferSize.Value); } writer.WritePropertyName(nameof(MaxRequestHeaderCount)); writer.WriteNumberValue(MaxRequestHeaderCount); writer.WritePropertyName(nameof(MaxRequestHeadersTotalSize)); writer.WriteNumberValue(MaxRequestHeadersTotalSize); writer.WritePropertyName(nameof(MaxRequestLineSize)); writer.WriteNumberValue(MaxRequestLineSize); writer.WritePropertyName(nameof(MaxResponseBufferSize)); if (MaxResponseBufferSize is null) { writer.WriteNullValue(); } else { writer.WriteNumberValue(MaxResponseBufferSize.Value); } writer.WriteString(nameof(MinRequestBodyDataRate), MinRequestBodyDataRate?.ToString()); writer.WriteString(nameof(MinResponseDataRate), MinResponseDataRate?.ToString()); writer.WriteString(nameof(RequestHeadersTimeout), RequestHeadersTimeout.ToString()); // HTTP2 writer.WritePropertyName(nameof(Http2)); writer.WriteStartObject(); Http2.Serialize(writer); writer.WriteEndObject(); // HTTP3 writer.WritePropertyName(nameof(Http3)); writer.WriteStartObject(); Http3.Serialize(writer); writer.WriteEndObject(); } /// <summary> /// Limits only applicable to HTTP/2 connections. /// </summary> public Http2Limits Http2 { get; } = new Http2Limits(); /// <summary> /// Limits only applicable to HTTP/3 connections. /// </summary> public Http3Limits Http3 { get; } = new Http3Limits(); /// <summary> /// Gets or sets the request body minimum data rate in bytes/second. /// Setting this property to null indicates no minimum data rate should be enforced. /// This limit has no effect on upgraded connections which are always unlimited. /// This can be overridden per-request via <see cref="IHttpMinRequestBodyDataRateFeature"/>. /// Defaults to 240 bytes/second with a 5 second grace period. /// </summary> /// <remarks> /// </remarks> public MinDataRate? MinRequestBodyDataRate { get; set; } = // Matches the default IIS minBytesPerSecond new MinDataRate(bytesPerSecond: 240, gracePeriod: TimeSpan.FromSeconds(5)); /// <summary> /// Gets or sets the response minimum data rate in bytes/second. /// Setting this property to null indicates no minimum data rate should be enforced. /// This limit has no effect on upgraded connections which are always unlimited. /// This can be overridden per-request via <see cref="IHttpMinResponseDataRateFeature"/>. /// <para> /// Defaults to 240 bytes/second with a 5 second grace period. /// </para> /// </summary> /// <remarks> /// <para> /// Contrary to the request body minimum data rate, this rate applies to the response status line and headers as well. /// </para> /// <para> /// This rate is enforced per write operation instead of being averaged over the life of the response. Whenever the server /// writes a chunk of data, a timer is set to the maximum of the grace period set in this property or the length of the write in /// bytes divided by the data rate (i.e. the maximum amount of time that write should take to complete with the specified data rate). /// The connection is aborted if the write has not completed by the time that timer expires. /// </para> /// <para> /// This rate may not accurately measure how much data a client is reading. /// Data is immediately copied into operating system buffers until those are full, and the rate only applies to the application buffers. /// </para> /// </remarks> public MinDataRate? MinResponseDataRate { get; set; } = // Matches the default IIS minBytesPerSecond new MinDataRate(bytesPerSecond: 240, gracePeriod: TimeSpan.FromSeconds(5)); }