diff --git a/CHANGELOG.md b/CHANGELOG.md index 98ab0856b..6bce44092 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Columns in the HTML Outbounds table on the debug page now properly line up with header rows. +### Changed +- Allow multiple values for the header `grpc-accept-encoding`. Only one (random) value will be used anyway, + but no error will be returned. + ## [1.75.3] - 2024-12-04 ### Added - Noop resolver to use in clients with custom load balancing. diff --git a/transport/grpc/headers.go b/transport/grpc/headers.go index 95e8d2713..92c65a81c 100644 --- a/transport/grpc/headers.go +++ b/transport/grpc/headers.go @@ -86,6 +86,11 @@ const ( baseContentType = "application/grpc" contentTypeHeader = "content-type" + + // grpcAcceptEncodingHeader is the header name that keeps the list of available compressors, + // applicable for both request and response headers. Usually consumed by grpc, but the + // value is kept in metadata and available in application code. + grpcAcceptEncodingHeader = "grpc-accept-encoding" ) // TODO: there are way too many repeat calls to strings.ToLower @@ -128,7 +133,12 @@ func metadataToTransportRequest(md metadata.MD) (*transport.Request, error) { case 1: value = values[0] default: - return nil, yarpcerrors.InvalidArgumentErrorf("header has more than one value: %s:%v", header, values) + // TODO (https://github.com/yarpc/yarpc-go/issues/2265) don't pass this values to application code + if header == grpcAcceptEncodingHeader { + value = values[0] + } else { + return nil, yarpcerrors.InvalidArgumentErrorf("header has more than one value: %s:%v", header, values) + } } header = transport.CanonicalizeHeaderKey(header) switch header { @@ -213,7 +223,12 @@ func getApplicationHeaders(md metadata.MD) (transport.Headers, error) { case 1: value = values[0] default: - return headers, yarpcerrors.InvalidArgumentErrorf("header has more than one value: %s:%v", header, values) + // TODO (https://github.com/yarpc/yarpc-go/issues/2265) don't pass this values to application code + if header == grpcAcceptEncodingHeader { + value = values[0] + } else { + return headers, yarpcerrors.InvalidArgumentErrorf("header has more than one value: %s:%v", header, values) + } } headers = headers.With(header, value) } diff --git a/transport/grpc/headers_test.go b/transport/grpc/headers_test.go index b23c7eab3..d9949dba6 100644 --- a/transport/grpc/headers_test.go +++ b/transport/grpc/headers_test.go @@ -116,6 +116,22 @@ func TestMetadataToTransportRequest(t *testing.T) { }), }, }, + { + Name: "Double grpc-accept-encoding value", + MD: metadata.Pairs( + grpcAcceptEncodingHeader, "gzip", + grpcAcceptEncodingHeader, "zlib", + "foo", "bar", + "baz", "bat", + ), + TransportRequest: &transport.Request{ + Headers: transport.HeadersFromMap(map[string]string{ + "foo": "bar", + "baz": "bat", + "grpc-accept-encoding": "gzip", + }), + }, + }, } for _, tt := range tests { t.Run(tt.Name, func(t *testing.T) { @@ -253,6 +269,19 @@ func TestGetApplicationHeaders(t *testing.T) { }, wantErr: "header has more than one value: test-header-dup:[test-value-1 test-value-2]", }, + { + msg: "Multiple value for grpc-accept-encoding header", + meta: metadata.MD{ + "test-header-valid-1": []string{"test-value-1"}, + "test-Header-Valid-2": []string{"test-value-2"}, + "grpc-accept-encoding": []string{"gzip", "zlib"}, + }, + wantHeaders: map[string]string{ + "test-header-valid-1": "test-value-1", + "test-header-valid-2": "test-value-2", + "grpc-accept-encoding": "gzip", + }, + }, } for _, tt := range tests {