Skip to content

Commit 388f939

Browse files
authored
Support non utf-8 charsets (#741)
1 parent a85a691 commit 388f939

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

src/Transports.AspNetCore/GraphQLHttpMiddleware.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,25 @@ public virtual async Task InvokeAsync(HttpContext context, RequestDelegate next)
8080
GraphQLRequest[] deserializationResult;
8181
try
8282
{
83+
#if NET5_0_OR_GREATER
84+
if (!TryGetEncoding(mediaTypeHeader.CharSet, out var sourceEncoding))
85+
{
86+
await HandleContentTypeCouldNotBeParsedErrorAsync(context);
87+
return;
88+
}
89+
// Wrap content stream into a transcoding stream that buffers the data transcoded from the sourceEncoding to utf-8.
90+
if (sourceEncoding != null && sourceEncoding != System.Text.Encoding.UTF8)
91+
{
92+
using var tempStream = System.Text.Encoding.CreateTranscodingStream(httpRequest.Body, innerStreamEncoding: sourceEncoding, outerStreamEncoding: System.Text.Encoding.UTF8, leaveOpen: true);
93+
deserializationResult = await _serializer.ReadAsync<GraphQLRequest[]>(tempStream, cancellationToken);
94+
}
95+
else
96+
{
97+
deserializationResult = await _serializer.ReadAsync<GraphQLRequest[]>(httpRequest.Body, cancellationToken);
98+
}
99+
#else
83100
deserializationResult = await _serializer.ReadAsync<GraphQLRequest[]>(httpRequest.Body, cancellationToken);
101+
#endif
84102
}
85103
catch (Exception ex)
86104
{
@@ -288,5 +306,34 @@ private async Task<GraphQLRequest> DeserializeFromGraphBodyAsync(Stream bodyStre
288306

289307
return new GraphQLRequest { Query = query }; // application/graphql MediaType supports only query text
290308
}
309+
310+
#if NET5_0_OR_GREATER
311+
private static bool TryGetEncoding(string charset, out System.Text.Encoding encoding)
312+
{
313+
encoding = null;
314+
315+
if (string.IsNullOrEmpty(charset))
316+
return true;
317+
318+
try
319+
{
320+
// Remove at most a single set of quotes.
321+
if (charset.Length > 2 && charset[0] == '\"' && charset[charset.Length - 1] == '\"')
322+
{
323+
encoding = System.Text.Encoding.GetEncoding(charset.Substring(1, charset.Length - 2));
324+
}
325+
else
326+
{
327+
encoding = System.Text.Encoding.GetEncoding(charset);
328+
}
329+
}
330+
catch (ArgumentException)
331+
{
332+
return false;
333+
}
334+
335+
return true;
336+
}
337+
#endif
291338
}
292339
}

tests/Samples.Server.Tests/ResponseTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ public async Task Wrong_Query_Should_Return_Error(HttpMethod httpMethod, HttpCon
9898
"Invalid 'Content-Type' header: non-supported media type 'something/unknown; charset=utf-8'. Must be of 'application/json', 'application/graphql' or 'application/x-www-form-urlencoded'. See: http://graphql.org/learn/serving-over-http/."
9999
},
100100

101+
// MediaTypeHeaderValue ctor throws exception
102+
// POST with unsupported charset should be a unsupported media type
103+
//new object[]
104+
//{
105+
// HttpMethod.Post,
106+
// new StringContent(Serializer.ToJson(new GraphQLRequest { Query = "query { __schema { queryType { name } } }" }), Encoding.UTF8, "application/json; charset=utf-3"),
107+
// HttpStatusCode.UnsupportedMediaType,
108+
// "Invalid 'Content-Type' header: non-supported media type 'application/json; charset=utf-3'. Must be of 'application/json', 'application/graphql' or 'application/x-www-form-urlencoded'. See: http://graphql.org/learn/serving-over-http/."
109+
//},
110+
101111
// POST with JSON mime type that doesn't start with an object or array token should be a bad request
102112
new object[]
103113
{

0 commit comments

Comments
 (0)