glassfish
  1. glassfish
  2. GLASSFISH-20482

Unable to read from HttpServletRequest.getInputStream when there are session beans in the web app

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Blocker Blocker
    • Resolution: Works as designed
    • Affects Version/s: 4.0_b87_RC3
    • Fix Version/s: None
    • Component/s: None
    • Labels:
      None
    • Environment:

      Mac OSX, JDK 1.7.0_21, Glassfish 4.0_b88_2013-05-06

      Description

      Have tested with and without the patch from GLASSFISH-20449. Simple test case:

      Servlet.processRequest:

      System.out.println(request.getInputStream().available());

      Client:

      HttpURLConnection uc = (HttpURLConnection) new URL("http://localhost:8080/WebApplication3/NewServlet").openConnection();
      uc.setDoOutput(true);

      OutputStream os = uc.getOutputStream();
      os.write("Test\r\n".getBytes());
      os.flush();

      What happens is that normally the servlet will print 6 to the console - but if you add an EJB session bean to the app it prints 0. Trying to read from the servlet input stream causes EOFException.

      GLASSFISH-20449 is about taglibs and session beans, and this seems similar - however the patch I tried for the taglib bug did not fix this problem.

        Activity

        Hide
        Peter Salomonsen added a comment -

        OK I see this now - it has never been a requirement in earlier versions - so I thought it was a bug. Thanks for clarifying the issue.

        Show
        Peter Salomonsen added a comment - OK I see this now - it has never been a requirement in earlier versions - so I thought it was a bug. Thanks for clarifying the issue.
        Hide
        Shing Wai Chan added a comment -

        There is an issue in the given test case.
        In ServletClientMain.java, the content-type is not specified. In this case, the HttpURLConnection will have a default content-type: Content-type: application/x-www-form-urlencoded.
        In this case, the payload is read as parameter. Hence, there will be no data to read through request.getInputStream().read().

        But if we specify a content-type in ServletClientMain.java as follows:

        uc.setRequestProperty("Content-type", "text/plain; charset=utf-8");
        

        Then you can read the data as expected.
        So, this is a test case issue.

        Show
        Shing Wai Chan added a comment - There is an issue in the given test case. In ServletClientMain.java, the content-type is not specified. In this case, the HttpURLConnection will have a default content-type: Content-type: application/x-www-form-urlencoded. In this case, the payload is read as parameter. Hence, there will be no data to read through request.getInputStream().read(). But if we specify a content-type in ServletClientMain.java as follows: uc.setRequestProperty( "Content-type" , "text/plain; charset=utf-8" ); Then you can read the data as expected. So, this is a test case issue.
        Hide
        Peter Salomonsen added a comment -

        I see that I probably misguided you when using .available() in the test case. You're right when you say this is an estimate, and the test case proves no bug in itself.

        But the original cause for reporting this wasn't that available() showed zero in the presence of session beans - it was that I was not able to read from the input stream at all. I've modified my testcase to show this - I've added "POST" as you said (which I also had in my original app where I first discovered this) - and the servlet now tries to read from the stream.

        You see that in the presence of the session bean, there is no data to read from the stream - while when removing it - you can read the text submitted from the client.

        Sorry for the confusion I made here - and I hope that you can reopen the issue so that I don't have to post it again. (I've sent you the updated test case by email)

        Show
        Peter Salomonsen added a comment - I see that I probably misguided you when using .available() in the test case. You're right when you say this is an estimate, and the test case proves no bug in itself. But the original cause for reporting this wasn't that available() showed zero in the presence of session beans - it was that I was not able to read from the input stream at all. I've modified my testcase to show this - I've added "POST" as you said (which I also had in my original app where I first discovered this) - and the servlet now tries to read from the stream. You see that in the presence of the session bean, there is no data to read from the stream - while when removing it - you can read the text submitted from the client. Sorry for the confusion I made here - and I hope that you can reopen the issue so that I don't have to post it again. (I've sent you the updated test case by email)
        Hide
        Shing Wai Chan added a comment -

        In order to consume the data in server side, one should use POST. We should add the following line in ServletClientMain.java:

            uc.setRequestMethod("POST");
        

        In my local environment, I notice that the value of #available is 0, independent of presence of EJBs. And in another environment, we get the correct value. The reason is that HttpURLConnection sends the headers and payload in two chunk which may arrives with latency. If the payload is delay (or the server is fast enough) while IO layer process the data, then we get a zero payload in this case.

        In JDK 7 javadoc of InputStream#available, we have:

        Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream. The next invocation might be the same thread or another thread. A single read or skip of this many bytes will not block, but may read or skip fewer bytes.
        
        Note that while some implementations of InputStream will return the total number of bytes in the stream, many will not. It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.
        

        Since this is an estimate value, it is not a bug.

        Show
        Shing Wai Chan added a comment - In order to consume the data in server side, one should use POST. We should add the following line in ServletClientMain.java: uc.setRequestMethod( "POST" ); In my local environment, I notice that the value of #available is 0, independent of presence of EJBs. And in another environment, we get the correct value. The reason is that HttpURLConnection sends the headers and payload in two chunk which may arrives with latency. If the payload is delay (or the server is fast enough) while IO layer process the data, then we get a zero payload in this case. In JDK 7 javadoc of InputStream#available, we have: Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream. The next invocation might be the same thread or another thread. A single read or skip of this many bytes will not block, but may read or skip fewer bytes. Note that while some implementations of InputStream will return the total number of bytes in the stream, many will not. It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream. Since this is an estimate value, it is not a bug.
        Hide
        Peter Salomonsen added a comment -

        I've sent a netbeans test case project to your email. The test case project contains a main class ServletClientMain that you should run after deploying the web app. This will create an URLConnection to the servlet and write some bytes to it. In return the server will respond the number of bytes in the input stream - and you will see that this is zero when the session bean is present and 8 if you remove the stateless annotation of the session bean (SessionBean.java).

        Show
        Peter Salomonsen added a comment - I've sent a netbeans test case project to your email. The test case project contains a main class ServletClientMain that you should run after deploying the web app. This will create an URLConnection to the servlet and write some bytes to it. In return the server will respond the number of bytes in the input stream - and you will see that this is zero when the session bean is present and 8 if you remove the stateless annotation of the session bean (SessionBean.java).
        Hide
        Shing Wai Chan added a comment -

        I do not see the above code in the test case for GLASSFISH-20449. Can you attach a test case here?

        Show
        Shing Wai Chan added a comment - I do not see the above code in the test case for GLASSFISH-20449 . Can you attach a test case here?

          People

          • Assignee:
            Shing Wai Chan
            Reporter:
            Peter Salomonsen
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: