Win a copy of Re-engineering Legacy Software this week in the Refactoring forum
or Docker in Action in the Cloud/Virtualization forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

OK to read the request body within a filter?

 
James Adams
Ranch Hand
Posts: 188
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 13411
Firefox Browser Redhat VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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?
 
Amit M Tank
Ranch Hand
Posts: 257
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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.
 
Ben Souther
Sheriff
Posts: 13411
Firefox Browser Redhat VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 188
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 188
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 13411
Firefox Browser Redhat VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 257
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 188
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The request body should contain XML. The servlet handles RESTful web service requests.

--James
 
Ben Souther
Sheriff
Posts: 13411
Firefox Browser Redhat VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 188
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 13411
Firefox Browser Redhat VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 188
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 13411
Firefox Browser Redhat VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 188
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 13411
Firefox Browser Redhat VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Nice job!
Thanks for posting back with your solution.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic