Alex Rivera | Logout

Modify HttpServletRequest body

Asked 2009-03-25T11:59:38.007
14

I'm working on legacy code and need to make a patch.

The problem: an ancient application sends bad HTTP POST requests. One of the parameters is not URL encoded. I know that this parameter always comes last and I know it's name. I'm now trying to fix it on the server side which is running inside tomcat.

This parameter is not accessible via standard getParameter method of HttpServletRequest, since it's malformed. Method simply returns null. But when I manually read the whole body of request through ServletInputStream all the other parameters disappear. Looks like underlying classes can't parse contents of ServletInputStream since it's drained out.

So far I've managed to make a wrapper that reads all parameters from body and overrides all parameter access methods. But if any filter in the chain before mine will try to access any parameter, everything will break since ServletInputStream will be empty.

Can I somehow evade this problem? May be there's different approach?

To summarize, If I'll read raw request body in the filter, parameters will disappear from the request. If I read single parameter, ServletInputStream will become empty and manual processing will be impossible. Moreover, it's impossible to read malformed parameter via getParameter method.

Edit
Report

1 Answer

6

I did a more complete wrapper that allows you to still access the content in the case Content-Type is application/x-www-form-urlencoded and you already called one of the getParameterXXX methods:

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;  
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.Principal;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * This class implements the Wrapper or Decorator pattern.<br/> 
 * Methods default to calling through to the wrapped request object, 
 * except the ones that read the request's content (parameters, stream or reader).
 * <p>
 * This class provides a buffered content reading that allows the methods
 * {@link #getReader()}, {@link #getInputStream()} and any of the getParameterXXX to be     called
 * safely and repeatedly with the same results.
 * <p>
 * This class is intended to wrap relatively small HttpServletRequest instances.
 * 
 * @author pgurov
 */
public class HttpServletRequestWrapper implements HttpServletRequest {

private class ServletInputStreamWrapper extends ServletInputStream {

    private byte[] data;
    private int idx = 0;
    ServletInputStreamWrapper(byte[] data) {
        if(data == null)
            data = new byte[0];
        this.data = data;
    }
    @Override
    public int read() throws IOException {
        if(idx == data.length)
            return -1;
        return data[idx++];
    }

}

private HttpServletRequest req;
private byte[] contentData;
private HashMap<String, String[]&
answered 2009-05-07T14:13:07.517

Your Answer