diff --git a/eng/Baseline.props b/eng/Baseline.props
index f052db5eb0..1d647402db 100644
--- a/eng/Baseline.props
+++ b/eng/Baseline.props
@@ -4,6 +4,24 @@
$(MSBuildAllProjects);$(MSBuildThisFileFullPath)
2.2.0
+
+
+ 2.2.0
+
+
+
+
+
+
+
+
+ 2.2.0
+
+
+
+
+
+
2.2.0
@@ -98,48 +116,48 @@
- 2.1.1
+ 2.2.0
-
-
-
+
+
+
- 2.1.1
+ 2.2.0
-
-
+
+
- 2.1.1
+ 2.2.0
-
+
-
+
- 2.1.1
+ 2.2.0
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -152,39 +170,39 @@
- 2.1.1
+ 2.2.0
-
+
- 2.1.1
+ 2.2.0
-
-
-
+
+
+
- 2.1.1
+ 2.2.0
-
+
- 2.1.1
+ 2.2.0
-
-
-
-
-
+
+
+
+
+
@@ -196,10 +214,10 @@
- 2.1.1
+ 2.2.0
-
+
@@ -291,11 +309,11 @@
- 2.1.1
+ 2.2.0
-
-
+
+
@@ -309,18 +327,18 @@
- 2.1.1
+ 2.2.0
-
+
- 2.1.1
+ 2.2.0
-
+
-
+
\ No newline at end of file
diff --git a/src/Http/Authentication.Abstractions/src/TokenExtensions.cs b/src/Http/Authentication.Abstractions/src/TokenExtensions.cs
index 497acabc23..128b0651d1 100644
--- a/src/Http/Authentication.Abstractions/src/TokenExtensions.cs
+++ b/src/Http/Authentication.Abstractions/src/TokenExtensions.cs
@@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Authentication
/// Returns all of the AuthenticationTokens contained in the properties.
///
/// The properties.
- /// The authentication toekns.
+ /// The authentication tokens.
public static IEnumerable GetTokens(this AuthenticationProperties properties)
{
if (properties == null)
@@ -132,7 +132,7 @@ namespace Microsoft.AspNetCore.Authentication
/// The context.
/// The name of the token.
/// The value of the token.
- public static Task GetTokenAsync(this IAuthenticationService auth, HttpContext context, string tokenName)
+ public static Task GetTokenAsync(this IAuthenticationService auth, HttpContext context, string tokenName)
=> auth.GetTokenAsync(context, scheme: null, tokenName: tokenName);
///
diff --git a/src/Http/Authentication.Core/src/AuthenticationSchemeProvider.cs b/src/Http/Authentication.Core/src/AuthenticationSchemeProvider.cs
index 050118d3c4..a7b913b1b2 100644
--- a/src/Http/Authentication.Core/src/AuthenticationSchemeProvider.cs
+++ b/src/Http/Authentication.Core/src/AuthenticationSchemeProvider.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
@@ -49,6 +50,9 @@ namespace Microsoft.AspNetCore.Authentication
private readonly IDictionary _schemes;
private readonly List _requestHandlers;
+ // Used as a safe return value for enumeration apis
+ private IEnumerable _schemesCopy = Array.Empty();
+ private IEnumerable _requestHandlersCopy = Array.Empty();
private Task GetDefaultSchemeAsync()
=> _options.DefaultScheme != null
@@ -102,7 +106,7 @@ namespace Microsoft.AspNetCore.Authentication
///
/// Returns the scheme that will be used by default for .
/// This is typically specified via .
- /// Otherwise this will fallback to if that supoorts sign out.
+ /// Otherwise this will fallback to if that supports sign out.
///
/// The scheme that will be used by default for .
public virtual Task GetDefaultSignOutSchemeAsync()
@@ -123,7 +127,7 @@ namespace Microsoft.AspNetCore.Authentication
///
/// The schemes in priority order for request handling
public virtual Task> GetRequestHandlerSchemesAsync()
- => Task.FromResult>(_requestHandlers);
+ => Task.FromResult(_requestHandlersCopy);
///
/// Registers a scheme for use by .
@@ -144,8 +148,10 @@ namespace Microsoft.AspNetCore.Authentication
if (typeof(IAuthenticationRequestHandler).IsAssignableFrom(scheme.HandlerType))
{
_requestHandlers.Add(scheme);
+ _requestHandlersCopy = _requestHandlers.ToArray();
}
_schemes[scheme.Name] = scheme;
+ _schemesCopy = _schemes.Values.ToArray();
}
}
@@ -164,13 +170,17 @@ namespace Microsoft.AspNetCore.Authentication
if (_schemes.ContainsKey(name))
{
var scheme = _schemes[name];
- _requestHandlers.Remove(scheme);
+ if (_requestHandlers.Remove(scheme))
+ {
+ _requestHandlersCopy = _requestHandlers.ToArray();
+ }
_schemes.Remove(name);
+ _schemesCopy = _schemes.Values.ToArray();
}
}
}
public virtual Task> GetAllSchemesAsync()
- => Task.FromResult>(_schemes.Values);
+ => Task.FromResult(_schemesCopy);
}
}
\ No newline at end of file
diff --git a/src/Http/Headers/src/ContentDispositionHeaderValue.cs b/src/Http/Headers/src/ContentDispositionHeaderValue.cs
index b9292ac1a8..392a441733 100644
--- a/src/Http/Headers/src/ContentDispositionHeaderValue.cs
+++ b/src/Http/Headers/src/ContentDispositionHeaderValue.cs
@@ -155,7 +155,7 @@ namespace Microsoft.Net.Http.Headers
{
if (!StringSegment.IsNullOrEmpty(fileName))
{
- FileName = Sanatize(fileName);
+ FileName = Sanitize(fileName);
}
else
{
@@ -166,7 +166,7 @@ namespace Microsoft.Net.Http.Headers
///
/// Sets the FileName parameter using encodings appropriate for MIME headers.
- /// The FileNameStar paraemter is removed.
+ /// The FileNameStar parameter is removed.
///
///
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.
- private StringSegment Sanatize(StringSegment input)
+ private StringSegment Sanitize(StringSegment input)
{
var result = input;
diff --git a/src/Http/Headers/src/HeaderUtilities.cs b/src/Http/Headers/src/HeaderUtilities.cs
index 20b4319252..c45ca9cf43 100644
--- a/src/Http/Headers/src/HeaderUtilities.cs
+++ b/src/Http/Headers/src/HeaderUtilities.cs
@@ -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.
Contract.Assert(Contract.ForAll(alreadyFound, value => { return value; }),
"Expected all values in 'alreadyFound' to be true since collections are considered equal.");
diff --git a/src/Http/Headers/src/HttpRuleParser.cs b/src/Http/Headers/src/HttpRuleParser.cs
index 3741ffa110..05f4a4576f 100644
--- a/src/Http/Headers/src/HttpRuleParser.cs
+++ b/src/Http/Headers/src/HttpRuleParser.cs
@@ -225,7 +225,7 @@ namespace Microsoft.Net.Http.Headers
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 ((startIndex + 2 > input.Length) || (input[startIndex + 1] > 127))
{
diff --git a/src/Http/Headers/src/MediaTypeHeaderValue.cs b/src/Http/Headers/src/MediaTypeHeaderValue.cs
index 32074b44cc..e069210843 100644
--- a/src/Http/Headers/src/MediaTypeHeaderValue.cs
+++ b/src/Http/Headers/src/MediaTypeHeaderValue.cs
@@ -650,6 +650,7 @@ namespace Microsoft.Net.Http.Headers
{
return true;
}
+
if (set.Suffix.HasValue)
{
if (Suffix.HasValue)
@@ -663,7 +664,10 @@ namespace Microsoft.Net.Http.Headers
}
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);
}
+ private bool MatchesEitherSubtypeOrSuffix(MediaTypeHeaderValue set)
+ {
+ return set.SubType.Equals(SubType, StringComparison.OrdinalIgnoreCase) ||
+ set.SubType.Equals(Suffix, StringComparison.OrdinalIgnoreCase);
+ }
+
private bool MatchesParameters(MediaTypeHeaderValue set)
{
if (set._parameters != null && set._parameters.Count != 0)
diff --git a/src/Http/Headers/src/RangeItemHeaderValue.cs b/src/Http/Headers/src/RangeItemHeaderValue.cs
index 99fdbfef5c..3b177f6e9a 100644
--- a/src/Http/Headers/src/RangeItemHeaderValue.cs
+++ b/src/Http/Headers/src/RangeItemHeaderValue.cs
@@ -169,7 +169,7 @@ namespace Microsoft.Net.Http.Headers
current = current + fromLength;
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] != '-'))
{
// We need a '-' character otherwise this can't be a valid range.
diff --git a/src/Http/Headers/test/ContentDispositionHeaderValueTest.cs b/src/Http/Headers/test/ContentDispositionHeaderValueTest.cs
index ad1f7fce1f..f2c53a8727 100644
--- a/src/Http/Headers/test/ContentDispositionHeaderValueTest.cs
+++ b/src/Http/Headers/test/ContentDispositionHeaderValueTest.cs
@@ -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") },
- { "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" } },
diff --git a/src/Http/Headers/test/CookieHeaderValueTest.cs b/src/Http/Headers/test/CookieHeaderValueTest.cs
index 416441991d..edd55bb7ab 100644
--- a/src/Http/Headers/test/CookieHeaderValueTest.cs
+++ b/src/Http/Headers/test/CookieHeaderValueTest.cs
@@ -286,7 +286,7 @@ namespace Microsoft.Net.Http.Headers
public void CookieHeaderValue_ParseList_ExcludesInvalidValues(IList cookies, string[] 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(), results);
}
diff --git a/src/Http/Headers/test/EntityTagHeaderValueTest.cs b/src/Http/Headers/test/EntityTagHeaderValueTest.cs
index f633fec226..b4ae186fb4 100644
--- a/src/Http/Headers/test/EntityTagHeaderValueTest.cs
+++ b/src/Http/Headers/test/EntityTagHeaderValueTest.cs
@@ -403,7 +403,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void ParseList_WithSomeInvlaidValues_ExcludesInvalidValues()
+ public void ParseList_WithSomeInvalidValues_ExcludesInvalidValues()
{
var inputs = new[]
{
@@ -433,7 +433,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void ParseStrictList_WithSomeInvlaidValues_Throws()
+ public void ParseStrictList_WithSomeInvalidValues_Throws()
{
var inputs = new[]
{
@@ -451,7 +451,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void TryParseList_WithSomeInvlaidValues_ExcludesInvalidValues()
+ public void TryParseList_WithSomeInvalidValues_ExcludesInvalidValues()
{
var inputs = new[]
{
@@ -482,7 +482,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void TryParseStrictList_WithSomeInvlaidValues_ReturnsFalse()
+ public void TryParseStrictList_WithSomeInvalidValues_ReturnsFalse()
{
var inputs = new[]
{
diff --git a/src/Http/Headers/test/MediaTypeHeaderValueTest.cs b/src/Http/Headers/test/MediaTypeHeaderValueTest.cs
index 75cccabc9c..63b2fa391b 100644
--- a/src/Http/Headers/test/MediaTypeHeaderValueTest.cs
+++ b/src/Http/Headers/test/MediaTypeHeaderValueTest.cs
@@ -617,7 +617,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void ParseList_WithSomeInvlaidValues_IgnoresInvalidValues()
+ public void ParseList_WithSomeInvalidValues_IgnoresInvalidValues()
{
var inputs = new[]
{
@@ -640,7 +640,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void ParseStrictList_WithSomeInvlaidValues_Throws()
+ public void ParseStrictList_WithSomeInvalidValues_Throws()
{
var inputs = new[]
{
@@ -651,7 +651,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void TryParseList_WithSomeInvlaidValues_IgnoresInvalidValues()
+ public void TryParseList_WithSomeInvalidValues_IgnoresInvalidValues()
{
var inputs = new[]
{
@@ -676,7 +676,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void TryParseStrictList_WithSomeInvlaidValues_ReturnsFalse()
+ public void TryParseStrictList_WithSomeInvalidValues_ReturnsFalse()
{
var inputs = new[]
{
@@ -750,6 +750,8 @@ namespace Microsoft.Net.Http.Headers
[InlineData("application/entity+json", "application/entity+json")]
[InlineData("application/*+json", "application/entity+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/vnd.github+json", "application/vnd.github+json")]
[InlineData("application/*", "application/entity+JSON")]
@@ -774,6 +776,7 @@ namespace Microsoft.Net.Http.Headers
[InlineData("application/*+*", "application/json")]
[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/entity+json", "application/entity")]
public void IsSubSetOfWithSuffixes_NegativeCases(string set, string subset)
{
// Arrange
diff --git a/src/Http/Headers/test/NameValueHeaderValueTest.cs b/src/Http/Headers/test/NameValueHeaderValueTest.cs
index cac18debbb..4833b6898a 100644
--- a/src/Http/Headers/test/NameValueHeaderValueTest.cs
+++ b/src/Http/Headers/test/NameValueHeaderValueTest.cs
@@ -60,7 +60,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void Copy_NameOnly_SuccesfullyCopied()
+ public void Copy_NameOnly_SuccessfullyCopied()
{
var pair0 = new NameValueHeaderValue("name");
var pair1 = pair0.Copy();
@@ -95,7 +95,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void Copy_NameAndValue_SuccesfullyCopied()
+ public void Copy_NameAndValue_SuccessfullyCopied()
{
var pair0 = new NameValueHeaderValue("name", "value");
var pair1 = pair0.Copy();
@@ -466,7 +466,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void ParseList_WithSomeInvlaidValues_ExcludesInvalidValues()
+ public void ParseList_WithSomeInvalidValues_ExcludesInvalidValues()
{
var inputs = new[]
{
@@ -502,7 +502,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void ParseStrictList_WithSomeInvlaidValues_Throws()
+ public void ParseStrictList_WithSomeInvalidValues_Throws()
{
var inputs = new[]
{
@@ -520,7 +520,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void TryParseList_WithSomeInvlaidValues_ExcludesInvalidValues()
+ public void TryParseList_WithSomeInvalidValues_ExcludesInvalidValues()
{
var inputs = new[]
{
@@ -557,7 +557,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void TryParseStrictList_WithSomeInvlaidValues_ReturnsFalse()
+ public void TryParseStrictList_WithSomeInvalidValues_ReturnsFalse()
{
var inputs = new[]
{
diff --git a/src/Http/Headers/test/RangeConditionHeaderValueTest.cs b/src/Http/Headers/test/RangeConditionHeaderValueTest.cs
index ce7c73997b..dab3f670a4 100644
--- a/src/Http/Headers/test/RangeConditionHeaderValueTest.cs
+++ b/src/Http/Headers/test/RangeConditionHeaderValueTest.cs
@@ -39,7 +39,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void ToString_UseDifferentrangeConditions_AllSerializedCorrectly()
+ public void ToString_UseDifferentRangeConditions_AllSerializedCorrectly()
{
var rangeCondition = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"x\""));
Assert.Equal("\"x\"", rangeCondition.ToString());
@@ -49,7 +49,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void GetHashCode_UseSameAndDifferentrangeConditions_SameOrDifferentHashCodes()
+ public void GetHashCode_UseSameAndDifferentRangeConditions_SameOrDifferentHashCodes()
{
var rangeCondition1 = new RangeConditionHeaderValue("\"x\"");
var rangeCondition2 = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"x\""));
diff --git a/src/Http/Headers/test/SetCookieHeaderValueTest.cs b/src/Http/Headers/test/SetCookieHeaderValueTest.cs
index e7e8bf045a..9a920f40d0 100644
--- a/src/Http/Headers/test/SetCookieHeaderValueTest.cs
+++ b/src/Http/Headers/test/SetCookieHeaderValueTest.cs
@@ -389,7 +389,7 @@ namespace Microsoft.Net.Http.Headers
public void SetCookieHeaderValue_ParseList_ExcludesInvalidValues(IList cookies, string[] 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(), results);
}
diff --git a/src/Http/Headers/test/StringWithQualityHeaderValueTest.cs b/src/Http/Headers/test/StringWithQualityHeaderValueTest.cs
index 49ee58b93e..971ad1028f 100644
--- a/src/Http/Headers/test/StringWithQualityHeaderValueTest.cs
+++ b/src/Http/Headers/test/StringWithQualityHeaderValueTest.cs
@@ -354,7 +354,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void ParseList_WithSomeInvlaidValues_IgnoresInvalidValues()
+ public void ParseList_WithSomeInvalidValues_IgnoresInvalidValues()
{
var inputs = new[]
{
@@ -392,7 +392,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void ParseStrictList_WithSomeInvlaidValues_Throws()
+ public void ParseStrictList_WithSomeInvalidValues_Throws()
{
var inputs = new[]
{
@@ -412,7 +412,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void TryParseList_WithSomeInvlaidValues_IgnoresInvalidValues()
+ public void TryParseList_WithSomeInvalidValues_IgnoresInvalidValues()
{
var inputs = new[]
{
@@ -451,7 +451,7 @@ namespace Microsoft.Net.Http.Headers
}
[Fact]
- public void TryParseStrictList_WithSomeInvlaidValues_ReturnsFalse()
+ public void TryParseStrictList_WithSomeInvalidValues_ReturnsFalse()
{
var inputs = new[]
{
diff --git a/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs b/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs
index a4f67ce4a2..4215b82697 100644
--- a/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs
+++ b/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs
@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Builder.Extensions
{
///
- /// 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.
///
public class MapMiddleware
{
@@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Builder.Extensions
private readonly MapOptions _options;
///
- /// Creates a new instace of .
+ /// Creates a new instance of .
///
/// The delegate representing the next middleware in the request pipeline.
/// The middleware options.
diff --git a/src/Http/Http.Abstractions/src/Extensions/MapWhenMiddleware.cs b/src/Http/Http.Abstractions/src/Extensions/MapWhenMiddleware.cs
index b012626ba9..1441da4d99 100644
--- a/src/Http/Http.Abstractions/src/Extensions/MapWhenMiddleware.cs
+++ b/src/Http/Http.Abstractions/src/Extensions/MapWhenMiddleware.cs
@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Builder.Extensions
{
///
- /// 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.
///
public class MapWhenMiddleware
{
diff --git a/src/Http/Http.Abstractions/src/Extensions/ResponseTrailerExtensions.cs b/src/Http/Http.Abstractions/src/Extensions/ResponseTrailerExtensions.cs
new file mode 100644
index 0000000000..745cbfd9de
--- /dev/null
+++ b/src/Http/Http.Abstractions/src/Extensions/ResponseTrailerExtensions.cs
@@ -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";
+
+ ///
+ /// Adds the given trailer name to the 'Trailer' response header. This must happen before the response headers are sent.
+ ///
+ ///
+ ///
+ public static void DeclareTrailer(this HttpResponse response, string trailerName)
+ {
+ response.Headers.AppendCommaSeparatedValues(Trailer, trailerName);
+ }
+
+ ///
+ /// Indicates if the server supports sending trailer headers for this response.
+ ///
+ ///
+ ///
+ public static bool SupportsTrailers(this HttpResponse response)
+ {
+ var feature = response.HttpContext.Features.Get();
+ return feature?.Trailers != null && !feature.Trailers.IsReadOnly;
+ }
+
+ ///
+ /// Adds the given trailer header to the trailers collection to be sent at the end of the response body.
+ /// Check or an InvalidOperationException may be thrown.
+ ///
+ ///
+ ///
+ ///
+ public static void AppendTrailer(this HttpResponse response, string trailerName, StringValues trailerValues)
+ {
+ var feature = response.HttpContext.Features.Get();
+ if (feature?.Trailers == null || feature.Trailers.IsReadOnly)
+ {
+ throw new InvalidOperationException("Trailers are not supported for this response.");
+ }
+
+ feature.Trailers.Append(trailerName, trailerValues);
+ }
+ }
+}
diff --git a/src/Http/Http.Abstractions/src/Extensions/UseMiddlewareExtensions.cs b/src/Http/Http.Abstractions/src/Extensions/UseMiddlewareExtensions.cs
index c07fe1e9f1..3342b4e08d 100644
--- a/src/Http/Http.Abstractions/src/Extensions/UseMiddlewareExtensions.cs
+++ b/src/Http/Http.Abstractions/src/Extensions/UseMiddlewareExtensions.cs
@@ -74,13 +74,13 @@ namespace Microsoft.AspNetCore.Builder
throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoInvokeMethod(InvokeMethodName, InvokeAsyncMethodName, middleware));
}
- var methodinfo = invokeMethods[0];
- if (!typeof(Task).IsAssignableFrom(methodinfo.ReturnType))
+ var methodInfo = invokeMethods[0];
+ if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType))
{
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))
{
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);
if (parameters.Length == 1)
{
- return (RequestDelegate)methodinfo.CreateDelegate(typeof(RequestDelegate), instance);
+ return (RequestDelegate)methodInfo.CreateDelegate(typeof(RequestDelegate), instance);
}
- var factory = Compile