Skip to content

fix(grpc): end a refused request body with grpc-status 8, not a bare reset (#426) - #430

Merged
EdmondDantes merged 1 commit into
mainfrom
fix/426-grpc-refused-body
Oct 20, 2026
Merged

EdmondDantes merged 1 commit into
mainfrom
fix/426-grpc-refused-body

Conversation

@EdmondDantes

Copy link
Copy Markdown
Contributor

Fixes #426.

A refused gRPC request body (HTTP/2 and HTTP/3, in-thread and under the HTTP/3 reactor pool) ended with a bare stream reset; curl read ENHANCE_YOUR_CALM and no grpc-status. It now ends with grpc-status: 8 (RESOURCE_EXHAUSTED; 13 for a 500 refusal) and a grpc-message, HTTP 200, trailers-only, followed by #412's clean reset.

  • h2_judge_refusal / h3_judge_refusal: gRPC is judged like any stream; WebSocket keeps the error reset; a gRPC response still being streamed keeps it too.
  • grpc_call_ensure_refusal_status (H2 dispose, H3 dispose, reactor answer): status from refused_status whether the handler failed or not; a status the handler set is kept with its own message.
  • Reactor: decided by req->grpc_mode (no worker has classified the call yet); grpc_call_init_response, status trailers promoted into the headers.
  • readMessage() throws the refusal's HttpException at entry and when a refusal ends its wait; the H2/H3 body upgrade does nothing on a refused request. Before, a handler that caught the refusal and read again parked for good.

Critic on the design (unsound, fixed) and on the diff (sound with remarks, all taken: grpc/022 lacked TRUE_ASYNC_SERVER_REACTOR_POOL=1; the wait loop threw RuntimeException 0; no test of a handler's own status).

Evidence (ZTS DEBUG, local): grpc/020-025 fail on main and pass 10 of 10; full phpt 635 passed, 2 skipped, 0 failed; cmocka 24 of 24. 023/024 time the upload in PHP (_grpc_h2_upload.inc, proc_open without a shell) so they run on Windows; not run on Windows locally.

Not covered: gRPC-Web over HTTP/1.1 keeps the HTTP/1 413 path. On the reactor a request with a gRPC content type but no gRPC handler gets the gRPC answer (the reactor has no handler map; the cumulative-cap waiver already keys on the content type).

@github-actions

Copy link
Copy Markdown
Contributor

Coverage

Total lines: 85.89% → 85.91% (+0.01 pp)

File Baseline Current Δ Touched
src/grpc/grpc_call.c 100.00% 100.00% +0.00 pp ●
src/http2/http2_session.c 91.63% 91.63% +0.00 pp ●
src/http2/http2_strategy.c 86.15% 86.18% +0.03 pp ●
src/http3/http3_callbacks.c 86.88% 86.87% -0.01 pp ●
src/http3/http3_connection.c 86.39% 86.45% +0.07 pp
src/http3/http3_dispatch.c 90.94% 91.08% +0.13 pp ●
src/http3/http3_io.c 89.09% 89.68% +0.59 pp
src/http_request.c 90.10% 90.00% -0.10 pp ●

@EdmondDantes
EdmondDantes merged commit 849c5ac into main Oct 20, 2026
8 checks passed
@EdmondDantes
EdmondDantes deleted the fix/426-grpc-refused-body branch October 20, 2026 07:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gRPC: a refused request body resets the stream with no grpc-status

1 participant