envoyproxy / envoyproxy/envoy

gRPC HTTP/1.1 bridge does not perform protobuf upgrading on empty payloads

Open
#21,312 4 comments 2 reactions 0 assignees View on GitHub
bug help wanted
Dominant language
C++
Stars
28.9k
Forks
5.6k
Avg merge
1d 20h
Merged PRs (30d)
437

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](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/grpc_http1_bridge_filter#protobuf-upgrade-support) 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*:

```console
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*:

```console
$ 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*:

```yaml
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
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.