-
Bug
-
Resolution: Duplicate
-
P4
-
None
-
8
-
generic
-
generic
ADDITIONAL SYSTEM INFORMATION :
I've tried on both Windows 10 and Mac OS Sonoma and I am able to see the issue.
openjdk 23.0.1 2024-10-15
OpenJDK Runtime Environment Corretto-23.0.1.8.1 (build 23.0.1+8-FR)
OpenJDK 64-Bit Server VM Corretto-23.0.1.8.1 (build 23.0.1+8-FR, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
When creating a lightweight application with the jdk.httpserver and a virtual thread executor, HttpExchange instances appear to be shared across threads causing unexpected errors and making the service unusable. (attributes having different values than they should, errors sending responses, etc)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I have provided an example code snippet that showcases the issue.
Run `java ExampleAPI.java` on the command line and view the logs.
Alternatively one can use a debugger and set a breakpoint in the filter where the attribute is set, and see that HttpExchange contains the wrong values
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
the following responses in no particular order:
jdk-http-0
jdk-http-1
jdk-http-2
ACTUAL -
Some permutation of:
<correct-thread-name>
attribute is <incorrect thread name> when should be: <correct-thread-name>
attribute is <incorrect thread name> when should be: <correct-thread-name>
---------- BEGIN SOURCE ----------
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.URI;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import com.sun.net.httpserver.Filter;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;
public class ExampleAPI {
public static void main(String[] args) throws IOException {
final Random random = new Random();
var server = HttpServer.create(new InetSocketAddress(8080), 0);
server.setExecutor(Executors.newThreadPerTaskExecutor(Thread.ofVirtual().name("jdk-http-", 0).factory()));
server
.createContext(
"/",
exchange -> {
var name = Thread.currentThread().getName();
try {
Thread.sleep(Duration.of(random.nextInt(1500, 5000), ChronoUnit.MILLIS));
} catch (InterruptedException e) {
}
var attribute = exchange.getAttribute("threadName");
if (!name.equals(attribute)) {
name = "attribute is " + attribute + " when should be: " + name;
}
var str = name.getBytes();
exchange.sendResponseHeaders(200, str.length);
exchange.getResponseBody().write(str);
})
.getFilters()
.add(new TestFilter());
server.start();
for (int i = 0; i < 3; i++) {
Thread.startVirtualThread(
() -> {
try (var is = URI.create("http://localhost:8080/travelpage").toURL().openStream(); ) {
System.err.println(
new BufferedReader(new InputStreamReader(is))
.lines()
.collect(Collectors.joining("\n")));
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
static class TestFilter extends Filter {
@Override
public void doFilter(HttpExchange exchange, Chain chain) throws IOException {
var name = Thread.currentThread().getName();
exchange.setAttribute("threadName", name);
try (exchange) {
chain.doFilter(exchange);
}
if (exchange.getResponseCode() == -1) {
exchange.sendResponseHeaders(500, -1);
}
}
@Override
public String description() {
return "test";
}
}
}
---------- END SOURCE ----------
FREQUENCY : always
I've tried on both Windows 10 and Mac OS Sonoma and I am able to see the issue.
openjdk 23.0.1 2024-10-15
OpenJDK Runtime Environment Corretto-23.0.1.8.1 (build 23.0.1+8-FR)
OpenJDK 64-Bit Server VM Corretto-23.0.1.8.1 (build 23.0.1+8-FR, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
When creating a lightweight application with the jdk.httpserver and a virtual thread executor, HttpExchange instances appear to be shared across threads causing unexpected errors and making the service unusable. (attributes having different values than they should, errors sending responses, etc)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I have provided an example code snippet that showcases the issue.
Run `java ExampleAPI.java` on the command line and view the logs.
Alternatively one can use a debugger and set a breakpoint in the filter where the attribute is set, and see that HttpExchange contains the wrong values
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
the following responses in no particular order:
jdk-http-0
jdk-http-1
jdk-http-2
ACTUAL -
Some permutation of:
<correct-thread-name>
attribute is <incorrect thread name> when should be: <correct-thread-name>
attribute is <incorrect thread name> when should be: <correct-thread-name>
---------- BEGIN SOURCE ----------
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.URI;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import com.sun.net.httpserver.Filter;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;
public class ExampleAPI {
public static void main(String[] args) throws IOException {
final Random random = new Random();
var server = HttpServer.create(new InetSocketAddress(8080), 0);
server.setExecutor(Executors.newThreadPerTaskExecutor(Thread.ofVirtual().name("jdk-http-", 0).factory()));
server
.createContext(
"/",
exchange -> {
var name = Thread.currentThread().getName();
try {
Thread.sleep(Duration.of(random.nextInt(1500, 5000), ChronoUnit.MILLIS));
} catch (InterruptedException e) {
}
var attribute = exchange.getAttribute("threadName");
if (!name.equals(attribute)) {
name = "attribute is " + attribute + " when should be: " + name;
}
var str = name.getBytes();
exchange.sendResponseHeaders(200, str.length);
exchange.getResponseBody().write(str);
})
.getFilters()
.add(new TestFilter());
server.start();
for (int i = 0; i < 3; i++) {
Thread.startVirtualThread(
() -> {
try (var is = URI.create("http://localhost:8080/travelpage").toURL().openStream(); ) {
System.err.println(
new BufferedReader(new InputStreamReader(is))
.lines()
.collect(Collectors.joining("\n")));
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
static class TestFilter extends Filter {
@Override
public void doFilter(HttpExchange exchange, Chain chain) throws IOException {
var name = Thread.currentThread().getName();
exchange.setAttribute("threadName", name);
try (exchange) {
chain.doFilter(exchange);
}
if (exchange.getResponseCode() == -1) {
exchange.sendResponseHeaders(500, -1);
}
}
@Override
public String description() {
return "test";
}
}
}
---------- END SOURCE ----------
FREQUENCY : always
- duplicates
-
JDK-8235786 Javadoc for com/sun/net/httpserver/HttpExchange.java#setAttribute is unclear
-
- Closed
-