Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

resetting a HttpRequest after calling request.getReader()

Is there a way to call the getReader() method on a HttpRequest and then "reset" the request so other calls to getReader() will not throw java.lang.IllegalStateException?

like image 586
Noam Nevo Avatar asked Jun 12 '11 14:06

Noam Nevo


2 Answers

Like other people have said, No I don't think there is a way to reset the request.

I have been in the same situation of wanting to log the content of the request in a ServletFilter before moving on. Here is a forum post that helped me figure out how to create a HttpServletRequestWrapper like Stephen C was talking about. That will store the data so you can call getReader() and getInputStream() multiple times.

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class MyRequestWrapper extends HttpServletRequestWrapper {

    private HttpServletRequest original;
    private byte[] reqBytes;
    private boolean firstTime = true;

    public MyRequestWrapper(HttpServletRequest request) {
        super(request);
        original = request;
    }

    @Override
    public BufferedReader getReader() throws IOException{

        if(firstTime)
            firstTime();

        InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(reqBytes));
        return new BufferedReader(isr);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {

        if(firstTime)
            firstTime();

        ServletInputStream sis = new ServletInputStream() {
            private int i;

            @Override
            public int read() throws IOException {
                byte b;
                if(reqBytes.length > i)
                    b = reqBytes[i++];
                else
                    b = -1;

                return b;
            }
        };

        return sis;
    }

    private void firstTime() throws IOException{
        firstTime = false;
        StringBuffer buffer = new StringBuffer();
        BufferedReader reader = original.getReader();
        String line;
        while((line = reader.readLine()) != null){
            buffer.append(line);
        }
        reqBytes = buffer.toString().getBytes();
    }
}
like image 121
bmeding Avatar answered Nov 12 '22 03:11

bmeding


The simple answer is "No".

The stream is not resettable and there's no API method that will allow you to reopen it. (And for good reason. It would require the servlet infrastructure to keep a copy of the input just in case the servlet decided to reopen the stream. That would be an unwarranted overhead.)

If you want to do this kind of thing, you will need to write your code to keep its own copy of the data. If you are implementing this in a Filter (or a Tomcat Valve) then you could create a HttpServletRequestWrapper to hide the fact that you've already read the data .... as suggested by @Vineet.

like image 11
Stephen C Avatar answered Nov 12 '22 02:11

Stephen C