Grpc-web Handle empty trailers (#247)

* Grpc-web Handle empty trailers
This commit is contained in:
Sigurd Meldgaard 2019-11-07 10:52:13 +01:00 committed by GitHub
parent fd92060ad0
commit 6061512afa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 1 deletions

View File

@ -1,5 +1,6 @@
## 2.1.3
* Fix bug in grpc-web when receiving an empty trailer.
* Fix a state bug in the server.
## 2.1.2

View File

@ -118,7 +118,8 @@ class _GrpcWebConversionSink extends ChunkedConversionSink<ByteBuffer> {
}
Map<String, String> _parseHttp1Headers(String stringData) {
final chunks = stringData.trim().split('\r\n');
final trimmed = stringData.trim();
final chunks = trimmed == '' ? [] : trimmed.split('\r\n');
final headers = <String, String>{};
for (final chunk in chunks) {
final pos = chunk.indexOf(':');

View File

@ -121,6 +121,68 @@ void main() {
});
});
test('Stream handles trailers properly', () async {
final trailers = <String, String>{
'trailer_1': 'value_1',
'trailer_2': 'value_2'
};
final connection = MockXhrClientConnection();
final stream = connection.makeRequest('test_path', Duration(seconds: 10),
{}, (error) => fail(error.toString()));
final encodedTrailers = frame(trailers.entries
.map((e) => '${e.key}:${e.value}')
.join('\r\n')
.codeUnits);
encodedTrailers[0] = 0x80; // Mark this frame as trailers.
final encodedString = String.fromCharCodes(encodedTrailers);
stream.incomingMessages.listen((message) {
expect(message, TypeMatcher<GrpcMetadata>());
if (message is GrpcMetadata) {
message.metadata.forEach((key, value) {
expect(value, trailers[key]);
});
}
});
when(connection.latestRequest.getResponseHeader('Content-Type'))
.thenReturn('application/grpc+proto');
when(connection.latestRequest.responseHeaders).thenReturn({});
when(connection.latestRequest.readyState)
.thenReturn(HttpRequest.HEADERS_RECEIVED);
when(connection.latestRequest.response).thenReturn(encodedString);
connection.latestRequest.readyStateChangeController.add(null);
connection.latestRequest.progressController.add(null);
});
test('Stream handles empty trailers properly', () async {
final connection = MockXhrClientConnection();
final stream = connection.makeRequest('test_path', Duration(seconds: 10),
{}, (error) => fail(error.toString()));
final encoded = frame(''.codeUnits);
encoded[0] = 0x80; // Mark this frame as trailers.
final encodedString = String.fromCharCodes(encoded);
stream.incomingMessages.listen((message) {
expect(message, TypeMatcher<GrpcMetadata>());
if (message is GrpcMetadata) {
message.metadata.isEmpty;
}
});
when(connection.latestRequest.getResponseHeader('Content-Type'))
.thenReturn('application/grpc+proto');
when(connection.latestRequest.responseHeaders).thenReturn({});
when(connection.latestRequest.readyState)
.thenReturn(HttpRequest.HEADERS_RECEIVED);
when(connection.latestRequest.response).thenReturn(encodedString);
connection.latestRequest.readyStateChangeController.add(null);
connection.latestRequest.progressController.add(null);
});
test('Stream deserializes data properly', () async {
final metadata = <String, String>{
'parameter_1': 'value_1',