module Metadata
Provides operations for building and extracting gRPC metadata.
Nested Classes and Modules
Definitions
def self.build(metadata: {}, timeout: nil, content_type: "application/grpc+proto")
Build gRPC request headers containing the given metadata.
Signature
-
parameter
metadataHash Custom metadata key-value pairs.
-
parameter
timeoutNumeric | Nil Optional timeout in seconds.
-
parameter
content_typeString The request content type.
-
returns
Protocol::HTTP::Headers The constructed request headers.
Implementation
def self.build(metadata: {}, timeout: nil, content_type: "application/grpc+proto")
headers = Protocol::HTTP::Headers.new(policy: Protocol::GRPC::HEADER_POLICY)
headers["content-type"] = content_type
headers["te"] = "trailers"
if timeout
# Coerced to proper format by header policy:
headers["grpc-timeout"] = timeout
end
metadata.each do |key, value|
# Binary headers end with -bin and are base64 encoded:
headers[key] = if key.end_with?("-bin")
Base64.strict_encode64(value)
else
value.to_s
end
end
headers
end
def self.extract(headers)
Extract application metadata from gRPC headers.
Signature
-
parameter
headersProtocol::HTTP::Headers The headers to inspect.
-
returns
Hash The extracted metadata key-value pairs.
Implementation
def self.extract(headers)
metadata = {}
headers.to_h.each do |key, value|
# Skip reserved headers:
next if key.start_with?("grpc-") || key == "content-type" || key == "te"
# Decode binary headers:
if key.end_with?("-bin")
if value.is_a?(String)
value = Base64.strict_decode64(value)
elsif value.is_a?(Array)
value = value.map{|item| Base64.strict_decode64(item)}
end
end
metadata[key] = value
end
metadata
end
def self.extract_status(headers)
Extract gRPC status from headers. Returns Status::UNKNOWN if status is not present.
Note: In Protocol::HTTP::Headers, trailers are merged into the headers so users just access headers["grpc-status"] regardless of whether it was sent as an initial header or trailer.
Signature
-
parameter
headersProtocol::HTTP::Headers -
returns
Integer Status code (0-16)
Implementation
def self.extract_status(headers)
# Ensure policy is set - setting policy clears the index (@indexed = nil)
# The index will be rebuilt automatically on next access via to_h
headers.policy = Protocol::GRPC::HEADER_POLICY unless headers.policy == Protocol::GRPC::HEADER_POLICY
status = headers["grpc-status"]
return Status::UNKNOWN unless status
return status.to_i
end
def self.extract_message(headers)
Extract gRPC status message from headers.
Returns Nil if message is not present.
Signature
-
parameter
headersProtocol::HTTP::Headers -
returns
String | Nil Status message
Implementation
def self.extract_message(headers)
# Ensure policy is set - setting policy clears the index (@indexed = nil)
# The index will be rebuilt automatically on next access via to_h
headers.policy = Protocol::GRPC::HEADER_POLICY unless headers.policy == Protocol::GRPC::HEADER_POLICY
message = headers["grpc-message"]
return nil unless message
return message.decode
end
def self.assign_status!(headers, status: Status::OK, message: nil, error: nil)
Assign gRPC status, message, and optional backtrace to headers.
Whether these become headers or trailers is controlled by the protocol layer.
Signature
-
parameter
headersProtocol::HTTP::Headers -
parameter
statusInteger gRPC status code
-
parameter
messageString | Nil Optional status message
-
parameter
errorException | Nil Optional error object (used to extract backtrace)
Implementation
def self.assign_status!(headers, status: Status::OK, message: nil, error: nil)
headers["grpc-status"] = status
if error && message.nil?
# If message is not provided but error is, use error message
message = error.message
end
if message
headers["grpc-message"] = message
end
# Add backtrace from error if available
if error && error.backtrace && !error.backtrace.empty?
# Assign backtrace array directly - Split header will handle it
headers["backtrace"] = error.backtrace
end
return headers
end