Modify HttpServletRequest body

46,658

Solution 1

Solution I've found:

It's not enough to just redefine parameter accessing methods. Several things must be done.

  1. A filter is needed where request will be wrapped.
  2. A custom HttpRequestWrapper is needed with all parameter access methods overridden. Request body should be parsed in constructor and stored as a field.
  3. getInputStream and getReader methods should be redefined as well. They return values depend on the stored request body.
  4. Custom class extending ServletInputStream is required since this one is abstract.

This 4 combined will allow you to use getParameter without interference with getInputStream and getReader methods.

Mind that manual request parameter parsing may get complicated with multipart requests. But that's another topic.

To clarify, I redefined parameter accessing methods because my request was damaged as stated in the question. You may not need that.

Solution 2

Rather than overriding methods, why don't you install a servlet filter which rewrites the request?

Jason Hunter has a pretty good article on filters.

Solution 3

I wanted to post this as a comment, but I do not have enough rep. Your solution is insufficient in that ServletInputStreamWrapper will return negative integers. For instance, mock a request with input encoding UTF-16, either big or little endian. The input may start with the Byte Order Mark indicating endianess, and when testing my statement please construct the mock request content to do so. http://en.wikipedia.org/wiki/Byte_order_mark#UTF-16 Either of these BOMs contains a 0xFF byte. Since java has no unsigned byte, this 0xFF is returned as a -1. To work around this, just change the read function like so

    public int read() throws IOException {
        if (index == data.length) {
            return -1;
        }
        return data[index++] & 0xff;
    }

I somewhat like your solution because it works well with Spring. At first I tried to eliminate some of the delegation code you wrote by extending from HttpServletRequestWrapper. However, Spring does something interesting: when it encounters a request of type ServletRequestWrapper it unwraps it, calling getRequest(). Problem being that my getRequest() method, as copied from your code, returns a new class that extends from HttpServletRequestWrapper... rinse and repeat infinitely. So it's sad to say, chalk up a win for not using interfaces!

Solution 4

You could write your own Servlet Filter and hopefully ensure that it appears first in the chain. Then wrap the ServletRequest object in something that will handle the re-writing where needed. Have a look at the Programming Customized Requests and Responses section of http://java.sun.com/products/servlet/Filters.html

------ Update ------

I must be missing something. You say you can read the request body and read the parameters yourself. Couldn't you then ensure your filter is first, wrap the ServletRequest object, read, process and store the parameters, pass your request object up the chain and offer the parameters you stored instead of the original ones?

Share:
46,658
clorz
Author by

clorz

Updated on August 31, 2020

Comments

  • clorz
    clorz almost 4 years

    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.

  • clorz
    clorz over 15 years
    I can read all parameters except broken one. I can only read broken parameter via ServletInputStream. When I use input stream, all other parameters disappear. If I parse all parameters from input stream, sometimes servlets later in the chain break. It's complicated =)
  • Illarion Kovalchuk
    Illarion Kovalchuk over 12 years
    Could you please provide more details regarding manual request parameter parsing? Isn't it enough to just override getInputStream and getReader?
  • clorz
    clorz over 12 years
    Ok, I looked it up. I had to manyally parse parameters because one of them was damaged as described in a question. If they are fine in your request, there's no need to do that.
  • Frans
    Frans over 10 years
    Do you have sample code? Having to overwrite getParameter() and friends worries me, because I'd rather leave that to the servlet container. In my case all parameters are readable, but I need to read and cache the input stream before my servlet calls getParameter(). And HttpServletRequestWrapper's getParameter() just cals the original request's getParameter() which only knows about the original requests's input stream (which is empty by then).
  • DanielKWinsor
    DanielKWinsor over 10 years
    I also found another problem, where req.getContentType().equals("application/x-www-form-urlencod‌​ed") should be req.getContentType().startsWith("application/x-www-form-urle‌​ncoded") As it turns out, Firefox can send "application/x-www-form-urlencoded; charset=UTF-8" whereas Chrome and IE only send "application/x-www-form-urlencoded"
  • PAA
    PAA over 4 years
    @clorz - Could you please share the sample code? I really need this.
  • PAA
    PAA over 4 years
    I am not still sure yet, how to read http post data and update post data and set it back to request, if I read request.getReader(), then again I cant read it, how can we do this ?
  • Jon Skeet
    Jon Skeet over 4 years
    @PAA: I suggest you ask a new question with all the details rather than adding comments on this not-entirely-related question that is over 10 years old.