Skip to content

Commit c955c7e

Browse files
authored
Add consistent implementations for close. (#851)
1 parent d434d42 commit c955c7e

File tree

12 files changed

+100
-6
lines changed

12 files changed

+100
-6
lines changed

pkgs/cronet_http/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.1.1
2+
3+
* `CronetClient` throws an exception if `send` is called after `close`.
4+
15
## 0.1.0
26

37
* Add a CronetClient that accepts a `Future<CronetEngine>`.

pkgs/cronet_http/example/integration_test/client_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ void testClientConformance(CronetClient Function() clientFactory) {
2222
testRedirect(client);
2323
testCompressedResponseBody(client);
2424
testMultipleClients(clientFactory);
25+
testClose(clientFactory);
2526
}
2627

2728
Future<void> testConformance() async {

pkgs/cronet_http/lib/cronet_client.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class CronetEngine {
134134
class CronetClient extends BaseClient {
135135
CronetEngine? _engine;
136136
Future<CronetEngine>? _engineFuture;
137+
bool _isClosed = false;
137138

138139
/// Indicates that [_engine] was constructed as an implementation detail for
139140
/// this [CronetClient] (i.e. was not provided as a constructor argument) and
@@ -170,13 +171,19 @@ class CronetClient extends BaseClient {
170171

171172
@override
172173
void close() {
173-
if (_ownedEngine) {
174+
if (!_isClosed && _ownedEngine) {
174175
_engine?.close();
175176
}
177+
_isClosed = true;
176178
}
177179

178180
@override
179181
Future<StreamedResponse> send(BaseRequest request) async {
182+
if (_isClosed) {
183+
throw ClientException(
184+
'HTTP request failed. Client is already closed.', request.url);
185+
}
186+
180187
if (_engine == null) {
181188
// Create the future here rather than in the [fromCronetEngineFuture]
182189
// factory so that [close] does not have to await the future just to

pkgs/cronet_http/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: cronet_http
22
description: >
33
An Android Flutter plugin that provides access to the Cronet HTTP client.
4-
version: 0.1.0
4+
version: 0.1.1
55
repository: https://github.com/dart-lang/http/tree/master/pkgs/cronet_http
66

77
environment:

pkgs/cupertino_http/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
* Fix a bug where the images in the example would be loaded using `dart:io`
44
`HttpClient`.
5+
* `CupertinoClient` throws an exception if `send` is called after `close`.
56

67
## 0.0.10
78

pkgs/cupertino_http/lib/cupertino_client.dart

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ class _TaskTracker {
5252
class CupertinoClient extends BaseClient {
5353
static final Map<URLSessionTask, _TaskTracker> _tasks = {};
5454

55-
URLSession _urlSession;
55+
URLSession? _urlSession;
5656

57-
CupertinoClient._(this._urlSession);
57+
CupertinoClient._(URLSession urlSession) : _urlSession = urlSession;
5858

5959
String? _findReasonPhrase(int statusCode) {
6060
switch (statusCode) {
@@ -205,6 +205,11 @@ class CupertinoClient extends BaseClient {
205205
return CupertinoClient._(session);
206206
}
207207

208+
@override
209+
void close() {
210+
_urlSession = null;
211+
}
212+
208213
@override
209214
Future<StreamedResponse> send(BaseRequest request) async {
210215
// The expected sucess case flow (without redirects) is:
@@ -219,6 +224,12 @@ class CupertinoClient extends BaseClient {
219224
// StreamController that controls the Stream<UInt8List>
220225
// 7. _onComplete is called after all the data is read and closes the
221226
// StreamController
227+
if (_urlSession == null) {
228+
throw ClientException(
229+
'HTTP request failed. Client is already closed.', request.url);
230+
}
231+
final urlSession = _urlSession!;
232+
222233
final stream = request.finalize();
223234

224235
final bytes = await stream.toBytes();
@@ -231,7 +242,7 @@ class CupertinoClient extends BaseClient {
231242
// This will preserve Apple default headers - is that what we want?
232243
request.headers.forEach(urlRequest.setValueForHttpHeaderField);
233244

234-
final task = _urlSession.dataTaskWithRequest(urlRequest);
245+
final task = urlSession.dataTaskWithRequest(urlRequest);
235246
final taskTracker = _TaskTracker(request);
236247
_tasks[task] = taskTracker;
237248
task.resume();

pkgs/cupertino_http/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: cupertino_http
22
description: >
33
A macOS/iOS Flutter plugin that provides access to the Foundation URL
44
Loading System.
5-
version: 0.0.10
5+
version: 0.0.11
66
repository: https://github.com/dart-lang/http/tree/master/pkgs/cupertino_http
77

88
environment:

pkgs/http/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## 0.13.6-dev
22

3+
* `BrowserClient` throws an exception if `send` is called after `close`.
4+
35
## 0.13.5
46

57
* Allow async callbacks in RetryClient.

pkgs/http/lib/src/browser_client.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,15 @@ class BrowserClient extends BaseClient {
3737
/// Defaults to `false`.
3838
bool withCredentials = false;
3939

40+
bool _isClosed = false;
41+
4042
/// Sends an HTTP request and asynchronously returns the response.
4143
@override
4244
Future<StreamedResponse> send(BaseRequest request) async {
45+
if (_isClosed) {
46+
throw ClientException(
47+
'HTTP request failed. Client is already closed.', request.url);
48+
}
4349
var bytes = await request.finalize().toBytes();
4450
var xhr = HttpRequest();
4551
_xhrs.add(xhr);
@@ -83,8 +89,10 @@ class BrowserClient extends BaseClient {
8389
/// This terminates all active requests.
8490
@override
8591
void close() {
92+
_isClosed = true;
8693
for (var xhr in _xhrs) {
8794
xhr.abort();
8895
}
96+
_xhrs.clear();
8997
}
9098
}

pkgs/http/lib/src/client.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ abstract class Client {
145145
///
146146
/// It's important to close each client when it's done being used; failing to
147147
/// do so can cause the Dart process to hang.
148+
///
149+
/// Once [close] is called, no other methods should be called. If [close] is
150+
/// called while other asynchronous methods are running, the behavior is
151+
/// undefined.
148152
void close();
149153
}
150154

0 commit comments

Comments
 (0)