Skip to content

Instantly share code, notes, and snippets.

@calo81
Created March 18, 2012 12:48
Show Gist options
  • Select an option

  • Save calo81/2071634 to your computer and use it in GitHub Desktop.

Select an option

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;
}
}
@sarthakbrahmbhatt
Copy link
Copy Markdown

Please its urgent,i m using spring boot .i use filter as interceptor and i got this messgae

"timestamp": 1450168414601,
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.http.converter.HttpMessageNotReadableException",
"message": "Required request body content is missing: org.springframework.web.method.HandlerMethod$HandlerMethodParameter@21779fb",
"path": "/BootMyBatisDemo/student/create"

}

@40lsgy1
Copy link
Copy Markdown

40lsgy1 commented Jan 22, 2016

It is really useful, but do I need to close the ByteArrayInputStream created in getReader method?

@gdegani
Copy link
Copy Markdown

gdegani commented Jan 22, 2016

Very useful! Thanks

@jpukg
Copy link
Copy Markdown

jpukg commented Jul 27, 2016

Very useful.

@buzz1000
Copy link
Copy Markdown

Awesome! Thanks for documenting this.

@spyhunter99
Copy link
Copy Markdown

This has potential issues with OOM if the request is too large, such as a large file upload. There should be limits on the how much content is recorded from the input stream

@nyIdeas
Copy link
Copy Markdown

nyIdeas commented Jul 17, 2017

Know its been long this thread has been stale. Much appreciate if someone can help. What is the Auditor class used here ? can you please let me know. I am writing a similar filter function to decode a header value.[At the Controller level request header param can only be retreived by getHeader() which by decode the value in some default encoding scheme.]

@Thyreach
Copy link
Copy Markdown

what about response filter, i want to catch or log all the data of webservice's response before it reach to client

someone have experience on it pleas share it bro... :)

@hkps4jj
Copy link
Copy Markdown

hkps4jj commented Apr 12, 2018

Thank you so much for this!
And hope my version is helpful to someone

public class ResponseFilter implements Filter{
    public ResponseFilter() {
        super();
    }
    
	private static class ResettableStreamHttpServletResponse extends HttpServletResponseWrapper {
		private HttpServletResponse response;
	
		public ResettableStreamHttpServletResponse(HttpServletResponse response) {
			super(response);
			this.response = response;
		}
	}
    
    
	@Override public void init(FilterConfig config) throws ServletException{}
	@Override public void destroy(){}
	
 
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException  
	{	
		ResettableStreamHttpServletResponse wrappedResponse = new ResettableStreamHttpServletResponse((HttpServletResponse) response);
		
		wrappedResponse.addHeader("Access-Control-Allow-Origin", "*");
		wrappedResponse.addHeader("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
		wrappedResponse.addHeader("Access-Control-Allow-Credentials", "true");
		wrappedResponse.addHeader("Access-Control-Allow-Methods", "GET, POST");
		
		chain.doFilter(request,  wrappedResponse);
	}
 
}

@miladhub
Copy link
Copy Markdown

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
Copy Markdown

This is awesome !!

@deepd
Copy link
Copy Markdown

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
Copy Markdown

Thanks ! Really useful !!! ๐Ÿ˜„

@javaHelper
Copy link
Copy Markdown

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
Copy Markdown

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
Copy Markdown

DuYr commented Aug 20, 2022

very good!!!

@pacisauctor
Copy link
Copy Markdown

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