Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/dart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 4.0.1

* Update xhr transport to migrate off legacy JS/HTML apis.

## 4.0.0

* Set compressed flag correctly for grpc-encoding = identity. Fixes [#669](https://github.com/grpc/grpc-dart/issues/669) (https://github.com/grpc/grpc-dart/pull/693)
Expand Down
2 changes: 1 addition & 1 deletion lib/grpc_or_grpcweb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
63 changes: 41 additions & 22 deletions lib/src/client/transport/xhr_transport.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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;
Expand All @@ -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 2:
_onHeadersReceived();
break;
case HttpRequest.DONE:
case 4:
_onRequestDone();
_close();
break;
Expand All @@ -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);
});

Expand All @@ -101,7 +101,7 @@ class XhrTransportStream implements GrpcTransportStream {
bool _validateResponseState() {
try {
validateHttpStatusAndContentType(
_request.status, _request.responseHeaders,
_request.status, _parseHeaders(_request.getAllResponseHeaders()),
rawResponse: _request.responseText);
return true;
} catch (e, st) {
Expand All @@ -115,16 +115,19 @@ class XhrTransportStream implements GrpcTransportStream {
if (!_validateResponseState()) {
return;
}
_incomingMessages.add(GrpcMetadata(_request.responseHeaders));
_incomingMessages
.add(GrpcMetadata(_parseHeaders(_request.getAllResponseHeaders())));
}

void _onRequestDone() {
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;
Expand All @@ -137,6 +140,20 @@ class XhrTransportStream implements GrpcTransportStream {
_onDone(this);
}

Map<String, String> _parseHeaders(String rawHeaders) {
final headers = <String, String>{};
final lines = rawHeaders.split('\r\n');
for (var line in lines) {
final index = line.indexOf(': ');
if (index != -1) {
final key = line.substring(0, index);
final value = line.substring(index + 2);
headers[key] = value;
}
}
return headers;
}

@override
Future<void> terminate() async {
_close();
Expand All @@ -153,20 +170,22 @@ class XhrClientConnection implements ClientConnection {

@override
String get authority => uri.authority;

@override
String get scheme => uri.scheme;

void _initializeRequest(HttpRequest request, Map<String, String> metadata) {
for (final header in metadata.keys) {
request.setRequestHeader(header, metadata[header]!);
}
void _initializeRequest(
XMLHttpRequest request, Map<String, String> 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,
Expand Down
5 changes: 3 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
name: grpc
description: Dart implementation of gRPC, a high performance, open-source universal RPC framework.
version: 4.0.0
version: 4.0.1

repository: https://github.com/grpc/grpc-dart

environment:
sdk: ^3.2.0
sdk: ^3.4.0

dependencies:
async: ^2.5.0
Expand All @@ -17,6 +17,7 @@ dependencies:
http2: ^2.2.0
protobuf: '>=2.0.0 <4.0.0'
clock: ^1.1.1
web: ^1.0.0

dev_dependencies:
build_runner: ^2.0.0
Expand Down