diff --git a/gradle.properties b/gradle.properties index 892f571..5772eeb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,8 +1,9 @@ group = org.xbib name = netty-http -version = 4.1.63.3 +version = 4.1.63.4 gradle.wrapper.version = 6.6.1 + netty.version = 4.1.63.Final tcnative.version = 2.0.38.Final bouncycastle.version = 1.68 @@ -11,9 +12,9 @@ reactivex.version = 1.3.8 conscrypt.version = 2.5.1 javassist.version = 3.27.0-GA jackson.version = 2.11.4 -mockito.version = 3.4.4 -xbib.net.version = 2.1.0 +mockito.version = 3.10.0 +xbib.net.version = 2.1.1 xbib-guice.version = 4.4.2 -junit.version = 5.7.0 +junit.version = 5.7.1 # uuhh, too many tests to update to jupiter in rx... junit4.version = 4.13.1 diff --git a/netty-http-client/src/test/java/org/xbib/netty/http/client/test/http1/Http1Test.java b/netty-http-client/src/test/java/org/xbib/netty/http/client/test/http1/Http1Test.java index c3b698a..5289868 100644 --- a/netty-http-client/src/test/java/org/xbib/netty/http/client/test/http1/Http1Test.java +++ b/netty-http-client/src/test/java/org/xbib/netty/http/client/test/http1/Http1Test.java @@ -62,6 +62,27 @@ class Http1Test { } } + @Test + void testHttpsGetRequest() throws Exception { + Client client = Client.builder() + .enableDebug() + .setJdkSslProvider() + .build(); + try { + Request request = Request.post() + .url("http://hebis.rz.uni-frankfurt.de/HEBCGI/vuefl_recv_data.pl") + .setResponseListener(resp -> logger.log(Level.INFO, + "got response: " + resp.getHeaders() + + resp.getBodyAsString(StandardCharsets.UTF_8) + + " status=" + resp.getStatus())) + .build(); + client.execute(request).get().close(); + } finally { + client.shutdownGracefully(); + } + } + + @Test void testSequentialRequests() throws Exception { Client client = Client.builder() diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/CleartextTest.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/CleartextTest.java index 6158f7b..9b42add 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/CleartextTest.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/CleartextTest.java @@ -65,7 +65,7 @@ class CleartextTest { @Test void testPooledClearTextHttp1() throws Exception { - int loop = 1; + int loop = 1024; HttpAddress httpAddress = HttpAddress.http1("localhost", 8008); HttpServerDomain domain = HttpServerDomain.builder(httpAddress) .singleEndpoint("/**", (request, response) -> @@ -77,13 +77,15 @@ class CleartextTest { server.accept(); Client client = Client.builder() .addPoolNode(httpAddress) - .setPoolNodeConnectionLimit(2) + .setPoolNodeConnectionLimit(4) .build(); AtomicInteger counter = new AtomicInteger(); final ResponseListener responseListener = resp -> { if (resp.getStatus().getCode() == HttpResponseStatus.OK.code()) { - logger.log(Level.INFO, resp.getBodyAsString(StandardCharsets.UTF_8)); counter.incrementAndGet(); + } else { + logger.log(Level.INFO, "response listener: headers = " + resp.getHeaders() + + " response body = " + resp.getBodyAsString(StandardCharsets.UTF_8)); } }; try { @@ -105,6 +107,7 @@ class CleartextTest { client.shutdownGracefully(); server.shutdownGracefully(); } + logger.log(Level.INFO, "expecting=" + loop + " counter=" + counter.get()); assertEquals(loop, counter.get()); } @@ -152,7 +155,7 @@ class CleartextTest { logger.log(Level.WARNING, "transport failed: " + transport.getFailure().getMessage(), transport.getFailure()); break; } - transport.get(20L, TimeUnit.SECONDS); + transport.get(30L, TimeUnit.SECONDS); } } catch (Throwable e) { logger.log(Level.SEVERE, e.getMessage(), e); @@ -160,14 +163,14 @@ class CleartextTest { }); } executorService.shutdown(); - boolean terminated = executorService.awaitTermination(20L, TimeUnit.SECONDS); + boolean terminated = executorService.awaitTermination(30L, TimeUnit.SECONDS); executorService.shutdownNow(); logger.log(Level.INFO, "terminated = " + terminated + ", now waiting for transport to complete"); } catch (Exception e) { logger.log(Level.SEVERE, e.getMessage(), e); } finally { - server.shutdownGracefully(20L, TimeUnit.SECONDS); - client.shutdownGracefully(20L, TimeUnit.SECONDS); + server.shutdownGracefully(30L, TimeUnit.SECONDS); + client.shutdownGracefully(30L, TimeUnit.SECONDS); } logger.log(Level.INFO, "client requests = " + client.getRequestCounter() + " client responses = " + client.getResponseCounter()); diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/EncryptedTest.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/EncryptedTest.java index 7bf7018..bd447a1 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/EncryptedTest.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/EncryptedTest.java @@ -61,7 +61,7 @@ class EncryptedTest { @Test void testPooledSecureHttp1() throws Exception { - int loop = 4096; + int loop = 1024; HttpAddress httpAddress = HttpAddress.secureHttp1("localhost", 8143); Server server = Server.builder(HttpServerDomain.builder(httpAddress) .setSelfCert() @@ -75,7 +75,7 @@ class EncryptedTest { Client client = Client.builder() .trustInsecure() .addPoolNode(httpAddress) - .setPoolNodeConnectionLimit(2) + .setPoolNodeConnectionLimit(4) .build(); AtomicInteger counter = new AtomicInteger(); final ResponseListener responseListener = resp -> counter.incrementAndGet(); @@ -105,7 +105,7 @@ class EncryptedTest { @Test void testMultithreadPooledSecureHttp1() throws Exception { int threads = 4; - int loop = 4 * 1024; + int loop = 1024; HttpAddress httpAddress = HttpAddress.secureHttp1("localhost", 8143); Server server = Server.builder(HttpServerDomain.builder(httpAddress) .setSelfCert() @@ -151,11 +151,11 @@ class EncryptedTest { }); } executorService.shutdown(); - boolean terminated = executorService.awaitTermination(60, TimeUnit.SECONDS); + boolean terminated = executorService.awaitTermination(30L, TimeUnit.SECONDS); logger.log(Level.INFO, "terminated = " + terminated); } finally { - client.shutdownGracefully(); - server.shutdownGracefully(); + client.shutdownGracefully(30L, TimeUnit.SECONDS); + server.shutdownGracefully(30L, TimeUnit.SECONDS); } assertEquals(threads * loop , counter.get()); } diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/PostTest.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/PostTest.java index b5621d4..050a007 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/PostTest.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/PostTest.java @@ -38,7 +38,8 @@ class PostTest { if ("Hello World".equals(parameters.get("withspace"))) { success2.set(true); } - if ("Jörg".equals(parameters.get("name"))) { + // ISO-8859 + if ("Jörg".equals(parameters.get("name"))) { success3.set(true); } resp.getBuilder().setStatus(HttpResponseStatus.OK.code()).build().flush(); @@ -70,6 +71,7 @@ class PostTest { client.shutdownGracefully(); logger.log(Level.INFO, "server and client shut down"); } + logger.log(Level.INFO, "1=" + success1 + " 2=" + success2 + " 3=" + success3); assertTrue(success1.get()); assertTrue(success2.get()); assertTrue(success3.get()); diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http2/CleartextTest.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http2/CleartextTest.java index 55e8228..3dc8ef0 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http2/CleartextTest.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http2/CleartextTest.java @@ -85,7 +85,7 @@ class CleartextTest { server.accept(); Client client = Client.builder() .addPoolNode(httpAddress) - .setPoolNodeConnectionLimit(2) + .setPoolNodeConnectionLimit(4) .build(); final AtomicInteger counter = new AtomicInteger(); final ResponseListener responseListener = resp -> { @@ -97,7 +97,6 @@ class CleartextTest { } }; try { - // single transport, single thread ClientTransport transport = client.newTransport(); for (int i = 0; i < loop; i++) { String payload = 0 + "/" + i; @@ -112,7 +111,7 @@ class CleartextTest { break; } } - transport.get(10L, TimeUnit.SECONDS); + transport.get(30L, TimeUnit.SECONDS); } finally { server.shutdownGracefully(); client.shutdownGracefully(); @@ -174,7 +173,6 @@ class CleartextTest { boolean terminated = executorService.awaitTermination(30L, TimeUnit.SECONDS); executorService.shutdownNow(); logger.log(Level.INFO, "terminated = " + terminated + ", now waiting 30s for transport to complete"); - Thread.sleep(2000L); transport.get(30L, TimeUnit.SECONDS); logger.log(Level.INFO, "transport complete"); } finally { @@ -189,8 +187,8 @@ class CleartextTest { @Test void testTwoPooledClearTextHttp2() throws Exception { - int threads = 2; - int loop = 1000; + int threads = 4; + int loop = 1024; HttpAddress httpAddress1 = HttpAddress.http2("localhost", 8008); AtomicInteger counter1 = new AtomicInteger(); HttpServerDomain domain1 = HttpServerDomain.builder(httpAddress1) @@ -258,10 +256,9 @@ class CleartextTest { }); } executorService.shutdown(); - boolean terminated = executorService.awaitTermination(10L, TimeUnit.SECONDS); + boolean terminated = executorService.awaitTermination(30L, TimeUnit.SECONDS); logger.log(Level.INFO, "terminated = " + terminated + ", now waiting for transport to complete"); - Thread.sleep(2000L); - transport.get(10L, TimeUnit.SECONDS); + transport.get(30L, TimeUnit.SECONDS); logger.log(Level.INFO, "transport complete"); } finally { server1.shutdownGracefully(); diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http2/EncryptedTest.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http2/EncryptedTest.java index 3c1054d..26bde68 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http2/EncryptedTest.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http2/EncryptedTest.java @@ -82,7 +82,7 @@ class EncryptedTest { Client client = Client.builder() .trustInsecure() .addPoolNode(httpAddress) - .setPoolNodeConnectionLimit(2) + .setPoolNodeConnectionLimit(4) .build(); final AtomicInteger counter = new AtomicInteger(); final ResponseListener responseListener = resp -> { @@ -109,7 +109,7 @@ class EncryptedTest { break; } } - transport.get(60L, TimeUnit.SECONDS); + transport.get(30L, TimeUnit.SECONDS); } finally { server.shutdownGracefully(); client.shutdownGracefully(); @@ -166,14 +166,13 @@ class EncryptedTest { }); } executorService.shutdown(); - boolean terminated = executorService.awaitTermination(20, TimeUnit.SECONDS); + boolean terminated = executorService.awaitTermination(30L, TimeUnit.SECONDS); executorService.shutdownNow(); logger.log(Level.INFO, "terminated = " + terminated + ", now waiting for transport to complete"); - Thread.sleep(2000L); - transport.get(20, TimeUnit.SECONDS); + transport.get(30L, TimeUnit.SECONDS); } finally { - client.shutdownGracefully(20, TimeUnit.SECONDS); - server.shutdownGracefully(20, TimeUnit.SECONDS); + client.shutdownGracefully(30L, TimeUnit.SECONDS); + server.shutdownGracefully(30L, TimeUnit.SECONDS); } assertEquals(threads * loop , counter.get()); } diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http2/PostTest.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http2/PostTest.java index 9682169..bc449bc 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http2/PostTest.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http2/PostTest.java @@ -2,6 +2,7 @@ package org.xbib.netty.http.server.test.http2; import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.xbib.netty.http.client.Client; @@ -39,7 +40,8 @@ class PostTest { if ("Hello World".equals(parameters.get("withspace"))) { success2.set(true); } - if ("Jörg".equals(parameters.get("name"))) { + // ISO-8859 + if ("Jörg".equals(parameters.get("name"))) { success3.set(true); } resp.getBuilder().setStatus(HttpResponseStatus.OK.code()).build().flush(); @@ -70,6 +72,7 @@ class PostTest { client.shutdownGracefully(); logger.log(Level.INFO, "server and client shut down"); } + logger.log(Level.INFO, "1=" + success1 + " 2=" + success2 + " 3=" + success3); assertTrue(success1.get()); assertTrue(success2.get()); assertTrue(success3.get()); @@ -120,8 +123,175 @@ class PostTest { client.shutdownGracefully(); logger.log(Level.INFO, "server and client shut down"); } + logger.log(Level.INFO, "1=" + success1 + " 2=" + success2 + " 3=" + success3); assertTrue(success1.get()); assertTrue(success2.get()); assertTrue(success3.get()); } + + + @Test + void testFormPostHttp2() throws Exception { + final AtomicBoolean success1 = new AtomicBoolean(false); + final AtomicBoolean success2 = new AtomicBoolean(false); + final AtomicBoolean success3 = new AtomicBoolean(false); + final AtomicBoolean success4 = new AtomicBoolean(false); + HttpAddress httpAddress = HttpAddress.http1("localhost", 8008); + HttpServerDomain domain = HttpServerDomain.builder(httpAddress) + .singleEndpoint("/post", "/**", (req, resp) -> { + HttpParameters parameters = req.getParameters(); + logger.log(Level.INFO, "got request " + parameters.toString() + ", sending OK"); + if ("Hello World".equals(parameters.get("withplus"))) { + success2.set(true); + } + if ("Jörg".equals(parameters.get("name"))) { + success3.set(true); + } + if ("my value".equals(parameters.get("my param"))) { + success4.set(true); + } + resp.getBuilder().setStatus(HttpResponseStatus.OK.code()).build().flush(); + }, "POST") + .build(); + Server server = Server.builder(domain) + .build(); + Client client = Client.builder() + .build(); + try { + server.accept(); + ResponseListener responseListener = (resp) -> { + if (resp.getStatus().getCode() == HttpResponseStatus.OK.code()) { + logger.log(Level.INFO, resp.getBodyAsString(StandardCharsets.UTF_8)); + success1.set(true); + } + }; + Request postRequest = Request.post().setVersion(HttpVersion.HTTP_1_1) + .url(server.getServerConfig().getAddress().base().resolve("/post/test.txt")) + .contentType(HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED, StandardCharsets.UTF_8) + .addParameter("a", "b") + // test 'plus' encoding + .addFormParameter("my param", "my value") + .addFormParameter("withplus", "Hello World") + .addFormParameter("name", "Jörg") + .setResponseListener(responseListener) + .build(); + client.execute(postRequest).get(); + } finally { + server.shutdownGracefully(); + client.shutdownGracefully(); + logger.log(Level.INFO, "server and client shut down"); + } + assertTrue(success1.get()); + assertTrue(success2.get()); + assertTrue(success3.get()); + assertTrue(success4.get()); + } + + @Test + void testTextPlainPostHttp2() throws Exception { + final AtomicBoolean success1 = new AtomicBoolean(false); + final AtomicBoolean success2 = new AtomicBoolean(false); + final AtomicBoolean success3 = new AtomicBoolean(false); + final AtomicBoolean success4 = new AtomicBoolean(false); + HttpAddress httpAddress = HttpAddress.http2("localhost", 8008); + HttpServerDomain domain = HttpServerDomain.builder(httpAddress) + .singleEndpoint("/post", "/**", (req, resp) -> { + HttpParameters parameters = req.getParameters(); + logger.log(Level.INFO, "got request " + parameters.toString() + ", sending OK"); + if ("Hello World".equals(parameters.get("withoutplus"))) { + success2.set(true); + } + if ("Jörg".equals(parameters.get("name"))) { + success3.set(true); + } + if ("my value".equals(parameters.get("my param"))) { + success4.set(true); + } + resp.getBuilder().setStatus(HttpResponseStatus.OK.code()).build().flush(); + }, "POST") + .build(); + Server server = Server.builder(domain) + .build(); + Client client = Client.builder() + .build(); + try { + server.accept(); + ResponseListener responseListener = (resp) -> { + if (resp.getStatus().getCode() == HttpResponseStatus.OK.code()) { + logger.log(Level.INFO, resp.getBodyAsString(StandardCharsets.UTF_8)); + success1.set(true); + } + }; + Request postRequest = Request.post() + .setVersion("HTTP/2.0") + .url(server.getServerConfig().getAddress().base().resolve("/post/test.txt")) + .contentType(HttpHeaderValues.TEXT_PLAIN, StandardCharsets.UTF_8) + // you can not pass form parameters on content type "text/plain" + .addParameter("a", "b") + .addParameter("my param", "my value") + .addParameter("withoutplus", "Hello World") + .addParameter("name", "Jörg") + .setResponseListener(responseListener) + .build(); + client.execute(postRequest).get(); + } finally { + server.shutdownGracefully(); + client.shutdownGracefully(); + logger.log(Level.INFO, "server and client shut down"); + } + assertTrue(success1.get()); + assertTrue(success2.get()); + assertTrue(success3.get()); + assertTrue(success4.get()); + } + + @Test + void testPostInvalidPercentEncodings() throws Exception { + final AtomicBoolean success1 = new AtomicBoolean(false); + final AtomicBoolean success2 = new AtomicBoolean(false); + final AtomicBoolean success3 = new AtomicBoolean(false); + HttpAddress httpAddress = HttpAddress.http2("localhost", 8008); + HttpServerDomain domain = HttpServerDomain.builder(httpAddress) + .singleEndpoint("/post", "/**", (req, resp) -> { + HttpParameters parameters = req.getParameters(); + logger.log(Level.INFO, "got request " + parameters.toString() + ", sending OK"); + if ("myÿvalue".equals(parameters.get("my param"))) { + success1.set(true); + } + if ("bÿc".equals(parameters.get("a"))) { + success2.set(true); + } + resp.getBuilder().setStatus(HttpResponseStatus.OK.code()).build().flush(); + }, "POST") + .build(); + Server server = Server.builder(domain) + .build(); + Client client = Client.builder() + .build(); + try { + server.accept(); + ResponseListener responseListener = (resp) -> { + if (resp.getStatus().getCode() == HttpResponseStatus.OK.code()) { + success3.set(true); + } + }; + Request postRequest = Request.post() + .setVersion("HTTP/2.0") + .url(server.getServerConfig().getAddress().base().resolve("/post/test.txt")) + .contentType(HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED, StandardCharsets.ISO_8859_1) + .addRawParameter("a", "b%YYc") + .addRawFormParameter("my param", "my%ZZvalue") + .setResponseListener(responseListener) + .build(); + client.execute(postRequest).get(); + } finally { + server.shutdownGracefully(); + client.shutdownGracefully(); + logger.log(Level.INFO, "server and client shut down"); + } + assertTrue(success1.get()); + assertTrue(success2.get()); + assertTrue(success3.get()); + } + }