From d57441a2a9ec3b519bfd8e23f9c3275a21760647 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Sat, 19 Jul 2025 10:57:33 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20Introduce=20`ClosableBaseClient?= =?UTF-8?q?`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkgs/http/lib/src/base_client.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pkgs/http/lib/src/base_client.dart b/pkgs/http/lib/src/base_client.dart index 48a7f92fe9..c6c75d52cd 100644 --- a/pkgs/http/lib/src/base_client.dart +++ b/pkgs/http/lib/src/base_client.dart @@ -106,3 +106,10 @@ abstract mixin class BaseClient implements Client { @override void close() {} } + +abstract class ClosableBaseClient extends BaseClient { + bool get isClosed; + + @override + void close(); +} From a2c0b60386c7f184919c134605c0b69ce311079a Mon Sep 17 00:00:00 2001 From: Alex Li Date: Sat, 19 Jul 2025 10:58:15 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=9A=80=20Integrate=20the=20class=20to?= =?UTF-8?q?=20clients?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkgs/cronet_http/lib/src/cronet_client.dart | 9 +++++++-- pkgs/cupertino_http/lib/src/cupertino_client.dart | 4 +++- pkgs/http/lib/src/browser_client.dart | 5 ++++- pkgs/http/lib/src/io_client.dart | 9 +++++++-- pkgs/ok_http/lib/src/ok_http_client.dart | 5 ++++- 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/pkgs/cronet_http/lib/src/cronet_client.dart b/pkgs/cronet_http/lib/src/cronet_client.dart index ef20b6b779..b664b74a6b 100644 --- a/pkgs/cronet_http/lib/src/cronet_client.dart +++ b/pkgs/cronet_http/lib/src/cronet_client.dart @@ -81,6 +81,8 @@ enum CacheMode { /// An environment that can be used to make HTTP requests. class CronetEngine { late final jb.CronetEngine _engine; + + bool get isClosed => _isClosed; bool _isClosed = false; CronetEngine._(this._engine); @@ -351,9 +353,12 @@ jb.UrlRequestCallbackProxy$UrlRequestCallbackInterface _urlRequestCallbacks( /// A HTTP [Client] based on the /// [Cronet](https://developer.android.com/guide/topics/connectivity/cronet) /// network stack. -class CronetClient extends BaseClient { +class CronetClient extends ClosableBaseClient { static final _executor = jb.Executors.newCachedThreadPool(); CronetEngine? _engine; + + @override + bool get isClosed => _isClosed; bool _isClosed = false; /// Indicates that [CronetClient] is responsible for closing [_engine]. @@ -414,7 +419,7 @@ class CronetClient extends BaseClient { final engine = _engine ?? CronetEngine.build(); _engine = engine; - if (engine._isClosed) { + if (engine.isClosed) { throw ClientException( 'HTTP request failed. CronetEngine is already closed.', request.url); } diff --git a/pkgs/cupertino_http/lib/src/cupertino_client.dart b/pkgs/cupertino_http/lib/src/cupertino_client.dart index 456254304e..bde61eb3f0 100644 --- a/pkgs/cupertino_http/lib/src/cupertino_client.dart +++ b/pkgs/cupertino_http/lib/src/cupertino_client.dart @@ -94,9 +94,11 @@ class _TaskTracker { /// } /// } /// ``` -class CupertinoClient extends BaseClient { +class CupertinoClient extends ClosableBaseClient { static final Map _tasks = {}; + @override + bool get isClosed => _urlSession == null; URLSession? _urlSession; CupertinoClient._(this._urlSession); diff --git a/pkgs/http/lib/src/browser_client.dart b/pkgs/http/lib/src/browser_client.dart index 0f57d5c38d..8c1cd6fcef 100644 --- a/pkgs/http/lib/src/browser_client.dart +++ b/pkgs/http/lib/src/browser_client.dart @@ -50,14 +50,17 @@ external JSPromise _fetch( /// /// Responses are streamed but requests are not. A request will only be sent /// once all the data is available. -class BrowserClient extends BaseClient { +class BrowserClient extends ClosableBaseClient { /// Whether to send credentials such as cookies or authorization headers for /// cross-site requests. /// /// Defaults to `false`. bool withCredentials = false; + @override + bool get isClosed => _isClosed; bool _isClosed = false; + final _openRequestAbortControllers = []; /// Sends an HTTP request and asynchronously returns the response. diff --git a/pkgs/http/lib/src/io_client.dart b/pkgs/http/lib/src/io_client.dart index f259181c90..42547ff3cb 100644 --- a/pkgs/http/lib/src/io_client.dart +++ b/pkgs/http/lib/src/io_client.dart @@ -82,10 +82,14 @@ class _IOStreamedResponseV2 extends IOStreamedResponse /// // would be caught by this handler. /// } /// ``` -class IOClient extends BaseClient { +class IOClient extends ClosableBaseClient { /// The underlying `dart:io` HTTP client. HttpClient? _inner; + @override + bool get isClosed => _isClosed; + bool _isClosed = false; + /// Create a new `dart:io`-based HTTP [Client]. /// /// If [inner] is provided then it can be used to provide configuration @@ -103,7 +107,7 @@ class IOClient extends BaseClient { /// Sends an HTTP request and asynchronously returns the response. @override Future send(BaseRequest request) async { - if (_inner == null) { + if (_inner == null || _isClosed) { throw ClientException( 'HTTP request failed. Client is already closed.', request.url); } @@ -243,5 +247,6 @@ class IOClient extends BaseClient { _inner!.close(force: true); _inner = null; } + _isClosed = true; } } diff --git a/pkgs/ok_http/lib/src/ok_http_client.dart b/pkgs/ok_http/lib/src/ok_http_client.dart index 7d96671216..5e73985be1 100644 --- a/pkgs/ok_http/lib/src/ok_http_client.dart +++ b/pkgs/ok_http/lib/src/ok_http_client.dart @@ -213,8 +213,11 @@ Future choosePrivateKeyAlias({ /// } /// } /// ``` -class OkHttpClient extends BaseClient { +class OkHttpClient extends ClosableBaseClient { late bindings.OkHttpClient _client; + + @override + bool get isClosed => _isClosed; bool _isClosed = false; /// The configuration for this client, applied on a per-call basis. From 31902f4348ad5dd20e9b454579f1df192a1cf412 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Sat, 19 Jul 2025 11:12:17 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=93=9D=20CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkgs/cronet_http/CHANGELOG.md | 5 +++++ pkgs/cupertino_http/CHANGELOG.md | 5 +++++ pkgs/http/CHANGELOG.md | 5 +++++ pkgs/ok_http/CHANGELOG.md | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/pkgs/cronet_http/CHANGELOG.md b/pkgs/cronet_http/CHANGELOG.md index 29778bfa46..6a42f58e2f 100644 --- a/pkgs/cronet_http/CHANGELOG.md +++ b/pkgs/cronet_http/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.5.0-wip + +* Implements `ClosableBaseClient`. +* Expose `CronetEngine.close` and `CronetClient.close`. + ## 1.4.0 * Add a new `CronetStreamedResponse` class that provides additional information diff --git a/pkgs/cupertino_http/CHANGELOG.md b/pkgs/cupertino_http/CHANGELOG.md index a42cd42da8..d7b8a8cd52 100644 --- a/pkgs/cupertino_http/CHANGELOG.md +++ b/pkgs/cupertino_http/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.4.0-wip + +* Implements `ClosableBaseClient`. +* Expose `CronetEngine.close` and `CronetClient.close`. + ## 2.3.0-wip * Add the ability to abort requests. diff --git a/pkgs/http/CHANGELOG.md b/pkgs/http/CHANGELOG.md index 80d9110d3e..2901f8f4e4 100644 --- a/pkgs/http/CHANGELOG.md +++ b/pkgs/http/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.5.0-wip + +* Introduce `ClosableBaseClient` specifically for clients that can be closed.## 0.2.0-wip +* Expose `IOClient.close` and `BrowserClient.close`. + ## 1.5.0-beta.2 * Fixed a bug in `IOClient` where the `HttpClient`'s response stream was diff --git a/pkgs/ok_http/CHANGELOG.md b/pkgs/ok_http/CHANGELOG.md index 196dc70a7b..d4dc2a40c0 100644 --- a/pkgs/ok_http/CHANGELOG.md +++ b/pkgs/ok_http/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.2.0-wip + +* Implements `ClosableBaseClient`. +* Expose `OkHttpClient.close`. + ## 0.1.1-wip - `OkHttpClient` now receives an `OkHttpClientConfiguration` to configure the client on a per-call basis.