allow parameter evaluation in j2html resources

This commit is contained in:
Jörg Prante 2024-06-05 17:34:31 +02:00
parent f0d743642a
commit be8f6ef4b3
9 changed files with 156 additions and 65 deletions

View file

@ -0,0 +1,41 @@
package org.xbib.net.http.j2html;
import org.xbib.net.ParameterException;
import org.xbib.net.Resource;
import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
import org.xbib.net.http.server.route.HttpRouterContext;
import java.io.IOException;
import static org.xbib.j2html.TagCreator.body;
import static org.xbib.j2html.TagCreator.h1;
import static org.xbib.j2html.TagCreator.html;
public class BadRequestHandler extends J2HtmlResourceHandler {
@Override
protected Resource createResource(HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
return new UnauthorizedResource(this, httpRouterContext);
}
protected static class UnauthorizedResource extends J2HtmlResource {
protected UnauthorizedResource(HtmlTemplateResourceHandler templateResourceHandler,
HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
super(templateResourceHandler, httpRouterContext);
}
@Override
protected HttpResponseStatus getResponseStatus() {
return HttpResponseStatus.BAD_REQUEST;
}
@Override
protected String renderHtml(HttpRouterContext httpRouterContext) {
return html(body(h1("Bad request"))).render();
}
}
}

View file

@ -1,6 +1,7 @@
package org.xbib.net.http.j2html; package org.xbib.net.http.j2html;
import org.xbib.net.Attributes; import org.xbib.net.Attributes;
import org.xbib.net.ParameterException;
import org.xbib.net.Resource; import org.xbib.net.Resource;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler; import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
@ -19,14 +20,16 @@ import static org.xbib.j2html.TagCreator.pre;
public class InternalServerErrorHandler extends J2HtmlResourceHandler { public class InternalServerErrorHandler extends J2HtmlResourceHandler {
@Override @Override
protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException { protected Resource createResource(HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
return new InternalServerErrorResource(this, httpRouterContext); return new InternalServerErrorResource(this, httpRouterContext);
} }
protected static class InternalServerErrorResource extends J2HtmlResource { protected static class InternalServerErrorResource extends J2HtmlResource {
protected InternalServerErrorResource(HtmlTemplateResourceHandler templateResourceHandler, protected InternalServerErrorResource(HtmlTemplateResourceHandler templateResourceHandler,
HttpRouterContext httpRouterContext) throws IOException { HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
super(templateResourceHandler, httpRouterContext); super(templateResourceHandler, httpRouterContext);
} }

View file

@ -1,6 +1,8 @@
package org.xbib.net.http.j2html; package org.xbib.net.http.j2html;
import org.xbib.net.ParameterException;
import org.xbib.net.buffer.DataBuffer; import org.xbib.net.buffer.DataBuffer;
import org.xbib.net.http.HttpHeaderValues;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpRequest; import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.resource.HtmlTemplateResource; import org.xbib.net.http.server.resource.HtmlTemplateResource;
@ -11,6 +13,8 @@ import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Objects; import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.xbib.j2html.TagCreator.body; import static org.xbib.j2html.TagCreator.body;
import static org.xbib.j2html.TagCreator.document; import static org.xbib.j2html.TagCreator.document;
@ -20,29 +24,40 @@ import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
public class J2HtmlResource extends HtmlTemplateResource { public class J2HtmlResource extends HtmlTemplateResource {
private static final Logger logger = Logger.getLogger(J2HtmlResource.class.getName());
protected HttpRequest request; protected HttpRequest request;
public J2HtmlResource(HtmlTemplateResourceHandler templateResourceHandler, public J2HtmlResource(HtmlTemplateResourceHandler templateResourceHandler,
HttpRouterContext httpRouterContext) throws IOException { HttpRouterContext httpRouterContext) throws IOException, ParameterException {
super(templateResourceHandler, httpRouterContext); super(templateResourceHandler, httpRouterContext);
} }
@Override @Override
public void render(HttpRouterContext context) throws IOException { public void render(HttpRouterContext context)
this.request = context.getRequest(); throws IOException {
Objects.requireNonNull(responseBuilder); try {
DataBuffer dataBuffer = context.getDataBufferFactory().allocateBuffer(); this.request = context.getRequest();
dataBuffer.write(renderHtml(context), getCharset()); Objects.requireNonNull(responseBuilder);
HttpResponseStatus httpResponseStatus = responseBuilder.getResponseStatus(); DataBuffer dataBuffer = context.getDataBufferFactory().allocateBuffer();
if (httpResponseStatus == null) { dataBuffer.write(renderHtml(context), getCharset());
httpResponseStatus = getResponseStatus(); HttpResponseStatus httpResponseStatus = responseBuilder.getResponseStatus();
if (httpResponseStatus == null) {
httpResponseStatus = getResponseStatus();
}
context.status(httpResponseStatus)
.setHeader("cache-control", "no-cache")
.setHeader("content-length", Integer.toString(dataBuffer.writePosition()))
.setHeader(CONTENT_TYPE, "text/html; charset=" + getCharset().displayName())
.body(dataBuffer)
.done();
} catch (ParameterException e) {
logger.log(Level.WARNING, e.getMessage(), e);
context.status(HttpResponseStatus.BAD_REQUEST)
.setHeader(CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.body(e.getMessage())
.done();
} }
context.status(httpResponseStatus)
.setHeader("cache-control", "no-cache")
.setHeader("content-length", Integer.toString(dataBuffer.writePosition()))
.setHeader(CONTENT_TYPE, "text/html; charset=" + getCharset().displayName())
.body(dataBuffer)
.done();
} }
protected HttpResponseStatus getResponseStatus() { protected HttpResponseStatus getResponseStatus() {
@ -54,14 +69,14 @@ public class J2HtmlResource extends HtmlTemplateResource {
} }
/** /**
* Rendering.
* By subclassing this handler, this method should be overridden by custom j2html code. * By subclassing this handler, this method should be overridden by custom j2html code.
* The HTML is here is just a greeting as an example. * The HTML is here is just a greeting as an example.
* *
* @param context the router context * @param context the router context
* @return the body string fo the HTTP response * @return the body string fo the HTTP response
*/ */
protected String renderHtml(HttpRouterContext context) { protected String renderHtml(HttpRouterContext context)
throws IOException, ParameterException {
return document(html(body(h1("Hello World")))); return document(html(body(h1("Hello World"))));
} }
} }

View file

@ -1,5 +1,6 @@
package org.xbib.net.http.j2html; package org.xbib.net.http.j2html;
import org.xbib.net.ParameterException;
import org.xbib.net.Resource; import org.xbib.net.Resource;
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler; import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
import org.xbib.net.http.server.route.HttpRouterContext; import org.xbib.net.http.server.route.HttpRouterContext;
@ -7,9 +8,6 @@ import org.xbib.net.http.server.route.HttpRouterContext;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import static org.xbib.j2html.TagCreator.body;
import static org.xbib.j2html.TagCreator.h1;
public class J2HtmlResourceHandler extends HtmlTemplateResourceHandler { public class J2HtmlResourceHandler extends HtmlTemplateResourceHandler {
public J2HtmlResourceHandler() { public J2HtmlResourceHandler() {
@ -21,13 +19,15 @@ public class J2HtmlResourceHandler extends HtmlTemplateResourceHandler {
} }
@Override @Override
protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException { protected Resource createResource(HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
return httpRouterContext.isAuthenticated() ? return httpRouterContext.isAuthenticated() ?
new J2HtmlResource(this, httpRouterContext) : new J2HtmlResource(this, httpRouterContext) :
createUnauthenticatedResource(httpRouterContext); createUnauthenticatedResource(httpRouterContext);
} }
protected Resource createUnauthenticatedResource(HttpRouterContext httpRouterContext) throws IOException { protected Resource createUnauthenticatedResource(HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
return new J2HtmlResource(this, httpRouterContext); return new J2HtmlResource(this, httpRouterContext);
} }
} }

View file

@ -1,5 +1,6 @@
package org.xbib.net.http.j2html; package org.xbib.net.http.j2html;
import org.xbib.net.ParameterException;
import org.xbib.net.Resource; import org.xbib.net.Resource;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler; import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
@ -14,14 +15,16 @@ import static org.xbib.j2html.TagCreator.html;
public class NotFoundHandler extends J2HtmlResourceHandler { public class NotFoundHandler extends J2HtmlResourceHandler {
@Override @Override
protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException { protected Resource createResource(HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
return new UnauthorizedResource(this, httpRouterContext); return new UnauthorizedResource(this, httpRouterContext);
} }
protected static class UnauthorizedResource extends J2HtmlResource { protected static class UnauthorizedResource extends J2HtmlResource {
protected UnauthorizedResource(HtmlTemplateResourceHandler templateResourceHandler, protected UnauthorizedResource(HtmlTemplateResourceHandler templateResourceHandler,
HttpRouterContext httpRouterContext) throws IOException { HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
super(templateResourceHandler, httpRouterContext); super(templateResourceHandler, httpRouterContext);
} }

View file

@ -1,5 +1,6 @@
package org.xbib.net.http.j2html; package org.xbib.net.http.j2html;
import org.xbib.net.ParameterException;
import org.xbib.net.Resource; import org.xbib.net.Resource;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler; import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
@ -14,14 +15,16 @@ import static org.xbib.j2html.TagCreator.html;
public class UnauthorizedHandler extends J2HtmlResourceHandler { public class UnauthorizedHandler extends J2HtmlResourceHandler {
@Override @Override
protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException { protected Resource createResource(HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
return new UnauthorizedResource(this, httpRouterContext); return new UnauthorizedResource(this, httpRouterContext);
} }
protected static class UnauthorizedResource extends J2HtmlResource { protected static class UnauthorizedResource extends J2HtmlResource {
protected UnauthorizedResource(HtmlTemplateResourceHandler templateResourceHandler, protected UnauthorizedResource(HtmlTemplateResourceHandler templateResourceHandler,
HttpRouterContext httpRouterContext) throws IOException { HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
super(templateResourceHandler, httpRouterContext); super(templateResourceHandler, httpRouterContext);
} }

View file

@ -5,15 +5,19 @@ import org.xbib.config.ConfigLogger;
import org.xbib.config.ConfigParams; import org.xbib.config.ConfigParams;
import org.xbib.config.SystemConfigLogger; import org.xbib.config.SystemConfigLogger;
import org.xbib.net.NetworkClass; import org.xbib.net.NetworkClass;
import org.xbib.net.ParameterException;
import org.xbib.net.Resource; import org.xbib.net.Resource;
import org.xbib.net.http.HttpHeaderNames; import org.xbib.net.http.HttpHeaderNames;
import org.xbib.net.http.HttpHeaderValues; import org.xbib.net.http.HttpHeaderValues;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.HttpVersion; import org.xbib.net.http.HttpVersion;
import org.xbib.net.http.j2html.BadRequestHandler;
import org.xbib.net.http.j2html.InternalServerErrorHandler; import org.xbib.net.http.j2html.InternalServerErrorHandler;
import org.xbib.net.http.j2html.J2HtmlResource; import org.xbib.net.http.j2html.J2HtmlResource;
import org.xbib.net.http.j2html.J2HtmlResourceHandler; import org.xbib.net.http.j2html.J2HtmlResourceHandler;
import org.xbib.net.http.j2html.J2HtmlService; import org.xbib.net.http.j2html.J2HtmlService;
import org.xbib.net.http.j2html.NotFoundHandler;
import org.xbib.net.http.j2html.UnauthorizedHandler;
import org.xbib.net.http.server.application.web.WebApplication; import org.xbib.net.http.server.application.web.WebApplication;
import org.xbib.net.http.server.auth.BasicAuthenticationHandler; import org.xbib.net.http.server.auth.BasicAuthenticationHandler;
import org.xbib.net.http.server.auth.FormAuthenticationHandler; import org.xbib.net.http.server.auth.FormAuthenticationHandler;
@ -141,6 +145,9 @@ public final class Bootstrap {
.build(); .build();
HttpRouter httpRouter = BaseHttpRouter.builder() HttpRouter httpRouter = BaseHttpRouter.builder()
.setHandler(401, new UnauthorizedHandler())
.setHandler(403, new BadRequestHandler())
.setHandler(404, new NotFoundHandler())
.setHandler(500, new InternalServerErrorHandler()) .setHandler(500, new InternalServerErrorHandler())
.addDomain(BaseHttpDomain.builder() .addDomain(BaseHttpDomain.builder()
.setHttpAddress(httpsAddress) .setHttpAddress(httpsAddress)
@ -206,12 +213,14 @@ public final class Bootstrap {
static class MyResourceHandler extends J2HtmlResourceHandler { static class MyResourceHandler extends J2HtmlResourceHandler {
@Override @Override
protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException { protected Resource createResource(HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
return new DemoResource(this, httpRouterContext); return new DemoResource(this, httpRouterContext);
} }
@Override @Override
protected Resource createUnauthenticatedResource(HttpRouterContext httpRouterContext) throws IOException { protected Resource createUnauthenticatedResource(HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
return new UnauthenticatedDemoResource(this, httpRouterContext); return new UnauthenticatedDemoResource(this, httpRouterContext);
} }
} }
@ -219,7 +228,8 @@ public final class Bootstrap {
static class DemoResource extends J2HtmlResource { static class DemoResource extends J2HtmlResource {
public DemoResource(HtmlTemplateResourceHandler templateResourceHandler, public DemoResource(HtmlTemplateResourceHandler templateResourceHandler,
HttpRouterContext httpRouterContext) throws IOException { HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
super(templateResourceHandler, httpRouterContext); super(templateResourceHandler, httpRouterContext);
} }
@ -233,7 +243,8 @@ public final class Bootstrap {
static class UnauthenticatedDemoResource extends J2HtmlResource { static class UnauthenticatedDemoResource extends J2HtmlResource {
public UnauthenticatedDemoResource(HtmlTemplateResourceHandler templateResourceHandler, public UnauthenticatedDemoResource(HtmlTemplateResourceHandler templateResourceHandler,
HttpRouterContext httpRouterContext) throws IOException { HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
super(templateResourceHandler, httpRouterContext); super(templateResourceHandler, httpRouterContext);
} }

View file

@ -18,12 +18,15 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.xbib.net.ParameterException;
import org.xbib.net.Resource; import org.xbib.net.Resource;
import org.xbib.net.URL; import org.xbib.net.URL;
import org.xbib.net.buffer.DataBuffer; import org.xbib.net.buffer.DataBuffer;
import org.xbib.net.buffer.DataBufferFactory; import org.xbib.net.buffer.DataBufferFactory;
import org.xbib.net.buffer.DataBufferUtil; import org.xbib.net.buffer.DataBufferUtil;
import org.xbib.net.http.HttpHeaderNames; import org.xbib.net.http.HttpHeaderNames;
import org.xbib.net.http.HttpHeaderValues;
import org.xbib.net.http.HttpHeaders; import org.xbib.net.http.HttpHeaders;
import org.xbib.net.http.HttpMethod; import org.xbib.net.http.HttpMethod;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
@ -44,7 +47,8 @@ public abstract class AbstractResourceHandler implements HttpHandler {
public AbstractResourceHandler() { public AbstractResourceHandler() {
} }
protected abstract Resource createResource(HttpRouterContext httpRouterContext) throws IOException; protected abstract Resource createResource(HttpRouterContext httpRouterContext)
throws IOException, ParameterException;
protected abstract boolean isETagEnabled(); protected abstract boolean isETagEnabled();
@ -56,39 +60,47 @@ public abstract class AbstractResourceHandler implements HttpHandler {
@Override @Override
public void handle(HttpRouterContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
logger.log(Level.FINEST, () -> "handle: before creating resource " + this.getClass().getName()); try {
Resource resource = createResource(context); logger.log(Level.FINEST, () -> "handle: before creating resource " + this.getClass().getName());
logger.log(Level.FINEST, () -> "handle: resource = " + (resource != null ? resource.getClass().getName() + " " + resource : null)); Resource resource = createResource(context);
if (resource instanceof HtmlTemplateResource) { logger.log(Level.FINEST, () -> "handle: resource = " + (resource != null ? resource.getClass().getName() + " " + resource : null));
generateCacheableResource(context, resource); if (resource instanceof HtmlTemplateResource) {
return;
}
if (resource == null) {
throw new HttpException("resource not found", context, HttpResponseStatus.NOT_FOUND);
} else if (resource.isDirectory()) {
logger.log(Level.FINEST, "we have a directory request");
if (!resource.getResourcePath().isEmpty() && !resource.getResourcePath().endsWith("/")) {
URL url = context.getRequestBuilder().getUrl().resolve(resource.getName() + '/');
String loc = URL.builder(url)
.query(url.getQuery())
.fragment(url.getFragment())
.build()
.toString();
logger.log(Level.FINEST, "client must add a /, external redirect to = " + loc);
context.setHeader(HttpHeaderNames.LOCATION, loc)
.status(HttpResponseStatus.TEMPORARY_REDIRECT);
} else if (resource.isExistsIndexFile()) {
// internal redirect to default index file in this directory
logger.log(Level.FINEST, "internal redirect to default index file in this directory: " + resource.getIndexFileName());
generateCacheableResource(context, resource); generateCacheableResource(context, resource);
} else { return;
// send forbidden, we do not allow directory access
context.status(HttpResponseStatus.FORBIDDEN);
} }
context.done(); if (resource == null) {
} else { throw new HttpException("resource not found", context, HttpResponseStatus.NOT_FOUND);
generateCacheableResource(context, resource); } else if (resource.isDirectory()) {
context.done(); logger.log(Level.FINEST, "we have a directory request");
if (!resource.getResourcePath().isEmpty() && !resource.getResourcePath().endsWith("/")) {
URL url = context.getRequestBuilder().getUrl().resolve(resource.getName() + '/');
String loc = URL.builder(url)
.query(url.getQuery())
.fragment(url.getFragment())
.build()
.toString();
logger.log(Level.FINEST, "client must add a /, external redirect to = " + loc);
context.setHeader(HttpHeaderNames.LOCATION, loc)
.status(HttpResponseStatus.TEMPORARY_REDIRECT);
} else if (resource.isExistsIndexFile()) {
// internal redirect to default index file in this directory
logger.log(Level.FINEST, "internal redirect to default index file in this directory: " + resource.getIndexFileName());
generateCacheableResource(context, resource);
} else {
// send forbidden, we do not allow directory access
context.status(HttpResponseStatus.FORBIDDEN);
}
context.done();
} else {
generateCacheableResource(context, resource);
context.done();
}
} catch (ParameterException e) {
logger.log(Level.WARNING, e.getMessage(), e);
context.status(HttpResponseStatus.BAD_REQUEST)
.setHeader(CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.body(e.getMessage())
.done();
} }
} }

View file

@ -2,6 +2,8 @@ package org.xbib.net.http.server.resource;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import org.xbib.net.ParameterException;
import org.xbib.net.Resource; import org.xbib.net.Resource;
import org.xbib.net.http.server.route.HttpRouterContext; import org.xbib.net.http.server.route.HttpRouterContext;
@ -22,7 +24,8 @@ public class HtmlTemplateResourceHandler extends AbstractResourceHandler {
} }
@Override @Override
protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException { protected Resource createResource(HttpRouterContext httpRouterContext)
throws IOException, ParameterException {
return new HtmlTemplateResource(this, httpRouterContext); return new HtmlTemplateResource(this, httpRouterContext);
} }