Quantcast
Channel: Active questions tagged servlets - Stack Overflow
Viewing all articles
Browse latest Browse all 717

Custom OncePerRequestFilter reads empty request body – why is the body already consumed?

$
0
0

I'm developing a Spring Boot application (with Spring Security) and need to add default headers (specifically, Content-Type and Content-Length) to requests targeting the endpoint /api/v1/mpos/set-token when those headers are missing. To achieve this, I wrote a custom filter that extends OncePerRequestFilter and wraps the incoming HttpServletRequest so that I can read and cache its body. I use the following code:

@Component@Order(Ordered.HIGHEST_PRECEDENCE)public class SetTokenDefaultHeadersFilter extends OncePerRequestFilter {    private static final String DEFAULT_CONTENT_TYPE = "application/json";    private static final String TARGET_URI = "/api/v1/mpos/set-token";    @Override    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)            throws ServletException, IOException {        if (TARGET_URI.equals(request.getRequestURI())&& "POST".equalsIgnoreCase(request.getMethod())&& (request.getHeader("Content-Type") == null || request.getHeader("Content-Length") == null)) {            HttpServletRequest wrappedRequest = new HttpServletRequestWrapper(request) {                private final byte[] cachedBody = toByteArray(request.getInputStream());                private byte[] toByteArray(InputStream input) throws IOException {                    ByteArrayOutputStream baos = new ByteArrayOutputStream();                    byte[] buffer = new byte[1024];                    int len;                    while ((len = input.read(buffer)) != -1) {                        baos.write(buffer, 0, len);                    }                    return baos.toByteArray();                }                @Override                public ServletInputStream getInputStream() {                    final ByteArrayInputStream bais = new ByteArrayInputStream(cachedBody);                    return new ServletInputStream() {                        @Override                        public int read() {                            return bais.read();                        }                        @Override                        public boolean isFinished() {                            return bais.available() == 0;                        }                        @Override                        public boolean isReady() {                            return true;                        }                        @Override                        public void setReadListener(ReadListener readListener) {                            // Not implemented                        }                    };                }                @Override                public BufferedReader getReader() {                    return new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8));                }                @Override                public int getContentLength() {                    return cachedBody.length;                }                @Override                public long getContentLengthLong() {                    return cachedBody.length;                }                @Override                public String getHeader(String name) {                    if ("Content-Type".equalsIgnoreCase(name)) {                        String header = super.getHeader(name);                        return header == null ? DEFAULT_CONTENT_TYPE : header;                    }                    if ("Content-Length".equalsIgnoreCase(name)) {                        String header = super.getHeader(name);                        return header == null ? String.valueOf(cachedBody.length) : header;                    }                    return super.getHeader(name);                }            };            filterChain.doFilter(wrappedRequest, response);        } else {            filterChain.doFilter(request, response);        }    }}

I have verified (via logging and FilterRegistrationBean) that my filter is registered with the highest precedence and should run first. However, when I call input.read(buffer), it immediately returns -1 (i.e. EOF), and the cached body is an empty array.

What I've tried so far:

Verified the filter order – my filter is running first.

Checked for other filters that might be reading the body; the logs indicate that my filter is before them.

My questions:

What could be consuming the request body before my filter even gets a chance to read it?

How can I ensure that my filter has access to the full request body so I can wrap it and add the default headers?

Is there a recommended approach in Spring Boot to cache the request body before any processing?

Any insights or suggestions would be greatly appreciated.


Viewing all articles
Browse latest Browse all 717

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>