Uploaded image for project: 'Undertow'
  1. Undertow
  2. UNDERTOW-1140

Undertow don't call onAllDataRead of ReadListener if inputStream.read is called more times

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Minor Minor
    • 2.0.0.Beta1, 1.4.19.Final
    • None
    • None
    • None

      Description:
      Undertow don't call onAllDataRead of ReadListener if inputStream.read is called more times

      Priority of this jira is blocker, because this is regression against EAP 7.0.0 and EAP 7.1.0.ER1

      Undertow works correctly, if I use 7.1.0.ER2 with Undertow from EAP 7.1.0.ER1

      Example of REST end-point with ServletInputStream and custom ReadListener:

      @Path("")
      public class ResourceInfoInjectionResource {
          protected static final Logger logger = Logger.getLogger(ResourceInfoInjectionResource.class.getName());
      
          @Context
          private HttpServletRequest request;
      
          @POST
          @Path("async")
          public void async(@Suspended final AsyncResponse async) throws IOException {
              logger.info("Start async");
              final ServletInputStream inputStream = request.getInputStream();
              final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
      
              inputStream.setReadListener(new ReadListener() {
                  @Override
                  public void onDataAvailable() throws IOException {
                      logger.info("Start onDataAvailable");
                      // copy input stream
                      byte[] buffer = new byte[4096];
                      int n1;
                      while (-1 != (n1 = inputStream.read(buffer))) {
                          outputStream.write(buffer, 0, n1);
                      }
                      logger.info("End onDataAvailable");
                  }
      
                  @Override
                  public void onAllDataRead() throws IOException {
                      logger.info("Start onAllDataRead");
                      inputStream.close();
                      outputStream.flush();
                      outputStream.close();
                      async.resume(outputStream.toString(StandardCharsets.UTF_8.name()));
                      logger.info("End onAllDataRead");
                  }
      
                  @Override
                  public void onError(Throwable t) {
                      logger.info("Start onError");
                      async.resume(t);
                      logger.info("End onError");
                  }
              });
              logger.info("End async");
          }
      }
      

      Steps to Reproduce:

      1. ./standalone.sh
      2. prepare deployment
        • download [^JBEAP-12223.zip]
        • mvn clean package
        • $JBOSS_HOME/bin/jboss-cli.sh -c
        • deploy target/jaxrs-wf.war -f
      3. curl -v --data "aaa" -X POST -H "Content-Type: text/plain" http://127.0.0.1:8080/jaxrs-wf/async

      Workaround
      Use inputStream.isReady() check. In onDataAvailable method, use this:

      while (inputStream.isReady()) {
          n1 = inputStream.read(buffer);
          outputStream.write(buffer, 0, n1);
      }

      instead of this:

      while (-1 != (n1 = inputStream.read(buffer))) {
          outputStream.write(buffer, 0, n1);
      }

      Additional info:
      This can be reproduced also by pure servlet, for example this, if you remove isReady() check.

              sdouglas1@redhat.com Stuart Douglas (Inactive)
              sdouglas1@redhat.com Stuart Douglas (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Created:
                Updated:
                Resolved: