diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Formatters/TextInputFormatter.cs b/src/Microsoft.AspNetCore.Mvc.Core/Formatters/TextInputFormatter.cs
index 8967511c00..9296bb68c1 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Formatters/TextInputFormatter.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Formatters/TextInputFormatter.cs
@@ -64,7 +64,9 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
/// The .
/// The used to read the request body.
/// A that on completion deserializes the request body.
- public abstract Task ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding);
+ public abstract Task ReadRequestBodyAsync(
+ InputFormatterContext context,
+ Encoding encoding);
///
/// Returns an based on 's
@@ -82,25 +84,31 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
throw new ArgumentNullException(nameof(context));
}
- if (SupportedEncodings?.Count == 0)
+ if (SupportedEncodings.Count == 0)
{
- var message = Resources.FormatTextInputFormatter_SupportedEncodingsMustNotBeEmpty(nameof(SupportedEncodings));
+ var message = Resources.FormatTextInputFormatter_SupportedEncodingsMustNotBeEmpty(
+ nameof(SupportedEncodings));
throw new InvalidOperationException(message);
}
- var request = context.HttpContext.Request;
-
- var requestEncoding = request.ContentType == null ? null : MediaType.GetEncoding(request.ContentType);
- if (requestEncoding != null)
+ var requestContentType = context.HttpContext.Request.ContentType;
+ var requestMediaType = requestContentType == null ? default(MediaType) : new MediaType(requestContentType);
+ if (requestMediaType.Charset.HasValue)
{
- for (int i = 0; i < SupportedEncodings.Count; i++)
+ // Create Encoding based on requestMediaType.Charset to support charset aliases and custom Encoding
+ // providers. Charset -> Encoding -> encoding.WebName chain canonicalizes the charset name.
+ var requestEncoding = requestMediaType.Encoding;
+ if (requestEncoding != null)
{
- if (string.Equals(
- requestEncoding.WebName,
- SupportedEncodings[i].WebName,
- StringComparison.OrdinalIgnoreCase))
+ for (int i = 0; i < SupportedEncodings.Count; i++)
{
- return SupportedEncodings[i];
+ if (string.Equals(
+ requestEncoding.WebName,
+ SupportedEncodings[i].WebName,
+ StringComparison.OrdinalIgnoreCase))
+ {
+ return SupportedEncodings[i];
+ }
}
}
@@ -116,7 +124,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
// cases where the client doesn't send a content type header or sends a content
// type header without encoding. For that reason we pick the first encoding of the
// list of supported encodings and try to use that to read the body. This encoding
- // is UTF-8 by default on our formatters, which generally is a safe choice for the
+ // is UTF-8 by default in our formatters, which generally is a safe choice for the
// encoding.
return SupportedEncodings[0];
}
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/TextInputFormatterTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/TextInputFormatterTest.cs
index c44135c856..f781cdf303 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/TextInputFormatterTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/TextInputFormatterTest.cs
@@ -62,8 +62,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
Assert.Throws(() => formatter.TestSelectCharacterEncoding(context));
}
- [Fact]
- public void SelectCharacterEncoding_ReturnsNull_IfItCanNotUnderstandContentTypeEncoding()
+ [Theory]
+ [InlineData("utf-8")]
+ [InlineData("invalid")]
+ public void SelectCharacterEncoding_ReturnsNull_IfItCanNotUnderstandContentTypeEncoding(string charset)
{
// Arrange
var formatter = new TestFormatter();
@@ -76,7 +78,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)),
(stream, encoding) => new StreamReader(stream, encoding));
- context.HttpContext.Request.ContentType = "application/json;charset=utf-8";
+ context.HttpContext.Request.ContentType = "application/json;charset=" + charset;
// Act
var result = formatter.TestSelectCharacterEncoding(context);
@@ -110,9 +112,79 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
}
[Theory]
- [InlineData("application/json")]
+ [InlineData("unicode-1-1-utf-8")]
+ [InlineData("unicode-2-0-utf-8")]
+ [InlineData("unicode-1-1-utf-8")]
+ [InlineData("unicode-2-0-utf-8")]
+ public void SelectCharacterEncoding_ReturnsUTF8Encoding_IfContentTypeIsAnAlias(string charset)
+ {
+ // Arrange
+ var formatter = new TestFormatter();
+ formatter.SupportedEncodings.Add(Encoding.UTF32);
+ formatter.SupportedEncodings.Add(Encoding.UTF8);
+
+ var context = new InputFormatterContext(
+ new DefaultHttpContext(),
+ "something",
+ new ModelStateDictionary(),
+ new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)),
+ (stream, encoding) => new StreamReader(stream, encoding));
+
+ context.HttpContext.Request.ContentType = "application/json;charset=" + charset;
+
+ // Act
+ var result = formatter.TestSelectCharacterEncoding(context);
+
+ // Assert
+ Assert.Equal(Encoding.UTF8, result);
+ }
+
+ [Theory]
+ [InlineData("ANSI_X3.4-1968")]
+ [InlineData("ANSI_X3.4-1986")]
+ [InlineData("ascii")]
+ [InlineData("cp367")]
+ [InlineData("csASCII")]
+ [InlineData("IBM367")]
+ [InlineData("iso-ir-6")]
+ [InlineData("ISO646-US")]
+ [InlineData("ISO_646.irv:1991")]
+ [InlineData("us")]
+ public void SelectCharacterEncoding_ReturnsAsciiEncoding_IfContentTypeIsAnAlias(string charset)
+ {
+ // Arrange
+ var formatter = new TestFormatter();
+ formatter.SupportedEncodings.Add(Encoding.UTF32);
+ formatter.SupportedEncodings.Add(Encoding.ASCII);
+
+ var context = new InputFormatterContext(
+ new DefaultHttpContext(),
+ "something",
+ new ModelStateDictionary(),
+ new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)),
+ (stream, encoding) => new StreamReader(stream, encoding));
+
+ context.HttpContext.Request.ContentType = "application/json;charset=\"" + charset + "\"";
+
+ // Act
+ var result = formatter.TestSelectCharacterEncoding(context);
+
+ // Assert
+ Assert.Equal(Encoding.ASCII, result);
+ }
+
+ [Theory]
[InlineData("")]
- public void SelectCharacterEncoding_ReturnsFirstEncoding_IfContentTypeIsNotSpecifiedOrDoesNotHaveEncoding(string contentType)
+ [InlineData("(garbage)")]
+ [InlineData("(garbage); charset=utf-32")]
+ [InlineData("text/(garbage)")]
+ [InlineData("text/(garbage); charset=utf-32")]
+ [InlineData("application/json")]
+ [InlineData("application/json; charset")]
+ [InlineData("application/json; charset=(garbage)")]
+ [InlineData("application/json; version=(garbage); charset=utf-32")]
+ public void SelectCharacterEncoding_ReturnsFirstEncoding_IfContentTypeIsMissingInvalidOrDoesNotHaveEncoding(
+ string contentType)
{
// Arrange
var formatter = new TestFormatter();