gRPC HTTP/1.1 bridge does not perform protobuf upgrading on empty payloads
#21,312 opened on May 16, 2022
Repository metrics
- Stars
- (27,997 stars)
- PR merge metrics
- (Avg merge 8d) (378 merged PRs in 30d)
Description
Title: gRPC HTTP/1.1 bridge does not perform protobuf upgrading on empty payloads
Description:
When sending an empty body over HTTP to an envoy instance configured with to perform protobuf upgrading the filter seems to be bypassed. The result is requests with content-type application/x-protobuf would not forwarded to desired gRPC cluster.
With the configuration I'm using this results in a 504 Gateway Timeout after the configured timeout expires, but the exact effects would depend on how exactly the routes and clusters are set-up.
ps: it seems like this only happens with empty payloads, if they have at least one byte it seems to work fine.
Repro steps:
I could reproduce it by running examples/grpc-bridge/server/service.go and an envoy instance with the configuration attached. I've encoded a few demo payloads to demonstrate the problem when calling POST /kv.KV/Set, but the problem should be reproducible with any endpoint.
generating payloads:
cd examples/grpc-bridge
# generate a payload with non-empty values
echo 'key: "foo", value: "bar"' | protoc --encode 'kv.SetRequest' -I./protos ./protos/kv.proto > set.protobuf.bin
# generate a payload with fields set to de default values (equivalent to empty payload in protobuf 3)
echo 'key: "", value: ""' | protoc --encode 'kv.SetRequest' -I./protos ./protos/kv.proto > set_default.protobuf.bin
sending with curl:
$ curl -v -X POST -H 'Content-Type: application/x-protobuf' --data-binary '@set.protobuf.bin' http://localhost:8090/kv.KV/Set
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying 127.0.0.1:8090...
* Connected to localhost (127.0.0.1) port 8090 (#0)
> POST /kv.KV/Set HTTP/1.1
> Host: localhost:8090
> User-Agent: curl/7.83.1
> Accept: */*
> Content-Type: application/x-protobuf
> Content-Length: 10
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< content-type: application/grpc
< x-envoy-upstream-service-time: 0
< grpc-status: 0
< grpc-message:
< content-length: 2
< date: Mon, 16 May 2022 15:24:58 GMT
< server: envoy
<
* Connection #0 to host localhost left intact
$ curl -v -X POST -H 'Content-Type: application/x-protobuf' --data-binary '@set_default.protobuf.bin' http://localhost:8090/kv.KV/Set
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying 127.0.0.1:8090...
* Connected to localhost (127.0.0.1) port 8090 (#0)
> POST /kv.KV/Set HTTP/1.1
> Host: localhost:8090
> User-Agent: curl/7.83.1
> Accept: */*
> Content-Type: application/x-protobuf
> Content-Length: 0
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 504 Gateway Timeout
< content-length: 24
< content-type: text/plain
< date: Mon, 16 May 2022 15:14:42 GMT
< server: envoy
<
* Connection #0 to host localhost left intact
upstream request timeout
Config:
staticResources:
listeners:
- address:
socketAddress:
address: 0.0.0.0
portValue: 8090
filterChains:
- filters:
- name: envoy.filters.network.http_conection_manager
typedConfig:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
statPrefix: ingress_http
routeConfig:
name: local_route
virtualHosts:
- name: backend
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: grpc
timeout: 60s
httpFilters:
- name: envoy.filters.http.grpc_http1_bridge
typedConfig:
"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_http1_bridge.v3.Config
upgradeProtobufToGrpc: true
- name: envoy.filters.http.router
clusters:
- name: grpc
type: LOGICAL_DNS
connectTimeout: 1s
loadAssignment:
clusterName: grpc
endpoints:
- lbEndpoints:
- endpoint:
address:
socketAddress:
address: 0.0.0.0
portValue: 8081
healthChecks:
- timeout: 1s
interval: 1s
unhealthyThreshold: 5
healthyThreshold: 2
grpcHealthCheck: {}
noTrafficInterval: 1s
typedExtensionProtocolOptions:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicitHttpConfig:
http2ProtocolOptions: {}
admin:
address:
socketAddress:
address: 0.0.0.0
portValue: 9901