Add support for setting headers for all requests (#1060)
diff --git a/pkgs/cupertino_http/CHANGELOG.md b/pkgs/cupertino_http/CHANGELOG.md
index 48d990e..47e25cb 100644
--- a/pkgs/cupertino_http/CHANGELOG.md
+++ b/pkgs/cupertino_http/CHANGELOG.md
@@ -1,4 +1,7 @@
-## 1.1.1-wip
+## 1.2.0-wip
+
+* 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 85386bc..ab117c3 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,38 @@
// 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';
+/// Make a HTTP request using the given configuration and return the headers
+/// received by the server.
+Future<Map<String, List<String>>> sentHeaders(
+ URLSessionConfiguration config) async {
+ final session = URLSession.sessionWithConfiguration(config);
+ final headers = <String, List<String>>{};
+ final server = (await HttpServer.bind('localhost', 0))
+ ..listen((request) async {
+ request.headers.forEach((k, v) => headers[k] = v);
+ await request.drain<void>();
+ request.response.headers.set('Content-Type', 'text/plain');
+ request.response.write('Hello World');
+ await request.response.close();
+ });
+
+ final task = session.dataTaskWithRequest(URLRequest.fromUrl(
+ Uri(scheme: 'http', host: 'localhost', port: server.port)))
+ ..resume();
+ while (task.state != URLSessionTaskState.urlSessionTaskStateCompleted) {
+ await pumpEventQueue();
+ }
+
+ await server.close();
+ return headers;
+}
+
void testProperties(URLSessionConfiguration config) {
group('properties', () {
test('allowsCellularAccess', () {
@@ -32,6 +60,22 @@
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 edfceac..32c2b08 100644
--- a/pkgs/cupertino_http/example/lib/main.dart
+++ b/pkgs/cupertino_http/example/lib/main.dart
@@ -15,7 +15,10 @@
void main() {
var clientFactory = Client.new; // The default Client.
if (Platform.isIOS || Platform.isMacOS) {
- clientFactory = CupertinoClient.defaultSessionConfiguration.call;
+ final config = URLSessionConfiguration.ephemeralSessionConfiguration()
+ ..cache = URLCache.withCapacity(memoryCapacity: 2 * 1024 * 1024)
+ ..httpAdditionalHeaders = {'User-Agent': 'Book Agent'};
+ clientFactory = () => CupertinoClient.fromSessionConfiguration(config);
}
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 01c4853..5cebd7e 100644
--- a/pkgs/cupertino_http/lib/src/cupertino_api.dart
+++ b/pkgs/cupertino_http/lib/src/cupertino_api.dart
@@ -344,6 +344,32 @@
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<String, String>? get httpAdditionalHeaders {
+ if (_nsObject.HTTPAdditionalHeaders case var additionalHeaders?) {
+ final headers = ncb.NSDictionary.castFrom(additionalHeaders);
+ return stringDictToMap(headers);
+ }
+ return null;
+ }
+
+ set httpAdditionalHeaders(Map<String, String>? 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 @@
'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 824a581..81905aa 100644
--- a/pkgs/cupertino_http/pubspec.yaml
+++ b/pkgs/cupertino_http/pubspec.yaml
@@ -1,5 +1,5 @@
name: cupertino_http
-version: 1.1.1-wip
+version: 1.2.0-wip
description: >-
A macOS/iOS Flutter plugin that provides access to the Foundation URL
Loading System.