From d12901e20a43112c23913a21c220549418164e34 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Wed, 29 Nov 2023 16:33:57 -0800 Subject: [PATCH 1/8] Add support for setting headers for all requests --- pkgs/cupertino_http/CHANGELOG.md | 5 ++- .../url_session_configuration_test.dart | 43 +++++++++++++++++++ pkgs/cupertino_http/example/lib/main.dart | 4 ++ .../cupertino_http/lib/src/cupertino_api.dart | 27 ++++++++++++ pkgs/cupertino_http/pubspec.yaml | 2 +- 5 files changed, 79 insertions(+), 2 deletions(-) diff --git a/pkgs/cupertino_http/CHANGELOG.md b/pkgs/cupertino_http/CHANGELOG.md index 48d990e185..d768f7a5c7 100644 --- a/pkgs/cupertino_http/CHANGELOG.md +++ b/pkgs/cupertino_http/CHANGELOG.md @@ -1,4 +1,7 @@ -## 1.1.1-wip +## 1.2.0 + +* Add support for setting additional http headers in + `URLSessionConfiguration`. ## 1.1.0 diff --git a/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart b/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart index 85386bcd90..e763337156 100644 --- a/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart +++ b/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart @@ -2,10 +2,37 @@ // 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:io'; + import 'package:cupertino_http/cupertino_http.dart'; import 'package:integration_test/integration_test.dart'; import 'package:test/test.dart'; +Future>> sentHeaders( + URLSessionConfiguration config) async { + final session = URLSession.sessionWithConfiguration(config); + final headers = >{}; + final server = (await HttpServer.bind('localhost', 0)) + ..listen((request) async { + request.headers.forEach((k, v) => headers[k] = v); + await request.drain(); + request.response.headers.set('Content-Type', 'text/plain'); + request.response.write('Hello World'); + await request.response.close(); + }); + + final task = session.dataTaskWithRequest( + URLRequest.fromUrl(Uri.parse('http://localhost:${server.port}'))) + ..resume(); + while (task.state != URLSessionTaskState.urlSessionTaskStateCompleted) { + // Let the event loop run. + await Future.delayed(const Duration()); + } + + await server.close(); + return headers; +} + void testProperties(URLSessionConfiguration config) { group('properties', () { test('allowsCellularAccess', () { @@ -32,6 +59,22 @@ void testProperties(URLSessionConfiguration config) { config.discretionary = false; expect(config.discretionary, false); }); + test('httpAdditionalHeaders', () async { + expect(config.httpAdditionalHeaders, isNull); + + config.httpAdditionalHeaders = { + 'User-Agent': 'My Client', + 'MyHeader': 'myvalue' + }; + expect(config.httpAdditionalHeaders, + {'User-Agent': 'My Client', 'MyHeader': 'myvalue'}); + final headers = await sentHeaders(config); + expect(headers, containsPair('user-agent', ['My Client'])); + expect(headers, containsPair('myheader', ['myvalue'])); + + config.httpAdditionalHeaders = null; + expect(config.httpAdditionalHeaders, isNull); + }); test('httpCookieAcceptPolicy', () { config.httpCookieAcceptPolicy = HTTPCookieAcceptPolicy.httpCookieAcceptPolicyAlways; diff --git a/pkgs/cupertino_http/example/lib/main.dart b/pkgs/cupertino_http/example/lib/main.dart index edfceac92e..0d3b98ef6d 100644 --- a/pkgs/cupertino_http/example/lib/main.dart +++ b/pkgs/cupertino_http/example/lib/main.dart @@ -15,6 +15,10 @@ import 'book.dart'; void main() { var clientFactory = Client.new; // The default Client. if (Platform.isIOS || Platform.isMacOS) { + final config = URLSessionConfiguration.ephemeralSessionConfiguration() + ..cache = URLCache.withCapacity(memoryCapacity: 2 * 1024 * 1024) + ..httpAdditionalHeaders = {'User-Agent': 'Book Agent'}; + clientFactory = () => CupertinoClient.fromSessionConfiguration(config); clientFactory = CupertinoClient.defaultSessionConfiguration.call; } runWithClient(() => runApp(const BookSearchApp()), clientFactory); diff --git a/pkgs/cupertino_http/lib/src/cupertino_api.dart b/pkgs/cupertino_http/lib/src/cupertino_api.dart index 01c4853b1c..0317eeb834 100644 --- a/pkgs/cupertino_http/lib/src/cupertino_api.dart +++ b/pkgs/cupertino_http/lib/src/cupertino_api.dart @@ -344,6 +344,32 @@ class URLSessionConfiguration bool get discretionary => _nsObject.discretionary; set discretionary(bool value) => _nsObject.discretionary = value; + /// Additional headers to send with each request. + /// + /// Note that the getter for this field returns a **copy** of the headers. + /// + /// See [NSURLSessionConfiguration.HTTPAdditionalHeaders](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1411532-httpadditionalheaders) + Map? get httpAdditionalHeaders { + if (_nsObject.HTTPAdditionalHeaders == null) { + return null; + } + final headers = ncb.NSDictionary.castFrom(_nsObject.HTTPAdditionalHeaders!); + return stringDictToMap(headers); + } + + set httpAdditionalHeaders(Map? headers) { + if (headers == null) { + _nsObject.HTTPAdditionalHeaders = null; + return; + } + final d = ncb.NSMutableDictionary.alloc(linkedLibs).init(); + headers.forEach((key, value) { + d.setObject_forKey_( + value.toNSString(linkedLibs), key.toNSString(linkedLibs)); + }); + _nsObject.HTTPAdditionalHeaders = d; + } + /// What policy to use when deciding whether to accept cookies. /// /// See [NSURLSessionConfiguration.HTTPCookieAcceptPolicy](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1408933-httpcookieacceptpolicy). @@ -441,6 +467,7 @@ class URLSessionConfiguration 'allowsConstrainedNetworkAccess=$allowsConstrainedNetworkAccess ' 'allowsExpensiveNetworkAccess=$allowsExpensiveNetworkAccess ' 'discretionary=$discretionary ' + 'httpAdditionalHeaders=$httpAdditionalHeaders ' 'httpCookieAcceptPolicy=$httpCookieAcceptPolicy ' 'httpShouldSetCookies=$httpShouldSetCookies ' 'httpMaximumConnectionsPerHost=$httpMaximumConnectionsPerHost ' diff --git a/pkgs/cupertino_http/pubspec.yaml b/pkgs/cupertino_http/pubspec.yaml index 9b7e1f828a..93cd94bfca 100644 --- a/pkgs/cupertino_http/pubspec.yaml +++ b/pkgs/cupertino_http/pubspec.yaml @@ -2,7 +2,7 @@ name: cupertino_http description: > A macOS/iOS Flutter plugin that provides access to the Foundation URL Loading System. -version: 1.1.1-wip +version: 1.2.0 repository: https://github.com/dart-lang/http/tree/master/pkgs/cupertino_http environment: From 3789296a6da123023ff9ebba69aec81b109a2f45 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Thu, 30 Nov 2023 10:40:56 -0800 Subject: [PATCH 2/8] Change to wip --- pkgs/cupertino_http/CHANGELOG.md | 2 +- pkgs/cupertino_http/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/cupertino_http/CHANGELOG.md b/pkgs/cupertino_http/CHANGELOG.md index d768f7a5c7..47e25cb590 100644 --- a/pkgs/cupertino_http/CHANGELOG.md +++ b/pkgs/cupertino_http/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.2.0 +## 1.2.0-wip * Add support for setting additional http headers in `URLSessionConfiguration`. diff --git a/pkgs/cupertino_http/pubspec.yaml b/pkgs/cupertino_http/pubspec.yaml index 93cd94bfca..f399f41762 100644 --- a/pkgs/cupertino_http/pubspec.yaml +++ b/pkgs/cupertino_http/pubspec.yaml @@ -2,7 +2,7 @@ name: cupertino_http description: > A macOS/iOS Flutter plugin that provides access to the Foundation URL Loading System. -version: 1.2.0 +version: 1.2.0-wip repository: https://github.com/dart-lang/http/tree/master/pkgs/cupertino_http environment: From 198d4d316c5bfb4369a6bb3aa38b45b1429533c9 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Thu, 30 Nov 2023 10:44:55 -0800 Subject: [PATCH 3/8] Comment --- .../integration_test/url_session_configuration_test.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart b/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart index e763337156..bef8352f69 100644 --- a/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart +++ b/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart @@ -8,6 +8,8 @@ import 'package:cupertino_http/cupertino_http.dart'; import 'package:integration_test/integration_test.dart'; import 'package:test/test.dart'; +/// Make a HTTP request using the given configuration and return the headers +/// received by the server. Future>> sentHeaders( URLSessionConfiguration config) async { final session = URLSession.sessionWithConfiguration(config); From 261267415bd7fcc2d4de95a7a8870b88cfb28f3a Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Thu, 30 Nov 2023 10:50:51 -0800 Subject: [PATCH 4/8] Remove --- pkgs/cupertino_http/example/lib/main.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgs/cupertino_http/example/lib/main.dart b/pkgs/cupertino_http/example/lib/main.dart index 0d3b98ef6d..32c2b08980 100644 --- a/pkgs/cupertino_http/example/lib/main.dart +++ b/pkgs/cupertino_http/example/lib/main.dart @@ -19,7 +19,6 @@ void main() { ..cache = URLCache.withCapacity(memoryCapacity: 2 * 1024 * 1024) ..httpAdditionalHeaders = {'User-Agent': 'Book Agent'}; clientFactory = () => CupertinoClient.fromSessionConfiguration(config); - clientFactory = CupertinoClient.defaultSessionConfiguration.call; } runWithClient(() => runApp(const BookSearchApp()), clientFactory); } From 2b32e908b3c306bab900955d425c6ec6cab2876b Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 4 Dec 2023 13:09:42 -0800 Subject: [PATCH 5/8] Update pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart Co-authored-by: Nate Bosch --- .../integration_test/url_session_configuration_test.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart b/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart index bef8352f69..c8e4ce483b 100644 --- a/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart +++ b/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart @@ -27,8 +27,7 @@ Future>> sentHeaders( URLRequest.fromUrl(Uri.parse('http://localhost:${server.port}'))) ..resume(); while (task.state != URLSessionTaskState.urlSessionTaskStateCompleted) { - // Let the event loop run. - await Future.delayed(const Duration()); + await pumpEventQueue(); } await server.close(); From 4d0faa63b1dca3fe817ff67324c3eed618e9da9a Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 4 Dec 2023 13:11:27 -0800 Subject: [PATCH 6/8] Update pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart Co-authored-by: Nate Bosch --- .../integration_test/url_session_configuration_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart b/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart index c8e4ce483b..ab117c37d0 100644 --- a/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart +++ b/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart @@ -23,8 +23,8 @@ Future>> sentHeaders( await request.response.close(); }); - final task = session.dataTaskWithRequest( - URLRequest.fromUrl(Uri.parse('http://localhost:${server.port}'))) + final task = session.dataTaskWithRequest(URLRequest.fromUrl( + Uri(scheme: 'http', host: 'localhost', port: server.port))) ..resume(); while (task.state != URLSessionTaskState.urlSessionTaskStateCompleted) { await pumpEventQueue(); From 60d062ef1f60d1547152410c3e4304370fe33fed Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 4 Dec 2023 13:11:41 -0800 Subject: [PATCH 7/8] Update pkgs/cupertino_http/lib/src/cupertino_api.dart Co-authored-by: Nate Bosch --- pkgs/cupertino_http/lib/src/cupertino_api.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkgs/cupertino_http/lib/src/cupertino_api.dart b/pkgs/cupertino_http/lib/src/cupertino_api.dart index 0317eeb834..5cebd7ed42 100644 --- a/pkgs/cupertino_http/lib/src/cupertino_api.dart +++ b/pkgs/cupertino_http/lib/src/cupertino_api.dart @@ -350,11 +350,11 @@ class URLSessionConfiguration /// /// See [NSURLSessionConfiguration.HTTPAdditionalHeaders](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1411532-httpadditionalheaders) Map? get httpAdditionalHeaders { - if (_nsObject.HTTPAdditionalHeaders == null) { - return null; + if (_nsObject.HTTPAdditionalHeaders case var additionalHeaders?) { + final headers = ncb.NSDictionary.castFrom(additionalHeaders); + return stringDictToMap(headers); } - final headers = ncb.NSDictionary.castFrom(_nsObject.HTTPAdditionalHeaders!); - return stringDictToMap(headers); + return null; } set httpAdditionalHeaders(Map? headers) { From 1dd2fd01f56e80ab6ab6e58c8e8c904fe7a357b1 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Mon, 4 Dec 2023 13:12:09 -0800 Subject: [PATCH 8/8] Commit --- .../integration_test/url_session_configuration_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart b/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart index bef8352f69..860054bcfc 100644 --- a/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart +++ b/pkgs/cupertino_http/example/integration_test/url_session_configuration_test.dart @@ -23,12 +23,12 @@ Future>> sentHeaders( await request.response.close(); }); - final task = session.dataTaskWithRequest( - URLRequest.fromUrl(Uri.parse('http://localhost:${server.port}'))) + final task = session.dataTaskWithRequest(URLRequest.fromUrl( + Uri(scheme: 'http', host: 'localhost', port: server.port))) ..resume(); while (task.state != URLSessionTaskState.urlSessionTaskStateCompleted) { // Let the event loop run. - await Future.delayed(const Duration()); + await pumpEventQueue(); } await server.close();