diff --git a/pkgs/http_client_conformance_tests/lib/http_client_conformance_tests.dart b/pkgs/http_client_conformance_tests/lib/http_client_conformance_tests.dart index 3500bf8df2..3d003193e9 100644 --- a/pkgs/http_client_conformance_tests/lib/http_client_conformance_tests.dart +++ b/pkgs/http_client_conformance_tests/lib/http_client_conformance_tests.dart @@ -15,6 +15,7 @@ import 'src/request_headers_tests.dart'; import 'src/response_body_streamed_test.dart'; import 'src/response_body_tests.dart'; import 'src/response_headers_tests.dart'; +import 'src/response_status_line_tests.dart'; import 'src/server_errors_test.dart'; export 'src/close_tests.dart' show testClose; @@ -29,6 +30,7 @@ export 'src/request_headers_tests.dart' show testRequestHeaders; export 'src/response_body_streamed_test.dart' show testResponseBodyStreamed; export 'src/response_body_tests.dart' show testResponseBody; export 'src/response_headers_tests.dart' show testResponseHeaders; +export 'src/response_status_line_tests.dart' show testResponseStatusLine; export 'src/server_errors_test.dart' show testServerErrors; /// Runs the entire test suite against the given [Client]. @@ -64,6 +66,7 @@ void testAll(Client Function() clientFactory, canStreamResponseBody: canStreamResponseBody); testRequestHeaders(clientFactory()); testResponseHeaders(clientFactory()); + testResponseStatusLine(clientFactory()); testRedirect(clientFactory(), redirectAlwaysAllowed: redirectAlwaysAllowed); testServerErrors(clientFactory()); testCompressedResponseBody(clientFactory()); diff --git a/pkgs/http_client_conformance_tests/lib/src/response_status_line_server.dart b/pkgs/http_client_conformance_tests/lib/src/response_status_line_server.dart new file mode 100644 index 0000000000..66d44889a1 --- /dev/null +++ b/pkgs/http_client_conformance_tests/lib/src/response_status_line_server.dart @@ -0,0 +1,42 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; +import 'dart:io'; + +import 'package:async/async.dart'; +import 'package:stream_channel/stream_channel.dart'; + +/// Starts an HTTP server that returns a custom status line. +/// +/// Channel protocol: +/// On Startup: +/// - send port +/// On Request Received: +/// - load response status line from channel +/// - exit +void hybridMain(StreamChannel channel) async { + late HttpServer server; + final clientQueue = StreamQueue(channel.stream); + + server = (await HttpServer.bind('localhost', 0)) + ..listen((request) async { + await request.drain(); + final socket = await request.response.detachSocket(writeHeaders: false); + + final statusLine = (await clientQueue.next) as String; + socket.writeAll( + [ + statusLine, + 'Content-Length: 0', + '\r\n', // Add \r\n at the end of this header section. + ], + '\r\n', // Separate each field by \r\n. + ); + await socket.close(); + unawaited(server.close()); + }); + + channel.sink.add(server.port); +} diff --git a/pkgs/http_client_conformance_tests/lib/src/response_status_line_server_vm.dart b/pkgs/http_client_conformance_tests/lib/src/response_status_line_server_vm.dart new file mode 100644 index 0000000000..ff2ea84f02 --- /dev/null +++ b/pkgs/http_client_conformance_tests/lib/src/response_status_line_server_vm.dart @@ -0,0 +1,12 @@ +// Generated by generate_server_wrappers.dart. Do not edit. + +import 'package:stream_channel/stream_channel.dart'; + +import 'response_status_line_server.dart'; + +/// Starts the redirect test HTTP server in the same process. +Future> startServer() async { + final controller = StreamChannelController(sync: true); + hybridMain(controller.foreign); + return controller.local; +} diff --git a/pkgs/http_client_conformance_tests/lib/src/response_status_line_server_web.dart b/pkgs/http_client_conformance_tests/lib/src/response_status_line_server_web.dart new file mode 100644 index 0000000000..f1ebbcbd3a --- /dev/null +++ b/pkgs/http_client_conformance_tests/lib/src/response_status_line_server_web.dart @@ -0,0 +1,10 @@ +// Generated by generate_server_wrappers.dart. Do not edit. + +import 'package:stream_channel/stream_channel.dart'; +import 'package:test/test.dart'; + +/// Starts the redirect test HTTP server out-of-process. +Future> startServer() async => spawnHybridUri(Uri( + scheme: 'package', + path: + 'http_client_conformance_tests/src/response_status_line_server.dart')); diff --git a/pkgs/http_client_conformance_tests/lib/src/response_status_line_tests.dart b/pkgs/http_client_conformance_tests/lib/src/response_status_line_tests.dart new file mode 100644 index 0000000000..922236ccc1 --- /dev/null +++ b/pkgs/http_client_conformance_tests/lib/src/response_status_line_tests.dart @@ -0,0 +1,39 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:async/async.dart'; +import 'package:http/http.dart'; +import 'package:stream_channel/stream_channel.dart'; +import 'package:test/test.dart'; + +import 'response_status_line_server_vm.dart' + if (dart.library.html) 'response_status_line_server_web.dart'; + +/// Tests that the [Client] correctly processes the response status line. +void testResponseStatusLine(Client client) async { + group('response status line', () { + late String host; + late StreamChannel httpServerChannel; + late StreamQueue httpServerQueue; + + setUp(() async { + httpServerChannel = await startServer(); + httpServerQueue = StreamQueue(httpServerChannel.stream); + host = 'localhost:${await httpServerQueue.next}'; + }); + + test( + 'without status code', + () async { + httpServerChannel.sink.add('HTTP/1.1 OK'); + await expectLater( + client.get(Uri.http(host, '')), + throwsA(isA()), + ); + }, + skip: + 'Enable after https://github.com/dart-lang/http/issues/1013 is fixed', + ); + }); +} diff --git a/pkgs/java_http/test/java_client_test.dart b/pkgs/java_http/test/java_client_test.dart index 5ad0120099..ee355dc662 100644 --- a/pkgs/java_http/test/java_client_test.dart +++ b/pkgs/java_http/test/java_client_test.dart @@ -11,6 +11,7 @@ void main() { testIsolate(JavaClient.new); testResponseBody(JavaClient(), canStreamResponseBody: false); testResponseHeaders(JavaClient()); + testResponseStatusLine(JavaClient()); testRequestBody(JavaClient()); testRequestHeaders(JavaClient()); testMultipleClients(JavaClient.new);