diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index c80305bd..b56c8d07 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - sdk: [3.2.0, dev] + sdk: [3.4.0, dev] steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 @@ -60,7 +60,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - sdk: [3.2.0, dev] + sdk: [3.4.0, dev] platform: [vm, chrome] exclude: # We only run Chrome tests on Linux. No need to run them diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f463fb5..57aae486 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Small fixes, such as ports in testing and enabling `timeline_test.dart`. * When the keep alive manager runs into a timeout, it will finish the transport instead of closing the connection, as defined in the gRPC spec. +* Update xhr transport to migrate off legacy JS/HTML apis. ## 4.0.1 diff --git a/lib/grpc_or_grpcweb.dart b/lib/grpc_or_grpcweb.dart index b23bed5d..049ceabf 100644 --- a/lib/grpc_or_grpcweb.dart +++ b/lib/grpc_or_grpcweb.dart @@ -14,7 +14,7 @@ // limitations under the License. import 'src/client/grpc_or_grpcweb_channel_grpc.dart' - if (dart.library.html) 'src/client/grpc_or_grpcweb_channel_web.dart'; + if (dart.library.js_interop) 'src/client/grpc_or_grpcweb_channel_web.dart'; import 'src/client/http2_channel.dart'; import 'src/client/options.dart'; diff --git a/lib/src/client/transport/xhr_transport.dart b/lib/src/client/transport/xhr_transport.dart index 16b0dca5..e41a7f39 100644 --- a/lib/src/client/transport/xhr_transport.dart +++ b/lib/src/client/transport/xhr_transport.dart @@ -14,10 +14,11 @@ // limitations under the License. import 'dart:async'; -import 'dart:html'; +import 'dart:js_interop'; import 'dart:typed_data'; import 'package:meta/meta.dart'; +import 'package:web/web.dart'; import '../../client/call.dart'; import '../../shared/message.dart'; @@ -30,7 +31,7 @@ import 'web_streams.dart'; const _contentTypeKey = 'Content-Type'; class XhrTransportStream implements GrpcTransportStream { - final HttpRequest _request; + final XMLHttpRequest _request; final ErrorHandler _onError; final Function(XhrTransportStream stream) _onDone; bool _headersReceived = false; @@ -49,19 +50,20 @@ class XhrTransportStream implements GrpcTransportStream { {required ErrorHandler onError, required onDone}) : _onError = onError, _onDone = onDone { - _outgoingMessages.stream - .map(frame) - .listen((data) => _request.send(data), cancelOnError: true); + _outgoingMessages.stream.map(frame).listen( + (data) => _request.send(Int8List.fromList(data).toJS), + cancelOnError: true, + onError: _onError); - _request.onReadyStateChange.listen((data) { + _request.onReadyStateChange.listen((_) { if (_incomingProcessor.isClosed) { return; } switch (_request.readyState) { - case HttpRequest.HEADERS_RECEIVED: + case XMLHttpRequest.HEADERS_RECEIVED: _onHeadersReceived(); break; - case HttpRequest.DONE: + case XMLHttpRequest.DONE: _onRequestDone(); _close(); break; @@ -81,13 +83,11 @@ class XhrTransportStream implements GrpcTransportStream { if (_incomingProcessor.isClosed) { return; } - // Use response over responseText as most browsers don't support - // using responseText during an onProgress event. - final responseString = _request.response as String; + final responseText = _request.responseText; final bytes = Uint8List.fromList( - responseString.substring(_requestBytesRead).codeUnits) + responseText.substring(_requestBytesRead).codeUnits) .buffer; - _requestBytesRead = responseString.length; + _requestBytesRead = responseText.length; _incomingProcessor.add(bytes); }); @@ -122,9 +122,11 @@ class XhrTransportStream implements GrpcTransportStream { if (!_headersReceived && !_validateResponseState()) { return; } - if (_request.response == null) { + if (_request.status != 200) { _onError( - GrpcError.unavailable('XhrConnection request null response', null, + GrpcError.unavailable( + 'Request failed with status: ${_request.status}', + null, _request.responseText), StackTrace.current); return; @@ -153,20 +155,22 @@ class XhrClientConnection implements ClientConnection { @override String get authority => uri.authority; + @override String get scheme => uri.scheme; - void _initializeRequest(HttpRequest request, Map metadata) { - for (final header in metadata.keys) { - request.setRequestHeader(header, metadata[header]!); - } + void _initializeRequest( + XMLHttpRequest request, Map metadata) { + metadata.forEach((key, value) { + request.setRequestHeader(key, value); + }); // Overriding the mimetype allows us to stream and parse the data request.overrideMimeType('text/plain; charset=x-user-defined'); request.responseType = 'text'; } @visibleForTesting - HttpRequest createHttpRequest() => HttpRequest(); + XMLHttpRequest createHttpRequest() => XMLHttpRequest(); @override GrpcTransportStream makeRequest(String path, Duration? timeout, diff --git a/pubspec.yaml b/pubspec.yaml index e89e71ae..ae05bbcc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ version: 4.0.2-wip repository: https://github.com/grpc/grpc-dart environment: - sdk: ^3.2.0 + sdk: ^3.4.0 dependencies: async: ^2.5.0 @@ -17,6 +17,7 @@ dependencies: http2: ^2.2.0 protobuf: '>=2.0.0 <4.0.0' clock: ^1.1.1 + web: ^1.1.0 dev_dependencies: build_runner: ^2.0.0