diff --git a/build.gradle b/build.gradle index 4305628..1573f59 100644 --- a/build.gradle +++ b/build.gradle @@ -64,14 +64,14 @@ subprojects { } test { - if (JavaVersion.current() == JavaVersion.VERSION_1_8) { - jvmArgs "-javaagent:" + configurations.alpnagent.asPath - } + systemProperty 'java.util.logging.config.file', 'src/test/resources/logging.properties' testLogging { - // set this to 'true' to show lot of debug output showStandardStreams = false exceptionFormat = 'full' } + if (JavaVersion.current() == JavaVersion.VERSION_1_8) { + jvmArgs "-javaagent:" + configurations.alpnagent.asPath + } } clean { diff --git a/gradle.properties b/gradle.properties index 6373179..efe7b45 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,17 +1,16 @@ group = org.xbib name = netty-http -version = 4.1.34.0 +version = 4.1.35.0 # main packages -netty.version = 4.1.34.Final +netty.version = 4.1.35.Final tcnative.version = 2.0.22.Final bouncycastle.version = 1.61 alpnagent.version = 2.0.9 -xbib-net-url.version = 1.2.1 +xbib-net-url.version = 1.2.2 # test packages junit.version = 4.12 -# 1.0.1 conscrypt.version = 2.0.0 jackson.version = 2.8.11.1 wagon.version = 3.0.0 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 87b738c..5c2d1cf 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 527b216..c157b6f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Mar 14 13:01:02 CET 2019 +#Mon Apr 22 17:45:04 CEST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.3-all.zip diff --git a/gradlew b/gradlew index af6708f..b0d6d0a 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m"' +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/gradlew.bat b/gradlew.bat index 0f8d593..15e1ee3 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/netty-http-client/src/main/java/org/xbib/netty/http/client/transport/HttpTransport.java b/netty-http-client/src/main/java/org/xbib/netty/http/client/transport/HttpTransport.java index 982ce85..be8237d 100644 --- a/netty-http-client/src/main/java/org/xbib/netty/http/client/transport/HttpTransport.java +++ b/netty-http-client/src/main/java/org/xbib/netty/http/client/transport/HttpTransport.java @@ -80,6 +80,10 @@ public class HttpTransport extends BaseTransport { logger.log(Level.WARNING, "throwable not null for response " + fullHttpResponse, throwable); return; } + if (requests.isEmpty()) { + logger.log(Level.WARNING, "no request present, can not handle response " + fullHttpResponse); + return; + } // streamID is expected to be null, last request on memory is expected to be current, remove request from memory Request request = requests.remove(requests.lastKey()); if (request != null) { diff --git a/netty-http-client/src/test/resources/logging.properties b/netty-http-client/src/test/resources/logging.properties new file mode 100644 index 0000000..b955428 --- /dev/null +++ b/netty-http-client/src/test/resources/logging.properties @@ -0,0 +1,5 @@ +handlers = java.util.logging.ConsoleHandler +.level = FINE +java.util.logging.ConsoleHandler.level = FINE +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter +java.util.logging.SimpleFormatter.format = %1$tFT%1$tT.%1$tL%1$tz [%4$-11s] [%3$s] %5$s %6$s%n 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 f506a2a..b348465 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 @@ -138,7 +138,7 @@ public final class Server { DomainNameMappingBuilder mappingBuilder = new DomainNameMappingBuilder<>(sslContext); for (VirtualServer virtualServer : serverConfig.getVirtualServers()) { String name = virtualServer.getName(); - mappingBuilder.add( name == null ? "*" : name, sslContext); + mappingBuilder.add(name == null ? "*" : name, sslContext); } domainNameMapping = mappingBuilder.build(); } diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/ServerBuilder.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/ServerBuilder.java index e3c704f..a107e46 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/ServerBuilder.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/ServerBuilder.java @@ -224,7 +224,7 @@ public class ServerBuilder { return this; } - public ServerBuilder addVirtualHost(VirtualServer virtualServer) { + public ServerBuilder addVirtualServer(VirtualServer virtualServer) { this.serverConfig.addVirtualServer(virtualServer); return this; } diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/context/ClasspathContextHandler.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/context/ClasspathContextHandler.java new file mode 100644 index 0000000..dd58212 --- /dev/null +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/context/ClasspathContextHandler.java @@ -0,0 +1,53 @@ +package org.xbib.netty.http.server.context; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http.HttpResponseStatus; +import org.xbib.netty.http.server.transport.ServerRequest; +import org.xbib.netty.http.server.transport.ServerResponse; +import org.xbib.netty.http.server.util.MimeTypeUtils; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class ClasspathContextHandler implements ContextHandler { + + private final ClassLoader classLoader; + + private final String prefix; + + public ClasspathContextHandler(ClassLoader classLoader, String prefix) { + this.classLoader = classLoader; + this.prefix = prefix; + } + + @Override + public void serve(ServerRequest serverRequest, ServerResponse serverResponse) throws IOException { + String contextPath = serverRequest.getContextPath(); + URL url = classLoader.getResource(prefix + contextPath); + if (url != null) { + try { + Path path = Paths.get(url.toURI()); + FileChannel fileChannel = (FileChannel) Files.newByteChannel(path); + MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()); + ByteBuf byteBuf = Unpooled.wrappedBuffer(mappedByteBuffer); + try { + String contentType = MimeTypeUtils.guessFromPath(contextPath, false); + serverResponse.write(HttpResponseStatus.OK, contentType, byteBuf); + } finally { + byteBuf.release(); + } + } catch (URISyntaxException e) { + serverResponse.write(HttpResponseStatus.INTERNAL_SERVER_ERROR); + } + } else { + serverResponse.write(HttpResponseStatus.NOT_FOUND); + } + } +} diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/context/ContextInfo.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/context/ContextInfo.java index 470ff38..483cfc8 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/context/ContextInfo.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/context/ContextInfo.java @@ -1,6 +1,6 @@ package org.xbib.netty.http.server.context; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; /** @@ -8,12 +8,13 @@ import java.util.Map; */ public class ContextInfo { - private final Map handlers = new HashMap<>(2); - private final VirtualServer virtualServer; + private final Map methodHandlerMap; + public ContextInfo(VirtualServer virtualServer) { this.virtualServer = virtualServer; + this.methodHandlerMap = new LinkedHashMap<>(); } /** @@ -21,8 +22,8 @@ public class ContextInfo { * * @return the map of supported HTTP methods and their corresponding handlers */ - public Map getHandlers() { - return handlers; + public Map getMethodHandlerMap() { + return methodHandlerMap; } /** @@ -33,11 +34,13 @@ public class ContextInfo { */ public void addHandler(ContextHandler handler, String... methods) { if (methods.length == 0) { - methods = new String[]{"GET"}; - } - for (String method : methods) { - handlers.put(method, handler); - virtualServer.getMethods().add(method); + methodHandlerMap.put("GET", handler); + virtualServer.getMethods().add("GET"); + } else { + for (String method : methods) { + methodHandlerMap.put(method, handler); + virtualServer.getMethods().add(method); + } } } } diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/context/DirectoryContextHandler.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/context/DirectoryContextHandler.java index 9f032fb..02b6e4d 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/context/DirectoryContextHandler.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/context/DirectoryContextHandler.java @@ -2,6 +2,7 @@ package org.xbib.netty.http.server.context; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.handler.codec.http.HttpResponseStatus; import org.xbib.netty.http.server.transport.ServerRequest; import org.xbib.netty.http.server.transport.ServerResponse; @@ -28,11 +29,10 @@ public class DirectoryContextHandler implements ContextHandler { String uri = serverRequest.getRequest().uri(); Path p = path.resolve(uri); ByteBuf byteBuf = read(allocator, p); - serverResponse.write(200, "application/octet-stream", byteBuf); + serverResponse.write(HttpResponseStatus.OK, "application/octet-stream", byteBuf); byteBuf.release(); } - public static ByteBuf read(ByteBufAllocator allocator, Path path) throws IOException { try (SeekableByteChannel sbc = Files.newByteChannel(path); diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/context/NioContextHandler.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/context/NioContextHandler.java new file mode 100644 index 0000000..3af4205 --- /dev/null +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/context/NioContextHandler.java @@ -0,0 +1,42 @@ +package org.xbib.netty.http.server.context; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http.HttpResponseStatus; +import org.xbib.netty.http.server.transport.ServerRequest; +import org.xbib.netty.http.server.transport.ServerResponse; +import org.xbib.netty.http.server.util.MimeTypeUtils; + +import java.io.IOException; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; + +public class NioContextHandler implements ContextHandler { + + private final Path prefix; + + public NioContextHandler(Path prefix) { + this.prefix = prefix; + if (!Files.exists(prefix) || !Files.isDirectory(prefix)) { + throw new IllegalArgumentException("prefix: " + prefix + " (not a directory"); + } + } + + @Override + public void serve(ServerRequest serverRequest, ServerResponse serverResponse) throws IOException { + String requestPath = serverRequest.getRequestPath(); + Path path = prefix.resolve(requestPath.substring(1)); // starts always with '/' + if (Files.exists(path) && Files.isReadable(path)) { + try (FileChannel fileChannel = (FileChannel) Files.newByteChannel(path)) { + MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()); + ByteBuf byteBuf = Unpooled.wrappedBuffer(mappedByteBuffer); + String contentType = MimeTypeUtils.guessFromPath(requestPath, false); + serverResponse.write(HttpResponseStatus.OK, contentType, byteBuf); + } + } else { + serverResponse.write(HttpResponseStatus.NOT_FOUND); + } + } +} diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/context/VirtualServer.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/context/VirtualServer.java index 04d24b8..9fb39ec 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/context/VirtualServer.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/context/VirtualServer.java @@ -24,6 +24,10 @@ public class VirtualServer { private volatile boolean allowGeneratedIndex; + public VirtualServer() { + this(null); + } + /** * Constructs a VirtualServer with the given name. * @@ -94,25 +98,6 @@ public class VirtualServer { return methods; } - /** - * Returns the context handler for the given path. - * If a context is not found for the given path, the search is repeated for - * its parent path, and so on until a base context is found. If neither the - * given path nor any of its parents has a context, an empty context is returned. - * - * @param path the context's path - * @return the context info for the given path, or an empty context if none exists - */ - public ContextInfo getContext(String path) { - path = trimRight(path, '/'); // remove trailing slash - ContextInfo info = null; - while (info == null && path != null) { - info = contexts.get(path); - path = getParentPath(path); - } - return info != null ? info : emptyContext; - } - /** * Adds a context and its corresponding context handler to this server. * Paths are normalized by removing trailing slashes (except the root). @@ -122,15 +107,16 @@ public class VirtualServer { * @param methods the HTTP methods supported by the context handler (default is "GET") * @throws IllegalArgumentException if path is malformed */ - public void addContext(String path, ContextHandler handler, String... methods) { + public VirtualServer addContext(String path, ContextHandler handler, String... methods) { if (path == null || !path.startsWith("/") && !path.equals("*")) { throw new IllegalArgumentException("invalid path: " + path); } - path = trimRight(path, '/'); + String s = trimRight(path, '/'); ContextInfo info = new ContextInfo(this); - ContextInfo existing = contexts.putIfAbsent(path, info); + ContextInfo existing = contexts.putIfAbsent(s, info); info = existing != null ? existing : info; info.addHandler(handler, methods); + return this; } /** @@ -141,17 +127,37 @@ public class VirtualServer { * @throws IllegalArgumentException if a Context-annotated * method has an {@link Context invalid signature} */ - public void addContexts(Object o) throws IllegalArgumentException { + public VirtualServer addContexts(Object o) throws IllegalArgumentException { for (Class c = o.getClass(); c != null; c = c.getSuperclass()) { - // add to contexts those with @Context annotation for (Method m : c.getDeclaredMethods()) { Context context = m.getAnnotation(Context.class); if (context != null) { - //m.setAccessible(true); // allow access to private method addContext(context.value(), new MethodContextHandler(m, o), context.methods()); } } } + return this; + } + + /** + * Returns the context handler for the given path. + * If a context is not found for the given path, the search is repeated for + * its parent path, and so on until a base context is found. If neither the + * given path nor any of its parents has a context, an empty context is returned. + * + * @param path the context's path + * @return the context info for the given path, or an empty context if none exists + */ + public ContextPath getContextPath(String path) { + String s = trimRight(path, '/'); + ContextInfo info = null; + String hook = null; + while (info == null && s != null) { + hook = s; + info = contexts.get(s); + s = getParentPath(s); + } + return new ContextPath(hook, info != null ? info : emptyContext); } /** @@ -179,9 +185,29 @@ public class VirtualServer { * or null if given path is the root path */ private static String getParentPath(String path) { - path = trimRight(path, '/'); // remove trailing slash - int slash = path.lastIndexOf('/'); - return slash == -1 ? null : path.substring(0, slash); + String s = trimRight(path, '/'); // remove trailing slash + int slash = s.lastIndexOf('/'); + return slash == -1 ? null : s.substring(0, slash); + } + + public class ContextPath { + + private final String hook; + + private final ContextInfo contextInfo; + + ContextPath(String hook, ContextInfo contextInfo) { + this.hook = hook; + this.contextInfo = contextInfo; + } + + public String getHook() { + return hook; + } + + public ContextInfo getContextInfo() { + return contextInfo; + } } } diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/BaseServerTransport.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/BaseServerTransport.java index 251e4a3..cd17bc4 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/BaseServerTransport.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/BaseServerTransport.java @@ -3,6 +3,7 @@ package org.xbib.netty.http.server.transport; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import org.xbib.netty.http.server.Server; import org.xbib.netty.http.server.context.ContextHandler; @@ -33,7 +34,7 @@ abstract class BaseServerTransport implements ServerTransport { } @Override - public void exceptionReceived(ChannelHandlerContext ctx, Throwable throwable) throws IOException { + public void exceptionReceived(ChannelHandlerContext ctx, Throwable throwable) { logger.log(Level.WARNING, throwable.getMessage(), throwable); } @@ -54,7 +55,7 @@ abstract class BaseServerTransport implements ServerTransport { case 2: if (!reqHeaders.contains(HttpHeaderNames.HOST)) { // RFC2616#14.23: missing Host header gets 400 - serverResponse.writeError(400, "missing 'Host' header"); + serverResponse.writeError(HttpResponseStatus.BAD_REQUEST, "missing 'Host' header"); return false; } // return a continue response before reading body @@ -65,13 +66,13 @@ abstract class BaseServerTransport implements ServerTransport { //tempResp.sendHeaders(100); } else { // RFC2616#14.20: if unknown expect, send 417 - serverResponse.writeError(417); + serverResponse.writeError(HttpResponseStatus.EXPECTATION_FAILED); return false; } } break; default: - serverResponse.writeError(400, "Unknown version: " + version); + serverResponse.writeError(HttpResponseStatus.BAD_REQUEST, "Unknown version: " + version); return false; } return true; @@ -88,12 +89,14 @@ abstract class BaseServerTransport implements ServerTransport { String method = serverRequest.getRequest().method().name(); String path = serverRequest.getRequest().uri(); VirtualServer virtualServer = serverRequest.getVirtualServer(); - Map handlers = virtualServer.getContext(path).getHandlers(); + VirtualServer.ContextPath contextPath = virtualServer.getContextPath(path); + serverRequest.setContextPath(contextPath.getHook()); + Map methodHandlerMap = contextPath.getContextInfo().getMethodHandlerMap(); // RFC 2616#5.1.1 - GET and HEAD must be supported - if (method.equals("GET") || method.equals("HEAD") || handlers.containsKey(method)) { - ContextHandler handler = virtualServer.getContext(path).getHandlers().get(method); + if (method.equals("GET") || method.equals("HEAD") || methodHandlerMap.containsKey(method)) { + ContextHandler handler = methodHandlerMap.get(method); if (handler == null) { - serverResponse.writeError(404); + serverResponse.writeError(HttpResponseStatus.NOT_FOUND); } else { handler.serve(serverRequest, serverResponse); } @@ -101,15 +104,15 @@ abstract class BaseServerTransport implements ServerTransport { Set methods = new LinkedHashSet<>(METHODS); // "*" is a special server-wide (no-context) request supported by OPTIONS boolean isServerOptions = path.equals("*") && method.equals("OPTIONS"); - methods.addAll(isServerOptions ? virtualServer.getMethods() : handlers.keySet()); + methods.addAll(isServerOptions ? virtualServer.getMethods() : methodHandlerMap.keySet()); serverResponse.setHeader(HttpHeaderNames.ALLOW, String.join(", ", methods)); if (method.equals("OPTIONS")) { // default OPTIONS handler serverResponse.setHeader(HttpHeaderNames.CONTENT_LENGTH, "0"); // RFC2616#9.2 - serverResponse.write(200); + serverResponse.write(HttpResponseStatus.OK); } else if (virtualServer.getMethods().contains(method)) { - serverResponse.write(405); // supported by server, but not this context (nor built-in) + serverResponse.write(HttpResponseStatus.METHOD_NOT_ALLOWED); // supported by server, but not this context (nor built-in) } else { - serverResponse.writeError(501); // unsupported method + serverResponse.writeError(HttpResponseStatus.NOT_IMPLEMENTED); // unsupported method } } } diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/Http2ServerResponse.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/Http2ServerResponse.java index e495544..182f98b 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/Http2ServerResponse.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/Http2ServerResponse.java @@ -41,7 +41,7 @@ public class Http2ServerResponse implements ServerResponse { @Override public void write(String text) { - write(200, "text/plain; charset=utf-8", text); + write(HttpResponseStatus.OK, "text/plain; charset=utf-8", text); } /** @@ -50,8 +50,8 @@ public class Http2ServerResponse implements ServerResponse { * @param status the response status */ @Override - public void writeError(int status) { - writeError(status, status < 400 ? ":)" : "sorry it didn't work out :("); + public void writeError(HttpResponseStatus status) { + writeError(status, status.code() < 400 ? ":)" : "sorry it didn't work out :("); } /** @@ -64,32 +64,32 @@ public class Http2ServerResponse implements ServerResponse { * @param text the text body (sent as text/html) */ @Override - public void writeError(int status, String text) { + public void writeError(HttpResponseStatus status, String text) { write(status, "text/html; charset=utf-8", String.format("%n%n%d %s%n" + "

%d %s

%n

%s

%n", - status, HttpResponseStatus.valueOf(status).reasonPhrase(), - status, HttpResponseStatus.valueOf(status).reasonPhrase(), + status.code(), status.reasonPhrase(), + status.code(), status.reasonPhrase(), escapeHTML(text))); } @Override - public void write(int status) { + public void write(HttpResponseStatus status) { write(status, null, (ByteBuf) null); } @Override - public void write(int status, String contentType, String text) { + public void write(HttpResponseStatus status, String contentType, String text) { write(status, contentType, ByteBufUtil.writeUtf8(ctx.alloc(), text)); } @Override - public void write(int status, String contentType, String text, Charset charset) { + public void write(HttpResponseStatus status, String contentType, String text, Charset charset) { write(status, contentType, ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.allocate(text.length()).append(text), charset)); } @Override - public void write(int status, String contentType, ByteBuf byteBuf) { + public void write(HttpResponseStatus status, String contentType, ByteBuf byteBuf) { if (byteBuf != null) { CharSequence s = headers.get(HttpHeaderNames.CONTENT_TYPE); if (s == null) { @@ -120,7 +120,7 @@ public class Http2ServerResponse implements ServerResponse { } } Http2Headers http2Headers = new DefaultHttp2Headers() - .status(HttpResponseStatus.valueOf(status).codeAsText()) + .status(status.codeAsText()) .add(headers); ctx.channel().write(new DefaultHttp2HeadersFrame(http2Headers,byteBuf == null)); if (byteBuf != null) { diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/Http2ServerTransport.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/Http2ServerTransport.java index 69e29b6..3280dfb 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/Http2ServerTransport.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/Http2ServerTransport.java @@ -3,6 +3,7 @@ package org.xbib.netty.http.server.transport; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http2.Http2Settings; import io.netty.handler.codec.http2.HttpConversionUtil; import org.xbib.netty.http.common.HttpAddress; @@ -36,6 +37,8 @@ public class Http2ServerTransport extends BaseServerTransport { ServerResponse serverResponse = new Http2ServerResponse(serverRequest, ctx); if (acceptRequest(serverRequest, serverResponse)) { handle(serverRequest, serverResponse); + } else { + serverResponse.write(HttpResponseStatus.NOT_ACCEPTABLE); } } diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/HttpServerResponse.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/HttpServerResponse.java index e381b69..df9821a 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/HttpServerResponse.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/HttpServerResponse.java @@ -21,12 +21,9 @@ import java.nio.charset.Charset; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.logging.Logger; public class HttpServerResponse implements ServerResponse { - private static final Logger logger = Logger.getLogger(HttpServerResponse.class.getName()); - private final ServerRequest serverRequest; private final ChannelHandlerContext ctx; @@ -49,7 +46,7 @@ public class HttpServerResponse implements ServerResponse { @Override public void write(String text) { - write(200, "text/plain; charset=utf-8", text); + write(HttpResponseStatus.OK, "text/plain; charset=utf-8", text); } /** @@ -58,8 +55,8 @@ public class HttpServerResponse implements ServerResponse { * @param status the response status */ @Override - public void writeError(int status) { - writeError(status, status < 400 ? ":)" : "sorry it didn't work out :("); + public void writeError(HttpResponseStatus status) { + writeError(status, status.code() < 400 ? ":)" : "sorry it didn't work out :("); } /** @@ -72,32 +69,32 @@ public class HttpServerResponse implements ServerResponse { * @param text the text body (sent as text/html) */ @Override - public void writeError(int status, String text) { + public void writeError(HttpResponseStatus status, String text) { write(status, "text/html; charset=utf-8", String.format("%n%n%d %s%n" + "

%d %s

%n

%s

%n", - status, HttpResponseStatus.valueOf(status).reasonPhrase(), - status, HttpResponseStatus.valueOf(status).reasonPhrase(), + status.code(), status.reasonPhrase(), + status.code(), status.reasonPhrase(), escapeHTML(text))); } @Override - public void write(int status) { + public void write(HttpResponseStatus status) { write(status, null, (ByteBuf) null); } @Override - public void write(int status, String contentType, String text) { + public void write(HttpResponseStatus status, String contentType, String text) { write(status, contentType, ByteBufUtil.writeUtf8(ctx.alloc(), text)); } @Override - public void write(int status, String contentType, String text, Charset charset) { + public void write(HttpResponseStatus status, String contentType, String text, Charset charset) { write(status, contentType, ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.allocate(text.length()).append(text), charset)); } @Override - public void write(int status, String contentType, ByteBuf byteBuf) { + public void write(HttpResponseStatus status, String contentType, ByteBuf byteBuf) { if (byteBuf != null) { CharSequence s = headers.get(HttpHeaderNames.CONTENT_TYPE); if (s == null) { @@ -123,9 +120,9 @@ public class HttpServerResponse implements ServerResponse { } FullHttpResponse fullHttpResponse = byteBuf != null ? new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, - HttpResponseStatus.valueOf(status), byteBuf, headers, trailingHeaders) : + status, byteBuf, headers, trailingHeaders) : new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, - HttpResponseStatus.valueOf(status), Unpooled.EMPTY_BUFFER, headers, trailingHeaders); + status, Unpooled.EMPTY_BUFFER, headers, trailingHeaders); if (serverRequest != null && serverRequest.getSequenceId() != null) { HttpPipelinedResponse httpPipelinedResponse = new HttpPipelinedResponse(fullHttpResponse, ctx.channel().newPromise(), serverRequest.getSequenceId()); @@ -176,7 +173,7 @@ public class HttpServerResponse implements ServerResponse { break; } if (ref != null) { - es.append(s.substring(start, i)).append(ref); + es.append(s, start, i).append(ref); start = i + 1; } } diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/HttpServerTransport.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/HttpServerTransport.java index c6962dc..cfa2cba 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/HttpServerTransport.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/HttpServerTransport.java @@ -3,6 +3,7 @@ package org.xbib.netty.http.server.transport; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http2.Http2Settings; import org.xbib.netty.http.common.HttpAddress; import org.xbib.netty.http.server.Server; @@ -35,6 +36,8 @@ public class HttpServerTransport extends BaseServerTransport { ServerResponse serverResponse = new HttpServerResponse(serverRequest, ctx); if (acceptRequest(serverRequest, serverResponse)) { handle(serverRequest, serverResponse); + } else { + serverResponse.write(HttpResponseStatus.NOT_ACCEPTABLE); } } diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/ServerRequest.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/ServerRequest.java index 3bd4559..9b766cd 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/ServerRequest.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/ServerRequest.java @@ -21,6 +21,8 @@ public class ServerRequest { private final Integer requestId; + private String contextPath; + public ServerRequest(VirtualServer virtualServer, HttpAddress httpAddress, FullHttpRequest httpRequest, Integer sequenceId, Integer streamId, Integer requestId) { this.virtualServer = virtualServer; @@ -35,6 +37,18 @@ public class ServerRequest { return virtualServer; } + public void setContextPath(String contextPath) { + this.contextPath = contextPath; + } + + public String getContextPath() { + return contextPath; + } + + public String getRequestPath() { + return contextPath != null ? httpRequest.uri().substring(contextPath.length()) : httpRequest.uri(); + } + public HttpAddress getHttpAddress() { return httpAddress; } diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/ServerResponse.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/ServerResponse.java index 297e813..c4dd0ee 100644 --- a/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/ServerResponse.java +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/transport/ServerResponse.java @@ -1,6 +1,7 @@ package org.xbib.netty.http.server.transport; import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.util.AsciiString; import java.nio.charset.Charset; @@ -14,16 +15,16 @@ public interface ServerResponse { void write(String text); - void writeError(int status); + void writeError(HttpResponseStatus status); - void writeError(int status, String text); + void writeError(HttpResponseStatus status, String text); - void write(int status); + void write(HttpResponseStatus status); - void write(int status, String contentType, String text); + void write(HttpResponseStatus status, String contentType, String text); - void write(int status, String contentType, String text, Charset charset); + void write(HttpResponseStatus status, String contentType, String text, Charset charset); - void write(int status, String contentType, ByteBuf byteBuf); + void write(HttpResponseStatus status, String contentType, ByteBuf byteBuf); } diff --git a/netty-http-server/src/main/java/org/xbib/netty/http/server/util/MimeTypeUtils.java b/netty-http-server/src/main/java/org/xbib/netty/http/server/util/MimeTypeUtils.java new file mode 100644 index 0000000..ed14c18 --- /dev/null +++ b/netty-http-server/src/main/java/org/xbib/netty/http/server/util/MimeTypeUtils.java @@ -0,0 +1,81 @@ +package org.xbib.netty.http.server.util; + +import java.net.URLConnection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import static java.util.Objects.requireNonNull; + +public class MimeTypeUtils { + + /** + * A map from extension to MIME types, which is queried before + * {@link URLConnection#guessContentTypeFromName(String)}, so that + * important extensions are always mapped to the right MIME types. + */ + private static final Map EXTENSION_TO_MEDIA_TYPE; + + static { + Map map = new HashMap<>(); + // Text files + add(map, "text/css", "css"); + add(map, "text/html", "html", "htm"); + add(map, "text/plain", "txt"); + + // Image files + add(map, "image/gif", "gif"); + add(map, "image/jpeg", "jpeg", "jpg"); + add(map, "image/png", "png"); + add(map, "image/svg+xml", "svg", "svgz"); + add(map, "image/x-icon", "ico"); + + // Font files + add(map, "application/x-font-ttf", "ttc", "ttf"); + add(map, "application/font-woff", "woff"); + add(map, "application/font-woff2", "woff2"); + add(map, "application/vnd.ms-fontobject", "eot"); + add(map, "font/opentype", "otf"); + + // JavaScript, XML, etc + add(map, "application/javascript", "js", "map"); + add(map, "application/json", "json"); + add(map, "application/pdf", "pdf"); + add(map, "application/xhtml+xml", "xhtml", "xhtm"); + add(map, "application/xml", "xml", "xsd"); + add(map, "application/xml-dtd", "dtd"); + + EXTENSION_TO_MEDIA_TYPE = Collections.unmodifiableMap(map); + } + + private static void add(Map extensionToMediaType, + String mediaType, String... extensions) { + for (String s : extensions) { + extensionToMediaType.put(s, mediaType); + } + } + + public static String guessFromPath(String path, boolean preCompressed) { + requireNonNull(path, "path"); + String s = path; + // If the path is for a precompressed file, it will have an additional extension indicating the + // encoding, which we don't want to use when determining content type. + if (preCompressed) { + s = s.substring(0, s.lastIndexOf('.')); + } + int dotIdx = s.lastIndexOf('.'); + int slashIdx = s.lastIndexOf('/'); + if (dotIdx < 0 || slashIdx > dotIdx) { + // No extension + return null; + } + String extension = s.substring(dotIdx + 1).toLowerCase(Locale.ROOT); + String mediaType = EXTENSION_TO_MEDIA_TYPE.get(extension); + if (mediaType != null) { + return mediaType; + } + String guessedContentType = URLConnection.guessContentTypeFromName(path); + return guessedContentType != null ? guessedContentType : "application/octet-stream"; + } +} diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/CleartextHttp1Test.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/CleartextHttp1Test.java index 9381ef6..b332bbb 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/CleartextHttp1Test.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/CleartextHttp1Test.java @@ -1,8 +1,8 @@ package org.xbib.netty.http.server.test; +import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import org.junit.Test; -import org.xbib.TestBase; import org.xbib.netty.http.client.Client; import org.xbib.netty.http.client.Request; import org.xbib.netty.http.client.listener.ResponseListener; @@ -30,7 +30,7 @@ public class CleartextHttp1Test extends TestBase { Server server = Server.builder() .bind(httpAddress).build(); server.getDefaultVirtualServer().addContext("/", (request, response) -> - response.write(200, "text/plain", request.getRequest().content().retain())); + response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain())); server.accept(); Client client = Client.builder() .build(); @@ -63,7 +63,7 @@ public class CleartextHttp1Test extends TestBase { //.enableDebug() .bind(httpAddress).build(); server.getDefaultVirtualServer().addContext("/", (request, response) -> { - response.write(200, "text/plain", request.getRequest().content().retain()); + response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain()); }); server.accept(); Client client = Client.builder() @@ -109,7 +109,7 @@ public class CleartextHttp1Test extends TestBase { //.enableDebug() .bind(httpAddress).build(); server.getDefaultVirtualServer().addContext("/", (request, response) -> { - response.write(200, "text/plain", request.getRequest().content().retain()); + response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain()); }); server.accept(); Client client = Client.builder() diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/CleartextHttp2Test.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/CleartextHttp2Test.java index 8d58d24..ef4011d 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/CleartextHttp2Test.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/CleartextHttp2Test.java @@ -1,7 +1,7 @@ package org.xbib.netty.http.server.test; +import io.netty.handler.codec.http.HttpResponseStatus; import org.junit.Test; -import org.xbib.TestBase; import org.xbib.netty.http.client.Client; import org.xbib.netty.http.client.Request; import org.xbib.netty.http.client.listener.ResponseListener; @@ -31,7 +31,7 @@ public class CleartextHttp2Test extends TestBase { .bind(httpAddress) .build(); server.getDefaultVirtualServer().addContext("/", (request, response) -> - response.write(200, "text/plain", request.getRequest().content().retain())); + response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain())); server.accept(); Client client = Client.builder() .build(); @@ -71,7 +71,7 @@ public class CleartextHttp2Test extends TestBase { Server server = Server.builder() .bind(httpAddress).build(); server.getDefaultVirtualServer().addContext("/", (request, response) -> - response.write(200, "text/plain", request.getRequest().content().retain())); + response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain())); //server.getDefaultVirtualServer().addContext("/", (request, response) -> // response.write(request.getRequest().content().toString(StandardCharsets.UTF_8))); server.accept(); diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/SecureHttp1Test.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/SecureHttp1Test.java index cd3400b..322eaa2 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/SecureHttp1Test.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/SecureHttp1Test.java @@ -1,10 +1,9 @@ package org.xbib.netty.http.server.test; +import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.junit.Ignore; import org.junit.Test; -import org.xbib.TestBase; import org.xbib.netty.http.client.Client; import org.xbib.netty.http.client.Request; import org.xbib.netty.http.client.listener.ResponseListener; @@ -53,7 +52,7 @@ public class SecureHttp1Test extends TestBase { }; try { server.getDefaultVirtualServer().addContext("/", (request, response) -> - response.write(200, "text/plain", request.getRequest().content().retain())); + response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain())); server.accept(); Request request = Request.get().setVersion(HttpVersion.HTTP_1_1) .url(server.getServerConfig().getAddress().base()) @@ -77,7 +76,7 @@ public class SecureHttp1Test extends TestBase { .setSelfCert() .bind(httpAddress).build(); server.getDefaultVirtualServer().addContext("/", (request, response) -> - response.write(200, "text/plain", request.getRequest().content().retain())); + response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain())); server.accept(); Client client = Client.builder() .setJdkSslProvider() @@ -125,7 +124,7 @@ public class SecureHttp1Test extends TestBase { .bind(httpAddress) .build(); server.getDefaultVirtualServer().addContext("/", (request, response) -> - response.write(200, "text/plain", request.getRequest().content().retain()) + response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain()) ); server.accept(); Client client = Client.builder() diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/SecureHttp2Test.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/SecureHttp2Test.java index 60a26a3..805bd31 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/SecureHttp2Test.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/SecureHttp2Test.java @@ -1,9 +1,8 @@ package org.xbib.netty.http.server.test; +import io.netty.handler.codec.http.HttpResponseStatus; import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.junit.Ignore; import org.junit.Test; -import org.xbib.TestBase; import org.xbib.netty.http.client.Client; import org.xbib.netty.http.client.Request; import org.xbib.netty.http.client.listener.ResponseListener; @@ -42,7 +41,7 @@ public class SecureHttp2Test extends TestBase { .bind(httpAddress) .build(); server.getDefaultVirtualServer().addContext("/", (request, response) -> - response.write(200, "text/plain", request.getRequest().content().retain())); + response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain())); server.accept(); Client client = Client.builder() .setJdkSslProvider() @@ -86,7 +85,7 @@ public class SecureHttp2Test extends TestBase { .bind(httpAddress) .build(); server.getDefaultVirtualServer().addContext("/", (request, response) -> - response.write(200, "text/plain", request.getRequest().content().retain())); + response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain())); server.accept(); Client client = Client.builder() .setJdkSslProvider() @@ -138,7 +137,7 @@ public class SecureHttp2Test extends TestBase { .bind(httpAddress) .build(); server.getDefaultVirtualServer().addContext("/", (request, response) -> - response.write(200, "text/plain", request.getRequest().content().retain()) + response.write(HttpResponseStatus.OK, "text/plain", request.getRequest().content().retain()) ); server.accept(); Client client = Client.builder() diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/StaticFileServerTest.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/StaticFileServerTest.java new file mode 100644 index 0000000..346dec1 --- /dev/null +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/StaticFileServerTest.java @@ -0,0 +1,55 @@ +package org.xbib.netty.http.server.test; + +import io.netty.handler.codec.http.HttpVersion; +import org.junit.Test; +import org.xbib.netty.http.client.Client; +import org.xbib.netty.http.client.Request; +import org.xbib.netty.http.server.Server; +import org.xbib.netty.http.server.context.NioContextHandler; +import org.xbib.netty.http.server.context.VirtualServer; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class StaticFileServerTest { + + private static final Logger logger = Logger.getLogger(StaticFileServerTest.class.getName()); + + @Test + public void testStaticFileServer() throws Exception { + Path vartmp = Paths.get("/var/tmp/"); + Server server = Server.builder() + .addVirtualServer(new VirtualServer().addContext("/static", new NioContextHandler(vartmp))) + .build(); + Client client = Client.builder() + .build(); + final AtomicBoolean success = new AtomicBoolean(false); + try { + Files.write(vartmp.resolve("test.txt"), "Hello Jörg".getBytes(StandardCharsets.UTF_8)); + server.accept(); + Request request = Request.get().setVersion(HttpVersion.HTTP_1_1) + .url(server.getServerConfig().getAddress().base().resolve("/static/test.txt")) + .build() + .setResponseListener(r -> { + assertEquals("Hello Jörg", r.content().toString(StandardCharsets.UTF_8)); + success.set(true); + }); + logger.log(Level.INFO, request.toString()); + client.execute(request).get(); + logger.log(Level.INFO, "request complete"); + } finally { + server.shutdownGracefully(); + client.shutdownGracefully(); + Files.delete(vartmp.resolve("test.txt")); + } + assertTrue(success.get()); + } +} diff --git a/netty-http-server/src/test/java/org/xbib/TestBase.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/TestBase.java similarity index 96% rename from netty-http-server/src/test/java/org/xbib/TestBase.java rename to netty-http-server/src/test/java/org/xbib/netty/http/server/test/TestBase.java index 7b46847..126e379 100644 --- a/netty-http-server/src/test/java/org/xbib/TestBase.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/TestBase.java @@ -1,4 +1,4 @@ -package org.xbib; +package org.xbib.netty.http.server.test; import java.util.logging.ConsoleHandler; import java.util.logging.Handler; diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/ThreadLeakTest.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/ThreadLeakTest.java index bbe63be..ecbe611 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/server/test/ThreadLeakTest.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/ThreadLeakTest.java @@ -3,7 +3,6 @@ package org.xbib.netty.http.server.test; import io.netty.buffer.UnpooledByteBufAllocator; import org.junit.After; import org.junit.Test; -import org.xbib.TestBase; import org.xbib.netty.http.server.Server; import java.io.IOException; diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/hacks/CleartextHttp2Test.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/CleartextHttp2Test.java similarity index 99% rename from netty-http-server/src/test/java/org/xbib/netty/http/hacks/CleartextHttp2Test.java rename to netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/CleartextHttp2Test.java index a4ffe5d..44b1fe3 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/hacks/CleartextHttp2Test.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/CleartextHttp2Test.java @@ -1,4 +1,4 @@ -package org.xbib.netty.http.hacks; +package org.xbib.netty.http.server.test.hacks; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; @@ -31,7 +31,7 @@ import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import org.junit.Ignore; import org.junit.Test; -import org.xbib.TestBase; +import org.xbib.netty.http.server.test.TestBase; import java.net.InetSocketAddress; import java.util.concurrent.CompletableFuture; diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/hacks/HttpPipeliningHandlerTest.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/HttpPipeliningHandlerTest.java similarity index 98% rename from netty-http-server/src/test/java/org/xbib/netty/http/hacks/HttpPipeliningHandlerTest.java rename to netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/HttpPipeliningHandlerTest.java index 5f82f00..3005170 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/hacks/HttpPipeliningHandlerTest.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/HttpPipeliningHandlerTest.java @@ -1,4 +1,4 @@ -package org.xbib.netty.http.hacks; +package org.xbib.netty.http.server.test.hacks; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; @@ -24,7 +24,7 @@ import org.junit.Test; import org.xbib.netty.http.server.handler.http.HttpPipelinedRequest; import org.xbib.netty.http.server.handler.http.HttpPipelinedResponse; import org.xbib.netty.http.server.handler.http.HttpPipeliningHandler; -import org.xbib.TestBase; +import org.xbib.netty.http.server.test.TestBase; import java.nio.channels.ClosedChannelException; import java.nio.charset.StandardCharsets; diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/hacks/MultiplexCodecCleartextHttp2Test.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/MultiplexCodecCleartextHttp2Test.java similarity index 99% rename from netty-http-server/src/test/java/org/xbib/netty/http/hacks/MultiplexCodecCleartextHttp2Test.java rename to netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/MultiplexCodecCleartextHttp2Test.java index 10cb1b8..eb0a8e8 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/hacks/MultiplexCodecCleartextHttp2Test.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/MultiplexCodecCleartextHttp2Test.java @@ -1,4 +1,4 @@ -package org.xbib.netty.http.hacks; +package org.xbib.netty.http.server.test.hacks; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; @@ -43,7 +43,7 @@ import io.netty.handler.logging.LoggingHandler; import io.netty.util.AsciiString; import org.junit.Ignore; import org.junit.Test; -import org.xbib.TestBase; +import org.xbib.netty.http.server.test.TestBase; import java.net.InetSocketAddress; import java.util.concurrent.CompletableFuture; diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/hacks/MultithreadedCleartextHttp2Test.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/MultithreadedCleartextHttp2Test.java similarity index 99% rename from netty-http-server/src/test/java/org/xbib/netty/http/hacks/MultithreadedCleartextHttp2Test.java rename to netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/MultithreadedCleartextHttp2Test.java index 47a45fe..a527983 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/hacks/MultithreadedCleartextHttp2Test.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/MultithreadedCleartextHttp2Test.java @@ -1,4 +1,4 @@ -package org.xbib.netty.http.hacks; +package org.xbib.netty.http.server.test.hacks; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; @@ -29,7 +29,7 @@ import io.netty.handler.codec.http2.HttpToHttp2ConnectionHandlerBuilder; import io.netty.handler.codec.http2.InboundHttp2ToHttpAdapterBuilder; import org.junit.Ignore; import org.junit.Test; -import org.xbib.TestBase; +import org.xbib.netty.http.server.test.TestBase; import java.net.InetSocketAddress; import java.util.concurrent.CompletableFuture; diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/hacks/MultithreadedMultiplexCodecCleartextHttp2Test.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/MultithreadedMultiplexCodecCleartextHttp2Test.java similarity index 99% rename from netty-http-server/src/test/java/org/xbib/netty/http/hacks/MultithreadedMultiplexCodecCleartextHttp2Test.java rename to netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/MultithreadedMultiplexCodecCleartextHttp2Test.java index 32e9a44..94b61cc 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/hacks/MultithreadedMultiplexCodecCleartextHttp2Test.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/MultithreadedMultiplexCodecCleartextHttp2Test.java @@ -1,4 +1,4 @@ -package org.xbib.netty.http.hacks; +package org.xbib.netty.http.server.test.hacks; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; @@ -37,7 +37,7 @@ import io.netty.handler.codec.http2.Http2StreamFrameToHttpObjectCodec; import io.netty.util.AsciiString; import org.junit.Ignore; import org.junit.Test; -import org.xbib.TestBase; +import org.xbib.netty.http.server.test.TestBase; import java.net.InetSocketAddress; import java.util.concurrent.CompletableFuture; diff --git a/netty-http-server/src/test/java/org/xbib/netty/http/hacks/package-info.java b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/package-info.java similarity index 53% rename from netty-http-server/src/test/java/org/xbib/netty/http/hacks/package-info.java rename to netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/package-info.java index 61b2924..d316592 100644 --- a/netty-http-server/src/test/java/org/xbib/netty/http/hacks/package-info.java +++ b/netty-http-server/src/test/java/org/xbib/netty/http/server/test/hacks/package-info.java @@ -1,4 +1,4 @@ /** * Hacking Netty for showing server functions. */ -package org.xbib.netty.http.hacks; +package org.xbib.netty.http.server.test.hacks; diff --git a/netty-http-server/src/test/resources/logging.properties b/netty-http-server/src/test/resources/logging.properties new file mode 100644 index 0000000..b955428 --- /dev/null +++ b/netty-http-server/src/test/resources/logging.properties @@ -0,0 +1,5 @@ +handlers = java.util.logging.ConsoleHandler +.level = FINE +java.util.logging.ConsoleHandler.level = FINE +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter +java.util.logging.SimpleFormatter.format = %1$tFT%1$tT.%1$tL%1$tz [%4$-11s] [%3$s] %5$s %6$s%n