JDK-8326498 : java.net.http.HttpClient connection leak using http/2
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 21.0.2
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2024-02-12
  • Updated: 2025-06-30
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.
Other
tbdUnresolved
Related Reports
Relates :  
Relates :  
Description
A DESCRIPTION OF THE PROBLEM :
HttpClient doesn't release tcp connections when using http/2 when receives goaway from server. 
It works on java17. Didn't try other version. 

REGRESSION : Last worked in version 17.0.10

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create HttpClient with http/2. And send requests with a BIG interval, bigger than the sever idle timeout. 
So that the server will send goaway to terminate the connection. 
Check open connections with `netstat -n | grep "0  127.0.0.1.8080" | wc -l` and the number of connections is increasing over time. 




EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The number of connections doesn't increase over time. 
ACTUAL -
The number of connections increases over time. 

---------- BEGIN SOURCE ----------
package com.example.demo.httpclient;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.SecureRandom;
import java.time.Duration;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

public class HttpClientTest {
    private static final AtomicInteger counter = new AtomicInteger(0);


    public static void main(String[] args) {
        URI requestUri = URI.create("https://localhost:8080/hello");
        String requestJson = """
            {
                "message": "This is the message"
            }
            """;

        HttpClient httpClient = getHttpClient();


        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(100);

        IntStream.range(0, 100)
                .forEach(c -> executor.scheduleAtFixedRate(() -> {
                    try {
                        HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
                                .header("Content-Type", "application/json")
                                .POST(HttpRequest.BodyPublishers.ofString(requestJson))
                                .uri(requestUri);

                        HttpRequest request = requestBuilder.build();

                        httpClient.send(request, HttpResponse.BodyHandlers.ofString());
                        counter.getAndIncrement();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, 0, 50000, TimeUnit.MILLISECONDS));


        while (true) {
            try {
                Thread.sleep(5000);
                System.out.println("Sent: " + counter.get());

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static HttpClient getHttpClient() {
        System.setProperty("jdk.internal.httpclient.disableHostnameVerification", "true");

        try {
            HttpClient.Builder builder = HttpClient.newBuilder();
            Duration connectionTimeout = Duration.ofSeconds(100);
            builder.connectTimeout(connectionTimeout);
            builder.version(HttpClient.Version.HTTP_2);
            builder.followRedirects(HttpClient.Redirect.NORMAL);

            SSLContext selectedSslContext;
            selectedSslContext = SSLContext.getInstance("SSL");
            selectedSslContext.init(null, TRUST_ALL_CERTS, new SecureRandom());

            builder.sslContext(selectedSslContext);

            HttpClient httpClient = builder.build();
            return httpClient;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private final static TrustManager[] TRUST_ALL_CERTS = new TrustManager[]{
            new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkClientTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                }
                public void checkServerTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                }
            }
    };

}

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

FREQUENCY : always



Comments
Please below response from reporter : It happened on both our production env and my local mac. #On my local, the java version: ``` Java version: 21.0.2+13-58, vendor: Oracle Corporation ``` CPU: Apple M2 Max, Os version: macOs 13.5. #And production jvm version: ``` openjdk version "21" 2023-09-19 LTS OpenJDK Runtime Environment Corretto-21.0.0.35.1 (build 21+35-LTS) OpenJDK 64-Bit Server VM Corretto-21.0.0.35.1 (build 21+35-LTS, mixed mode, sharing) ``` OS info: Linux ip-172-27-33-252.ec2.internal 4.14.326-245.539.amzn2.x86_64 #1 SMP Tue Sep 26 09:59:02 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux I pushed my code to github, including the http/2 server and the client code I am using to demo the issue: https://urldefense.com/v3/__https://github.com/liangde-chen/java-21-httpclient-connection-leak-demo__;!!ACWV5N9M2RV99hQ!Mw-1XpDjWV_q8jZURyv7OXmOC-2Oh1lwNbEufg43Ksq-KpwWSQpEl0ELfMe4IQbxHGMLdkREWrFQ6WJn5hU$ Run `DemoApplication.java` to start the http/2 server and the `HttpClientTest` to start the client.
23-02-2024

Thanks, [~jpai]. I requested a reporter to provide this details. I will update the ticket as soon as this information is received.
23-02-2024

Hello Raghu [~rkale], I'll assign this to myself to see if I can reproduce this. The fact that the reporter states that this is reproducible on some version but not on other seems to indicate this will need some additional investigation. Can we ask the reporter what specific OS they are running this on and which server vendor/version they are testing this against?
23-02-2024

Observation: After two hours of executing the shared program, I couldn't observed on JDK 17.0.10 or JDK 21.0.2.
22-02-2024