Skip to content

Instantly share code, notes, and snippets.

@calo81
Created March 18, 2012 12:48
Show Gist options
  • Star 69 You must be signed in to star a gist
  • Fork 27 You must be signed in to fork a gist
  • Save calo81/2071634 to your computer and use it in GitHub Desktop.
Save calo81/2071634 to your computer and use it in GitHub Desktop.
Filter for reading and logging HttpServletRequest body, and resetting the input stream
package com.paddypower.financials.market.management.rest.logging;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.io.IOUtils;
public class LoggerFilter implements Filter {
private Auditor auditor;
public void destroy() {
// Nothing to do
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
ResettableStreamHttpServletRequest wrappedRequest = new ResettableStreamHttpServletRequest(
(HttpServletRequest) request);
// wrappedRequest.getInputStream().read();
String body = IOUtils.toString(wrappedRequest.getReader());
auditor.audit(wrappedRequest.getRequestURI(),wrappedRequest.getUserPrincipal(), body);
wrappedRequest.resetInputStream();
chain.doFilter(wrappedRequest, response);
}
public void init(FilterConfig arg0) throws ServletException {
// Nothing to do
}
private static class ResettableStreamHttpServletRequest extends
HttpServletRequestWrapper {
private byte[] rawData;
private HttpServletRequest request;
private ResettableServletInputStream servletStream;
public ResettableStreamHttpServletRequest(HttpServletRequest request) {
super(request);
this.request = request;
this.servletStream = new ResettableServletInputStream();
}
public void resetInputStream() {
servletStream.stream = new ByteArrayInputStream(rawData);
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (rawData == null) {
rawData = IOUtils.toByteArray(this.request.getReader());
servletStream.stream = new ByteArrayInputStream(rawData);
}
return servletStream;
}
@Override
public BufferedReader getReader() throws IOException {
if (rawData == null) {
rawData = IOUtils.toByteArray(this.request.getReader());
servletStream.stream = new ByteArrayInputStream(rawData);
}
return new BufferedReader(new InputStreamReader(servletStream));
}
private class ResettableServletInputStream extends ServletInputStream {
private InputStream stream;
@Override
public int read() throws IOException {
return stream.read();
}
}
}
public void setAuditor(Auditor auditor) {
this.auditor = auditor;
}
}
@miladhub
Copy link

Concerning the encoding problem, this might work, but I haven't tried it:

public class ResettableStreamHttpServletRequest extends HttpServletRequestWrapper {
	private byte[] rawData;
	private HttpServletRequest request;
	private ResettableServletInputStream servletStream;

	ResettableStreamHttpServletRequest(HttpServletRequest request) {
		super(request);
		this.request = request;
		this.servletStream = new ResettableServletInputStream();
	}

	void resetInputStream() {
		servletStream.stream = new ByteArrayInputStream(rawData);
	}

	@Override
	public ServletInputStream getInputStream() throws IOException {
		if (rawData == null) {
			rawData = IOUtils.toByteArray(this.request.getInputStream());
			servletStream.stream = new ByteArrayInputStream(rawData);
		}
		return servletStream;
	}

	@Override
	public BufferedReader getReader() throws IOException {
		if (rawData == null) {
			rawData = IOUtils.toByteArray(this.request.getInputStream());
			servletStream.stream = new ByteArrayInputStream(rawData);
		}
        String encoding = getCharacterEncoding();
		if (encoding != null) {
            return new BufferedReader(new InputStreamReader(servletStream, encoding));
        } else {
            return new BufferedReader(new InputStreamReader(servletStream));
        }
	}

	private class ResettableServletInputStream extends ServletInputStream {
		private InputStream stream;

		@Override
		public int read() throws IOException {
			return stream.read();
		}
	}
}

@gargvive18
Copy link

This is awesome !!

@deepd
Copy link

deepd commented Sep 27, 2019

Thanks. The following code with some changes from your code works for me :

private static class ResettableStreamHttpServletRequest extends HttpServletRequestWrapper {

    private byte[] rawData;
    private HttpServletRequest request;
    private ResettableServletInputStream servletStream;

    private ResettableStreamHttpServletRequest(HttpServletRequest request) {
        super(request);
        this.request = request;
        servletStream = new ResettableServletInputStream();
    }

