fix(clients): verify Dart client, case-insensitive Content-Range lookup

This commit is contained in:
2026-09-30 22:42:55 +02:00
parent ce706bacda
commit 17bb6ea76d
7 changed files with 200 additions and 70 deletions
+21 -7
View File
@@ -10,7 +10,8 @@ class ResolveSpecException implements Exception {
final String message;
final ApiError error;
ResolveSpecException(this.message, this.statusCode, [ApiError? error]) : error = error ?? ApiError(message: message);
ResolveSpecException(this.message, this.statusCode, [ApiError? error])
: error = error ?? ApiError(message: message);
@override
String toString() => 'ResolveSpecException($statusCode): $message';
@@ -25,7 +26,11 @@ class ClientOptions {
/// Supply your own client (tests, pooling).
final http.Client? httpClient;
const ClientOptions({this.token, this.headers = const {}, this.timeout = const Duration(seconds: 30), this.httpClient});
const ClientOptions(
{this.token,
this.headers = const {},
this.timeout = const Duration(seconds: 30),
this.httpClient});
}
class Transport {
@@ -39,7 +44,8 @@ class Transport {
_http = options?.httpClient ?? http.Client();
/// Content-Type < custom headers < per-call headers < bearer token.
Future<http.Response> send(String method, Uri uri, {String? body, Map<String, String>? extra}) {
Future<http.Response> send(String method, Uri uri,
{String? body, Map<String, String>? extra}) {
final headers = <String, String>{'Content-Type': 'application/json'};
void merge(Map<String, String> src) {
for (final e in src.entries) {
@@ -51,11 +57,16 @@ class Transport {
merge(options.headers);
if (extra != null) merge(extra);
final token = options.token;
if (token != null && token.isNotEmpty) merge({'Authorization': 'Bearer $token'});
if (token != null && token.isNotEmpty) {
merge({'Authorization': 'Bearer $token'});
}
final req = http.Request(method, uri)..headers.addAll(headers);
if (body != null) req.body = body;
return _http.send(req).timeout(options.timeout).then(http.Response.fromStream);
return _http
.send(req)
.timeout(options.timeout)
.then(http.Response.fromStream);
}
void close() => _http.close();
@@ -67,7 +78,8 @@ class Transport {
try {
final parsed = jsonDecode(body);
isJson = true;
if (parsed is Map<String, dynamic> && parsed['error'] is Map<String, dynamic>) {
if (parsed is Map<String, dynamic> &&
parsed['error'] is Map<String, dynamic>) {
err = ApiError.fromJson(parsed['error'] as Map<String, dynamic>);
}
} on FormatException {
@@ -77,7 +89,9 @@ class Transport {
if (message.isEmpty) {
var text = isJson ? '' : body.trim();
if (text.length > 200) text = text.substring(0, 200);
message = text.isNotEmpty ? text : '${resp.reasonPhrase ?? 'Error'} (${resp.statusCode})';
message = text.isNotEmpty
? text
: '${resp.reasonPhrase ?? 'Error'} (${resp.statusCode})';
}
return ResolveSpecException(message, resp.statusCode, err);
}