-
Notifications
You must be signed in to change notification settings - Fork 10k
/
HttpSysOptions.cs
271 lines (239 loc) · 10.7 KB
/
HttpSysOptions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Globalization;
using System.Text;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Server.HttpSys;
/// <summary>
/// Contains the options used by HttpSys.
/// </summary>
public class HttpSysOptions
{
private const uint MaximumRequestQueueNameLength = 260;
private const Http503VerbosityLevel DefaultRejectionVerbosityLevel = Http503VerbosityLevel.Basic; // Http.sys default.
private const long DefaultRequestQueueLength = 1000; // Http.sys default.
internal static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount;
// Matches the default maxAllowedContentLength in IIS (~28.6 MB)
// https://www.iis.net/configreference/system.webserver/security/requestfiltering/requestlimits#005
private const long DefaultMaxRequestBodySize = 30000000;
private Http503VerbosityLevel _rejectionVebosityLevel = DefaultRejectionVerbosityLevel;
// The native request queue
private long _requestQueueLength = DefaultRequestQueueLength;
private long? _maxConnections;
private RequestQueue? _requestQueue;
private UrlGroup? _urlGroup;
private long? _maxRequestBodySize = DefaultMaxRequestBodySize;
private string? _requestQueueName;
/// <summary>
/// Initializes a new <see cref="HttpSysOptions"/>.
/// </summary>
public HttpSysOptions()
{
}
/// <summary>
/// The name of the Http.Sys request queue
/// The default is `null` (Anonymous queue).
/// </summary>
public string? RequestQueueName
{
get => _requestQueueName;
set
{
if (value?.Length > MaximumRequestQueueNameLength)
{
throw new ArgumentOutOfRangeException(nameof(value),
value,
$"The request queue name should be fewer than {MaximumRequestQueueNameLength} characters in length");
}
_requestQueueName = value;
}
}
/// <summary>
/// This indicates whether the server is responsible for creating and configuring the request queue, or if it should attach to an existing queue.
/// Most existing configuration options do not apply when attaching to an existing queue.
/// The default is `RequestQueueMode.Create`.
/// </summary>
public RequestQueueMode RequestQueueMode { get; set; }
/// <summary>
/// Indicates how client certificates should be populated. The default is to allow a certificate without renegotiation.
/// This does not change the netsh 'clientcertnegotiation' binding option which will need to be enabled for
/// ClientCertificateMethod.AllowCertificate to resolve a certificate.
/// </summary>
public ClientCertificateMethod ClientCertificateMethod { get; set; } = ClientCertificateMethod.AllowCertificate;
/// <summary>
/// The maximum number of concurrent accepts.
/// The default is 5 times the number of processors as returned by <see cref="Environment.ProcessorCount" />.
/// </summary>
public int MaxAccepts { get; set; } = DefaultMaxAccepts;
/// <summary>
/// Attempt kernel-mode caching for responses with eligible headers.
/// The response may not include Set-Cookie, Vary, or Pragma headers.
/// It must include a Cache-Control header that's public and either a shared-max-age or max-age value, or an Expires header.
/// The default is `true`.
/// </summary>
public bool EnableResponseCaching { get; set; } = true;
/// <summary>
/// The url prefixes to register with Http.Sys. These may be modified at any time prior to disposing
/// the listener.
/// When attached to an existing queue the prefixes are only used to compute PathBase for requests.
/// </summary>
public UrlPrefixCollection UrlPrefixes { get; } = new UrlPrefixCollection();
/// <summary>
/// Http.Sys authentication settings. These may be modified at any time prior to disposing
/// the listener.
/// </summary>
public AuthenticationManager Authentication { get; } = new AuthenticationManager();
/// <summary>
/// Exposes the Http.Sys timeout configurations. These may also be configured in the registry.
/// These may be modified at any time prior to disposing the listener.
/// These settings do not apply when attaching to an existing queue.
/// </summary>
public TimeoutManager Timeouts { get; } = new TimeoutManager();
/// <summary>
/// Gets or Sets if response body writes that fail due to client disconnects should throw exceptions or
/// complete normally.
/// The default is `false` (complete normally).
/// </summary>
public bool ThrowWriteExceptions { get; set; }
/// <summary>
/// Enable buffering of response data in the Kernel. The default value is <code>false</code>.
/// It should be used by an application doing synchronous I/O or by an application doing asynchronous I/O with
/// no more than one outstanding write at a time, and can significantly improve throughput over high-latency connections.
/// Applications that use asynchronous I/O and that may have more than one send outstanding at a time should not use this flag.
/// Enabling this can results in higher CPU and memory usage by Http.Sys.
/// </summary>
public bool EnableKernelResponseBuffering { get; set; }
/// <summary>
/// Gets or sets the maximum number of concurrent connections to accept. Set `-1` for infinite.
/// Set to `null` to use the registry's machine-wide setting.
/// The default value is `null` (machine-wide setting).
/// </summary>
public long? MaxConnections
{
get => _maxConnections;
set
{
if (value.HasValue && value < -1)
{
throw new ArgumentOutOfRangeException(nameof(value), value, "The value must be positive, or -1 for infinite.");
}
if (value.HasValue && _urlGroup != null)
{
_urlGroup.SetMaxConnections(value.Value);
}
_maxConnections = value;
}
}
/// <summary>
/// Gets or sets the maximum number of requests that will be queued up in Http.Sys.
/// This settings does not apply when attaching to an existing queue.
/// The default is 1000.
/// </summary>
public long RequestQueueLimit
{
get
{
return _requestQueueLength;
}
set
{
if (value <= 0)
{
throw new ArgumentOutOfRangeException(nameof(value), value, "The value must be greater than zero.");
}
_requestQueue?.SetLengthLimit(_requestQueueLength);
// Only store it if it succeeds or hasn't started yet
_requestQueueLength = 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"/>.
/// The default is set to 30,000,000 bytes, which is approximately 28.6MB.
/// </summary>
public long? MaxRequestBodySize
{
get => _maxRequestBodySize;
set
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(nameof(value), value, "The value must be greater or equal to zero.");
}
_maxRequestBodySize = value;
}
}
/// <summary>
/// Control whether synchronous input/output is allowed for the HttpContext.Request.Body and HttpContext.Response.Body.
/// The default is `false`.
/// </summary>
public bool AllowSynchronousIO { get; set; }
/// <summary>
/// Gets or sets a value that controls how http.sys reacts when rejecting requests due to throttling conditions - like when the request
/// queue limit is reached. The default in http.sys is "Basic" which means http.sys is just resetting the TCP connection. IIS uses Limited
/// as its default behavior which will result in sending back a 503 - Service Unavailable back to the client.
/// This settings does not apply when attaching to an existing queue.
/// </summary>
public Http503VerbosityLevel Http503Verbosity
{
get
{
return _rejectionVebosityLevel;
}
set
{
if (value < Http503VerbosityLevel.Basic || value > Http503VerbosityLevel.Full)
{
string message = String.Format(
CultureInfo.InvariantCulture,
"The value must be one of the values defined in the '{0}' enum.",
typeof(Http503VerbosityLevel).Name);
throw new ArgumentOutOfRangeException(nameof(value), value, message);
}
_requestQueue?.SetRejectionVerbosity(value);
// Only store it if it succeeds or hasn't started yet
_rejectionVebosityLevel = value;
}
}
/// <summary>
/// Inline request processing instead of dispatching to the threadpool.
/// </summary>
/// <remarks>
/// Enabling this setting will run application code on the IO thread to reduce request processing latency.
/// However, this will limit parallel request processing to <see cref="MaxAccepts"/>. This setting can make
/// overall throughput worse if requests take long to process.
/// </remarks>
public bool UnsafePreferInlineScheduling { get; set; }
/// <summary>
/// Configures request headers to use <see cref="Encoding.Latin1"/> encoding.
/// </summary>
/// <remarks>
/// Defaults to `false`, in which case <see cref="Encoding.UTF8"/> will be used. />.
/// </remarks>
public bool UseLatin1RequestHeaders { get; set; }
// Not called when attaching to an existing queue.
internal void Apply(UrlGroup urlGroup, RequestQueue? requestQueue)
{
_urlGroup = urlGroup;
_requestQueue = requestQueue;
if (_maxConnections.HasValue)
{
_urlGroup.SetMaxConnections(_maxConnections.Value);
}
if (_requestQueue is not null)
{
if (_requestQueueLength != DefaultRequestQueueLength)
{
_requestQueue.SetLengthLimit(_requestQueueLength);
}
if (_rejectionVebosityLevel != DefaultRejectionVerbosityLevel)
{
_requestQueue.SetRejectionVerbosity(_rejectionVebosityLevel);
}
}
Authentication.SetUrlGroupSecurity(urlGroup);
Timeouts.SetUrlGroupTimeouts(urlGroup);
}
}