diff --git a/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlAuthResourceHandler.java b/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlAuthResourceHandler.java deleted file mode 100644 index 7769646..0000000 --- a/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlAuthResourceHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.xbib.net.http.j2html; - -import org.xbib.net.Resource; -import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler; -import org.xbib.net.http.server.route.HttpRouterContext; - -import java.io.IOException; -import java.nio.file.Path; - -public class J2HtmlAuthResourceHandler extends HtmlTemplateResourceHandler { - - public J2HtmlAuthResourceHandler() { - this(null, "java", "index.java"); - } - - public J2HtmlAuthResourceHandler(Path root, String suffix, String indexFileName) { - super(root, suffix, indexFileName); - } - - @Override - protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException { - return httpRouterContext.isAuthenticated() ? - createAuthenticatedResource(httpRouterContext) : - createUnauthenticatedResource(httpRouterContext); - } - - protected Resource createAuthenticatedResource(HttpRouterContext httpRouterContext) throws IOException { - return new J2HtmlResource(this, httpRouterContext); - } - - protected Resource createUnauthenticatedResource(HttpRouterContext httpRouterContext) throws IOException { - return new UnauthorizedHandler.UnauthorizedResource(this, httpRouterContext); - } -} diff --git a/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResource.java b/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResource.java index 8da9777..e47ebe8 100644 --- a/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResource.java +++ b/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResource.java @@ -13,6 +13,7 @@ import java.nio.charset.StandardCharsets; import java.util.Objects; import static org.xbib.j2html.TagCreator.body; +import static org.xbib.j2html.TagCreator.document; import static org.xbib.j2html.TagCreator.h1; import static org.xbib.j2html.TagCreator.html; import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE; @@ -37,17 +38,13 @@ public class J2HtmlResource extends HtmlTemplateResource { httpResponseStatus = getResponseStatus(); } context.status(httpResponseStatus) - .header("cache-control", cacheControl()) // override default must-revalidate behavior - .header("content-length", Integer.toString(dataBuffer.writePosition())) - .header(CONTENT_TYPE, "text/html; charset=" + getCharset().displayName()) + .setHeader("cache-control", "no-cache") + .setHeader("content-length", Integer.toString(dataBuffer.writePosition())) + .setHeader(CONTENT_TYPE, "text/html; charset=" + getCharset().displayName()) .body(dataBuffer) .done(); } - protected String cacheControl() { - return "no-cache"; - } - protected HttpResponseStatus getResponseStatus() { return HttpResponseStatus.OK; } @@ -65,6 +62,6 @@ public class J2HtmlResource extends HtmlTemplateResource { * @return the body string fo the HTTP response */ protected String renderHtml(HttpRouterContext context) { - return html(body(h1("Hello World"))).render(); + return document(html(body(h1("Hello World")))); } } diff --git a/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResourceHandler.java b/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResourceHandler.java index 3ffd985..1ade22c 100644 --- a/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResourceHandler.java +++ b/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResourceHandler.java @@ -22,6 +22,12 @@ public class J2HtmlResourceHandler extends HtmlTemplateResourceHandler { @Override protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException { + return httpRouterContext.isAuthenticated() ? + new J2HtmlResource(this, httpRouterContext) : + createUnauthenticatedResource(httpRouterContext); + } + + protected Resource createUnauthenticatedResource(HttpRouterContext httpRouterContext) throws IOException { return new J2HtmlResource(this, httpRouterContext); } } diff --git a/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlServiceBuilder.java b/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlServiceBuilder.java index de9dfd1..f0162b8 100644 --- a/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlServiceBuilder.java +++ b/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlServiceBuilder.java @@ -61,13 +61,8 @@ public class J2HtmlServiceBuilder extends BaseHttpServiceBuilder { public J2HtmlService build() { if (handlers == null) { - if (securityDomain != null) { - HttpHandler httpHandler = new J2HtmlAuthResourceHandler(prefix, suffix, "index.java"); - setHandler(httpHandler); - } else { - HttpHandler httpHandler = new J2HtmlResourceHandler(prefix, suffix, "index.java"); - setHandler(httpHandler); - } + HttpHandler httpHandler = new J2HtmlResourceHandler(prefix, suffix, "index.java"); + setHandler(httpHandler); } return new J2HtmlService(this); } diff --git a/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/groovy/Bootstrap.java b/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/groovy/Bootstrap.java index de6628d..9e8c319 100644 --- a/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/groovy/Bootstrap.java +++ b/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/groovy/Bootstrap.java @@ -138,7 +138,7 @@ public final class Bootstrap { .setPath("/secure") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("secure domain: " + " SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() + @@ -165,14 +165,14 @@ public final class Bootstrap { .setPath("/favicon.ico") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, "image/x-icon") + .setHeader(HttpHeaderNames.CONTENT_TYPE, "image/x-icon") .body(NettyDataBufferFactory.getInstance().wrap(fromHex(hexFavIcon))) .done(); }) .build()) .addService(BaseHttpService.builder() .setPath("/webjars/**") - .setHandler(new ClassLoaderResourceHandler(Bootstrap.class.getClassLoader(), "META-INF/resources/")) + .setHandler(new ClassLoaderResourceHandler(Bootstrap.class.getClassLoader(), "META-INF/resources/", 24 + 2600)) .build()) .addService(httpService) .addService(GroovyTemplateService.builder() diff --git a/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/j2html/Bootstrap.java b/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/j2html/Bootstrap.java index de215f6..34ff7fa 100644 --- a/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/j2html/Bootstrap.java +++ b/net-http-server-application-web/src/main/java/org/xbib/net/http/server/application/web/j2html/Bootstrap.java @@ -11,8 +11,8 @@ import org.xbib.net.http.HttpHeaderValues; import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpVersion; import org.xbib.net.http.j2html.InternalServerErrorHandler; -import org.xbib.net.http.j2html.J2HtmlAuthResourceHandler; import org.xbib.net.http.j2html.J2HtmlResource; +import org.xbib.net.http.j2html.J2HtmlResourceHandler; import org.xbib.net.http.j2html.J2HtmlService; import org.xbib.net.http.server.application.web.WebApplication; import org.xbib.net.http.server.auth.BasicAuthenticationHandler; @@ -148,20 +148,20 @@ public final class Bootstrap { .setPath("/favicon.ico") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, "image/x-icon") + .setHeader(HttpHeaderNames.CONTENT_TYPE, "image/x-icon") .body(NettyDataBufferFactory.getInstance().wrap(fromHex(hexFavIcon))) .done(); }) .build()) .addService(BaseHttpService.builder() .setPath("/webjars/**") - .setHandler(new ClassLoaderResourceHandler(Bootstrap.class.getClassLoader(), "META-INF/resources/")) + .setHandler(new ClassLoaderResourceHandler(Bootstrap.class.getClassLoader(), "META-INF/resources/", 24 * 3600)) .build()) .addService(BaseHttpService.builder() .setPath("/insecure") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("secure domain: " + " SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() + @@ -203,10 +203,10 @@ public final class Bootstrap { return 0; } - static class MyResourceHandler extends J2HtmlAuthResourceHandler { + static class MyResourceHandler extends J2HtmlResourceHandler { @Override - protected Resource createAuthenticatedResource(HttpRouterContext httpRouterContext) throws IOException { + protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException { return new DemoResource(this, httpRouterContext); } diff --git a/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttps2ServerMultiRequestLoadTest.java b/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttps2ServerMultiRequestLoadTest.java index 200a11e..0548e94 100644 --- a/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttps2ServerMultiRequestLoadTest.java +++ b/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttps2ServerMultiRequestLoadTest.java @@ -62,7 +62,7 @@ public class NettyHttps2ServerMultiRequestLoadTest { .setPath("/secure") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("secure domain " + " SNI host " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() + " " + diff --git a/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttps2ServerTest.java b/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttps2ServerTest.java index d6e0422..4dbadd4 100644 --- a/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttps2ServerTest.java +++ b/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttps2ServerTest.java @@ -62,7 +62,7 @@ public class NettyHttps2ServerTest { .setPath("/secure") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("secure domain " + " SNI host " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() + " " + diff --git a/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttpsServerMultiRequestLoadTest.java b/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttpsServerMultiRequestLoadTest.java index d17f411..dd34616 100644 --- a/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttpsServerMultiRequestLoadTest.java +++ b/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttpsServerMultiRequestLoadTest.java @@ -64,7 +64,7 @@ public class NettyHttpsServerMultiRequestLoadTest { .setHandler(ctx -> { logger.log(Level.INFO, "executing /secure"); ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("secure domain: " + " SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() + @@ -151,7 +151,7 @@ public class NettyHttpsServerMultiRequestLoadTest { .setPath("/secure") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("secure domain: " + " SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() + diff --git a/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttpsServerTest.java b/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttpsServerTest.java index ee0fd98..057df54 100644 --- a/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttpsServerTest.java +++ b/net-http-server-netty-secure/src/test/java/org/xbib/net/http/server/netty/secure/test/NettyHttpsServerTest.java @@ -68,7 +68,7 @@ public class NettyHttpsServerTest { .setPath("/secure") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("secure domain: " + " SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() + @@ -146,7 +146,7 @@ public class NettyHttpsServerTest { .setPath("/secure") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("secure domain: " + " SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() + @@ -223,7 +223,7 @@ public class NettyHttpsServerTest { .setPath("/secure") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("secure domain " + " SNI host " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() + " " + diff --git a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttp2ServerMultiRequestLoadTest.java b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttp2ServerMultiRequestLoadTest.java index cf5c263..1587974 100644 --- a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttp2ServerMultiRequestLoadTest.java +++ b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttp2ServerMultiRequestLoadTest.java @@ -51,7 +51,7 @@ public class NettyHttp2ServerMultiRequestLoadTest { .setPath("/domain") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("domain: " + " base URL = " + ctx.getRequest().getBaseURL() + diff --git a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttp2ServerTest.java b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttp2ServerTest.java index 5b7d046..f52cb5e 100644 --- a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttp2ServerTest.java +++ b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttp2ServerTest.java @@ -49,7 +49,7 @@ public class NettyHttp2ServerTest { .setPath("/domain") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("Hello, here is my response: " + ctx.getRequest().asJson()) diff --git a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerBodyTest.java b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerBodyTest.java index 2f0ae25..3192ac3 100644 --- a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerBodyTest.java +++ b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerBodyTest.java @@ -48,7 +48,7 @@ public class NettyHttpServerBodyTest { .setHandler(ctx -> { String body = ctx.getRequestBuilder().getBodyAsChars(StandardCharsets.UTF_8).toString(); ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("parameter = " + ctx.getRequest().getParameter().toString() + " local address = " + ctx.getRequest().getLocalAddress() + diff --git a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerByteOrderMarkTest.java b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerByteOrderMarkTest.java index bfbc725..bf336f1 100644 --- a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerByteOrderMarkTest.java +++ b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerByteOrderMarkTest.java @@ -58,7 +58,7 @@ class NettyHttpServerByteOrderMarkTest { String content = ctx.getRequestBuilder().getBodyAsChars(StandardCharsets.UTF_8).toString(); logger.log(Level.FINEST, "got content = " + content); ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("parameter = " + ctx.getRequest().getParameter().toString() + " local address = " + ctx.getRequest().getLocalAddress() + diff --git a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerFailureTest.java b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerFailureTest.java index 1f0af1f..55a8b87 100644 --- a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerFailureTest.java +++ b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerFailureTest.java @@ -53,7 +53,7 @@ public class NettyHttpServerFailureTest { .setPath("/domain") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("domain" + " parameter = " + ctx.getRequest().getParameter().toString() + diff --git a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerFileUploadTest.java b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerFileUploadTest.java index a2e2d20..1756346 100644 --- a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerFileUploadTest.java +++ b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerFileUploadTest.java @@ -82,7 +82,7 @@ public class NettyHttpServerFileUploadTest { .map(m -> StandardCharsets.UTF_8.decode(m.getByteBuffer())) .collect(Collectors.joining()); ctx.status(httpResponseStatus) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("parameter = " + ctx.getRequest().getParameter().toString() + " local address = " + ctx.getRequest().getLocalAddress() + @@ -175,7 +175,7 @@ public class NettyHttpServerFileUploadTest { } } ctx.status(httpResponseStatus) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("parameter = " + ctx.getRequest().getParameter().toString() + " local address = " + ctx.getRequest().getLocalAddress() + diff --git a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerMultiRequestLoadTest.java b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerMultiRequestLoadTest.java index 20b861b..017b75c 100644 --- a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerMultiRequestLoadTest.java +++ b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerMultiRequestLoadTest.java @@ -51,7 +51,7 @@ public class NettyHttpServerMultiRequestLoadTest { .setPath("/domain") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("domain: " + " base URL = " + ctx.getRequest().getBaseURL() + diff --git a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerRequestTest.java b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerRequestTest.java index b2d5f59..5108da9 100644 --- a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerRequestTest.java +++ b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerRequestTest.java @@ -55,7 +55,7 @@ public class NettyHttpServerRequestTest { try { String value = ctx.getRequest().getParameter().getAsString("value", Parameter.Domain.QUERY); ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("local address = " + ctx.getRequest().getLocalAddress() + " remote address = " + ctx.getRequest().getRemoteAddress() + diff --git a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerTest.java b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerTest.java index f4c8c4b..d260029 100644 --- a/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerTest.java +++ b/net-http-server-netty/src/test/java/org/xbib/net/http/server/netty/test/NettyHttpServerTest.java @@ -52,7 +52,7 @@ public class NettyHttpServerTest { .setPath("/domain") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body(ctx.getRequest().asJson()) .done(); diff --git a/net-http-server-nio/src/test/java/org/xbib/net/http/server/nio/test/NioHttpServerTest.java b/net-http-server-nio/src/test/java/org/xbib/net/http/server/nio/test/NioHttpServerTest.java index ca29b68..afa12d8 100644 --- a/net-http-server-nio/src/test/java/org/xbib/net/http/server/nio/test/NioHttpServerTest.java +++ b/net-http-server-nio/src/test/java/org/xbib/net/http/server/nio/test/NioHttpServerTest.java @@ -35,7 +35,7 @@ public class NioHttpServerTest { .setPath("/domain1") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("domain1 " + ctx.getRequest().getParameter().toString() + " " + @@ -50,7 +50,7 @@ public class NioHttpServerTest { .setPath("/domain2") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("domain2 " + ctx.getRequest().getParameter().toString() + " " + diff --git a/net-http-server-simple-secure/src/test/java/org/xbib/net/http/server/simple/secure/test/SimpleHttpsServerTest.java b/net-http-server-simple-secure/src/test/java/org/xbib/net/http/server/simple/secure/test/SimpleHttpsServerTest.java index 42ab4f8..de3f6c5 100644 --- a/net-http-server-simple-secure/src/test/java/org/xbib/net/http/server/simple/secure/test/SimpleHttpsServerTest.java +++ b/net-http-server-simple-secure/src/test/java/org/xbib/net/http/server/simple/secure/test/SimpleHttpsServerTest.java @@ -54,7 +54,7 @@ public class SimpleHttpsServerTest { .setPath("/secure") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("secure domain: " + " SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() + diff --git a/net-http-server-simple/src/test/java/org/xbib/net/http/server/simple/test/HttpRouterTest.java b/net-http-server-simple/src/test/java/org/xbib/net/http/server/simple/test/HttpRouterTest.java index e450a96..d7cb8b1 100644 --- a/net-http-server-simple/src/test/java/org/xbib/net/http/server/simple/test/HttpRouterTest.java +++ b/net-http-server-simple/src/test/java/org/xbib/net/http/server/simple/test/HttpRouterTest.java @@ -41,7 +41,7 @@ public class HttpRouterTest { .setHandler(ctx -> { Logger.getAnonymousLogger().log(Level.INFO, "got request: " + ctx.getRequestBuilder().getRequestURI()); ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body(ctx.getRequestBuilder().getRequestURI()); }) diff --git a/net-http-server-simple/src/test/java/org/xbib/net/http/server/simple/test/SimpleHttpServerTest.java b/net-http-server-simple/src/test/java/org/xbib/net/http/server/simple/test/SimpleHttpServerTest.java index 8f7d6ad..4a69bbc 100644 --- a/net-http-server-simple/src/test/java/org/xbib/net/http/server/simple/test/SimpleHttpServerTest.java +++ b/net-http-server-simple/src/test/java/org/xbib/net/http/server/simple/test/SimpleHttpServerTest.java @@ -35,7 +35,7 @@ public class SimpleHttpServerTest { .setPath("/domain1") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("domain1 " + ctx.getRequest().getParameter() + " " + @@ -54,7 +54,7 @@ public class SimpleHttpServerTest { .setPath("/domain2") .setHandler(ctx -> { ctx.status(HttpResponseStatus.OK) - .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + .setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8) .body("domain2 " + ctx.getRequest().getParameter() + " " + diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/BaseHttpResponseBuilder.java b/net-http-server/src/main/java/org/xbib/net/http/server/BaseHttpResponseBuilder.java index d7f0c3c..2fa16d0 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/BaseHttpResponseBuilder.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/BaseHttpResponseBuilder.java @@ -155,14 +155,17 @@ public abstract class BaseHttpResponseBuilder implements HttpResponseBuilder { if (done) { return this; } + if (name == null || value == null) { + return this; + } if (HttpHeaderNames.CONTENT_TYPE.equalsIgnoreCase(name.toString())) { if (value.startsWith("text") && charset != null) { value = value + "; charset=" + charset.name().toLowerCase(Locale.ROOT); } setContentType(value); } - if (headers.containsHeader(name)) { - logger.log(Level.WARNING, "header already exist: " + headers.get(name) + " overwriting with " + value); + if (headers.containsHeader(name) && !value.equals(headers.get(name))) { + logger.log(Level.WARNING, "header '" + name + "' already exist, old value = '" + headers.get(name) + "', overwriting with '" + value + "'"); } headers.set(name, value); return this; @@ -173,8 +176,18 @@ public abstract class BaseHttpResponseBuilder implements HttpResponseBuilder { if (done) { return this; } + if (name == null) { + return this; + } + if (HttpHeaderNames.CONTENT_TYPE.equalsIgnoreCase(name.toString())) { + if (value.startsWith("text") && charset != null) { + value = value + "; charset=" + charset.name().toLowerCase(Locale.ROOT); + } + setContentType(value); + } if (headers.containsHeader(name)) { - logger.log(Level.WARNING, "header already exist: " + headers.get(name) + " adding " + value); + logger.log(Level.WARNING, "when adding '" + value + "', the header already exist: " + name + " - ignoring"); + return this; } headers.add(name, value); return this; @@ -315,11 +328,10 @@ public abstract class BaseHttpResponseBuilder implements HttpResponseBuilder { @Override public BaseHttpResponseBuilder addCookie(Cookie cookie) { - if (done) { - return this; - } - Objects.requireNonNull(cookie); - headers.add(HttpHeaderNames.SET_COOKIE, CookieEncoder.STRICT.encode(cookie)); + // skip done check, we force cookie add + Objects.requireNonNull(cookie, "cookie must not be null when adding"); + String cookieValue = CookieEncoder.STRICT.encode(cookie); + headers.add(HttpHeaderNames.SET_COOKIE,cookieValue); return this; } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/application/BaseApplication.java b/net-http-server/src/main/java/org/xbib/net/http/server/application/BaseApplication.java index 3538130..33ef9fc 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/application/BaseApplication.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/application/BaseApplication.java @@ -30,8 +30,8 @@ import org.xbib.net.http.server.executor.Executor; import org.xbib.net.http.server.persist.Codec; import org.xbib.net.http.server.render.HttpResponseRenderer; import org.xbib.net.http.server.route.HttpRouter; -import org.xbib.net.http.server.session.IncomingSessionHandler; -import org.xbib.net.http.server.session.OutgoingSessionHandler; +import org.xbib.net.http.server.session.IncomingContextHandler; +import org.xbib.net.http.server.session.OutgoingContextHandler; import org.xbib.net.http.server.session.PersistSessionHandler; import org.xbib.net.http.server.session.Session; import org.xbib.net.http.server.session.memory.MemoryPropertiesSessionCodec; @@ -171,9 +171,9 @@ public class BaseApplication implements Application { if (builder.sessionsEnabled) { Codec sessionCodec = newSessionCodec(httpRouterContext); httpRouterContext.getAttributes().put("sessioncodec", sessionCodec); - httpRouterContext.addOpenHandler(newIncomingSessionHandler(sessionCodec)); - httpRouterContext.addCloseHandler(newOutgoingSessionHandler()); - httpRouterContext.addReleaseHandler(newPersistSessionHandler(sessionCodec)); + httpRouterContext.addOpenHandler(newIncomingContextHandler(sessionCodec)); + httpRouterContext.addCloseHandler(newOutgoingContextHandler()); + httpRouterContext.addCloseHandler(newPersistHandler(sessionCodec)); } httpRouterContext.addCloseHandler(newOutgoingCookieHandler()); return httpRouterContext; @@ -212,26 +212,22 @@ public class BaseApplication implements Application { return new MemoryPropertiesSessionCodec(sessionName,this, 1024, Duration.ofDays(1)); } - protected HttpHandler newIncomingSessionHandler(Codec sessionCodec) { - return new IncomingSessionHandler( + protected HttpHandler newIncomingContextHandler(Codec sessionCodec) { + return new IncomingContextHandler( getSecret(), "HmacSHA1", sessionName, sessionCodec, getStaticFileSuffixes(), - "user_id", - "e_user_id", () -> RandomUtil.randomString(16)); } - protected HttpHandler newOutgoingSessionHandler() { - return new OutgoingSessionHandler( + protected HttpHandler newOutgoingContextHandler() { + return new OutgoingContextHandler( getSecret(), "HmacSHA1", sessionName, getStaticFileSuffixes(), - "user_id", - "e_user_id", Duration.ofDays(1), true, false, @@ -239,7 +235,7 @@ public class BaseApplication implements Application { ); } - protected HttpHandler newPersistSessionHandler(Codec sessionCodec) { + protected HttpHandler newPersistHandler(Codec sessionCodec) { return new PersistSessionHandler(sessionCodec); } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/auth/BaseAttributes.java b/net-http-server/src/main/java/org/xbib/net/http/server/auth/BaseAttributes.java index cc6e919..31aea1f 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/auth/BaseAttributes.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/auth/BaseAttributes.java @@ -1,6 +1,8 @@ package org.xbib.net.http.server.auth; import java.util.LinkedHashMap; +import java.util.Map; + import org.xbib.net.Attributes; @SuppressWarnings("serial") @@ -10,6 +12,10 @@ public class BaseAttributes extends LinkedHashMap implements Att super(); } + public BaseAttributes(Map map) { + super(map); + } + @SuppressWarnings("unchecked") @Override public T get(Class cl, String key) { diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/auth/BaseUserProfile.java b/net-http-server/src/main/java/org/xbib/net/http/server/auth/BaseUserProfile.java index 994f3fd..29eb410 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/auth/BaseUserProfile.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/auth/BaseUserProfile.java @@ -1,35 +1,33 @@ package org.xbib.net.http.server.auth; import java.util.ArrayList; -import java.util.List; +import java.util.Collection; +import java.util.Map; + +import org.xbib.datastructures.tiny.TinyMap; import org.xbib.net.Attributes; import org.xbib.net.UserProfile; public class BaseUserProfile implements UserProfile { - private final Attributes attributes; - - private final Attributes effectiveAttributes; - - private final List roles; - - private final List effectiveRoles; - - private final List permissions; - - private final List effectivePermissions; - private String uid; private String euid; private String name; - private boolean isRemembered; + private Attributes attributes; + + private Collection roles; + + private Collection effectiveRoles; + + private Collection permissions; + + private Collection effectivePermissions; public BaseUserProfile() { this.attributes = new BaseAttributes(); - this.effectiveAttributes = new BaseAttributes(); this.roles = new ArrayList<>(); this.effectiveRoles = new ArrayList<>(); this.permissions = new ArrayList<>(); @@ -71,105 +69,64 @@ public class BaseUserProfile implements UserProfile { roles.add(role); } + @Override + public void setRoles(Collection roles) { + this.roles = roles; + } + + @Override + public Collection getRoles() { + return roles; + } + @Override public void addEffectiveRole(String role) { effectiveRoles.add(role); } @Override - public List getRoles() { - return roles; + public void setEffectiveRoles(Collection effectiveRoles) { + this.effectiveRoles = effectiveRoles; } @Override - public List getEffectiveRoles() { + public Collection getEffectiveRoles() { return effectiveRoles; } - public boolean hasRole(String role) { - return roles.contains(role); - } - - public boolean hasEffectiveRole(String role) { - return effectiveRoles.contains(role); - } - - public boolean hasAccess(String requireAnyRole, String requireAllRoles) { - boolean access = true; - if (!requireAnyRole.isEmpty()) { - String[] expectedRoles = requireAnyRole.split(","); - if (!hasAnyRole(expectedRoles)) { - access = false; - } - } else if (!requireAllRoles.isEmpty()) { - String[] expectedRoles = requireAllRoles.split(","); - if (!hasAllRoles(expectedRoles)) { - access = false; - } - } - return access; - } - - public boolean hasAnyRole(String[] expectedRoles) { - if (expectedRoles == null || expectedRoles.length == 0) { - return true; - } - for (final String role : expectedRoles) { - if (roles.contains(role)) { - return true; - } - } - return false; - } - - public boolean hasAnyEffectiveRole(String[] expectedRoles) { - if (expectedRoles == null || expectedRoles.length == 0) { - return true; - } - for (final String role : expectedRoles) { - if (effectiveRoles.contains(role)) { - return true; - } - } - return false; - } - - public boolean hasAllRoles(String[] expectedRoles) { - if (expectedRoles == null) { - return true; - } - for (String role : expectedRoles) { - if (!roles.contains(role)) { - return false; - } - } - return true; - } - - public boolean hasAllEffectiveRoles(String[] expectedRoles) { - if (expectedRoles == null) { - return true; - } - for (String role : expectedRoles) { - if (!effectiveRoles.contains(role)) { - return false; - } - } - return true; - } - @Override public void addPermission(String permission) { permissions.add(permission); } - public void removePermission(String permission) { - permissions.remove(permission); + @Override + public void setPermissions(Collection permissions) { + this.permissions = permissions; } @Override - public void setRemembered(boolean remembered) { - this.isRemembered = remembered; + public Collection getPermissions() { + return permissions; + } + + @Override + public void addEffectivePermission(String permission) { + effectivePermissions.add(permission); + } + + @Override + public void setEffectivePermissions(Collection effectivePermissions) { + this.effectivePermissions = effectivePermissions; + } + + @Override + public Collection getEffectivePermissions() { + return effectivePermissions; + } + + @Override + public void setAttributes(Attributes attributes) { + this.attributes = attributes; } @Override @@ -178,38 +135,74 @@ public class BaseUserProfile implements UserProfile { } @Override - public Attributes getEffectiveAttributes() { - return effectiveAttributes; + public Map asMap() { + TinyMap.Builder builder = TinyMap.builder(); + builder.put("name", getName()); + String userId = getUserId(); + if (userId == null) { + userId = ""; + } + builder.put("user_id", userId); + String eUserId = getEffectiveUserId(); + if (eUserId == null) { + eUserId = ""; + } + builder.put("e_user_id", eUserId); + if (getRoles() != null && !getRoles().isEmpty()) { + builder.put("roles", getRoles()); + } + if (getEffectiveRoles() != null && !getEffectiveRoles().isEmpty()) { + builder.put("e_roles", getEffectiveRoles()); + } + if (getPermissions() != null && !getPermissions().isEmpty()) { + builder.put("perms", getPermissions()); + } + if (getEffectivePermissions() != null && !getEffectivePermissions().isEmpty()) { + builder.put("e_perms", getEffectivePermissions()); + } + if (getAttributes() != null && !getAttributes().isEmpty()) { + builder.put("attrs", getAttributes()); + } + return builder.build(); } - @Override - public List getPermissions() { - return permissions; - } - - @Override - public void addEffectivePermission(String permission) { - effectivePermissions.add(permission); - } - @Override - public List getEffectivePermissions() { - return effectivePermissions; - } - - @Override - public boolean isRemembered() { - return isRemembered; - } - - @Override - public String toString() { - return "uid=" + uid + - ",roles=" + roles + - ",permissons=" + permissions + - ",attributes=" + attributes + - ",euid=" + euid + - ",eroles=" + effectiveRoles + - ",epermissions=" + effectivePermissions + - ",eattributes=" + effectiveAttributes; + @SuppressWarnings("unchecked") + public static UserProfile fromMap(Map map) { + BaseUserProfile userProfile = new BaseUserProfile(); + if (map.containsKey("name")) { + userProfile.setName((String) map.get("name")); + } + if (map.containsKey("user_id")) { + String userId = (String) map.get("user_id"); + // empty user ID for better map transport, change it to null + if (userId != null && userId.isEmpty()) { + userId = null; + } + userProfile.setUserId(userId); + } + if (map.containsKey("e_user_id")) { + String eUserId = (String) map.get("e_user_id"); + // empty effective user ID for better map transport, change it to null + if (eUserId != null && eUserId.isEmpty()) { + eUserId = null; + } + userProfile.setEffectiveUserId(eUserId); + } + if (map.containsKey("roles")) { + userProfile.setRoles((Collection) map.get("roles")); + } + if (map.containsKey("e_roles")) { + userProfile.setEffectiveRoles((Collection) map.get("e_roles")); + } + if (map.containsKey("perms")) { + userProfile.setPermissions((Collection) map.get("perms")); + } + if (map.containsKey("e_perms")) { + userProfile.setEffectivePermissions((Collection) map.get("e_perms")); + } + if (map.containsKey("attrs")) { + userProfile.setAttributes(new BaseAttributes((Map) map.get("attrs"))); + } + return userProfile; } } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/auth/BasicAuthenticationHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/auth/BasicAuthenticationHandler.java index 212df0b..05098df 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/auth/BasicAuthenticationHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/auth/BasicAuthenticationHandler.java @@ -52,6 +52,6 @@ public class BasicAuthenticationHandler extends LoginAuthenticationHandler imple } logger.log(Level.INFO, "unauthenticated"); context.status(HttpResponseStatus.UNAUTHORIZED) - .header("WWW-Authenticate", "Basic realm=\"" + getSecurityRealm().getName() + "\""); + .setHeader("WWW-Authenticate", "Basic realm=\"" + getSecurityRealm().getName() + "\""); } } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/auth/FormAuthenticationHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/auth/FormAuthenticationHandler.java index 8dcc0e9..34b1316 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/auth/FormAuthenticationHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/auth/FormAuthenticationHandler.java @@ -26,7 +26,7 @@ public class FormAuthenticationHandler extends LoginAuthenticationHandler implem logger.log(Level.FINE, "request = " + context.getRequest()); UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile"); if (userProfile != null && userProfile.getUserId() != null) { - logger.log(Level.FINE, "user id already set: " + userProfile.getUserId()); + logger.log(Level.FINE, "already authenticated, user id = " + userProfile.getUserId()); context.setAuthenticated(true); return; } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/cookie/OutgoingCookieHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/cookie/OutgoingCookieHandler.java index cf6d2a3..0b94891 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/cookie/OutgoingCookieHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/cookie/OutgoingCookieHandler.java @@ -20,6 +20,7 @@ public class OutgoingCookieHandler implements HttpHandler { CookieBox cookieBox = context.getAttributes().get(CookieBox.class, "outgoingcookies"); if (cookieBox != null) { for (Cookie cookie : cookieBox) { + // move cookie to http response context.cookie(cookie); logger.log(Level.FINEST, "cookie prepared for outgoing = " + cookie); } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/handler/BadRequestHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/handler/BadRequestHandler.java index 09bbf26..5a83256 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/handler/BadRequestHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/handler/BadRequestHandler.java @@ -15,7 +15,7 @@ public class BadRequestHandler implements HttpErrorHandler { @Override public void handle(HttpRouterContext context) throws IOException { context.status(HttpResponseStatus.BAD_REQUEST) - .header(CONTENT_TYPE, "text/plain;charset=utf-8") + .setHeader(CONTENT_TYPE, "text/plain;charset=utf-8") .body("Bad request") .done(); } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/handler/ForbiddenHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/handler/ForbiddenHandler.java index 0aab640..602f57f 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/handler/ForbiddenHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/handler/ForbiddenHandler.java @@ -15,7 +15,7 @@ public class ForbiddenHandler implements HttpErrorHandler { @Override public void handle(HttpRouterContext context) throws IOException { context.status(HttpResponseStatus.FORBIDDEN) - .header(CONTENT_TYPE, "text/plain;charset=utf-8") + .setHeader(CONTENT_TYPE, "text/plain; charset=utf-8") .body("Forbidden") .done(); } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/handler/InternalServerErrorHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/handler/InternalServerErrorHandler.java index 56ae1dd..c56088f 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/handler/InternalServerErrorHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/handler/InternalServerErrorHandler.java @@ -32,7 +32,7 @@ public class InternalServerErrorHandler implements HttpErrorHandler { message = throwable != null ? throwable.getMessage() : ""; } context.status(status) - .header(CONTENT_TYPE, "text/plain;charset=utf-8") + .setHeader(CONTENT_TYPE, "text/plain; charset=utf-8") .body(message) .done(); } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/handler/NotFoundHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/handler/NotFoundHandler.java index e857605..e933e4b 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/handler/NotFoundHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/handler/NotFoundHandler.java @@ -15,7 +15,7 @@ public class NotFoundHandler implements HttpErrorHandler { @Override public void handle(HttpRouterContext context) throws IOException { context.status(HttpResponseStatus.NOT_FOUND) - .header(CONTENT_TYPE, "text/plain;charset=utf-8") + .setHeader(CONTENT_TYPE, "text/plain; charset=utf-8") .body("Not found") .done(); } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/handler/NotImplementedHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/handler/NotImplementedHandler.java index 24e97b2..26ca741 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/handler/NotImplementedHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/handler/NotImplementedHandler.java @@ -15,7 +15,7 @@ public class NotImplementedHandler implements HttpErrorHandler { @Override public void handle(HttpRouterContext context) throws IOException { context.status(HttpResponseStatus.NOT_IMPLEMENTED) - .header(CONTENT_TYPE, "text/plain;charset=utf-8") + .setHeader(CONTENT_TYPE, "text/plain;charset=utf-8") .body("Not implemented") .done(); } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/handler/UnauthorizedHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/handler/UnauthorizedHandler.java index d5add6e..e57dac3 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/handler/UnauthorizedHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/handler/UnauthorizedHandler.java @@ -15,7 +15,7 @@ public class UnauthorizedHandler implements HttpErrorHandler { @Override public void handle(HttpRouterContext context) throws IOException { context.status(HttpResponseStatus.UNAUTHORIZED) - .header(CONTENT_TYPE, "text/plain;charset=utf-8") + .setHeader(CONTENT_TYPE, "text/plain; charset=utf-8") .body("Unauthorized") .done(); } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/handler/VersionNotSupportedHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/handler/VersionNotSupportedHandler.java index 3c70138..db33670 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/handler/VersionNotSupportedHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/handler/VersionNotSupportedHandler.java @@ -15,7 +15,7 @@ public class VersionNotSupportedHandler implements HttpErrorHandler { @Override public void handle(HttpRouterContext context) throws IOException { context.status(HttpResponseStatus.HTTP_VERSION_NOT_SUPPORTED) - .header(CONTENT_TYPE, "text/plain;charset=utf-8") + .setHeader(CONTENT_TYPE, "text/plain; charset=utf-8") .body("HTTP version not supported") .done(); } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/ldap/LdapGroupsProvider.java b/net-http-server/src/main/java/org/xbib/net/http/server/ldap/LdapGroupsProvider.java index cf7ee3b..c32980e 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/ldap/LdapGroupsProvider.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/ldap/LdapGroupsProvider.java @@ -41,6 +41,7 @@ public class LdapGroupsProvider extends GroupsProvider { * Get groups, or null if not possible. * @throws LdapException if unable to retrieve groups */ + @Override public Collection getGroups(String username) { if (userMappings == null) { return null; diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/resource/AbstractResourceHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/resource/AbstractResourceHandler.java index dba070c..007048f 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/resource/AbstractResourceHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/resource/AbstractResourceHandler.java @@ -46,13 +46,13 @@ public abstract class AbstractResourceHandler implements HttpHandler { protected abstract Resource createResource(HttpRouterContext httpRouterContext) throws IOException; - protected abstract boolean isETagResponseEnabled(); + protected abstract boolean isETagEnabled(); - protected abstract boolean isCacheResponseEnabled(); + protected abstract boolean isRangeEnabled(); - protected abstract boolean isRangeResponseEnabled(); + protected abstract int getCacheMaxAgeSeconds(); - protected abstract int getMaxAgeSeconds(); + protected abstract String getCacheControl(); @Override public void handle(HttpRouterContext context) throws IOException { @@ -75,7 +75,7 @@ public abstract class AbstractResourceHandler implements HttpHandler { .build() .toString(); logger.log(Level.FINEST, "client must add a /, external redirect to = " + loc); - context.header(HttpHeaderNames.LOCATION, loc) + context.setHeader(HttpHeaderNames.LOCATION, loc) .status(HttpResponseStatus.TEMPORARY_REDIRECT); } else if (resource.isExistsIndexFile()) { // internal redirect to default index file in this directory @@ -102,7 +102,7 @@ public abstract class AbstractResourceHandler implements HttpHandler { } HttpHeaders headers = context.getRequestBuilder().getHeaders(); String contentType = resource.getMimeType(); - context.header(CONTENT_TYPE, contentType); + context.setHeader(CONTENT_TYPE, contentType); // heuristic for inline disposition String disposition; if (!contentType.startsWith("text") && !contentType.startsWith("image") && !contentType.startsWith("font")) { @@ -114,22 +114,26 @@ public abstract class AbstractResourceHandler implements HttpHandler { if (resource.getBaseName() != null && resource.getSuffix() != null) { String contentDisposition = disposition + ";filename=\"" + resource.getBaseName() + '.' + resource.getSuffix() + '"'; logger.log(Level.FINEST, () -> "content type = " + contentType + " content disposition = " + contentDisposition); - context.header(HttpHeaderNames.CONTENT_DISPOSITION, contentDisposition); + context.setHeader(HttpHeaderNames.CONTENT_DISPOSITION, contentDisposition); } - long expirationMillis = System.currentTimeMillis() + 1000L * getMaxAgeSeconds(); - String expires = DateTimeUtil.formatRfc1123(expirationMillis); - if (isCacheResponseEnabled()) { - String cacheControl = "public, max-age=" + getMaxAgeSeconds(); - logger.log(Level.FINEST, () -> "cache response, expires = " + expires + " cache control = " + cacheControl); - context.header(HttpHeaderNames.EXPIRES, expires) - .header(HttpHeaderNames.CACHE_CONTROL, cacheControl); + if (getCacheMaxAgeSeconds() > 0) { + long expirationMillis = System.currentTimeMillis() + 1000L * getCacheMaxAgeSeconds(); + String expires = DateTimeUtil.formatRfc1123(expirationMillis); + String cacheControl = "public, max-age=" + getCacheMaxAgeSeconds(); + logger.log(Level.FINEST, () -> "expires = " + expires + " cache control = " + cacheControl); + context.setHeader(HttpHeaderNames.EXPIRES, expires) + .setHeader(HttpHeaderNames.CACHE_CONTROL, cacheControl); } else { - logger.log(Level.FINEST, () -> "uncached response"); - context.header(HttpHeaderNames.EXPIRES, "0") - .header(HttpHeaderNames.CACHE_CONTROL, "no-cache, no-store, must-revalidate"); + if (getCacheControl() == null) { + context.setHeader(HttpHeaderNames.EXPIRES, "0") + .setHeader(HttpHeaderNames.CACHE_CONTROL, "no-cache, no-store, must-revalidate"); + } else { + context.setHeader(HttpHeaderNames.EXPIRES, "0") + .setHeader(HttpHeaderNames.CACHE_CONTROL, getCacheControl()); + } } boolean sent = false; - if (isETagResponseEnabled()) { + if (isETagEnabled()) { Instant lastModifiedInstant = resource.getLastModified(); String eTag = Long.toHexString(resource.getResourcePath().hashCode() + lastModifiedInstant.toEpochMilli() + resource.getLength()); logger.log(Level.FINEST, () -> "eTag = " + eTag); @@ -149,7 +153,7 @@ public abstract class AbstractResourceHandler implements HttpHandler { String ifNoneMatch = headers.get(HttpHeaderNames.IF_NONE_MATCH); if (ifNoneMatch != null && matches(ifNoneMatch, eTag)) { logger.log(Level.FINEST, () -> "not modified, eTag = " + eTag); - context.header(HttpHeaderNames.ETAG, eTag) + context.setHeader(HttpHeaderNames.ETAG, eTag) .status(HttpResponseStatus.NOT_MODIFIED); return; } @@ -157,15 +161,15 @@ public abstract class AbstractResourceHandler implements HttpHandler { if (ifModifiedSinceInstant != null && ifModifiedSinceInstant.plusMillis(1000L).isAfter(lastModifiedInstant)) { logger.log(Level.FINEST, () -> "not modified (after if-modified-since), eTag = " + eTag); - context.header(HttpHeaderNames.ETAG, eTag) + context.setHeader(HttpHeaderNames.ETAG, eTag) .status(HttpResponseStatus.NOT_MODIFIED); return; } String lastModified = DateTimeUtil.formatRfc1123(lastModifiedInstant); logger.log(Level.FINEST, () -> "sending resource, lastModified = " + lastModified); - context.header(HttpHeaderNames.ETAG, eTag) - .header(HttpHeaderNames.LAST_MODIFIED, lastModified); - if (isRangeResponseEnabled()) { + context.setHeader(HttpHeaderNames.ETAG, eTag) + .setHeader(HttpHeaderNames.LAST_MODIFIED, lastModified); + if (isRangeEnabled()) { performRangeResponse(context, resource, contentType, eTag, headers); sent = true; } else { @@ -176,7 +180,7 @@ public abstract class AbstractResourceHandler implements HttpHandler { long length = resource.getLength(); if (length > 0L) { String string = Long.toString(resource.getLength()); - context.header(HttpHeaderNames.CONTENT_LENGTH, string); + context.setHeader(HttpHeaderNames.CONTENT_LENGTH, string); logger.log(Level.FINEST, "length is known = " + resource.getLength()); send(resource, HttpResponseStatus.OK, contentType, context, 0L, resource.getLength()); } else { @@ -194,13 +198,13 @@ public abstract class AbstractResourceHandler implements HttpHandler { HttpHeaders headers) throws IOException { long length = resource.getLength(); logger.log(Level.FINEST, "performing range response on resource = " + resource); - context.header(HttpHeaderNames.ACCEPT_RANGES, "bytes"); + context.setHeader(HttpHeaderNames.ACCEPT_RANGES, "bytes"); Range full = new Range(0, length - 1, length); List ranges = new ArrayList<>(); String range = headers.get(HttpHeaderNames.RANGE); if (range != null) { if (!range.matches("^bytes=\\d*-\\d*(,\\d*-\\d*)*$")) { - context.header(HttpHeaderNames.CONTENT_RANGE, "bytes */" + length) + context.setHeader(HttpHeaderNames.CONTENT_RANGE, "bytes */" + length) .status(HttpResponseStatus.REQUESTED_RANGE_NOT_SATISFIABLE); return; } @@ -226,7 +230,7 @@ public abstract class AbstractResourceHandler implements HttpHandler { end = length - 1; } if (start > end) { - context.header(HttpHeaderNames.CONTENT_RANGE, "bytes */" + length) + context.setHeader(HttpHeaderNames.CONTENT_RANGE, "bytes */" + length) .status(HttpResponseStatus.REQUESTED_RANGE_NOT_SATISFIABLE); return; } @@ -235,16 +239,16 @@ public abstract class AbstractResourceHandler implements HttpHandler { } } if (ranges.isEmpty() || ranges.getFirst() == full) { - context.header(HttpHeaderNames.CONTENT_RANGE, "bytes " + full.start + '-' + full.end + '/' + full.total) - .header(HttpHeaderNames.CONTENT_LENGTH, Long.toString(full.length)); + context.setHeader(HttpHeaderNames.CONTENT_RANGE, "bytes " + full.start + '-' + full.end + '/' + full.total) + .setHeader(HttpHeaderNames.CONTENT_LENGTH, Long.toString(full.length)); send(resource, HttpResponseStatus.OK, contentType, context, full.start, full.length); } else if (ranges.size() == 1) { Range r = ranges.getFirst(); - context.header(HttpHeaderNames.CONTENT_RANGE, "bytes " + r.start + '-' + r.end + '/' + r.total) - .header(HttpHeaderNames.CONTENT_LENGTH, Long.toString(r.length)); + context.setHeader(HttpHeaderNames.CONTENT_RANGE, "bytes " + r.start + '-' + r.end + '/' + r.total) + .setHeader(HttpHeaderNames.CONTENT_LENGTH, Long.toString(r.length)); send(resource, HttpResponseStatus.PARTIAL_CONTENT, contentType, context, r.start, r.length); } else { - context.header(CONTENT_TYPE, "multipart/byteranges; boundary=MULTIPART_BOUNDARY"); + context.setHeader(CONTENT_TYPE, "multipart/byteranges; boundary=MULTIPART_BOUNDARY"); StringBuilder sb = new StringBuilder(); for (Range r : ranges) { try { @@ -262,7 +266,7 @@ public abstract class AbstractResourceHandler implements HttpHandler { } } context.status(HttpResponseStatus.OK) - .header(CONTENT_TYPE, contentType) + .setHeader(CONTENT_TYPE, contentType) .body(CharBuffer.wrap(sb), StandardCharsets.ISO_8859_1); } } @@ -296,7 +300,7 @@ public abstract class AbstractResourceHandler implements HttpHandler { } else if (context.getRequestBuilder().getMethod() == HttpMethod.HEAD) { logger.log(Level.FINEST, "HEAD request, do not send body"); context.status(HttpResponseStatus.OK) - .header(CONTENT_TYPE, contentType); + .setHeader(CONTENT_TYPE, contentType); } else { if ("file".equals(url.getScheme())) { Path path = resource.getPath(); @@ -338,7 +342,7 @@ public abstract class AbstractResourceHandler implements HttpHandler { try (ReadableByteChannel channel = fileChannel) { DataBuffer dataBuffer = DataBufferUtil.readBuffer(context.getDataBufferFactory(), channel, size); context.status(httpResponseStatus) - .header(CONTENT_TYPE, contentType) + .setHeader(CONTENT_TYPE, contentType) .body(dataBuffer); } } @@ -358,7 +362,7 @@ public abstract class AbstractResourceHandler implements HttpHandler { try (ReadableByteChannel channel = Channels.newChannel(inputStream)) { DataBuffer dataBuffer = DataBufferUtil.readBuffer(context.getDataBufferFactory(), channel, size); context.status(httpResponseStatus) - .header(CONTENT_TYPE, contentType) + .setHeader(CONTENT_TYPE, contentType) .body(dataBuffer); } } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/resource/ClassLoaderResourceHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/resource/ClassLoaderResourceHandler.java index 26828e8..5c64492 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/resource/ClassLoaderResourceHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/resource/ClassLoaderResourceHandler.java @@ -19,13 +19,18 @@ public class ClassLoaderResourceHandler extends AbstractResourceHandler { private final String resourcePrefix; + private final int cacheSeconds; + public ClassLoaderResourceHandler(ClassLoader classLoader) { - this(classLoader, null); + this(classLoader, null, 24 * 3600); } - public ClassLoaderResourceHandler(ClassLoader classLoader, String resourcePrefix) { + public ClassLoaderResourceHandler(ClassLoader classLoader, + String resourcePrefix, + int cacheSeconds) { this.classLoader = classLoader; this.resourcePrefix = resourcePrefix; + this.cacheSeconds = cacheSeconds; } @Override @@ -34,23 +39,23 @@ public class ClassLoaderResourceHandler extends AbstractResourceHandler { } @Override - protected boolean isETagResponseEnabled() { + protected boolean isETagEnabled() { return true; } @Override - protected boolean isCacheResponseEnabled() { + protected String getCacheControl() { + return "public"; + } + + @Override + protected boolean isRangeEnabled() { return true; } @Override - protected boolean isRangeResponseEnabled() { - return true; - } - - @Override - protected int getMaxAgeSeconds() { - return 24 * 3600; + protected int getCacheMaxAgeSeconds() { + return cacheSeconds; } class ClassLoaderResource implements Resource { diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/resource/FileResourceHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/resource/FileResourceHandler.java index f166416..ddc2e7c 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/resource/FileResourceHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/resource/FileResourceHandler.java @@ -24,14 +24,20 @@ public class FileResourceHandler extends AbstractResourceHandler { private final String pathNameOfResource; + private final int cacheSeconds; + public FileResourceHandler() { - this(null, "index.html", null); + this(null, "index.html", null, 24 * 3600); } - public FileResourceHandler(String webRoot, String indexFileName, String pathNameOfResource) { + public FileResourceHandler(String webRoot, + String indexFileName, + String pathNameOfResource, + int cacheSeconds) { this.webRoot = webRoot; this.indexFileName = indexFileName; this.pathNameOfResource = pathNameOfResource; + this.cacheSeconds = cacheSeconds; } @Override @@ -58,23 +64,23 @@ public class FileResourceHandler extends AbstractResourceHandler { } @Override - protected boolean isETagResponseEnabled() { + protected boolean isETagEnabled() { return true; } @Override - protected boolean isCacheResponseEnabled() { + protected boolean isRangeEnabled() { return true; } @Override - protected boolean isRangeResponseEnabled() { - return true; + protected int getCacheMaxAgeSeconds() { + return cacheSeconds; } @Override - protected int getMaxAgeSeconds() { - return 24 * 3600; + public String getCacheControl() { + return "public"; } protected class FileResource implements Resource { diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/resource/HtmlTemplateResourceHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/resource/HtmlTemplateResourceHandler.java index c9146ad..9a0d146 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/resource/HtmlTemplateResourceHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/resource/HtmlTemplateResourceHandler.java @@ -27,25 +27,26 @@ public class HtmlTemplateResourceHandler extends AbstractResourceHandler { } @Override - protected boolean isETagResponseEnabled() { + protected boolean isETagEnabled() { return false; } @Override - protected boolean isCacheResponseEnabled() { + protected boolean isRangeEnabled() { return false; } @Override - protected boolean isRangeResponseEnabled() { - return false; - } - - @Override - protected int getMaxAgeSeconds() { + protected int getCacheMaxAgeSeconds() { + // disables caching return 0; } + @Override + protected String getCacheControl() { + return "no-cache"; + } + public Path getRoot() { return root; } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/resource/WebRootResourceResolver.java b/net-http-server/src/main/java/org/xbib/net/http/server/resource/WebRootResourceResolver.java index 3661fd2..861e558 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/resource/WebRootResourceResolver.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/resource/WebRootResourceResolver.java @@ -56,7 +56,7 @@ public class WebRootResourceResolver implements ResourceResolver { .build() .toString(); httpRouterContext.status(HttpResponseStatus.TEMPORARY_REDIRECT) - .header("location", loc); + .setHeader("location", loc); } } return resource; diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/route/BaseHttpRouterContext.java b/net-http-server/src/main/java/org/xbib/net/http/server/route/BaseHttpRouterContext.java index 6c76c49..a079e4f 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/route/BaseHttpRouterContext.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/route/BaseHttpRouterContext.java @@ -230,7 +230,13 @@ public class BaseHttpRouterContext implements HttpRouterContext { } @Override - public BaseHttpRouterContext header(String name, String value) { + public BaseHttpRouterContext setHeader(String name, String value) { + httpResponseBuilder.setHeader(name, value); + return this; + } + + @Override + public BaseHttpRouterContext addHeader(String name, String value) { httpResponseBuilder.addHeader(name, value); return this; } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/route/HttpRouterContext.java b/net-http-server/src/main/java/org/xbib/net/http/server/route/HttpRouterContext.java index a5b4ff8..ee14a70 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/route/HttpRouterContext.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/route/HttpRouterContext.java @@ -79,7 +79,9 @@ public interface HttpRouterContext { HttpRouterContext charset(Charset charset); - HttpRouterContext header(String name, String value); + HttpRouterContext setHeader(String name, String value); + + HttpRouterContext addHeader(String name, String value); HttpRouterContext cookie(Cookie cookie); diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/session/IncomingSessionHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/session/IncomingContextHandler.java similarity index 69% rename from net-http-server/src/main/java/org/xbib/net/http/server/session/IncomingSessionHandler.java rename to net-http-server/src/main/java/org/xbib/net/http/server/session/IncomingContextHandler.java index 633ab68..e33adab 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/session/IncomingSessionHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/session/IncomingContextHandler.java @@ -24,9 +24,9 @@ import org.xbib.net.http.server.cookie.CookieSignatureException; import org.xbib.net.http.server.cookie.CookieSignatureUtil; import org.xbib.net.http.server.persist.Codec; -public class IncomingSessionHandler implements HttpHandler { +public class IncomingContextHandler implements HttpHandler { - private static final Logger logger = Logger.getLogger(IncomingSessionHandler.class.getName()); + private static final Logger logger = Logger.getLogger(IncomingContextHandler.class.getName()); private final String sessionSecret; @@ -36,32 +36,21 @@ public class IncomingSessionHandler implements HttpHandler { private final Codec sessionCodec; - private final String sessionUserName; - - private final String sessionEffectiveUserName; - - /** - * These suffixes disable incoming session creation. - */ private final Set suffixes; Supplier sessionIdGenerator; - public IncomingSessionHandler(String sessionSecret, + public IncomingContextHandler(String sessionSecret, String sessionCookieAlgorithm, String sessionCookieName, Codec sessionCodec, Set suffixes, - String sessionUserName, - String sessionEffectiveUserName, Supplier sessionIdGenerator) { this.sessionSecret = sessionSecret; this.sessionCookieAlgorithm = sessionCookieAlgorithm; this.sessionCookieName = sessionCookieName; this.sessionCodec = sessionCodec; this.suffixes = suffixes; - this.sessionUserName = sessionUserName; - this.sessionEffectiveUserName = sessionEffectiveUserName; this.sessionIdGenerator = sessionIdGenerator; } @@ -73,14 +62,20 @@ public class IncomingSessionHandler implements HttpHandler { } Map payload = null; Session session = null; + UserProfile userProfile = null; CookieBox cookieBox = context.getAttributes().get(CookieBox.class, "incomingcookies"); if (cookieBox != null) { for (Cookie cookie : cookieBox) { if (cookie.name().equals(sessionCookieName)) { + logger.log(Level.FINE, "found our cookie " + sessionCookieName); if (session == null) { try { payload = decodeCookie(cookie); + logger.log(Level.FINE, "payload from cookie = " + payload); session = toSession(payload); + logger.log(Level.FINE, "session from payload = " + session); + userProfile = toUserProfile(session); + logger.log(Level.FINE, "userprofile from session = " + userProfile); } catch (CookieSignatureException e) { // set exception in context to discard broken cookie later and render exception message context.getAttributes().put("_throwable", e); @@ -97,19 +92,63 @@ public class IncomingSessionHandler implements HttpHandler { if (session == null) { try { session = sessionCodec.create(sessionIdGenerator.get()); + logger.log(Level.FINE, "creating new session " + session.id()); } catch (IOException e) { logger.log(Level.SEVERE, e.getMessage(), e); - throw new HttpException("unable to create session", context, HttpResponseStatus.INTERNAL_SERVER_ERROR); + throw new HttpException("unable to create new session", context, HttpResponseStatus.INTERNAL_SERVER_ERROR); } } - if (payload != null) { - UserProfile userProfile = newUserProfile(payload, session); - if (userProfile != null) { - context.getAttributes().put("userprofile", userProfile); - } + if (userProfile == null) { + logger.log(Level.FINE, "creating new user profile"); + userProfile = newUserProfile(payload); } - logger.log(Level.FINEST, "incoming session ID = " + session.id() + " keys = " + session.keySet()); context.getAttributes().put("session", session); + context.getAttributes().put("userprofile", userProfile); + } + + protected Session toSession(Map map) { + return toSession((String) map.get("id"), map); + } + + protected Session toSession(String id, Map map) { + Session session = null; + try { + session = sessionCodec.read(id); + if (session != null && map != null) { + logger.log(Level.FINE, "session id " + id + " restored"); + session.putAll(map); + } + } catch (Exception e) { + logger.log(Level.FINEST, "unable to restore session, id = " + id, e); + } + return session; + } + + @SuppressWarnings("unchecked") + protected UserProfile toUserProfile(Session session) { + Map map = (Map) session.get("userprofile"); + return map != null ? BaseUserProfile.fromMap(map) : null; + } + + @SuppressWarnings("unchecked") + protected UserProfile newUserProfile(Map cookieMap) { + UserProfile userProfile = new BaseUserProfile(); + // user_id, e_user_id are in cookie map + if (cookieMap != null) { + Map m = (Map) cookieMap.get("map"); + if (m == null) { + // nothing found + return userProfile; + } + if (m.containsKey("user_id")) { + userProfile.setUserId((String) m.get("user_id")); + } + if (m.containsKey("e_user_id")) { + userProfile.setEffectiveUserId((String) m.get("e_user_id")); + } + // roles, permissions, attributes must be filled later + } + return userProfile; } private Map decodeCookie(Cookie cookie) throws IOException, @@ -127,48 +166,10 @@ public class IncomingSessionHandler implements HttpHandler { String sig = s[2]; String mysig = CookieSignatureUtil.hmac(payload, sessionSecret, sessionCookieAlgorithm); if (!sig.equals(mysig)) { - logger.log(Level.SEVERE, MessageFormat.format("signature in cookie does not match. algo={1} secret={2} payload={3} sig={4} mysig={5}", + logger.log(Level.SEVERE, () -> MessageFormat.format("signature in cookie does not match. algo={0} secret={1} payload={2} sig={3} mysig={4}", sessionCookieAlgorithm, sessionSecret, payload, sig, mysig)); throw new CookieSignatureException("cookie security problem"); } - Map map = CookieSignatureUtil.toMap(payload); - return Map.of("id", id, "payload", payload, "map", map); - } - - protected Session toSession(Map map) { - return toSession((String) map.get("id"), map); - } - - protected Session toSession(String id, Map map) { - Session session = null; - try { - session = sessionCodec.read(id); - if (session != null && map != null) { - session.putAll(map); - } - } catch (Exception e) { - logger.log(Level.FINEST, "unable to read session, id = " + id, e); - } - return session; - } - - @SuppressWarnings("unchecked") - protected UserProfile newUserProfile(Map map, Session session) { - UserProfile userProfile = new BaseUserProfile(); - Map m = (Map) map.get("map"); - if (m == null) { - return userProfile; - } - if (sessionUserName != null && m.containsKey(sessionUserName)) { - userProfile.setUserId((String) m.get(sessionUserName)); - } - if (sessionEffectiveUserName != null && m.containsKey(sessionEffectiveUserName)) { - userProfile.setEffectiveUserId((String) m.get(sessionEffectiveUserName)); - } - if (session != null && userProfile.getUserId() != null) { - session.put("user_id", userProfile.getUserId()); - session.put("e_user_id", userProfile.getUserId()); - } - return userProfile; + return Map.of("id", id, "payload", payload, "map", CookieSignatureUtil.toMap(payload)); } } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/session/OutgoingSessionHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/session/OutgoingContextHandler.java similarity index 79% rename from net-http-server/src/main/java/org/xbib/net/http/server/session/OutgoingSessionHandler.java rename to net-http-server/src/main/java/org/xbib/net/http/server/session/OutgoingContextHandler.java index 0616874..2d7788b 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/session/OutgoingSessionHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/session/OutgoingContextHandler.java @@ -5,7 +5,6 @@ import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.time.Duration; -import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.logging.Level; @@ -25,9 +24,9 @@ import org.xbib.net.http.server.application.Application; import org.xbib.net.http.server.cookie.CookieSignatureException; import org.xbib.net.http.server.cookie.CookieSignatureUtil; -public class OutgoingSessionHandler implements HttpHandler { +public class OutgoingContextHandler implements HttpHandler { - private static final Logger logger = Logger.getLogger(OutgoingSessionHandler.class.getName()); + private static final Logger logger = Logger.getLogger(OutgoingContextHandler.class.getName()); private final String sessionSecret; @@ -39,22 +38,16 @@ public class OutgoingSessionHandler implements HttpHandler { private final Set suffixes; - private final String sessionUserName; - - private final String sessionEffectiveUserName; - private final boolean httpOnly; private final boolean secure; private final SameSite sameSite; - public OutgoingSessionHandler(String sessionSecret, + public OutgoingContextHandler(String sessionSecret, String sessionCookieAlgorithm, String sessionCookieName, Set suffixes, - String sessionUserName, - String sessionEffectiveUserName, Duration sessionDuration, boolean httpOnly, boolean secure, @@ -63,8 +56,6 @@ public class OutgoingSessionHandler implements HttpHandler { this.sessionCookieAlgorithm = sessionCookieAlgorithm; this.sessionCookieName = sessionCookieName; this.suffixes = suffixes; - this.sessionUserName = sessionUserName; - this.sessionEffectiveUserName = sessionEffectiveUserName; this.sessionDuration = sessionDuration; this.httpOnly = httpOnly; this.secure = secure; @@ -79,7 +70,6 @@ public class OutgoingSessionHandler implements HttpHandler { } String suffix = SessionUtil.extractExtension(context.getRequestBuilder().getRequestPath()); if (suffix != null && suffixes.contains(suffix)) { - logger.log(Level.FINEST, () -> "suffix " + suffix + " blocking outgoing session handling"); return; } CookieBox cookieBox = context.getAttributes().get(CookieBox.class, "outgoingcookies"); @@ -87,7 +77,6 @@ public class OutgoingSessionHandler implements HttpHandler { cookieBox = new CookieBox(); } Application application = context.getAttributes().get(Application.class, "application"); - UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile"); String host = context.getContextURL().getHost(); String path = application.getContextPath(); Throwable throwable = context.getAttributes().get(Throwable.class, "_throwable"); @@ -99,16 +88,11 @@ public class OutgoingSessionHandler implements HttpHandler { Session session = context.getAttributes().get(Session.class, "session"); if (session != null) { try { + UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile"); if (userProfile != null) { - logger.log(Level.FINEST, () -> "user profile present: " + userProfile); - if (sessionUserName != null) { - session.put(sessionUserName, userProfile.getUserId()); - } - if (sessionEffectiveUserName != null) { - session.put(sessionEffectiveUserName, userProfile.getEffectiveUserId()); - } + session.put("userprofile", userProfile.asMap()); } - Cookie cookie = encodeCookie(session, host, path); + Cookie cookie = encodeCookie(session, userProfile, host, path); if (cookie != null) { cookieBox.add(cookie); } @@ -117,12 +101,18 @@ public class OutgoingSessionHandler implements HttpHandler { throw new HttpException("unable to create session data for cookie", context, HttpResponseStatus.INTERNAL_SERVER_ERROR); } } - logger.log(Level.FINEST, "prepared outgoing cookies = " + cookieBox); context.getAttributes().put("outgoingcookies", cookieBox); } - private Cookie encodeCookie(Session session, String host, String path) throws IOException, + private Cookie encodeCookie(Session session, + UserProfile userProfile, + String host, + String path) throws IOException, NoSuchAlgorithmException, InvalidKeyException { + if (session == null) { + logger.log(Level.WARNING, "no session, no cookie"); + return null; + } if (sessionSecret == null) { logger.log(Level.WARNING, "no secret, no cookie"); return null; @@ -137,13 +127,10 @@ public class OutgoingSessionHandler implements HttpHandler { session.invalidate(); return createEmptyCookie(host, path); } - Map map = new HashMap<>(); - if (sessionUserName != null) { - map.put(sessionUserName, session.get(sessionUserName)); - } - if (sessionEffectiveUserName != null) { - map.put(sessionEffectiveUserName, session.get(sessionEffectiveUserName)); - } + Map map = userProfile != null ? + Map.of("user_id", userProfile.getUserId() != null ? userProfile.getUserId() :"", + "e_user_id", userProfile.getEffectiveUserId() != null ? userProfile.getEffectiveUserId() : "") : + Map.of(); String payload = CookieSignatureUtil.toString(map); String sig = CookieSignatureUtil.hmac(payload, sessionSecret, sessionCookieAlgorithm); String cookieValue = String.join(":", id, payload, sig); diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/session/PersistSessionHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/session/PersistSessionHandler.java index 2097633..b7a8574 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/session/PersistSessionHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/session/PersistSessionHandler.java @@ -28,7 +28,7 @@ public class PersistSessionHandler implements HttpHandler { sessionCodec.write(session.id(), session); } catch (Exception e) { logger.log(Level.SEVERE, e.getMessage(), e); - throw new HttpException("unable to create session data for cookie", context, HttpResponseStatus.INTERNAL_SERVER_ERROR); + throw new HttpException("unable to write session data", context, HttpResponseStatus.INTERNAL_SERVER_ERROR); } } } diff --git a/net-http-template-groovy/src/main/java/org/xbib/net/http/template/groovy/GroovyTemplateRenderer.java b/net-http-template-groovy/src/main/java/org/xbib/net/http/template/groovy/GroovyTemplateRenderer.java index de82dca..ffed456 100644 --- a/net-http-template-groovy/src/main/java/org/xbib/net/http/template/groovy/GroovyTemplateRenderer.java +++ b/net-http-template-groovy/src/main/java/org/xbib/net/http/template/groovy/GroovyTemplateRenderer.java @@ -30,9 +30,9 @@ public class GroovyTemplateRenderer implements HttpHandler { } HttpResponseStatus httpResponseStatus = context.getAttributes().get(HttpResponseStatus.class, "_status", HttpResponseStatus.OK); context.status(httpResponseStatus) - .header("cache-control", "no-cache") // override default must-revalidate behavior - .header("content-length", Integer.toString(dataBuffer.writePosition())) - .header(CONTENT_TYPE, "text/html; charset=" + StandardCharsets.UTF_8.displayName()) + .setHeader("cache-control", "no-cache") + .setHeader("content-length", Integer.toString(dataBuffer.writePosition())) + .setHeader(CONTENT_TYPE, "text/html; charset=" + StandardCharsets.UTF_8.displayName()) .body(dataBuffer); } }