Aias00 opened a new issue, #7807:
URL: https://github.com/apache/shenyu/issues/7807
### Is there an existing issue for this?
- [x] I searched existing issues for ClusterForwardFilter, chunked responses
and Transfer-Encoding. Previous data-plane response/header issues such as #5788
and #1861 are different paths; this report concerns Admin follower-to-master
HTTP forwarding.
### Current Behavior
An authenticated HTTP API request sent to an Admin **follower** with
`Connection: close` receives `Transfer-Encoding: chunked` but an unchunked JSON
body. Python urllib raises `http.client.IncompleteRead` while trying to parse
the opening JSON bytes as a chunk size.
The same request sent directly to the master is correctly chunk-encoded.
With keep-alive, the follower body is chunk-encoded but the response contains
duplicate Transfer-Encoding headers and duplicated Connection values.
This was verified from raw TCP response bytes, not inferred solely from a
client exception.
### Expected Behavior
A follower should emit a valid HTTP response independently of the
master-to-follower connection framing. Transfer-Encoding and Connection must
describe the follower-to-client hop. Both close and keep-alive clients should
be able to read the complete JSON response.
### Steps To Reproduce
1. Start two Admin nodes in JDBC cluster mode against the same MySQL
database, with matching JWT and cluster event secrets.
2. Identify the elected master and follower. Obtain a normal Admin login
token.
3. Send the same authenticated GET to each node:
```python
import os
import urllib.request
for port in (9095, 9096):
req = urllib.request.Request(
f"http://127.0.0.1:{port}/selector?pluginId=5¤tPage=1&pageSize=100",
headers={
"X-Access-Token": os.environ["ADMIN_TOKEN"],
"Connection": "close",
},
)
with urllib.request.urlopen(req, timeout=10) as response:
print(port, response.status,
response.headers.get("Transfer-Encoding"))
print(len(response.read()))
```
4. The master's response is readable; reading the follower response raises
IncompleteRead. A matching request using keep-alive may be readable but still
exhibits duplicated framing headers.
### Raw Response Evidence
With master on port 9095 and follower on port 9096 in this run:
| Node / request | Response headers | Raw body prefix |
| --- | --- | --- |
| master / close | `Transfer-Encoding: chunked`, `Connection: close` |
`5fb\r\n{"code":200,...}` |
| follower / close | `Transfer-Encoding: chunked`, `Connection: close` |
`{"code":200,...}` — no chunk-size line |
| follower / keep-alive | two `Transfer-Encoding: chunked` header lines;
`Connection: keep-alive, keep-alive` | `5fb\r\n{"code":200,...}` |
The chunk size above depends on the selector data present. The relevant
invariant is that the follower/close response advertises chunked encoding
without transmitting it.
### Environment
- ShenYu `2.7.2-SNAPSHOT`, master `04f7c2e8b7d282f14510157a9ab0bfaab538ecac`
- Java 17, ARM64 Linux Docker containers, MySQL 8.0
- Two Admin nodes with JDBC cluster mode enabled
### Code Evidence / Suggested Scope
[ClusterForwardFilter.java](https://github.com/apache/shenyu/blob/04f7c2e8b7d282f14510157a9ab0bfaab538ecac/shenyu-admin/src/main/java/org/apache/shenyu/admin/mode/cluster/filter/ClusterForwardFilter.java#L132-L149):
1. Line 138 buffers the master response as `ResponseEntity<byte[]>`; the
HTTP client has already decoded the master's transfer framing.
2. Line 143 copies the master response headers to the follower Servlet
response.
3. Line 148 writes the decoded byte array to the Servlet output stream.
4. [The header-copy
helper](https://github.com/apache/shenyu/blob/04f7c2e8b7d282f14510157a9ab0bfaab538ecac/shenyu-admin/src/main/java/org/apache/shenyu/admin/mode/cluster/filter/ClusterForwardFilter.java#L182-L199)
does not filter hop-by-hop/framing headers.
Please filter connection-specific/framing headers at the forwarding boundary
and let the Servlet container produce the client-facing framing. Review
request-side forwarding as well. Preserve ordinary representation headers and
ensure Content-Length, if set, matches the actual forwarded bytes.
Regression coverage should include real HTTP master/follower responses for
both Connection modes. A mocked Servlet output stream alone will not exercise
Tomcat's framing decisions.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]