Merge aspnet/HttpAbstractions release/2.2

This commit is contained in:
Nate McMaster 2018-11-20 09:15:59 -08:00
commit 0f64aa5c01
No known key found for this signature in database
GPG Key ID: A778D9601BD78810
45 changed files with 599 additions and 170 deletions

View File

@ -4,6 +4,24 @@
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects> <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<AspNetCoreBaselineVersion>2.2.0</AspNetCoreBaselineVersion> <AspNetCoreBaselineVersion>2.2.0</AspNetCoreBaselineVersion>
</PropertyGroup> </PropertyGroup>
<!-- Package: Microsoft.AspNetCore.Authentication.Abstractions-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Authentication.Abstractions' ">
<BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Authentication.Abstractions' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.2.0, )" />
</ItemGroup>
<!-- Package: Microsoft.AspNetCore.Authentication.Core-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Authentication.Core' ">
<BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Authentication.Core' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.Authentication.Abstractions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.AspNetCore.Http" Version="[2.2.0, )" />
</ItemGroup>
<!-- Package: Microsoft.AspNetCore.Connections.Abstractions--> <!-- Package: Microsoft.AspNetCore.Connections.Abstractions-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Connections.Abstractions' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Connections.Abstractions' ">
<BaselinePackageVersion>2.2.0</BaselinePackageVersion> <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
@ -98,48 +116,48 @@
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.Hosting.Abstractions--> <!-- Package: Microsoft.AspNetCore.Hosting.Abstractions-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.Abstractions' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.Abstractions' ">
<BaselinePackageVersion>2.1.1</BaselinePackageVersion> <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.Abstractions' AND '$(TargetFramework)' == 'netstandard2.0' "> <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.Abstractions' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="[2.2.0, )" />
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.Hosting.Server.Abstractions--> <!-- Package: Microsoft.AspNetCore.Hosting.Server.Abstractions-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.Server.Abstractions' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.Server.Abstractions' ">
<BaselinePackageVersion>2.1.1</BaselinePackageVersion> <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.Server.Abstractions' AND '$(TargetFramework)' == 'netstandard2.0' "> <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.Server.Abstractions' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.Http.Features" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.Http.Features" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="[2.2.0, )" />
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.Hosting.WindowsServices--> <!-- Package: Microsoft.AspNetCore.Hosting.WindowsServices-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.WindowsServices' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.WindowsServices' ">
<BaselinePackageVersion>2.1.1</BaselinePackageVersion> <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.WindowsServices' AND '$(TargetFramework)' == 'net461' "> <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.WindowsServices' AND '$(TargetFramework)' == 'net461' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.Hosting" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.Hosting" Version="[2.2.0, )" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.WindowsServices' AND '$(TargetFramework)' == 'netstandard2.0' "> <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting.WindowsServices' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.Hosting" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.Hosting" Version="[2.2.0, )" />
<BaselinePackageReference Include="System.ServiceProcess.ServiceController" Version="[4.5.0, )" /> <BaselinePackageReference Include="System.ServiceProcess.ServiceController" Version="[4.5.0, )" />
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.Hosting--> <!-- Package: Microsoft.AspNetCore.Hosting-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting' ">
<BaselinePackageVersion>2.1.1</BaselinePackageVersion> <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting' AND '$(TargetFramework)' == 'netstandard2.0' "> <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.AspNetCore.Http" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.Http" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Configuration" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.Configuration" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.DependencyInjection" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.DependencyInjection" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Logging" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.Logging" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.2.0, )" />
<BaselinePackageReference Include="System.Diagnostics.DiagnosticSource" Version="[4.5.0, )" /> <BaselinePackageReference Include="System.Diagnostics.DiagnosticSource" Version="[4.5.0, )" />
<BaselinePackageReference Include="System.Reflection.Metadata" Version="[1.6.0, )" /> <BaselinePackageReference Include="System.Reflection.Metadata" Version="[1.6.0, )" />
</ItemGroup> </ItemGroup>
@ -152,39 +170,39 @@
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.Http.Abstractions--> <!-- Package: Microsoft.AspNetCore.Http.Abstractions-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http.Abstractions' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http.Abstractions' ">
<BaselinePackageVersion>2.1.1</BaselinePackageVersion> <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http.Abstractions' AND '$(TargetFramework)' == 'netstandard2.0' "> <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http.Abstractions' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.Http.Features" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.Http.Features" Version="[2.2.0, )" />
<BaselinePackageReference Include="System.Text.Encodings.Web" Version="[4.5.0, )" /> <BaselinePackageReference Include="System.Text.Encodings.Web" Version="[4.5.0, )" />
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.Http.Extensions--> <!-- Package: Microsoft.AspNetCore.Http.Extensions-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http.Extensions' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http.Extensions' ">
<BaselinePackageVersion>2.1.1</BaselinePackageVersion> <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http.Extensions' AND '$(TargetFramework)' == 'netstandard2.0' "> <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http.Extensions' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Net.Http.Headers" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Net.Http.Headers" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.FileProviders.Abstractions" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.FileProviders.Abstractions" Version="[2.2.0, )" />
<BaselinePackageReference Include="System.Buffers" Version="[4.5.0, )" /> <BaselinePackageReference Include="System.Buffers" Version="[4.5.0, )" />
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.Http.Features--> <!-- Package: Microsoft.AspNetCore.Http.Features-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http.Features' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http.Features' ">
<BaselinePackageVersion>2.1.1</BaselinePackageVersion> <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http.Features' AND '$(TargetFramework)' == 'netstandard2.0' "> <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http.Features' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.Extensions.Primitives" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.Primitives" Version="[2.2.0, )" />
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.Http--> <!-- Package: Microsoft.AspNetCore.Http-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http' ">
<BaselinePackageVersion>2.1.1</BaselinePackageVersion> <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http' AND '$(TargetFramework)' == 'netstandard2.0' "> <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Http' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Net.Http.Headers" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Net.Http.Headers" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.ObjectPool" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.ObjectPool" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.2.0, )" />
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.JsonPatch--> <!-- Package: Microsoft.AspNetCore.JsonPatch-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.JsonPatch' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.JsonPatch' ">
@ -196,10 +214,10 @@
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.Owin--> <!-- Package: Microsoft.AspNetCore.Owin-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Owin' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Owin' ">
<BaselinePackageVersion>2.1.1</BaselinePackageVersion> <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Owin' AND '$(TargetFramework)' == 'netstandard2.0' "> <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Owin' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.Http" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.Http" Version="[2.2.0, )" />
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.Server.Kestrel.Core--> <!-- Package: Microsoft.AspNetCore.Server.Kestrel.Core-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Core' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Core' ">
@ -291,11 +309,11 @@
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.TestHost--> <!-- Package: Microsoft.AspNetCore.TestHost-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.TestHost' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.TestHost' ">
<BaselinePackageVersion>2.1.1</BaselinePackageVersion> <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.TestHost' AND '$(TargetFramework)' == 'netstandard2.0' "> <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.TestHost' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.Hosting" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.AspNetCore.Hosting" Version="[2.2.0, )" />
<BaselinePackageReference Include="System.IO.Pipelines" Version="[4.5.0, )" /> <BaselinePackageReference Include="System.IO.Pipelines" Version="[4.5.2, )" />
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.WebSockets--> <!-- Package: Microsoft.AspNetCore.WebSockets-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.WebSockets' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.WebSockets' ">
@ -309,18 +327,18 @@
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.AspNetCore.WebUtilities--> <!-- Package: Microsoft.AspNetCore.WebUtilities-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.WebUtilities' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.WebUtilities' ">
<BaselinePackageVersion>2.1.1</BaselinePackageVersion> <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.WebUtilities' AND '$(TargetFramework)' == 'netstandard2.0' "> <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.WebUtilities' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.Net.Http.Headers" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Net.Http.Headers" Version="[2.2.0, )" />
<BaselinePackageReference Include="System.Text.Encodings.Web" Version="[4.5.0, )" /> <BaselinePackageReference Include="System.Text.Encodings.Web" Version="[4.5.0, )" />
</ItemGroup> </ItemGroup>
<!-- Package: Microsoft.Net.Http.Headers--> <!-- Package: Microsoft.Net.Http.Headers-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.Net.Http.Headers' "> <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.Net.Http.Headers' ">
<BaselinePackageVersion>2.1.1</BaselinePackageVersion> <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.Net.Http.Headers' AND '$(TargetFramework)' == 'netstandard2.0' "> <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.Net.Http.Headers' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.Extensions.Primitives" Version="[2.1.1, )" /> <BaselinePackageReference Include="Microsoft.Extensions.Primitives" Version="[2.2.0, )" />
<BaselinePackageReference Include="System.Buffers" Version="[4.5.0, )" /> <BaselinePackageReference Include="System.Buffers" Version="[4.5.0, )" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Authentication
/// Returns all of the AuthenticationTokens contained in the properties. /// Returns all of the AuthenticationTokens contained in the properties.
/// </summary> /// </summary>
/// <param name="properties">The <see cref="AuthenticationProperties"/> properties.</param> /// <param name="properties">The <see cref="AuthenticationProperties"/> properties.</param>
/// <returns>The authentication toekns.</returns> /// <returns>The authentication tokens.</returns>
public static IEnumerable<AuthenticationToken> GetTokens(this AuthenticationProperties properties) public static IEnumerable<AuthenticationToken> GetTokens(this AuthenticationProperties properties)
{ {
if (properties == null) if (properties == null)
@ -132,7 +132,7 @@ namespace Microsoft.AspNetCore.Authentication
/// <param name="context">The <see cref="HttpContext"/> context.</param> /// <param name="context">The <see cref="HttpContext"/> context.</param>
/// <param name="tokenName">The name of the token.</param> /// <param name="tokenName">The name of the token.</param>
/// <returns>The value of the token.</returns> /// <returns>The value of the token.</returns>
public static Task<string> GetTokenAsync(this IAuthenticationService auth, HttpContext context, string tokenName) public static Task<string> GetTokenAsync(this IAuthenticationService auth, HttpContext context, string tokenName)
=> auth.GetTokenAsync(context, scheme: null, tokenName: tokenName); => auth.GetTokenAsync(context, scheme: null, tokenName: tokenName);
/// <summary> /// <summary>

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -49,6 +50,9 @@ namespace Microsoft.AspNetCore.Authentication
private readonly IDictionary<string, AuthenticationScheme> _schemes; private readonly IDictionary<string, AuthenticationScheme> _schemes;
private readonly List<AuthenticationScheme> _requestHandlers; private readonly List<AuthenticationScheme> _requestHandlers;
// Used as a safe return value for enumeration apis
private IEnumerable<AuthenticationScheme> _schemesCopy = Array.Empty<AuthenticationScheme>();
private IEnumerable<AuthenticationScheme> _requestHandlersCopy = Array.Empty<AuthenticationScheme>();
private Task<AuthenticationScheme> GetDefaultSchemeAsync() private Task<AuthenticationScheme> GetDefaultSchemeAsync()
=> _options.DefaultScheme != null => _options.DefaultScheme != null
@ -102,7 +106,7 @@ namespace Microsoft.AspNetCore.Authentication
/// <summary> /// <summary>
/// Returns the scheme that will be used by default for <see cref="IAuthenticationService.SignOutAsync(HttpContext, string, AuthenticationProperties)"/>. /// Returns the scheme that will be used by default for <see cref="IAuthenticationService.SignOutAsync(HttpContext, string, AuthenticationProperties)"/>.
/// This is typically specified via <see cref="AuthenticationOptions.DefaultSignOutScheme"/>. /// This is typically specified via <see cref="AuthenticationOptions.DefaultSignOutScheme"/>.
/// Otherwise this will fallback to <see cref="GetDefaultSignInSchemeAsync"/> if that supoorts sign out. /// Otherwise this will fallback to <see cref="GetDefaultSignInSchemeAsync"/> if that supports sign out.
/// </summary> /// </summary>
/// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.SignOutAsync(HttpContext, string, AuthenticationProperties)"/>.</returns> /// <returns>The scheme that will be used by default for <see cref="IAuthenticationService.SignOutAsync(HttpContext, string, AuthenticationProperties)"/>.</returns>
public virtual Task<AuthenticationScheme> GetDefaultSignOutSchemeAsync() public virtual Task<AuthenticationScheme> GetDefaultSignOutSchemeAsync()
@ -123,7 +127,7 @@ namespace Microsoft.AspNetCore.Authentication
/// </summary> /// </summary>
/// <returns>The schemes in priority order for request handling</returns> /// <returns>The schemes in priority order for request handling</returns>
public virtual Task<IEnumerable<AuthenticationScheme>> GetRequestHandlerSchemesAsync() public virtual Task<IEnumerable<AuthenticationScheme>> GetRequestHandlerSchemesAsync()
=> Task.FromResult<IEnumerable<AuthenticationScheme>>(_requestHandlers); => Task.FromResult(_requestHandlersCopy);
/// <summary> /// <summary>
/// Registers a scheme for use by <see cref="IAuthenticationService"/>. /// Registers a scheme for use by <see cref="IAuthenticationService"/>.
@ -144,8 +148,10 @@ namespace Microsoft.AspNetCore.Authentication
if (typeof(IAuthenticationRequestHandler).IsAssignableFrom(scheme.HandlerType)) if (typeof(IAuthenticationRequestHandler).IsAssignableFrom(scheme.HandlerType))
{ {
_requestHandlers.Add(scheme); _requestHandlers.Add(scheme);
_requestHandlersCopy = _requestHandlers.ToArray();
} }
_schemes[scheme.Name] = scheme; _schemes[scheme.Name] = scheme;
_schemesCopy = _schemes.Values.ToArray();
} }
} }
@ -164,13 +170,17 @@ namespace Microsoft.AspNetCore.Authentication
if (_schemes.ContainsKey(name)) if (_schemes.ContainsKey(name))
{ {
var scheme = _schemes[name]; var scheme = _schemes[name];
_requestHandlers.Remove(scheme); if (_requestHandlers.Remove(scheme))
{
_requestHandlersCopy = _requestHandlers.ToArray();
}
_schemes.Remove(name); _schemes.Remove(name);
_schemesCopy = _schemes.Values.ToArray();
} }
} }
} }
public virtual Task<IEnumerable<AuthenticationScheme>> GetAllSchemesAsync() public virtual Task<IEnumerable<AuthenticationScheme>> GetAllSchemesAsync()
=> Task.FromResult<IEnumerable<AuthenticationScheme>>(_schemes.Values); => Task.FromResult(_schemesCopy);
} }
} }

