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();
     }
 }