rpc_dart_http 0.4.0
rpc_dart_http: ^0.4.0 copied to clipboard
HTTP/1.1 caller/responder transports for rpc_dart (unary only).
0.4.0 #
Breaking #
- Requires rpc_dart 6. See its changelog — notably that a handler's bare
Exceptiontext no longer reaches the caller. - gRPC is POST-only. The server executed a handler for any HTTP method.
Security #
maxMetadataBytesis enforced on inbound headers. The responder checkedmaxHeadersand the per-header caps, which do not imply a total: the defaults allow 128 × 8 KiB = 1 MiB against a 64 KiB bound. Measured with raw HTTP/1.1 POSTs, 960 000 bytes of headers were answered200 OK— 14.6x the bound, every header individually legal, before any authentication, anddart:ioimposes no limit of its own.- The caller bounds the response body it is willing to buffer. A server bounds what clients send it and forgets it is also a client of its peers: a 192 MiB body cost 756 MiB of RSS, resident three times over, before the parser's own error fired.
- The refusal path has the deadline it documented, so refusing is not the cheap way to pin a server.
- The CORS policy applies to rejections too, with
Varymarked, and the credentials guard holds outsidedart test. - The pipeline stream opens only once the request is in hand.
Fixed #
- A connection failure is a gRPC status, not a raw
ClientException, and closing under an in-flight call gives a status rather than a dropped socket. - A big error page no longer destroys the status it carried, and an
oversized request is
RESOURCE_EXHAUSTEDrather thanINVALID_ARGUMENT. - The rejection reason reaches the caller instead of a bare code.
- A gRPC content type is accepted in any case.
- The server starts its own endpoint, and
stop()releases a partially started one. - The stream-id watermark is joined, so a dead call can no longer fire a live request.
- The security policy reaches the responder pipeline.
- Opt-in graceful drain on
stop().
Performance #
- Request and response bodies are buffered as bytes rather than word-sized ints.
Documentation #
- The example no longer teaches accepting any TLS certificate.
- What streaming methods actually do on HTTP/1.1 is stated, along with the
", "header-splitting limitation and the fact thatbodyReadTimeoutrejects anExpect: 100-continueclient.
0.3.0 #
Changed #
- Requires rpc_dart 5. See its changelog: flow control is on by default, an
expired deadline is now
RpcDeadlineExceededExceptionon every shape, and a stream that ends without a trailer raisesUNAVAILABLE.
0.2.4 #
- Deliver the
400when a request body exceedsRpcSecurityPolicy.maxMessageLengthBytes. The responder used to stop reading the moment the limit was passed, which left unread bytes on the socket; dart:io then tore the connection down before the response was flushed and the client saw "Connection closed before full header was received" instead of the status. The body is now drained to its end (buffer dropped, later chunks discarded, so memory stays bounded) before the400is returned. - Validate outgoing metadata on send. Both the caller (
sendMetadata) and the responder (sendMetadata) now runRpcSecurityPolicy.validateMetadatabefore writing headers, closing the gap where HTTP/1.1 sent metadata without the checks every other transport applies. Combined with the core change, this enforces printable-ASCII header values (%x20-%x7E) — non-ASCII / CR-LF values are rejected with anArgumentErrorinstead of corrupting or injecting HTTP headers. The caller uses a defaultRpcSecurityPolicy; the responder uses its configuredsecurityPolicy(or the default when unset).
0.2.3 #
- BEHAVIORAL CHANGE (secure-by-default CORS):
RpcHttpCorsPolicy.allowedOriginsnow defaults toconst [](CLOSED) instead ofconst ['*']. With the closed default, cross-origin browser preflights are rejected (403, noaccess-control-allow-origin) and cross-origin actual requests receive no CORS headers, so the browser blocks the response read. Same-origin requests (which carry noOriginheader) are unaffected. The previous allow-any-origin default let any web page (including DNS-rebinding / drive-by attackers) call a local/internal RPC server. To restore the old behavior, passallowedOrigins: ['*']explicitly, or list specific origins. - Allowing any origin via
allowedOrigins: ['*']now emits a one-time warning (via an optionalloggeron the policy constructor, falling back to stderr), noting it is intended for dev / public-API use only. The existing assert that'*'is incompatible withallowCredentialsis unchanged.
0.2.2 #
- Server-side hardening.
RpcHttpServernow forwards asecurityPolicyand an optionalbodyReadTimeoutto itsRpcHttpResponderTransport. Previously the server constructed the transport with only the CORS policy, so request bodies reached via the public server API were buffered UNBOUNDED (DoS via large/slow POST) and had no read timeout (slowloris). - BEHAVIORAL CHANGE:
securityPolicydefaults to a non-nullconst RpcSecurityPolicy(), so the built-inmaxMessageLengthBytes(16 MiB), header, and concurrency limits are now ENFORCED out of the box. Requests exceeding the body limit are rejected with400instead of being buffered. PasssecurityPolicy: nullto opt out (not recommended), or a tunedRpcSecurityPolicyto adjust the limits. - Added
RpcHttpServer.actualPortgetter (returns the OS-assigned port after binding when constructed with port0).
0.2.1 #
- Added
test/web_smoke_test.dart: cross-platform (dart2js) smoke test proving theRpcHttpCallerTransportclient compiles to JS and round-trips a unary call without a real server. It injects apackage:httpMockClientthat decodes the gRPC-framed request and returns a canned framed response. - Wired the http web smoke into the
just test_webrecipe and thewebCI job (runs on-p node; also verified on-p chrome).
0.2.0 #
- Updated to
rpc_dart: ^3.0.0. RpcHttpServer: addedafterModulesStarthook support.
0.1.0 #
- Initial release: HTTP/1.1 unary-only transport for rpc_dart using
shelf.