Feature/ext validation/request validation #15

Merged
Relism merged 10 commits from feature/ext-validation/request-validation into master 2026-09-09 14:21:17 +00:00
23 changed files with 132 additions and 235 deletions
Showing only changes of commit e0ad83eb2f - Show all commits
@@ -4,11 +4,10 @@ import dev.relism.flash.extension.FlashApp;
import dev.relism.flash.extension.FlashConfiguration;
import dev.relism.flash.http.ContentType;
import dev.relism.flash.models.Response;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.net.ServerSocket;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
@@ -25,20 +24,17 @@ import static org.junit.jupiter.api.Assertions.*;
class HttpServerConcurrencyTest {
private FlashApp app;
private int port;
private HttpClient httpClient;
@BeforeEach
void setUp() throws Exception {
try (ServerSocket s = new ServerSocket(0)) {
port = s.getLocalPort();
}
private static FlashApp app;
private static int port;
private static HttpClient httpClient;
@BeforeAll
static void setUp() {
app = FlashApp.create(FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.build());
port = app.port();
app.get("/ping", (req, res) -> "pong");
app.post("/echo", (req, res) -> {
@@ -53,9 +49,9 @@ class HttpServerConcurrencyTest {
.build();
}
@AfterEach
void tearDown() {
if (app != null) app.stop();
@AfterAll
static void tearDown() {
if (app != null) app.stop().join();
}
// --- helpers ---
@@ -173,15 +169,13 @@ class HttpServerConcurrencyTest {
*/
@Test
void concurrent_lazyCompile_noRaceCondition() throws Exception {
int freshPort;
try (ServerSocket s = new ServerSocket(0)) {
freshPort = s.getLocalPort();
}
// Deliberately a brand-new app: this test is about compiling routes lazily on first
// use, so it must not share the class-scoped server.
FlashApp freshApp = FlashApp.create(FlashConfiguration.builder()
.port(freshPort)
.port(0)
.host("127.0.0.1")
.build());
int freshPort = freshApp.port();
for (int i = 0; i < 10; i++) {
final int idx = i;
@@ -2,15 +2,14 @@ package dev.relism.flash;
import dev.relism.flash.extension.FlashApp;
import dev.relism.flash.extension.FlashConfiguration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
@@ -18,19 +17,17 @@ import static org.junit.jupiter.api.Assertions.*;
class HttpServerTest {
private FlashApp app;
private int port;
@BeforeEach
void setUp() throws Exception {
try (ServerSocket s = new ServerSocket(0)) {
port = s.getLocalPort();
}
// Every test here is read-only against the same routes, so one boot for the class.
private static FlashApp app;
private static int port;
@BeforeAll
static void setUp() {
app = FlashApp.create(FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.build());
port = app.port();
app.get("/api/ping", (req, res) -> "pong");
@@ -61,9 +58,9 @@ class HttpServerTest {
app.start();
}
@AfterEach
void tearDown() {
if (app != null) app.stop();
@AfterAll
static void tearDown() {
if (app != null) app.stop().join();
}
// --- helpers ---
@@ -9,7 +9,6 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
@@ -30,21 +29,15 @@ class HttpServerTimeoutTest {
if (app != null) app.stop();
}
private int freePort() throws Exception {
try (ServerSocket s = new ServerSocket(0)) {
return s.getLocalPort();
}
}
@Test
void slowlorisHeaderDribble_disconnectedWithinHeaderReadTimeout() throws Exception {
int headerTimeoutMs = 300;
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.headerReadTimeoutMs(headerTimeoutMs)
.idleKeepAliveTimeoutMs(60_000)
.build());
int port = app.port();
app.get("/", (req, res) -> "ok");
app.start();
@@ -71,12 +64,12 @@ class HttpServerTimeoutTest {
@Test
void idleKeepAliveConnection_disconnectedWithinIdleTimeout() throws Exception {
int idleTimeoutMs = 300;
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.headerReadTimeoutMs(10_000)
.idleKeepAliveTimeoutMs(idleTimeoutMs)
.build());
int port = app.port();
app.get("/", (req, res) -> "ok");
app.start();
@@ -96,13 +89,13 @@ class HttpServerTimeoutTest {
@Test
void slowBodyDribble_disconnectedWithinBodyReadTimeout() throws Exception {
int bodyTimeoutMs = 300;
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.headerReadTimeoutMs(10_000)
.idleKeepAliveTimeoutMs(10_000)
.bodyReadTimeoutMs(bodyTimeoutMs)
.build());
int port = app.port();
app.post("/echo", (req, res) -> req.body().bytes());
app.start();
@@ -130,12 +123,12 @@ class HttpServerTimeoutTest {
int headerTimeoutMs = 300;
Path ks = TestKeystores.build(dir, "timeout.p12", "changeit",
TestKeystores.Entry.of("only", "timeout.test"));
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.tls(TlsConfig.keystore(ks, "changeit"))
.headerReadTimeoutMs(headerTimeoutMs)
.build());
int port = app.port();
app.get("/", (req, res) -> "ok");
app.start();
@@ -157,13 +150,13 @@ class HttpServerTimeoutTest {
@Test
void wellBehavedRequest_wellWithinTimeouts_unaffected() throws Exception {
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.headerReadTimeoutMs(300)
.idleKeepAliveTimeoutMs(300)
.bodyReadTimeoutMs(300)
.build());
int port = app.port();
app.get("/ping", (req, res) -> "pong");
app.start();
@@ -60,9 +60,6 @@ class HttpServerTlsTest {
if (app != null) app.stop();
}
private static int freePort() throws IOException {
try (ServerSocket s = new ServerSocket(0)) { return s.getLocalPort(); }
}
private static String httpGet(SSLSocket socket, String path) throws IOException {
socket.setSoTimeout(SOCKET_TIMEOUT_MS);
@@ -79,11 +76,11 @@ class HttpServerTlsTest {
@Test
void httpsRequest_servedOverModernTls(@TempDir java.nio.file.Path dir) throws Exception {
var ks = TestKeystores.build(dir, "id.p12", "changeit", TestKeystores.Entry.of("srv", "localhost"));
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.tls(TlsConfig.keystore(ks, "changeit"))
.build());
int port = app.port();
app.get("/ping", (req, res) -> "pong");
app.start();
@@ -103,11 +100,11 @@ class HttpServerTlsTest {
var ks = TestKeystores.build(dir, "sni.p12", "changeit",
TestKeystores.Entry.of("a", "a.test"),
TestKeystores.Entry.of("b", "b.test"));
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.tls(TlsConfig.keystore(ks, "changeit"))
.build());
int port = app.port();
app.get("/ping", (req, res) -> "pong");
app.start();
@@ -143,11 +140,11 @@ class HttpServerTlsTest {
@Test
void mTls_requireRejectsClientWithNoCertificate(@TempDir java.nio.file.Path dir) throws Exception {
var ks = TestKeystores.build(dir, "id.p12", "changeit", TestKeystores.Entry.of("srv", "localhost"));
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.tls(TlsConfig.keystore(ks, "changeit").clientAuth(ClientAuth.REQUIRE))
.build());
int port = app.port();
app.get("/ping", (req, res) -> "pong");
app.start();
@@ -180,11 +177,11 @@ class HttpServerTlsTest {
SSLContext serverCtx = SSLContext.getInstance("TLS");
serverCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.tls(TlsConfig.ofContext(serverCtx).clientAuth(ClientAuth.REQUIRE))
.build());
int port = app.port();
app.get("/ping", (req, res) -> "pong");
app.start();
@@ -219,12 +216,12 @@ class HttpServerTlsTest {
@Test
void multipleListeners_plainAndTlsServeTheSameApp(@TempDir java.nio.file.Path dir) throws Exception {
var ks = TestKeystores.build(dir, "id.p12", "changeit", TestKeystores.Entry.of("srv", "localhost"));
int plainPort = freePort();
int tlsPort = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.listener(new FlashConfiguration.Listener(plainPort, "127.0.0.1", null))
.listener(new FlashConfiguration.Listener(tlsPort, "127.0.0.1", TlsConfig.keystore(ks, "changeit")))
.listener(new FlashConfiguration.Listener(0, "127.0.0.1", null))
.listener(new FlashConfiguration.Listener(0, "127.0.0.1", TlsConfig.keystore(ks, "changeit")))
.build());
int plainPort = app.ports().get(0);
int tlsPort = app.ports().get(1);
app.get("/ping", (req, res) -> "pong");
app.start();
@@ -287,11 +284,11 @@ class HttpServerTlsTest {
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(managers, null, null);
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.tls(TlsConfig.ofContext(ctx))
.build());
int port = app.port();
app.get("/ping", (req, res) -> "pong");
app.start();
@@ -364,11 +361,11 @@ class HttpServerTlsTest {
SSLContext[] boxedCtx = new SSLContext[1];
RecordingKeyManager recorder = buildRecordingContext(ks, boxedCtx);
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.tls(TlsConfig.ofContext(boxedCtx[0]).applicationProtocols("acme-tls/1", "http/1.1"))
.build());
int port = app.port();
app.get("/ping", (req, res) -> "pong");
app.start();
@@ -422,11 +419,11 @@ class HttpServerTlsTest {
@Test
void request_isSecureAndSessionAvailableOverTls(@TempDir java.nio.file.Path dir) throws Exception {
var ks = TestKeystores.build(dir, "id.p12", "changeit", TestKeystores.Entry.of("srv", "localhost"));
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.tls(TlsConfig.keystore(ks, "changeit"))
.build());
int port = app.port();
app.get("/secure-info", (req, res) -> {
SSLSession session = req.sslSession();
return req.isSecure() + ":" + (session != null) + ":" + (session != null ? session.getCipherSuite() : "");
@@ -456,13 +453,13 @@ class HttpServerTlsTest {
SSLContext serverCtx = SSLContext.getInstance("TLS");
serverCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
// OPTIONAL, not REQUIRE: proves getPeerCertificates() works without also
// re-testing the REQUIRE-rejection path already covered elsewhere in this file.
.tls(TlsConfig.ofContext(serverCtx).clientAuth(ClientAuth.OPTIONAL))
.build());
int port = app.port();
app.get("/secure-info", (req, res) -> {
try {
X509Certificate peer = (X509Certificate) req.sslSession().getPeerCertificates()[0];
@@ -488,8 +485,8 @@ class HttpServerTlsTest {
@Test
void request_isNotSecureAndSessionIsNullOnPlainListener() throws Exception {
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder().port(port).host("127.0.0.1").build());
app = FlashApp.create(FlashConfiguration.builder().port(0).host("127.0.0.1").build());
int port = app.port();
app.get("/secure-info", (req, res) -> req.isSecure() + ":" + (req.sslSession() == null));
app.start();
@@ -524,11 +521,11 @@ class HttpServerTlsTest {
@Test
void wss_sessionIsSecureAndExposesSslSession(@TempDir java.nio.file.Path dir) throws Exception {
var ks = TestKeystores.build(dir, "id.p12", "changeit", TestKeystores.Entry.of("srv", "localhost"));
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.tls(TlsConfig.keystore(ks, "changeit"))
.build());
int port = app.port();
AtomicReference<Boolean> observedSecure = new AtomicReference<>();
AtomicReference<SSLSession> observedSession = new AtomicReference<>();
@@ -13,7 +13,6 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
@@ -29,14 +28,11 @@ class HttpServerWebSocketTest {
@BeforeEach
void setUp() throws Exception {
try (ServerSocket s = new ServerSocket(0)) {
port = s.getLocalPort();
}
app = FlashApp.create(FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.build());
port = app.port();
app.ws("/chat", new WebSocketHandler() {
@Override
@@ -9,7 +9,6 @@ import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.ServerSocket;
import static org.junit.jupiter.api.Assertions.*;
@@ -20,14 +19,11 @@ class FlashAppWebSocketTest {
@BeforeEach
void setUp() throws Exception {
try (ServerSocket s = new ServerSocket(0)) {
port = s.getLocalPort();
}
app = FlashApp.create(FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.build());
port = app.port();
}
@AfterEach
@@ -32,7 +32,6 @@ class CurlInteropTest {
@Test
void tlsGetPostLargeUploadAndLargeDownload(@TempDir Path directory) throws Exception {
int port = freePort();
Path keystore =
TestKeystores.build(
directory,
@@ -43,23 +42,24 @@ class CurlInteropTest {
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.tls(TlsConfig.keystore(keystore, "changeit"))
.http2Enabled(true)
.build());
int port = app.port();
exercise(directory, "https://localhost:" + port, "--http2", "--insecure");
}
@Test
void cleartextGetPostLargeUploadAndLargeDownload(@TempDir Path directory) throws Exception {
int port = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.http2CleartextEnabled(true)
.build());
int port = app.port();
exercise(directory, "http://127.0.0.1:" + port, "--http2-prior-knowledge");
}
@@ -112,9 +112,4 @@ class CurlInteropTest {
return result;
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
}
@@ -28,14 +28,14 @@ class GrpcInteropTest {
@Test
void grpcurlCompletesUnaryStreamingAndErrorCalls(@TempDir Path directory) throws Exception {
int port = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.http2CleartextEnabled(true)
.build());
int port = app.port();
app.post("/flash.test.Echo/Unary", (request, response) ->
response.type("application/grpc")
.body(request.body().bytes())
@@ -156,11 +156,6 @@ class GrpcInteropTest {
return count;
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
private record Result(int exitCode, String output) {}
}
@@ -42,16 +42,16 @@ class H2LoadMeasurementTest {
@Test
void measureFlashAndNghttpdMatrix(@TempDir Path directory) throws Exception {
int flashPort = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(flashPort)
.port(0)
.http2CleartextEnabled(true)
.h2MaxStreamsCreatedPerInterval(Integer.MAX_VALUE)
.h2MaxStreamsPerConnection(0)
.build());
int flashPort = app.port();
app.get("/index.html", (request, response) -> "flash-load");
app.start();
@@ -133,6 +133,10 @@ class H2LoadMeasurementTest {
if (path != null) builder.environment().put("LD_LIBRARY_PATH", path);
}
/**
* Still needed here: this port is handed to an external nghttpd process, which has no
* equivalent of {@code FlashApp.port()} to read an OS-assigned port back from.
*/
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
@@ -36,14 +36,14 @@ class H2SpecComplianceTest {
@Test
void cleartextSuiteHasNoFailuresOrSkips(@TempDir Path directory) throws Exception {
int port = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.http2CleartextEnabled(true)
.build());
int port = app.port();
registerProbeRoutes();
app.start();
@@ -52,7 +52,6 @@ class H2SpecComplianceTest {
@Test
void tlsSuiteHasNoFailuresOrSkips(@TempDir Path directory) throws Exception {
int port = freePort();
Path keystore =
TestKeystores.build(
directory,
@@ -63,10 +62,11 @@ class H2SpecComplianceTest {
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.tls(TlsConfig.keystore(keystore, "changeit"))
.http2Enabled(true)
.build());
int port = app.port();
registerProbeRoutes();
app.start();
@@ -145,11 +145,6 @@ class H2SpecComplianceTest {
assertEquals(0, skipped.getLength(), output);
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
private record ProcessResult(int exitCode, String output) {}
}
@@ -28,14 +28,14 @@ class H2cPriorKnowledgeTest {
@Test
void priorKnowledgeRequiresItsIndependentOptIn() throws Exception {
int disabledPort = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(disabledPort)
.port(0)
.http2Enabled(true)
.build());
int disabledPort = app.port();
app.get("/", (request, response) -> "wrong protocol");
app.start();
@@ -47,14 +47,14 @@ class H2cPriorKnowledgeTest {
}
app.stop().join();
int enabledPort = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(enabledPort)
.port(0)
.http2CleartextEnabled(true)
.build());
int enabledPort = app.port();
app.get("/", (request, response) -> "h2c");
app.start();
@@ -125,9 +125,4 @@ class H2cPriorKnowledgeTest {
payload);
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
}
@@ -183,15 +183,15 @@ class Http2AbuseTest {
@Test
void idleOpenStreamIsCancelledWithinConfiguredDeadline() throws Exception {
int port = freePort();
FlashApp app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.http2CleartextEnabled(true)
.h2StreamIdleTimeoutMs(20)
.build());
int port = app.port();
app.post("/idle", (request, response) -> request.body().bytes());
app.start();
ByteWriter headers = new ByteWriter(64);
@@ -295,11 +295,6 @@ class Http2AbuseTest {
throw new AssertionError("missing " + expected);
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
private record Run(List<Http2TestFrames.WireFrame> frames) {
int lastGoAwayError() {
@@ -29,16 +29,16 @@ class Http2ConcurrencyTest {
@Test
void thousandMultiplexedStreamsCompleteOnOneConnection() throws Exception {
int port = freePort();
AtomicInteger handled = new AtomicInteger();
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.http2CleartextEnabled(true)
.h2MaxStreamsCreatedPerInterval(2_000)
.build());
int port = app.port();
app.get("/work", (request, response) -> Integer.toString(handled.incrementAndGet()));
app.start();
@@ -110,9 +110,4 @@ class Http2ConcurrencyTest {
payload);
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
}
@@ -28,14 +28,14 @@ class Http2ConnectTest {
@Test
void connectTunnelCanExchangeDataBeforeEitherSideCloses() throws Exception {
int port = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.http2CleartextEnabled(true)
.build());
int port = app.port();
app.connect("tunnel", (request, response) ->
response.type(ContentType.NONE).streaming(output -> {
byte[] bytes = new byte[16];
@@ -100,9 +100,4 @@ class Http2ConnectTest {
return text.getBytes(StandardCharsets.US_ASCII);
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
}
@@ -48,7 +48,6 @@ class Http2ConnectionIntegrationTest {
@Test
void javaHttpClientUsesHttp2AgainstAnExistingParameterizedRoute(@TempDir Path directory)
throws Exception {
int port = freePort();
Path keystore =
TestKeystores.build(
directory,
@@ -58,11 +57,12 @@ class Http2ConnectionIntegrationTest {
app =
FlashApp.create(
FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.tls(TlsConfig.keystore(keystore, "changeit"))
.http2Enabled(true)
.build());
int port = app.port();
app.get(
"/users/{id}", (request, response) -> request.param("id") + ":" + request.header("host"));
app.start();
@@ -87,7 +87,6 @@ class Http2ConnectionIntegrationTest {
@Test
void javaHttpClientUploadsAndDownloadsFlowControlledBodies(@TempDir Path directory)
throws Exception {
int port = freePort();
Path keystore =
TestKeystores.build(
directory,
@@ -102,11 +101,12 @@ class Http2ConnectionIntegrationTest {
app =
FlashApp.create(
FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.tls(TlsConfig.keystore(keystore, "changeit"))
.http2Enabled(true)
.build());
int port = app.port();
app.post("/echo", (request, response) -> request.body().bytes());
app.get("/fixed", (request, response) -> response.body(download));
app.get(
@@ -143,7 +143,6 @@ class Http2ConnectionIntegrationTest {
@Test
void pushStreamingAppliesBackpressureAcrossMultipleWindows(@TempDir Path directory)
throws Exception {
int port = freePort();
int length = 2 * 1024 * 1024 + 31;
Path keystore =
TestKeystores.build(
@@ -154,11 +153,12 @@ class Http2ConnectionIntegrationTest {
app =
FlashApp.create(
FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.tls(TlsConfig.keystore(keystore, "changeit"))
.http2Enabled(true)
.build());
int port = app.port();
app.get(
"/push",
(request, response) ->
@@ -197,7 +197,6 @@ class Http2ConnectionIntegrationTest {
@Test
void hundredMegabyteUploadAndDownloadRemainStreaming(@TempDir Path directory) throws Exception {
int port = freePort();
long length = 100L * 1024 * 1024;
Path keystore =
TestKeystores.build(
@@ -208,11 +207,12 @@ class Http2ConnectionIntegrationTest {
app =
FlashApp.create(
FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.tls(TlsConfig.keystore(keystore, "changeit"))
.http2Enabled(true)
.build());
int port = app.port();
app.post(
"/upload",
(request, response) -> {
@@ -250,14 +250,14 @@ class Http2ConnectionIntegrationTest {
@Test
void bodylessGetRunsExistingRouteAndReturnsHeadersAndData() throws Exception {
int port = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.http2CleartextEnabled(true)
.build());
int port = app.port();
app.get("/api/ping", (request, response) -> "pong");
app.start();
@@ -314,15 +314,15 @@ class Http2ConnectionIntegrationTest {
@Test
void resetQueuedStreamCannotReleaseOrReuseItBeforeDispatchObservesCancellation()
throws Exception {
int port = freePort();
AtomicInteger calls = new AtomicInteger();
app =
FlashApp.create(
FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.http2CleartextEnabled(true)
.build());
int port = app.port();
app.get(
"/queued",
(request, response) -> {
@@ -384,15 +384,15 @@ class Http2ConnectionIntegrationTest {
@Test
void h2cTransportDispatchesControlFramesWithoutRunningApplicationWork() throws Exception {
int port = freePort();
AtomicBoolean handlerEntered = new AtomicBoolean();
app =
FlashApp.create(
FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.http2CleartextEnabled(true)
.build());
int port = app.port();
app.get(
"/",
(request, response) -> {
@@ -442,15 +442,15 @@ class Http2ConnectionIntegrationTest {
@Test
void serverStopInitiatesTwoStageGoAwayOnIdleConnection() throws Exception {
int port = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.http2CleartextEnabled(true)
.shutdownDrainTimeoutMs(5_000)
.build());
int port = app.port();
app.start();
try (Socket socket = new Socket("127.0.0.1", port)) {
@@ -485,14 +485,14 @@ class Http2ConnectionIntegrationTest {
@Test
void protocolStateDoesNotLeakAcrossConsecutiveConnections() throws Exception {
int port = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.http2CleartextEnabled(true)
.build());
int port = app.port();
app.start();
try (Socket first = new Socket("127.0.0.1", port)) {
@@ -537,7 +537,6 @@ class Http2ConnectionIntegrationTest {
@Test
void tlsListenerOffersAndNegotiatesH2WhenHttp2IsEnabled(@TempDir Path directory)
throws Exception {
int port = freePort();
Path keystore =
TestKeystores.build(
directory,
@@ -547,11 +546,12 @@ class Http2ConnectionIntegrationTest {
app =
FlashApp.create(
FlashConfiguration.builder()
.port(port)
.port(0)
.host("127.0.0.1")
.tls(TlsConfig.keystore(keystore, "changeit"))
.http2Enabled(true)
.build());
int port = app.port();
app.start();
try (SSLSocket socket =
@@ -630,11 +630,6 @@ class Http2ConnectionIntegrationTest {
payload);
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
private static String ascii(dev.relism.fpr.core.ByteView view) {
byte[] bytes = new byte[view.length()];
@@ -31,7 +31,6 @@ class Http2MisdirectedRequestTest {
@Test
void authorityOutsideSelectedCertificateReceives421(@TempDir Path directory) throws Exception {
int port = freePort();
Path keystore =
TestKeystores.build(
directory,
@@ -42,10 +41,11 @@ class Http2MisdirectedRequestTest {
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.tls(TlsConfig.keystore(keystore, "changeit"))
.http2Enabled(true)
.build());
int port = app.port();
app.get("/", (request, response) -> "must not run");
app.start();
@@ -114,9 +114,4 @@ class Http2MisdirectedRequestTest {
}
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
}
@@ -47,14 +47,14 @@ class Http2RegressionCorpusTest {
@Test
void headersOnHalfClosedRemoteStreamUseStreamErrorBeforeDispatch() throws Exception {
int port = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.http2CleartextEnabled(true)
.build());
int port = app.port();
app.get("/", (request, response) -> "ok");
app.start();
@@ -101,9 +101,4 @@ class Http2RegressionCorpusTest {
payload);
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
}
@@ -35,18 +35,18 @@ class Http2SoakTest {
@Test
void sustainedMixedTrafficRetainsBoundedHeapAndCompletesRequests() throws Exception {
long seconds = Long.getLong("flash.http2.soak.seconds", 600L);
int port = freePort();
byte[] streamBody = new byte[8 * 1024];
Arrays.fill(streamBody, (byte) 's');
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.http2CleartextEnabled(true)
.h2MaxStreamsCreatedPerInterval(100_000)
.h2MaxStreamsPerConnection(0)
.build());
int port = app.port();
app.get("/get", (request, response) -> "get");
app.post("/post", (request, response) -> request.body().bytes());
app.get("/stream", (request, response) -> response.chunked(new ByteArrayInputStream(streamBody)));
@@ -182,9 +182,4 @@ class Http2SoakTest {
payload);
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
}
@@ -27,14 +27,14 @@ class Http2TrailersTest {
@Test
void requestTrailersReachHandlerAfterBodyEof() throws Exception {
int port = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.http2CleartextEnabled(true)
.build());
int port = app.port();
app.post("/trailers", (request, response) -> {
assertEquals("abc", new String(request.body().bytes(), StandardCharsets.US_ASCII));
return request.trailers().first("grpc-status");
@@ -99,14 +99,14 @@ class Http2TrailersTest {
}
private int startBlockingRoute() throws Exception {
int port = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.http2CleartextEnabled(true)
.build());
int port = app.port();
app.post("/trailers", (request, response) -> request.body().bytes());
app.start();
return port;
@@ -152,9 +152,4 @@ class Http2TrailersTest {
payload);
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
}
@@ -38,9 +38,8 @@ class NghttpInteropTest {
}
private void exercise(Path directory, boolean tls) throws Exception {
int port = freePort();
FlashConfiguration.FlashConfigurationBuilder builder =
FlashConfiguration.builder().host("127.0.0.1").port(port);
FlashConfiguration.builder().host("127.0.0.1").port(0);
if (tls) {
Path keystore =
TestKeystores.build(
@@ -54,6 +53,7 @@ class NghttpInteropTest {
}
byte[] large = new byte[2 * 1024 * 1024 + 29];
app = FlashApp.create(builder.build());
int port = app.port();
app.get("/get", (request, response) -> "nghttp-get");
app.post("/post", (request, response) -> "uploaded-" + request.body().bytes().length);
app.get("/large", (request, response) -> response.body(large));
@@ -93,9 +93,4 @@ class NghttpInteropTest {
assertTrue(trace.contains("recv DATA frame"), trace);
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
}
@@ -23,15 +23,15 @@ class WebSocketOverH2Test {
@Test
void opensEchoesFragmentsAndCarriesAMessageLargerThanTheFlowWindow() throws Exception {
int port = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.http2CleartextEnabled(true)
.wsFrameBufferSize(2 * 1024 * 1024)
.build());
int port = app.port();
app.ws(
"/chat",
new WebSocketHandler() {
@@ -67,9 +67,4 @@ class WebSocketOverH2Test {
}
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
}
@@ -28,14 +28,14 @@ class WebSocketParityTest {
@Test
void oneRouteAndHandlerEchoTheSameMessageOverHttp1AndHttp2() throws Exception {
int port = freePort();
app =
FlashApp.create(
FlashConfiguration.builder()
.host("127.0.0.1")
.port(port)
.port(0)
.http2CleartextEnabled(true)
.build());
int port = app.port();
app.ws(
"/parity",
new WebSocketHandler() {
@@ -135,9 +135,4 @@ class WebSocketParityTest {
return input.readNBytes(length);
}
private static int freePort() throws Exception {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
}
@@ -28,22 +28,17 @@ class ServerLifecycleGracefulShutdownTest {
if (app != null) app.stop();
}
private static int freePort() throws Exception {
try (ServerSocket s = new ServerSocket(0)) {
return s.getLocalPort();
}
}
@Test
void inFlightRequest_completesWithConnectionClose_duringShutdown() throws Exception {
int port = freePort();
CountDownLatch handlerStarted = new CountDownLatch(1);
CountDownLatch releaseHandler = new CountDownLatch(1);
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.shutdownDrainTimeoutMs(5_000)
.build());
int port = app.port();
app.get("/slow", (req, res) -> {
handlerStarted.countDown();
assertTrue(releaseHandler.await(5, TimeUnit.SECONDS));
@@ -80,11 +75,11 @@ class ServerLifecycleGracefulShutdownTest {
@Test
void stop_closesListener_soNewConnectionsAreRefused() throws Exception {
int port = freePort();
app = FlashApp.create(FlashConfiguration.builder()
.port(port).host("127.0.0.1")
.port(0).host("127.0.0.1")
.shutdownDrainTimeoutMs(500)
.build());
int port = app.port();
app.get("/ping", (req, res) -> "pong");
app.start();