View File

@ -155,7 +155,7 @@ namespace Microsoft.Net.Http.Headers
{ {
if (!StringSegment.IsNullOrEmpty(fileName)) if (!StringSegment.IsNullOrEmpty(fileName))
{ {
FileName = Sanatize(fileName); FileName = Sanitize(fileName);
} }
else else
{ {
@ -166,7 +166,7 @@ namespace Microsoft.Net.Http.Headers
/// <summary> /// <summary>
/// Sets the FileName parameter using encodings appropriate for MIME headers. /// Sets the FileName parameter using encodings appropriate for MIME headers.
/// The FileNameStar paraemter is removed. /// The FileNameStar parameter is removed.
/// </summary> /// </summary>
/// <param name="fileName"></param> /// <param name="fileName"></param>
public void SetMimeFileName(StringSegment fileName) public void SetMimeFileName(StringSegment fileName)
@ -434,7 +434,7 @@ namespace Microsoft.Net.Http.Headers
} }
// Replaces characters not suitable for HTTP headers with '_' rather than MIME encoding them. // Replaces characters not suitable for HTTP headers with '_' rather than MIME encoding them.
private StringSegment Sanatize(StringSegment input) private StringSegment Sanitize(StringSegment input)
{ {
var result = input; var result = input;

View File

@ -143,7 +143,7 @@ namespace Microsoft.Net.Http.Headers
} }
} }
// Since we never re-use a "found" value in 'y', we expecte 'alreadyFound' to have all fields set to 'true'. // Since we never re-use a "found" value in 'y', we expected 'alreadyFound' to have all fields set to 'true'.
// Otherwise the two collections can't be equal and we should not get here. // Otherwise the two collections can't be equal and we should not get here.
Contract.Assert(Contract.ForAll(alreadyFound, value => { return value; }), Contract.Assert(Contract.ForAll(alreadyFound, value => { return value; }),
"Expected all values in 'alreadyFound' to be true since collections are considered equal."); "Expected all values in 'alreadyFound' to be true since collections are considered equal.");

View File

@ -225,7 +225,7 @@ namespace Microsoft.Net.Http.Headers
return HttpParseResult.NotParsed; return HttpParseResult.NotParsed;
} }
// Quoted-char has 2 characters. Check wheter there are 2 chars left ('\' + char) // Quoted-char has 2 characters. Check whether there are 2 chars left ('\' + char)
// If so, check whether the character is in the range 0-127. If not, it's an invalid value. // If so, check whether the character is in the range 0-127. If not, it's an invalid value.
if ((startIndex + 2 > input.Length) || (input[startIndex + 1] > 127)) if ((startIndex + 2 > input.Length) || (input[startIndex + 1] > 127))
{ {

View File

@ -650,6 +650,7 @@ namespace Microsoft.Net.Http.Headers
{ {
return true; return true;
} }
if (set.Suffix.HasValue) if (set.Suffix.HasValue)
{ {
if (Suffix.HasValue) if (Suffix.HasValue)
@ -663,7 +664,10 @@ namespace Microsoft.Net.Http.Headers
} }
else else
{ {
return set.SubType.Equals(SubType, StringComparison.OrdinalIgnoreCase); // If this subtype or suffix matches the subtype of the set,
// it is considered a subtype.
// Ex: application/json > application/val+json
return MatchesEitherSubtypeOrSuffix(set);
} }
} }
@ -673,6 +677,12 @@ namespace Microsoft.Net.Http.Headers
set.SubTypeWithoutSuffix.Equals(SubTypeWithoutSuffix, StringComparison.OrdinalIgnoreCase); set.SubTypeWithoutSuffix.Equals(SubTypeWithoutSuffix, StringComparison.OrdinalIgnoreCase);
} }
private bool MatchesEitherSubtypeOrSuffix(MediaTypeHeaderValue set)
{
return set.SubType.Equals(SubType, StringComparison.OrdinalIgnoreCase) ||
set.SubType.Equals(Suffix, StringComparison.OrdinalIgnoreCase);
}
private bool MatchesParameters(MediaTypeHeaderValue set) private bool MatchesParameters(MediaTypeHeaderValue set)
{ {
if (set._parameters != null && set._parameters.Count != 0) if (set._parameters != null && set._parameters.Count != 0)

View File

@ -169,7 +169,7 @@ namespace Microsoft.Net.Http.Headers
current = current + fromLength; current = current + fromLength;
current = current + HttpRuleParser.GetWhitespaceLength(input, current); current = current + HttpRuleParser.GetWhitespaceLength(input, current);
// Afer the first value, the '-' character must follow. // After the first value, the '-' character must follow.
if ((current == input.Length) || (input[current] != '-')) if ((current == input.Length) || (input[current] != '-'))
{ {
// We need a '-' character otherwise this can't be a valid range. // We need a '-' character otherwise this can't be a valid range.

View File

@ -465,7 +465,7 @@ namespace Microsoft.Net.Http.Headers
{ {
{ "inline", new ContentDispositionHeaderValue("inline") }, // @"This should be equivalent to not including the header at all." { "inline", new ContentDispositionHeaderValue("inline") }, // @"This should be equivalent to not including the header at all."
{ "inline;", new ContentDispositionHeaderValue("inline") }, { "inline;", new ContentDispositionHeaderValue("inline") },
{ "inline;name=", new ContentDispositionHeaderValue("inline") { Parameters = { new NameValueHeaderValue("name", "") } } }, // TODO: passing in a null value causes a strange assert on CoreCLR before the test even starts. Not reproducable in the body of a test. { "inline;name=", new ContentDispositionHeaderValue("inline") { Parameters = { new NameValueHeaderValue("name", "") } } }, // TODO: passing in a null value causes a strange assert on CoreCLR before the test even starts. Not reproducible in the body of a test.
{ "inline;name=value", new ContentDispositionHeaderValue("inline") { Name = "value" } }, { "inline;name=value", new ContentDispositionHeaderValue("inline") { Name = "value" } },
{ "inline;name=value;", new ContentDispositionHeaderValue("inline") { Name = "value" } }, { "inline;name=value;", new ContentDispositionHeaderValue("inline") { Name = "value" } },
{ "inline;name=value;", new ContentDispositionHeaderValue("inline") { Name = "value" } }, { "inline;name=value;", new ContentDispositionHeaderValue("inline") { Name = "value" } },

View File

@ -286,7 +286,7 @@ namespace Microsoft.Net.Http.Headers
public void CookieHeaderValue_ParseList_ExcludesInvalidValues(IList<CookieHeaderValue> cookies, string[] input) public void CookieHeaderValue_ParseList_ExcludesInvalidValues(IList<CookieHeaderValue> cookies, string[] input)
{ {
var results = CookieHeaderValue.ParseList(input); var results = CookieHeaderValue.ParseList(input);
// ParseList aways returns a list, even if empty. TryParseList may return null (via out). // ParseList always returns a list, even if empty. TryParseList may return null (via out).
Assert.Equal(cookies ?? new List<CookieHeaderValue>(), results); Assert.Equal(cookies ?? new List<CookieHeaderValue>(), results);
} }

View File

@ -403,7 +403,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void ParseList_WithSomeInvlaidValues_ExcludesInvalidValues() public void ParseList_WithSomeInvalidValues_ExcludesInvalidValues()
{ {
var inputs = new[] var inputs = new[]
{ {
@ -433,7 +433,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void ParseStrictList_WithSomeInvlaidValues_Throws() public void ParseStrictList_WithSomeInvalidValues_Throws()
{ {
var inputs = new[] var inputs = new[]
{ {
@ -451,7 +451,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void TryParseList_WithSomeInvlaidValues_ExcludesInvalidValues() public void TryParseList_WithSomeInvalidValues_ExcludesInvalidValues()
{ {
var inputs = new[] var inputs = new[]
{ {
@ -482,7 +482,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void TryParseStrictList_WithSomeInvlaidValues_ReturnsFalse() public void TryParseStrictList_WithSomeInvalidValues_ReturnsFalse()
{ {
var inputs = new[] var inputs = new[]
{ {

View File

@ -617,7 +617,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void ParseList_WithSomeInvlaidValues_IgnoresInvalidValues() public void ParseList_WithSomeInvalidValues_IgnoresInvalidValues()
{ {
var inputs = new[] var inputs = new[]
{ {
@ -640,7 +640,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void ParseStrictList_WithSomeInvlaidValues_Throws() public void ParseStrictList_WithSomeInvalidValues_Throws()
{ {
var inputs = new[] var inputs = new[]
{ {
@ -651,7 +651,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void TryParseList_WithSomeInvlaidValues_IgnoresInvalidValues() public void TryParseList_WithSomeInvalidValues_IgnoresInvalidValues()
{ {
var inputs = new[] var inputs = new[]
{ {
@ -676,7 +676,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void TryParseStrictList_WithSomeInvlaidValues_ReturnsFalse() public void TryParseStrictList_WithSomeInvalidValues_ReturnsFalse()
{ {
var inputs = new[] var inputs = new[]
{ {
@ -750,6 +750,8 @@ namespace Microsoft.Net.Http.Headers
[InlineData("application/entity+json", "application/entity+json")] [InlineData("application/entity+json", "application/entity+json")]
[InlineData("application/*+json", "application/entity+json")] [InlineData("application/*+json", "application/entity+json")]
[InlineData("application/*+json", "application/*+json")] [InlineData("application/*+json", "application/*+json")]
[InlineData("application/json", "application/problem+json")]
[InlineData("application/json", "application/vnd.restful+json")]
[InlineData("application/*", "application/*+JSON")] [InlineData("application/*", "application/*+JSON")]
[InlineData("application/vnd.github+json", "application/vnd.github+json")] [InlineData("application/vnd.github+json", "application/vnd.github+json")]
[InlineData("application/*", "application/entity+JSON")] [InlineData("application/*", "application/entity+JSON")]
@ -774,6 +776,7 @@ namespace Microsoft.Net.Http.Headers
[InlineData("application/*+*", "application/json")] [InlineData("application/*+*", "application/json")]
[InlineData("application/entity+*", "application/entity+json")] // We don't allow suffixes to be wildcards [InlineData("application/entity+*", "application/entity+json")] // We don't allow suffixes to be wildcards
[InlineData("application/*+*", "application/entity+json")] // We don't allow suffixes to be wildcards [InlineData("application/*+*", "application/entity+json")] // We don't allow suffixes to be wildcards
[InlineData("application/entity+json", "application/entity")]
public void IsSubSetOfWithSuffixes_NegativeCases(string set, string subset) public void IsSubSetOfWithSuffixes_NegativeCases(string set, string subset)
{ {
// Arrange // Arrange

View File

@ -60,7 +60,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void Copy_NameOnly_SuccesfullyCopied() public void Copy_NameOnly_SuccessfullyCopied()
{ {
var pair0 = new NameValueHeaderValue("name"); var pair0 = new NameValueHeaderValue("name");
var pair1 = pair0.Copy(); var pair1 = pair0.Copy();
@ -95,7 +95,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void Copy_NameAndValue_SuccesfullyCopied() public void Copy_NameAndValue_SuccessfullyCopied()
{ {
var pair0 = new NameValueHeaderValue("name", "value"); var pair0 = new NameValueHeaderValue("name", "value");
var pair1 = pair0.Copy(); var pair1 = pair0.Copy();
@ -466,7 +466,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void ParseList_WithSomeInvlaidValues_ExcludesInvalidValues() public void ParseList_WithSomeInvalidValues_ExcludesInvalidValues()
{ {
var inputs = new[] var inputs = new[]
{ {
@ -502,7 +502,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void ParseStrictList_WithSomeInvlaidValues_Throws() public void ParseStrictList_WithSomeInvalidValues_Throws()
{ {
var inputs = new[] var inputs = new[]
{ {
@ -520,7 +520,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void TryParseList_WithSomeInvlaidValues_ExcludesInvalidValues() public void TryParseList_WithSomeInvalidValues_ExcludesInvalidValues()
{ {
var inputs = new[] var inputs = new[]
{ {
@ -557,7 +557,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void TryParseStrictList_WithSomeInvlaidValues_ReturnsFalse() public void TryParseStrictList_WithSomeInvalidValues_ReturnsFalse()
{ {
var inputs = new[] var inputs = new[]
{ {

View File

@ -39,7 +39,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void ToString_UseDifferentrangeConditions_AllSerializedCorrectly() public void ToString_UseDifferentRangeConditions_AllSerializedCorrectly()
{ {
var rangeCondition = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"x\"")); var rangeCondition = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"x\""));
Assert.Equal("\"x\"", rangeCondition.ToString()); Assert.Equal("\"x\"", rangeCondition.ToString());
@ -49,7 +49,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void GetHashCode_UseSameAndDifferentrangeConditions_SameOrDifferentHashCodes() public void GetHashCode_UseSameAndDifferentRangeConditions_SameOrDifferentHashCodes()
{ {
var rangeCondition1 = new RangeConditionHeaderValue("\"x\""); var rangeCondition1 = new RangeConditionHeaderValue("\"x\"");
var rangeCondition2 = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"x\"")); var rangeCondition2 = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"x\""));

View File

@ -389,7 +389,7 @@ namespace Microsoft.Net.Http.Headers
public void SetCookieHeaderValue_ParseList_ExcludesInvalidValues(IList<SetCookieHeaderValue> cookies, string[] input) public void SetCookieHeaderValue_ParseList_ExcludesInvalidValues(IList<SetCookieHeaderValue> cookies, string[] input)
{ {
var results = SetCookieHeaderValue.ParseList(input); var results = SetCookieHeaderValue.ParseList(input);
// ParseList aways returns a list, even if empty. TryParseList may return null (via out). // ParseList always returns a list, even if empty. TryParseList may return null (via out).
Assert.Equal(cookies ?? new List<SetCookieHeaderValue>(), results); Assert.Equal(cookies ?? new List<SetCookieHeaderValue>(), results);
} }

View File

@ -354,7 +354,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void ParseList_WithSomeInvlaidValues_IgnoresInvalidValues() public void ParseList_WithSomeInvalidValues_IgnoresInvalidValues()
{ {
var inputs = new[] var inputs = new[]
{ {
@ -392,7 +392,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void ParseStrictList_WithSomeInvlaidValues_Throws() public void ParseStrictList_WithSomeInvalidValues_Throws()
{ {
var inputs = new[] var inputs = new[]
{ {
@ -412,7 +412,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void TryParseList_WithSomeInvlaidValues_IgnoresInvalidValues() public void TryParseList_WithSomeInvalidValues_IgnoresInvalidValues()
{ {
var inputs = new[] var inputs = new[]
{ {
@ -451,7 +451,7 @@ namespace Microsoft.Net.Http.Headers
} }
[Fact] [Fact]
public void TryParseStrictList_WithSomeInvlaidValues_ReturnsFalse() public void TryParseStrictList_WithSomeInvalidValues_ReturnsFalse()
{ {
var inputs = new[] var inputs = new[]
{ {

View File

@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Builder.Extensions namespace Microsoft.AspNetCore.Builder.Extensions
{ {
/// <summary> /// <summary>
/// Respresents a middleware that maps a request path to a sub-request pipeline. /// Represents a middleware that maps a request path to a sub-request pipeline.
/// </summary> /// </summary>
public class MapMiddleware public class MapMiddleware
{ {
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Builder.Extensions
private readonly MapOptions _options; private readonly MapOptions _options;
/// <summary> /// <summary>
/// Creates a new instace of <see cref="MapMiddleware"/>. /// Creates a new instance of <see cref="MapMiddleware"/>.
/// </summary> /// </summary>
/// <param name="next">The delegate representing the next middleware in the request pipeline.</param> /// <param name="next">The delegate representing the next middleware in the request pipeline.</param>
/// <param name="options">The middleware options.</param> /// <param name="options">The middleware options.</param>

View File

@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Builder.Extensions namespace Microsoft.AspNetCore.Builder.Extensions
{ {
/// <summary> /// <summary>
/// Respresents a middleware that runs a sub-request pipeline when a given predicate is matched. /// Represents a middleware that runs a sub-request pipeline when a given predicate is matched.
/// </summary> /// </summary>
public class MapWhenMiddleware public class MapWhenMiddleware
{ {

View File

@ -0,0 +1,53 @@
// 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 Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Http
{
public static class ResponseTrailerExtensions
{
private const string Trailer = "Trailer";
/// <summary>
/// Adds the given trailer name to the 'Trailer' response header. This must happen before the response headers are sent.
/// </summary>
/// <param name="response"></param>
/// <param name="trailerName"></param>
public static void DeclareTrailer(this HttpResponse response, string trailerName)
{
response.Headers.AppendCommaSeparatedValues(Trailer, trailerName);
}
/// <summary>
/// Indicates if the server supports sending trailer headers for this response.
/// </summary>
/// <param name="response"></param>
/// <returns></returns>
public static bool SupportsTrailers(this HttpResponse response)
{
var feature = response.HttpContext.Features.Get<IHttpResponseTrailersFeature>();
return feature?.Trailers != null && !feature.Trailers.IsReadOnly;
}
/// <summary>
/// Adds the given trailer header to the trailers collection to be sent at the end of the response body.
/// Check <see cref="SupportsTrailers" /> or an InvalidOperationException may be thrown.
/// </summary>
/// <param name="response"></param>
/// <param name="trailerName"></param>
/// <param name="trailerValues"></param>
public static void AppendTrailer(this HttpResponse response, string trailerName, StringValues trailerValues)
{
var feature = response.HttpContext.Features.Get<IHttpResponseTrailersFeature>();
if (feature?.Trailers == null || feature.Trailers.IsReadOnly)
{
throw new InvalidOperationException("Trailers are not supported for this response.");
}
feature.Trailers.Append(trailerName, trailerValues);
}
}
}

View File

@ -74,13 +74,13 @@ namespace Microsoft.AspNetCore.Builder
throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoInvokeMethod(InvokeMethodName, InvokeAsyncMethodName, middleware)); throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoInvokeMethod(InvokeMethodName, InvokeAsyncMethodName, middleware));
} }
var methodinfo = invokeMethods[0]; var methodInfo = invokeMethods[0];
if (!typeof(Task).IsAssignableFrom(methodinfo.ReturnType)) if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType))
{ {
throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNonTaskReturnType(InvokeMethodName, InvokeAsyncMethodName, nameof(Task))); throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNonTaskReturnType(InvokeMethodName, InvokeAsyncMethodName, nameof(Task)));
} }
var parameters = methodinfo.GetParameters(); var parameters = methodInfo.GetParameters();
if (parameters.Length == 0 || parameters[0].ParameterType != typeof(HttpContext)) if (parameters.Length == 0 || parameters[0].ParameterType != typeof(HttpContext))
{ {
throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoParameters(InvokeMethodName, InvokeAsyncMethodName, nameof(HttpContext))); throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoParameters(InvokeMethodName, InvokeAsyncMethodName, nameof(HttpContext)));
@ -92,10 +92,10 @@ namespace Microsoft.AspNetCore.Builder
var instance = ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs); var instance = ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs);
if (parameters.Length == 1) if (parameters.Length == 1)
{ {
return (RequestDelegate)methodinfo.CreateDelegate(typeof(RequestDelegate), instance); return (RequestDelegate)methodInfo.CreateDelegate(typeof(RequestDelegate), instance);
} }
var factory = Compile<object>(methodinfo, parameters); var factory = Compile<object>(methodInfo, parameters);
return context => return context =>
{ {
@ -142,13 +142,13 @@ namespace Microsoft.AspNetCore.Builder
}); });
} }
private static Func<T, HttpContext, IServiceProvider, Task> Compile<T>(MethodInfo methodinfo, ParameterInfo[] parameters) private static Func<T, HttpContext, IServiceProvider, Task> Compile<T>(MethodInfo methodInfo, ParameterInfo[] parameters)
{ {
// If we call something like // If we call something like
// //
// public class Middleware // public class Middleware
// { // {
// public Task Invoke(HttpContext context, ILoggerFactory loggeryFactory) // public Task Invoke(HttpContext context, ILoggerFactory loggerFactory)
// { // {
// //
// } // }
@ -158,14 +158,14 @@ namespace Microsoft.AspNetCore.Builder
// We'll end up with something like this: // We'll end up with something like this:
// Generic version: // Generic version:
// //
// Task Invoke(Middleware instance, HttpContext httpContext, IServiceprovider provider) // Task Invoke(Middleware instance, HttpContext httpContext, IServiceProvider provider)
// { // {
// return instance.Invoke(httpContext, (ILoggerFactory)UseMiddlewareExtensions.GetService(provider, typeof(ILoggerFactory)); // return instance.Invoke(httpContext, (ILoggerFactory)UseMiddlewareExtensions.GetService(provider, typeof(ILoggerFactory));
// } // }
// Non generic version: // Non generic version:
// //
// Task Invoke(object instance, HttpContext httpContext, IServiceprovider provider) // Task Invoke(object instance, HttpContext httpContext, IServiceProvider provider)
// { // {
// return ((Middleware)instance).Invoke(httpContext, (ILoggerFactory)UseMiddlewareExtensions.GetService(provider, typeof(ILoggerFactory)); // return ((Middleware)instance).Invoke(httpContext, (ILoggerFactory)UseMiddlewareExtensions.GetService(provider, typeof(ILoggerFactory));
// } // }
@ -190,7 +190,7 @@ namespace Microsoft.AspNetCore.Builder
{ {
providerArg, providerArg,
Expression.Constant(parameterType, typeof(Type)), Expression.Constant(parameterType, typeof(Type)),
Expression.Constant(methodinfo.DeclaringType, typeof(Type)) Expression.Constant(methodInfo.DeclaringType, typeof(Type))
}; };
var getServiceCall = Expression.Call(GetServiceInfo, parameterTypeExpression); var getServiceCall = Expression.Call(GetServiceInfo, parameterTypeExpression);
@ -198,12 +198,12 @@ namespace Microsoft.AspNetCore.Builder
} }
Expression middlewareInstanceArg = instanceArg; Expression middlewareInstanceArg = instanceArg;
if (methodinfo.DeclaringType != typeof(T)) if (methodInfo.DeclaringType != typeof(T))
{ {
middlewareInstanceArg = Expression.Convert(middlewareInstanceArg, methodinfo.DeclaringType); middlewareInstanceArg = Expression.Convert(middlewareInstanceArg, methodInfo.DeclaringType);
} }
var body = Expression.Call(middlewareInstanceArg, methodinfo, methodArguments); var body = Expression.Call(middlewareInstanceArg, methodInfo, methodArguments);
var lambda = Expression.Lambda<Func<T, HttpContext, IServiceProvider, Task>>(body, instanceArg, httpContextArg, providerArg); var lambda = Expression.Lambda<Func<T, HttpContext, IServiceProvider, Task>>(body, instanceArg, httpContextArg, providerArg);

View File

@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Builder.Extensions
private readonly PathString _pathBase; private readonly PathString _pathBase;
/// <summary> /// <summary>
/// Creates a new instace of <see cref="UsePathBaseMiddleware"/>. /// Creates a new instance of <see cref="UsePathBaseMiddleware"/>.
/// </summary> /// </summary>
/// <param name="next">The delegate representing the next middleware in the request pipeline.</param> /// <param name="next">The delegate representing the next middleware in the request pipeline.</param>
/// <param name="pathBase">The path base to extract.</param> /// <param name="pathBase">The path base to extract.</param>

View File

@ -35,7 +35,12 @@ namespace Microsoft.AspNetCore.Http
/// <param name="port">A positive, greater than 0 value representing the port in the host string.</param> /// <param name="port">A positive, greater than 0 value representing the port in the host string.</param>
public HostString(string host, int port) public HostString(string host, int port)
{ {
if(port <= 0) if (host == null)
{
throw new ArgumentNullException(nameof(host));
}
if (port <= 0)
{ {
throw new ArgumentOutOfRangeException(nameof(port), Resources.Exception_PortMustBeGreaterThanZero); throw new ArgumentOutOfRangeException(nameof(port), Resources.Exception_PortMustBeGreaterThanZero);
} }

View File

@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Http
private readonly string _value; private readonly string _value;
/// <summary> /// <summary>
/// Initalize the path string with a given value. This value must be in unescaped format. Use /// Initialize the path string with a given value. This value must be in unescaped format. Use
/// PathString.FromUriComponent(value) if you have a path value which is in an escaped format. /// PathString.FromUriComponent(value) if you have a path value which is in an escaped format.
/// </summary> /// </summary>
/// <param name="value">The unescaped path to be assigned to the Value property.</param> /// <param name="value">The unescaped path to be assigned to the Value property.</param>
@ -117,7 +117,7 @@ namespace Microsoft.AspNetCore.Http
{ {
if (!requiresEscaping) if (!requiresEscaping)
{ {
// the current segument doesn't require escape // the current segment doesn't require escape
if (buffer == null) if (buffer == null)
{ {
buffer = new StringBuilder(_value.Length * 3); buffer = new StringBuilder(_value.Length * 3);

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Builder.Extensions
public class MapPredicateMiddlewareTests public class MapPredicateMiddlewareTests
{ {
private static readonly Predicate NotImplementedPredicate = new Predicate(envionment => { throw new NotImplementedException(); }); private static readonly Predicate NotImplementedPredicate = new Predicate(environment => { throw new NotImplementedException(); });
private static Task Success(HttpContext context) private static Task Success(HttpContext context)
{ {

View File

@ -59,10 +59,10 @@ namespace Microsoft.AspNetCore.Http.Abstractions
[InlineData("", "value", "?=value")] [InlineData("", "value", "?=value")]
[InlineData("", "", "?=")] [InlineData("", "", "?=")]
[InlineData("", null, "?=")] [InlineData("", null, "?=")]
public void CreateNameValue_Success(string name, string value, string exepcted) public void CreateNameValue_Success(string name, string value, string expected)
{ {
var query = QueryString.Create(name, value); var query = QueryString.Create(name, value);
Assert.Equal(exepcted, query.Value); Assert.Equal(expected, query.Value);
} }
[Fact] [Fact]

View File

@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.Http
} }
[Fact] [Fact]
public void UseMiddleware_MutlipleInvokeMethods_ThrowsException() public void UseMiddleware_MultipleInvokeMethods_ThrowsException()
{ {
var builder = new ApplicationBuilder(new DummyServiceProvider()); var builder = new ApplicationBuilder(new DummyServiceProvider());
builder.UseMiddleware(typeof(MiddlewareMultipleInvokesStub)); builder.UseMiddleware(typeof(MiddlewareMultipleInvokesStub));
@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.Http
} }
[Fact] [Fact]
public void UseMiddleware_MutlipleInvokeAsyncMethods_ThrowsException() public void UseMiddleware_MultipleInvokeAsyncMethods_ThrowsException()
{ {
var builder = new ApplicationBuilder(new DummyServiceProvider()); var builder = new ApplicationBuilder(new DummyServiceProvider());
builder.UseMiddleware(typeof(MiddlewareMultipleInvokeAsyncStub)); builder.UseMiddleware(typeof(MiddlewareMultipleInvokeAsyncStub));
@ -116,7 +116,7 @@ namespace Microsoft.AspNetCore.Http
} }
[Fact] [Fact]
public void UseMiddleware_MutlipleInvokeAndInvokeAsyncMethods_ThrowsException() public void UseMiddleware_MultipleInvokeAndInvokeAsyncMethods_ThrowsException()
{ {
var builder = new ApplicationBuilder(new DummyServiceProvider()); var builder = new ApplicationBuilder(new DummyServiceProvider());
builder.UseMiddleware(typeof(MiddlewareMultipleInvokeAndInvokeAsyncStub)); builder.UseMiddleware(typeof(MiddlewareMultipleInvokeAndInvokeAsyncStub));
@ -153,7 +153,7 @@ namespace Microsoft.AspNetCore.Http
} }
[Fact] [Fact]
public void UseMiddlewareWithIvokeWithOutAndRefThrows() public void UseMiddlewareWithInvokeWithOutAndRefThrows()
{ {
var mockServiceProvider = new DummyServiceProvider(); var mockServiceProvider = new DummyServiceProvider();
var builder = new ApplicationBuilder(mockServiceProvider); var builder = new ApplicationBuilder(mockServiceProvider);

View File

@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Http.Features
} }
else if (flush) else if (flush)
{ {
// Cache was cleared, but item retrived from current Collection for version // Cache was cleared, but item retrieved from current Collection for version
// so use passed in revision rather than making another virtual call // so use passed in revision rather than making another virtual call
Revision = revision; Revision = revision;
} }

View File

@ -0,0 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Http.Features
{
public interface IHttpResponseTrailersFeature
{
IHeaderDictionary Trailers { get; set; }
}
}

View File

@ -131,6 +131,11 @@ namespace Microsoft.AspNetCore.Http.Features
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
if (_request.ContentLength == 0)
{
return FormCollection.Empty;
}
if (_options.BufferBody) if (_options.BufferBody)
{ {
_request.EnableRewind(_options.MemoryBufferThreshold, _options.BufferBodyLengthLimit); _request.EnableRewind(_options.MemoryBufferThreshold, _options.BufferBodyLengthLimit);
@ -221,7 +226,7 @@ namespace Microsoft.AspNetCore.Http.Features
// //
// value // value
// Do not limit the key name length here because the mulipart headers length limit is already in effect. // Do not limit the key name length here because the multipart headers length limit is already in effect.
var key = formDataSection.Name; var key = formDataSection.Name;
var value = await formDataSection.GetValueAsync(); var value = await formDataSection.GetValueAsync();

View File

@ -7,17 +7,20 @@ namespace Microsoft.AspNetCore.Http
{ {
public class HttpContextAccessor : IHttpContextAccessor public class HttpContextAccessor : IHttpContextAccessor
{ {
private static AsyncLocal<HttpContext> _httpContextCurrent = new AsyncLocal<HttpContext>(); private static AsyncLocal<(string traceIdentifier, HttpContext context)> _httpContextCurrent = new AsyncLocal<(string traceIdentifier, HttpContext context)>();
public HttpContext HttpContext public HttpContext HttpContext
{ {
get get
{ {
return _httpContextCurrent.Value; var value = _httpContextCurrent.Value;
// Only return the context if the stored request id matches the stored trace identifier
// context.TraceIdentifier is cleared by HttpContextFactory.Dispose.
return value.traceIdentifier == value.context?.TraceIdentifier ? value.context : null;
} }
set set
{ {
_httpContextCurrent.Value = value; _httpContextCurrent.Value = (value?.TraceIdentifier, value);
} }
} }
} }

View File

@ -53,6 +53,10 @@ namespace Microsoft.AspNetCore.Http
{ {
_httpContextAccessor.HttpContext = null; _httpContextAccessor.HttpContext = null;
} }
// Null out the TraceIdentifier here as a sign that this request is done,
// the HttpContextAccessor implementation relies on this to detect that the request is over
httpContext.TraceIdentifier = null;
} }
} }
} }

View File

@ -157,7 +157,7 @@ namespace Microsoft.AspNetCore.Http
features.Set<IHttpResponseFeature>(new HttpResponseFeature()); features.Set<IHttpResponseFeature>(new HttpResponseFeature());
features.Set<IHttpWebSocketFeature>(new TestHttpWebSocketFeature()); features.Set<IHttpWebSocketFeature>(new TestHttpWebSocketFeature());
// featurecollection is set. all cached interfaces are null. // FeatureCollection is set. all cached interfaces are null.
var context = new DefaultHttpContext(features); var context = new DefaultHttpContext(features);
TestAllCachedFeaturesAreNull(context, features); TestAllCachedFeaturesAreNull(context, features);
Assert.Equal(3, features.Count()); Assert.Equal(3, features.Count());
@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.Http
TestAllCachedFeaturesAreSet(context, features); TestAllCachedFeaturesAreSet(context, features);
Assert.NotEqual(3, features.Count()); Assert.NotEqual(3, features.Count());
// featurecollection is null. and all cached interfaces are null. // FeatureCollection is null. and all cached interfaces are null.
// only top level is tested because child objects are inaccessible. // only top level is tested because child objects are inaccessible.
context.Uninitialize(); context.Uninitialize();
TestCachedFeaturesAreNull(context, null); TestCachedFeaturesAreNull(context, null);
@ -177,7 +177,7 @@ namespace Microsoft.AspNetCore.Http
newFeatures.Set<IHttpResponseFeature>(new HttpResponseFeature()); newFeatures.Set<IHttpResponseFeature>(new HttpResponseFeature());
newFeatures.Set<IHttpWebSocketFeature>(new TestHttpWebSocketFeature()); newFeatures.Set<IHttpWebSocketFeature>(new TestHttpWebSocketFeature());
// featurecollection is set to newFeatures. all cached interfaces are null. // FeatureCollection is set to newFeatures. all cached interfaces are null.
context.Initialize(newFeatures); context.Initialize(newFeatures);
TestAllCachedFeaturesAreNull(context, newFeatures); TestAllCachedFeaturesAreNull(context, newFeatures);
Assert.Equal(3, newFeatures.Count()); Assert.Equal(3, newFeatures.Count());

View File

@ -12,6 +12,23 @@ namespace Microsoft.AspNetCore.Http.Features
{ {
public class FormFeatureTests public class FormFeatureTests
{ {
[Fact]
public async Task ReadFormAsync_0ContentLength_ReturnsEmptyForm()
{
var context = new DefaultHttpContext();
var responseFeature = new FakeResponseFeature();
context.Features.Set<IHttpResponseFeature>(responseFeature);
context.Request.ContentType = MultipartContentType;
context.Request.ContentLength = 0;
var formFeature = new FormFeature(context.Request, new FormOptions());
context.Features.Set<IFormFeature>(formFeature);
var formCollection = await context.Request.ReadFormAsync();
Assert.Same(FormCollection.Empty, formCollection);
}
[Theory] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [InlineData(false)]

View File

@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.Http
} }
[Fact] [Fact]
public void EmtpyQuotedHeaderSegmentsAreIgnored() public void EmptyQuotedHeaderSegmentsAreIgnored()
{ {
var headers = new HeaderDictionary( var headers = new HeaderDictionary(
new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase) new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase)

View File

@ -0,0 +1,197 @@
// 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.Linq;
using System.Net.WebSockets;
using System.Reflection;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features;
using Xunit;
namespace Microsoft.AspNetCore.Http
{
public class HttpContextAccessorTests
{
[Fact]
public async Task HttpContextAccessor_GettingHttpContextReturnsHttpContext()
{
var accessor = new HttpContextAccessor();
var context = new DefaultHttpContext();
context.TraceIdentifier = "1";
accessor.HttpContext = context;
await Task.Delay(100);
Assert.Same(context, accessor.HttpContext);
}
[Fact]
public void HttpContextAccessor_GettingHttpContextWithOutSettingReturnsNull()
{
var accessor = new HttpContextAccessor();
Assert.Null(accessor.HttpContext);
}
[Fact]
public async Task HttpContextAccessor_GettingHttpContextReturnsNullHttpContextIfSetToNull()
{
var accessor = new HttpContextAccessor();
var context = new DefaultHttpContext();
context.TraceIdentifier = "1";
accessor.HttpContext = context;
var checkAsyncFlowTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
var waitForNullTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
var afterNullCheckTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
ThreadPool.QueueUserWorkItem(async _ =>
{
// The HttpContext flows with the execution context
Assert.Same(context, accessor.HttpContext);
checkAsyncFlowTcs.SetResult(null);
await waitForNullTcs.Task;
try
{
Assert.Null(accessor.HttpContext);
afterNullCheckTcs.SetResult(null);
}
catch (Exception ex)
{
afterNullCheckTcs.SetException(ex);
}
});
await checkAsyncFlowTcs.Task;
// Null out the accessor
accessor.HttpContext = null;
context.TraceIdentifier = null;
waitForNullTcs.SetResult(null);
Assert.Null(accessor.HttpContext);
await afterNullCheckTcs.Task;
}
[Fact]
public async Task HttpContextAccessor_GettingHttpContextReturnsNullHttpContextIfDifferentTraceIdentifier()
{
var accessor = new HttpContextAccessor();
var context = new DefaultHttpContext();
context.TraceIdentifier = "1";
accessor.HttpContext = context;
var checkAsyncFlowTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
var waitForNullTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
var afterNullCheckTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
ThreadPool.QueueUserWorkItem(async _ =>
{
// The HttpContext flows with the execution context
Assert.Same(context, accessor.HttpContext);
checkAsyncFlowTcs.SetResult(null);
await waitForNullTcs.Task;
try
{
Assert.Null(accessor.HttpContext);
afterNullCheckTcs.SetResult(null);
}
catch (Exception ex)
{
afterNullCheckTcs.SetException(ex);
}
});
await checkAsyncFlowTcs.Task;
// Reset the trace identifier on the first request
context.TraceIdentifier = null;
// Set a new http context
var context2 = new DefaultHttpContext();
context2.TraceIdentifier = "2";
accessor.HttpContext = context2;
waitForNullTcs.SetResult(null);
Assert.Same(context2, accessor.HttpContext);
await afterNullCheckTcs.Task;
}
[Fact]
public async Task HttpContextAccessor_GettingHttpContextDoesNotFlowIfAccessorSetToNull()
{
var accessor = new HttpContextAccessor();
var context = new DefaultHttpContext();
context.TraceIdentifier = "1";
accessor.HttpContext = context;
var checkAsyncFlowTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
accessor.HttpContext = null;
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
// The HttpContext flows with the execution context
Assert.Null(accessor.HttpContext);
checkAsyncFlowTcs.SetResult(null);
}
catch (Exception ex)
{
checkAsyncFlowTcs.SetException(ex);
}
});
await checkAsyncFlowTcs.Task;
}
[Fact]
public async Task HttpContextAccessor_GettingHttpContextDoesNotFlowIfExecutionContextDoesNotFlow()
{
var accessor = new HttpContextAccessor();
var context = new DefaultHttpContext();
context.TraceIdentifier = "1";
accessor.HttpContext = context;
var checkAsyncFlowTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
ThreadPool.UnsafeQueueUserWorkItem(_ =>
{
try
{
// The HttpContext flows with the execution context
Assert.Null(accessor.HttpContext);
checkAsyncFlowTcs.SetResult(null);
}
catch (Exception ex)
{
checkAsyncFlowTcs.SetException(ex);
}
}, null);
await checkAsyncFlowTcs.Task;
}
}
}

View File

@ -22,7 +22,27 @@ namespace Microsoft.AspNetCore.Http
var context = contextFactory.Create(new FeatureCollection()); var context = contextFactory.Create(new FeatureCollection());
// Assert // Assert
Assert.True(ReferenceEquals(context, accessor.HttpContext)); Assert.Same(context, accessor.HttpContext);
}
[Fact]
public void DisposeHttpContextSetsHttpContextAccessorToNull()
{
// Arrange
var accessor = new HttpContextAccessor();
var contextFactory = new HttpContextFactory(Options.Create(new FormOptions()), accessor);
// Act
var context = contextFactory.Create(new FeatureCollection());
var traceIdentifier = context.TraceIdentifier;
// Assert
Assert.Same(context, accessor.HttpContext);
contextFactory.Dispose(context);
Assert.Null(accessor.HttpContext);
Assert.NotEqual(traceIdentifier, context.TraceIdentifier);
} }
[Fact] [Fact]

View File

@ -15,13 +15,13 @@ namespace Microsoft.AspNetCore.Http.Tests
{ {
var headers = new HeaderDictionary(); var headers = new HeaderDictionary();
var cookies = new ResponseCookies(headers, null); var cookies = new ResponseCookies(headers, null);
var testcookie = "TestCookie"; var testCookie = "TestCookie";
cookies.Delete(testcookie); cookies.Delete(testCookie);
var cookieHeaderValues = headers[HeaderNames.SetCookie]; var cookieHeaderValues = headers[HeaderNames.SetCookie];
Assert.Single(cookieHeaderValues); Assert.Single(cookieHeaderValues);
Assert.StartsWith(testcookie, cookieHeaderValues[0]); Assert.StartsWith(testCookie, cookieHeaderValues[0]);
Assert.Contains("path=/", cookieHeaderValues[0]); Assert.Contains("path=/", cookieHeaderValues[0]);
Assert.Contains("expires=Thu, 01 Jan 1970 00:00:00 GMT", cookieHeaderValues[0]); Assert.Contains("expires=Thu, 01 Jan 1970 00:00:00 GMT", cookieHeaderValues[0]);
} }
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Http.Tests
{ {
var headers = new HeaderDictionary(); var headers = new HeaderDictionary();
var cookies = new ResponseCookies(headers, null); var cookies = new ResponseCookies(headers, null);
var testcookie = "TestCookie"; var testCookie = "TestCookie";
var time = new DateTimeOffset(2000, 1, 1, 1, 1, 1, 1, TimeSpan.Zero); var time = new DateTimeOffset(2000, 1, 1, 1, 1, 1, 1, TimeSpan.Zero);
var options = new CookieOptions var options = new CookieOptions
{ {
@ -43,11 +43,11 @@ namespace Microsoft.AspNetCore.Http.Tests
SameSite = SameSiteMode.Lax SameSite = SameSiteMode.Lax
}; };
cookies.Delete(testcookie, options); cookies.Delete(testCookie, options);
var cookieHeaderValues = headers[HeaderNames.SetCookie]; var cookieHeaderValues = headers[HeaderNames.SetCookie];
Assert.Single(cookieHeaderValues); Assert.Single(cookieHeaderValues);
Assert.StartsWith(testcookie, cookieHeaderValues[0]); Assert.StartsWith(testCookie, cookieHeaderValues[0]);
Assert.Contains("path=/", cookieHeaderValues[0]); Assert.Contains("path=/", cookieHeaderValues[0]);
Assert.Contains("expires=Thu, 01 Jan 1970 00:00:00 GMT", cookieHeaderValues[0]); Assert.Contains("expires=Thu, 01 Jan 1970 00:00:00 GMT", cookieHeaderValues[0]);
Assert.Contains("secure", cookieHeaderValues[0]); Assert.Contains("secure", cookieHeaderValues[0]);
@ -60,14 +60,14 @@ namespace Microsoft.AspNetCore.Http.Tests
{ {
var headers = new HeaderDictionary(); var headers = new HeaderDictionary();
var cookies = new ResponseCookies(headers, null); var cookies = new ResponseCookies(headers, null);
var testcookie = "TestCookie"; var testCookie = "TestCookie";
cookies.Append(testcookie, testcookie); cookies.Append(testCookie, testCookie);
cookies.Delete(testcookie); cookies.Delete(testCookie);
var cookieHeaderValues = headers[HeaderNames.SetCookie]; var cookieHeaderValues = headers[HeaderNames.SetCookie];
Assert.Single(cookieHeaderValues); Assert.Single(cookieHeaderValues);
Assert.StartsWith(testcookie, cookieHeaderValues[0]); Assert.StartsWith(testCookie, cookieHeaderValues[0]);
Assert.Contains("path=/", cookieHeaderValues[0]); Assert.Contains("path=/", cookieHeaderValues[0]);
Assert.Contains("expires=Thu, 01 Jan 1970 00:00:00 GMT", cookieHeaderValues[0]); Assert.Contains("expires=Thu, 01 Jan 1970 00:00:00 GMT", cookieHeaderValues[0]);
} }
@ -80,9 +80,9 @@ namespace Microsoft.AspNetCore.Http.Tests
var cookieOptions = new CookieOptions(); var cookieOptions = new CookieOptions();
var maxAgeTime = TimeSpan.FromHours(1); var maxAgeTime = TimeSpan.FromHours(1);
cookieOptions.MaxAge = TimeSpan.FromHours(1); cookieOptions.MaxAge = TimeSpan.FromHours(1);
var testcookie = "TestCookie"; var testCookie = "TestCookie";
cookies.Append(testcookie, testcookie, cookieOptions); cookies.Append(testCookie, testCookie, cookieOptions);
var cookieHeaderValues = headers[HeaderNames.SetCookie]; var cookieHeaderValues = headers[HeaderNames.SetCookie];
Assert.Single(cookieHeaderValues); Assert.Single(cookieHeaderValues);

View File

@ -34,11 +34,11 @@ namespace Microsoft.AspNetCore.Builder
{ {
Func<RequestDelegate, RequestDelegate> middleware1 = next1 => Func<RequestDelegate, RequestDelegate> middleware1 = next1 =>
{ {
AppFunc exitMiddlware = env => AppFunc exitMiddleware = env =>
{ {
return next1((HttpContext)env[typeof(HttpContext).FullName]); return next1((HttpContext)env[typeof(HttpContext).FullName]);
}; };
var app = middleware(exitMiddlware); var app = middleware(exitMiddleware);
return httpContext => return httpContext =>
{ {
// Use the existing OWIN env if there is one. // Use the existing OWIN env if there is one.

View File

@ -103,10 +103,10 @@ namespace Microsoft.AspNetCore.Owin
// 2. The middleware inserts an alternate Accept signature into the OWIN environment. // 2. The middleware inserts an alternate Accept signature into the OWIN environment.
// 3. The middleware invokes Next and stores Next's Task locally. It then returns an alternate Task to the server. // 3. The middleware invokes Next and stores Next's Task locally. It then returns an alternate Task to the server.
// 4. The OwinFeatureCollection adapts the alternate Accept signature to IHttpWebSocketFeature.AcceptAsync. // 4. The OwinFeatureCollection adapts the alternate Accept signature to IHttpWebSocketFeature.AcceptAsync.
// 5. A component later in the pipleline invokes IHttpWebSocketFeature.AcceptAsync (mapped to AcceptWebSocketAsync). // 5. A component later in the pipeline invokes IHttpWebSocketFeature.AcceptAsync (mapped to AcceptWebSocketAsync).
// 6. The middleware calls the OWIN Accept, providing a local callback, and returns an incomplete Task. // 6. The middleware calls the OWIN Accept, providing a local callback, and returns an incomplete Task.
// 7. The middleware completes the alternate Task it returned from Invoke, telling the server that the request pipeline has completed. // 7. The middleware completes the alternate Task it returned from Invoke, telling the server that the request pipeline has completed.
// 8. The server invokes the middleware's callback, which creats a WebSocket adapter complete's the orriginal Accept Task with it. // 8. The server invokes the middleware's callback, which creates a WebSocket adapter and completes the original Accept Task with it.
// 9. The middleware waits while the application uses the WebSocket, where the end is signaled by the Next's Task completion. // 9. The middleware waits while the application uses the WebSocket, where the end is signaled by the Next's Task completion.
public static AppFunc AdaptWebSockets(AppFunc next) public static AppFunc AdaptWebSockets(AppFunc next)
{ {

View File

@ -131,7 +131,7 @@ namespace Microsoft.AspNetCore.Owin
} }
[Fact] [Fact]
public void OwinEnvironmentImpelmentsGetEnumerator() public void OwinEnvironmentImplementsGetEnumerator()
{ {
var owinEnvironment = new OwinEnvironment(CreateContext()); var owinEnvironment = new OwinEnvironment(CreateContext());

View File

@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.WebUtilities
public KeyValuePair<string, string>? ReadNextPair() public KeyValuePair<string, string>? ReadNextPair()
{ {
ReadNextPairImpl(); ReadNextPairImpl();
if (ReadSucceded()) if (ReadSucceeded())
{ {
return new KeyValuePair<string, string>(_currentKey, _currentValue); return new KeyValuePair<string, string>(_currentKey, _currentValue);
} }
@ -134,7 +134,7 @@ namespace Microsoft.AspNetCore.WebUtilities
public async Task<KeyValuePair<string, string>?> ReadNextPairAsync(CancellationToken cancellationToken = new CancellationToken()) public async Task<KeyValuePair<string, string>?> ReadNextPairAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
await ReadNextPairAsyncImpl(cancellationToken); await ReadNextPairAsyncImpl(cancellationToken);
if (ReadSucceded()) if (ReadSucceeded())
{ {
return new KeyValuePair<string, string>(_currentKey, _currentValue); return new KeyValuePair<string, string>(_currentKey, _currentValue);
} }
@ -189,11 +189,11 @@ namespace Microsoft.AspNetCore.WebUtilities
return true; return true;
} }
private bool TryReadWord(char seperator, int limit, out string value) private bool TryReadWord(char separator, int limit, out string value)
{ {
do do
{ {
if (ReadChar(seperator, limit, out value)) if (ReadChar(separator, limit, out value))
{ {
return true; return true;
} }
@ -201,7 +201,7 @@ namespace Microsoft.AspNetCore.WebUtilities
return false; return false;
} }
private bool ReadChar(char seperator, int limit, out string word) private bool ReadChar(char separator, int limit, out string word)
{ {
// End // End
if (_bufferCount == 0) if (_bufferCount == 0)
@ -213,7 +213,7 @@ namespace Microsoft.AspNetCore.WebUtilities
var c = _buffer[_bufferOffset++]; var c = _buffer[_bufferOffset++];
_bufferCount--; _bufferCount--;
if (c == seperator) if (c == separator)
{ {
word = BuildWord(); word = BuildWord();
return true; return true;
@ -283,14 +283,14 @@ namespace Microsoft.AspNetCore.WebUtilities
return accumulator.GetResults(); return accumulator.GetResults();
} }
private bool ReadSucceded() private bool ReadSucceeded()
{ {
return _currentKey != null && _currentValue != null; return _currentKey != null && _currentValue != null;
} }
private void Append(ref KeyValueAccumulator accumulator) private void Append(ref KeyValueAccumulator accumulator)
{ {
if (ReadSucceded()) if (ReadSucceeded())
{ {
accumulator.Append(_currentKey, _currentValue); accumulator.Append(_currentKey, _currentValue);
if (accumulator.ValueCount > ValueCountLimit) if (accumulator.ValueCount > ValueCountLimit)

View File

@ -3,7 +3,9 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -150,34 +152,66 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
} }
public override async Task WriteAsync(char value) public override Task WriteAsync(char value)
{ {
if (_disposed) if (_disposed)
{ {
throw new ObjectDisposedException(nameof(HttpResponseStreamWriter)); return GetObjectDisposedTask();
} }
if (_charBufferCount == _charBufferSize) if (_charBufferCount == _charBufferSize)
{ {
await FlushInternalAsync(flushEncoder: false); return WriteAsyncAwaited(value);
} }
else
{
// Enough room in buffer, no need to go async
_charBuffer[_charBufferCount] = value;
_charBufferCount++;
return Task.CompletedTask;
}
}
private async Task WriteAsyncAwaited(char value)
{
Debug.Assert(_charBufferCount == _charBufferSize);
await FlushInternalAsync(flushEncoder: false);
_charBuffer[_charBufferCount] = value; _charBuffer[_charBufferCount] = value;
_charBufferCount++; _charBufferCount++;
} }
public override async Task WriteAsync(char[] values, int index, int count) public override Task WriteAsync(char[] values, int index, int count)
{ {
if (_disposed) if (_disposed)
{ {
throw new ObjectDisposedException(nameof(HttpResponseStreamWriter)); return GetObjectDisposedTask();
} }
if (values == null) if (values == null || count == 0)
{ {
return; return Task.CompletedTask;
} }
var remaining = _charBufferSize - _charBufferCount;
if (remaining >= count)
{
// Enough room in buffer, no need to go async
CopyToCharBuffer(values, ref index, ref count);
return Task.CompletedTask;
}
else
{
return WriteAsyncAwaited(values, index, count);
}
}
private async Task WriteAsyncAwaited(char[] values, int index, int count)
{
Debug.Assert(count > 0);
Debug.Assert(_charBufferSize - _charBufferCount > count);
while (count > 0) while (count > 0)
{ {
if (_charBufferCount == _charBufferSize) if (_charBufferCount == _charBufferSize)
@ -186,22 +220,43 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
CopyToCharBuffer(values, ref index, ref count); CopyToCharBuffer(values, ref index, ref count);
Debug.Assert(count == 0);
} }
} }
public override async Task WriteAsync(string value) public override Task WriteAsync(string value)
{ {
if (_disposed) if (_disposed)
{ {
throw new ObjectDisposedException(nameof(HttpResponseStreamWriter)); return GetObjectDisposedTask();
} }
if (value == null) var count = value?.Length ?? 0;
if (count == 0)
{ {
return; return Task.CompletedTask;
} }
var remaining = _charBufferSize - _charBufferCount;
if (remaining >= count)
{
// Enough room in buffer, no need to go async
CopyToCharBuffer(value);
return Task.CompletedTask;
}
else
{
return WriteAsyncAwaited(value);
}
}
private async Task WriteAsyncAwaited(string value)
{
var count = value.Length; var count = value.Length;
Debug.Assert(count > 0);
Debug.Assert(_charBufferSize - _charBufferCount < count);
var index = 0; var index = 0;
while (count > 0) while (count > 0)
{ {
@ -231,7 +286,7 @@ namespace Microsoft.AspNetCore.WebUtilities
{ {
if (_disposed) if (_disposed)
{ {
throw new ObjectDisposedException(nameof(HttpResponseStreamWriter)); return GetObjectDisposedTask();
} }
return FlushInternalAsync(flushEncoder: true); return FlushInternalAsync(flushEncoder: true);
@ -306,6 +361,19 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
} }
private void CopyToCharBuffer(string value)
{
Debug.Assert(_charBufferSize - _charBufferCount >= value.Length);
value.CopyTo(
sourceIndex: 0,
destination: _charBuffer,
destinationIndex: _charBufferCount,
count: value.Length);
_charBufferCount += value.Length;
}
private void CopyToCharBuffer(string value, ref int index, ref int count) private void CopyToCharBuffer(string value, ref int index, ref int count)
{ {
var remaining = Math.Min(_charBufferSize - _charBufferCount, count); var remaining = Math.Min(_charBufferSize - _charBufferCount, count);
@ -336,5 +404,11 @@ namespace Microsoft.AspNetCore.WebUtilities
index += remaining; index += remaining;
count -= remaining; count -= remaining;
} }
[MethodImpl(MethodImplOptions.NoInlining)]
private static Task GetObjectDisposedTask()
{
return Task.FromException(new ObjectDisposedException(nameof(HttpResponseStreamWriter)));
}
} }
} }

View File

@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.WebUtilities
var anchorIndex = uri.IndexOf('#'); var anchorIndex = uri.IndexOf('#');
var uriToBeAppended = uri; var uriToBeAppended = uri;
var anchorText = ""; var anchorText = "";
// If there is an anchor, then the query string must be inserted before its first occurance. // If there is an anchor, then the query string must be inserted before its first occurence.
if (anchorIndex != -1) if (anchorIndex != -1)
{ {
anchorText = uri.Substring(anchorIndex); anchorText = uri.Substring(anchorIndex);

View File

@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
[Fact] [Fact]
public async Task MutipartReader_ReadSinglePartBody_Success() public async Task MultipartReader_ReadSinglePartBody_Success()
{ {
var stream = MakeStream(OnePartBody); var stream = MakeStream(OnePartBody);
var reader = new MultipartReader(Boundary, stream); var reader = new MultipartReader(Boundary, stream);
@ -123,7 +123,7 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
[Fact] [Fact]
public async Task MutipartReader_HeaderCountExceeded_Throws() public async Task MultipartReader_HeaderCountExceeded_Throws()
{ {
var stream = MakeStream(OnePartBodyTwoHeaders); var stream = MakeStream(OnePartBodyTwoHeaders);
var reader = new MultipartReader(Boundary, stream) var reader = new MultipartReader(Boundary, stream)
@ -136,7 +136,7 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
[Fact] [Fact]
public async Task MutipartReader_HeadersLengthExceeded_Throws() public async Task MultipartReader_HeadersLengthExceeded_Throws()
{ {
var stream = MakeStream(OnePartBodyTwoHeaders); var stream = MakeStream(OnePartBodyTwoHeaders);
var reader = new MultipartReader(Boundary, stream) var reader = new MultipartReader(Boundary, stream)
@ -149,7 +149,7 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
[Fact] [Fact]
public async Task MutipartReader_ReadSinglePartBodyWithTrailingWhitespace_Success() public async Task MultipartReader_ReadSinglePartBodyWithTrailingWhitespace_Success()
{ {
var stream = MakeStream(OnePartBodyWithTrailingWhitespace); var stream = MakeStream(OnePartBodyWithTrailingWhitespace);
var reader = new MultipartReader(Boundary, stream); var reader = new MultipartReader(Boundary, stream);
@ -166,7 +166,7 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
[Fact] [Fact]
public async Task MutipartReader_ReadSinglePartBodyWithoutLastCRLF_Success() public async Task MultipartReader_ReadSinglePartBodyWithoutLastCRLF_Success()
{ {
var stream = MakeStream(OnePartBodyWithoutFinalCRLF); var stream = MakeStream(OnePartBodyWithoutFinalCRLF);
var reader = new MultipartReader(Boundary, stream); var reader = new MultipartReader(Boundary, stream);
@ -183,7 +183,7 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
[Fact] [Fact]
public async Task MutipartReader_ReadTwoPartBody_Success() public async Task MultipartReader_ReadTwoPartBody_Success()
{ {
var stream = MakeStream(TwoPartBody); var stream = MakeStream(TwoPartBody);
var reader = new MultipartReader(Boundary, stream); var reader = new MultipartReader(Boundary, stream);
@ -209,7 +209,7 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
[Fact] [Fact]
public async Task MutipartReader_ReadTwoPartBodyWithUnicodeFileName_Success() public async Task MultipartReader_ReadTwoPartBodyWithUnicodeFileName_Success()
{ {
var stream = MakeStream(TwoPartBodyWithUnicodeFileName); var stream = MakeStream(TwoPartBodyWithUnicodeFileName);
var reader = new MultipartReader(Boundary, stream); var reader = new MultipartReader(Boundary, stream);
@ -235,7 +235,7 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
[Fact] [Fact]
public async Task MutipartReader_ThreePartBody_Success() public async Task MultipartReader_ThreePartBody_Success()
{ {
var stream = MakeStream(ThreePartBody); var stream = MakeStream(ThreePartBody);
var reader = new MultipartReader(Boundary, stream); var reader = new MultipartReader(Boundary, stream);
@ -270,7 +270,7 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
[Fact] [Fact]
public void MutipartReader_BufferSizeMustBeLargerThanBoundary_Throws() public void MultipartReader_BufferSizeMustBeLargerThanBoundary_Throws()
{ {
var stream = MakeStream(ThreePartBody); var stream = MakeStream(ThreePartBody);
Assert.Throws<ArgumentOutOfRangeException>(() => Assert.Throws<ArgumentOutOfRangeException>(() =>
@ -280,7 +280,7 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
[Fact] [Fact]
public async Task MutipartReader_TwoPartBodyIncompleteBuffer_TwoSectionsReadSuccessfullyThirdSectionThrows() public async Task MultipartReader_TwoPartBodyIncompleteBuffer_TwoSectionsReadSuccessfullyThirdSectionThrows()
{ {
var stream = MakeStream(TwoPartBodyIncompleteBuffer); var stream = MakeStream(TwoPartBodyIncompleteBuffer);
var reader = new MultipartReader(Boundary, stream); var reader = new MultipartReader(Boundary, stream);
@ -311,7 +311,7 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
[Fact] [Fact]
public async Task MutipartReader_ReadInvalidUtf8Header_ReplacementCharacters() public async Task MultipartReader_ReadInvalidUtf8Header_ReplacementCharacters()
{ {
var body1 = var body1 =
"--9051914041544843365972754266\r\n" + "--9051914041544843365972754266\r\n" +
@ -346,7 +346,7 @@ namespace Microsoft.AspNetCore.WebUtilities
} }
[Fact] [Fact]
public async Task MutipartReader_ReadInvalidUtf8SurrogateHeader_ReplacementCharacters() public async Task MultipartReader_ReadInvalidUtf8SurrogateHeader_ReplacementCharacters()
{ {
var body1 = var body1 =
"--9051914041544843365972754266\r\n" + "--9051914041544843365972754266\r\n" +

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netcoreapp2.1;net461</TargetFrameworks> <TargetFrameworks>netcoreapp2.2;net461</TargetFrameworks>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
</PropertyGroup> </PropertyGroup>