JDK-8236596 : HttpClient leaves HTTP/2 sockets in CLOSE_WAIT, when using proxy tunnel
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 13
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: os_x
  • CPU: x86
  • Submitted: 2019-12-30
  • Updated: 2025-06-10
  • Resolved: 2020-01-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11 JDK 15
11.0.14Fixed 15 b08Fixed
Related Reports
Relates :  
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



Comments
Fix Request [11u]: Mike Lothian reports this being also hit on 11u with this patch fixing the issue: https://twitter.com/FireBurn/status/1453679927824461824 Patch applies cleanly, PR filed.
10-11-2021

Informed the submitter download the fix from https://jdk.java.net/15/ and verify it.
15-07-2020

URL: https://hg.openjdk.java.net/jdk/jdk/rev/26dbc9b2c8dc User: dfuchs Date: 2020-01-24 17:58:24 +0000
24-01-2020

A simple work around for this issue can be to reuse the HttpClient, if that's possible (single user application).
23-01-2020

The issue seems to be that Http2ClientImpl::stop calls Http2Connection::close which sends a GOAWAY frame to the server but never actually closes the underlying TCP connection.
20-01-2020

I have been able to reproduce when sending multiple requests. I see couple of connections where one end is in FIN_WAIT_2 and the other in CLOSE_WAIT: tcp4 0 0 127.0.0.1.8888 127.0.0.1.65326 FIN_WAIT_2 tcp4 24 0 127.0.0.1.65326 127.0.0.1.8888 CLOSE_WAIT This only happens however if one new client is created for each new request. If you take the creation of the HttpClient out of the loop the problem disappears.
20-01-2020