users@jersey.java.net

Re: Inconsistent behavior with POST

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Thu, 20 Mar 2008 11:52:38 +0100

Hi Tim,

Tim McCune wrote:
> I'll preface this with the fact that I'm still using version 0.4, so if
> a good answer is "already fixed in a newer version", then awesome.
>

I can reproduce it in the trunk.


> I'm running into problems using POST with my resources. I just want to
> get at application/x-www-form-urlencoded name/value pairs. If I pass a
> FormURLEncodedProperties parameter to my resource method, that seems to
> work, until I introduce a filter or a Tomcat valve (e.g. request dumper)
> somewhere in the processing chain before it, that reads from the input
> stream. Jersey doesn't seem to reset the stream (not sure if that's
> even possible), and so I end up with an empty FormURLEncodedProperties.
>

For the most part Jersey is container independent and tries to make as
minimal assumptions as possible on the container used to get the HTTP
meta-data and request entity. Which is why it always uses the input
stream for processing a request entity.

The problem is the Tomcat Request Dumper Valve has side effects that
result in the processing of the input stream. In general if any
filter/valve has side effects that affect the input stream then it can
potentially break many types of servlet or another type of filter. For
example, if a logging filter was configured to occur after the Tomcat
Request Dumper Valve and that filter wants to dump the request entity as
bytes, or a filter that needs to verify the signature of the request entity.


> Another approach that I've tried is adding a
> @Resource private HttpServletRequest _request;
> field to my resource, and then just reading the request parameters
> directly from that inside my resource method. That one's a bit more
> interesting, as it seems to work exactly backwards of the other
> approach. :) Jersey looks to be wrapping the servlet request and
> causing some problems. If I don't touch the servlet request before it
> gets to Jersey, I get an empty set of parameters from the request.
> Then, to try to debug it, I added this line:
> System.out.println("------------JERSEY SERVLET: " +
> req.getParameterMap());
> to the beginning of the Jersey servlet's service() method, and after
> that I was always able to get my parameters from the request.
>
> I didn't dig too deeply into the code, but the overall problem seems to
> be around the way that Jersey wants to read the parameters directly from
> the servlet input stream, instead of reading them from the actual
> servlet request. It's making too many assumptions about the
> environment.
>

The reason is because Jersey reads the input stream and this means
ServletRequest.getParameter* will not function, from the JavaDoc:

   "If the parameter data was sent in the request body, such as occurs
    with an HTTP POST request, then reading the body directly via
    getInputStream() or getReader() can interfere with the execution of
    this method."

But of course if set up the valve it will work because the valve gets
the parameters.


> Is there a good recommended, reliable way to read posted,
> form-urlencoded parameters in a Jersey resource?
>

Two possible immediate solutions:

1) Use a filter/valve that does not have side-effects; or

2) Try the following if you need to use a filter/valve that has
    side-effects:

    @Path("/") public class FormResource {
      @Resource HttpServletRequest request;

      @POST public String formPost() {
        return request.getParameterMap();
      }
    }

I recommend the former if possible. The latter works because the
"formPost" method does not have any request entity parameter does does
not consume the input stream.

I might be able to develop a special form processing message body reader
  that is used with servlet that works around potential side-effects of
filters but i need to think more about it...

Paul.

-- 
| ? + ? = To question
----------------\
    Paul Sandoz
         x38109
+33-4-76188109