gRPC over HTTP/2 + gRPC-Web — Spec-Coverage

Specs: docs/standards/cache/grpc/protocol-http2.md + docs/standards/cache/grpc/protocol-web.md.

Folgt dem Format aus docs/spec-coverage/PROCESS.md.

Kontext: gRPC ist die Cloud-RPC-Spec von Google. ZeroDDS implementiert die gRPC-Wire-Elemente in crates/grpc-bridge/, plus eigene no_std-tauglich-HTTP/2-Implementation in crates/http2/ (RFC 7540) und HPACK-Header-Compression in crates/hpack/ (RFC 7541). Compression-Codecs (gzip/deflate) sind Caller-Layer.

Crate-Mapping:

Spec-Bereich Crate(s)
gRPC Wire (LPM, Path, Status, Timeout) crates/grpc-bridge/
HTTP/2 Frame-Layer (RFC 7540) crates/http2/
HPACK Header-Compression (RFC 7541) crates/hpack/

protocol-http2 §“Outline”

Request/Response Message Stream

Spec: Request → Request-Headers *Length-Prefixed-Message EOS, Response → (Response-Headers *Length-Prefixed-Message Trailers) / Trailers-Only.

Repo: crates/grpc-bridge/src/frame.rs::{encode_message, decode_message, encode_web_trailers}.

Tests: frame::tests::* (9 Tests inkl. back-to-back-Stream).

Status: done


protocol-http2 §“Requests”

Request-Headers (Path/Method/Authority/etc.)

Spec: Method :method POST, Scheme :scheme http/https, Path /<service>/<method>, Authority, TE: trailers, grpc-timeout, Content-Type: application/grpc, grpc-encoding/grpc-accept-encoding, User-Agent, grpc-message-type, Custom-Metadata.

Repo: Path-Parsing in crates/grpc-bridge/src/path.rs::parse_path; Timeout-Header in crates/grpc-bridge/src/timeout.rs; Generic-Request-Header-Konstanten in crates/grpc-bridge/src/metadata.rs::request_headers::{METHOD, SCHEME, PATH, AUTHORITY, TE, CONTENT_TYPE, GRPC_ENCODING, GRPC_ACCEPT_ENCODING, USER_AGENT, GRPC_TIMEOUT, GRPC_MESSAGE_TYPE} + content_types::{GRPC, GRPC_PROTO, GRPC_WEB, GRPC_WEB_TEXT}.

Tests: path::tests::* (7 Tests), timeout::tests::* (10 Tests), metadata::tests::{request_headers_constants_match_spec, content_types_match_spec_strings}.

Status: done — alle Required-Header-Names + Content-Type-Set als Konstanten ausgewiesen.

Path-Parsing

Spec: Path → ":path" "/" Service-Name "/" {method name}.

Repo: crates/grpc-bridge/src/path.rs::parse_path mit Reject von relative-paths, missing-method, empty-segments, method-mit-slash.

Tests: path::tests::parses_standard_grpc_path, rejects_relative_path, rejects_path_without_method, rejects_empty_service, rejects_empty_method, rejects_method_with_slash, parses_dotted_service_name.

Status: done

Timeout Header (grpc-timeout)

Spec: Timeout → "grpc-timeout" TimeoutValue TimeoutUnit, TimeoutValue MUST be at most 8 digits, Unit ∈ {H,M,S,m,u,n}.

Repo: crates/grpc-bridge/src/timeout.rs::{TimeoutUnit, encode_timeout, decode_timeout} mit Reject von ueber-8-Digit, non- digit, unbekannter-Unit, leerem Header.

Tests: timeout::tests::* (10 Tests inkl. Round-Trip aller 6 Units).

Status: done

Length-Prefixed-Message

Spec: Length-Prefixed-Message → Compressed-Flag Message-Length Message, Compressed-Flag = 1 byte, Message-Length = 4 byte BE.

Repo: crates/grpc-bridge/src/frame.rs::{encode_message, decode_message} mit empty/short/large/back-to-back-Stream-Tests.

Tests: frame::tests::empty_message_encodes_to_5_byte_header, uncompressed_message_has_compressed_flag_zero, compressed_message_has_compressed_flag_one, round_trip_message, message_length_uses_big_endian_4_bytes, header_too_short_decode_fails, body_truncated_decode_fails, back_to_back_messages_can_be_decoded_sequentially.

Status: done


protocol-http2 §“Responses”

Response-Headers + Trailers

