You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by lh...@apache.org on 2026/07/22 10:06:50 UTC
(pulsar) branch branch-4.2 updated: [fix][broker][branch-4.2] Fix admin API HTTP 400 FAIL_ON_TRAILING_TOKENS when a broker interceptor is loaded (#26223)
This is an automated email from the ASF dual-hosted git repository.
lhotari pushed a commit to branch branch-4.2
in repository https://gitbox.apache.org/repos/asf/pulsar.git
The following commit(s) were added to refs/heads/branch-4.2 by this push:
new 7a172adc2ede [fix][broker][branch-4.2] Fix admin API HTTP 400 FAIL_ON_TRAILING_TOKENS when a broker interceptor is loaded (#26223)
7a172adc2ede is described below
commit 7a172adc2ede1e37819d9351cfde86d224c9e45c
Author: Lari Hotari <lh...@users.noreply.github.com>
AuthorDate: Wed Jul 22 13:06:43 2026 +0300
[fix][broker][branch-4.2] Fix admin API HTTP 400 FAIL_ON_TRAILING_TOKENS when a broker interceptor is loaded (#26223)
---
.../apache/pulsar/broker/web/RequestWrapper.java | 69 +++++++++++++++-------
1 file changed, 48 insertions(+), 21 deletions(-)
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/RequestWrapper.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/RequestWrapper.java
index afebbd276eba..0530f46abbb5 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/RequestWrapper.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/RequestWrapper.java
@@ -36,36 +36,63 @@ import org.apache.commons.io.IOUtils;
*/
public class RequestWrapper extends HttpServletRequestWrapper {
- private final byte[] body;
+ private byte[] body;
+ private ServletInputStream inputStream;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
- body = IOUtils.toByteArray(new InputStreamReader(request.getInputStream()), Charset.defaultCharset());
+ }
+
+ /**
+ * Buffers the request body on first access. Buffering is lazy on purpose: an interceptor that
+ * does not read the body (the common case) must not cause the body to be buffered at all, so the
+ * underlying request stream is consumed only once, by the downstream resource (Jersey). The read
+ * is bounded to Content-Length so it never reads past the request body.
+ */
+ private byte[] body() throws IOException {
+ if (body == null) {
+ HttpServletRequest request = (HttpServletRequest) getRequest();
+ int contentLength = request.getContentLength();
+ if (contentLength >= 0) {
+ body = IOUtils.toByteArray(request.getInputStream(), contentLength);
+ } else {
+ body = IOUtils.toByteArray(request.getInputStream());
+ }
+ }
+ return body;
}
@Override
public ServletInputStream getInputStream() throws IOException {
- final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
- return new ServletInputStream() {
- @Override
- public boolean isFinished() {
- return false;
- }
+ if (inputStream == null) {
+ // Return a single, stable stream over the buffered body. Repeated getInputStream() calls
+ // must return the same stream (per the Servlet contract); returning a fresh stream each
+ // time lets a reader that re-fetches the stream after EOF read the body's first byte
+ // again, surfacing as a spurious "Trailing token" error.
+ final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body());
+ inputStream = new ServletInputStream() {
+ @Override
+ public boolean isFinished() {
+ return byteArrayInputStream.available() == 0;
+ }
- @Override
- public boolean isReady() {
- return true;
- }
+ @Override
+ public boolean isReady() {
+ return true;
+ }
- @Override
- public void setReadListener(ReadListener readListener) {
+ @Override
+ public void setReadListener(ReadListener readListener) {
- }
+ }
- public int read() {
- return byteArrayInputStream.read();
- }
- };
+ @Override
+ public int read() {
+ return byteArrayInputStream.read();
+ }
+ };
+ }
+ return inputStream;
}
@Override
@@ -74,7 +101,7 @@ public class RequestWrapper extends HttpServletRequestWrapper {
}
//Use this method to read the request body N times
- public byte[] getBody() {
- return this.body;
+ public byte[] getBody() throws IOException {
+ return body();
}
}