Skip to content

Commit

Permalink
Add the "grpc-encoding" header to the response (#20)
Browse files Browse the repository at this point in the history
* Add the "grpc-encoding" header to the response

Once the per-message compression encoding has been negotiated (by
inspecting the `grpc-accept-encoding` request header), the server should
tell the client the chosen encoding (either `identity` or `gzip`) by
setting the `grpc-encoding` response header.

The meaning of the header is: if any message in the response has its
compression flag set, then that message has been compressed using this
encoding.

Some clients can live with the header being missing. If they encounter a
message with its compression flag set, they just assume the encoding is
GZip. But other clients, notably the official Java gRPC library, are
stricter and require the header to be present.

Aside: compression can be done at the stream level rather than the
individual message level. In that case, the `content-encoding` header
must be set, and the `grpc-encoding` header must *not* be set.

None of this is really documented anywhere. I worked it out using
Wireshark and reading the [grpc-java
source](https://github.com/grpc/grpc-java/blob/8d4240f4800f20de0e5f0b7c213577b3c0324f93/core/src/main/java/io/grpc/internal/AbstractClientStream.java#L313-L356).
  • Loading branch information
cb372 committed Mar 25, 2020
1 parent 6e21111 commit 91713cf
Showing 1 changed file with 10 additions and 11 deletions.
21 changes: 10 additions & 11 deletions warp-grpc/src/Network/GRPC/Server/Wai.hs
Expand Up @@ -95,28 +95,27 @@ grpcService compressions services app = \req rep -> do
, Handler $ \(e::SomeException) ->
modifyGRPCStatus r req (GRPCStatus INTERNAL $ ByteString.pack $ show e)
]
in (rep $ responseStream status200 hdrs200 grpcHandler)
in (rep $ responseStream status200 (hdrs200 req) grpcHandler)
Nothing ->
app req rep
where
hdrs200 = [
bestCompression req = lookupEncoding req compressions
pickedCompression req = fromMaybe (Encoding uncompressed) (bestCompression req)

hopefulDecompression req = lookupDecoding req compressions
pickedDecompression req = fromMaybe (Decoding uncompressed) (hopefulDecompression req)

hdrs200 req = [
("content-type", grpcContentTypeHV)
, ("grpc-encoding", grpcCompressionHV (_getEncodingCompression $ pickedCompression req))
, ("trailer", CI.original grpcStatusH)
, ("trailer", CI.original grpcMessageH)
]
lookupHandler :: ByteString -> [ServiceHandler] -> Maybe WaiHandler
lookupHandler p plainHandlers = grpcWaiHandler <$>
List.find (\(ServiceHandler rpcPath _) -> rpcPath == p) plainHandlers
doHandle r handler req write flush = do
let bestCompression = lookupEncoding req compressions
let pickedCompression = fromMaybe (Encoding uncompressed) bestCompression

let hopefulDecompression = lookupDecoding req compressions
let pickedDecompression = fromMaybe (Decoding uncompressed) hopefulDecompression

putStrLn "running handler"
_ <- handler pickedDecompression pickedCompression req write flush
putStrLn "setting GRPC status"
_ <- handler (pickedDecompression req) (pickedCompression req) req write flush
modifyGRPCStatus r req (GRPCStatus OK "WAI handler ended.")

#if MIN_VERSION_warp(3,3,0)
Expand Down

0 comments on commit 91713cf

Please sign in to comment.