HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

Modulegrpc-spec-1.0.0Haskell2010

Network.GRPC.Spec.Serialization

Serialization functions

We collect these functions in a separate module, rather than exporting them from Network.GRPC.Spec, because while the functions in Network.GRPC.Spec may be needed in some user code (albeit rarely), the serialization functions from this module really should only be needed in gRPC implementations such as grapesy.

  • 2 types
  • 31 values
  • Packagegrpc-spec-1.0.0
  • Exports33
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourceSerialization.hs

Messages

0 declarations

Inputs

Serialize RPC input

Length-Prefixed-Message → Compressed-Flag Message-Length Message

Compressed-Flag → 0 / 1
                    # encoded as 1 byte unsigned integer
Message-Length  → {length of Message}
                    # encoded as 4 byte unsigned integer (big endian)
Message         → *{binary octet}

Outputs

Headers

0 declarations

Pseudoheaders

RequestHeaders

Timeouts

OpenTelemetry

ResponseHeaders

Pushback

valueparsePushback :: Monad m => ByteString -> m Pushback
#

Parse Pushback

Parsing a pushback cannot fail; the spec mandates:

If the value for pushback is negative or unparseble, then it will be seen
as the server asking the client not to retry at all.

We therefore only require Monad m, not MonadError m (having the Monad constraint at all keeps the type signature consistent with other parsing functions).

ProperTrailers

TrailersOnly

valuebuildTrailersOnly
  1. :: (ContentType -> Maybe ByteString)

    Interpret ContentType

    Under normal circumstances this should be Just . chooseContentType. In some cases, however, the content-type might not be known. For example, when a request comes in for an unknown method, the gRPC server is supposed to respond with a Trailers-Only message, with an UNIMPLEMENTED error code. Frustratingly, Trailers-Only requires a Content-Type header, even though there is no content. This Content-Type header normally indicates the serialization format (e.g., application/grpc+proto), but this format depends on the specific method, which was not found!

    To resolve this catch-22, this function is allowed to return Nothing, in which case the Content-Type we will use application/grpc, with no format specifier. Fortunately, this is allowed by the spec.

  2. -> TrailersOnly
  3. -> [Header]
#

Build trailers for the Trailers-Only case

Classify server response

valueclassifyServerResponse
  1. :: IsRPC rpc
  2. => Proxy rpc
  3. -> Status

    HTTP status

  4. -> [Header]

    Headers

  5. -> Maybe ByteString

    Response body, if known (used for errors only)

  6. -> Either (TrailersOnly' GrpcException) (ResponseHeaders' GrpcException)
#

Classify server response

gRPC servers are supposed to respond with HTTP status 200 OK no matter whether the call was successful or not; if not successful, the information about the failure should be reported using grpc-status and related headers (grpc-message, grpc-status-details-bin).

The gRPC spec mandates that if we get a non-200 status from a broken deployment, we synthesize a gRPC exception with an appropriate status and status message. The spec itself does not provide any guidance on what such an appropriate status would look like, but the official gRPC repo does provide a partial mapping between HTTP status codes and gRPC status codes at https://github.com/grpc/grpc/blob/master/doc/http-grpc-status-mapping.md. This is the mapping we implement here.

Custom metadata

Binary values

Parse binary value

The presence of duplicate headers makes this a bit subtle. Let's consider an example. Suppose we have two duplicate headers

foo-bin: YWJj    -- encoding of "abc"
foo-bin: ZGVm    -- encoding of "def"

The spec says

Custom-Metadata header order is not guaranteed to be preserved except for
values with duplicate header names. Duplicate header names may have their
values joined with "," as the delimiter and be considered semantically
equivalent.

We will do the decoding of both headers prior to joining duplicate headers, and so the value we will reconstruct for foo-bin is "abc,def".

However, suppose we deal with a (non-compliant) peer which is unaware of binary headers and has applied the joining rule without decoding:

foo-bin: YWJj,ZGVm

The spec is a bit vague about this case, saying only:

Implementations must split Binary-Headers on "," before decoding the
Base64-encoded values.

Here we assume that this case must be treated the same way as if the headers had been decoded prior to joining. Therefore, we split the input on commas, decode each result separately, and join the results with commas again.

Status (Protobuf specific)