Dump request and response using javax.servlet.Filter

Java class

package com.foo;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class DumpFilter implements Filter {

  private static class ByteArrayServletStream extends ServletOutputStream {

    ByteArrayOutputStream baos;

    ByteArrayServletStream(ByteArrayOutputStream baos) {
      this.baos = baos;
    }

    public void write(int param) throws IOException {
      baos.write(param);
    }
  }

  private static class ByteArrayPrintWriter {

    private ByteArrayOutputStream baos = new ByteArrayOutputStream();

    private PrintWriter pw = new PrintWriter(baos);

    private ServletOutputStream sos = new ByteArrayServletStream(baos);

    public PrintWriter getWriter() {
      return pw;
    }

    public ServletOutputStream getStream() {
      return sos;
    }

    byte[] toByteArray() {
      return baos.toByteArray();
    }
  }

  private class BufferedServletInputStream extends ServletInputStream {

    ByteArrayInputStream bais;

    public BufferedServletInputStream(ByteArrayInputStream bais) {
      this.bais = bais;
    }

    public int available() {
      return bais.available();
    }

    public int read() {
      return bais.read();
    }

    public int read(byte[] buf, int off, int len) {
      return bais.read(buf, off, len);
    }

  }

  private class BufferedRequestWrapper extends HttpServletRequestWrapper {

    ByteArrayInputStream bais;

    ByteArrayOutputStream baos;

    BufferedServletInputStream bsis;

    byte[] buffer;

    public BufferedRequestWrapper(HttpServletRequest req) throws IOException {
      super(req);
      InputStream is = req.getInputStream();
      baos = new ByteArrayOutputStream();
      byte buf[] = new byte[1024];
      int letti;
      while ((letti = is.read(buf)) > 0) {
        baos.write(buf, 0, letti);
      }
      buffer = baos.toByteArray();
    }

    public ServletInputStream getInputStream() {
      try {
        bais = new ByteArrayInputStream(buffer);
        bsis = new BufferedServletInputStream(bais);
      } catch (Exception ex) {
        ex.printStackTrace();
      }

      return bsis;
    }

    public byte[] getBuffer() {
      return buffer;
    }

  }

  private boolean dumpRequest;
  private boolean dumpResponse;

  public void init(FilterConfig filterConfig) throws ServletException {
    dumpRequest = Boolean.valueOf(filterConfig.getInitParameter("dumpRequest"));
    dumpResponse = Boolean.valueOf(filterConfig.getInitParameter("dumpResponse"));
  }

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

    final HttpServletRequest httpRequest = (HttpServletRequest)servletRequest;
    BufferedRequestWrapper bufferedRequest= new BufferedRequestWrapper(httpRequest);

    if (dumpRequest) {
        System.out.println("REQUEST -> " + new String(bufferedRequest.getBuffer());
    }

    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(bufferedRequest, wrappedResp);

    byte[] bytes = pw.toByteArray();
    response.getOutputStream().write(bytes);
    if (dumpResponse) System.out.println("RESPONSE -> " + new String(bytes));
  }

  public void destroy() {}

}

web.xml

<filter>
    <filter_name>DumpFilter</filter_name>
    <filter_class>
    com.foo.DumpFilter
    </filter_class>
    <init_param>
        <param_name>dumpRequest</param_name>
        <param_value>true</param_value>
    </init_param>
    <init_param>
        <param_name>dumpResponse</param_name>
        <param_value>true</param_value>
    </init_param>
 </filter>
<filter_mapping>
    <filter_name>DumpFilter</filter_name>
    <url_pattern>/services/*</url_pattern>
</filter_mapping>

Note. Character “-” replaced by “_” in web.xml for correct visualization.

Published by angelborroy

Understanding software.

9 thoughts on “Dump request and response using javax.servlet.Filter

  1. thanks for the guide. Have you had any luck in extracting the http headers that are send back to the client?

    I am implementing a filter that dumps the complete request and response to disk. The request is easy as all the properties needed to reconstruct the request are available.

    The response is more difficult. Thanks to your guide I have the response body but the default headers are eluding me.

    I have extended HttpServletResponseWrapper and overridden every method, logged it, then called the super class method.

    A standard request generates the following headers:
    HTTP/1.1 200 OK
    Server: Apache-Coyote/1.1
    Content-Type: text/html;charset=UTF-8
    Content-Length: 296
    Date: Mon, 20 Apr 2009 04:15:43 GMT

    the best i can capture in the servlet is
    HTTP/1.1
    Content-Type: text/html;charset=UTF-8

    Date, Content-Length and Server are not set through the response object.

    I suspect what is happening is those headers are written by the container, after the response has left the control of the servlet and associated filters, in which case they can’t be retrieved and I’m doomed to failure.

  2. It’s a “System.out” standard sentence, but you can log the results at your will.

Leave a comment