eclipse-ee4j / eclipse-ee4j/jersey

Deadlock when LoggingFeature with PAYLOAD_ANY is registered on the client with JdkConnectorProvider

Open
#6,100 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
730
Forks
382
PR merge metrics
No merged PRs in 30d

Description

Hello,

i ran into a hard hang when combining `JdkConnectorProvider` with `LoggingFeature(Verbosity.PAYLOAD_ANY)` on the Jersey client. The client submits an async request but the `Future.get()` never returns — the process hangs indefinitely.

I couldn't find any hint whether this problem is known or not. Am I missing sth?

Thanks in advance

My environment is:
- Jersey: 3.1.9
- Java: 21.0.6 (OpenJDK)
- OS: Windows 11
- Connector: `jersey-jdk-connector`

Steps to reproduce (a threaddump is attached):

[threaddump-1783593915981.tdump.txt](https://github.com/user-attachments/files/29845199/threaddump-1783593915981.tdump.txt)

```java
import com.sun.net.httpserver.HttpServer;
import jakarta.ws.rs.core.Response;
import org.glassfish.jersey.client.JerseyClientBuilder;
import org.glassfish.jersey.jdk.connector.JdkConnectorProvider;
import org.glassfish.jersey.logging.LoggingFeature;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Reproducer {

public static void main(String[] args) throws Exception {
byte[] body = "Hello".getBytes(StandardCharsets.UTF_8);

HttpServer server = HttpServer.create(new InetSocketAddress("localhost", 0), 0);
server.createContext("/test", exchange -> {
exchange.getResponseHeaders().set("Content-Type", "text/plain");
exchange.sendResponseHeaders(200, body.length);
exchange.getResponseBody().write(body);
exchange.getResponseBody().close();
});
server.setExecutor(null);
server.start();

String url = "http://localhost:" + server.getAddress().getPort() + "/test";

var client = (org.glassfish.jersey.client.JerseyClient)
JerseyClientBuilder.newBuilder()
.register(new LoggingFeature(
Logger.getLogger("test"),
Level.INFO,
LoggingFeature.Verbosity.PAYLOAD_ANY,
65535))
.build();

client.getConfiguration().connectorProvider(new JdkConnectorProvider());

System.out.println("Sending request ...");
Future future = client.target(url).request().buildGet().submit();

try {
Response response = future.get(10, TimeUnit.SECONDS);
System.out.println("OK: " + response.readEntity(String.class));
} catch (java.util.concurrent.TimeoutException e) {
System.err.println("DEADLOCK: timed out after 10s.");
}

client.close();
server.stop(0);
}
}
```

The code does not hang when:
- the line `client.getConfiguration().connectorProvider(new JdkConnectorProvider());` is comment out
- instead of `LoggingFeature.Verbosity.PAYLOAD_ANY` the value `LoggingFeature.Verbosity.HEADERS_ONLY` is used

Best Regards,

Contributor guide

Open the contributing guide

Research direction

Start by running the supplied Java reproducer with JdkConnectorProvider and LoggingFeature.Verbosity.PAYLOAD_ANY, then inspect the attached threaddump and the Future.get() wait. Compare it with HEADERS_ONLY and the default connector. Done means the asynchronous request completes without hanging in the PAYLOAD_ANY and JdkConnectorProvider combination.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.