    public void resetInputStream() {
        servletStream.stream = new ByteArrayInputStream(rawData);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (rawData == null) {
            rawData = IOUtils.toByteArray(request.getReader());
            servletStream.stream = new ByteArrayInputStream(rawData);
        }
        return servletStream;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        if (rawData == null) {
            rawData = IOUtils.toByteArray(request.getReader());
            servletStream.stream = new ByteArrayInputStream(rawData);
        }
        return new BufferedReader(new InputStreamReader(servletStream));
    }
}

private static class ResettableServletInputStream extends ServletInputStream {

    private InputStream stream;

    @Override
    public int read() throws IOException {
        return stream.read();
    }

    @Override
    public boolean isFinished() {
        try {
            int available = stream.available();
            return available == 0;
        } catch (IOException e) {
            return true;
        }
    }

    @Override
    public boolean isReady() {
        return true;
    }

    @Override
    public void setReadListener(ReadListener readListener) { }
}

@baohoanGmail
Copy link

Thanks ! Really useful !!! 😄

@javaHelper
Copy link

I am calling Http POST to the REST endpoint, but making XML request, in my case 3rd party system can only make the SOAP request, now I need to remove soapenv:Envelope from the request and only pass the xml tags. I am using Spring Boot application.

Is there any way to read the request and update the POST data?

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:wer.com:dms:wsdls:organization">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:getProfile>
         <getProfileRequest>
            <patientId>160166</patientId>
         </getProfileRequest>
      </urn:getProfile>
   </soapenv:Body>
</soapenv:Envelope>

@from-Mateusz
Copy link

Thank you.
It was really helpful.
Here is my working solution, that is up-to-date with packages' versions.

private static final class CopyableHttpServletRequestWrapper extends HttpServletRequestWrapper {

    private byte[] rawData;
    private HttpServletRequest request;
    private CopyableServletInputStream servletInputStream;

    private static final class CopyableServletInputStream extends ServletInputStream {

        private InputStream stream;

        public CopyableServletInputStream(InputStream stream) {
            this.stream = stream;
        }

        @Override
        public boolean isFinished() {
            try {
                int remainingBytes = stream.available();
                return 0 == remainingBytes;
            } catch (IOException ex) {
                return false;
            }
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener listener) { }

        @Override
        public int read() throws IOException {
            return stream.read();
        }
    }

    private CopyableHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        this.request = request;
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        copyBodyDataIfNecessary();
        return servletInputStream;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        copyBodyDataIfNecessary();
        return new BufferedReader(new InputStreamReader(servletInputStream));
    }

    public void copyBodyDataIfNecessary() throws IOException {
        if(null == rawData) {
            rawData = IOUtils.toByteArray(request.getReader(), "utf-8");
            servletInputStream = new CopyableServletInputStream(new ByteArrayInputStream(rawData));
        }
    }

    public void resetStream() throws IOException {
        this.servletInputStream = new CopyableServletInputStream(new ByteArrayInputStream(rawData));
    }
}

@DuYr
Copy link

DuYr commented Aug 20, 2022

very good!!!

@pacisauctor
Copy link

Thank you every one, a little change because not working in my project by a cast wrong

private static final class CopyableHttpServletRequestWrapper extends HttpServletRequestWrapper {

        private byte[] rawData;
        private final HttpServletRequest request;
        private CopyableServletInputStream servletInputStream;

        private static final class CopyableServletInputStream extends ServletInputStream {

            private final InputStream stream;

            public CopyableServletInputStream(InputStream stream) {
                this.stream = stream;
            }

            @Override
            public boolean isFinished() {
                try {
                    int remainingBytes = stream.available();
                    return 0 == remainingBytes;
                } catch (IOException ex) {
                    return false;
                }
            }

            @Override
            public boolean isReady() {
                return true;
            }

            @Override
            public void setReadListener(ReadListener listener) {
            }

            @Override
            public int read() throws IOException {
                return stream.read();
            }
        }

        private CopyableHttpServletRequestWrapper(HttpServletRequest request) {
            super(request);
            this.request = request;
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            copyBodyDataIfNecessary();
            return servletInputStream;
        }

        @Override
        public BufferedReader getReader() throws IOException {
            copyBodyDataIfNecessary();
            return new BufferedReader(new InputStreamReader(servletInputStream));
        }

        public void copyBodyDataIfNecessary() throws IOException {
            if (null == rawData) {
                rawData = IOUtils.toByteArray(this.request.getInputStream());
                servletInputStream = new CopyableServletInputStream(new ByteArrayInputStream(rawData));
            }
        }

        public void resetStream() throws IOException {
            this.servletInputStream = new CopyableServletInputStream(new ByteArrayInputStream(rawData));
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment