diff --git a/avaje-jex/src/main/java/io/avaje/jex/Context.java b/avaje-jex/src/main/java/io/avaje/jex/Context.java index 3cebb73f..1b94b007 100644 --- a/avaje-jex/src/main/java/io/avaje/jex/Context.java +++ b/avaje-jex/src/main/java/io/avaje/jex/Context.java @@ -3,6 +3,7 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; +import java.io.InputStream; import java.time.Duration; import java.time.LocalDateTime; import java.time.ZoneId; @@ -278,6 +279,16 @@ default String userAgent() { */ Context write(String content); + /** + * Write raw bytes to the response. + */ + Context write(byte[] bytes); + + /** + * Write raw inputStream to the response. + */ + Context write(InputStream is); + /** * Render a template typically as html. * diff --git a/avaje-jex/src/main/java/io/avaje/jex/DJexConfig.java b/avaje-jex/src/main/java/io/avaje/jex/DJexConfig.java index 0b4e5b51..536380c9 100644 --- a/avaje-jex/src/main/java/io/avaje/jex/DJexConfig.java +++ b/avaje-jex/src/main/java/io/avaje/jex/DJexConfig.java @@ -89,7 +89,7 @@ public ThreadFactory threadFactory() { if (factory == null) { factory = - Thread.ofVirtual().name("jex-http-", 0).factory(); + Thread.ofVirtual().name("avaje-jex-http-", 0).factory(); } return factory; diff --git a/avaje-jex/src/main/java/io/avaje/jex/TemplateRender.java b/avaje-jex/src/main/java/io/avaje/jex/TemplateRender.java index 1d58d8f4..562d3aaa 100644 --- a/avaje-jex/src/main/java/io/avaje/jex/TemplateRender.java +++ b/avaje-jex/src/main/java/io/avaje/jex/TemplateRender.java @@ -11,10 +11,9 @@ public non-sealed interface TemplateRender extends JexExtension { /** * Return the extensions this template renders for by default. - *

- * When the template render is not explicitly registered it can be - * automatically registered via ServiceLoader and these are the extensions - * it will register for by default. + * + *

When the template render is not explicitly registered, it can be automatically registered + * via ServiceLoader with the provided extensions by default. */ String[] defaultExtensions(); diff --git a/avaje-jex/src/main/java/io/avaje/jex/jdk/BufferedOutStream.java b/avaje-jex/src/main/java/io/avaje/jex/jdk/BufferedOutStream.java index 0940b949..0387eddd 100644 --- a/avaje-jex/src/main/java/io/avaje/jex/jdk/BufferedOutStream.java +++ b/avaje-jex/src/main/java/io/avaje/jex/jdk/BufferedOutStream.java @@ -63,7 +63,7 @@ public void close() throws IOException { stream.flush(); stream.close(); } else { - context.writeBytes(buffer.toByteArray()); + context.write(buffer.toByteArray()); } } } diff --git a/avaje-jex/src/main/java/io/avaje/jex/jdk/JdkContext.java b/avaje-jex/src/main/java/io/avaje/jex/jdk/JdkContext.java index c7066bf3..7dd5ec6b 100644 --- a/avaje-jex/src/main/java/io/avaje/jex/jdk/JdkContext.java +++ b/avaje-jex/src/main/java/io/avaje/jex/jdk/JdkContext.java @@ -343,20 +343,36 @@ public Context html(String content) { @Override public Context write(String content) { - try { - writeBytes(content.getBytes(StandardCharsets.UTF_8)); - return this; + + write(content.getBytes(StandardCharsets.UTF_8)); + return this; + } + + @Override + public Context write(byte[] bytes) { + + try (var os = exchange.getResponseBody()) { + exchange.sendResponseHeaders(statusCode(), bytes.length); + + os.write(bytes); + os.flush(); } catch (IOException e) { throw new UncheckedIOException(e); } + return this; } - void writeBytes(byte[] bytes) throws IOException { - exchange.sendResponseHeaders(statusCode(), bytes.length); - final OutputStream os = exchange.getResponseBody(); - os.write(bytes); - os.flush(); - os.close(); + @Override + public Context write(InputStream is) { + + try (is; var os = exchange.getResponseBody()) { + exchange.sendResponseHeaders(statusCode(), 0); + is.transferTo(os); + os.flush(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + return this; } int statusCode() { diff --git a/avaje-jex/src/main/java/io/avaje/jex/jdk/JdkServerStart.java b/avaje-jex/src/main/java/io/avaje/jex/jdk/JdkServerStart.java index 1ace94d4..5676b749 100644 --- a/avaje-jex/src/main/java/io/avaje/jex/jdk/JdkServerStart.java +++ b/avaje-jex/src/main/java/io/avaje/jex/jdk/JdkServerStart.java @@ -24,21 +24,22 @@ public Jex.Server start(Jex jex, SpiRoutes routes, SpiServiceManager serviceMana final ServiceManager manager = new ServiceManager(serviceManager, "http", ""); try { - int port = jex.config().port(); final HttpServer server; + var port = new InetSocketAddress(jex.config().port()); final var sslContext = jex.config().sslContext(); - if (sslContext != null) { - var httpsServer = HttpsServer.create(new InetSocketAddress(port), 0); + if (sslContext != null) { + var httpsServer = HttpsServer.create(port, 0); httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext)); server = httpsServer; } else { - server = HttpServer.create(new InetSocketAddress(port), 0); + server = HttpServer.create(port, 0); } + var handler = new BaseHandler(routes); var context = server.createContext("/", handler); - context.getFilters().add(new BaseFilter(routes, manager)); + context.getFilters().add(new RoutingFilter(routes, manager)); context.getFilters().addAll(routes.filters()); server.setExecutor(Executors.newThreadPerTaskExecutor(jex.config().threadFactory())); server.start(); diff --git a/avaje-jex/src/main/java/io/avaje/jex/jdk/BaseFilter.java b/avaje-jex/src/main/java/io/avaje/jex/jdk/RoutingFilter.java similarity index 96% rename from avaje-jex/src/main/java/io/avaje/jex/jdk/BaseFilter.java rename to avaje-jex/src/main/java/io/avaje/jex/jdk/RoutingFilter.java index 3117f83a..f78fdbdd 100644 --- a/avaje-jex/src/main/java/io/avaje/jex/jdk/BaseFilter.java +++ b/avaje-jex/src/main/java/io/avaje/jex/jdk/RoutingFilter.java @@ -14,12 +14,12 @@ import io.avaje.jex.routes.SpiRoutes; import io.avaje.jex.spi.SpiContext; -class BaseFilter extends Filter { +final class RoutingFilter extends Filter { private final SpiRoutes routes; private final ServiceManager mgr; - BaseFilter(SpiRoutes routes, ServiceManager mgr) { + RoutingFilter(SpiRoutes routes, ServiceManager mgr) { this.mgr = mgr; this.routes = routes; }