https://bz.apache.org/bugzilla/show_bug.cgi?id=62605

            Bug ID: 62605
           Summary: Async servlet over HTTP/2 setReadListener does not
                    work if post request data arrives much later than
                    headers
           Product: Tomcat 9
           Version: 9.0.10
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Servlet
          Assignee: dev@tomcat.apache.org
          Reporter: zdap...@google.com
  Target Milestone: -----

[Previously I filed an invalid bug
https://bz.apache.org/bugzilla/show_bug.cgi?id=62569 , which was not producible
with telnet client over HTTP/1.1, sorry about that]

The issue is reproducible when using client over HTTP/2

Steps to reproduce:

1. Enable HTTP/2 for Tomcat
<Connector port="8080" protocol="HTTP/1.1">
    <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol"/>
</Connector>

2. Deploy the following Servlet (basically the same as the tutorial example
https://javaee.github.io/tutorial/servlets013.html with more debug info and
fixing reading EOS problem)

@WebServlet(urlPatterns={"/asyncioservlet"}, asyncSupported=true)
public class AsyncIOServlet extends HttpServlet {
  @Override
  public void doPost(HttpServletRequest request,
      HttpServletResponse response)
      throws IOException {
    final AsyncContext acontext = request.startAsync();
    final ServletInputStream input = request.getInputStream();

    System.out.println("Set listener");
    input.setReadListener(
        new ReadListener() {
          byte buffer[] = new byte[4 * 1024];
          StringBuilder sbuilder = new StringBuilder();

          @Override
          public void onDataAvailable() {
            System.out.println("onDataAvailable");
            try {
              do {
                int length = input.read(buffer);
                System.out.println("length = " + length);
                if (length == -1) {
                  return;
                }
                sbuilder.append(new String(buffer, 0, length));
              } while (input.isReady());
            } catch (IOException ex) {
              ex.printStackTrace();
            } catch (RuntimeException e) {
              e.printStackTrace();
            }
          }

          @Override
          public void onAllDataRead() {
            System.out.println("onAllDataRead");
            try {
              acontext.getResponse().getWriter().write("...the response...");
            } catch (IOException ex) {
              ex.printStackTrace();
            }
            acontext.complete();
          }

          @Override
          public void onError(Throwable t) {
            t.printStackTrace();
          }
        });
    System.out.println("Set listener - done");
  }

3. Make sure the curl command supports HTTP/2
$ curl --version
curl 7.60.0
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL
libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL

4. Run the following curl command 
$ (sleep 2s; echo "hello world") | curl --http2 --http2-prior-knowledge
http://localhost:8080/asyncioservlet -H "content-type: text/plain" -T - -X POST

(for TLS use the following command, I didn't check the TLS case though)
$ (sleep 2s; echo "hello world") | curl --http2 --http2-prior-knowledge
https://localhost:8443/asyncioservlet -H "content-type: text/plain" -T - -X
POST -k

5. The client will hang, and check the server log "logs/catalina.out"
Set listener
Set listener - done

no sign of ReadListener callbacks invoked.

6. Without the sleep, the client does not hang, and ReadListener callbacks get
invoked.

Deploying the same servlet to Glassfish/Undertow/Jetty will not see this
problem.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to