This repository has been archived by the owner on Dec 14, 2018. It is now read-only.
/
TextInputFormatter.cs
131 lines (116 loc) · 5.78 KB
/
TextInputFormatter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// 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.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace Microsoft.AspNetCore.Mvc.Formatters
{
/// <summary>
/// Reads an object from a request body with a text format.
/// </summary>
public abstract class TextInputFormatter : InputFormatter
{
/// <summary>
/// Returns UTF8 Encoding without BOM and throws on invalid bytes.
/// </summary>
protected static readonly Encoding UTF8EncodingWithoutBOM
= new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
/// <summary>
/// Returns UTF16 Encoding which uses littleEndian byte order with BOM and throws on invalid bytes.
/// </summary>
protected static readonly Encoding UTF16EncodingLittleEndian
= new UnicodeEncoding(bigEndian: false, byteOrderMark: true, throwOnInvalidBytes: true);
/// <summary>
/// Gets the mutable collection of character encodings supported by
/// this <see cref="TextInputFormatter"/>. The encodings are
/// used when reading the data.
/// </summary>
public IList<Encoding> SupportedEncodings { get; } = new List<Encoding>();
/// <inheritdoc />
public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var selectedEncoding = SelectCharacterEncoding(context);
if (selectedEncoding == null)
{
var message = Resources.FormatUnsupportedContentType(
context.HttpContext.Request.ContentType);
var exception = new UnsupportedContentTypeException(message);
context.ModelState.AddModelError(context.ModelName, exception, context.Metadata);
return InputFormatterResult.FailureAsync();
}
return ReadRequestBodyAsync(context, selectedEncoding);
}
/// <summary>
/// Reads an object from the request body.
/// </summary>
/// <param name="context">The <see cref="InputFormatterContext"/>.</param>
/// <param name="encoding">The <see cref="Encoding"/> used to read the request body.</param>
/// <returns>A <see cref="Task"/> that on completion deserializes the request body.</returns>
public abstract Task<InputFormatterResult> ReadRequestBodyAsync(
InputFormatterContext context,
Encoding encoding);
/// <summary>
/// Returns an <see cref="Encoding"/> based on <paramref name="context"/>'s
/// character set.
/// </summary>
/// <param name="context">The <see cref="InputFormatterContext"/>.</param>
/// <returns>
/// An <see cref="Encoding"/> based on <paramref name="context"/>'s
/// character set. <c>null</c> if no supported encoding was found.
/// </returns>
protected Encoding SelectCharacterEncoding(InputFormatterContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (SupportedEncodings.Count == 0)
{
var message = Resources.FormatTextInputFormatter_SupportedEncodingsMustNotBeEmpty(
nameof(SupportedEncodings));
throw new InvalidOperationException(message);
}
var requestContentType = context.HttpContext.Request.ContentType;
var requestMediaType = requestContentType == null ? default(MediaType) : new MediaType(requestContentType);
if (requestMediaType.Charset.HasValue)
{
// 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)
{
for (int i = 0; i < SupportedEncodings.Count; i++)
{
if (string.Equals(
requestEncoding.WebName,
SupportedEncodings[i].WebName,
StringComparison.OrdinalIgnoreCase))
{
return SupportedEncodings[i];
}
}
}
// The client specified an encoding in the content type header of the request
// but we don't understand it. In this situation we don't try to pick any other encoding
// from the list of supported encodings and read the body with that encoding.
// Instead, we return null and that will translate later on into a 415 Unsupported Media Type
// response.
return null;
}
// We want to do our best effort to read the body of the request even in the
// 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 in our formatters, which generally is a safe choice for the
// encoding.
return SupportedEncodings[0];
}
}
}