Skip to content

fix: preserve client-control body limit for gRPC upstreams - #14036

Open
ruanweihong-aaa wants to merge 3 commits into
apache:masterfrom
ruanweihong-aaa:codex/fix-grpc-client-body-limit
Open

ruanweihong-aaa wants to merge 3 commits into
apache:masterfrom
ruanweihong-aaa:codex/fix-grpc-client-body-limit

Conversation

@ruanweihong-aaa

@ruanweihong-aaa ruanweihong-aaa commented Oct 15, 2026 •

Copy link
Copy Markdown

Summary

  • Save the client-control body limit in the APISIX request context after the runtime setter succeeds.
  • Restore the limit in grpc_access_phase() after the redirect to @grpc_pass, with the existing setter and 503 error handling.
  • Add gRPC regression cases for a stricter route limit, zero/unlimited, and a route limit above the global default.

Fixes #14009.

Verification

  • Reproduced the 5 MiB route rejecting a 2 MiB gRPC request and the 512 KiB route accepting a 900 KiB request with a real Python gRPC client and backend. Both behaved as configured with the changed Lua files mounted in APISIX 3.19.0.
  • Also checked 6 MiB rejection, zero/unlimited, no plugin, with and without Content-Length, ordinary HTTP, and grpcs with a TLS backend.
  • LuaJIT syntax compilation and git diff --check passed.
  • Added Test::Nginx regression cases for repository CI. The repository workflows currently show action_required on this fork PR, so their results are pending.

@ruanweihong-aaa
ruanweihong-aaa marked this pull request as ready for review October 15, 2026 03:58
Comment thread apisix/init.lua Outdated
apisix_ngx_client.enable_mirror()
end

if api_ctx.client_max_body_size and has_mod then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The judgment of has_mod is redundant, and this judgment does not exist in the code of apisix/plugins/client-control.lua.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out. I removed the redundant has_mod check in 3eccc1e8. client-control saves the limit in the request context only after set_client_max_body_size succeeds.

nic-6443
nic-6443 previously approved these changes Oct 15, 2026
Comment thread t/node/grpc-proxy-unary.t Outdated
Comment on lines +36 to +44
=== TEST: client-control rejects a gRPC request without Content-Length after internal redirect
--- http2
--- apisix_yaml
routes:
- id: grpc-body-limit
uri: /helloworld.Greeter/SayHello
plugins:
client-control:
max_body_size: 1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gRPC tests lack a runtime gate

Without apisix-nginx-module, client-control returns 501 before the new gRPC tests reach their assertions. The existing client-control suite skips that environment; these cases need the same gate.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this. I moved the new cases to t/node/grpc-client-control.t and added the same apisix-nginx-module availability check used by the existing client-control test suite. The new cases are skipped when the module is unavailable, while the existing gRPC proxy tests remain runnable.

Comment thread t/node/grpc-proxy-unary.t Outdated
Comment on lines +84 to +105
=== TEST: client-control raises the gRPC body limit above the global limit
--- http2
--- extra_yaml_config
nginx_config:
http:
client_max_body_size: 1
--- apisix_yaml
routes:
- id: grpc-larger-body-limit
uri: /helloworld.Greeter/SayHello
plugins:
client-control:
max_body_size: 5242880
upstream:
scheme: grpc
nodes:
"127.0.0.1:10051": 1
type: roundrobin
#END
--- exec
grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto -plaintext -d '{"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHello
--- response_body_like: Hello apisix

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raised-limit cases use tiny requests

The zero and 5 MiB cases send a small request, so both pass even if the original Nginx limit remains in force. The test fixture builds Nginx configuration separately from extra_yaml_config; verify the limit reaches it and send a larger body.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed—the original small requests could not verify that the raised limit took effect. The test fixture already sets a 30 MiB Nginx limit, so I removed the duplicate directive after CI showed it prevented Nginx from starting. In adec29cd, both raised-limit cases send a 31 MiB request, with the plugin set to unlimited or 50 MiB. They expect the upstream gRPC server's ResourceExhausted response rather than an APISIX 413, which would show that the request reached the upstream. CI for this revision is still running.

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.

client-control max_body_size has no effect on routes with a gRPC upstream

4 participants