grpc-dart
grpc-dart copied to clipboard
Help: Invalid frame type: 1
Error: gRPC Error (code: 12, codeName: UNIMPLEMENTED, message: Invalid frame type: 1, details: null, rawResponse: null)
at Object.throw_ [as throw] (http://localhost:40069/dart_sdk.js:5062:11)
at web_streams._GrpcWebConversionSink.new.[_parseFrameType] (http://localhost:40069/packages/grpc/src/client/transport/web_streams.dart.lib.js:136:19)
at web_streams._GrpcWebConversionSink.new.add (http://localhost:40069/packages/grpc/src/client/transport/web_streams.dart.lib.js:209:53)
at _ConverterStreamEventSink.new.add (http://localhost:40069/dart_sdk.js:45045:29)
at _SinkTransformerStreamSubscription.new.[_handleData] (http://localhost:40069/dart_sdk.js:36146:34)
at _RootZone.runUnaryGuarded (http://localhost:40069/dart_sdk.js:37595:11)
at _ControllerSubscription.new.[_sendData] (http://localhost:40069/dart_sdk.js:31475:22)
at _DelayedData.new.perform (http://localhost:40069/dart_sdk.js:34780:28)
at _StreamImplEvents.new.handleNext (http://localhost:40069/dart_sdk.js:34884:15)
at async._AsyncCallbackEntry.new.callback (http://localhost:40069/dart_sdk.js:34645:16)
at Object._microtaskLoop (http://localhost:40069/dart_sdk.js:37925:13)
at _startMicrotaskLoop (http://localhost:40069/dart_sdk.js:37931:13)
at http://localhost:40069/dart_sdk.js:33666:9
grpc: dependency: "direct main" description: name: grpc url: "https://pub.dartlang.org" source: hosted version: "3.0.0"
Repro steps
https://github.com/MateusAmin/grpc-dart-issues-506
- Goto messages and run ./grpc.sh
- Goto server and run ./run-server.sh and ./run-envoy.sh
- Goto client and run flutter run -d chrome
Expected result: gRPC unary call completes without expectation
Actual result: gRPC unary call completes successfully server side but client throws expectation parsing response (an empty message object).
Details
enovy config:
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
codec_type: auto
access_log:
- name: envoy.access_loggers.file
config:
path: "/dev/stdout"
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: greeter_service
max_grpc_timeout: 0s
cors:
allow_origin_string_match:
- prefix: "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
max_age: "1728000"
expose_headers: custom-header-1,grpc-status,grpc-message
http_filters:
- name: envoy.filters.http.grpc_web
- name: envoy.filters.http.cors
- name: envoy.filters.http.router
clusters:
- name: greeter_service
connect_timeout: 0.25s
type: logical_dns
http2_protocol_options: {}
lb_policy: round_robin
# win/mac hosts: Use address: host.docker.internal instead of address: localhost in the line below
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 0.0.0.0
port_value: 50051
envy boot:
#! /bin/sh
sudo docker run -it -v "$(pwd)"/envoy.yaml:/etc/envoy/envoy.yaml:ro \
--network=host envoyproxy/envoy:v1.15.0 --use-dynamic-base-id --config-path '/etc/envoy/envoy.yaml'
dart grpc server:
#! /bin/sh
shellcheck ./*.sh
cd ../messages || exit
./../messages/grpc.sh
cd - || exit
dart bin/server.dart
message script
#! /bin/sh
shellcheck ./*.sh
# mac os specific
# brew install protobuf
dart pub global activate protoc_plugin
export PATH="$PATH:$HOME/.pub-cache/bin"
protoc --dart_out=grpc:lib/src/generated -Iprotos protos/messages.proto
https://github.com/grpc/grpc-dart/blob/c982597faea6079712182b663779bf3098d25578/lib/src/client/transport/web_streams.dart#L61
Updated envoy to latest 17 and matched grpc-web echo example config. Updated to dart grpc master. Same error.
HAR: localhost.zip
HAR without _initiator:
{
"log": {
"version": "1.2",
"creator": {
"name": "WebInspector",
"version": "537.36"
},
"pages": [],
"entries": [
{
"_initiator": {},
"_priority": "High",
"_resourceType": "xhr",
"cache": {},
"connection": "150085",
"request": {
"method": "POST",
"url": "http://localhost:8080/messages.Greeter/ResetPassword",
"httpVersion": "HTTP/1.1",
"headers": [
{
"name": "Host",
"value": "localhost:8080"
},
{
"name": "Connection",
"value": "keep-alive"
},
{
"name": "Content-Length",
"value": "28"
},
{
"name": "sec-ch-ua",
"value": "\" Not;A Brand\";v=\"99\", \"Google Chrome\";v=\"91\", \"Chromium\";v=\"91\""
},
{
"name": "X-User-Agent",
"value": "grpc-web-dart/0.1"
},
{
"name": "X-Grpc-Web",
"value": "1"
},
{
"name": "sec-ch-ua-mobile",
"value": "?0"
},
{
"name": "User-Agent",
"value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36"
},
{
"name": "Content-Type",
"value": "application/grpc-web+proto"
},
{
"name": "Accept",
"value": "*/*"
},
{
"name": "Origin",
"value": "http://localhost:34893"
},
{
"name": "Sec-Fetch-Site",
"value": "same-site"
},
{
"name": "Sec-Fetch-Mode",
"value": "cors"
},
{
"name": "Sec-Fetch-Dest",
"value": "empty"
},
{
"name": "Referer",
"value": "http://localhost:34893/"
},
{
"name": "Accept-Encoding",
"value": "gzip, deflate, br"
},
{
"name": "Accept-Language",
"value": "en-US,en;q=0.9"
}
],
"queryString": [],
"cookies": [],
"headersSize": 641,
"bodySize": 28,
"postData": {
"mimeType": "application/grpc-web+proto",
"text": "\u0000\u0000\u0000\u0000\u0017\n\[email protected]"
}
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "HTTP/1.1",
"headers": [
{
"name": "content-type",
"value": "application/grpc-web+proto"
},
{
"name": "grpc-encoding",
"value": "identity"
},
{
"name": "x-envoy-upstream-service-time",
"value": "1223"
},
{
"name": "access-control-allow-origin",
"value": "http://localhost:34893"
},
{
"name": "access-control-expose-headers",
"value": "custom-header-1,grpc-status,grpc-message"
},
{
"name": "date",
"value": "Sun, 18 Jul 2021 12:54:58 GMT"
},
{
"name": "server",
"value": "envoy"
},
{
"name": "transfer-encoding",
"value": "chunked"
}
],
"cookies": [],
"content": {
"size": 27,
"mimeType": "application/grpc-web+proto",
"compression": -16,
"text": "AQAAAAIIAYAAAAAPZ3JwYy1zdGF0dXM6MA0K",
"encoding": "base64"
},
"redirectURL": "",
"headersSize": 329,
"bodySize": 43,
"_transferSize": 372,
"_error": null
},
"serverIPAddress": "127.0.0.1",
"startedDateTime": "2021-07-18T12:54:57.572Z",
"time": 1226.0509999947772,
"timings": {
"blocked": 0.6939999983739108,
"dns": 0.00899999999999998,
"ssl": -1,
"connect": 0.235,
"send": 0.08400000000000002,
"wait": 1223.828999997614,
"receive": 1.1999999987892807,
"_blocked_queueing": 0.5539999983739108
}
}
]
}
}
So, I am looking at: https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md
I can see that it should be:
- 10000000b - trailers without compression
- 10000001b - trailers with compression
- 00000000b - data
with the most significant bit last
Added minimal example to replicate. Only need docker, dart, and flutter. 3 steps:
https://github.com/MateusAmin/grpc-dart-issues-506
Looks like I "fixed" the issue by removing the indentity codec from the server constructor.
final server = Server(
[GreeterService()],
const <Interceptor>[],
CodecRegistry(codecs: const [GzipCodec(), IdentityCodec()]),
);
final server = Server(
[GreeterService()],
const <Interceptor>[],
CodecRegistry(codecs: const [GzipCodec(),]),
);
https://grpc.github.io/grpc/core/md_doc_compression.html
I take it the GzipCodec() + IdentityCodec() purpose is to be used to prevent CRIME/BEAST attacks?
@MateusAmin I have the same problem. A very ugly workaround is to change https://github.com/grpc/grpc-dart/blob/master/lib/src/client/transport/web_streams.dart#L57:L65
int _parseFrameType(List<int> chunkData) {
final frameType = chunkData[_chunkOffset];
_chunkOffset++;
const frameTypeDataWebWorkaround = 0x01;
if (frameType != frameTypeData &&
frameType != frameTypeTrailers &&
frameType != frameTypeDataWebWorkaround) {
throw GrpcError.unimplemented('Invalid frame type: ${frameType}');
}
_state = _GrpcWebParseState.Length;
if (frameType == frameTypeDataWebWorkaround) {
return frameTypeData;
}
return frameType;
}
Looks like I "fixed" the issue by removing the indentity codec from the server constructor.
final server = Server( [GreeterService()], const <Interceptor>[], CodecRegistry(codecs: const [GzipCodec(), IdentityCodec()]), );
final server = Server( [GreeterService()], const <Interceptor>[], CodecRegistry(codecs: const [GzipCodec(),]), );
This solution works for me.