Spec: Response-Headers → HTTP-Status [Message-Encoding] [Message-Accept-Encoding] Content-Type *Custom-Metadata, Trailers → Status [Status-Message] *Custom-Metadata.

Repo: Status-Code in crates/grpc-bridge/src/status.rs; Response-Header-Konstanten in crates/grpc-bridge/src/metadata.rs::response_headers::{STATUS, CONTENT_TYPE, GRPC_ENCODING, GRPC_STATUS, GRPC_MESSAGE}.

Tests: Cross-Ref status::tests::*, metadata::tests::response_headers_constants_match_spec.

Status: done — Status-Code-Set + Required-Response-Header-Set als Konstanten ausgewiesen.

Status Codes

Spec: Status → "grpc-status" 1*DIGIT ; 0-9 mit kanonischen Werten 0..=16 (OK/CANCELLED/UNKNOWN/…/UNAUTHENTICATED).

Repo: crates/grpc-bridge/src/status.rs::Status Enum mit code/from_code/is_ok/name-Methods. Alle 17 Werte modelliert.

Tests: status::tests::* (5 Tests inkl. Round-Trip aller 17 + Reject von Code-17/255 + name() screaming-snake-case).

Status: done


protocol-http2 §“Custom-Metadata”

Binary + ASCII Headers

Spec: Binary-Header → {Header-Name "-bin"} {base64 encoded value}, ASCII-Header → Header-Name ASCII-Value. Header-Names mit grpc- sind reserved.

Repo: crates/grpc-bridge/src/metadata.rs::{is_binary_header, encode_base64, decode_base64, encode_header_value, decode_header_value, BIN_SUFFIX}. RFC-4648-base64 ohne externe Crate-Dependency; rejection von non-ASCII-Bytes in Text-Headern.

Tests: metadata::tests::{is_binary_header_recognizes_bin_suffix, is_binary_header_rejects_text_headers, encode_base64_empty, encode_base64_one_byte_pads_two, encode_base64_two_bytes_pads_one, encode_base64_three_bytes_no_padding, encode_base64_known_vector, decode_base64_round_trip, decode_base64_rejects_invalid_chars, decode_base64_rejects_bad_padding_length, encode_header_value_text_passes_ascii, encode_header_value_text_rejects_non_ascii, encode_header_value_bin_uses_base64, decode_header_value_round_trip_bin, decode_header_value_text_passes_through} (15 Tests).

Status: done — Binary-Header-Codec + ASCII-Validation live.


protocol-http2 §“HTTP2 Transport Mapping”

HTTP/2 Frame-Types + HPACK + Connection-Management

Spec: HEADERS, CONTINUATION, DATA, RST_STREAM, SETTINGS, PING, GOAWAY, WINDOW_UPDATE.

Repo: crates/http2/src/{frame,settings,stream,flow,preface, error}.rs (1191 SLOC) für RFC 7540 Frame-Layer + Connection- Management; crates/hpack/src/{encoder,decoder,table,huffman, integer,string}.rs (1704 SLOC) für RFC 7541 Header-Compression.

Tests: Inline-Tests in beiden Crates.

Status: done — eigene no_std-tauglich-Implementation (Greenfield- Lücke in 2026 geschlossen).


protocol-web

gRPC-Web Trailers in LPM-Frame

Spec: gRPC-Web encoded Trailers im Length-Prefixed-Message-Frame mit Compressed-Flag-MSB=1 (0x80).

Repo: crates/grpc-bridge/src/frame.rs::encode_web_trailers.

Tests: frame::tests::web_trailers_encoded_with_msb_set.

Status: done — Caller liefert die Trailers als UTF-8-Bytes (typisch grpc-status: 0\r\ngrpc-message: ...\r\n).

gRPC-Web Base64-Encoding (text-Subprotocol)

Spec: gRPC-Web hat application/grpc-web (binary) und application/grpc-web-text (base64-encoded).

Repo: crates/grpc-bridge/src/metadata.rs::{encode_base64, decode_base64} (RFC-4648 Standard-Variante mit Padding) + content_types::GRPC_WEB_TEXT als Marker.

Tests: Cross-Ref metadata::tests::{encode_base64_*, decode_base64_round_trip}.

Status: done — Base64-Subprotocol-Codec + Content-Type-Marker live.


Audit-Status

12 done / 0 partial / 0 open / 0 n/a (informative) / 0 n/a (rejected).

Test-Lauf:

Offene Punkte: siehe grpc-protocol.open.md.