private readonly double _http2Probability;
public RequestContext(HttpClient httpClient, Random random, int taskNum,
- string contentSource, int maxRequestParameters, int maxRequestLineSize,
+ string contentSource, int maxRequestParameters, int maxRequestUriSize,
double cancellationProbability, double http2Probability)
{
_random = random;
TaskNum = taskNum;
IsCancellationRequested = false;
MaxRequestParameters = maxRequestParameters;
- MaxRequestLineSize = maxRequestLineSize;
+ MaxRequestUriSize = maxRequestUriSize;
ContentSource = contentSource;
}
public bool IsCancellationRequested { get; set; }
public string ContentSource { get; }
public int MaxRequestParameters { get; }
- public int MaxRequestLineSize { get; }
+ public int MaxRequestUriSize { get; }
public int MaxContentLength => ContentSource.Length;
// HttpClient.SendAsync() wrapper that wires randomized cancellation
{
Version httpVersion = ctx.GetRandomHttpVersion();
string uri = "/variables";
- string expectedResponse = GetGetQueryParameters(ref uri, ctx.MaxRequestLineSize, ctx, ctx.MaxRequestParameters);
+ string expectedResponse = GetGetQueryParameters(ref uri, ctx.MaxRequestUriSize, ctx, ctx.MaxRequestParameters);
using (var req = new HttpRequestMessage(HttpMethod.Get, uri) { Version = httpVersion })
using (HttpResponseMessage m = await ctx.SendAsync(req))
{
}
}
- private static string GetGetQueryParameters(ref string uri, int maxRequestLineSize, RequestContext clientContext, int numParameters)
+ private static string GetGetQueryParameters(ref string uri, int maxRequestUriSize, RequestContext clientContext, int numParameters)
{
- if (maxRequestLineSize < uri.Length)
+ if (maxRequestUriSize < uri.Length)
{
- throw new ArgumentOutOfRangeException(nameof(maxRequestLineSize));
+ throw new ArgumentOutOfRangeException(nameof(maxRequestUriSize));
}
if (numParameters <= 0)
{
var expectedString = new StringBuilder();
var uriSb = new StringBuilder(uri);
- maxRequestLineSize -= uri.Length;
+ maxRequestUriSize -= uri.Length;
- int appxMaxValueLength = Math.Max(maxRequestLineSize / numParameters, 1);
+ int appxMaxValueLength = Math.Max(maxRequestUriSize / numParameters, 1);
int num = clientContext.GetRandomInt32(1, numParameters + 1);
for (int i = 0; i < num; i++)
{
string key = $"{(i == 0 ? "?" : "&")}Var{i}=";
- int remainingLength = maxRequestLineSize - uriSb.Length - key.Length;
+ int remainingLength = maxRequestUriSize - uriSb.Length - key.Length;
if (remainingLength <= 0)
{
break;
cmd.AddOption(new Option("-serverUri", "Stress suite server uri.") { Argument = new Argument<Uri>("serverUri", new Uri("https://localhost:5001")) });
cmd.AddOption(new Option("-runMode", "Stress suite execution mode. Defaults to Both.") { Argument = new Argument<RunMode>("runMode", RunMode.both)});
cmd.AddOption(new Option("-maxContentLength", "Max content length for request and response bodies.") { Argument = new Argument<int>("numBytes", 1000) });
- cmd.AddOption(new Option("-maxRequestLineSize", "Max query string length support by the server.") { Argument = new Argument<int>("numChars", 8192) });
+ cmd.AddOption(new Option("-maxRequestUriSize", "Max query string length support by the server.") { Argument = new Argument<int>("numChars", 8000) });
cmd.AddOption(new Option("-http", "HTTP version (1.1 or 2.0)") { Argument = new Argument<Version>("version", HttpVersion.Version20) });
cmd.AddOption(new Option("-connectionLifetime", "Max connection lifetime length (milliseconds).") { Argument = new Argument<int?>("connectionLifetime", null)});
cmd.AddOption(new Option("-ops", "Indices of the operations to use") { Argument = new Argument<int[]>("space-delimited indices", null) });
httpSys : cmdline.ValueForOption<bool>("-httpSys"),
concurrentRequests : cmdline.ValueForOption<int>("-n"),
maxContentLength : cmdline.ValueForOption<int>("-maxContentLength"),
- maxRequestLineSize : cmdline.ValueForOption<int>("-maxRequestLineSize"),
+ maxRequestUriSize : cmdline.ValueForOption<int>("-maxRequestUriSize"),
httpVersion : cmdline.ValueForOption<Version>("-http"),
connectionLifetime : cmdline.ValueForOption<int?>("-connectionLifetime"),
opIndices : cmdline.ValueForOption<int[]>("-ops"),
displayIntervalSeconds : cmdline.ValueForOption<int>("-displayInterval"));
}
- private static async Task Run(RunMode runMode, Uri serverUri, bool httpSys, int concurrentRequests, int maxContentLength, int maxRequestLineSize, Version httpVersion, int? connectionLifetime, int[] opIndices, int[] excludedOpIndices, string logPath, bool aspnetLog, bool listOps, int seed, int numParameters, double cancellationProbability, int displayIntervalSeconds)
+ private static async Task Run(RunMode runMode, Uri serverUri, bool httpSys, int concurrentRequests, int maxContentLength, int maxRequestUriSize, Version httpVersion, int? connectionLifetime, int[] opIndices, int[] excludedOpIndices, string logPath, bool aspnetLog, bool listOps, int seed, int numParameters, double cancellationProbability, int displayIntervalSeconds)
{
(string name, Func<RequestContext, Task> op)[] clientOperations = ClientOperations.Operations;
{
// Start the Kestrel web server in-proc.
Console.WriteLine($"Starting {(httpSys ? "http.sys" : "Kestrel")} server.");
- var server = new StressServer(serverUri, httpSys, maxContentLength, logPath, aspnetLog);
- maxRequestLineSize = server.MaxRequestLineSize;
+ var server = new StressServer(serverUri, httpSys, maxContentLength, maxRequestUriSize, logPath, aspnetLog);
Console.WriteLine($"Server started at {server.ServerUri}");
}
concurrentRequests: concurrentRequests,
maxContentLength: maxContentLength,
maxRequestParameters: numParameters,
- maxRequestLineSize: maxRequestLineSize,
+ maxRequestUriSize: maxRequestUriSize,
randomSeed: seed,
cancellationProbability: cancellationProbability,
http2Probability: (httpVersion == new Version(2, 0)) ? 1 : 0,
// TOCONSIDER: configuration class to avoid threading so many parameters
public StressClient(Uri serverUri, (string name, Func<RequestContext, Task> operation)[] clientOperations, int concurrentRequests,
- int maxContentLength, int maxRequestParameters, int maxRequestLineSize,
+ int maxContentLength, int maxRequestParameters, int maxRequestUriSize,
int randomSeed, double cancellationProbability, double http2Probability,
int? connectionLifetime, TimeSpan displayInterval)
{
// Random instance should be shared across all requests made by same worker
Random random = CreateRandomInstance();
- return () => new RequestContext(client, random, taskNum, contentSource, maxRequestParameters, maxRequestLineSize, cancellationProbability, http2Probability);
+ return () => new RequestContext(client, random, taskNum, contentSource, maxRequestParameters, maxRequestUriSize, cancellationProbability, http2Probability);
}
async Task RunWorker(int taskNum)
private readonly IWebHost _webHost;
public Uri ServerUri { get; }
- public int MaxRequestLineSize { get; private set; } = -1;
- public StressServer(Uri serverUri, bool httpSys, int maxContentLength, string logPath, bool enableAspNetLogs)
+ public StressServer(Uri serverUri, bool httpSys, int maxContentLength, int maxRequestUriSize, string logPath, bool enableAspNetLogs)
{
ServerUri = serverUri;
IWebHostBuilder host = WebHost.CreateDefaultBuilder();
// 3. Register the cert, e.g. netsh http add sslcert ipport=[::1]:5001 certhash=THUMBPRINTFROMABOVE appid="{some-guid}"
host = host.UseHttpSys(hso =>
{
- MaxRequestLineSize = 8192;
hso.UrlPrefixes.Add(ServerUri.ToString());
hso.Authentication.Schemes = Microsoft.AspNetCore.Server.HttpSys.AuthenticationSchemes.None;
hso.Authentication.AllowAnonymous = true;
// Use Kestrel, and configure it for HTTPS with a self-signed test certificate.
host = host.UseKestrel(ko =>
{
- MaxRequestLineSize = ko.Limits.MaxRequestLineSize - 10;
+ // conservative estimation based on https://github.com/aspnet/AspNetCore/blob/caa910ceeba5f2b2c02c47a23ead0ca31caea6f0/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Stream.cs#L204
+ ko.Limits.MaxRequestLineSize = Math.Max(ko.Limits.MaxRequestLineSize, maxRequestUriSize + 100);
+
ko.ListenLocalhost(serverUri.Port, listenOptions =>
{
// Create self-signed cert for server.