Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update: Migrate off legacy JS/HTML apis #730

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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';
minoic marked this conversation as resolved.
Show resolved Hide resolved
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:
minoic marked this conversation as resolved.
Show resolved Hide resolved
_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));
minoic marked this conversation as resolved.
Show resolved Hide resolved
_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
minoic marked this conversation as resolved.
Show resolved Hide resolved
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
Loading