Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 181 additions & 24 deletions lib/src/fetch/response.io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,40 @@ final class NativeResponseHost extends ResponseHost<native.Response> {
}

class Response implements native.Response {
Response._(this._host);
Response._(
this._host, {
io_headers.Headers? headers,
bool? redirected,
int? status,
String? statusText,
native.ResponseType? type,
String? url,
}) : _headers = headers,
_redirected = redirected,
_status = status,
_statusText = statusText,
_type = type,
_url = url;

factory Response([Object? body, native.ResponseInit? init]) {
final host = switch ((body, init)) {
(final Response response, _) => response._host,
(final io.HttpClientResponse response, null) => HttpClientResponseHost(
return switch ((body, init)) {
(final Response response, null) => response.clone(),
(final Response response, _) => _responseFromWrappedResponse(
response,
init,
),
(final native.Response response, _) => NativeResponseHost(response),
_ => NativeResponseHost(native.Response(body, init)),
(final io.HttpClientResponse response, null) => Response._(
HttpClientResponseHost(response),
),
(final native.Response response, null) => Response._(
NativeResponseHost(response.clone()),
),
(final native.Response response, _) => _responseFromNativeResponse(
response,
init,
),
_ => Response._(NativeResponseHost(native.Response(body, init))),
};

return Response._(host);
}

factory Response.error() => Response(native.Response.error());
Expand All @@ -51,6 +72,11 @@ class Response implements native.Response {
final ResponseHost _host;
io_headers.Headers? _headers;
Body? _body;
final bool? _redirected;
final int? _status;
final String? _statusText;
final native.ResponseType? _type;
final String? _url;

@override
io_headers.Headers get headers {
Expand Down Expand Up @@ -81,6 +107,9 @@ class Response implements native.Response {

@override
bool get ok {
final status = _status;
if (status != null) return HttpStatus.isSuccess(status);

return switch (_host) {
final HttpClientResponseHost host => HttpStatus.isSuccess(
host.value.statusCode,
Expand All @@ -91,6 +120,9 @@ class Response implements native.Response {

@override
bool get redirected {
final redirected = _redirected;
if (redirected != null) return redirected;

return switch (_host) {
final HttpClientResponseHost host => host.value.redirects.isNotEmpty,
final NativeResponseHost host => host.value.redirected,
Expand All @@ -99,6 +131,9 @@ class Response implements native.Response {

@override
int get status {
final status = _status;
if (status != null) return status;

return switch (_host) {
final HttpClientResponseHost host => host.value.statusCode,
final NativeResponseHost host => host.value.status,
Expand All @@ -107,6 +142,9 @@ class Response implements native.Response {

@override
String get statusText {
final statusText = _statusText;
if (statusText != null) return statusText;

return switch (_host) {
final HttpClientResponseHost host => host.value.reasonPhrase,
final NativeResponseHost host => host.value.statusText,
Expand All @@ -115,6 +153,9 @@ class Response implements native.Response {

@override
native.ResponseType get type {
final type = _type;
if (type != null) return type;

return switch (_host) {
final HttpClientResponseHost _ => native.ResponseType.default_,
final NativeResponseHost host => host.value.type,
Expand All @@ -123,6 +164,9 @@ class Response implements native.Response {

@override
String get url {
final url = _url;
if (url != null) return url;

return switch (_host) {
final HttpClientResponseHost _ => '',
final NativeResponseHost host => host.value.url,
Expand Down Expand Up @@ -189,33 +233,146 @@ class Response implements native.Response {
@override
Response clone() {
return switch (_host) {
final NativeResponseHost host => Response(host.value.clone()),
final HttpClientResponseHost _ => Response(
native.Response(
_bodyForNativeClone(),
native.ResponseInit(
status: status,
statusText: statusText,
headers: io_headers.Headers(headers),
final NativeResponseHost host => Response._(
NativeResponseHost(host.value.clone()),
headers: io_headers.Headers(headers),
redirected: redirected,
status: status,
statusText: statusText,
type: type,
url: url,
),
final HttpClientResponseHost _ => Response._(
NativeResponseHost(
native.Response(
_bodyForNativeCopy(),
native.ResponseInit(
status: status,
statusText: statusText,
headers: io_headers.Headers(headers),
),
),
),
redirected: redirected,
type: type,
url: url,
),
};
}

Body? _bodyForNativeClone() {
if (!_statusAllowsBody(status)) {
return null;
}

return body?.clone();
}

static bool _statusAllowsBody(int status) {
return !const <int>{
HttpStatus.noContent,
HttpStatus.resetContent,
HttpStatus.notModified,
}.contains(status);
}

static Response _responseFromWrappedResponse(
Response response,
native.ResponseInit? init,
) {
if (init?.status == null && response.status == 0) {
final clone = response.clone();
return Response._(
clone._host,
headers: io_headers.Headers(init?.headers ?? response.headers),
redirected: response.redirected,
status: response.status,
statusText: init?.statusText ?? response.statusText,
type: response.type,
url: response.url,
);
}

return Response._(
NativeResponseHost(_nativeResponseFromWrappedResponse(response, init)),
redirected: response.redirected,
type: response.type,
url: response.url,
);
}

static Response _responseFromNativeResponse(
native.Response response,
native.ResponseInit? init,
) {
if (init?.status == null && response.status == 0) {
return Response._(
NativeResponseHost(response.clone()),
headers: io_headers.Headers(init?.headers ?? response.headers),
redirected: response.redirected,
status: response.status,
statusText: init?.statusText ?? response.statusText,
type: response.type,
url: response.url,
);
}

return Response._(
NativeResponseHost(_nativeResponseFromNativeResponse(response, init)),
redirected: response.redirected,
type: response.type,
url: response.url,
);
}

static native.Response _nativeResponseFromWrappedResponse(
Response response,
native.ResponseInit? init,
) {
final sourceHeaders = io_headers.Headers(response.headers);
return _nativeResponseFromCopy(
response._bodyForNativeCopy(),
status: init?.status ?? response.status,
statusText: init?.statusText ?? response.statusText,
Comment thread
medz marked this conversation as resolved.
headers: init?.headers ?? sourceHeaders,
preserveMissingContentType:
init?.headers == null && !sourceHeaders.has('content-type'),
);
}

static native.Response _nativeResponseFromNativeResponse(
native.Response response,
native.ResponseInit? init,
) {
final sourceHeaders = io_headers.Headers(response.headers);
return _nativeResponseFromCopy(
response.body,
status: init?.status ?? response.status,
statusText: init?.statusText ?? response.statusText,
headers: init?.headers ?? sourceHeaders,
preserveMissingContentType:
init?.headers == null && !sourceHeaders.has('content-type'),
);
}

static native.Response _nativeResponseFromCopy(
Body? body, {
required int status,
required String statusText,
required Object? headers,
required bool preserveMissingContentType,
}) {
final response = native.Response(
body,
native.ResponseInit(
status: status,
statusText: statusText,
headers: headers,
),
);
if (preserveMissingContentType) {
response.headers.delete('content-type');
}
return response;
}

Body? _bodyForNativeCopy() {
if (!_statusAllowsBody(status)) {
return null;
}

return body;
}
}
Loading