feat: add proxy-buffering plugin#13348
Conversation
The proxy-buffering plugin controls nginx proxy buffering behavior per route. When proxy buffering is disabled, nginx streams the response directly to the client without buffering, which is essential for Server-Sent Events (SSE), streaming APIs, and real-time data delivery. This commit also extends the APISIX HTTP pipeline with a dedicated nginx location (@disable_proxy_buffering) to handle routes where buffering should be disabled, similar to the existing @grpc_pass and @dubbo_pass locations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace AI-generated tests with tests based on actual streaming behavior: - Use hello_chunked upstream (chunked streaming) instead of /hello - Test baseline (without plugin) then with disable_proxy_buffering=true - Remove redundant schema validation and duplicate route tests - Update English doc: add canonical link, simplify description (remove internal priority detail), restructure to Examples format with named subsection - Update Chinese doc: add canonical link Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace AI-generated Test::Nginx integration tests with the enterprise edition test scripts. Keep only schema validation tests in .t file. - t/plugin/test_proxy_buffering.sh: shell script that tests SSE streaming via real HTTP requests against a running APISIX instance - t/test_sse.py: Python SSE server + client used by the shell script - t/certs/sse_server.crt, sse_server.key: TLS certs for SSL SSE test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The sse_server.key file contains base64 data with the string 'bRe' which codespell incorrectly flags as a misspelling. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
license check failing |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds a new proxy-buffering plugin to disable Nginx proxy buffering on a per-route basis (primarily to support SSE/streaming), wiring it into APISIX request handling and the Nginx template, plus adding docs and tests.
Changes:
- Introduces
proxy-bufferingplugin (priority 21991) that flags requests to be proxied withproxy_buffering off. - Routes flagged requests to a dedicated named Nginx location (
@disable_proxy_buffering) viaapisix/init.lua+apisix/cli/ngx_tpl.lua. - Adds docs (EN/ZH) and adds tests/scripts for schema validation and SSE verification.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| t/test_sse.py | Adds a Python SSE upstream + client used for manual/integration validation. |
| t/plugin/test_proxy_buffering.sh | Adds a shell-based flow configuring routes/SSLs and running SSE checks. |
| t/plugin/proxy-buffering.t | Adds schema validation tests for the new plugin. |
| t/certs/sse_server.key | Adds TLS private key for the SSE upstream used in tests. |
| t/certs/sse_server.crt | Adds TLS certificate for the SSE upstream used in tests. |
| t/admin/plugins.t | Registers proxy-buffering in admin plugin listing tests. |
| t/APISIX.pm | Adds a named Nginx location for disabling proxy buffering in test harness template. |
| docs/zh/latest/plugins/proxy-buffering.md | Adds Chinese documentation for proxy-buffering. |
| docs/zh/latest/config.json | Adds doc nav entry for plugin (ZH). |
| docs/en/latest/plugins/proxy-buffering.md | Adds English documentation for proxy-buffering. |
| docs/en/latest/config.json | Adds doc nav entry for plugin (EN). |
| conf/config.yaml.example | Adds plugin to default plugin list with priority comment. |
| apisix/plugins/proxy-buffering.lua | Implements the proxy-buffering plugin and schema. |
| apisix/init.lua | Adds upstream routing to @disable_proxy_buffering and a ctx-restoring access handler. |
| apisix/cli/ngx_tpl.lua | Adds @disable_proxy_buffering named location when plugin enabled. |
| apisix/cli/config.lua | Adds plugin to default enabled plugins list. |
| .ignore_words | Adds an ignored word entry. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
- Re-add 'bre' to .ignore_words to fix codespell CI failure (the previous commit incorrectly removed it) - Add Apache license headers to t/test_sse.py and t/plugin/test_proxy_buffering.sh to fix check-license CI failure - Rename Response subclass to SseResponse to avoid shadowing aiohttp.web.Response import - Use headers.pop() instead of del to safely remove X-Accel-Buffering header even if absent - Add --fail-with-body to curl wrapper so Admin API errors fail the test - Add additionalProperties = false to plugin schema for stricter validation - Fix Required column value from 'False' to 'No' in docs attribute table Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
AlinsRan
left a comment
There was a problem hiding this comment.
CI Failure Analysis
The two failing CI jobs (linux_apisix_current_luarocks and linux_apisix_current_luarocks_in_customed_nginx) fail with:
curl: (7) Failed to connect to 127.0.0.1 port 9180 after 0 ms: Could not connect to server
Root Cause
The CLI test framework in t/cli/ does not run APISIX as a live server. Looking at the runner script (ci/linux_apisix_current_luarocks_runner.sh), it:
- Starts and immediately stops APISIX (
apisix start / stop) to verify startup - Then runs all
t/cli/test_*.shscripts — these are nginx.conf generation tests, not live API tests
The correct pattern (see t/cli/test_dubbo.sh for reference) is:
. ./t/cli/common.sh
echo 'plugins:
- proxy-buffering' > conf/config.yaml
make init
if ! grep "location @disable_proxy_buffering" conf/nginx.conf > /dev/null; then
echo "failed: @disable_proxy_buffering location not found in nginx.conf"
exit 1
fi
echo "passed: @disable_proxy_buffering location found when proxy-buffering is enabled"Suggested Fix
t/cli/test_proxy_buffering.sh should be rewritten to use the make init + nginx.conf grep pattern. The t/cli/test_sse.py live SSE test does not belong in the CLI test directory.
Here is the corrected t/cli/test_proxy_buffering.sh:
#!/usr/bin/env bash
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
. ./t/cli/common.sh
# test: @disable_proxy_buffering location is generated when proxy-buffering is enabled
echo '
plugins:
- proxy-buffering
' > conf/config.yaml
make init
if ! grep "location @disable_proxy_buffering" conf/nginx.conf > /dev/null; then
echo "failed: @disable_proxy_buffering location not found in nginx.conf when proxy-buffering is enabled"
exit 1
fi
echo "passed: @disable_proxy_buffering location found when proxy-buffering is enabled"
if ! grep "proxy_buffering off" conf/nginx.conf > /dev/null; then
echo "failed: proxy_buffering off not found in nginx.conf"
exit 1
fi
echo "passed: proxy_buffering off found in nginx.conf"
# test: @disable_proxy_buffering location is NOT generated when proxy-buffering is not enabled
echo '
plugins: []
' > conf/config.yaml
make init
if grep "location @disable_proxy_buffering" conf/nginx.conf > /dev/null; then
echo "failed: @disable_proxy_buffering location should not be in nginx.conf when proxy-buffering is not enabled"
exit 1
fi
echo "passed: @disable_proxy_buffering location not generated when proxy-buffering is not enabled"The t/cli/test_sse.py file and its reference in the test script should be removed from this PR — live SSE integration testing would be better placed in a .t test file if needed.
Summary
The
proxy-bufferingplugin controls nginx proxy buffering behavior per route. When proxy buffering is disabled, nginx streams responses directly to clients without buffering, which is essential for Server-Sent Events (SSE), streaming APIs, and real-time data delivery.This plugin runs at a very high priority (21991) so it takes effect before authentication plugins, ensuring the streaming behavior is established early in the request lifecycle.
Changes
apisix/plugins/proxy-buffering.lua(priority: 21991)apisix/init.luawith adisable_proxy_buffering_access_phase()handler and routing checkapisix/cli/ngx_tpl.luawith a@disable_proxy_bufferingnginx location block (similar to@grpc_pass)Example
Requests to
/eventswill be proxied withproxy_buffering off, allowing SSE or chunked streaming responses to be delivered immediately to the client.