File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Servlets and the fly likes OK to read the request body within a filter? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Servlets
Bookmark "OK to read the request body within a filter?" Watch "OK to read the request body within a filter?" New topic
Author

OK to read the request body within a filter?

James Adams
Ranch Hand

Joined: Sep 12, 2003
Posts: 188
If I read a request's body within a servlet filter then is the body still going to be available to be read again by the servlet, or can it be read only once?

For example:

1. Filter reads the request body via getInputStream().
2. Filter performs a validation of the body data, and the validation passes.
3. The request moves along to the servlet.
4. The servlet reads the body in order to perform its processing.

In step 4 above is the body again available to the servlet, or does the filter somehow have to replace the body of the request to insure that it's again available to the servlet?

Thanks in advance for any insight.

--James
Ben Souther
Sheriff

Joined: Dec 11, 2004
Posts: 13410

It can only be read once.

What type of validation are you doing?
Once you're done validating, how are you working with the request in the servet: via request.getParameter() calls?


Java API J2EE API Servlet Spec JSP Spec How to ask a question... Simple Servlet Examples jsonf
Amit M Tank
Ranch Hand

Joined: Mar 28, 2004
Posts: 257
Its availble in the servlet. Coz the Filter is only the intercepter between the client and the servlet. It passes the same request it gets to the servlet. Hope this answers your question.


Amit Tank
Linked In
Ben Souther
Sheriff

Joined: Dec 11, 2004
Posts: 13410

Originally posted by Amit M Tank:
Its availble in the servlet. Coz the Filter is only the intercepter between the client and the servlet. It passes the same request it gets to the servlet. Hope this answers your question.


Not true.
You can read the input stream only once.
It doesn't matter if you do it from a filter or a servlet.
James Adams
Ranch Hand

Joined: Sep 12, 2003
Posts: 188
In the filter I perform authentication against the body using a signature found in the header. I pull the signature from the header and the payload from the body and then send these two pieces of data to my authenticator which makes sure that they line up. If so then I want to pass along the request as it first arrived to the filter so that the servlet can process the body accordingly.

If the body can't be read again by the servlet after it has already been read by the filter then I need to come up with a better approach -- perhaps by duplicating the body payload in the header, which would enable me to do the authentication using two header values and leaving the body unread. Unfortunately this approach would double the amount of payload data sent with each request, which seems like an inefficient way to go about it. Perhaps someone can suggest a better idea?

--James
James Adams
Ranch Hand

Joined: Sep 12, 2003
Posts: 188
What about if I create a HttpServletRequestWrapper and read the body from that? Is the original request unaffected, i.e. the body will be considered unread by the servlet which can then read the body without an IOException?

I'll give this a whirl and report back with my results.

--James
Ben Souther
Sheriff

Joined: Dec 11, 2004
Posts: 13410

Originally posted by James Adams:
In the filter I perform authentication against the body using a signature found in the header. I pull the signature from the header and the payload from the body and then send these two pieces of data to my authenticator which makes sure that they line up. If so then I want to pass along the request as it first arrived to the filter so that the servlet can process the body accordingly.

If the body can't be read again by the servlet after it has already been read by the filter then I need to come up with a better approach -- perhaps by duplicating the body payload in the header, which would enable me to do the authentication using two header values and leaving the body unread. Unfortunately this approach would double the amount of payload data sent with each request, which seems like an inefficient way to go about it. Perhaps someone can suggest a better idea?

--James


What's in the body; regular post fields or something else?
Amit M Tank
Ranch Hand

Joined: Mar 28, 2004
Posts: 257
My bad.


Originally posted by Amit M Tank:
Its availble in the servlet. Coz the Filter is only the intercepter between the client and the servlet. It passes the same request it gets to the servlet. Hope this answers your question.





Not true.
You can read the input stream only once.
It doesn't matter if you do it from a filter or a servlet.



Thanks Ben for correcting me.
James Adams
Ranch Hand

Joined: Sep 12, 2003
Posts: 188
The request body should contain XML. The servlet handles RESTful web service requests.

--James
Ben Souther
Sheriff

Joined: Dec 11, 2004
Posts: 13410

You could have your filter save the xml as a string and bind it to request scope. From there your servlet could retrieve it with request.getAttribute("xmlString");

If you already have lots of servlets reading the input stream, you could wrap the request. In the wrapper create a property that holds the xmlString. Then you could override the getInputStream method with one that returns a stream which reads the xmlString instead of the actual servletInputStream. This would be a lot more work than the first option unless you've already got tons of servlets that already count on being able to read from the inputStream.
James Adams
Ranch Hand

Joined: Sep 12, 2003
Posts: 188
I need to be able to put this filter in place transparently, i.e. no code changes whatsoever to the existing services/servlets. There may be instances in which the services are deployed without the authentication filter in front of them, so we can't have a dependency on a filter modifying the requests, since it may or may not be there when the services are deployed.

--James
Ben Souther
Sheriff

Joined: Dec 11, 2004
Posts: 13410

Originally posted by James Adams:
I need to be able to put this filter in place transparently, i.e. no code changes whatsoever to the existing services/servlets. There may be instances in which the services are deployed without the authentication filter in front of them, so we can't have a dependency on a filter modifying the requests, since it may or may not be there when the services are deployed.

--James


In that case you would want to look into the second suggestion that I made.
If you wrap the request and override the getServletInputStream, the existing servlets would have no idea that you've sent them a wrapper.
James Adams
Ranch Hand

Joined: Sep 12, 2003
Posts: 188
Thanks Ben, that's a good idea.

It looks like wrapping the request to do the first read of the payload/body works fine. The second time I read the request body I can get the payload data out with no IOException, so apparently by making a request wrapper you essentially get a duplicate request which leaves the original request alone.

In the authenticator used by my filter I read the request's payload like this:



In the JUnit test for the authenticator class I run the request through the authenticateRequest() method and then try reading the request's body a second time, and sure enough the payload is still there, no IOException, etc.



My JUnit test uses a MockHttpServletRequest from the Spring framework so perhaps that's somehow helping me out -- hopefully not and this will work the same way with real HttpServletRequests. I'll soon find out once I do a more realistic test using actual web service requests.

--James
Ben Souther
Sheriff

Joined: Dec 11, 2004
Posts: 13410

My JUnit test uses a MockHttpServletRequest from the Spring framework so perhaps that's somehow helping me out


I suspect it might.

A wrapper is nothing more than a class with the same methods.
Each method simply calls the method of the object that you're wrapping.



In your case, you would want to override the getServletInputStream method with your own. In your method, instead of returning the original inputStream (which would throw an IOException), you would return your own inputStream (you'll have to subclass servletInputStream). This stream would do nothing more than read the stored xmlString that you got from the original input stream when it was read in the filter.

This way, you're only reading the real inputStream once.
You then store it a property of the wrapper class as a string.
You pass the wrapper to the chain.doFilter method instead of the original request.
Then, your servlet will have a the wrapper.
When it calls the getServletInputStream method, it will read it just as if it were the original (it won't know the difference) but will be reading the stored xmlString instead of the original servletInputStream.
James Adams
Ranch Hand

Joined: Sep 12, 2003
Posts: 188
Thanks again Ben. Your solution is indeed the way to go about it.

Below is the code used to wrap the request:


And here's how it's being used in the filter:

Ben Souther
Sheriff

Joined: Dec 11, 2004
Posts: 13410

Nice job!
Thanks for posting back with your solution.
 
jQuery in Action, 2nd edition
 
subject: OK to read the request body within a filter?