fix: force to decode as utf-8 when header contains application/json to avoid text garbling. (#1700)

* fix: force to decode as utf-8 when header contains application/json to avoid text garbling.

The original processing is using `response.body` to deserialize as json.
However, this is decoded by latin1 if the header contains only "application/json" instead of "application/json; charset=utf-8".

Because of this behavior, if the response body is encoded UTF-8 but the headers doesn't contain charset, the body will garbling.

cf: https://github.com/dart-lang/http/issues/175

Since playframework 2.6 returns "Content-Type: application/json" without "charset=utf-8", I changed this parsing algolithm.

* fix: force to decode as utf-8 when header contains application/json to avoid text garbling on error.
This commit is contained in:
Daisuke Shimada 2019-01-09 12:08:35 +09:00 committed by William Cheng
parent 60dd3d51be
commit 189849319c
4 changed files with 32 additions and 8 deletions

View File

@ -89,22 +89,22 @@ class {{classname}} {
authNames);
if(response.statusCode >= 400) {
throw new ApiException(response.statusCode, response.body);
throw new ApiException(response.statusCode, _decodeBodyBytes(response));
} else if(response.body != null) {
{{#isListContainer}}
{{#returnType}}
return (apiClient.deserialize(response.body, '{{{returnType}}}') as List).map((item) => item as {{returnBaseType}}).toList();
return (apiClient.deserialize(_decodeBodyBytes(response), '{{{returnType}}}') as List).map((item) => item as {{returnBaseType}}).toList();
{{/returnType}}
{{/isListContainer}}
{{^isListContainer}}
{{#isMapContainer}}
{{#returnType}}
return new {{{returnType}}}.from(apiClient.deserialize(response.body, '{{{returnType}}}'));
return new {{{returnType}}}.from(apiClient.deserialize(_decodeBodyBytes(response), '{{{returnType}}}'));
{{/returnType}};
{{/isMapContainer}}
{{^isMapContainer}}
{{#returnType}}
return apiClient.deserialize(response.body, '{{{returnType}}}') as {{{returnType}}};
return apiClient.deserialize(_decodeBodyBytes(response), '{{{returnType}}}') as {{{returnType}}};
{{/returnType}}
{{/isMapContainer}}
{{/isListContainer}}

View File

@ -50,3 +50,15 @@ String parameterToString(dynamic value) {
return value.toString();
}
}
/// Returns the decoded body by utf-8 if application/json with the given headers.
/// Else, returns the decoded body by default algorithm of dart:http.
/// Because avoid to text garbling when header only contains "application/json" without "; charset=utf-8".
String _decodeBodyBytes(Response response) {
var contentType = response.headers['content-type'];
if (contentType != null && contentType.contains("application/json")) {
return utf8.decode(response.bodyBytes);
} else {
return response.body;
}
}

View File

@ -89,22 +89,22 @@ class {{classname}} {
authNames);
if(response.statusCode >= 400) {
throw new ApiException(response.statusCode, response.body);
throw new ApiException(response.statusCode, _decodeBodyBytes(response));
} else if(response.body != null) {
{{#isListContainer}}
{{#returnType}}
return (apiClient.deserialize(response.body, '{{{returnType}}}') as List).map((item) => item as {{returnBaseType}}).toList();
return (apiClient.deserialize(_decodeBodyBytes(response), '{{{returnType}}}') as List).map((item) => item as {{returnBaseType}}).toList();
{{/returnType}}
{{/isListContainer}}
{{^isListContainer}}
{{#isMapContainer}}
{{#returnType}}
return new {{{returnType}}}.from(apiClient.deserialize(response.body, '{{{returnType}}}'));
return new {{{returnType}}}.from(apiClient.deserialize(_decodeBodyBytes(response), '{{{returnType}}}'));
{{/returnType}};
{{/isMapContainer}}
{{^isMapContainer}}
{{#returnType}}
return apiClient.deserialize(response.body, '{{{returnType}}}') as {{{returnType}}};
return apiClient.deserialize(_decodeBodyBytes(response), '{{{returnType}}}') as {{{returnType}}};
{{/returnType}}
{{/isMapContainer}}
{{/isListContainer}}

View File

@ -50,3 +50,15 @@ String parameterToString(dynamic value) {
return value.toString();
}
}
/// Returns the decoded body by utf-8 if application/json with the given headers.
/// Else, returns the decoded body by default algorithm of dart:http.
/// Because avoid to text garbling when header only contains "application/json" without "; charset=utf-8".
String _decodeBodyBytes(Response response) {
var contentType = response.headers['content-type'];
if (contentType != null && contentType.contains("application/json")) {
return utf8.decode(response.bodyBytes);
} else {
return response.body;
}
}