Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8236596

HttpClient leaves HTTP/2 sockets in CLOSE_WAIT, when using proxy tunnel

XMLWordPrintable

    • b08
    • x86
    • os_x
    • Not verified

        ADDITIONAL SYSTEM INFORMATION :
        It happens also on linux (originally discovered in QA environment), but I am able to reproduce on a mac.

        A DESCRIPTION OF THE PROBLEM :
        This bug is VERY similar to JDK-8221395, except that this bug only happens with HTTP/2 protocol using a proxy tunnel. The JDK-8221395 test case only fixes the HTTP/1 case, so I modified it to use HTTP/2 to reproduce this issue.

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        1. git clone https://github.com/tinyproxy/tinyproxy.git # clone tinyproxy repo
        2. cd tinyproxy # go into tinyproxy checkout
        3. ./autogen.sh && ./configure && make # build tinyproxy
        4. src/tinyproxy -d -c etc/tinyproxy.conf # start tinyproxy server, it will listen on port 8888
        5. java SocketSandbox.java # start socket server (repro)
        6. telnet localhost 59090

        Wait a few minutes, for the connection to time out. You'll see tinyproxy terminate the connection to nghttp2.org, but netstat will show a leaked TUNNEL to the proxy in CLOSE_WAIT state, it will look something like this.

        tcp4 24 0 127.0.0.1.58252 127.0.0.1.8888 CLOSE_WAIT

        This will never get close()'d.

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        The socket connection to the proxy should eventually be closed.
        ACTUAL -
        The socket connection to the proxy remains in CLOSE_WAIT indefinitely until the java process ends. There is always some small amount of bytes (e.g. 24) in Recv-Q.

        ---------- BEGIN SOURCE ----------
        import java.io.PrintWriter;
        import java.net.InetSocketAddress;
        import java.net.ProxySelector;
        import java.net.ServerSocket;
        import java.net.URI;
        import java.net.http.HttpClient;
        import java.net.http.HttpClient.Version;
        import java.net.http.HttpRequest;
        import java.net.http.HttpResponse;
        import java.net.http.HttpResponse.BodyHandlers;

        public class SocketSandbox {
          public static void main(String[] args) throws Exception {
            try (var listener = new ServerSocket(59090)) {
              System.out.println("Server is running...");
              while (true) {
                try (var socket = listener.accept()) {
                  HttpClient client = HttpClient.newBuilder()
                                                .version(Version.HTTP_2)
                                                .proxy(ProxySelector.of(new InetSocketAddress("127.0.0.1", 8888)))
                                                .build();
                  HttpRequest request = HttpRequest.newBuilder(URI.create("https://nghttp2.org/httpbin/anything")).build();
                  HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
                  var out = new PrintWriter(socket.getOutputStream(), true);
                  out.println(String.format("Response HTTP status: %s", response.statusCode()));
                }
              }
            }
          }
        }

        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        This issue can be worked around by explicitly disabling the http/2 protocol via Version.HTTP_1_1. The bug does not happen at all, except with HTTP/2, and only when a proxy is used.

        FREQUENCY : always


              dfuchs Daniel Fuchs
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

                Created:
                Updated:
                Resolved: