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.
Solution I've found:
It's not enough to just redefine parameter accessing methods. Several things must be done.
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.
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
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!
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:
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.
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?