Skip to content

Commit

Permalink
refactor: Small improvement on how content-length and transfer encodi…
Browse files Browse the repository at this point in the history
…ng are set to the response headers
  • Loading branch information
klkucaj committed Jan 3, 2025
1 parent 5f66712 commit 135bea5
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 17 deletions.
31 changes: 15 additions & 16 deletions lib/src/extensions/http_response_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ extension HttpResponseExtension on io.HttpResponse {
statusCode != 204 &&
// 304 is not modified
statusCode != 304 &&
// If the content length is not known, chunked encoding is applied.
body.contentLength == null &&
// If the content type is not multipart/byteranges, chunked encoding is applied.
!isMultipartByteranges;

Expand All @@ -52,20 +50,21 @@ extension HttpResponseExtension on io.HttpResponse {
isChunked = true;
}

if (isChunked) {
// Remove conflicting 'identity' encoding if present.
encodings.removeWhere((e) => e.name == TransferEncoding.identity.name);

// Set Transfer-Encoding header and remove Content-Length as it is not needed for chunked encoding.
responseHeaders
..set(
Headers.transferEncodingHeader,
encodings.map((e) => e.name).toList(),
)
..removeAll(Headers.contentLengthHeader);
} else {
// Set Content-Length if chunked encoding is not enabled.
responseHeaders.contentLength = contentLength ?? 0;
if (!isChunked) {
// Set Content-Length to 0 if chunked encoding is not enabled.
responseHeaders.contentLength = 0;
return;
}

// Remove conflicting 'identity' encoding if present.
encodings.removeWhere((e) => e.name == TransferEncoding.identity.name);

// Set Transfer-Encoding header and remove Content-Length as it is not needed for chunked encoding.
responseHeaders
..set(
Headers.transferEncodingHeader,
encodings.map((e) => e.name).toList(),
)
..removeAll(Headers.contentLengthHeader);
}
}
42 changes: 41 additions & 1 deletion test/message/body_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';

Expand Down Expand Up @@ -159,6 +160,45 @@ void main() {
expect(response.headers['transfer-encoding'], isNull);
expect(response.bodyBytes, equals([1, 2, 3, 4]));
});

test(
'with an unknown content length and chunked encoding '
'then content-length should be set to 0 and it should throw an HttpException '
'with a message that states the content size exceeds the specified contentLength',
() async {
Completer<Object?> completer = Completer();

unawaited(runZonedGuarded(
() async {
await _scheduleServer(
(_) => Response.ok(
body: Body.fromDataStream(
Stream.fromIterable([
Uint8List.fromList([1, 2, 3, 4])
]),
mimeType: MimeType.multipartByteranges,
),
headers: Headers.response(),
),
);

await _get();
},
(error, stackTrace) {
if (completer.isCompleted) return;
completer.complete(error);
},
));

var error = await completer.future;

expect(error, isA<HttpException>());
expect(
error.toString(),
contains('Content size exceeds specified contentLength'),
);
},
);
});
}

Expand All @@ -173,7 +213,7 @@ Future<void> _scheduleServer(
assert(_server == null);
_server = await relic_server.serve(
handler,
'localhost',
RelicAddress.fromHostname('localhost'),
0,
securityContext: securityContext,
);
Expand Down

0 comments on commit 135bea5

Please sign in to comment.