Why is HttpServletRequest inputstream empty?

23,632

Solution 1

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

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.

Solution 2

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)

Solution 3

I had the problem that my request InputStream was always empty with Jetty 6.1.15, and found out that it was caused by a missing or wrong "Content-Type" header.

I generate the requests in another Java program with HttpUrlConnection. When I did not set the Content-Type header explicitly, the InputStream returned by request.getInputStream() in the receiving program was always empty. When I set the content type to "binary/octet-stream", the InputStream of the request contained the correct data.

The only method that is called on the request object before getInputStream() is getContentLength().

Solution 4

I was using mod_jk 1.2.39 which had a bug that caused this issue. After updating to 1.2.40 it started working.

Share:
23,632
Usman Ismail
Author by

Usman Ismail

Updated on July 18, 2022

Comments

  • Usman Ismail
    Usman Ismail almost 2 years

    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)
    
  • Usman Ismail
    Usman Ismail over 12 years
    There is nothing in my code consuming it, but Guice might be doing something under the hood.
  • BalusC
    BalusC over 12 years
    You could try to use getQueryString() instead, I'm only not sure how GAE acts on "syntactically invalid" query strings.
  • Usman Ismail
    Usman Ismail over 12 years
    Its a post request and I am pulling the data from there.
  • BalusC
    BalusC over 12 years
    You never know on an odd beast as GAE. At least, I googled using "gae request getinputstream" and found several similar problems and bug reports. I included it in my answer.
  • Usman Ismail
    Usman Ismail over 12 years
    This is running on an ec2 instance in jetty 7 not app engine.
  • BalusC
    BalusC over 12 years
    Perhaps EC2 suffers same problems and perhaps it's after all Jetty specific. GAE also uses Jetty under covers.
  • Usman Ismail
    Usman Ismail over 12 years
    Here is the exact issue I am facing. code.google.com/p/google-sitebricks/issues/detail?id=45
  • John Yeary
    John Yeary about 12 years
    The original remarks are correct from BalusC. For further information please look at the Servlet API 3.0 Specification section 3.1 and 3.1.1 which details the behavior noted above.
  • djb
    djb almost 8 years
    See also my answer below stackoverflow.com/a/34280561/21352 which works around another case where Apache Catalina (Tomcat) consumes the input if the Content-Type is application/x-www-form-urlencoded (even though the controller does not call getParameter(), getParameterValues(), getParameterMap(), getReader() etc.) and how to work around that.
  • Bằng Rikimaru
    Bằng Rikimaru about 7 years
    This is a great discovery, or otherwise, HttpServletRequest in Post handler of controller always returns empty without reason.
  • emerino
    emerino almost 7 years
    This was a tough one, 2 hours trying to find out why post entity was empty. Thanks a lot!