Merge branch 'merge/release/2.2-to-master'
This commit is contained in:
commit
a7a3dbd53e
|
|
@ -86,6 +86,19 @@ Finished:
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||||
|
HRESULT
|
||||||
|
http_set_server_variable(
|
||||||
|
_In_ IN_PROCESS_HANDLER* pInProcessHandler,
|
||||||
|
_In_ PCSTR pszVariableName,
|
||||||
|
_In_ PCWSTR pszVariableValue
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return pInProcessHandler
|
||||||
|
->QueryHttpContext()
|
||||||
|
->SetServerVariable(pszVariableName, pszVariableValue);
|
||||||
|
}
|
||||||
|
|
||||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||||
HRESULT
|
HRESULT
|
||||||
http_set_response_status_code(
|
http_set_response_status_code(
|
||||||
|
|
@ -400,6 +413,17 @@ http_cancel_io(
|
||||||
return pInProcessHandler->QueryHttpContext()->CancelIo();
|
return pInProcessHandler->QueryHttpContext()->CancelIo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||||
|
HRESULT
|
||||||
|
http_disable_buffering(
|
||||||
|
_In_ IN_PROCESS_HANDLER* pInProcessHandler
|
||||||
|
)
|
||||||
|
{
|
||||||
|
pInProcessHandler->QueryHttpContext()->GetResponse()->DisableBuffering();
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||||
HRESULT
|
HRESULT
|
||||||
http_response_set_unknown_header(
|
http_response_set_unknown_header(
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@ using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
@ -23,13 +25,16 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
IHttpUpgradeFeature,
|
IHttpUpgradeFeature,
|
||||||
IHttpRequestLifetimeFeature,
|
IHttpRequestLifetimeFeature,
|
||||||
IHttpAuthenticationFeature,
|
IHttpAuthenticationFeature,
|
||||||
IServerVariablesFeature
|
IServerVariablesFeature,
|
||||||
|
IHttpBufferingFeature,
|
||||||
|
ITlsConnectionFeature
|
||||||
{
|
{
|
||||||
// NOTE: When feature interfaces are added to or removed from this HttpProtocol implementation,
|
// 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.
|
// then the list of `implementedFeatures` in the generated code project MUST also be updated.
|
||||||
|
|
||||||
private int _featureRevision;
|
private int _featureRevision;
|
||||||
private string _httpProtocolVersion = null;
|
private string _httpProtocolVersion = null;
|
||||||
|
private X509Certificate2 _certificate;
|
||||||
|
|
||||||
private List<KeyValuePair<Type, object>> MaybeExtra;
|
private List<KeyValuePair<Type, object>> MaybeExtra;
|
||||||
public void ResetFeatureCollection()
|
public void ResetFeatureCollection()
|
||||||
|
|
@ -202,7 +207,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(variableName))
|
if (string.IsNullOrEmpty(variableName))
|
||||||
{
|
{
|
||||||
return null;
|
throw new ArgumentException($"{nameof(variableName)} should be non-empty string");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Synchronize access to native methods that might run in parallel with IO loops
|
// Synchronize access to native methods that might run in parallel with IO loops
|
||||||
|
|
@ -211,6 +216,19 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
return NativeMethods.HttpTryGetServerVariable(_pInProcessHandler, variableName, out var value) ? value : null;
|
return NativeMethods.HttpTryGetServerVariable(_pInProcessHandler, variableName, out var value) ? value : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(variableName))
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"{nameof(variableName)} should be non-empty string");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synchronize access to native methods that might run in parallel with IO loops
|
||||||
|
lock (_contextLock)
|
||||||
|
{
|
||||||
|
NativeMethods.HttpSetServerVariable(_pInProcessHandler, variableName, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object IFeatureCollection.this[Type key]
|
object IFeatureCollection.this[Type key]
|
||||||
|
|
@ -262,7 +280,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
ReasonPhrase = ReasonPhrases.GetReasonPhrase(StatusCodes.Status101SwitchingProtocols);
|
ReasonPhrase = ReasonPhrases.GetReasonPhrase(StatusCodes.Status101SwitchingProtocols);
|
||||||
|
|
||||||
// If we started reading before calling Upgrade Task should be completed at this point
|
// If we started reading before calling Upgrade Task should be completed at this point
|
||||||
// because read would return 0 syncronosly
|
// because read would return 0 synchronously
|
||||||
Debug.Assert(_readBodyTask == null || _readBodyTask.IsCompleted);
|
Debug.Assert(_readBodyTask == null || _readBodyTask.IsCompleted);
|
||||||
|
|
||||||
// Reset reading status to allow restarting with new IO
|
// Reset reading status to allow restarting with new IO
|
||||||
|
|
@ -276,6 +294,35 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
return new DuplexStream(RequestBody, ResponseBody);
|
return new DuplexStream(RequestBody, ResponseBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Task<X509Certificate2> ITlsConnectionFeature.GetClientCertificateAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.FromResult(((ITlsConnectionFeature)this).ClientCertificate);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe X509Certificate2 ITlsConnectionFeature.ClientCertificate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_certificate == null &&
|
||||||
|
NativeRequest->pSslInfo != null &&
|
||||||
|
NativeRequest->pSslInfo->pClientCertInfo != null &&
|
||||||
|
NativeRequest->pSslInfo->pClientCertInfo->pCertEncoded != null &&
|
||||||
|
NativeRequest->pSslInfo->pClientCertInfo->CertEncodedSize != 0)
|
||||||
|
{
|
||||||
|
// Based off of from https://referencesource.microsoft.com/#system/net/System/Net/HttpListenerRequest.cs,1037c8ec82879ba0,references
|
||||||
|
var rawCertificateCopy = new byte[NativeRequest->pSslInfo->pClientCertInfo->CertEncodedSize];
|
||||||
|
Marshal.Copy((IntPtr)NativeRequest->pSslInfo->pClientCertInfo->pCertEncoded, rawCertificateCopy, 0, rawCertificateCopy.Length);
|
||||||
|
_certificate = new X509Certificate2(rawCertificateCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _certificate;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_certificate = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
|
IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
|
||||||
|
|
@ -284,5 +331,21 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
{
|
{
|
||||||
Abort();
|
Abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IHttpBufferingFeature.DisableRequestBuffering()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHttpBufferingFeature.DisableResponseBuffering()
|
||||||
|
{
|
||||||
|
NativeMethods.HttpDisableBuffering(_pInProcessHandler);
|
||||||
|
DisableCompression();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisableCompression()
|
||||||
|
{
|
||||||
|
var serverVariableFeature = (IServerVariablesFeature)this;
|
||||||
|
serverVariableFeature["IIS_EnableDynamicCompression"] = "0";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
private static readonly Type IHttpSendFileFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature);
|
private static readonly Type IHttpSendFileFeatureType = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpSendFileFeature);
|
||||||
private static readonly Type IISHttpContextType = typeof(IISHttpContext);
|
private static readonly Type IISHttpContextType = typeof(IISHttpContext);
|
||||||
private static readonly Type IServerVariablesFeature = typeof(global::Microsoft.AspNetCore.Http.Features.IServerVariablesFeature);
|
private static readonly Type IServerVariablesFeature = typeof(global::Microsoft.AspNetCore.Http.Features.IServerVariablesFeature);
|
||||||
|
private static readonly Type IHttpBufferingFeature = typeof(global::Microsoft.AspNetCore.Http.Features.IHttpBufferingFeature);
|
||||||
|
|
||||||
private object _currentIHttpRequestFeature;
|
private object _currentIHttpRequestFeature;
|
||||||
private object _currentIHttpResponseFeature;
|
private object _currentIHttpResponseFeature;
|
||||||
|
|
@ -41,14 +42,12 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
private object _currentIResponseCookiesFeature;
|
private object _currentIResponseCookiesFeature;
|
||||||
private object _currentIItemsFeature;
|
private object _currentIItemsFeature;
|
||||||
private object _currentITlsConnectionFeature;
|
private object _currentITlsConnectionFeature;
|
||||||
private object _currentIHttpMaxRequestBodySizeFeature;
|
|
||||||
private object _currentIHttpMinRequestBodyDataRateFeature;
|
|
||||||
private object _currentIHttpMinResponseDataRateFeature;
|
|
||||||
private object _currentIHttpWebSocketFeature;
|
private object _currentIHttpWebSocketFeature;
|
||||||
private object _currentISessionFeature;
|
private object _currentISessionFeature;
|
||||||
private object _currentIHttpBodyControlFeature;
|
private object _currentIHttpBodyControlFeature;
|
||||||
private object _currentIHttpSendFileFeature;
|
private object _currentIHttpSendFileFeature;
|
||||||
private object _currentIServerVariablesFeature;
|
private object _currentIServerVariablesFeature;
|
||||||
|
private object _currentIHttpBufferingFeature;
|
||||||
|
|
||||||
private void Initialize()
|
private void Initialize()
|
||||||
{
|
{
|
||||||
|
|
@ -58,12 +57,11 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
_currentIHttpRequestIdentifierFeature = this;
|
_currentIHttpRequestIdentifierFeature = this;
|
||||||
_currentIHttpRequestLifetimeFeature = this;
|
_currentIHttpRequestLifetimeFeature = this;
|
||||||
_currentIHttpConnectionFeature = this;
|
_currentIHttpConnectionFeature = this;
|
||||||
_currentIHttpMaxRequestBodySizeFeature = this;
|
|
||||||
_currentIHttpMinRequestBodyDataRateFeature = this;
|
|
||||||
_currentIHttpMinResponseDataRateFeature = this;
|
|
||||||
_currentIHttpBodyControlFeature = this;
|
_currentIHttpBodyControlFeature = this;
|
||||||
_currentIHttpAuthenticationFeature = this;
|
_currentIHttpAuthenticationFeature = this;
|
||||||
_currentIServerVariablesFeature = this;
|
_currentIServerVariablesFeature = this;
|
||||||
|
_currentIHttpBufferingFeature = this;
|
||||||
|
_currentITlsConnectionFeature = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal object FastFeatureGet(Type key)
|
internal object FastFeatureGet(Type key)
|
||||||
|
|
@ -142,7 +140,11 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
}
|
}
|
||||||
if (key == IServerVariablesFeature)
|
if (key == IServerVariablesFeature)
|
||||||
{
|
{
|
||||||
return this;
|
return _currentIServerVariablesFeature;
|
||||||
|
}
|
||||||
|
if (key == IHttpBufferingFeature)
|
||||||
|
{
|
||||||
|
return _currentIHttpBufferingFeature;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExtraFeatureGet(key);
|
return ExtraFeatureGet(key);
|
||||||
|
|
@ -242,6 +244,11 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
_currentIServerVariablesFeature = feature;
|
_currentIServerVariablesFeature = feature;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (key == IHttpBufferingFeature)
|
||||||
|
{
|
||||||
|
_currentIHttpBufferingFeature = feature;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (key == IISHttpContextType)
|
if (key == IISHttpContextType)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Cannot set IISHttpContext in feature collection");
|
throw new InvalidOperationException("Cannot set IISHttpContext in feature collection");
|
||||||
|
|
@ -323,6 +330,10 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IServerVariablesFeature, _currentIServerVariablesFeature as global::Microsoft.AspNetCore.Http.Features.IServerVariablesFeature);
|
yield return new KeyValuePair<Type, object>(IServerVariablesFeature, _currentIServerVariablesFeature as global::Microsoft.AspNetCore.Http.Features.IServerVariablesFeature);
|
||||||
}
|
}
|
||||||
|
if (_currentIHttpBufferingFeature != null)
|
||||||
|
{
|
||||||
|
yield return new KeyValuePair<Type, object>(IHttpBufferingFeature, _currentIHttpBufferingFeature as global::Microsoft.AspNetCore.Http.Features.IHttpBufferingFeature);
|
||||||
|
}
|
||||||
|
|
||||||
if (MaybeExtra != null)
|
if (MaybeExtra != null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,10 @@ namespace Microsoft.AspNetCore.Http.Features
|
||||||
public interface IServerVariablesFeature
|
public interface IServerVariablesFeature
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the value of a server variable for the current request.
|
/// Gets or sets the value of a server variable for the current request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="variableName">The variable name</param>
|
/// <param name="variableName">The variable name</param>
|
||||||
/// <returns>May return null or empty if the variable does not exist or is not set.</returns>
|
/// <returns>May return null or empty if the variable does not exist or is not set.</returns>
|
||||||
string this[string variableName] { get; }
|
string this[string variableName] { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ namespace Microsoft.AspNetCore.Server.IIS
|
||||||
|
|
||||||
public static extern bool CloseHandle(IntPtr handle);
|
public static extern bool CloseHandle(IntPtr handle);
|
||||||
|
|
||||||
|
|
||||||
[DllImport("kernel32.dll")]
|
[DllImport("kernel32.dll")]
|
||||||
private static extern IntPtr GetModuleHandle(string lpModuleName);
|
private static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||||
|
|
||||||
|
|
@ -76,6 +75,9 @@ namespace Microsoft.AspNetCore.Server.IIS
|
||||||
[DllImport(AspNetCoreModuleDll)]
|
[DllImport(AspNetCoreModuleDll)]
|
||||||
private static extern int http_stop_incoming_requests(IntPtr pInProcessApplication);
|
private static extern int http_stop_incoming_requests(IntPtr pInProcessApplication);
|
||||||
|
|
||||||
|
[DllImport(AspNetCoreModuleDll)]
|
||||||
|
private static extern int http_disable_buffering(IntPtr pInProcessApplication);
|
||||||
|
|
||||||
[DllImport(AspNetCoreModuleDll, CharSet = CharSet.Ansi)]
|
[DllImport(AspNetCoreModuleDll, CharSet = CharSet.Ansi)]
|
||||||
private static extern int http_set_response_status_code(IntPtr pInProcessHandler, ushort statusCode, string pszReason);
|
private static extern int http_set_response_status_code(IntPtr pInProcessHandler, ushort statusCode, string pszReason);
|
||||||
|
|
||||||
|
|
@ -97,6 +99,12 @@ namespace Microsoft.AspNetCore.Server.IIS
|
||||||
[MarshalAs(UnmanagedType.LPStr)] string variableName,
|
[MarshalAs(UnmanagedType.LPStr)] string variableName,
|
||||||
[MarshalAs(UnmanagedType.BStr)] out string value);
|
[MarshalAs(UnmanagedType.BStr)] out string value);
|
||||||
|
|
||||||
|
[DllImport(AspNetCoreModuleDll)]
|
||||||
|
private static extern int http_set_server_variable(
|
||||||
|
IntPtr pInProcessHandler,
|
||||||
|
[MarshalAs(UnmanagedType.LPStr)] string variableName,
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)] string value);
|
||||||
|
|
||||||
[DllImport(AspNetCoreModuleDll)]
|
[DllImport(AspNetCoreModuleDll)]
|
||||||
private static extern unsafe int http_websockets_read_bytes(
|
private static extern unsafe int http_websockets_read_bytes(
|
||||||
IntPtr pInProcessHandler,
|
IntPtr pInProcessHandler,
|
||||||
|
|
@ -176,6 +184,11 @@ namespace Microsoft.AspNetCore.Server.IIS
|
||||||
Validate(http_stop_incoming_requests(pInProcessApplication));
|
Validate(http_stop_incoming_requests(pInProcessApplication));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void HttpDisableBuffering(IntPtr pInProcessApplication)
|
||||||
|
{
|
||||||
|
Validate(http_disable_buffering(pInProcessApplication));
|
||||||
|
}
|
||||||
|
|
||||||
public static void HttpSetResponseStatusCode(IntPtr pInProcessHandler, ushort statusCode, string pszReason)
|
public static void HttpSetResponseStatusCode(IntPtr pInProcessHandler, ushort statusCode, string pszReason)
|
||||||
{
|
{
|
||||||
Validate(http_set_response_status_code(pInProcessHandler, statusCode, pszReason));
|
Validate(http_set_response_status_code(pInProcessHandler, statusCode, pszReason));
|
||||||
|
|
@ -208,6 +221,11 @@ namespace Microsoft.AspNetCore.Server.IIS
|
||||||
return http_get_server_variable(pInProcessHandler, variableName, out value) == 0;
|
return http_get_server_variable(pInProcessHandler, variableName, out value) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void HttpSetServerVariable(IntPtr pInProcessHandler, string variableName, string value)
|
||||||
|
{
|
||||||
|
Validate(http_set_server_variable(pInProcessHandler, variableName, value));
|
||||||
|
}
|
||||||
|
|
||||||
public static unsafe int HttpWebsocketsReadBytes(
|
public static unsafe int HttpWebsocketsReadBytes(
|
||||||
IntPtr pInProcessHandler,
|
IntPtr pInProcessHandler,
|
||||||
byte* pvBuffer,
|
byte* pvBuffer,
|
||||||
|
|
|
||||||
|
|
@ -80,5 +80,31 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
||||||
aspNetCoreElement.SetAttributeValue("arguments", transformation((string)aspNetCoreElement.Attribute("arguments"), contentRoot));
|
aspNetCoreElement.SetAttributeValue("arguments", transformation((string)aspNetCoreElement.Attribute("arguments"), contentRoot));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void EnableModule(this IISDeploymentParameters parameters, string moduleName, string modulePath)
|
||||||
|
{
|
||||||
|
if (parameters.ServerType == ServerType.IIS)
|
||||||
|
{
|
||||||
|
modulePath = modulePath.Replace("%IIS_BIN%", "%windir%\\System32\\inetsrv");
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters.ServerConfigActionList.Add(
|
||||||
|
(element, _) => {
|
||||||
|
var webServerElement = element
|
||||||
|
.RequiredElement("system.webServer");
|
||||||
|
|
||||||
|
webServerElement
|
||||||
|
.RequiredElement("globalModules")
|
||||||
|
.GetOrAdd("add", "name", moduleName)
|
||||||
|
.SetAttributeValue("image", modulePath);
|
||||||
|
|
||||||
|
(webServerElement.Element("modules") ??
|
||||||
|
element
|
||||||
|
.Element("location")
|
||||||
|
.RequiredElement("system.webServer")
|
||||||
|
.RequiredElement("modules"))
|
||||||
|
.GetOrAdd("add", "name", moduleName);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -293,7 +293,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
||||||
|
|
||||||
ConfigureModuleAndBinding(config.Root, contentRoot, port);
|
ConfigureModuleAndBinding(config.Root, contentRoot, port);
|
||||||
|
|
||||||
if (!DeploymentParameters.PublishApplicationBeforeDeployment)
|
var webConfigPath = Path.Combine(contentRoot, "web.config");
|
||||||
|
if (!DeploymentParameters.PublishApplicationBeforeDeployment && !File.Exists(webConfigPath))
|
||||||
{
|
{
|
||||||
// The elements normally in the web.config are in the applicationhost.config for unpublished apps.
|
// The elements normally in the web.config are in the applicationhost.config for unpublished apps.
|
||||||
AddAspNetCoreElement(config.Root);
|
AddAspNetCoreElement(config.Root);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
// 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.Security.Cryptography;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
{
|
||||||
|
public class ClientCertificateFixture : IDisposable
|
||||||
|
{
|
||||||
|
public ClientCertificateFixture()
|
||||||
|
{
|
||||||
|
using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
|
||||||
|
{
|
||||||
|
store.Open(OpenFlags.ReadWrite);
|
||||||
|
|
||||||
|
foreach (var cert in store.Certificates)
|
||||||
|
{
|
||||||
|
if (cert.Issuer != "CN=IISIntegrationTest_Root")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Certificate = cert;
|
||||||
|
store.Close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parentKey = CreateKeyMaterial(2048);
|
||||||
|
|
||||||
|
// On first run of the test, creates the certificate in the trusted root certificate authorities.
|
||||||
|
var parentRequest = new CertificateRequest("CN=IISIntegrationTest_Root", parentKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||||
|
|
||||||
|
parentRequest.CertificateExtensions.Add(
|
||||||
|
new X509BasicConstraintsExtension(
|
||||||
|
certificateAuthority: true,
|
||||||
|
hasPathLengthConstraint: false,
|
||||||
|
pathLengthConstraint: 0,
|
||||||
|
critical: true));
|
||||||
|
|
||||||
|
parentRequest.CertificateExtensions.Add(
|
||||||
|
new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation, critical: true));
|
||||||
|
|
||||||
|
parentRequest.CertificateExtensions.Add(
|
||||||
|
new X509SubjectKeyIdentifierExtension(parentRequest.PublicKey, false));
|
||||||
|
|
||||||
|
var notBefore = DateTimeOffset.Now.AddDays(-1);
|
||||||
|
var notAfter = DateTimeOffset.Now.AddYears(5);
|
||||||
|
|
||||||
|
var parentCert = parentRequest.CreateSelfSigned(notBefore, notAfter);
|
||||||
|
|
||||||
|
// Need to export/import the certificate to associate the private key with the cert.
|
||||||
|
var imported = parentCert;
|
||||||
|
|
||||||
|
var export = parentCert.Export(X509ContentType.Pkcs12, "");
|
||||||
|
imported = new X509Certificate2(export, "", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
|
||||||
|
Array.Clear(export, 0, export.Length);
|
||||||
|
|
||||||
|
// Add the cert to the cert store
|
||||||
|
Certificate = imported;
|
||||||
|
|
||||||
|
store.Add(certificate: imported);
|
||||||
|
store.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public X509Certificate2 Certificate { get; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
|
||||||
|
{
|
||||||
|
store.Open(OpenFlags.ReadWrite);
|
||||||
|
store.Remove(Certificate);
|
||||||
|
store.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RSA CreateKeyMaterial(int minimumKeySize)
|
||||||
|
{
|
||||||
|
var rsa = RSA.Create(minimumKeySize);
|
||||||
|
if (rsa.KeySize < minimumKeySize)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Failed to create a key with a size of {minimumKeySize} bits");
|
||||||
|
}
|
||||||
|
|
||||||
|
return rsa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
// 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.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
||||||
|
using Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
||||||
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
|
||||||
|
{
|
||||||
|
[Collection(PublishedSitesCollection.Name)]
|
||||||
|
[SkipIfNotAdmin]
|
||||||
|
public class ClientCertificateTests : IISFunctionalTestBase
|
||||||
|
{
|
||||||
|
private readonly PublishedSitesFixture _fixture;
|
||||||
|
private readonly ClientCertificateFixture _certFixture;
|
||||||
|
|
||||||
|
public ClientCertificateTests(PublishedSitesFixture fixture, ClientCertificateFixture certFixture)
|
||||||
|
{
|
||||||
|
_fixture = fixture;
|
||||||
|
_certFixture = certFixture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TestMatrix TestVariants
|
||||||
|
=> TestMatrix.ForServers(DeployerSelector.ServerType)
|
||||||
|
.WithTfms(Tfm.NetCoreApp22, Tfm.Net461)
|
||||||
|
.WithAllApplicationTypes()
|
||||||
|
.WithAllAncmVersions()
|
||||||
|
.WithAllHostingModels();
|
||||||
|
|
||||||
|
[ConditionalTheory]
|
||||||
|
[MemberData(nameof(TestVariants))]
|
||||||
|
public Task HttpsNoClientCert_NoClientCert(TestVariant variant)
|
||||||
|
{
|
||||||
|
return ClientCertTest(variant, sendClientCert: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalTheory]
|
||||||
|
[MemberData(nameof(TestVariants))]
|
||||||
|
public Task HttpsClientCert_GetCertInformation(TestVariant variant)
|
||||||
|
{
|
||||||
|
return ClientCertTest(variant, sendClientCert: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ClientCertTest(TestVariant variant, bool sendClientCert)
|
||||||
|
{
|
||||||
|
var port = TestPortHelper.GetNextSSLPort();
|
||||||
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant);
|
||||||
|
deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/";
|
||||||
|
deploymentParameters.AddHttpsToServerConfig();
|
||||||
|
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
var handler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
|
||||||
|
ClientCertificateOptions = ClientCertificateOption.Manual,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (sendClientCert)
|
||||||
|
{
|
||||||
|
Assert.NotNull(_certFixture.Certificate);
|
||||||
|
handler.ClientCertificates.Add(_certFixture.Certificate);
|
||||||
|
}
|
||||||
|
|
||||||
|
var client = deploymentResult.CreateClient(handler);
|
||||||
|
var response = await client.GetAsync("GetClientCert");
|
||||||
|
|
||||||
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
if (sendClientCert)
|
||||||
|
{
|
||||||
|
Assert.Equal($"Enabled;{_certFixture.Certificate.GetCertHashString()}", responseText);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.Equal("Disabled", responseText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,10 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// 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.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
// 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.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
{
|
||||||
|
[Collection(IISCompressionSiteCollection.Name)]
|
||||||
|
public class CompressionTests : FixtureLoggedTest
|
||||||
|
{
|
||||||
|
private readonly IISCompressionSiteFixture _fixture;
|
||||||
|
|
||||||
|
public CompressionTests(IISCompressionSiteFixture fixture): base(fixture)
|
||||||
|
{
|
||||||
|
_fixture = fixture;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalTheory]
|
||||||
|
[RequiresIIS(IISCapability.DynamicCompression)]
|
||||||
|
[InlineData(true)]
|
||||||
|
[InlineData(false)]
|
||||||
|
public async Task BufferingDisabled(bool compression)
|
||||||
|
{
|
||||||
|
using (var connection = _fixture.CreateTestConnection())
|
||||||
|
{
|
||||||
|
var requestLength = 0;
|
||||||
|
var messages = new List<string>();
|
||||||
|
for (var i = 1; i < 100; i++)
|
||||||
|
{
|
||||||
|
var message = i + Environment.NewLine;
|
||||||
|
requestLength += message.Length;
|
||||||
|
messages.Add(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
await connection.Send(
|
||||||
|
"POST /ReadAndWriteEchoLinesNoBuffering HTTP/1.1",
|
||||||
|
$"Content-Length: {requestLength}",
|
||||||
|
"Accept-Encoding: " + (compression ? "gzip": "identity"),
|
||||||
|
"Response-Content-Type: text/event-stream",
|
||||||
|
"Host: localhost",
|
||||||
|
"Connection: close",
|
||||||
|
"",
|
||||||
|
"");
|
||||||
|
|
||||||
|
await connection.Receive(
|
||||||
|
"HTTP/1.1 200 OK",
|
||||||
|
"");
|
||||||
|
await connection.ReceiveHeaders();
|
||||||
|
|
||||||
|
foreach (var message in messages)
|
||||||
|
{
|
||||||
|
await connection.Send(message);
|
||||||
|
await connection.ReceiveChunk(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
await connection.Send("\r\n");
|
||||||
|
await connection.ReceiveChunk("");
|
||||||
|
await connection.WaitForConnectionClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[RequiresIIS(IISCapability.DynamicCompression)]
|
||||||
|
public async Task DynamicResponsesAreCompressed()
|
||||||
|
{
|
||||||
|
var handler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
AutomaticDecompression = DecompressionMethods.GZip
|
||||||
|
};
|
||||||
|
var client = new HttpClient(handler)
|
||||||
|
{
|
||||||
|
BaseAddress = _fixture.Client.BaseAddress,
|
||||||
|
};
|
||||||
|
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
|
||||||
|
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("identity", 0));
|
||||||
|
client.DefaultRequestHeaders.Add("Response-Content-Type", "text/event-stream");
|
||||||
|
var messages = "Message1\r\nMessage2\r\n";
|
||||||
|
|
||||||
|
// Send messages with terminator
|
||||||
|
var response = await client.PostAsync("ReadAndWriteEchoLines", new StringContent(messages + "\r\n"));
|
||||||
|
Assert.Equal(messages, await response.Content.ReadAsStringAsync());
|
||||||
|
Assert.True(response.Content.Headers.TryGetValues("Content-Type", out var contentTypes));
|
||||||
|
Assert.Single(contentTypes, "text/event-stream");
|
||||||
|
// Not the cleanest check but I wasn't able to figure out other way to check
|
||||||
|
// that response was compressed
|
||||||
|
Assert.Contains("gzip", response.Content.GetType().FullName, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -34,6 +34,12 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
Assert.Equal("THIS_VAR_IS_UNDEFINED: (null)", await _fixture.Client.GetStringAsync("/ServerVariable?q=THIS_VAR_IS_UNDEFINED"));
|
Assert.Equal("THIS_VAR_IS_UNDEFINED: (null)", await _fixture.Client.GetStringAsync("/ServerVariable?q=THIS_VAR_IS_UNDEFINED"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
public async Task CanSetAndReadVariable()
|
||||||
|
{
|
||||||
|
Assert.Equal("ROUNDTRIP: 1", await _fixture.Client.GetStringAsync("/ServerVariable?v=1&q=ROUNDTRIP"));
|
||||||
|
}
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
public async Task BasePathIsNotPrefixedBySlashSlashQuestionMark()
|
public async Task BasePathIsNotPrefixedBySlashSlashQuestionMark()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
||||||
|
|
@ -12,7 +11,7 @@ using Xunit;
|
||||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
[Collection(PublishedSitesCollection.Name)]
|
[Collection(PublishedSitesCollection.Name)]
|
||||||
public class StartupExceptionTests : IISFunctionalTestBase
|
public class StartupExceptionTests : LogFileTestBase
|
||||||
{
|
{
|
||||||
private readonly PublishedSitesFixture _fixture;
|
private readonly PublishedSitesFixture _fixture;
|
||||||
|
|
||||||
|
|
@ -22,18 +21,20 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[ConditionalTheory]
|
[ConditionalTheory]
|
||||||
[InlineData("ConsoleWrite")]
|
[InlineData("CheckLargeStdErrWrites")]
|
||||||
[InlineData("ConsoleErrorWrite")]
|
[InlineData("CheckLargeStdOutWrites")]
|
||||||
public async Task CheckStdoutWithRandomNumber(string mode)
|
[InlineData("CheckOversizedStdErrWrites")]
|
||||||
|
[InlineData("CheckOversizedStdOutWrites")]
|
||||||
|
public async Task CheckStdoutWithLargeWrites_TestSink(string mode)
|
||||||
{
|
{
|
||||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true);
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true);
|
||||||
|
deploymentParameters.TransformArguments((a, _) => $"{a} {mode}");
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
var randomNumberString = new Random(Guid.NewGuid().GetHashCode()).Next(10000000).ToString();
|
await AssertFailsToStart(deploymentResult);
|
||||||
deploymentParameters.TransformArguments((a, _) => $"{a} {mode} {randomNumberString}");
|
var expectedString = new string('a', 30000);
|
||||||
|
Assert.Contains(TestSink.Writes, context => context.Message.Contains(expectedString));
|
||||||
await AssertFailsToStart(deploymentParameters);
|
EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessThreadExitStdOut(deploymentResult, "12", expectedString));
|
||||||
|
|
||||||
Assert.Contains(TestSink.Writes, context => context.Message.Contains($"Random number: {randomNumberString}"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[ConditionalTheory]
|
[ConditionalTheory]
|
||||||
|
|
@ -41,14 +42,21 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
[InlineData("CheckLargeStdOutWrites")]
|
[InlineData("CheckLargeStdOutWrites")]
|
||||||
[InlineData("CheckOversizedStdErrWrites")]
|
[InlineData("CheckOversizedStdErrWrites")]
|
||||||
[InlineData("CheckOversizedStdOutWrites")]
|
[InlineData("CheckOversizedStdOutWrites")]
|
||||||
public async Task CheckStdoutWithLargeWrites(string mode)
|
public async Task CheckStdoutWithLargeWrites_LogFile(string mode)
|
||||||
{
|
{
|
||||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true);
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true);
|
||||||
deploymentParameters.TransformArguments((a, _) => $"{a} {mode}");
|
deploymentParameters.TransformArguments((a, _) => $"{a} {mode}");
|
||||||
|
deploymentParameters.EnableLogging(_logFolderPath);
|
||||||
|
|
||||||
await AssertFailsToStart(deploymentParameters);
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
Assert.Contains(TestSink.Writes, context => context.Message.Contains(new string('a', 30000)));
|
await AssertFailsToStart(deploymentResult);
|
||||||
|
|
||||||
|
var contents = GetLogFileContent(deploymentResult);
|
||||||
|
var expectedString = new string('a', 30000);
|
||||||
|
|
||||||
|
Assert.Contains(expectedString, contents);
|
||||||
|
EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessThreadExitStdOut(deploymentResult, "12", expectedString));
|
||||||
}
|
}
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
|
|
@ -57,16 +65,16 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true);
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true);
|
||||||
deploymentParameters.TransformArguments((a, _) => $"{a} CheckConsoleFunctions");
|
deploymentParameters.TransformArguments((a, _) => $"{a} CheckConsoleFunctions");
|
||||||
|
|
||||||
await AssertFailsToStart(deploymentParameters);
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
|
await AssertFailsToStart(deploymentResult);
|
||||||
|
|
||||||
Assert.Contains(TestSink.Writes, context => context.Message.Contains("Is Console redirection: True"));
|
Assert.Contains(TestSink.Writes, context => context.Message.Contains("Is Console redirection: True"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AssertFailsToStart(IISDeploymentParameters deploymentParameters)
|
private async Task AssertFailsToStart(IISDeploymentResult deploymentResult)
|
||||||
{
|
{
|
||||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
var response = await deploymentResult.HttpClient.GetAsync("/HelloWorld");
|
||||||
|
|
||||||
var response = await deploymentResult.HttpClient.GetAsync("/");
|
|
||||||
|
|
||||||
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
response = await deploymentResult.HttpClient.GetAsync("/Auth");
|
response = await deploymentResult.HttpClient.GetAsync("/Auth");
|
||||||
responseText = await response.Content.ReadAsStringAsync();
|
responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
Assert.True("backcompat;Windows".Equals(responseText) || "latest;null".Equals(responseText), "Auth");
|
Assert.True("null".Equals(responseText), "Auth");
|
||||||
|
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
$"ContentRootPath {deploymentResult.ContentRoot}" + Environment.NewLine +
|
$"ContentRootPath {deploymentResult.ContentRoot}" + Environment.NewLine +
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
/// This type just maps collection names to available fixtures
|
/// This type just maps collection names to available fixtures
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[CollectionDefinition(Name)]
|
[CollectionDefinition(Name)]
|
||||||
public class PublishedSitesCollection : ICollectionFixture<PublishedSitesFixture>
|
public class PublishedSitesCollection : ICollectionFixture<PublishedSitesFixture>, ICollectionFixture<ClientCertificateFixture>
|
||||||
{
|
{
|
||||||
public const string Name = nameof(PublishedSitesCollection);
|
public const string Name = nameof(PublishedSitesCollection);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
// 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.Security.Principal;
|
||||||
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
|
||||||
|
public sealed class SkipIfNotAdminAttribute : Attribute, ITestCondition
|
||||||
|
{
|
||||||
|
public bool IsMet
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var identity = WindowsIdentity.GetCurrent();
|
||||||
|
var principal = new WindowsPrincipal(identity);
|
||||||
|
return principal.IsInRole(WindowsBuiltInRole.Administrator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SkipReason => "The current process is not running as admin.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
Websockets = 1,
|
Websockets = 1,
|
||||||
WindowsAuthentication = 2,
|
WindowsAuthentication = 2,
|
||||||
PoolEnvironmentVariables = 4,
|
PoolEnvironmentVariables = 4,
|
||||||
ShutdownToken = 8
|
ShutdownToken = 8,
|
||||||
|
DynamicCompression = 16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// 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.IISIntegration.FunctionalTests
|
||||||
|
{
|
||||||
|
[CollectionDefinition(Name)]
|
||||||
|
public class IISCompressionSiteCollection : ICollectionFixture<IISCompressionSiteFixture>
|
||||||
|
{
|
||||||
|
public const string Name = nameof(IISCompressionSiteCollection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
// 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.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
{
|
||||||
|
public class IISCompressionSiteFixture : IISTestSiteFixture
|
||||||
|
{
|
||||||
|
public IISCompressionSiteFixture() : base(Configure)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Configure(IISDeploymentParameters deploymentParameters)
|
||||||
|
{
|
||||||
|
// Enable dynamic compression
|
||||||
|
deploymentParameters.ServerConfigActionList.Add(
|
||||||
|
(element, _) => {
|
||||||
|
var webServerElement = element
|
||||||
|
.RequiredElement("system.webServer");
|
||||||
|
|
||||||
|
webServerElement
|
||||||
|
.GetOrAdd("urlCompression")
|
||||||
|
.SetAttributeValue("doDynamicCompression", "true");
|
||||||
|
|
||||||
|
webServerElement
|
||||||
|
.GetOrAdd("httpCompression")
|
||||||
|
.GetOrAdd("dynamicTypes")
|
||||||
|
.GetOrAdd("add", "mimeType", "text/*")
|
||||||
|
.SetAttributeValue("enabled", "true");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
deploymentParameters.EnableModule("DynamicCompressionModule", "%IIS_BIN%\\compdyn.dll");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,40 +14,36 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
public class IISTestSiteFixture : IDisposable
|
public class IISTestSiteFixture : IDisposable
|
||||||
{
|
{
|
||||||
private readonly ApplicationDeployer _deployer;
|
private ApplicationDeployer _deployer;
|
||||||
private readonly ForwardingProvider _forwardingProvider;
|
private ILoggerFactory _loggerFactory;
|
||||||
|
private ForwardingProvider _forwardingProvider;
|
||||||
|
private IISDeploymentResult _deploymentResult;
|
||||||
|
private readonly Action<IISDeploymentParameters> _configure;
|
||||||
|
|
||||||
public IISTestSiteFixture()
|
public IISTestSiteFixture() : this(_ => { })
|
||||||
{
|
{
|
||||||
var logging = AssemblyTestLog.ForAssembly(typeof(IISTestSiteFixture).Assembly);
|
|
||||||
|
|
||||||
var deploymentParameters = new IISDeploymentParameters(Helpers.GetInProcessTestSitesPath(),
|
|
||||||
DeployerSelector.ServerType,
|
|
||||||
RuntimeFlavor.CoreClr,
|
|
||||||
RuntimeArchitecture.x64)
|
|
||||||
{
|
|
||||||
TargetFramework = Tfm.NetCoreApp22,
|
|
||||||
AncmVersion = AncmVersion.AspNetCoreModuleV2,
|
|
||||||
HostingModel = HostingModel.InProcess,
|
|
||||||
PublishApplicationBeforeDeployment = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
_forwardingProvider = new ForwardingProvider();
|
|
||||||
var loggerFactory = logging.CreateLoggerFactory(null, nameof(IISTestSiteFixture));
|
|
||||||
loggerFactory.AddProvider(_forwardingProvider);
|
|
||||||
|
|
||||||
_deployer = IISApplicationDeployerFactory.Create(deploymentParameters, loggerFactory);
|
|
||||||
|
|
||||||
DeploymentResult = (IISDeploymentResult)_deployer.DeployAsync().Result;
|
|
||||||
Client = DeploymentResult.HttpClient;
|
|
||||||
BaseUri = DeploymentResult.ApplicationBaseUri;
|
|
||||||
ShutdownToken = DeploymentResult.HostShutdownToken;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string BaseUri { get; }
|
public IISTestSiteFixture(Action<IISDeploymentParameters> configure)
|
||||||
public HttpClient Client { get; }
|
{
|
||||||
public CancellationToken ShutdownToken { get; }
|
var logging = AssemblyTestLog.ForAssembly(typeof(IISTestSiteFixture).Assembly);
|
||||||
public IISDeploymentResult DeploymentResult { get; }
|
_loggerFactory = logging.CreateLoggerFactory(null, nameof(IISTestSiteFixture));
|
||||||
|
|
||||||
|
_forwardingProvider = new ForwardingProvider();
|
||||||
|
_loggerFactory.AddProvider(_forwardingProvider);
|
||||||
|
|
||||||
|
_configure = configure;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpClient Client => DeploymentResult.HttpClient;
|
||||||
|
public IISDeploymentResult DeploymentResult
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
EnsureInitialized();
|
||||||
|
return _deploymentResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TestConnection CreateTestConnection()
|
public TestConnection CreateTestConnection()
|
||||||
{
|
{
|
||||||
|
|
@ -56,7 +52,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_deployer.Dispose();
|
_deployer?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Attach(LoggedTest test)
|
public void Attach(LoggedTest test)
|
||||||
|
|
@ -79,6 +75,30 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
_forwardingProvider.LoggerFactory = null;
|
_forwardingProvider.LoggerFactory = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EnsureInitialized()
|
||||||
|
{
|
||||||
|
if (_deployer != null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var deploymentParameters = new IISDeploymentParameters(Helpers.GetInProcessTestSitesPath(),
|
||||||
|
DeployerSelector.ServerType,
|
||||||
|
RuntimeFlavor.CoreClr,
|
||||||
|
RuntimeArchitecture.x64)
|
||||||
|
{
|
||||||
|
TargetFramework = Tfm.NetCoreApp22,
|
||||||
|
AncmVersion = AncmVersion.AspNetCoreModuleV2,
|
||||||
|
HostingModel = HostingModel.InProcess,
|
||||||
|
PublishApplicationBeforeDeployment = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
_configure(deploymentParameters);
|
||||||
|
|
||||||
|
_deployer = IISApplicationDeployerFactory.Create(deploymentParameters, _loggerFactory);
|
||||||
|
_deploymentResult = (IISDeploymentResult)_deployer.DeployAsync().Result;
|
||||||
|
}
|
||||||
|
|
||||||
private class ForwardingProvider : ILoggerProvider
|
private class ForwardingProvider : ILoggerProvider
|
||||||
{
|
{
|
||||||
private readonly List<ForwardingLogger> _loggers = new List<ForwardingLogger>();
|
private readonly List<ForwardingLogger> _loggers = new List<ForwardingLogger>();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
// 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 Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities
|
||||||
|
{
|
||||||
|
public class LogFileTestBase : IISFunctionalTestBase
|
||||||
|
{
|
||||||
|
protected string _logFolderPath;
|
||||||
|
|
||||||
|
public LogFileTestBase(ITestOutputHelper output = null) : base(output)
|
||||||
|
{
|
||||||
|
_logFolderPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||||
|
}
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
base.Dispose();
|
||||||
|
if (Directory.Exists(_logFolderPath))
|
||||||
|
{
|
||||||
|
Directory.Delete(_logFolderPath, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetLogFileContent(IISDeploymentResult deploymentResult)
|
||||||
|
{
|
||||||
|
return File.ReadAllText(Helpers.GetExpectedLogName(deploymentResult, _logFolderPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,7 +24,6 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||||
private readonly bool _ownsSocket;
|
private readonly bool _ownsSocket;
|
||||||
private readonly Socket _socket;
|
private readonly Socket _socket;
|
||||||
private readonly NetworkStream _stream;
|
private readonly NetworkStream _stream;
|
||||||
private readonly StreamReader _reader;
|
|
||||||
|
|
||||||
public TestConnection(int port)
|
public TestConnection(int port)
|
||||||
: this(port, AddressFamily.InterNetwork)
|
: this(port, AddressFamily.InterNetwork)
|
||||||
|
|
@ -46,13 +45,10 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||||
_ownsSocket = ownsSocket;
|
_ownsSocket = ownsSocket;
|
||||||
_socket = socket;
|
_socket = socket;
|
||||||
_stream = new NetworkStream(_socket, ownsSocket: false);
|
_stream = new NetworkStream(_socket, ownsSocket: false);
|
||||||
_reader = new StreamReader(_stream, Encoding.ASCII);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Socket Socket => _socket;
|
public Socket Socket => _socket;
|
||||||
|
|
||||||
public StreamReader Reader => _reader;
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_stream.Dispose();
|
_stream.Dispose();
|
||||||
|
|
@ -79,50 +75,96 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||||
await _stream.FlushAsync().ConfigureAwait(false);
|
await _stream.FlushAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<int> ReadCharAsync()
|
||||||
|
{
|
||||||
|
var bytes = new byte[1];
|
||||||
|
return (await _stream.ReadAsync(bytes, 0, 1) == 1) ? bytes[0] : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> ReadLineAsync()
|
||||||
|
{
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
var current = await ReadCharAsync();
|
||||||
|
while (current != '\r')
|
||||||
|
{
|
||||||
|
builder.Append((char)current);
|
||||||
|
current = await ReadCharAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume \n
|
||||||
|
await ReadCharAsync();
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Memory<byte>> ReceiveChunk()
|
||||||
|
{
|
||||||
|
var length = int.Parse(await ReadLineAsync(), System.Globalization.NumberStyles.HexNumber);
|
||||||
|
|
||||||
|
var bytes = await Receive(length);
|
||||||
|
|
||||||
|
await ReadLineAsync();
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ReceiveChunk(string expected)
|
||||||
|
{
|
||||||
|
Assert.Equal(expected, Encoding.ASCII.GetString((await ReceiveChunk()).Span));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Receive(params string[] lines)
|
public async Task Receive(params string[] lines)
|
||||||
{
|
{
|
||||||
var expected = string.Join("\r\n", lines);
|
var expected = string.Join("\r\n", lines);
|
||||||
var actual = new char[expected.Length];
|
var actual = await Receive(expected.Length);
|
||||||
var offset = 0;
|
|
||||||
|
|
||||||
|
Assert.Equal(expected, Encoding.ASCII.GetString(actual.Span));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Memory<byte>> Receive(int length)
|
||||||
|
{
|
||||||
|
var actual = new byte[length];
|
||||||
|
int offset = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (offset < expected.Length)
|
while (offset < length)
|
||||||
{
|
{
|
||||||
var data = new byte[expected.Length];
|
var task = _stream.ReadAsync(actual, offset, actual.Length - offset);
|
||||||
var task = _reader.ReadAsync(actual, offset, actual.Length - offset);
|
|
||||||
if (!Debugger.IsAttached)
|
if (!Debugger.IsAttached)
|
||||||
{
|
{
|
||||||
task = task.TimeoutAfter(Timeout);
|
task = task.TimeoutAfter(Timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
var count = await task.ConfigureAwait(false);
|
var count = await task.ConfigureAwait(false);
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += count;
|
offset += count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (TimeoutException ex) when (offset != 0)
|
catch (TimeoutException ex) when (offset != 0)
|
||||||
{
|
{
|
||||||
throw new TimeoutException($"Did not receive a complete response within {Timeout}.{Environment.NewLine}{Environment.NewLine}" +
|
throw new TimeoutException(
|
||||||
$"Expected:{Environment.NewLine}{expected}{Environment.NewLine}{Environment.NewLine}" +
|
$"Did not receive a complete response within {Timeout}.{Environment.NewLine}{Environment.NewLine}" +
|
||||||
$"Actual:{Environment.NewLine}{new string(actual, 0, offset)}{Environment.NewLine}",
|
$"Expected:{Environment.NewLine}{length} bytes of data{Environment.NewLine}{Environment.NewLine}" +
|
||||||
|
$"Actual:{Environment.NewLine}{Encoding.ASCII.GetString(actual, 0, offset)}{Environment.NewLine}",
|
||||||
ex);
|
ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.Equal(expected, new string(actual, 0, offset));
|
return actual.AsMemory(0, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ReceiveStartsWith(string prefix, int maxLineLength = 1024)
|
public async Task ReceiveStartsWith(string prefix, int maxLineLength = 1024)
|
||||||
{
|
{
|
||||||
var actual = new char[maxLineLength];
|
var actual = new byte[maxLineLength];
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
|
|
||||||
while (offset < maxLineLength)
|
while (offset < maxLineLength)
|
||||||
{
|
{
|
||||||
// Read one char at a time so we don't read past the end of the line.
|
// Read one char at a time so we don't read past the end of the line.
|
||||||
var task = _reader.ReadAsync(actual, offset, 1);
|
var task = _stream.ReadAsync(actual, offset, 1);
|
||||||
if (!Debugger.IsAttached)
|
if (!Debugger.IsAttached)
|
||||||
{
|
{
|
||||||
Assert.True(task.Wait(4000), "timeout");
|
Assert.True(task.Wait(4000), "timeout");
|
||||||
|
|
@ -142,7 +184,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var actualLine = new string(actual, 0, offset);
|
var actualLine = Encoding.ASCII.GetString(actual, 0, offset);
|
||||||
Assert.StartsWith(prefix, actualLine);
|
Assert.StartsWith(prefix, actualLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,7 +194,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||||
string line;
|
string line;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
line = await _reader.ReadLineAsync();
|
line = await ReadLineAsync();
|
||||||
headers.Add(line);
|
headers.Add(line);
|
||||||
} while (line != "");
|
} while (line != "");
|
||||||
|
|
||||||
|
|
@ -190,7 +232,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tcs.SetException(new IOException(
|
tcs.SetException(new IOException(
|
||||||
$"Expected connection close, received data instead: \"{_reader.CurrentEncoding.GetString(e.Buffer, 0, e.BytesTransferred)}\""));
|
$"Expected connection close, received data instead: \"{Encoding.ASCII.GetString(e.Buffer, 0, e.BytesTransferred)}\""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,26 +15,15 @@ using Xunit;
|
||||||
namespace IIS.FunctionalTests.Inprocess
|
namespace IIS.FunctionalTests.Inprocess
|
||||||
{
|
{
|
||||||
[Collection(PublishedSitesCollection.Name)]
|
[Collection(PublishedSitesCollection.Name)]
|
||||||
public class StdOutRedirectionTests : IISFunctionalTestBase
|
public class StdOutRedirectionTests : LogFileTestBase
|
||||||
{
|
{
|
||||||
private readonly PublishedSitesFixture _fixture;
|
private readonly PublishedSitesFixture _fixture;
|
||||||
private readonly string _logFolderPath;
|
|
||||||
|
|
||||||
public StdOutRedirectionTests(PublishedSitesFixture fixture)
|
public StdOutRedirectionTests(PublishedSitesFixture fixture)
|
||||||
{
|
{
|
||||||
_logFolderPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
|
||||||
_fixture = fixture;
|
_fixture = fixture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
|
||||||
{
|
|
||||||
base.Dispose();
|
|
||||||
if (Directory.Exists(_logFolderPath))
|
|
||||||
{
|
|
||||||
Directory.Delete(_logFolderPath, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
[SkipIfDebug]
|
[SkipIfDebug]
|
||||||
public async Task FrameworkNotFoundExceptionLogged_Pipe()
|
public async Task FrameworkNotFoundExceptionLogged_Pipe()
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
private static readonly bool _isMetStatic;
|
private static readonly bool _isMetStatic;
|
||||||
private static readonly string _skipReasonStatic;
|
private static readonly string _skipReasonStatic;
|
||||||
|
|
||||||
private readonly bool _isMet;
|
|
||||||
private readonly string _skipReason;
|
|
||||||
|
|
||||||
private static readonly bool _websocketsAvailable;
|
private static readonly bool _websocketsAvailable;
|
||||||
private static readonly bool _windowsAuthAvailable;
|
private static readonly bool _windowsAuthAvailable;
|
||||||
private static readonly bool _poolEnvironmentVariablesAvailable;
|
private static readonly bool _poolEnvironmentVariablesAvailable;
|
||||||
|
private static readonly bool _dynamicCompressionAvailable;
|
||||||
|
|
||||||
static RequiresIISAttribute()
|
static RequiresIISAttribute()
|
||||||
{
|
{
|
||||||
|
|
@ -84,6 +82,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
|
||||||
_windowsAuthAvailable = File.Exists(Path.Combine(Environment.SystemDirectory, "inetsrv", "authsspi.dll"));
|
_windowsAuthAvailable = File.Exists(Path.Combine(Environment.SystemDirectory, "inetsrv", "authsspi.dll"));
|
||||||
|
|
||||||
|
_dynamicCompressionAvailable = File.Exists(Path.Combine(Environment.SystemDirectory, "inetsrv", "compdyn.dll"));
|
||||||
|
|
||||||
var iisRegistryKey = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\InetStp", writable: false);
|
var iisRegistryKey = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\InetStp", writable: false);
|
||||||
if (iisRegistryKey == null)
|
if (iisRegistryKey == null)
|
||||||
{
|
{
|
||||||
|
|
@ -98,47 +98,56 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public RequiresIISAttribute()
|
public RequiresIISAttribute()
|
||||||
: this (IISCapability.None) { }
|
: this (IISCapability.None) { }
|
||||||
|
|
||||||
public RequiresIISAttribute(IISCapability capabilities)
|
public RequiresIISAttribute(IISCapability capabilities)
|
||||||
{
|
{
|
||||||
_isMet = _isMetStatic;
|
IsMet = _isMetStatic;
|
||||||
_skipReason = _skipReasonStatic;
|
SkipReason = _skipReasonStatic;
|
||||||
if (capabilities.HasFlag(IISCapability.Websockets))
|
if (capabilities.HasFlag(IISCapability.Websockets))
|
||||||
{
|
{
|
||||||
_isMet &= _websocketsAvailable;
|
IsMet &= _websocketsAvailable;
|
||||||
if (!_websocketsAvailable)
|
if (!_websocketsAvailable)
|
||||||
{
|
{
|
||||||
_skipReason += "The machine does not have IIS websockets installed.";
|
SkipReason += "The machine does not have IIS websockets installed.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (capabilities.HasFlag(IISCapability.WindowsAuthentication))
|
if (capabilities.HasFlag(IISCapability.WindowsAuthentication))
|
||||||
{
|
{
|
||||||
_isMet &= _windowsAuthAvailable;
|
IsMet &= _windowsAuthAvailable;
|
||||||
|
|
||||||
if (!_windowsAuthAvailable)
|
if (!_windowsAuthAvailable)
|
||||||
{
|
{
|
||||||
_skipReason += "The machine does not have IIS windows authentication installed.";
|
SkipReason += "The machine does not have IIS windows authentication installed.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (capabilities.HasFlag(IISCapability.PoolEnvironmentVariables))
|
if (capabilities.HasFlag(IISCapability.PoolEnvironmentVariables))
|
||||||
{
|
{
|
||||||
_isMet &= _poolEnvironmentVariablesAvailable;
|
IsMet &= _poolEnvironmentVariablesAvailable;
|
||||||
if (!_poolEnvironmentVariablesAvailable)
|
if (!_poolEnvironmentVariablesAvailable)
|
||||||
{
|
{
|
||||||
_skipReason += "The machine does allow for setting environment variables on application pools.";
|
SkipReason += "The machine does allow for setting environment variables on application pools.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (capabilities.HasFlag(IISCapability.ShutdownToken))
|
if (capabilities.HasFlag(IISCapability.ShutdownToken))
|
||||||
{
|
{
|
||||||
_isMet = false;
|
IsMet = false;
|
||||||
_skipReason += "https://github.com/aspnet/IISIntegration/issues/1074";
|
SkipReason += "https://github.com/aspnet/IISIntegration/issues/1074";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (capabilities.HasFlag(IISCapability.DynamicCompression))
|
||||||
|
{
|
||||||
|
IsMet &= _dynamicCompressionAvailable;
|
||||||
|
if (!_dynamicCompressionAvailable)
|
||||||
|
{
|
||||||
|
SkipReason += "The machine does not have IIS dynamic compression installed.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsMet => _isMet;
|
public bool IsMet { get; }
|
||||||
public string SkipReason => _skipReason;
|
public string SkipReason { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
// 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.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
||||||
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
{
|
||||||
|
[Collection(PublishedSitesCollection.Name)]
|
||||||
|
public class HttpsTests : IISFunctionalTestBase
|
||||||
|
{
|
||||||
|
private readonly PublishedSitesFixture _fixture;
|
||||||
|
|
||||||
|
public HttpsTests(PublishedSitesFixture fixture)
|
||||||
|
{
|
||||||
|
_fixture = fixture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TestMatrix TestVariants
|
||||||
|
=> TestMatrix.ForServers(DeployerSelector.ServerType)
|
||||||
|
.WithTfms(Tfm.NetCoreApp22, Tfm.Net461)
|
||||||
|
.WithAllApplicationTypes()
|
||||||
|
.WithAllAncmVersions()
|
||||||
|
.WithAllHostingModels();
|
||||||
|
|
||||||
|
[ConditionalTheory]
|
||||||
|
[MemberData(nameof(TestVariants))]
|
||||||
|
public async Task HttpsHelloWorld(TestVariant variant)
|
||||||
|
{
|
||||||
|
var port = TestPortHelper.GetNextSSLPort();
|
||||||
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant);
|
||||||
|
deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/";
|
||||||
|
deploymentParameters.AddHttpsToServerConfig();
|
||||||
|
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
|
var handler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = (a, b, c, d) => true
|
||||||
|
};
|
||||||
|
var client = deploymentResult.CreateClient(handler);
|
||||||
|
var response = await client.GetAsync("HttpsHelloWorld");
|
||||||
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
if (variant.HostingModel == HostingModel.OutOfProcess)
|
||||||
|
{
|
||||||
|
Assert.Equal("Scheme:https; Original:http", responseText);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.Equal("Scheme:https; Original:", responseText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
|
||||||
public WebSocketsTests(IISTestSiteFixture fixture)
|
public WebSocketsTests(IISTestSiteFixture fixture)
|
||||||
{
|
{
|
||||||
_webSocketUri = fixture.BaseUri.Replace("http:", "ws:");
|
_webSocketUri = fixture.DeploymentResult.ApplicationBaseUri.Replace("http:", "ws:");
|
||||||
}
|
}
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
|
|
|
||||||
|
|
@ -1,148 +0,0 @@
|
||||||
// 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.Net.Http;
|
|
||||||
using System.Security.Cryptography.X509Certificates;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
|
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
|
||||||
using Xunit;
|
|
||||||
using Xunit.Abstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|
||||||
{
|
|
||||||
// IIS Express preregisteres 44300-44399 ports with SSL bindings.
|
|
||||||
// So these tests always have to use ports in this range, and we can't rely on OS-allocated ports without a whole lot of ceremony around
|
|
||||||
// creating self-signed certificates and registering SSL bindings with HTTP.sys
|
|
||||||
// Test specific to IISExpress
|
|
||||||
[Collection(PublishedSitesCollection.Name)]
|
|
||||||
public class HttpsTest : IISFunctionalTestBase
|
|
||||||
{
|
|
||||||
private readonly PublishedSitesFixture _fixture;
|
|
||||||
|
|
||||||
public HttpsTest(PublishedSitesFixture fixture)
|
|
||||||
{
|
|
||||||
_fixture = fixture;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TestMatrix TestVariants
|
|
||||||
=> TestMatrix.ForServers(DeployerSelector.ServerType)
|
|
||||||
.WithTfms(Tfm.NetCoreApp22, Tfm.Net461)
|
|
||||||
.WithAllAncmVersions();
|
|
||||||
|
|
||||||
[ConditionalTheory]
|
|
||||||
[MemberData(nameof(TestVariants))]
|
|
||||||
public async Task HttpsHelloWorld(TestVariant variant)
|
|
||||||
{
|
|
||||||
var port = TestPortHelper.GetNextSSLPort();
|
|
||||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant);
|
|
||||||
deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/";
|
|
||||||
deploymentParameters.AddHttpsToServerConfig();
|
|
||||||
|
|
||||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
|
||||||
|
|
||||||
var handler = new HttpClientHandler
|
|
||||||
{
|
|
||||||
ServerCertificateCustomValidationCallback = (a, b, c, d) => true
|
|
||||||
};
|
|
||||||
var client = deploymentResult.CreateClient(handler);
|
|
||||||
var response = await client.GetAsync("HttpsHelloWorld");
|
|
||||||
var responseText = await response.Content.ReadAsStringAsync();
|
|
||||||
Assert.Equal("Scheme:https; Original:http", responseText);
|
|
||||||
}
|
|
||||||
|
|
||||||
[ConditionalTheory]
|
|
||||||
[MemberData(nameof(TestVariants))]
|
|
||||||
public Task HttpsHelloWorld_NoClientCert(TestVariant variant)
|
|
||||||
{
|
|
||||||
return HttpsHelloWorldCerts(variant, sendClientCert: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable xUnit1004 // Test methods should not be skipped
|
|
||||||
[ConditionalTheory(Skip = "Manual test only, selecting a client cert is non-determanistic on different machines.")]
|
|
||||||
[MemberData(nameof(TestVariants))]
|
|
||||||
#pragma warning restore xUnit1004 // Test methods should not be skipped
|
|
||||||
public Task HttpsHelloWorld_ClientCert(TestVariant variant)
|
|
||||||
{
|
|
||||||
return HttpsHelloWorldCerts(variant, sendClientCert: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task HttpsHelloWorldCerts(TestVariant variant, bool sendClientCert)
|
|
||||||
{
|
|
||||||
var port = TestPortHelper.GetNextSSLPort();
|
|
||||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant);
|
|
||||||
deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/";
|
|
||||||
deploymentParameters.AddHttpsToServerConfig();
|
|
||||||
|
|
||||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
|
||||||
|
|
||||||
var handler = new HttpClientHandler
|
|
||||||
{
|
|
||||||
ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
|
|
||||||
ClientCertificateOptions = ClientCertificateOption.Manual
|
|
||||||
};
|
|
||||||
|
|
||||||
if (sendClientCert)
|
|
||||||
{
|
|
||||||
X509Certificate2 clientCert = FindClientCert();
|
|
||||||
Assert.NotNull(clientCert);
|
|
||||||
handler.ClientCertificates.Add(clientCert);
|
|
||||||
}
|
|
||||||
|
|
||||||
var client = deploymentResult.CreateClient(handler);
|
|
||||||
|
|
||||||
// Request to base address and check if various parts of the body are rendered & measure the cold startup time.
|
|
||||||
var response = await client.GetAsync("checkclientcert");
|
|
||||||
|
|
||||||
var responseText = await response.Content.ReadAsStringAsync();
|
|
||||||
if (sendClientCert)
|
|
||||||
{
|
|
||||||
Assert.Equal("Scheme:https; Original:http; has cert? True", responseText);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Assert.Equal("Scheme:https; Original:http; has cert? False", responseText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private X509Certificate2 FindClientCert()
|
|
||||||
{
|
|
||||||
var store = new X509Store();
|
|
||||||
store.Open(OpenFlags.ReadOnly);
|
|
||||||
|
|
||||||
foreach (var cert in store.Certificates)
|
|
||||||
{
|
|
||||||
bool isClientAuth = false;
|
|
||||||
bool isSmartCard = false;
|
|
||||||
foreach (var extension in cert.Extensions)
|
|
||||||
{
|
|
||||||
var eku = extension as X509EnhancedKeyUsageExtension;
|
|
||||||
if (eku != null)
|
|
||||||
{
|
|
||||||
foreach (var oid in eku.EnhancedKeyUsages)
|
|
||||||
{
|
|
||||||
if (oid.FriendlyName == "Client Authentication")
|
|
||||||
{
|
|
||||||
isClientAuth = true;
|
|
||||||
}
|
|
||||||
else if (oid.FriendlyName == "Smart Card Logon")
|
|
||||||
{
|
|
||||||
isSmartCard = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isClientAuth && !isSmartCard)
|
|
||||||
{
|
|
||||||
return cert;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -26,7 +26,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
=> TestMatrix.ForServers(DeployerSelector.ServerType)
|
=> TestMatrix.ForServers(DeployerSelector.ServerType)
|
||||||
.WithTfms(Tfm.NetCoreApp22, Tfm.Net461)
|
.WithTfms(Tfm.NetCoreApp22, Tfm.Net461)
|
||||||
.WithAllApplicationTypes()
|
.WithAllApplicationTypes()
|
||||||
.WithAllAncmVersions();
|
.WithAllAncmVersions()
|
||||||
|
.WithAllHostingModels();
|
||||||
|
|
||||||
[ConditionalTheory]
|
[ConditionalTheory]
|
||||||
[MemberData(nameof(TestVariants))]
|
[MemberData(nameof(TestVariants))]
|
||||||
|
|
@ -41,7 +42,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
var response = await deploymentResult.HttpClient.GetAsync("/Auth");
|
var response = await deploymentResult.HttpClient.GetAsync("/Auth");
|
||||||
var responseText = await response.Content.ReadAsStringAsync();
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
Assert.True("backcompat;Windows".Equals(responseText) || "latest;Windows".Equals(responseText), "Auth");
|
Assert.Equal("Windows", responseText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -30,7 +30,13 @@ namespace TestSite
|
||||||
private async Task ServerVariable(HttpContext ctx)
|
private async Task ServerVariable(HttpContext ctx)
|
||||||
{
|
{
|
||||||
var varName = ctx.Request.Query["q"];
|
var varName = ctx.Request.Query["q"];
|
||||||
await ctx.Response.WriteAsync($"{varName}: {ctx.GetIISServerVariable(varName) ?? "(null)"}");
|
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)
|
private async Task AuthenticationAnonymous(HttpContext ctx)
|
||||||
|
|
@ -321,6 +327,11 @@ namespace TestSite
|
||||||
|
|
||||||
private async Task ReadAndWriteEchoLines(HttpContext ctx)
|
private async Task ReadAndWriteEchoLines(HttpContext ctx)
|
||||||
{
|
{
|
||||||
|
if (ctx.Request.Headers.TryGetValue("Response-Content-Type", out var contentType))
|
||||||
|
{
|
||||||
|
ctx.Response.ContentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
//Send headers
|
//Send headers
|
||||||
await ctx.Response.Body.FlushAsync();
|
await ctx.Response.Body.FlushAsync();
|
||||||
|
|
||||||
|
|
@ -337,6 +348,31 @@ namespace TestSite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
private async Task ReadPartialBody(HttpContext ctx)
|
||||||
{
|
{
|
||||||
var data = new byte[5];
|
var data = new byte[5];
|
||||||
|
|
@ -631,10 +667,11 @@ namespace TestSite
|
||||||
// executed on background thread while request thread calls GetServerVariable
|
// executed on background thread while request thread calls GetServerVariable
|
||||||
// concurrent native calls may cause native object corruption
|
// concurrent native calls may cause native object corruption
|
||||||
|
|
||||||
|
var serverVariableFeature = ctx.Features.Get<IServerVariablesFeature>();
|
||||||
await ctx.Response.WriteAsync("Response Begin");
|
await ctx.Response.WriteAsync("Response Begin");
|
||||||
for (int i = 0; i < 1000; i++)
|
for (int i = 0; i < 1000; i++)
|
||||||
{
|
{
|
||||||
await ctx.Response.WriteAsync(ctx.GetIISServerVariable("REMOTE_PORT"));
|
await ctx.Response.WriteAsync(serverVariableFeature["REMOTE_PORT"]);
|
||||||
await ctx.Response.Body.FlushAsync();
|
await ctx.Response.Body.FlushAsync();
|
||||||
}
|
}
|
||||||
await ctx.Response.WriteAsync("Response End");
|
await ctx.Response.WriteAsync("Response End");
|
||||||
|
|
@ -644,5 +681,8 @@ namespace TestSite
|
||||||
{
|
{
|
||||||
await ctx.Response.WriteAsync(string.Join("|", Environment.GetCommandLineArgs().Skip(1)));
|
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"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,30 +36,12 @@ namespace TestSite
|
||||||
|
|
||||||
public Task BodyLimit(HttpContext ctx) => ctx.Response.WriteAsync(ctx.Features.Get<IHttpMaxRequestBodySizeFeature>()?.MaxRequestBodySize?.ToString() ?? "null");
|
public Task BodyLimit(HttpContext ctx) => ctx.Response.WriteAsync(ctx.Features.Get<IHttpMaxRequestBodySizeFeature>()?.MaxRequestBodySize?.ToString() ?? "null");
|
||||||
|
|
||||||
public async Task Auth(HttpContext ctx)
|
|
||||||
{
|
|
||||||
var iisAuth = Environment.GetEnvironmentVariable("ASPNETCORE_IIS_HTTPAUTH");
|
|
||||||
var authProvider = ctx.RequestServices.GetService<IAuthenticationSchemeProvider>();
|
|
||||||
var authScheme = (await authProvider.GetAllSchemesAsync()).SingleOrDefault();
|
|
||||||
if (string.IsNullOrEmpty(iisAuth))
|
|
||||||
{
|
|
||||||
await ctx.Response.WriteAsync("backcompat;" + (authScheme?.Name ?? "null"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await ctx.Response.WriteAsync("latest;" + (authScheme?.Name ?? "null"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task HelloWorld(HttpContext ctx) => ctx.Response.WriteAsync("Hello World");
|
public Task HelloWorld(HttpContext ctx) => ctx.Response.WriteAsync("Hello World");
|
||||||
|
|
||||||
public Task HttpsHelloWorld(HttpContext ctx) =>
|
public Task HttpsHelloWorld(HttpContext ctx) =>
|
||||||
ctx.Response.WriteAsync("Scheme:" + ctx.Request.Scheme + "; Original:" + ctx.Request.Headers["x-original-proto"]);
|
ctx.Response.WriteAsync("Scheme:" + ctx.Request.Scheme + "; Original:" + ctx.Request.Headers["x-original-proto"]);
|
||||||
|
|
||||||
public Task CheckClientCert(HttpContext ctx) =>
|
|
||||||
ctx.Response.WriteAsync("Scheme:" + ctx.Request.Scheme + "; Original:" + ctx.Request.Headers["x-original-proto"]
|
|
||||||
+ "; has cert? " + (ctx.Connection.ClientCertificate != null));
|
|
||||||
|
|
||||||
public Task Anonymous(HttpContext context) => context.Response.WriteAsync("Anonymous?" + !context.User.Identity.IsAuthenticated);
|
public Task Anonymous(HttpContext context) => context.Response.WriteAsync("Anonymous?" + !context.User.Identity.IsAuthenticated);
|
||||||
|
|
||||||
public Task Restricted(HttpContext context)
|
public Task Restricted(HttpContext context)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
@ -33,5 +35,19 @@ namespace TestSite
|
||||||
|
|
||||||
await ctx.Response.WriteAsync("Hello World");
|
await ctx.Response.WriteAsync("Hello World");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task Auth(HttpContext ctx)
|
||||||
|
{
|
||||||
|
var authProvider = ctx.RequestServices.GetService<IAuthenticationSchemeProvider>();
|
||||||
|
var authScheme = (await authProvider.GetAllSchemesAsync()).SingleOrDefault();
|
||||||
|
|
||||||
|
await ctx.Response.WriteAsync(authScheme?.Name ?? "null");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task GetClientCert(HttpContext context)
|
||||||
|
{
|
||||||
|
var clientCert = context.Connection.ClientCertificate;
|
||||||
|
await context.Response.WriteAsync(clientCert != null ? $"Enabled;{clientCert.GetCertHashString()}" : "Disabled");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue