From bf52bd4d26fd8104d718fc38957c27d6457953c9 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Thu, 1 May 2025 16:09:29 -0700 Subject: [PATCH 1/4] Add a new exception type `NSErrorClientException` --- pkgs/cupertino_http/CHANGELOG.md | 4 ++- .../ns_error_client_exception.dart | 35 +++++++++++++++++++ pkgs/cupertino_http/lib/cupertino_http.dart | 3 +- .../lib/src/cupertino_client.dart | 23 ++++++++++-- pkgs/cupertino_http/pubspec.yaml | 2 +- 5 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 pkgs/cupertino_http/example/integration_test/ns_error_client_exception.dart diff --git a/pkgs/cupertino_http/CHANGELOG.md b/pkgs/cupertino_http/CHANGELOG.md index e21c2fd886..b5b1c56c8d 100644 --- a/pkgs/cupertino_http/CHANGELOG.md +++ b/pkgs/cupertino_http/CHANGELOG.md @@ -1,6 +1,8 @@ -## 2.1.2-wip +## 2.2.0 * Cancel requests when the response stream is cancelled. +* Add a new exception type `NSErrorClientException` that contains the + `NSError` associated with the failure. ## 2.1.1 diff --git a/pkgs/cupertino_http/example/integration_test/ns_error_client_exception.dart b/pkgs/cupertino_http/example/integration_test/ns_error_client_exception.dart new file mode 100644 index 0000000000..c00677a838 --- /dev/null +++ b/pkgs/cupertino_http/example/integration_test/ns_error_client_exception.dart @@ -0,0 +1,35 @@ +// Copyright (c) 2025, 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:cupertino_http/cupertino_http.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:objective_c/objective_c.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + group('NSErrorClientException', () { + late CupertinoClient client; + + setUpAll(() => client = CupertinoClient.defaultSessionConfiguration()); + tearDownAll(() => client.close()); + + test('thrown', () async { + expect( + () => client.get(Uri.http('doesnotexist', '/')), + throwsA(isA() + .having((e) => e.error.domain.toDartString(), 'error.domain', + 'NSURLErrorDomain') + .having((e) => e.error.code, 'error.code', -1003) + .having( + (e) => e.toString(), + 'toString()', + 'NSErrorClientExceptions: A server with the specified ' + 'hostname could not be found. ' + '[domain=NSURLErrorDomain, code=-1003], ' + 'uri=http://doesnotexist/'))); + }); + }); +} diff --git a/pkgs/cupertino_http/lib/cupertino_http.dart b/pkgs/cupertino_http/lib/cupertino_http.dart index b85a868b4e..6dfd922e19 100644 --- a/pkgs/cupertino_http/lib/cupertino_http.dart +++ b/pkgs/cupertino_http/lib/cupertino_http.dart @@ -92,5 +92,6 @@ import 'package:http/http.dart'; import 'src/cupertino_client.dart'; export 'src/cupertino_api.dart'; -export 'src/cupertino_client.dart' show CupertinoClient; +export 'src/cupertino_client.dart' + show CupertinoClient, NSErrorClientExceptions; export 'src/cupertino_web_socket.dart'; diff --git a/pkgs/cupertino_http/lib/src/cupertino_client.dart b/pkgs/cupertino_http/lib/src/cupertino_client.dart index 72db68525e..1840095164 100644 --- a/pkgs/cupertino_http/lib/src/cupertino_client.dart +++ b/pkgs/cupertino_http/lib/src/cupertino_client.dart @@ -17,6 +17,26 @@ final _digitRegex = RegExp(r'^\d+$'); const _nsurlErrorCancelled = -999; +/// A [ClientException] generated from an [NSError]. +class NSErrorClientExceptions extends ClientException { + final NSError error; + + NSErrorClientExceptions(this.error, [Uri? uri]) + : super(error.localizedDescription.toDartString(), uri); + + @override + String toString() { + final b = StringBuffer( + 'NSErrorClientExceptions: ${error.localizedDescription.toDartString()} ' + '[domain=${error.domain.toDartString()}, code=${error.code}]'); + + if (uri != null) { + b.write(', uri=$uri'); + } + return b.toString(); + } +} + /// This class can be removed when `package:http` v2 is released. class _StreamedResponseWithUrl extends StreamedResponse implements BaseResponseWithUrl { @@ -176,8 +196,7 @@ class CupertinoClient extends BaseClient { if (error != null && !(error.domain.toDartString() == 'NSURLErrorDomain' && error.code == _nsurlErrorCancelled)) { - final exception = ClientException( - error.localizedDescription.toDartString(), taskTracker.request.url); + final exception = NSErrorClientExceptions(error, taskTracker.request.url); if (taskTracker.profile != null && taskTracker.profile!.requestData.endTime == null) { // Error occurred during the request. diff --git a/pkgs/cupertino_http/pubspec.yaml b/pkgs/cupertino_http/pubspec.yaml index 585b5ea7ac..fd5a228ff6 100644 --- a/pkgs/cupertino_http/pubspec.yaml +++ b/pkgs/cupertino_http/pubspec.yaml @@ -1,5 +1,5 @@ name: cupertino_http -version: 2.1.2-wip +version: 2.2.0-wip description: >- A macOS/iOS Flutter plugin that provides access to the Foundation URL Loading System. From d09da073f607d10b45bf0068b194a3951b9fd361 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Thu, 1 May 2025 16:16:29 -0700 Subject: [PATCH 2/4] Update client_profile_test.dart --- .../example/integration_test/client_profile_test.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkgs/cupertino_http/example/integration_test/client_profile_test.dart b/pkgs/cupertino_http/example/integration_test/client_profile_test.dart index aa74415881..eba570d800 100644 --- a/pkgs/cupertino_http/example/integration_test/client_profile_test.dart +++ b/pkgs/cupertino_http/example/integration_test/client_profile_test.dart @@ -164,7 +164,8 @@ void main() { expect(profile.requestData.bodyBytes, 'Hi'.codeUnits); expect(profile.requestData.contentLength, 2); expect(profile.requestData.endTime, isNotNull); - expect(profile.requestData.error, startsWith('ClientException:')); + expect( + profile.requestData.error, startsWith('NSErrorClientException:')); expect( profile.requestData.headers, containsPair('Content-Length', ['2'])); expect(profile.requestData.headers, @@ -247,7 +248,8 @@ void main() { expect(profile.responseData.compressionState, isNull); expect(profile.responseData.contentLength, 11); expect(profile.responseData.endTime, isNotNull); - expect(profile.responseData.error, startsWith('ClientException:')); + expect( + profile.responseData.error, startsWith('NSErrorClientException:')); expect(profile.responseData.headers, containsPair('content-type', ['text/plain'])); expect(profile.responseData.headers, From 6a3cf01b62a464a8b80baef9599b94ba25d043b9 Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Thu, 1 May 2025 16:22:32 -0700 Subject: [PATCH 3/4] Fix exception name --- .../example/integration_test/ns_error_client_exception.dart | 2 +- pkgs/cupertino_http/lib/src/cupertino_client.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/cupertino_http/example/integration_test/ns_error_client_exception.dart b/pkgs/cupertino_http/example/integration_test/ns_error_client_exception.dart index c00677a838..295e5ae09d 100644 --- a/pkgs/cupertino_http/example/integration_test/ns_error_client_exception.dart +++ b/pkgs/cupertino_http/example/integration_test/ns_error_client_exception.dart @@ -26,7 +26,7 @@ void main() { .having( (e) => e.toString(), 'toString()', - 'NSErrorClientExceptions: A server with the specified ' + 'NSErrorClientException: A server with the specified ' 'hostname could not be found. ' '[domain=NSURLErrorDomain, code=-1003], ' 'uri=http://doesnotexist/'))); diff --git a/pkgs/cupertino_http/lib/src/cupertino_client.dart b/pkgs/cupertino_http/lib/src/cupertino_client.dart index 1840095164..adbf580226 100644 --- a/pkgs/cupertino_http/lib/src/cupertino_client.dart +++ b/pkgs/cupertino_http/lib/src/cupertino_client.dart @@ -27,7 +27,7 @@ class NSErrorClientExceptions extends ClientException { @override String toString() { final b = StringBuffer( - 'NSErrorClientExceptions: ${error.localizedDescription.toDartString()} ' + 'NSErrorClientException: ${error.localizedDescription.toDartString()} ' '[domain=${error.domain.toDartString()}, code=${error.code}]'); if (uri != null) { From 8efdab5b4d934034e5cc4cd82f2177f9a357a83a Mon Sep 17 00:00:00 2001 From: Brian Quinlan Date: Fri, 2 May 2025 09:28:51 -0700 Subject: [PATCH 4/4] Fix name --- .../example/integration_test/ns_error_client_exception.dart | 2 +- pkgs/cupertino_http/lib/cupertino_http.dart | 3 +-- pkgs/cupertino_http/lib/src/cupertino_client.dart | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pkgs/cupertino_http/example/integration_test/ns_error_client_exception.dart b/pkgs/cupertino_http/example/integration_test/ns_error_client_exception.dart index 295e5ae09d..46b34befeb 100644 --- a/pkgs/cupertino_http/example/integration_test/ns_error_client_exception.dart +++ b/pkgs/cupertino_http/example/integration_test/ns_error_client_exception.dart @@ -19,7 +19,7 @@ void main() { test('thrown', () async { expect( () => client.get(Uri.http('doesnotexist', '/')), - throwsA(isA() + throwsA(isA() .having((e) => e.error.domain.toDartString(), 'error.domain', 'NSURLErrorDomain') .having((e) => e.error.code, 'error.code', -1003) diff --git a/pkgs/cupertino_http/lib/cupertino_http.dart b/pkgs/cupertino_http/lib/cupertino_http.dart index 6dfd922e19..a24e2a8fc3 100644 --- a/pkgs/cupertino_http/lib/cupertino_http.dart +++ b/pkgs/cupertino_http/lib/cupertino_http.dart @@ -92,6 +92,5 @@ import 'package:http/http.dart'; import 'src/cupertino_client.dart'; export 'src/cupertino_api.dart'; -export 'src/cupertino_client.dart' - show CupertinoClient, NSErrorClientExceptions; +export 'src/cupertino_client.dart' show CupertinoClient, NSErrorClientException; export 'src/cupertino_web_socket.dart'; diff --git a/pkgs/cupertino_http/lib/src/cupertino_client.dart b/pkgs/cupertino_http/lib/src/cupertino_client.dart index adbf580226..7e592eb3e6 100644 --- a/pkgs/cupertino_http/lib/src/cupertino_client.dart +++ b/pkgs/cupertino_http/lib/src/cupertino_client.dart @@ -18,10 +18,10 @@ final _digitRegex = RegExp(r'^\d+$'); const _nsurlErrorCancelled = -999; /// A [ClientException] generated from an [NSError]. -class NSErrorClientExceptions extends ClientException { +class NSErrorClientException extends ClientException { final NSError error; - NSErrorClientExceptions(this.error, [Uri? uri]) + NSErrorClientException(this.error, [Uri? uri]) : super(error.localizedDescription.toDartString(), uri); @override @@ -196,7 +196,7 @@ class CupertinoClient extends BaseClient { if (error != null && !(error.domain.toDartString() == 'NSURLErrorDomain' && error.code == _nsurlErrorCancelled)) { - final exception = NSErrorClientExceptions(error, taskTracker.request.url); + final exception = NSErrorClientException(error, taskTracker.request.url); if (taskTracker.profile != null && taskTracker.profile!.requestData.endTime == null) { // Error occurred during the request.