Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion transport/grpc/headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ const (
// _applicationErrorDetailsHeader is the header for the the application error
// meta details string.
_applicationErrorDetailsHeader = "rpc-application-error-details"
// _routingRegionHeader is one of the cross-zone header for the region of the routing key.
_routingRegionHeader = "rpc-routing-region"
// _routingZoneHeader is one of the cross-zone header for the zone of the routing key.
_routingZoneHeader = "rpc-routing-zone"

// ApplicationErrorHeaderValue is the value that will be set for
// ApplicationErrorHeader is there was an application error.
Expand All @@ -88,12 +92,24 @@ const (
contentTypeHeader = "content-type"
)

var (
routingHeaders = map[string]bool{
_routingZoneHeader: true,
_routingRegionHeader: true,
}
)

// TODO: there are way too many repeat calls to strings.ToLower
// Note that these calls are done indirectly, primarily through
// transport.CanonicalizeHeaderKey

func isReserved(header string) bool {
return strings.HasPrefix(strings.ToLower(header), "rpc-")
header = transport.CanonicalizeHeaderKey(header)
// exempt routing headers from isReserved check
if routingHeaders[header] {
return false
}
return strings.HasPrefix(header, "rpc-")
}

// transportRequestToMetadata will populate all reserved and application headers
Expand Down Expand Up @@ -131,6 +147,10 @@ func metadataToTransportRequest(md metadata.MD) (*transport.Request, error) {
return nil, yarpcerrors.InvalidArgumentErrorf("header has more than one value: %s:%v", header, values)
}
header = transport.CanonicalizeHeaderKey(header)
// skip routing header
if routingHeaders[header] {
continue
}
switch header {
case CallerHeader:
request.Caller = value
Expand Down
17 changes: 16 additions & 1 deletion transport/grpc/headers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ func TestMetadataToTransportRequest(t *testing.T) {
CallerProcedureHeader, "example-caller-procedure",
"foo", "bar",
"baz", "bat",
_routingRegionHeader, "phx",
_routingZoneHeader, "phx98",
),
TransportRequest: &transport.Request{
Caller: "example-caller",
Expand Down Expand Up @@ -162,7 +164,7 @@ func TestTransportRequestToMetadata(t *testing.T) {
},
},
{
Name: "Reserved header key in application headers",
Name: "Reserved header key in application headers - caller headers",
MD: metadata.Pairs(),
TransportRequest: &transport.Request{
Headers: transport.HeadersFromMap(map[string]string{
Expand All @@ -171,6 +173,16 @@ func TestTransportRequestToMetadata(t *testing.T) {
},
Error: yarpcerrors.InvalidArgumentErrorf("cannot use reserved header in application headers: %s", CallerHeader),
},
{
Name: "Routing headers exempted",
MD: metadata.Pairs(
_routingZoneHeader, "example-zone"),
TransportRequest: &transport.Request{
Headers: transport.HeadersFromMap(map[string]string{
_routingZoneHeader: "example-zone",
}),
},
},
} {
t.Run(tt.Name, func(t *testing.T) {
md, err := transportRequestToMetadata(tt.TransportRequest)
Expand Down Expand Up @@ -203,6 +215,9 @@ func TestIsReserved(t *testing.T) {
assert.True(t, isReserved(RoutingDelegateHeader))
assert.True(t, isReserved(EncodingHeader))
assert.True(t, isReserved("rpc-foo"))
for header := range routingHeaders {
assert.False(t, isReserved(header))
}
}

func TestMDReadWriterDuplicateKey(t *testing.T) {
Expand Down