Add IServerVariablesFeature
Enables fetching variables directly from IIS when using in-process hosting. This is not available for out-of-process hosting. Other changes: - Update tests to only run if IIS Express has been updated to support the new schema for hostingModel - Add a simpler test fixture for in-proc testing
This commit is contained in:
parent
6f54ed1c68
commit
011cf720e6
|
|
@ -6,6 +6,8 @@ branches:
|
|||
- release
|
||||
- dev
|
||||
- /^(.*\/)?ci-.*$/
|
||||
install:
|
||||
- ps: .\tools\update_schema.ps1
|
||||
build_script:
|
||||
- ps: .\run.ps1 default-build
|
||||
clone_depth: 1
|
||||
|
|
@ -15,4 +17,4 @@ environment:
|
|||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
test: off
|
||||
deploy: off
|
||||
os: Visual Studio 2017
|
||||
os: Visual Studio 2017
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2020
|
||||
VisualStudioVersion = 15.0.27130.2026
|
||||
MinimumVisualStudioVersion = 15.0.26730.03
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04B1EDB6-E967-4D25-89B9-E6F8304038CD}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@
|
|||
|
||||
<ItemGroup Condition="'$(OS)' == 'Windows_NT'">
|
||||
<!-- x86 -->
|
||||
<None Include="..\..\src\RequestHandler\bin\$(Configuration)\Win32\aspnetcorerh.dll" CopyToOutputDirectory="PreserveNewest" Visible="false" Link="x86\aspnetcorerh.dll" />
|
||||
<None Include="..\..\src\AspNetCore\bin\$(Configuration)\Win32\aspnetcore.dll" CopyToOutputDirectory="PreserveNewest" Visible="false" Link="x86\aspnetcore.dll" />
|
||||
<None Include="..\..\src\RequestHandler\bin\$(Configuration)\Win32\*.*" CopyToOutputDirectory="PreserveNewest" Visible="false" Link="x86\%(FileName)%(Extension)" />
|
||||
<None Include="..\..\src\AspNetCore\bin\$(Configuration)\Win32\*.*" CopyToOutputDirectory="PreserveNewest" Visible="false" Link="x86\%(FileName)%(Extension)" />
|
||||
<!-- x64 -->
|
||||
<None Include="..\..\src\RequestHandler\bin\$(Configuration)\x64\aspnetcorerh.dll" CopyToOutputDirectory="PreserveNewest" Visible="false" Link="x64\aspnetcorerh.dll" />
|
||||
<None Include="..\..\src\AspNetCore\bin\$(Configuration)\x64\aspnetcore.dll" CopyToOutputDirectory="PreserveNewest" Visible="false" Link="x64\aspnetcore.dll" />
|
||||
<None Include="..\..\src\RequestHandler\bin\$(Configuration)\x64\*.*" CopyToOutputDirectory="PreserveNewest" Visible="false" Link="x64\%(FileName)%(Extension)" />
|
||||
<None Include="..\..\src\AspNetCore\bin\$(Configuration)\x64\*.*" CopyToOutputDirectory="PreserveNewest" Visible="false" Link="x64\%(FileName)%(Extension)" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -7,19 +7,20 @@ using Microsoft.AspNetCore.Authentication;
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Server.IIS;
|
||||
using Microsoft.AspNetCore.Server.IISIntegration;
|
||||
|
||||
namespace NativeIISSample
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAuthenticationSchemeProvider authSchemeProvider)
|
||||
{
|
||||
app.Run(async (context) =>
|
||||
{
|
||||
context.Response.ContentType = "text/plain";
|
||||
|
||||
await context.Response.WriteAsync("Hello World - " + DateTimeOffset.Now + Environment.NewLine);
|
||||
await context.Response.WriteAsync(Environment.NewLine);
|
||||
|
||||
|
|
@ -60,9 +61,29 @@ namespace NativeIISSample
|
|||
await context.Response.WriteAsync(key + ": " + value + Environment.NewLine);
|
||||
}
|
||||
await context.Response.WriteAsync(Environment.NewLine);
|
||||
|
||||
// accessing IIS server variables
|
||||
await context.Response.WriteAsync("Server Variables:" + Environment.NewLine);
|
||||
|
||||
foreach (var varName in IISServerVarNames)
|
||||
{
|
||||
await context.Response.WriteAsync(varName + ": " + context.GetIISServerVariable(varName) + Environment.NewLine);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static readonly string[] IISServerVarNames =
|
||||
{
|
||||
"AUTH_TYPE",
|
||||
"AUTH_USER",
|
||||
"CONTENT_TYPE",
|
||||
"HTTP_HOST",
|
||||
"HTTPS",
|
||||
"REMOTE_PORT",
|
||||
"REMOTE_USER",
|
||||
"REQUEST_METHOD",
|
||||
};
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
// 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 Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions to <see cref="HttpContext"/> that enable access to IIS features.
|
||||
/// </summary>
|
||||
public static class IISHttpContextExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the value of a server variable for the current request.
|
||||
/// </summary>
|
||||
/// <param name="context">The http context for the request.</param>
|
||||
/// <param name="variableName">The name of the variable.</param>
|
||||
/// <returns>
|
||||
/// <c>null</c> if the feature does not support the <see cref="IServerVariablesFeature"/> feature.
|
||||
/// May return null or empty if the variable does not exist or is not set.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// For a list of common server variables available in IIS, see http://go.microsoft.com/fwlink/?LinkId=52471.
|
||||
/// </remarks>
|
||||
public static string GetIISServerVariable(this HttpContext context, string variableName)
|
||||
{
|
||||
var feature = context.Features.Get<IServerVariablesFeature>();
|
||||
|
||||
if (feature == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return feature[variableName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Http.Features
|
||||
{
|
||||
/// <summary>
|
||||
/// This feature provides access to request server variables set.
|
||||
/// <para>
|
||||
/// This feature is only available when hosting ASP.NET Core in-process with IIS or IIS Express.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For a list of common server variables available in IIS, see http://go.microsoft.com/fwlink/?LinkId=52471.
|
||||
/// </remarks>
|
||||
public interface IServerVariablesFeature
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the value of a server variable for the current request.
|
||||
/// </summary>
|
||||
/// <param name="variableName">The variable name</param>
|
||||
/// <returns>May return null or empty if the variable does not exist or is not set.</returns>
|
||||
string this[string variableName] { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -77,6 +77,9 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
[DllImport(AspNetCoreModuleDll)]
|
||||
public unsafe static extern int http_get_application_properties(ref IISConfigurationData iiConfigData);
|
||||
|
||||
[DllImport(AspNetCoreModuleDll)]
|
||||
public static extern int http_get_server_variable(IntPtr pInProcessHandler, [MarshalAs(UnmanagedType.AnsiBStr)] string variableName, [MarshalAs(UnmanagedType.BStr)] out string value);
|
||||
|
||||
[DllImport(AspNetCoreModuleDll)]
|
||||
public unsafe static extern bool http_shutdown();
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
IHttpConnectionFeature,
|
||||
IHttpRequestLifetimeFeature,
|
||||
IHttpRequestIdentifierFeature,
|
||||
IHttpAuthenticationFeature
|
||||
IHttpAuthenticationFeature,
|
||||
IServerVariablesFeature
|
||||
{
|
||||
// NOTE: When feature interfaces are added to or removed from this HttpProtocol implementation,
|
||||
// then the list of `implementedFeatures` in the generated code project MUST also be updated.
|
||||
|
|
@ -234,6 +235,20 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
|
||||
public IAuthenticationHandler Handler { get; set; }
|
||||
|
||||
string IServerVariablesFeature.this[string variableName]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(variableName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int hr = NativeMethods.http_get_server_variable(_pInProcessHandler, variableName, out var value);
|
||||
return hr == 0 ? value : null;
|
||||
}
|
||||
}
|
||||
|
||||
object IFeatureCollection.this[Type key]
|
||||
{
|
||||
get => FastFeatureGet(key);
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration
|
||||
{
|
||||
|
|
@ -28,6 +26,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
private static readonly Type IHttpBodyControlFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpBodyControlFeature);
|
||||
private static readonly Type IHttpSendFileFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature);
|
||||
private static readonly Type IISHttpContextType = typeof(IISHttpContext);
|
||||
private static readonly Type IServerVariablesFeature = typeof(global::Microsoft.AspNetCore.Http.Features.IServerVariablesFeature);
|
||||
|
||||
private object _currentIHttpRequestFeature;
|
||||
private object _currentIHttpResponseFeature;
|
||||
|
|
@ -49,6 +48,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
private object _currentISessionFeature;
|
||||
private object _currentIHttpBodyControlFeature;
|
||||
private object _currentIHttpSendFileFeature;
|
||||
private object _currentIServerVariablesFeature;
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
|
|
@ -63,6 +63,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
_currentIHttpMinResponseDataRateFeature = this;
|
||||
_currentIHttpBodyControlFeature = this;
|
||||
_currentIHttpAuthenticationFeature = this;
|
||||
_currentIServerVariablesFeature = this;
|
||||
}
|
||||
|
||||
internal object FastFeatureGet(Type key)
|
||||
|
|
@ -139,6 +140,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
{
|
||||
return this;
|
||||
}
|
||||
if (key == IServerVariablesFeature)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
return ExtraFeatureGet(key);
|
||||
}
|
||||
|
|
@ -232,6 +237,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
_currentIHttpSendFileFeature = feature;
|
||||
return;
|
||||
}
|
||||
if (key == IServerVariablesFeature)
|
||||
{
|
||||
_currentIServerVariablesFeature = feature;
|
||||
return;
|
||||
}
|
||||
if (key == IISHttpContextType)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot set IISHttpContext in feature collection");
|
||||
|
|
@ -309,6 +319,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration
|
|||
{
|
||||
yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, _currentIHttpSendFileFeature as global::Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature);
|
||||
}
|
||||
if (_currentIServerVariablesFeature != null)
|
||||
{
|
||||
yield return new KeyValuePair<Type, object>(IServerVariablesFeature, _currentIServerVariablesFeature as global::Microsoft.AspNetCore.Http.Features.IServerVariablesFeature);
|
||||
}
|
||||
|
||||
if (MaybeExtra != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,6 +43,37 @@ http_get_raw_response(
|
|||
return pInProcessHandler->QueryHttpContext()->GetResponse()->GetRawHttpResponse();
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||
HRESULT
|
||||
http_get_server_variable(
|
||||
_In_ IN_PROCESS_HANDLER* pInProcessHandler,
|
||||
_In_ PCSTR pszVariableName,
|
||||
_Out_ BSTR* pwszReturn
|
||||
)
|
||||
{
|
||||
PCWSTR pszVariableValue;
|
||||
DWORD cbLength;
|
||||
HRESULT hr = pInProcessHandler
|
||||
->QueryHttpContext()
|
||||
->GetServerVariable(pszVariableName, &pszVariableValue, &cbLength);
|
||||
|
||||
if (FAILED(hr) || cbLength == 0)
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
*pwszReturn = SysAllocString(pszVariableValue);
|
||||
|
||||
if (*pwszReturn == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
}
|
||||
|
||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT VOID http_set_response_status_code(
|
||||
_In_ IN_PROCESS_HANDLER* pInProcessHandler,
|
||||
_In_ USHORT statusCode,
|
||||
|
|
@ -392,4 +423,4 @@ http_get_authentication_information(
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
// End of export
|
||||
// End of export
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@
|
|||
#if NET461
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Xunit;
|
||||
|
|
@ -26,7 +25,7 @@ namespace IISIntegration.IISServerFunctionalTests
|
|||
{
|
||||
}
|
||||
|
||||
[Fact(Skip = "See https://github.com/aspnet/IISIntegration/issues/424")]
|
||||
[ConditionalFact]
|
||||
public Task Authentication_InProcess_IISExpress()
|
||||
{
|
||||
return Authentication();
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Xunit;
|
||||
|
|
@ -22,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
{
|
||||
}
|
||||
|
||||
[Theory(Skip = "See https://github.com/aspnet/IISIntegration/issues/424")]
|
||||
[ConditionalTheory]
|
||||
[InlineData("SetRequestFeatures")]
|
||||
[InlineData("SetResponseFeatures")]
|
||||
[InlineData("SetConnectionFeatures")]
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Xunit;
|
||||
|
|
@ -21,7 +20,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
{
|
||||
}
|
||||
|
||||
[Fact(Skip = "See https://github.com/aspnet/IISIntegration/issues/515")]
|
||||
[ConditionalFact]
|
||||
public Task HelloWorld_InProcess_IISExpress_CoreClr_X64_Portable()
|
||||
{
|
||||
return HelloWorld(RuntimeFlavor.CoreClr, ApplicationType.Portable);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
|
||||
<RootNamespace>Microsoft.AspNetCore.Server.IIS.FunctionalTests</RootNamespace>
|
||||
<AssemblyName>Microsoft.AspNetCore.Server.IIS.FunctionalTests</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -2,12 +2,10 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Xunit;
|
||||
|
|
@ -23,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
{
|
||||
}
|
||||
|
||||
[Theory(Skip = "See https://github.com/aspnet/IISIntegration/issues/424")]
|
||||
[ConditionalTheory]
|
||||
[InlineData(10000)]
|
||||
[InlineData(100000)]
|
||||
[InlineData(1000000)]
|
||||
|
|
@ -84,7 +82,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
}
|
||||
|
||||
|
||||
[Fact (Skip = "See https://github.com/aspnet/IISIntegration/issues/424")]
|
||||
[ConditionalFact]
|
||||
public Task LargeFileResponseBodyInternalCheck()
|
||||
{
|
||||
return LargeResponseBodyFromFile(RuntimeFlavor.CoreClr, ApplicationType.Portable);
|
||||
|
|
@ -106,7 +104,12 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
SiteName = "HttpTestSite", // This is configured in the Http.config
|
||||
TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
|
||||
ApplicationType = applicationType,
|
||||
|
||||
Configuration =
|
||||
#if DEBUG
|
||||
"Debug"
|
||||
#else
|
||||
"Release"
|
||||
#endif
|
||||
};
|
||||
|
||||
using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
// 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.
|
||||
|
||||
// All functional tests in this project require a version of IIS express with an updated schema
|
||||
[assembly: Microsoft.AspNetCore.Server.IIS.FunctionalTests.IISExpressSupportsInProcessHosting]
|
||||
|
|
@ -2,13 +2,12 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
|
@ -24,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
{
|
||||
}
|
||||
|
||||
[Fact(Skip = "See https://github.com/aspnet/IISIntegration/issues/424")]
|
||||
[ConditionalFact]
|
||||
public Task AddResponseHeaders_HeaderValuesAreSetCorrectly()
|
||||
{
|
||||
return RunResponseHeaders(ApplicationType.Portable);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Xunit;
|
||||
|
|
@ -19,7 +20,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
|||
{
|
||||
}
|
||||
|
||||
[Theory(Skip = "See https://github.com/aspnet/IISIntegration/issues/424")]
|
||||
[ConditionalTheory]
|
||||
[InlineData("SetStatusCodeAfterWrite")]
|
||||
[InlineData("SetHeaderAfterWrite")]
|
||||
public Task ResponseInvalidOrderingTests_ExpectFailure(string path)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
{
|
||||
[Collection(IISTestSiteCollection.Name)]
|
||||
public class ServerVariablesTest
|
||||
{
|
||||
private readonly IISTestSiteFixture _fixture;
|
||||
|
||||
public ServerVariablesTest(IISTestSiteFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ProvidesAccessToServerVariables()
|
||||
{
|
||||
var port = _fixture.Client.BaseAddress.Port;
|
||||
Assert.Equal("SERVER_PORT: " + port, await _fixture.Client.GetStringAsync("/ServerVariable?q=SERVER_PORT"));
|
||||
Assert.Equal("QUERY_STRING: q=QUERY_STRING", await _fixture.Client.GetStringAsync("/ServerVariable?q=QUERY_STRING"));
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ReturnsNullForUndefinedServerVariable()
|
||||
{
|
||||
var port = _fixture.Client.BaseAddress.Port;
|
||||
Assert.Equal("THIS_VAR_IS_UNDEFINED: (null)", await _fixture.Client.GetStringAsync("/ServerVariable?q=THIS_VAR_IS_UNDEFINED"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// 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.Runtime.InteropServices;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Assembly | AttributeTargets.Class)]
|
||||
public sealed class IISExpressSupportsInProcessHostingAttribute : Attribute, ITestCondition
|
||||
{
|
||||
public bool IsMet => AncmSchema.SupportsInProcessHosting;
|
||||
|
||||
public string SkipReason => AncmSchema.SkipReason;
|
||||
|
||||
private class AncmSchema
|
||||
{
|
||||
public static bool SupportsInProcessHosting { get; }
|
||||
public static string SkipReason { get; } = "IIS Express must be upgraded to support in-process hosting.";
|
||||
|
||||
static AncmSchema()
|
||||
{
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
SkipReason = "IIS Express tests can only be run on Windows";
|
||||
return;
|
||||
}
|
||||
|
||||
var ancmConfigPath = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
|
||||
"IIS Express", "config", "schema", "aspnetcore_schema.xml");
|
||||
|
||||
if (!File.Exists(ancmConfigPath))
|
||||
{
|
||||
SkipReason = "IIS Express is not installed.";
|
||||
return;
|
||||
}
|
||||
|
||||
XDocument ancmConfig;
|
||||
|
||||
try
|
||||
{
|
||||
ancmConfig = XDocument.Load(ancmConfigPath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
SkipReason = "Could not read ANCM schema configuration";
|
||||
return;
|
||||
}
|
||||
|
||||
SupportsInProcessHosting = ancmConfig
|
||||
.Root
|
||||
.Descendants("attribute")
|
||||
.Any(n => "hostingModel".Equals(n.Attribute("name")?.Value, StringComparison.Ordinal));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// 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 Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
{
|
||||
/// <summary>
|
||||
/// This type just maps collection names to available fixtures
|
||||
/// </summary>
|
||||
[CollectionDefinition(Name)]
|
||||
public class IISTestSiteCollection : ICollectionFixture<IISTestSiteFixture>
|
||||
{
|
||||
public const string Name = nameof(IISTestSiteCollection);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// 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.Net.Http;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||
{
|
||||
public class IISTestSiteFixture : IDisposable
|
||||
{
|
||||
private readonly IApplicationDeployer _deployer;
|
||||
|
||||
public IISTestSiteFixture()
|
||||
{
|
||||
var deploymentParameters = new DeploymentParameters(Helpers.GetTestSitesPath(),
|
||||
ServerType.IISExpress,
|
||||
RuntimeFlavor.CoreClr,
|
||||
RuntimeArchitecture.x64)
|
||||
{
|
||||
ServerConfigTemplateContent = File.ReadAllText("Http.config"),
|
||||
SiteName = "HttpTestSite",
|
||||
TargetFramework = "netcoreapp2.0",
|
||||
ApplicationType = ApplicationType.Portable,
|
||||
Configuration =
|
||||
#if DEBUG
|
||||
"Debug"
|
||||
#else
|
||||
"Release"
|
||||
#endif
|
||||
};
|
||||
|
||||
_deployer = ApplicationDeployerFactory.Create(deploymentParameters, NullLoggerFactory.Instance);
|
||||
var deploymentResult = _deployer.DeployAsync().Result;
|
||||
Client = deploymentResult.HttpClient;
|
||||
BaseUri = deploymentResult.ApplicationBaseUri;
|
||||
ShutdownToken = deploymentResult.HostShutdownToken;
|
||||
}
|
||||
|
||||
public string BaseUri { get; }
|
||||
public HttpClient Client { get; }
|
||||
public CancellationToken ShutdownToken { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_deployer.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// 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 Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Server.IIS;
|
||||
|
||||
namespace IISTestSite
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.Map("/ServerVariable", ServerVariable);
|
||||
}
|
||||
|
||||
private void ServerVariable(IApplicationBuilder app)
|
||||
{
|
||||
app.Run(async ctx =>
|
||||
{
|
||||
var varName = ctx.Request.Query["q"];
|
||||
await ctx.Response.WriteAsync($"{varName}: {ctx.GetIISServerVariable(varName) ?? "(null)"}");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<#
|
||||
.DESCRIPTION
|
||||
Updates aspnetcore_schema.xml to the latest version.
|
||||
Requires admin privileges.
|
||||
#>
|
||||
[cmdletbinding(SupportsShouldProcess = $true)]
|
||||
param()
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
Set-StrictMode -Version 1
|
||||
|
||||
$schemaSource = Resolve-Path "$PSScriptRoot\..\src\AspNetCore\aspnetcore_schema.xml"
|
||||
[bool]$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
|
||||
|
||||
if (-not $isAdmin -and -not $WhatIfPreference) {
|
||||
if ($PSCmdlet.ShouldContinue("Continue as an admin?", "This script needs admin privileges to update IIS Express and IIS.")) {
|
||||
$thisFile = Join-Path $PSScriptRoot $MyInvocation.MyCommand.Name
|
||||
|
||||
Start-Process `
|
||||
-Verb runas `
|
||||
-FilePath "powershell.exe" `
|
||||
-ArgumentList $thisFile `
|
||||
-Wait `
|
||||
| Out-Null
|
||||
|
||||
if (-not $?) {
|
||||
throw 'Update failed'
|
||||
}
|
||||
exit
|
||||
}
|
||||
else {
|
||||
throw 'Requires admin privileges'
|
||||
}
|
||||
}
|
||||
|
||||
$destinations = @(
|
||||
"${env:ProgramFiles(x86)}\IIS Express\config\schema\aspnetcore_schema.xml",
|
||||
"${env:ProgramFiles}\IIS Express\config\schema\aspnetcore_schema.xml",
|
||||
"${env:windir}\system32\inetsrv\config\schema\aspnetcore_schema.xml"
|
||||
) | Get-Unique
|
||||
|
||||
|
||||
foreach ($dest in $destinations) {
|
||||
if (-not (Test-Path $dest)) {
|
||||
Write-Host -ForegroundColor Yellow "Skipping $dest. File does not already exist."
|
||||
continue
|
||||
}
|
||||
|
||||
if ($PSCmdlet.ShouldProcess($dest, "Replace file")) {
|
||||
Write-Host "Updated $dest"
|
||||
Move-Item $dest "${dest}.bak" -ErrorAction Ignore
|
||||
Copy-Item $schemaSource $dest
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue