diff --git a/gradle.properties b/gradle.properties index 7f95a11..a79191b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group = org.xbib name = netty-http -version = 4.1.77.0 +version = 4.1.84.0 org.gradle.warning.mode = ALL diff --git a/gradle/compile/java.gradle b/gradle/compile/java.gradle index 0dc1a1d..c417727 100644 --- a/gradle/compile/java.gradle +++ b/gradle/compile/java.gradle @@ -6,27 +6,28 @@ java { } compileJava { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } compileTestJava { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } jar { manifest { attributes('Implementation-Title': project.name) attributes('Implementation-Version': project.version) - attributes('Implementation-Vendor': 'Jörg Prante') } } tasks.withType(JavaCompile) { - options.compilerArgs << '-Xlint:all,-exports' + options.compilerArgs.add('-Xlint:all,-exports') + options.encoding = 'UTF-8' } -javadoc { +tasks.withType(Javadoc) { options.addStringOption('Xdoclint:none', '-quiet') + options.encoding = 'UTF-8' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927..249e583 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 92f06b5..8fad3f5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c787..a69d9cb 100755 --- a/gradlew +++ b/gradlew @@ -205,6 +205,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index ac1b06f..53a6b23 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/netty-http-client-api/src/main/java/module-info.java b/netty-http-client-api/src/main/java/module-info.java index 1d5cce3..9e18354 100644 --- a/netty-http-client-api/src/main/java/module-info.java +++ b/netty-http-client-api/src/main/java/module-info.java @@ -1,7 +1,7 @@ module org.xbib.netty.http.client.api { exports org.xbib.netty.http.client.api; requires org.xbib.netty.http.common; - requires org.xbib.net.url; + requires org.xbib.net; requires io.netty.buffer; requires io.netty.common; requires io.netty.transport; diff --git a/netty-http-client-api/src/main/java/org/xbib/netty/http/client/api/Request.java b/netty-http-client-api/src/main/java/org/xbib/netty/http/client/api/Request.java index f6e2a80..9aef6c2 100644 --- a/netty-http-client-api/src/main/java/org/xbib/netty/http/client/api/Request.java +++ b/netty-http-client-api/src/main/java/org/xbib/netty/http/client/api/Request.java @@ -16,6 +16,7 @@ import io.netty.handler.codec.http.websocketx.WebSocketFrame; import io.netty.handler.codec.http2.HttpConversionUtil; import io.netty.util.AsciiString; import org.xbib.net.URL; +import org.xbib.net.URLBuilder; import org.xbib.netty.http.common.HttpAddress; import org.xbib.netty.http.common.HttpResponse; import org.xbib.netty.http.common.cookie.Cookie; @@ -668,7 +669,7 @@ public final class Request implements AutoCloseable { validatedHeaders.set(headers); if (url != null) { // add our URI parameters to the URL - URL.Builder mutator = url.mutator(); + URLBuilder mutator = url.mutator(); uriParameters.forEach(e -> mutator.queryParam(e.getKey(), e.getValue())); // calling build() performs extra percent encoding! url = mutator.build(); diff --git a/netty-http-client-rest/src/main/java/module-info.java b/netty-http-client-rest/src/main/java/module-info.java index 67e48b3..b86f169 100644 --- a/netty-http-client-rest/src/main/java/module-info.java +++ b/netty-http-client-rest/src/main/java/module-info.java @@ -5,5 +5,5 @@ module org.xbib.netty.http.client.rest { requires org.xbib.netty.http.client.api; requires io.netty.buffer; requires io.netty.codec.http; - requires org.xbib.net.url; + requires org.xbib.net; } diff --git a/netty-http-client/src/main/java/module-info.java b/netty-http-client/src/main/java/module-info.java index 7e025a8..e4cb63e 100644 --- a/netty-http-client/src/main/java/module-info.java +++ b/netty-http-client/src/main/java/module-info.java @@ -13,7 +13,7 @@ module org.xbib.netty.http.client { exports org.xbib.netty.http.client.transport; requires transitive org.xbib.netty.http.client.api; requires transitive org.xbib.netty.http.common; - requires org.xbib.net.url; + requires org.xbib.net; requires io.netty.handler.proxy; requires java.logging; requires io.netty.transport; diff --git a/netty-http-client/src/main/java/org/xbib/netty/http/client/transport/BaseTransport.java b/netty-http-client/src/main/java/org/xbib/netty/http/client/transport/BaseTransport.java index 965524d..fdae87d 100644 --- a/netty-http-client/src/main/java/org/xbib/netty/http/client/transport/BaseTransport.java +++ b/netty-http-client/src/main/java/org/xbib/netty/http/client/transport/BaseTransport.java @@ -291,7 +291,7 @@ public abstract class BaseTransport implements ClientTransport { Request.Builder newHttpRequestBuilder = Request.builder(method, request) .url(redirUrl); request.url().getQueryParams().forEach(pair -> - newHttpRequestBuilder.addParameter(pair.getFirst(), pair.getSecond()) + newHttpRequestBuilder.addParameter(pair.getKey(), pair.getValue()) ); request.cookies().forEach(newHttpRequestBuilder::addCookie); Request newHttpRequest = newHttpRequestBuilder.build(); diff --git a/netty-http-common/build.gradle b/netty-http-common/build.gradle index e00cd75..6a5cb89 100644 --- a/netty-http-common/build.gradle +++ b/netty-http-common/build.gradle @@ -1,4 +1,4 @@ dependencies { - api libs.net.url + api libs.net api libs.netty.http2 } diff --git a/netty-http-common/src/main/java/module-info.java b/netty-http-common/src/main/java/module-info.java index b1cafc3..5327691 100644 --- a/netty-http-common/src/main/java/module-info.java +++ b/netty-http-common/src/main/java/module-info.java @@ -5,7 +5,7 @@ module org.xbib.netty.http.common { exports org.xbib.netty.http.common.security; exports org.xbib.netty.http.common.util; exports org.xbib.netty.http.common.ws; - requires org.xbib.net.url; + requires org.xbib.net; requires io.netty.buffer; requires io.netty.common; requires io.netty.transport; diff --git a/netty-http-server-api/src/main/java/module-info.java b/netty-http-server-api/src/main/java/module-info.java index 1a84cb3..848d3aa 100644 --- a/netty-http-server-api/src/main/java/module-info.java +++ b/netty-http-server-api/src/main/java/module-info.java @@ -1,7 +1,7 @@ module org.xbib.netty.http.server.api { exports org.xbib.netty.http.server.api; requires org.xbib.netty.http.common; - requires org.xbib.net.url; + requires org.xbib.net; requires io.netty.buffer; requires io.netty.common; requires io.netty.handler; diff --git a/netty-http-server/build.gradle b/netty-http-server/build.gradle index f2af2c6..06de66f 100644 --- a/netty-http-server/build.gradle +++ b/netty-http-server/build.gradle @@ -2,6 +2,7 @@ dependencies { api project(":netty-http-server-api") api project(":netty-http-common") + implementation libs.net.path testImplementation project(":netty-http-client") testImplementation project(":netty-http-bouncycastle") testRuntimeOnly libs.javassist diff --git a/netty-http-server/src/main/java/module-info.java b/netty-http-server/src/main/java/module-info.java index 5c49bcb..1ec35ff 100644 --- a/netty-http-server/src/main/java/module-info.java +++ b/netty-http-server/src/main/java/module-info.java @@ -16,7 +16,8 @@ module org.xbib.netty.http.server { exports org.xbib.netty.http.server.util; requires transitive org.xbib.netty.http.server.api; requires transitive org.xbib.netty.http.common; - requires org.xbib.net.url; + requires org.xbib.net; + requires org.xbib.net.path; requires java.logging; requires io.netty.buffer; requires io.netty.common; diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/HttpServerRequest.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/HttpServerRequest.java index a790cd5..2b8d68d 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/HttpServerRequest.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/HttpServerRequest.java @@ -7,9 +7,10 @@ import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpUtil; -import org.xbib.net.Pair; +import org.xbib.datastructures.common.Pair; +import org.xbib.net.Parameter; +import org.xbib.net.ParameterBuilder; import org.xbib.net.PercentDecoder; -import org.xbib.net.QueryParameters; import org.xbib.net.URL; import org.xbib.netty.http.common.HttpParameters; import org.xbib.netty.http.server.api.Domain; @@ -367,7 +368,8 @@ public class HttpServerRequest implements ServerRequest { .charset(charset, CodingErrorAction.REPLACE) .path(fullHttpRequest.uri()) // creates path, query params, fragment .build(); - QueryParameters queryParameters = url.getQueryParams(); + ParameterBuilder queryParameters = Parameter.builder(); + //url.getQueryParams(); CharSequence mimeType = HttpUtil.getMimeType(fullHttpRequest); ByteBuf byteBuf = fullHttpRequest.content(); if (byteBuf != null) { @@ -389,9 +391,9 @@ public class HttpServerRequest implements ServerRequest { .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE)); this.parameters = new HttpParameters(mimeType, charset); - for (Pair pair : queryParameters) { + for (Pair pair : queryParameters.build()) { try { - parameters.addRaw(percentDecoder.decode(pair.getFirst()), percentDecoder.decode(pair.getSecond())); + parameters.addRaw(percentDecoder.decode(pair.getKey()), percentDecoder.decode(pair.getValue().toString())); } catch (Exception e) { // does not happen throw new IllegalArgumentException(pair.toString()); diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/Server.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/Server.java index f971da1..6dd02f9 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/Server.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/Server.java @@ -18,6 +18,7 @@ import io.netty.handler.ssl.SslContext; import io.netty.util.DomainWildcardMappingBuilder; import io.netty.util.Mapping; import org.xbib.net.URL; +import org.xbib.net.URLBuilder; import org.xbib.netty.http.common.HttpAddress; import org.xbib.netty.http.common.HttpChannelInitializer; import org.xbib.netty.http.common.TransportProvider; @@ -241,7 +242,7 @@ public final class Server implements AutoCloseable { } else { throw new IllegalArgumentException("no host header in " + headers); } - URL.Builder builder = URL.builder().scheme(scheme).host(host); + URLBuilder builder = URL.builder().scheme(scheme).host(host); if (port != null) { builder.port(Integer.parseInt(port)); } diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/endpoint/HttpEndpoint.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/endpoint/HttpEndpoint.java index 9d467ed..fb85e02 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/endpoint/HttpEndpoint.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/endpoint/HttpEndpoint.java @@ -1,9 +1,11 @@ package org.xbib.netty.http.server.endpoint; -import org.xbib.net.Pair; -import org.xbib.net.QueryParameters; -import org.xbib.net.path.PathMatcher; -import org.xbib.net.path.PathNormalizer; +import org.xbib.datastructures.common.Pair; +import org.xbib.net.Parameter; +import org.xbib.net.PathNormalizer; +import org.xbib.net.path.simple.Path; +import org.xbib.net.path.simple.PathComparator; +import org.xbib.net.path.simple.PathMatcher; import org.xbib.netty.http.common.HttpMethod; import org.xbib.netty.http.server.api.Domain; import org.xbib.netty.http.server.api.Endpoint; @@ -88,7 +90,7 @@ public class HttpEndpoint implements Endpoint { public ServerRequest resolveRequest(ServerRequest.Builder serverRequestBuilder, Domain>> domain, EndpointResolver> endpointResolver) { - List context = pathMatcher.tokenizePath(getPrefix()); + List context = pathMatcher.tokenize(getPrefix()); serverRequestBuilder.setDomain(domain) .setEndpointResolver(endpointResolver) .setEndpoint((this)) @@ -96,9 +98,9 @@ public class HttpEndpoint implements Endpoint { String pattern = path; String effectiveRequestPath = serverRequestBuilder.getEffectiveRequestPath(); if (pathMatcher.match(pattern, effectiveRequestPath)) { - QueryParameters queryParameters = pathMatcher.extractUriTemplateVariables(pattern, effectiveRequestPath); - for (Pair pair : queryParameters) { - serverRequestBuilder.addPathParameter(pair.getFirst(), pair.getSecond()); + Parameter queryParameters = pathMatcher.extractUriTemplateVariables(pattern, effectiveRequestPath); + for (Pair pair : queryParameters) { + serverRequestBuilder.addPathParameter(pair.getKey(), pair.getValue().toString()); } } return serverRequestBuilder.build(); @@ -134,7 +136,7 @@ public class HttpEndpoint implements Endpoint { static class EndpointPathComparator implements Comparator { - private final Comparator pathComparator; + private final PathComparator pathComparator; EndpointPathComparator(String path) { this.pathComparator = pathMatcher.getPatternComparator(path); @@ -142,7 +144,7 @@ public class HttpEndpoint implements Endpoint { @Override public int compare(HttpEndpoint endpoint1, HttpEndpoint endpoint2) { - return pathComparator.compare(endpoint1.path, endpoint2.path); + return pathComparator.compare(Path.of(endpoint1.path), Path.of(endpoint2.path)); } } diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/FailureTest.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/FailureTest.java new file mode 100644 index 0000000..3517f7a --- /dev/null +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/http1/FailureTest.java @@ -0,0 +1,93 @@ +package org.xbib.netty.http.server.test.http1; + +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.InetAddress; +import java.net.Socket; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.xbib.net.URL; +import org.xbib.netty.http.client.Client; +import org.xbib.netty.http.client.api.Request; +import org.xbib.netty.http.client.api.ResponseListener; +import org.xbib.netty.http.common.HttpAddress; +import org.xbib.netty.http.common.HttpParameters; +import org.xbib.netty.http.common.HttpResponse; +import org.xbib.netty.http.server.HttpServerDomain; +import org.xbib.netty.http.server.Server; +import org.xbib.netty.http.server.test.NettyHttpTestExtension; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(NettyHttpTestExtension.class) +class FailureTest { + + private static final Logger logger = Logger.getLogger(FailureTest.class.getName()); + + /** + * This test checks if the server hangs after a failure. + * @throws Exception exception + */ + @Test + void testFail() throws Exception { + URL url = URL.from("http://localhost:8008/domain/"); + HttpAddress httpAddress = HttpAddress.http1(url); + HttpServerDomain domain = HttpServerDomain.builder(httpAddress) + .singleEndpoint("/fail", "/**", (req, resp) -> { + HttpParameters parameters = req.getParameters(); + logger.log(Level.INFO, "got request " + parameters.toString() + ", sending 302 Found"); + resp.getBuilder().setStatus(HttpResponseStatus.FOUND.code()) + .build().flush(); + }) + .build(); + Server server = Server.builder(domain) + .enableDebug() + .build(); + + Client client = Client.builder() + .build(); + final AtomicBoolean success1 = new AtomicBoolean(false); + try { + server.accept(); + + // send bad request + + /*Socket socket = new Socket(InetAddress.getByName(url.getHost()), url.getPort()); + PrintWriter pw = new PrintWriter(socket.getOutputStream()); + pw.println("GET /::{} HTTP/1.1"); + pw.println("Host: " + url.getHost() + ":" + url.getPort()); + pw.println(""); + pw.flush(); + BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); + String t; + while ((t = br.readLine()) != null) { + logger.log(Level.INFO, t); + } + br.close();*/ + + // send good request + + ResponseListener responseListener1 = (resp) -> { + logger.log(Level.INFO, "got response = " + resp.getStatus()); + success1.set(true); + }; + Request getRequest = Request.get().setVersion(HttpVersion.HTTP_1_1) + .url(server.getServerConfig().getAddress().base().resolve("/fail")) + .addParameter("a", "b") + .setResponseListener(responseListener1) + .build(); + client.execute(getRequest).get(); + + } finally { + server.shutdownGracefully(); + client.shutdownGracefully(); + logger.log(Level.INFO, "server and client shut down"); + } + assertTrue(success1.get()); + } +} diff --git a/settings.gradle b/settings.gradle index b1b26ec..b07d429 100644 --- a/settings.gradle +++ b/settings.gradle @@ -9,30 +9,31 @@ pluginManagement { dependencyResolutionManagement { versionCatalogs { libs { - version('gradle', '7.4.2') - version('groovy', '3.0.9') + version('gradle', '7.5.1') + version('groovy', '3.0.10') version('spock', '2.0-groovy-3.0') - version('junit', '5.8.2') - version('netty', '4.1.77.Final') - version('netty-tcnative', '2.0.52.Final') + version('junit', '5.9.1') + version('netty', '4.1.84.Final') + version('netty-tcnative', '2.0.54.Final') library('groovy-core', 'org.codehaus.groovy', 'groovy').versionRef('groovy') library('spock-core', 'org.spockframework', 'spock-core').versionRef('spock') library('spock-junit4', 'org.spockframework', 'spock-junit4').versionRef('spock') library('junit-jupiter-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit') library('junit-jupiter-params', 'org.junit.jupiter', 'junit-jupiter-params').versionRef('junit') library('junit-jupiter-engine', 'org.junit.jupiter', 'junit-jupiter-engine').versionRef('junit') - library('hamcrest', 'org.hamcrest:hamcrest-library:2.2') + library('hamcrest', 'org.hamcrest', 'hamcrest-library').version('2.2') library('netty-http2', 'io.netty', 'netty-codec-http2').versionRef('netty') library('netty-handler-proxy', 'io.netty', 'netty-handler-proxy').versionRef('netty') library('netty-epoll', 'io.netty', 'netty-transport-native-epoll').versionRef('netty') library('netty-kqueue', 'io.netty', 'netty-transport-native-kqueue').versionRef('netty') library('netty-boringssl', 'io.netty', 'netty-tcnative-boringssl-static').versionRef('netty-tcnative') - library('net-url', 'org.xbib', 'net-url').version('2.1.1') - library('bouncycastle', 'org.bouncycastle', 'bcpkix-jdk18on').version('1.71') + library('net', 'org.xbib', 'net').version('3.0.1') + library('net-path', 'org.xbib', 'net-path').version('3.0.1') + library('bouncycastle', 'org.bouncycastle', 'bcpkix-jdk18on').version('1.72') library('conscrypt', 'org.conscrypt', 'conscrypt-openjdk-uber').version('2.5.2') - library('jackson', 'com.fasterxml.jackson.core', 'jackson-databind').version('2.12.6') - library('guice', 'org.xbib', 'guice').version('4.4.2') - library('javassist', 'org.javassist', 'javassist').version('3.28.0-GA') + library('jackson', 'com.fasterxml.jackson.core', 'jackson-databind').version('2.12.7') + library('guice', 'org.xbib', 'guice').version('5.0.1.0') + library('javassist', 'org.javassist', 'javassist').version('3.29.1-GA') } } }