aspnetcore/test/WebSites/InProcessWebSite/Startup.cs

700 lines
25 KiB
C#

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.IISIntegration.FunctionalTests;
using Microsoft.AspNetCore.Server.IIS;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;
using Xunit;
namespace TestSite
{
public partial class Startup
{
public void Configure(IApplicationBuilder app)
{
TestStartup.Register(app, this);
}
private async Task ServerVariable(HttpContext ctx)
{
var varName = ctx.Request.Query["q"];
var newValue = ctx.Request.Query["v"];
var feature = ctx.Features.Get<IServerVariablesFeature>();
if (newValue.Count != 0)
{
feature[varName] = newValue;
}
await ctx.Response.WriteAsync($"{varName}: {feature[varName] ?? "(null)"}");
}
private async Task AuthenticationAnonymous(HttpContext ctx)
{
await ctx.Response.WriteAsync("Anonymous?" + !ctx.User.Identity.IsAuthenticated);
}
private async Task AuthenticationRestricted(HttpContext ctx)
{
if (ctx.User.Identity.IsAuthenticated)
{
await ctx.Response.WriteAsync(ctx.User.Identity.AuthenticationType);
}
else
{
await ctx.ChallengeAsync(IISServerDefaults.AuthenticationScheme);
}
}
private async Task AuthenticationForbidden(HttpContext ctx)
{
await ctx.ForbidAsync(IISServerDefaults.AuthenticationScheme);
}
private async Task AuthenticationRestrictedNTLM(HttpContext ctx)
{
if (string.Equals("NTLM", ctx.User.Identity.AuthenticationType, StringComparison.Ordinal))
{
await ctx.Response.WriteAsync("NTLM");
}
else
{
await ctx.ChallengeAsync(IISServerDefaults.AuthenticationScheme);
}
}
private async Task FeatureCollectionSetRequestFeatures(HttpContext ctx)
{
try
{
Assert.Equal("GET", ctx.Request.Method);
ctx.Request.Method = "test";
Assert.Equal("test", ctx.Request.Method);
Assert.Equal("http", ctx.Request.Scheme);
ctx.Request.Scheme = "test";
Assert.Equal("test", ctx.Request.Scheme);
Assert.Equal("/FeatureCollectionSetRequestFeatures", ctx.Request.PathBase);
ctx.Request.PathBase = "/base";
Assert.Equal("/base", ctx.Request.PathBase);
Assert.Equal("/path", ctx.Request.Path);
ctx.Request.Path = "/path";
Assert.Equal("/path", ctx.Request.Path);
Assert.Equal("?query", ctx.Request.QueryString.Value);
ctx.Request.QueryString = QueryString.Empty;
Assert.Equal("", ctx.Request.QueryString.Value);
Assert.Equal("HTTP/1.1", ctx.Request.Protocol);
ctx.Request.Protocol = "HTTP/1.0";
Assert.Equal("HTTP/1.0", ctx.Request.Protocol);
Assert.NotNull(ctx.Request.Headers);
var headers = new HeaderDictionary();
ctx.Features.Get<IHttpRequestFeature>().Headers = headers;
Assert.Same(headers, ctx.Features.Get<IHttpRequestFeature>().Headers);
Assert.NotNull(ctx.Request.Body);
var body = new MemoryStream();
ctx.Request.Body = body;
Assert.Same(body, ctx.Request.Body);
//Assert.NotNull(ctx.Features.Get<IHttpRequestIdentifierFeature>().TraceIdentifier);
//Assert.NotEqual(CancellationToken.None, ctx.RequestAborted);
//var token = new CancellationTokenSource().Token;
//ctx.RequestAborted = token;
//Assert.Equal(token, ctx.RequestAborted);
await ctx.Response.WriteAsync("Success");
return;
}
catch (Exception exception)
{
ctx.Response.StatusCode = 500;
await ctx.Response.WriteAsync(exception.ToString());
}
await ctx.Response.WriteAsync("_Failure");
}
private async Task FeatureCollectionSetResponseFeatures(HttpContext ctx)
{
try
{
Assert.Equal(200, ctx.Response.StatusCode);
ctx.Response.StatusCode = 404;
Assert.Equal(404, ctx.Response.StatusCode);
ctx.Response.StatusCode = 200;
Assert.Null(ctx.Features.Get<IHttpResponseFeature>().ReasonPhrase);
ctx.Features.Get<IHttpResponseFeature>().ReasonPhrase = "Set Response";
Assert.Equal("Set Response", ctx.Features.Get<IHttpResponseFeature>().ReasonPhrase);
Assert.NotNull(ctx.Response.Headers);
var headers = new HeaderDictionary();
ctx.Features.Get<IHttpResponseFeature>().Headers = headers;
Assert.Same(headers, ctx.Features.Get<IHttpResponseFeature>().Headers);
var originalBody = ctx.Response.Body;
Assert.NotNull(originalBody);
var body = new MemoryStream();
ctx.Response.Body = body;
Assert.Same(body, ctx.Response.Body);
ctx.Response.Body = originalBody;
await ctx.Response.WriteAsync("Success");
return;
}
catch (Exception exception)
{
ctx.Response.StatusCode = 500;
await ctx.Response.WriteAsync(exception.ToString());
}
await ctx.Response.WriteAsync("_Failure");
}
private async Task FeatureCollectionSetConnectionFeatures(HttpContext ctx)
{
try
{
Assert.True(IPAddress.IsLoopback(ctx.Connection.LocalIpAddress));
ctx.Connection.LocalIpAddress = IPAddress.IPv6Any;
Assert.Equal(IPAddress.IPv6Any, ctx.Connection.LocalIpAddress);
Assert.True(IPAddress.IsLoopback(ctx.Connection.RemoteIpAddress));
ctx.Connection.RemoteIpAddress = IPAddress.IPv6Any;
Assert.Equal(IPAddress.IPv6Any, ctx.Connection.RemoteIpAddress);
await ctx.Response.WriteAsync("Success");
return;
}
catch (Exception exception)
{
ctx.Response.StatusCode = 500;
await ctx.Response.WriteAsync(exception.ToString());
}
await ctx.Response.WriteAsync("_Failure");
}
private void Throw(HttpContext ctx)
{
throw new Exception();
}
private async Task SetCustomErorCode(HttpContext ctx)
{
var feature = ctx.Features.Get<IHttpResponseFeature>();
feature.ReasonPhrase = ctx.Request.Query["reason"];
feature.StatusCode = int.Parse(ctx.Request.Query["code"]);
if (ctx.Request.Query["writeBody"] == "True")
{
await ctx.Response.WriteAsync(ctx.Request.Query["body"]);
}
}
private async Task HelloWorld(HttpContext ctx)
{
if (ctx.Request.Path.Value.StartsWith("/Path"))
{
await ctx.Response.WriteAsync(ctx.Request.Path.Value);
return;
}
if (ctx.Request.Path.Value.StartsWith("/Query"))
{
await ctx.Response.WriteAsync(ctx.Request.QueryString.Value);
return;
}
await ctx.Response.WriteAsync("Hello World");
}
private async Task LargeResponseBody(HttpContext ctx)
{
if (int.TryParse(ctx.Request.Query["length"], out var length))
{
await ctx.Response.WriteAsync(new string('a', length));
}
}
private async Task ResponseHeaders(HttpContext ctx)
{
ctx.Response.Headers["UnknownHeader"] = "test123=foo";
ctx.Response.ContentType = "text/plain";
ctx.Response.Headers["MultiHeader"] = new StringValues(new string[] { "1", "2" });
await ctx.Response.WriteAsync("Request Complete");
}
private async Task ResponseInvalidOrdering(HttpContext ctx)
{
if (ctx.Request.Path.Equals("/SetStatusCodeAfterWrite"))
{
await ctx.Response.WriteAsync("Started_");
try
{
ctx.Response.StatusCode = 200;
}
catch (InvalidOperationException)
{
await ctx.Response.WriteAsync("SetStatusCodeAfterWriteThrew_");
}
await ctx.Response.WriteAsync("Finished");
return;
}
else if (ctx.Request.Path.Equals("/SetHeaderAfterWrite"))
{
await ctx.Response.WriteAsync("Started_");
try
{
ctx.Response.Headers["This will fail"] = "some value";
}
catch (InvalidOperationException)
{
await ctx.Response.WriteAsync("SetHeaderAfterWriteThrew_");
}
await ctx.Response.WriteAsync("Finished");
return;
}
}
private async Task CheckEnvironmentVariable(HttpContext ctx)
{
var variable = Environment.GetEnvironmentVariable("ASPNETCORE_INPROCESS_TESTING_VALUE");
await ctx.Response.WriteAsync(variable);
}
private async Task CheckEnvironmentLongValueVariable(HttpContext ctx)
{
var variable = Environment.GetEnvironmentVariable("ASPNETCORE_INPROCESS_TESTING_LONG_VALUE");
await ctx.Response.WriteAsync(variable);
}
private async Task CheckAppendedEnvironmentVariable(HttpContext ctx)
{
var variable = Environment.GetEnvironmentVariable("ProgramFiles");
await ctx.Response.WriteAsync(variable);
}
private async Task CheckRemoveAuthEnvironmentVariable(HttpContext ctx)
{
var variable = Environment.GetEnvironmentVariable("ASPNETCORE_IIS_HTTPAUTH");
await ctx.Response.WriteAsync(variable);
}
private async Task ReadAndWriteSynchronously(HttpContext ctx)
{
var t2 = Task.Run(() => WriteManyTimesToResponseBody(ctx));
var t1 = Task.Run(() => ReadRequestBody(ctx));
await Task.WhenAll(t1, t2);
}
private async Task ReadRequestBody(HttpContext ctx)
{
var readBuffer = new byte[1];
var result = await ctx.Request.Body.ReadAsync(readBuffer, 0, 1);
while (result != 0)
{
result = await ctx.Request.Body.ReadAsync(readBuffer, 0, 1);
}
}
private async Task WriteManyTimesToResponseBody(HttpContext ctx)
{
for (var i = 0; i < 10000; i++)
{
await ctx.Response.WriteAsync("hello world");
}
}
private async Task ReadAndWriteEcho(HttpContext ctx)
{
var readBuffer = new byte[4096];
var result = await ctx.Request.Body.ReadAsync(readBuffer, 0, readBuffer.Length);
while (result != 0)
{
await ctx.Response.WriteAsync(Encoding.UTF8.GetString(readBuffer, 0, result));
result = await ctx.Request.Body.ReadAsync(readBuffer, 0, readBuffer.Length);
}
}
private async Task ReadAndFlushEcho(HttpContext ctx)
{
var readBuffer = new byte[4096];
var result = await ctx.Request.Body.ReadAsync(readBuffer, 0, readBuffer.Length);
while (result != 0)
{
await ctx.Response.WriteAsync(Encoding.UTF8.GetString(readBuffer, 0, result));
await ctx.Response.Body.FlushAsync();
result = await ctx.Request.Body.ReadAsync(readBuffer, 0, readBuffer.Length);
}
}
private async Task ReadAndWriteEchoLines(HttpContext ctx)
{
if (ctx.Request.Headers.TryGetValue("Response-Content-Type", out var contentType))
{
ctx.Response.ContentType = contentType;
}
//Send headers
await ctx.Response.Body.FlushAsync();
var reader = new StreamReader(ctx.Request.Body);
while (!reader.EndOfStream)
{
var line = await reader.ReadLineAsync();
if (line == "")
{
return;
}
await ctx.Response.WriteAsync(line + Environment.NewLine);
await ctx.Response.Body.FlushAsync();
}
}
private async Task ReadAndWriteEchoLinesNoBuffering(HttpContext ctx)
{
var feature = ctx.Features.Get<IHttpBufferingFeature>();
feature.DisableResponseBuffering();
if (ctx.Request.Headers.TryGetValue("Response-Content-Type", out var contentType))
{
ctx.Response.ContentType = contentType;
}
//Send headers
await ctx.Response.Body.FlushAsync();
var reader = new StreamReader(ctx.Request.Body);
while (!reader.EndOfStream)
{
var line = await reader.ReadLineAsync();
if (line == "")
{
return;
}
await ctx.Response.WriteAsync(line + Environment.NewLine);
}
}
private async Task ReadPartialBody(HttpContext ctx)
{
var data = new byte[5];
var count = 0;
do
{
count += await ctx.Request.Body.ReadAsync(data, count, data.Length - count);
} while (count != data.Length);
await ctx.Response.Body.WriteAsync(data, 0, data.Length);
}
private async Task SetHeaderFromBody(HttpContext ctx)
{
using (var reader = new StreamReader(ctx.Request.Body))
{
var value = await reader.ReadToEndAsync();
ctx.Response.Headers["BodyAsString"] = value;
await ctx.Response.WriteAsync(value);
}
}
private async Task ReadAndWriteEchoTwice(HttpContext ctx)
{
var readBuffer = new byte[4096];
var result = await ctx.Request.Body.ReadAsync(readBuffer, 0, readBuffer.Length);
while (result != 0)
{
await ctx.Response.WriteAsync(Encoding.UTF8.GetString(readBuffer, 0, result));
await ctx.Response.Body.FlushAsync();
await ctx.Response.WriteAsync(Encoding.UTF8.GetString(readBuffer, 0, result));
await ctx.Response.Body.FlushAsync();
result = await ctx.Request.Body.ReadAsync(readBuffer, 0, readBuffer.Length);
}
}
private async Task ReadAndWriteSlowConnection(HttpContext ctx)
{
var t2 = Task.Run(() => WriteResponseBodyAFewTimes(ctx));
var t1 = Task.Run(() => ReadRequestBody(ctx));
await Task.WhenAll(t1, t2);
}
private async Task WriteResponseBodyAFewTimes(HttpContext ctx)
{
for (var i = 0; i < 100; i++)
{
await ctx.Response.WriteAsync("hello world");
}
}
private async Task ReadAndWriteCopyToAsync(HttpContext ctx)
{
await ctx.Request.Body.CopyToAsync(ctx.Response.Body);
}
private async Task UpgradeFeatureDetection(HttpContext ctx)
{
if (ctx.Features.Get<IHttpUpgradeFeature>() != null)
{
await ctx.Response.WriteAsync("Enabled");
}
else
{
await ctx.Response.WriteAsync("Disabled");
}
}
private async Task TestReadOffsetWorks(HttpContext ctx)
{
var buffer = new byte[11];
ctx.Request.Body.Read(buffer, 0, 6);
ctx.Request.Body.Read(buffer, 6, 5);
await ctx.Response.WriteAsync(Encoding.UTF8.GetString(buffer));
}
private async Task TestInvalidReadOperations(HttpContext ctx)
{
var success = false;
if (ctx.Request.Path.StartsWithSegments("/NullBuffer"))
{
try
{
await ctx.Request.Body.ReadAsync(null, 0, 0);
}
catch (Exception)
{
success = true;
}
}
else if (ctx.Request.Path.StartsWithSegments("/InvalidOffsetSmall"))
{
try
{
await ctx.Request.Body.ReadAsync(new byte[1], -1, 0);
}
catch (ArgumentOutOfRangeException)
{
success = true;
}
}
else if (ctx.Request.Path.StartsWithSegments("/InvalidOffsetLarge"))
{
try
{
await ctx.Request.Body.ReadAsync(new byte[1], 2, 0);
}
catch (ArgumentOutOfRangeException)
{
success = true;
}
}
else if (ctx.Request.Path.StartsWithSegments("/InvalidCountSmall"))
{
try
{
await ctx.Request.Body.ReadAsync(new byte[1], 0, -1);
}
catch (ArgumentOutOfRangeException)
{
success = true;
}
}
else if (ctx.Request.Path.StartsWithSegments("/InvalidCountLarge"))
{
try
{
await ctx.Request.Body.ReadAsync(new byte[1], 0, -1);
}
catch (ArgumentOutOfRangeException)
{
success = true;
}
}
else if (ctx.Request.Path.StartsWithSegments("/InvalidCountWithOffset"))
{
try
{
await ctx.Request.Body.ReadAsync(new byte[3], 1, 3);
}
catch (ArgumentOutOfRangeException)
{
success = true;
}
}
await ctx.Response.WriteAsync(success ? "Success" : "Failure");
}
private async Task TestValidReadOperations(HttpContext ctx)
{
var count = -1;
if (ctx.Request.Path.StartsWithSegments("/NullBuffer"))
{
count = await ctx.Request.Body.ReadAsync(null, 0, 0);
}
else if (ctx.Request.Path.StartsWithSegments("/NullBufferPost"))
{
count = await ctx.Request.Body.ReadAsync(null, 0, 0);
}
else if (ctx.Request.Path.StartsWithSegments("/InvalidCountZeroRead"))
{
count = await ctx.Request.Body.ReadAsync(new byte[1], 0, 0);
}
else if (ctx.Request.Path.StartsWithSegments("/InvalidCountZeroReadPost"))
{
count = await ctx.Request.Body.ReadAsync(new byte[1], 0, 0);
}
await ctx.Response.WriteAsync(count == 0 ? "Success" : "Failure");
}
private async Task TestInvalidWriteOperations(HttpContext ctx)
{
var success = false;
if (ctx.Request.Path.StartsWithSegments("/InvalidOffsetSmall"))
{
try
{
await ctx.Response.Body.WriteAsync(new byte[1], -1, 0);
}
catch (ArgumentOutOfRangeException)
{
success = true;
}
}
else if (ctx.Request.Path.StartsWithSegments("/InvalidOffsetLarge"))
{
try
{
await ctx.Response.Body.WriteAsync(new byte[1], 2, 0);
}
catch (ArgumentOutOfRangeException)
{
success = true;
}
}
else if (ctx.Request.Path.StartsWithSegments("/InvalidCountSmall"))
{
try
{
await ctx.Response.Body.WriteAsync(new byte[1], 0, -1);
}
catch (ArgumentOutOfRangeException)
{
success = true;
}
}
else if (ctx.Request.Path.StartsWithSegments("/InvalidCountLarge"))
{
try
{
await ctx.Response.Body.WriteAsync(new byte[1], 0, -1);
}
catch (ArgumentOutOfRangeException)
{
success = true;
}
}
else if (ctx.Request.Path.StartsWithSegments("/InvalidCountWithOffset"))
{
try
{
await ctx.Response.Body.WriteAsync(new byte[3], 1, 3);
}
catch (ArgumentOutOfRangeException)
{
success = true;
}
}
await ctx.Response.WriteAsync(success ? "Success" : "Failure");
}
private async Task TestValidWriteOperations(HttpContext ctx)
{
if (ctx.Request.Path.StartsWithSegments("/NullBuffer"))
{
await ctx.Response.Body.WriteAsync(null, 0, 0);
}
else if (ctx.Request.Path.StartsWithSegments("/NullBufferPost"))
{
await ctx.Response.Body.WriteAsync(null, 0, 0);
}
await ctx.Response.WriteAsync("Success");
}
private async Task LargeResponseFile(HttpContext ctx)
{
var tempFile = Path.GetTempFileName();
var fileContent = new string('a', 200000);
var fileStream = File.OpenWrite(tempFile);
for (var i = 0; i < 1000; i++)
{
await fileStream.WriteAsync(Encoding.UTF8.GetBytes(fileContent), 0, fileContent.Length);
}
fileStream.Close();
await ctx.Response.SendFileAsync(tempFile, 0, null);
// Try to delete the file from the temp directory. If it fails, don't report an error
// to the application. File should eventually be cleaned up from the temp directory
// by OS.
try
{
File.Delete(tempFile);
}
catch (Exception)
{
}
}
private async Task BasePath(HttpContext ctx)
{
await ctx.Response.WriteAsync(AppDomain.CurrentDomain.BaseDirectory);
}
private async Task Shutdown(HttpContext ctx)
{
await ctx.Response.WriteAsync("Shutting down");
ctx.RequestServices.GetService<IApplicationLifetime>().StopApplication();
}
private async Task GetServerVariableStress(HttpContext ctx)
{
// This test simulates the scenario where native Flush call is being
// executed on background thread while request thread calls GetServerVariable
// concurrent native calls may cause native object corruption
var serverVariableFeature = ctx.Features.Get<IServerVariablesFeature>();
await ctx.Response.WriteAsync("Response Begin");
for (int i = 0; i < 1000; i++)
{
await ctx.Response.WriteAsync(serverVariableFeature["REMOTE_PORT"]);
await ctx.Response.Body.FlushAsync();
}
await ctx.Response.WriteAsync("Response End");
}
private async Task CommandLineArgs(HttpContext ctx)
{
await ctx.Response.WriteAsync(string.Join("|", Environment.GetCommandLineArgs().Skip(1)));
}
public Task HttpsHelloWorld(HttpContext ctx) =>
ctx.Response.WriteAsync("Scheme:" + ctx.Request.Scheme + "; Original:" + ctx.Request.Headers["x-original-proto"]);
}
}