Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is HttpServletRequest inputstream empty?

Tags:

I have this code where I read the input from a request input stream and use a JacksonMapper to convert into a POJO. Its running in a jetty 7 container with guice support.

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    try {
        RequestType requestType = mapper.readValue(req.getInputStream(), RequestType.class);
    } Catch(Exception ex) {
        ....
    }
}

However, sometimes under load the following exception is thrown. I have checked my client and I am sure its sending a valid json string. What is going wrong? Is it expected behavior for Jetty 7 under load?

java.io.EOFException: No content to map to Object due to end of input
    at org.codehaus.jackson.map.ObjectMapper._initForReading(ObjectMapper.java:2433)
    at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2385)
    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1637)
    at com.ea.wsop.user.LoginServlet.processRequest(LoginServlet.java:69)
    at com.ea.wsop.user.LoginServlet.doPost(LoginServlet.java:63)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$doPost$0(<generated>)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke(<generated>)
    at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.java:228)
    at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72)
    at com.ea.monitor.MethodExecutionTimer.invoke(MethodExecutionTimer.java:130)
    at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72)
    at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.java:52)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.doPost(<generated>)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$service$8(<generated>)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke(<generated>)
    at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.java:228)
    at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72)
    at com.ea.monitor.MethodExecutionTimer.invoke(MethodExecutionTimer.java:130)
    at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72)
    at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.java:52)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.service(<generated>)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$service$9(<generated>)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke(<generated>)
    at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.java:228)
    at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72)
    at com.ea.monitor.MethodExecutionTimer.invoke(MethodExecutionTimer.java:130)
    at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72)
    at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.java:52)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.service(<generated>)
    at com.google.inject.servlet.ServletDefinition.doService(ServletDefinition.java:263)
like image 938
Usman Ismail Avatar asked Dec 15 '11 15:12

Usman Ismail


People also ask

How do I read HttpServletRequest multiple times?

Then, we created a new implementation of the HttpServletRequestWrapper class. We overrode the getInputStream() method to return an object of ServletInputStream class. Finally, we created a new filter to pass the request wrapper object to the filter chain. So, we were able to read the request multiple times.

What is the difference between ServletRequest and HttpServletRequest?

ServletRequest provides basic setter and getter methods for requesting a Servlet, but it doesn't specify how to communicate. HttpServletRequest extends the Interface with getters for HTTP-communication (which is of course the most common way for communicating since Servlets mostly generate HTML).

What is request getInputStream ()?

ServletInputStream. getInputStream() Retrieves the body of the request as binary data using a ServletInputStream . java.lang.String.

What is an HttpServletRequest?

The HttpServletRequest provides methods for accessing parameters of a request. The type of the request determines where the parameters come from. In most implementations, a GET request takes the parameters from the query string, while a POST request takes the parameters from the posted arguments.


2 Answers

I had a similar problem running a Spring Boot application. My Spring Boot app is a simple Dispatcher servlet that reads the request body and processes it.

In my case, the client (curl) sets a content-type header of application/x-www-form-urlencoded if the curl command line uses -d {some-data} and does not set an specific content-type header via -Hcontent-type=some-other-media-type.

Inside the Apache Catalina servlet engine that Spring Boot runs, the Request class makes the following test in parseParameters()

        if (!("application/x-www-form-urlencoded".equals(contentType))) {
            success = true;
            return;
        }

For other content-type values, Request returns here, done.

However, if the content type matches application/x-www-form-urlencoded, Request continues:

    try {
       if (readPostBody(formData, len) != len) {           
            parameters.setParseFailedReason(FailReason.REQUEST_BODY_INCOMPLETE);
            return;
        }
    } catch (....)

which will consume the body. So in my case, even though my servlet does nothing other than call request.getInputStream() and try to read() from it, it is already too late - the runtime Request already reads the input and does not buffer or unread it. The only workaround is to set a different Content-Type.

The culprit is OrderedHiddenHttpMethodFilter(HiddenHttpMethodFilter).doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line 70

which is looking for the "_method" query parameter.

I was able to disable the filter by adding

@Bean
public FilterRegistrationBean registration(HiddenHttpMethodFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(filter);
    registration.setEnabled(false);
    return registration;
}

(which was used to solve another problem)

like image 63
djb Avatar answered Sep 28 '22 02:09

djb


It will be empty if it's already consumed beforehand. This will be implicitly done whenever you call getParameter(), getParameterValues(), getParameterMap(), getReader(), etc on the HttpServletRequest. Make sure that you don't call any of those kind of methods which by themselves need to gather information from the request body before calling getInputStream(). If your servlet isn't doing that, then start checking the servlet filters which are mapped on the same URL pattern.


Update: this seems to be GAE 1.5 specific. See also

  • http://code.google.com/p/googleappengine/issues/detail?id=5161
  • http://code.google.com/p/googleappengine/issues/detail?id=5898

I'm afraid that there's no solution/workaround until they get it fixed. You could try to check if it's available inside a Filter and if so, then copy and store it as request attribute. But this might affect further processing by some GAE servlet.

like image 33
BalusC Avatar answered Sep 28 '22 04:09

BalusC