From b7aed63e0b37accd494bd6617b0b715f4c579ffc Mon Sep 17 00:00:00 2001 From: Herbert Poul Date: Wed, 21 Aug 2024 13:42:09 +0200 Subject: [PATCH] use utf-8 encoding for json responses. --- packages/openapi_base/CHANGELOG.md | 4 ++++ .../lib/src/openapi_client_base.dart | 24 ++++++++++++++----- .../lib/src/openapi_content_type.dart | 11 +++++++-- packages/openapi_base/pubspec.lock | 12 +++++----- packages/openapi_base/pubspec.yaml | 5 ++-- 5 files changed, 40 insertions(+), 16 deletions(-) diff --git a/packages/openapi_base/CHANGELOG.md b/packages/openapi_base/CHANGELOG.md index ee01261..4315200 100644 --- a/packages/openapi_base/CHANGELOG.md +++ b/packages/openapi_base/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0-rc.1 + +* Use UTF-8 encoding by default for json responses. + ## 1.3.2 * Allow encoding optional parameters. diff --git a/packages/openapi_base/lib/src/openapi_client_base.dart b/packages/openapi_base/lib/src/openapi_client_base.dart index 046f5ef..07a8ca2 100644 --- a/packages/openapi_base/lib/src/openapi_client_base.dart +++ b/packages/openapi_base/lib/src/openapi_client_base.dart @@ -259,7 +259,7 @@ abstract class OpenApiClientResponse { Map> get headers; - OpenApiContentType responseContentType(); + OpenApiContentType? responseContentType(); Future> responseBodyJson(); @@ -342,12 +342,12 @@ class HttpClientResponse extends OpenApiClientResponse { @override Future> responseBodyJson() async { - return json.decode(response.body) as Map; + return json.decode(await responseBodyString()) as Map; } @override Future responseBodyJsonDynamic() async { - return json.decode(response.body); + return json.decode(await responseBodyString()); } @override @@ -357,14 +357,26 @@ class HttpClientResponse extends OpenApiClientResponse { late final Map> headers = response.headers.map((key, value) => MapEntry(key, [value])); + String? _responseContentTypeString() => response.headers['content-type']; + @override - OpenApiContentType responseContentType() { - final contentTypeString = response.headers['content-type']!; - return OpenApiContentType.parse(contentTypeString); + OpenApiContentType? responseContentType() { + if (_responseContentTypeString() case final contentTypeString?) { + return OpenApiContentType.parse(contentTypeString); + } + return null; } @override Future responseBodyString() async { + if (responseContentType() case final contentType?) { + final encoding = switch (contentType.charset) { + final charset? => Encoding.getByName(charset), + null => null, + } ?? + (contentType.isJson ? utf8 : latin1); + return encoding.decode(response.bodyBytes); + } return response.body; } diff --git a/packages/openapi_base/lib/src/openapi_content_type.dart b/packages/openapi_base/lib/src/openapi_content_type.dart index 74edf1e..b7e2308 100644 --- a/packages/openapi_base/lib/src/openapi_content_type.dart +++ b/packages/openapi_base/lib/src/openapi_content_type.dart @@ -1,13 +1,18 @@ +import 'package:http_parser/http_parser.dart'; + /// Represents the content type header describing content encoding for /// request and responses. class OpenApiContentType { - const OpenApiContentType._(this.contentType); + const OpenApiContentType._(this.contentType, [this.mediaType]); /// Parses the value as returned by [toString] factory OpenApiContentType.parse(String value) { - return OpenApiContentType._(value); + final mediaType = MediaType.parse(value); + return OpenApiContentType._(value, mediaType); } + final MediaType? mediaType; + static const json = OpenApiContentType._('application/json'); static const html = OpenApiContentType._('text/html'); static const textPlain = OpenApiContentType._('text/plain'); @@ -23,6 +28,8 @@ class OpenApiContentType { static const allKnown = [json, html, urlencoded]; + String? get charset => mediaType?.parameters['charset']; + /// Reverse of [parse] @override String toString() { diff --git a/packages/openapi_base/pubspec.lock b/packages/openapi_base/pubspec.lock index bb49c12..a94c291 100644 --- a/packages/openapi_base/pubspec.lock +++ b/packages/openapi_base/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: "direct main" description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" crypto: dependency: transitive description: @@ -82,13 +82,13 @@ packages: source: hosted version: "1.2.0" http_parser: - dependency: transitive + dependency: "direct main" description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "40f592dd352890c3b60fec1b68e786cefb9603e05ff303dbc4dda49b304ecdf4" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.0" intl: dependency: transitive description: @@ -266,4 +266,4 @@ packages: source: hosted version: "0.4.2" sdks: - dart: ">=3.2.0 <4.0.0" + dart: ">=3.4.0 <4.0.0" diff --git a/packages/openapi_base/pubspec.yaml b/packages/openapi_base/pubspec.yaml index 7b682f5..6b430fa 100644 --- a/packages/openapi_base/pubspec.yaml +++ b/packages/openapi_base/pubspec.yaml @@ -1,10 +1,10 @@ name: openapi_base description: Open API base implementation for client/server to be used with openapi_code_builder. -version: 1.3.2 +version: 2.0.0-rc.1 homepage: https://github.com/hpoul/openapi_dart/tree/master/packages/openapi_base environment: - sdk: '>=2.17.0 <4.0.0' + sdk: '>=3.3.0 <4.0.0' dependencies: # path: ^1.7.0 @@ -25,6 +25,7 @@ dependencies: # for the client: http: ">=0.13.0 <2.0.0" + http_parser: ">=4.0.0 <5.0.0" dev_dependencies: lints: ^4.0.0