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

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

    Details

    • Subcomponent:
    • Resolved In Build:
      b08
    • CPU:
      x86
    • OS:
      os_x

      Description

      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


        Attachments

          Activity

            People

            • Assignee:
              dfuchs Daniel Fuchs
              Reporter:
              webbuggrp Webbug Group
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: