Fix applicationInitialization tests and disconnect handler (#1484)

This commit is contained in:
Pavel Krymets 2018-10-10 12:41:11 -07:00 committed by GitHub
parent ac7a6b56d4
commit ab124fc344
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 94 additions and 36 deletions

View File

@ -159,9 +159,16 @@ REQUEST_NOTIFICATION_STATUS ASPNET_CORE_PROXY_MODULE::HandleNotificationStatus(R
void ASPNET_CORE_PROXY_MODULE::SetupDisconnectHandler(IHttpContext * pHttpContext)
{
auto moduleContainer = pHttpContext
->GetConnection()
->GetModuleContextContainer();
auto connection = pHttpContext
->GetConnection();
// connection might be null in when applicationInitialization is running
if (connection == nullptr)
{
return;
}
auto moduleContainer = connection->GetModuleContextContainer();
#pragma warning( push )
#pragma warning ( disable : 26466 ) // Disable "Don't use static_cast downcasts". We build without RTTI support so dynamic_cast is not available

View File

@ -120,7 +120,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
KnownMethod = VerbId;
StatusCode = 200;
var originalPath = RequestUriBuilder.DecodeAndUnescapePath(GetRawUrlInBytes());
var originalPath = GetOriginalPath();
if (KnownMethod == HttpApiTypes.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawTarget, "*", StringComparison.Ordinal))
{
@ -172,6 +172,22 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
_bodyOutput = new OutputProducer(pipe);
}
private string GetOriginalPath()
{
// applicationInitialization request might have trailing \0 character included in the length
// check and skip it
var rawUrlInBytes = GetRawUrlInBytes();
if (rawUrlInBytes.Length > 0 && rawUrlInBytes[rawUrlInBytes.Length - 1] == 0)
{
var newRawUrlInBytes = new byte[rawUrlInBytes.Length - 1];
Array.Copy(rawUrlInBytes, newRawUrlInBytes, newRawUrlInBytes.Length);
rawUrlInBytes = newRawUrlInBytes;
}
var originalPath = RequestUriBuilder.DecodeAndUnescapePath(rawUrlInBytes);
return originalPath;
}
public int StatusCode
{
get { return _statusCode; }

View File

@ -13,6 +13,7 @@ namespace Microsoft.AspNetCore.Server.IIS
internal const int HR_OK = 0;
internal const int ERROR_NOT_FOUND = unchecked((int)0x80070490);
internal const int ERROR_OPERATION_ABORTED = unchecked((int)0x800703E3);
internal const int ERROR_INVALID_PARAMETER = unchecked((int)0x80070057);
internal const int COR_E_IO = unchecked((int)0x80131620);
private const string KERNEL32 = "kernel32.dll";
@ -262,9 +263,10 @@ namespace Microsoft.AspNetCore.Server.IIS
public static bool HttpTryCancelIO(IntPtr pInProcessHandler)
{
var hr = http_cancel_io(pInProcessHandler);
// Async operation finished
// ERROR_NOT_FOUND is expected if async operation finished
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363792(v=vs.85).aspx
if (hr == ERROR_NOT_FOUND)
// ERROR_INVALID_PARAMETER is expected for "fake" requests like applicationInitialization ones
if (hr == ERROR_NOT_FOUND || hr == ERROR_INVALID_PARAMETER)
{
return false;
}

View File

@ -1,7 +1,10 @@
// 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.ServiceProcess;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests;
@ -27,24 +30,44 @@ namespace IIS.FunctionalTests
[RequiresIIS(IISCapability.ApplicationInitialization)]
[InlineData(HostingModel.InProcess)]
[InlineData(HostingModel.OutOfProcess)]
public async Task ApplicationInitializationInitializedInProc(HostingModel hostingModel)
public async Task ApplicationPreloadStartsApp(HostingModel hostingModel)
{
var baseDeploymentParameters = _fixture.GetBaseDeploymentParameters(hostingModel);
EnableAppInitialization(baseDeploymentParameters);
var baseDeploymentParameters = _fixture.GetBaseDeploymentParameters(hostingModel, publish: true);
baseDeploymentParameters.TransformArguments((args, contentRoot)=> $"{args} CreateFile \"{Path.Combine(contentRoot, "Started.txt")}\"");
EnablePreload(baseDeploymentParameters);
var result = await DeployAsync(baseDeploymentParameters);
// Allow IIS a bit of time to complete starting before we start checking
await Task.Delay(100);
// There is always a race between which Init request arrives first
// retry couple times to see if we ever get the one comming from ApplicationInitialization module
await result.HttpClient.RetryRequestAsync("/ApplicationInitialization", async message => await message.Content.ReadAsStringAsync() == "True");
await Helpers.Retry(async () => await File.ReadAllTextAsync(Path.Combine(result.ContentRoot, "Started.txt")), 10, 200);
StopServer();
EventLogHelpers.VerifyEventLogEvent(result, EventLogHelpers.Started(result));
}
private static void EnableAppInitialization(IISDeploymentParameters baseDeploymentParameters)
[ConditionalTheory]
[RequiresIIS(IISCapability.ApplicationInitialization)]
[InlineData(HostingModel.InProcess)]
[InlineData(HostingModel.OutOfProcess)]
public async Task ApplicationInitializationPageIsRequested(HostingModel hostingModel)
{
var baseDeploymentParameters = _fixture.GetBaseDeploymentParameters(hostingModel, publish: true);
EnablePreload(baseDeploymentParameters);
baseDeploymentParameters.ServerConfigActionList.Add(
(config, _) => {
config
.RequiredElement("system.webServer")
.GetOrAdd("applicationInitialization")
.GetOrAdd("add", "initializationPage", "/CreateFile");
});
var result = await DeployAsync(baseDeploymentParameters);
await Helpers.Retry(async () => await File.ReadAllTextAsync(Path.Combine(result.ContentRoot, "Started.txt")), 10, 200);
StopServer();
EventLogHelpers.VerifyEventLogEvent(result, EventLogHelpers.Started(result));
}
private static void EnablePreload(IISDeploymentParameters baseDeploymentParameters)
{
baseDeploymentParameters.ServerConfigActionList.Add(
(config, _) => {
@ -60,11 +83,6 @@ namespace IIS.FunctionalTests
.RequiredElement("site")
.RequiredElement("application")
.SetAttributeValue("preloadEnabled", true);
config
.RequiredElement("system.webServer")
.GetOrAdd("applicationInitialization")
.GetOrAdd("add", "initializationPage", "/ApplicationInitialization?IISInit=true");
});
baseDeploymentParameters.EnableModule("ApplicationInitializationModule", "%IIS_BIN%\\warmup.dll");

View File

@ -2,6 +2,7 @@
// 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.Text;
using System.Threading;
@ -21,7 +22,9 @@ namespace TestSite
var mode = args.FirstOrDefault();
switch (mode)
{
// Semicolons are appended to env variables; removing them.
case "CreateFile":
File.WriteAllText(args[1], "");
return StartServer();
case "CheckLargeStdOutWrites":
Console.WriteLine(new string('a', 30000));
break;

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
@ -9,14 +10,27 @@ namespace TestSite
{
public static class Program
{
public static void Main(string[] args)
public static int Main(string[] args)
{
var mode = args.FirstOrDefault();
switch (mode)
{
case "CreateFile":
File.WriteAllText(args[1], "");
return StartServer();
}
return StartServer();
}
private static int StartServer()
{
var host = new WebHostBuilder()
.ConfigureLogging((_, factory) =>
{
factory.AddConsole();
factory.AddFilter("Console", level => level >= LogLevel.Information);
})
.ConfigureLogging(
(_, factory) => {
factory.AddConsole();
factory.AddFilter("Console", level => level >= LogLevel.Information);
})
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
@ -24,6 +38,7 @@ namespace TestSite
.Build();
host.Run();
return 0;
}
}
}

View File

@ -2,6 +2,7 @@
// 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.Threading;
using System.Threading.Tasks;
@ -72,15 +73,11 @@ namespace TestSite
await context.Response.WriteAsync(_waitingRequestCount.ToString());
}
private static bool _applicationInitializationCalled;
public async Task ApplicationInitialization(HttpContext context)
public Task CreateFile(HttpContext context)
{
if (context.Request.Query["IISInit"] == "true")
{
_applicationInitializationCalled = true;
}
await context.Response.WriteAsync(_applicationInitializationCalled.ToString());
var hostingEnv = context.RequestServices.GetService<IHostingEnvironment>();
File.WriteAllText(System.IO.Path.Combine(hostingEnv.ContentRootPath, "Started.txt"), "");
return Task.CompletedTask;
}
public Task OverrideServer(HttpContext context)