Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write to outputStream after HTTPServletResponse is committed

Is it possible to write response bytes to OutputStream of HTTPServletResponse even if Response is committed? I have a Servlet Filter which forwards request to CXFServlet by calling doFilter. After doFilter I explicitly want to write bytes in OutputStream. Currently I am not getting response when I write to OutputStream after response is committed.

public void doFilter(ServletRequest servletRequest,
        ServletResponse servletResponse, FilterChain filterChain)
        throws IOException, ServletException {
    final HttpServletResponse response = (HttpServletResponse) servletResponse;

    final ByteArrayPrintWriter pw = new ByteArrayPrintWriter();
    HttpServletResponse wrappedResp = new HttpServletResponseWrapper(
            response) {
        public PrintWriter getWriter() {
            return pw.getWriter();
        }

        public ServletOutputStream getOutputStream() {
            return pw.getStream();
        }
    };
    filterChain.doFilter(servletRequest, wrappedResp);

    byte[] bytes = pw.toByteArray();
    response.getOutputStream().write(bytes);
    response.getOutputStream().flush();
    response.getOutputStream().close();

// Do logging after response is sent to client. 


}
like image 243
apurva Avatar asked Aug 24 '26 20:08

apurva


1 Answers

I see two possible issues:

1) If you receive the content in byte[] bytes from pw (put a breakpoint on that line) that means the filter and wrapper did their job and that your servlet (or other inner filter) did close the real response somehow. Or - try using the Writer instead, I guess ByteArrayPrintWriter does have a method that returns char[] so you can use response.getWriter() to write the content.

2) If there is no content in byte[] bytes then ByteArrayPrintWriter does not collect the content correctly. Note that implementation may (or will) close the response writer, so maybe implementation of ByteArrayPrintWriter closes and thats why you don't get any content.

You can also try the following:

BufferResponseWrapper wrappedResp = new BufferResponseWrapper(response);
filterChain.doFilter(request, wrappedResp);

// get buffered content
char[] chars = wrapper.getBufferContentAsChars();
// modify it somehow
chars = ArraysUtil.join(chars, "peep!".toCharArray());
// flush
wrapper.writeContentToResponse(chars);

from the Jodd project: BufferResponseWrapper.java.

EDIT

Here is the similar filter that worked for me on Tomcat, using just Java classes:

public class MyFilter implements Filter {

public void init(FilterConfig filterConfig) throws ServletException {
}

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    final ByteArrayPrintWriter pw = new ByteArrayPrintWriter(baos);

    HttpServletResponse wrappedResp = new HttpServletResponseWrapper((HttpServletResponse) servletResponse) {
        @Override
        public PrintWriter getWriter() {
            return pw;
        }

        @Override
        public ServletOutputStream getOutputStream() {
            return new ServletOutputStream() {
                @Override
                public void write(int b) {
                    baos.write(b);
                }
            };
        }
    };

    filterChain.doFilter(servletRequest, wrappedResp);
    byte[] bytes = baos.toByteArray();
    servletResponse.getOutputStream().write(bytes);
}

public void destroy() {
}

public static class ByteArrayPrintWriter extends PrintWriter {
    public ByteArrayPrintWriter(OutputStream out) {
        super(out);
    }
}
}

Please note it is a quick-and-dirty implementation, used just for the illustration purposes.

like image 69
igr Avatar answered Aug 26 '26 22:08

igr



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!