Skip to content

Commit eafbbb0

Browse files
authored
Separate the cronet callbacks from the send method (dart-lang#1017)
1 parent 2cbb703 commit eafbbb0

File tree

1 file changed

+101
-100
lines changed

1 file changed

+101
-100
lines changed

pkgs/cronet_http/lib/src/cronet_client.dart

+101-100
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,103 @@ Map<String, String> _cronetToClientHeaders(
135135
key.toDartString(releaseOriginal: true).toLowerCase(),
136136
value.join(',')));
137137

138+
jb.UrlRequestCallbackProxy_UrlRequestCallbackInterface _urlRequestCallbacks(
139+
BaseRequest request, Completer<StreamedResponse> responseCompleter) {
140+
StreamController<List<int>>? responseStream;
141+
jb.ByteBuffer? byteBuffer;
142+
var numRedirects = 0;
143+
144+
// The order of callbacks generated by Cronet is documented here:
145+
// https://developer.android.com/guide/topics/connectivity/cronet/lifecycle
146+
return jb.UrlRequestCallbackProxy_UrlRequestCallbackInterface.implement(
147+
jb.$UrlRequestCallbackProxy_UrlRequestCallbackInterfaceImpl(
148+
onResponseStarted: (urlRequest, responseInfo) {
149+
responseStream = StreamController();
150+
final responseHeaders =
151+
_cronetToClientHeaders(responseInfo.getAllHeaders());
152+
int? contentLength;
153+
154+
switch (responseHeaders['content-length']) {
155+
case final contentLengthHeader?
156+
when !_digitRegex.hasMatch(contentLengthHeader):
157+
responseCompleter.completeError(ClientException(
158+
'Invalid content-length header [$contentLengthHeader].',
159+
request.url,
160+
));
161+
urlRequest.cancel();
162+
return;
163+
case final contentLengthHeader?:
164+
contentLength = int.parse(contentLengthHeader);
165+
}
166+
responseCompleter.complete(StreamedResponse(
167+
responseStream!.stream,
168+
responseInfo.getHttpStatusCode(),
169+
contentLength: contentLength,
170+
reasonPhrase: responseInfo
171+
.getHttpStatusText()
172+
.toDartString(releaseOriginal: true),
173+
request: request,
174+
isRedirect: false,
175+
headers: responseHeaders,
176+
));
177+
178+
byteBuffer = jb.ByteBuffer.allocateDirect(1024 * 1024);
179+
urlRequest.read(byteBuffer!);
180+
},
181+
onRedirectReceived: (urlRequest, responseInfo, newLocationUrl) {
182+
if (!request.followRedirects) {
183+
urlRequest.cancel();
184+
responseCompleter.complete(StreamedResponse(
185+
const Stream.empty(), // Cronet provides no body for redirects.
186+
responseInfo.getHttpStatusCode(),
187+
contentLength: 0,
188+
reasonPhrase: responseInfo
189+
.getHttpStatusText()
190+
.toDartString(releaseOriginal: true),
191+
request: request,
192+
isRedirect: true,
193+
headers: _cronetToClientHeaders(responseInfo.getAllHeaders())));
194+
return;
195+
}
196+
++numRedirects;
197+
if (numRedirects <= request.maxRedirects) {
198+
urlRequest.followRedirect();
199+
} else {
200+
urlRequest.cancel();
201+
responseCompleter.completeError(
202+
ClientException('Redirect limit exceeded', request.url));
203+
}
204+
},
205+
onReadCompleted: (urlRequest, responseInfo, byteBuffer) {
206+
byteBuffer.flip();
207+
208+
final remaining = byteBuffer.remaining();
209+
final data = Uint8List(remaining);
210+
// TODO: Use a more efficient approach when
211+
// https://github.com/dart-lang/jnigen/issues/387 is fixed.
212+
for (var i = 0; i < remaining; ++i) {
213+
data[i] = byteBuffer.get1(i);
214+
}
215+
responseStream!.add(data);
216+
byteBuffer.clear();
217+
urlRequest.read(byteBuffer);
218+
},
219+
onSucceeded: (urlRequest, responseInfo) {
220+
responseStream!.sink.close();
221+
},
222+
onFailed: (urlRequest, responseInfo, cronetException) {
223+
final error = ClientException(
224+
'Cronet exception: ${cronetException.toString()}', request.url);
225+
if (responseStream == null) {
226+
responseCompleter.completeError(error);
227+
} else {
228+
responseStream!.addError(error);
229+
responseStream!.close();
230+
}
231+
},
232+
));
233+
}
234+
138235
/// A HTTP [Client] based on the
139236
/// [Cronet](https://developer.android.com/guide/topics/connectivity/cronet)
140237
/// network stack.
@@ -219,106 +316,10 @@ class CronetClient extends BaseClient {
219316
final responseCompleter = Completer<StreamedResponse>();
220317
final engine = _engine!._engine;
221318

222-
late jb.UrlRequest cronetRequest;
223-
var numRedirects = 0;
224-
StreamController<List<int>>? responseStream;
225-
jb.ByteBuffer? byteBuffer;
226-
227-
// The order of callbacks generated by Cronet is documented here:
228-
// https://developer.android.com/guide/topics/connectivity/cronet/lifecycle
229-
230-
final cronetCallbacks =
231-
jb.UrlRequestCallbackProxy_UrlRequestCallbackInterface.implement(
232-
jb.$UrlRequestCallbackProxy_UrlRequestCallbackInterfaceImpl(
233-
onResponseStarted: (urlRequest, responseInfo) {
234-
responseStream = StreamController();
235-
final responseHeaders =
236-
_cronetToClientHeaders(responseInfo.getAllHeaders());
237-
int? contentLength;
238-
239-
switch (responseHeaders['content-length']) {
240-
case final contentLengthHeader?
241-
when !_digitRegex.hasMatch(contentLengthHeader):
242-
responseCompleter.completeError(ClientException(
243-
'Invalid content-length header [$contentLengthHeader].',
244-
request.url,
245-
));
246-
urlRequest.cancel();
247-
return;
248-
case final contentLengthHeader?:
249-
contentLength = int.parse(contentLengthHeader);
250-
}
251-
responseCompleter.complete(StreamedResponse(
252-
responseStream!.stream,
253-
responseInfo.getHttpStatusCode(),
254-
contentLength: contentLength,
255-
reasonPhrase: responseInfo
256-
.getHttpStatusText()
257-
.toDartString(releaseOriginal: true),
258-
request: request,
259-
isRedirect: false,
260-
headers: responseHeaders,
261-
));
262-
263-
byteBuffer = jb.ByteBuffer.allocateDirect(1024 * 1024);
264-
urlRequest.read(byteBuffer!);
265-
},
266-
onRedirectReceived: (urlRequest, responseInfo, newLocationUrl) {
267-
if (!request.followRedirects) {
268-
cronetRequest.cancel();
269-
responseCompleter.complete(StreamedResponse(
270-
const Stream.empty(), // Cronet provides no body for redirects.
271-
responseInfo.getHttpStatusCode(),
272-
contentLength: 0,
273-
reasonPhrase: responseInfo
274-
.getHttpStatusText()
275-
.toDartString(releaseOriginal: true),
276-
request: request,
277-
isRedirect: true,
278-
headers: _cronetToClientHeaders(responseInfo.getAllHeaders())));
279-
return;
280-
}
281-
++numRedirects;
282-
if (numRedirects <= request.maxRedirects) {
283-
cronetRequest.followRedirect();
284-
} else {
285-
cronetRequest.cancel();
286-
responseCompleter.completeError(
287-
ClientException('Redirect limit exceeded', request.url));
288-
}
289-
},
290-
onReadCompleted: (urlRequest, responseInfo, byteBuffer) {
291-
byteBuffer.flip();
292-
293-
final remaining = byteBuffer.remaining();
294-
final data = Uint8List(remaining);
295-
// TODO: Use a more efficient approach when
296-
// https://github.com/dart-lang/jnigen/issues/387 is fixed.
297-
for (var i = 0; i < remaining; ++i) {
298-
data[i] = byteBuffer.get1(i);
299-
}
300-
responseStream!.add(data);
301-
byteBuffer.clear();
302-
cronetRequest.read(byteBuffer);
303-
},
304-
onSucceeded: (urlRequest, responseInfo) {
305-
responseStream!.sink.close();
306-
},
307-
onFailed: (urlRequest, responseInfo, cronetException) {
308-
final error = ClientException(
309-
'Cronet exception: ${cronetException.toString()}', request.url);
310-
if (responseStream == null) {
311-
responseCompleter.completeError(error);
312-
} else {
313-
responseStream!.addError(error);
314-
responseStream!.close();
315-
}
316-
},
317-
));
318-
319319
final builder = engine.newUrlRequestBuilder(
320320
request.url.toString().toJString(),
321-
jb.UrlRequestCallbackProxy.new1(cronetCallbacks),
321+
jb.UrlRequestCallbackProxy.new1(
322+
_urlRequestCallbacks(request, responseCompleter)),
322323
_executor,
323324
);
324325

@@ -341,7 +342,7 @@ class CronetClient extends BaseClient {
341342
builder.setUploadDataProvider(
342343
jb.UploadDataProviders.create4(bodyBytes), _executor);
343344
}
344-
cronetRequest = builder.build()..start();
345-
return responseCompleter.future.whenComplete(() => byteBuffer?.release());
345+
builder.build().start();
346+
return responseCompleter.future;
346347
}
347348
}

0 commit comments

Comments
 (0)