grpc / grpc-web

gRPC for Web Clients
https://grpc.io
Apache License 2.0
8.45k stars 760 forks source link

Trailer metadata - repeated values only supported with "trailers-only" responses #1399

Open jhump opened 5 months ago

jhump commented 5 months ago

If a gRPC response sets multiple values for the same trailer key, split across multiple lines, all of the values are available (via the metadata property of the status) if the response arrives as a "trailers-only" response (meaning that the trailers are all encoded as HTTP headers and there is no body).

But if the trailer metadata arrives in the body, as the final special message in the stream, only the final value is made available, as if the others were never even present. Most likely, a simple map (key -> singular string value) is being used to process the final message, so later values are incorrectly overwriting earlier ones.

sampajano commented 3 months ago

@jhump Thanks for the report!

If a gRPC response sets multiple values for the same trailer key, split across multiple lines, all of the values are available (via the metadata property of the status) if the response arrives as a "trailers-only" response (meaning that the trailers are all encoded as HTTP headers and there is no body).

Thanks for pointing out! I'm not too familiar with the spec.. But my naive understanding is that trailer is like a map (or http header) in nature, so it might/should not support multiple values for the same key, or does it? Do you have a pointer to the spec if you don't mind?


In the above PR you've mentioned it might be a trivial fix? If you already exactly understand what the problem is, it might be easier for you to submit a PR in that case? 😃

akshayjshah commented 3 months ago

Headers and trailers behave the same, but neither has last-writer-wins semantics.

Recent versions of the HTTP specification call both headers and trailers "fields". In both headers and trailers, keys may be repeated. The effective value for a key is computed by combining the individual values. Section 5.2 of RFC 9110 addresses this directly:

For example, this section:

Example-Field: Foo, Bar
Example-Field: Baz

contains two field lines, both with the field name "Example-Field". The first field line has a field line value of "Foo, Bar", while the second field line value is "Baz". The field value for "Example-Field" is the list "Foo, Bar, Baz".

sampajano commented 3 months ago

@akshayjshah Thanks for explaining, Akshay! That makes total sense!


If a gRPC response sets multiple values for the same trailer key, split across multiple lines, all of the values are available (via the metadata property of the status) if the response arrives as a "trailers-only" response (meaning that the trailers are all encoded as HTTP headers and there is no body).

But if the trailer metadata arrives in the body, as the final special message in the stream, only the final value is made available, as if the others were never even present. Most likely, a simple map (key -> singular string value) is being used to process the final message, so later values are incorrectly overwriting earlier ones.

@jhump By any chance you can provide some quick server code example to showcase the difference between these 2 scenarios?

Or maybe it can be easily demonstrated using our interop or unit test?

https://github.com/grpc/grpc-web/blob/master/javascript/net/grpc/web/grpcwebclientbase_test.js https://github.com/grpc/grpc-web/blob/master/test/interop/interop_client.js

Thanks!