diff --git a/frameworks/robaho-httpserver/Dockerfile b/frameworks/robaho-httpserver/Dockerfile
new file mode 100644
index 00000000..b8e38084
--- /dev/null
+++ b/frameworks/robaho-httpserver/Dockerfile
@@ -0,0 +1,13 @@
+FROM maven:3.9-eclipse-temurin-21 AS build
+WORKDIR /app
+COPY pom.xml .
+RUN mvn dependency:go-offline -q
+COPY src ./src
+RUN mvn package -DskipTests -q
+
+FROM eclipse-temurin:21-jre
+WORKDIR /app
+COPY --from=build /app/target/robaho-httpserver-1.0.0.jar app.jar
+COPY --from=build /app/target/libs ./libs
+EXPOSE 8080
+ENTRYPOINT ["java", "-Drobaho.net.httpserver.nodelay=true", "-jar", "app.jar"]
diff --git a/frameworks/robaho-httpserver/meta.json b/frameworks/robaho-httpserver/meta.json
new file mode 100644
index 00000000..816a0c53
--- /dev/null
+++ b/frameworks/robaho-httpserver/meta.json
@@ -0,0 +1,23 @@
+{
+ "display_name": "robaho-httpserver",
+ "language": "Java",
+ "type": "production",
+ "engine": "robaho-httpserver",
+ "description": "High-performance Java HTTP server using robaho/httpserver, a drop-in replacement for com.sun.net.httpserver with improved throughput.",
+ "repo": "https://github.com/robaho/httpserver",
+ "enabled": true,
+ "tests": [
+ "baseline",
+ "pipelined",
+ "limited-conn",
+ "json",
+ "json-comp",
+ "upload",
+ "static",
+ "async-db",
+ "fortunes",
+ "api-4",
+ "api-16"
+ ],
+ "maintainers": []
+}
diff --git a/frameworks/robaho-httpserver/pom.xml b/frameworks/robaho-httpserver/pom.xml
new file mode 100644
index 00000000..1c6300b3
--- /dev/null
+++ b/frameworks/robaho-httpserver/pom.xml
@@ -0,0 +1,74 @@
+
+
+ 4.0.0
+
+ com.httparena
+ robaho-httpserver
+ 1.0.0
+ jar
+
+
+ 21
+ ${java.version}
+ ${java.version}
+
+
+
+
+ io.github.robaho
+ httpserver
+ 1.0.25
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.19.0
+
+
+ io.pebbletemplates
+ pebble
+ 3.2.4
+
+
+ io.vertx
+ vertx-pg-client
+ 5.0.0.CR7
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.4.2
+
+
+
+ com.httparena.Main
+ true
+ libs/
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 3.7.1
+
+
+ copy-dependencies
+ package
+ copy-dependencies
+
+ ${project.build.directory}/libs
+
+
+
+
+
+
+
diff --git a/frameworks/robaho-httpserver/src/main/java/Main.java b/frameworks/robaho-httpserver/src/main/java/Main.java
new file mode 100644
index 00000000..af939b96
--- /dev/null
+++ b/frameworks/robaho-httpserver/src/main/java/Main.java
@@ -0,0 +1,249 @@
+package com.httparena;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.pebbletemplates.pebble.PebbleEngine;
+import io.pebbletemplates.pebble.template.PebbleTemplate;
+import io.vertx.pgclient.PgBuilder;
+import io.vertx.pgclient.PgConnectOptions;
+import io.vertx.sqlclient.*;
+import robaho.net.httpserver.HttpServer;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+
+import java.io.*;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.concurrent.Executors;
+import java.util.zip.GZIPOutputStream;
+
+public class Main {
+
+ static final ObjectMapper mapper = new ObjectMapper();
+ static final PebbleEngine pebble = new PebbleEngine.Builder().autoEscaping(true).build();
+ static final PebbleTemplate fortunesTemplate = pebble.getTemplate("templates/fortunes.html");
+ static List- dataset = List.of();
+ static Pool pgPool;
+
+ public static void main(String[] args) throws Exception {
+ loadDataset();
+ initPostgres();
+
+ HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
+ server.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
+
+ server.createContext("/baseline11", new BaselineHandler());
+ server.createContext("/baseline2", new BaselineHandler());
+ server.createContext("/pipeline", new PipelineHandler());
+ server.createContext("/json/", new JsonHandler());
+ server.createContext("/upload", new UploadHandler());
+ server.createContext("/static/", new StaticHandler());
+ if (pgPool != null) {
+ server.createContext("/async-db", new AsyncDbHandler());
+ server.createContext("/fortunes", new FortunesHandler());
+ }
+
+ server.start();
+ }
+
+ static void loadDataset() {
+ String path = System.getenv().getOrDefault("DATASET_PATH", "/data/dataset.json");
+ try {
+ dataset = mapper.readValue(new File(path), new TypeReference<>() {});
+ } catch (Exception ignored) {}
+ }
+
+ static void initPostgres() {
+ String url = System.getenv("POSTGRES_URL");
+ if (url == null || url.isEmpty()) return;
+ try {
+ URI uri = new URI(url);
+ String[] userInfo = uri.getUserInfo().split(":");
+ PgConnectOptions connectOptions = new PgConnectOptions()
+ .setHost(uri.getHost())
+ .setPort(uri.getPort())
+ .setDatabase(uri.getPath().substring(1))
+ .setUser(userInfo[0])
+ .setPassword(userInfo[1]);
+ PoolOptions poolOptions = new PoolOptions().setMaxSize(64);
+ pgPool = PgBuilder.pool()
+ .with(poolOptions)
+ .connectingTo(connectOptions)
+ .build();
+ } catch (Exception ignored) {}
+ }
+
+ static Map parseQuery(String query) {
+ Map params = new HashMap<>();
+ if (query == null) return params;
+ for (String pair : query.split("&")) {
+ int eq = pair.indexOf('=');
+ if (eq > 0) params.put(pair.substring(0, eq), pair.substring(eq + 1));
+ }
+ return params;
+ }
+
+ static void sendText(HttpExchange ex, String text) throws IOException {
+ byte[] bytes = text.getBytes();
+ ex.getResponseHeaders().set("Content-Type", "text/plain");
+ ex.sendResponseHeaders(200, bytes.length);
+ ex.getResponseBody().write(bytes);
+ ex.close();
+ }
+
+ static void sendJson(HttpExchange ex, Object obj) throws IOException {
+ byte[] bytes = mapper.writeValueAsBytes(obj);
+ String accept = ex.getRequestHeaders().getFirst("Accept-Encoding");
+ if (accept != null && accept.contains("gzip")) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (GZIPOutputStream gz = new GZIPOutputStream(baos)) { gz.write(bytes); }
+ bytes = baos.toByteArray();
+ ex.getResponseHeaders().set("Content-Encoding", "gzip");
+ }
+ ex.getResponseHeaders().set("Content-Type", "application/json");
+ ex.sendResponseHeaders(200, bytes.length);
+ ex.getResponseBody().write(bytes);
+ ex.close();
+ }
+
+ // --- Handlers ---
+
+ static class BaselineHandler implements HttpHandler {
+ public void handle(HttpExchange ex) throws IOException {
+ Map params = parseQuery(ex.getRequestURI().getQuery());
+ int a = Integer.parseInt(params.getOrDefault("a", "0"));
+ int b = Integer.parseInt(params.getOrDefault("b", "0"));
+ int sum = a + b;
+ if ("POST".equals(ex.getRequestMethod())) {
+ String body = new String(ex.getRequestBody().readAllBytes());
+ sum += Integer.parseInt(body.trim());
+ }
+ sendText(ex, String.valueOf(sum));
+ }
+ }
+
+ static class PipelineHandler implements HttpHandler {
+ public void handle(HttpExchange ex) throws IOException {
+ sendText(ex, "ok");
+ }
+ }
+
+ static class JsonHandler implements HttpHandler {
+ public void handle(HttpExchange ex) throws IOException {
+ String path = ex.getRequestURI().getPath();
+ int count = Integer.parseInt(path.substring(path.lastIndexOf('/') + 1));
+ Map params = parseQuery(ex.getRequestURI().getQuery());
+ int m = Integer.parseInt(params.getOrDefault("m", "1"));
+ int n = Math.min(Math.max(count, 0), dataset.size());
+ List