From fc076a859e616410deb8464521b64dbf7e8d56ad Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Tue, 9 Jan 2024 18:17:22 -0800 Subject: [PATCH 1/8] Commit all --- pkgs/cupertino_http/example/ios/Podfile.lock | 4 +- .../ios/Runner.xcodeproj/project.pbxproj | 3 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- .../lib/http_client_conformance_tests.dart | 3 ++ .../lib/src/request_cookies_server.dart | 42 +++++++++++++++++++ .../lib/src/request_cookies_server_vm.dart | 14 +++++++ .../lib/src/request_cookies_server_web.dart | 11 +++++ .../lib/src/request_cookies_test.dart | 37 ++++++++++++++++ 8 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 pkgs/http_client_conformance_tests/lib/src/request_cookies_server.dart create mode 100644 pkgs/http_client_conformance_tests/lib/src/request_cookies_server_vm.dart create mode 100644 pkgs/http_client_conformance_tests/lib/src/request_cookies_server_web.dart create mode 100644 pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart diff --git a/pkgs/cupertino_http/example/ios/Podfile.lock b/pkgs/cupertino_http/example/ios/Podfile.lock index 709672b9d7..8bd679657f 100644 --- a/pkgs/cupertino_http/example/ios/Podfile.lock +++ b/pkgs/cupertino_http/example/ios/Podfile.lock @@ -21,8 +21,8 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: cupertino_http: 5f8b1161107fe6c8d94a0c618735a033d93fa7db Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - integration_test: a1e7d09bd98eca2fc37aefd79d4f41ad37bdbbe5 + integration_test: 13825b8a9334a850581300559b8839134b124670 PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 diff --git a/pkgs/cupertino_http/example/ios/Runner.xcodeproj/project.pbxproj b/pkgs/cupertino_http/example/ios/Runner.xcodeproj/project.pbxproj index 3f233bb8b9..c4cc403ce4 100644 --- a/pkgs/cupertino_http/example/ios/Runner.xcodeproj/project.pbxproj +++ b/pkgs/cupertino_http/example/ios/Runner.xcodeproj/project.pbxproj @@ -156,7 +156,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -205,6 +205,7 @@ files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( diff --git a/pkgs/cupertino_http/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/pkgs/cupertino_http/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a335..a6b826db27 100644 --- a/pkgs/cupertino_http/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/pkgs/cupertino_http/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ > +/// When Receive Anything: +/// - exit +void hybridMain(StreamChannel channel) async { + late HttpServer server; + + server = (await HttpServer.bind('localhost', 0)) + ..listen((request) async { + request.response.headers.set('Access-Control-Allow-Origin', '*'); + if (request.method == 'OPTIONS') { + // Handle a CORS preflight request: + // https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests + request.response.headers + ..set('Access-Control-Allow-Methods', 'GET') + ..set('Access-Control-Allow-Headers', '*'); + } else { + channel.sink + .add([for (var cookie in request.cookies) cookie.toString()]); + } + unawaited(request.response.close()); + }); + + channel.sink.add(server.port); + await channel + .stream.first; // Any writes indicates that the server should exit. + unawaited(server.close()); +} diff --git a/pkgs/http_client_conformance_tests/lib/src/request_cookies_server_vm.dart b/pkgs/http_client_conformance_tests/lib/src/request_cookies_server_vm.dart new file mode 100644 index 0000000000..1f30e5f871 --- /dev/null +++ b/pkgs/http_client_conformance_tests/lib/src/request_cookies_server_vm.dart @@ -0,0 +1,14 @@ +// Generated by generate_server_wrappers.dart. Do not edit. + +import 'package:stream_channel/stream_channel.dart'; + +import 'request_cookies_server.dart'; + +export 'server_queue_helpers.dart' show StreamQueueOfNullableObjectExtension; + +/// 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/request_cookies_server_web.dart b/pkgs/http_client_conformance_tests/lib/src/request_cookies_server_web.dart new file mode 100644 index 0000000000..31d961b047 --- /dev/null +++ b/pkgs/http_client_conformance_tests/lib/src/request_cookies_server_web.dart @@ -0,0 +1,11 @@ +// Generated by generate_server_wrappers.dart. Do not edit. + +import 'package:stream_channel/stream_channel.dart'; +import 'package:test/test.dart'; + +export 'server_queue_helpers.dart' show StreamQueueOfNullableObjectExtension; + +/// Starts the redirect test HTTP server out-of-process. +Future> startServer() async => spawnHybridUri(Uri( + scheme: 'package', + path: 'http_client_conformance_tests/src/request_cookies_server.dart')); diff --git a/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart b/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart new file mode 100644 index 0000000000..f9ca72c299 --- /dev/null +++ b/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2022, 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 'request_cookies_server_vm.dart' + if (dart.library.js_interop) 'request_cookies_server_web.dart'; + +/// Tests that the [Client] correctly sends headers in the request. +void testRequestCookies(Client client) async { + group('request cookies', () { + late final String host; + late final StreamChannel httpServerChannel; + late final StreamQueue httpServerQueue; + + setUpAll(() async { + httpServerChannel = await startServer(); + httpServerQueue = StreamQueue(httpServerChannel.stream); + host = 'localhost:${await httpServerQueue.nextAsInt}'; + }); + tearDownAll(() => httpServerChannel.sink.add(null)); + + test('set-cookie', () async { + await client.get(Uri.http(host, ''), headers: { + 'Cookie': 'PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1' + }); + + final cookies = await httpServerQueue.next as List; + expect(cookies, + ['PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1']); + }); + }); +} From 7d4721344e5f26677397cf78c8ef622335951aff Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Thu, 11 Jan 2024 11:05:36 -0800 Subject: [PATCH 2/8] Cookies! --- .../example/integration_test/client_test.dart | 2 + .../client_conformance_test.dart | 14 ++- .../http/test/io/client_conformance_test.dart | 7 +- .../lib/http_client_conformance_tests.dart | 15 ++- .../lib/src/request_cookies_server.dart | 51 +++++++---- .../lib/src/request_cookies_test.dart | 30 ++++-- .../lib/src/response_cookies_server.dart | 44 +++++++++ .../lib/src/response_cookies_server_vm.dart | 14 +++ .../lib/src/response_cookies_server_web.dart | 11 +++ .../lib/src/response_cookies_test.dart | 91 +++++++++++++++++++ 10 files changed, 244 insertions(+), 35 deletions(-) create mode 100644 pkgs/http_client_conformance_tests/lib/src/response_cookies_server.dart create mode 100644 pkgs/http_client_conformance_tests/lib/src/response_cookies_server_vm.dart create mode 100644 pkgs/http_client_conformance_tests/lib/src/response_cookies_server_web.dart create mode 100644 pkgs/http_client_conformance_tests/lib/src/response_cookies_test.dart diff --git a/pkgs/cronet_http/example/integration_test/client_test.dart b/pkgs/cronet_http/example/integration_test/client_test.dart index cc6b80edfc..f126f84fc3 100644 --- a/pkgs/cronet_http/example/integration_test/client_test.dart +++ b/pkgs/cronet_http/example/integration_test/client_test.dart @@ -13,6 +13,8 @@ Future testConformance() async { () => testAll( CronetClient.defaultCronetEngine, canStreamRequestBody: false, + canReceiveSetCookieHeaders: true, + canSendCookieHeaders: true, )); group('from cronet engine', () { diff --git a/pkgs/cupertino_http/example/integration_test/client_conformance_test.dart b/pkgs/cupertino_http/example/integration_test/client_conformance_test.dart index a0823bf71d..3007123a98 100644 --- a/pkgs/cupertino_http/example/integration_test/client_conformance_test.dart +++ b/pkgs/cupertino_http/example/integration_test/client_conformance_test.dart @@ -11,11 +11,19 @@ void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('defaultSessionConfiguration', () { - testAll(CupertinoClient.defaultSessionConfiguration); + testAll( + CupertinoClient.defaultSessionConfiguration, + canReceiveSetCookieHeaders: true, + canSendCookieHeaders: true, + ); }); group('fromSessionConfiguration', () { final config = URLSessionConfiguration.ephemeralSessionConfiguration(); - testAll(() => CupertinoClient.fromSessionConfiguration(config), - canWorkInIsolates: false); + testAll( + () => CupertinoClient.fromSessionConfiguration(config), + canWorkInIsolates: false, + canReceiveSetCookieHeaders: true, + canSendCookieHeaders: true, + ); }); } diff --git a/pkgs/http/test/io/client_conformance_test.dart b/pkgs/http/test/io/client_conformance_test.dart index 20bf39f281..65368e57a0 100644 --- a/pkgs/http/test/io/client_conformance_test.dart +++ b/pkgs/http/test/io/client_conformance_test.dart @@ -10,6 +10,9 @@ import 'package:http_client_conformance_tests/http_client_conformance_tests.dart import 'package:test/test.dart'; void main() { - testAll(IOClient.new, preservesMethodCase: false // https://dartbug.com/54187 - ); + testAll( + IOClient.new, preservesMethodCase: false, // https://dartbug.com/54187 + canReceiveSetCookieHeaders: true, + canSendCookieHeaders: true, + ); } 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 0182f87d39..07903b5246 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 @@ -16,6 +16,7 @@ import 'src/request_headers_tests.dart'; import 'src/request_methods_tests.dart'; import 'src/response_body_streamed_test.dart'; import 'src/response_body_tests.dart'; +import 'src/response_cookies_test.dart'; import 'src/response_headers_tests.dart'; import 'src/response_status_line_tests.dart'; import 'src/server_errors_test.dart'; @@ -33,6 +34,7 @@ export 'src/request_headers_tests.dart' show testRequestHeaders; export 'src/request_methods_tests.dart' show testRequestMethods; export 'src/response_body_streamed_test.dart' show testResponseBodyStreamed; export 'src/response_body_tests.dart' show testResponseBody; +export 'src/response_cookies_test.dart' show testResponseCookies; 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; @@ -56,6 +58,12 @@ export 'src/server_errors_test.dart' show testServerErrors; /// If [preservesMethodCase] is `false` then tests that assume that the /// [Client] preserves custom request method casing will be skipped. /// +/// If [canSendCookieHeaders] is `false` then tests that require that "cookie" +/// headers be sent by the client will not be run. +/// +/// If [canReceiveSetCookieHeaders] is `false` then tests that require that +/// "set-cookie" headers be received by the client will not be run. +/// /// The tests are run against a series of HTTP servers that are started by the /// tests. If the tests are run in the browser, then the test servers are /// started in another process. Otherwise, the test servers are run in-process. @@ -66,6 +74,8 @@ void testAll( bool redirectAlwaysAllowed = false, bool canWorkInIsolates = true, bool preservesMethodCase = false, + bool canSendCookieHeaders = false, + bool canReceiveSetCookieHeaders = false, }) { testRequestBody(clientFactory()); testRequestBodyStreamed(clientFactory(), @@ -84,5 +94,8 @@ void testAll( testMultipleClients(clientFactory); testClose(clientFactory); testIsolate(clientFactory, canWorkInIsolates: canWorkInIsolates); - testRequestCookies(clientFactory()); + testRequestCookies(clientFactory(), + canSendCookieHeaders: canSendCookieHeaders); + testResponseCookies(clientFactory(), + canReceiveSetCookieHeaders: canReceiveSetCookieHeaders); } diff --git a/pkgs/http_client_conformance_tests/lib/src/request_cookies_server.dart b/pkgs/http_client_conformance_tests/lib/src/request_cookies_server.dart index cfb57d8f78..44653a7cd5 100644 --- a/pkgs/http_client_conformance_tests/lib/src/request_cookies_server.dart +++ b/pkgs/http_client_conformance_tests/lib/src/request_cookies_server.dart @@ -1,38 +1,51 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2024, 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:convert'; import 'dart:io'; import 'package:stream_channel/stream_channel.dart'; -/// Starts an HTTP server that captures the request headers. +/// Starts an HTTP server that captures "cookie" headers. /// /// Channel protocol: /// On Startup: /// - send port /// On Request Received: -/// - send headers as Map> +/// - send a list of header lines starting with "cookie:" /// When Receive Anything: /// - exit void hybridMain(StreamChannel channel) async { - late HttpServer server; - - server = (await HttpServer.bind('localhost', 0)) - ..listen((request) async { - request.response.headers.set('Access-Control-Allow-Origin', '*'); - if (request.method == 'OPTIONS') { - // Handle a CORS preflight request: - // https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests - request.response.headers - ..set('Access-Control-Allow-Methods', 'GET') - ..set('Access-Control-Allow-Headers', '*'); - } else { - channel.sink - .add([for (var cookie in request.cookies) cookie.toString()]); - } - unawaited(request.response.close()); + late ServerSocket server; + + server = (await ServerSocket.bind('localhost', 0)) + ..listen((Socket socket) async { + final request = utf8.decoder.bind(socket).transform(const LineSplitter()); + + final cookies = []; + request.listen((line) { + if (line.toLowerCase().startsWith('cookie:')) { + cookies.add(line); + } + + if (line.isEmpty) { + // A blank line indicates the end of the headers. + channel.sink.add(cookies); + } + }); + + socket.writeAll( + [ + 'HTTP/1.1 200 OK', + 'Access-Control-Allow-Origin: *', + '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(); }); channel.sink.add(server.port); diff --git a/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart b/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart index f9ca72c299..f9bbe45f23 100644 --- a/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart +++ b/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart @@ -1,4 +1,4 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2024, 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. @@ -10,8 +10,12 @@ import 'package:test/test.dart'; import 'request_cookies_server_vm.dart' if (dart.library.js_interop) 'request_cookies_server_web.dart'; -/// Tests that the [Client] correctly sends headers in the request. -void testRequestCookies(Client client) async { +/// Tests that the [Client] correctly sends "cookie" headers in the request. +/// +/// If [canSendCookieHeaders] is `false` then tests that require that "cookie" +/// headers be sent by the client will not be run. +void testRequestCookies(Client client, + {bool canSendCookieHeaders = false}) async { group('request cookies', () { late final String host; late final StreamChannel httpServerChannel; @@ -24,14 +28,20 @@ void testRequestCookies(Client client) async { }); tearDownAll(() => httpServerChannel.sink.add(null)); - test('set-cookie', () async { - await client.get(Uri.http(host, ''), headers: { - 'Cookie': 'PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1' - }); + test('one cookie', () async { + await client + .get(Uri.http(host, ''), headers: {'Cookie': 'SID=298zf09hf012fh2'}); final cookies = await httpServerQueue.next as List; - expect(cookies, - ['PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1']); - }); + expect(cookies, ['cookie: SID=298zf09hf012fh2']); + }, skip: canSendCookieHeaders ? false : 'cannot send cookie headers'); + + test('multiple cookies semicolon separated', () async { + await client.get(Uri.http(host, ''), + headers: {'Cookie': 'SID=298zf09hf012fh2; lang=en-US'}); + + final cookies = await httpServerQueue.next as List; + expect(cookies, ['cookie: SID=298zf09hf012fh2; lang=en-US']); + }, skip: canSendCookieHeaders ? false : 'cannot send cookie headers'); }); } diff --git a/pkgs/http_client_conformance_tests/lib/src/response_cookies_server.dart b/pkgs/http_client_conformance_tests/lib/src/response_cookies_server.dart new file mode 100644 index 0000000000..392e22832d --- /dev/null +++ b/pkgs/http_client_conformance_tests/lib/src/response_cookies_server.dart @@ -0,0 +1,44 @@ +// Copyright (c) 2024, 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 headers = (await clientQueue.next) as List; + socket.writeAll( + [ + 'HTTP/1.1 200 OK', + 'Access-Control-Allow-Origin: *', + 'Content-Length: 0', + ...headers, + '\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_cookies_server_vm.dart b/pkgs/http_client_conformance_tests/lib/src/response_cookies_server_vm.dart new file mode 100644 index 0000000000..2edbb4581f --- /dev/null +++ b/pkgs/http_client_conformance_tests/lib/src/response_cookies_server_vm.dart @@ -0,0 +1,14 @@ +// Generated by generate_server_wrappers.dart. Do not edit. + +import 'package:stream_channel/stream_channel.dart'; + +import 'response_cookies_server.dart'; + +export 'server_queue_helpers.dart' show StreamQueueOfNullableObjectExtension; + +/// 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_cookies_server_web.dart b/pkgs/http_client_conformance_tests/lib/src/response_cookies_server_web.dart new file mode 100644 index 0000000000..cb8e384ed4 --- /dev/null +++ b/pkgs/http_client_conformance_tests/lib/src/response_cookies_server_web.dart @@ -0,0 +1,11 @@ +// Generated by generate_server_wrappers.dart. Do not edit. + +import 'package:stream_channel/stream_channel.dart'; +import 'package:test/test.dart'; + +export 'server_queue_helpers.dart' show StreamQueueOfNullableObjectExtension; + +/// Starts the redirect test HTTP server out-of-process. +Future> startServer() async => spawnHybridUri(Uri( + scheme: 'package', + path: 'http_client_conformance_tests/src/response_cookies_server.dart')); diff --git a/pkgs/http_client_conformance_tests/lib/src/response_cookies_test.dart b/pkgs/http_client_conformance_tests/lib/src/response_cookies_test.dart new file mode 100644 index 0000000000..c62c748e7b --- /dev/null +++ b/pkgs/http_client_conformance_tests/lib/src/response_cookies_test.dart @@ -0,0 +1,91 @@ +// Copyright (c) 2024, 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_cookies_server_vm.dart' + if (dart.library.js_interop) 'response_cookies_server_web.dart'; + +/// Tests that the [Client] correctly receives "set-cookie-headers" +/// +/// If [canReceiveSetCookieHeaders] is `false` then tests that require that +/// "set-cookie" headers be received by the client will not be run. +void testResponseCookies(Client client, + {required bool canReceiveSetCookieHeaders}) async { + group('response cookies', () { + late String host; + late StreamChannel httpServerChannel; + late StreamQueue httpServerQueue; + + setUp(() async { + httpServerChannel = await startServer(); + httpServerQueue = StreamQueue(httpServerChannel.stream); + host = 'localhost:${await httpServerQueue.nextAsInt}'; + }); + + test('single session cookie', () async { + httpServerChannel.sink.add(['Set-Cookie: SID=1231AB3']); + final response = await client.get(Uri.http(host, '')); + + expect(response.headers['set-cookie'], 'SID=1231AB3'); + }, + skip: canReceiveSetCookieHeaders + ? false + : 'cannot receive set-cookie headers'); + + test('multiple session cookies', () async { + // RFC-2616 4.2 says: + // "The field value MAY be preceded by any amount of LWS, though a single + // SP is preferred." and + // "The field-content does not include any leading or trailing LWS ..." + httpServerChannel.sink.add([ + 'Set-Cookie: SID=1231AB3', + ['Set-Cookie: lang=en_US'] + ]); + final response = await client.get(Uri.http(host, '')); + + expect( + response.headers['set-cookie'], + matches(r'SID=1231AB3' + r'[ \t]*,[ \t]*' + r'lang=en_US')); + }, + skip: canReceiveSetCookieHeaders + ? false + : 'cannot receive set-cookie headers'); + + test('permanent cookie with expires', () async { + httpServerChannel.sink + .add(['Set-Cookie: id=a3fWa; Expires=Wed, 10 Jan 2024 07:28:00 GMT']); + final response = await client.get(Uri.http(host, '')); + + expect(response.headers['set-cookie'], + 'id=a3fWa; Expires=Wed, 10 Jan 2024 07:28:00 GMT'); + }, + skip: canReceiveSetCookieHeaders + ? false + : 'cannot receive set-cookie headers'); + + test('multiple permanent cookies with expires', () async { + // RFC-2616 4.2 says: + // "The field value MAY be preceded by any amount of LWS, though a single + // SP is preferred." and + // "The field-content does not include any leading or trailing LWS ..." + httpServerChannel.sink.add([ + 'Set-Cookie: id=a3fWa; Expires=Wed, 10 Jan 2024 07:28:00 GMT', + 'Set-Cookie: id=2fasd; Expires=Wed, 21 Oct 2025 07:28:00 GMT' + ]); + final response = await client.get(Uri.http(host, '')); + + expect( + response.headers['set-cookie'], + matches(r'id=a3fWa; Expires=Wed, 10 Jan 2024 07:28:00 GMT' + r'[ \t]*,[ \t]*' + r'id=2fasd; Expires=Wed, 21 Oct 2025 07:28:00 GMT')); + }); + }); +} From a630c9fe821ca641b055b1140ef738cc2fd263cd Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Thu, 11 Jan 2024 11:16:36 -0800 Subject: [PATCH 3/8] Update response_cookies_test.dart --- .../lib/src/response_cookies_test.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkgs/http_client_conformance_tests/lib/src/response_cookies_test.dart b/pkgs/http_client_conformance_tests/lib/src/response_cookies_test.dart index c62c748e7b..a94cb54032 100644 --- a/pkgs/http_client_conformance_tests/lib/src/response_cookies_test.dart +++ b/pkgs/http_client_conformance_tests/lib/src/response_cookies_test.dart @@ -86,6 +86,9 @@ void testResponseCookies(Client client, matches(r'id=a3fWa; Expires=Wed, 10 Jan 2024 07:28:00 GMT' r'[ \t]*,[ \t]*' r'id=2fasd; Expires=Wed, 21 Oct 2025 07:28:00 GMT')); - }); + }, + skip: canReceiveSetCookieHeaders + ? false + : 'cannot receive set-cookie headers'); }); } From af93745cba2caf63c7967b83ec6a8f5ba04422dd Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Thu, 11 Jan 2024 11:20:14 -0800 Subject: [PATCH 4/8] Update response_cookies_test.dart --- .../lib/src/response_cookies_test.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pkgs/http_client_conformance_tests/lib/src/response_cookies_test.dart b/pkgs/http_client_conformance_tests/lib/src/response_cookies_test.dart index a94cb54032..f8e154d611 100644 --- a/pkgs/http_client_conformance_tests/lib/src/response_cookies_test.dart +++ b/pkgs/http_client_conformance_tests/lib/src/response_cookies_test.dart @@ -42,10 +42,8 @@ void testResponseCookies(Client client, // "The field value MAY be preceded by any amount of LWS, though a single // SP is preferred." and // "The field-content does not include any leading or trailing LWS ..." - httpServerChannel.sink.add([ - 'Set-Cookie: SID=1231AB3', - ['Set-Cookie: lang=en_US'] - ]); + httpServerChannel.sink + .add(['Set-Cookie: SID=1231AB3', 'Set-Cookie: lang=en_US']); final response = await client.get(Uri.http(host, '')); expect( From 8976b1531db07870b8da6e6fcd7c4ac5bcc5de27 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Thu, 11 Jan 2024 17:48:42 -0800 Subject: [PATCH 5/8] Update request_cookies_test.dart --- .../lib/src/request_cookies_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart b/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart index f9bbe45f23..ec52748488 100644 --- a/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart +++ b/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart @@ -30,7 +30,7 @@ void testRequestCookies(Client client, test('one cookie', () async { await client - .get(Uri.http(host, ''), headers: {'Cookie': 'SID=298zf09hf012fh2'}); + .get(Uri.http(host, ''), headers: {'cookie': 'SID=298zf09hf012fh2'}); final cookies = await httpServerQueue.next as List; expect(cookies, ['cookie: SID=298zf09hf012fh2']); @@ -38,7 +38,7 @@ void testRequestCookies(Client client, test('multiple cookies semicolon separated', () async { await client.get(Uri.http(host, ''), - headers: {'Cookie': 'SID=298zf09hf012fh2; lang=en-US'}); + headers: {'cookie': 'SID=298zf09hf012fh2; lang=en-US'}); final cookies = await httpServerQueue.next as List; expect(cookies, ['cookie: SID=298zf09hf012fh2; lang=en-US']); From eb018354ee63b9d56a7a7e843f0a421915ca86cd Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Thu, 11 Jan 2024 18:21:01 -0800 Subject: [PATCH 6/8] Update request_cookies_test.dart --- .../lib/src/request_cookies_test.dart | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart b/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart index ec52748488..8c8895a7fa 100644 --- a/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart +++ b/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart @@ -32,16 +32,22 @@ void testRequestCookies(Client client, await client .get(Uri.http(host, ''), headers: {'cookie': 'SID=298zf09hf012fh2'}); - final cookies = await httpServerQueue.next as List; - expect(cookies, ['cookie: SID=298zf09hf012fh2']); + final cookies = (await httpServerQueue.next as List).cast(); + expect(cookies, hasLength(1)); + final [header, value] = cookies[0].split(RegExp(':[ \t]+')); + expect(header.toLowerCase(), 'cookie'); + expect(value, 'SID=298zf09hf012fh2'); }, skip: canSendCookieHeaders ? false : 'cannot send cookie headers'); test('multiple cookies semicolon separated', () async { await client.get(Uri.http(host, ''), headers: {'cookie': 'SID=298zf09hf012fh2; lang=en-US'}); - final cookies = await httpServerQueue.next as List; - expect(cookies, ['cookie: SID=298zf09hf012fh2; lang=en-US']); + final cookies = (await httpServerQueue.next as List).cast(); + expect(cookies, hasLength(1)); + final [header, value] = cookies[0].split(RegExp(':[ \t]+')); + expect(header.toLowerCase(), 'cookie'); + expect(value, 'SID=298zf09hf012fh2; lang=en-US'); }, skip: canSendCookieHeaders ? false : 'cannot send cookie headers'); }); } From a18395242582384501d2362a5b5dc601470f7566 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Fri, 12 Jan 2024 07:03:46 -0800 Subject: [PATCH 7/8] Update request_cookies_test.dart --- .../lib/src/request_cookies_test.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart b/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart index 8c8895a7fa..a4eb78cf56 100644 --- a/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart +++ b/pkgs/http_client_conformance_tests/lib/src/request_cookies_test.dart @@ -10,6 +10,9 @@ import 'package:test/test.dart'; import 'request_cookies_server_vm.dart' if (dart.library.js_interop) 'request_cookies_server_web.dart'; +// The an HTTP header into [name, value]. +final headerSplitter = RegExp(':[ \t]+'); + /// Tests that the [Client] correctly sends "cookie" headers in the request. /// /// If [canSendCookieHeaders] is `false` then tests that require that "cookie" @@ -34,7 +37,7 @@ void testRequestCookies(Client client, final cookies = (await httpServerQueue.next as List).cast(); expect(cookies, hasLength(1)); - final [header, value] = cookies[0].split(RegExp(':[ \t]+')); + final [header, value] = cookies[0].split(headerSplitter); expect(header.toLowerCase(), 'cookie'); expect(value, 'SID=298zf09hf012fh2'); }, skip: canSendCookieHeaders ? false : 'cannot send cookie headers'); @@ -45,7 +48,7 @@ void testRequestCookies(Client client, final cookies = (await httpServerQueue.next as List).cast(); expect(cookies, hasLength(1)); - final [header, value] = cookies[0].split(RegExp(':[ \t]+')); + final [header, value] = cookies[0].split(headerSplitter); expect(header.toLowerCase(), 'cookie'); expect(value, 'SID=298zf09hf012fh2; lang=en-US'); }, skip: canSendCookieHeaders ? false : 'cannot send cookie headers'); From 05d1a51f3d44aeb6ca59414988e234751f9544e8 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Fri, 12 Jan 2024 09:04:03 -0800 Subject: [PATCH 8/8] Revert project files --- pkgs/cupertino_http/example/ios/Podfile.lock | 4 ++-- .../example/ios/Runner.xcodeproj/project.pbxproj | 3 +-- .../Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pkgs/cupertino_http/example/ios/Podfile.lock b/pkgs/cupertino_http/example/ios/Podfile.lock index 8bd679657f..709672b9d7 100644 --- a/pkgs/cupertino_http/example/ios/Podfile.lock +++ b/pkgs/cupertino_http/example/ios/Podfile.lock @@ -21,8 +21,8 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: cupertino_http: 5f8b1161107fe6c8d94a0c618735a033d93fa7db Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - integration_test: 13825b8a9334a850581300559b8839134b124670 + integration_test: a1e7d09bd98eca2fc37aefd79d4f41ad37bdbbe5 PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 -COCOAPODS: 1.11.3 +COCOAPODS: 1.11.2 diff --git a/pkgs/cupertino_http/example/ios/Runner.xcodeproj/project.pbxproj b/pkgs/cupertino_http/example/ios/Runner.xcodeproj/project.pbxproj index c4cc403ce4..3f233bb8b9 100644 --- a/pkgs/cupertino_http/example/ios/Runner.xcodeproj/project.pbxproj +++ b/pkgs/cupertino_http/example/ios/Runner.xcodeproj/project.pbxproj @@ -156,7 +156,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -205,7 +205,6 @@ files = ( ); inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( diff --git a/pkgs/cupertino_http/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/pkgs/cupertino_http/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a6b826db27..c87d15a335 100644 --- a/pkgs/cupertino_http/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/pkgs/cupertino_http/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@