refactoring HttpServerContext into HttpRouterContext

This commit is contained in:
Jörg Prante 2023-04-29 22:02:01 +02:00
parent 8786e768e1
commit 6c10666fe5
84 changed files with 1206 additions and 1179 deletions

View file

@ -1,5 +1,5 @@
group = org.xbib group = org.xbib
name = net-http name = net-http
version = 3.3.2 version = 3.4.0
org.gradle.warning.mode = ALL org.gradle.warning.mode = ALL

View file

@ -9,7 +9,7 @@ import org.xbib.config.SystemConfigLogger;
import org.xbib.net.http.server.HttpRequest; import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.application.Application; import org.xbib.net.http.server.application.Application;
import org.xbib.net.http.server.application.BaseApplicationModule; import org.xbib.net.http.server.application.BaseApplicationModule;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.service.HttpService; import org.xbib.net.http.server.service.HttpService;
import org.xbib.settings.Settings; import org.xbib.settings.Settings;
@ -47,9 +47,9 @@ public class ConfigApplicationModule extends BaseApplicationModule {
} }
@Override @Override
public void onOpen(HttpServerContext httpServerContext, HttpService httpService, HttpRequest httpRequest) { public void onOpen(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest) {
httpServerContext.getAttributes().put("configparams", configParams); httpRouterContext.getAttributes().put("configparams", configParams);
httpServerContext.getAttributes().put("configloader", configLoader); httpRouterContext.getAttributes().put("configloader", configLoader);
httpServerContext.getAttributes().put("settings", settings); httpRouterContext.getAttributes().put("settings", settings);
} }
} }

View file

@ -3,11 +3,10 @@ package org.xbib.net.http.server.application.database;
import org.xbib.jdbc.connection.pool.PoolConfig; import org.xbib.jdbc.connection.pool.PoolConfig;
import org.xbib.jdbc.connection.pool.PoolDataSource; import org.xbib.jdbc.connection.pool.PoolDataSource;
import org.xbib.jdbc.query.DatabaseProvider; import org.xbib.jdbc.query.DatabaseProvider;
import org.xbib.jdbc.query.Flavor;
import org.xbib.net.http.server.application.Application; import org.xbib.net.http.server.application.Application;
import org.xbib.net.http.server.application.BaseApplicationModule; import org.xbib.net.http.server.application.BaseApplicationModule;
import org.xbib.net.http.server.HttpRequest; import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.service.HttpService; import org.xbib.net.http.server.service.HttpService;
import org.xbib.settings.Settings; import org.xbib.settings.Settings;
@ -29,16 +28,16 @@ public class DatabaseApplicationModule extends BaseApplicationModule {
this.dataSource = createDataSource(); this.dataSource = createDataSource();
String flavor = System.getProperty("database.flavor"); String flavor = System.getProperty("database.flavor");
this.databaseProvider = flavor != null ? this.databaseProvider = flavor != null ?
DatabaseProvider.builder(dataSource, Flavor.valueOf(flavor)).build() : null; DatabaseProvider.builder(dataSource, flavor).build() : null;
} }
@Override @Override
public void onOpen(HttpServerContext httpServerContext, HttpService httpService, HttpRequest httpRequest) { public void onOpen(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest) {
if (dataSource != null) { if (dataSource != null) {
httpServerContext.getAttributes().put("datasource", dataSource); httpRouterContext.getAttributes().put("datasource", dataSource);
} }
if (databaseProvider != null) { if (databaseProvider != null) {
httpServerContext.getAttributes().put("databaseprovider", databaseProvider); httpRouterContext.getAttributes().put("databaseprovider", databaseProvider);
} }
} }

View file

@ -9,7 +9,6 @@ dependencies {
implementation libs.webjars.jquery implementation libs.webjars.jquery
implementation libs.webjars.fontawesome implementation libs.webjars.fontawesome
runtimeOnly libs.net.bouncycastle runtimeOnly libs.net.bouncycastle
runtimeOnly libs.oracle
} }
application { application {

View file

@ -136,18 +136,17 @@ public final class Bootstrap {
HttpService httpService = BaseHttpService.builder() HttpService httpService = BaseHttpService.builder()
.setPath("/secure") .setPath("/secure")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("secure domain: " +
ctx.write("secure domain: " + " SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() +
" SNI host = " + ctx.httpRequest().as(HttpsRequest.class).getSNIHost() + " SSL session = " + ctx.getRequest().as(HttpsRequest.class).getSSLSession() +
" SSL session = " + ctx.httpRequest().as(HttpsRequest.class).getSSLSession() + " base URL = " + ctx.getRequest().getBaseURL() +
" base URL = " + ctx.httpRequest().getBaseURL() + " parameter = " + ctx.getRequest().getParameter().allToString() +
" parameter = " + ctx.httpRequest().getParameter().allToString() +
" attributes = " + ctx.getAttributes() + " attributes = " + ctx.getAttributes() +
" local address = " + ctx.httpRequest().getLocalAddress() + " local address = " + ctx.getRequest().getLocalAddress() +
" remote address = " + ctx.httpRequest().getRemoteAddress()); " remote address = " + ctx.getRequest().getRemoteAddress());
ctx.done(); ctx.done();
}) })
.build(); .build();
@ -163,12 +162,10 @@ public final class Bootstrap {
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/favicon.ico") .setPath("/favicon.ico")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, "image/x-icon")
.setHeader(HttpHeaderNames.CONTENT_TYPE, "image/x-icon") .body(NettyDataBufferFactory.getInstance().wrap(Hex.fromHex(hexFavIcon)))
.write(NettyDataBufferFactory.getInstance().wrap(Hex.fromHex(hexFavIcon))) .done();
.build();
ctx.done();
}) })
.build()) .build())
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()

View file

@ -6,7 +6,7 @@ import java.time.Duration;
import org.xbib.net.http.cookie.SameSite; import org.xbib.net.http.cookie.SameSite;
import org.xbib.net.http.server.application.BaseApplication; import org.xbib.net.http.server.application.BaseApplication;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.persist.Codec; import org.xbib.net.http.server.persist.Codec;
import org.xbib.net.http.server.session.IncomingSessionHandler; import org.xbib.net.http.server.session.IncomingSessionHandler;
import org.xbib.net.http.server.session.OutgoingSessionHandler; import org.xbib.net.http.server.session.OutgoingSessionHandler;
@ -28,14 +28,14 @@ public class WebApplication extends BaseApplication {
} }
} }
protected Codec<Session> newSessionCodec(HttpServerContext httpServerContext) { protected Codec<Session> newSessionCodec(HttpRouterContext httpRouterContext) {
return new FileJsonSessionCodec(sessionName, this, 1024, Duration.ofDays(1), return new FileJsonSessionCodec(sessionName, this, 1024, Duration.ofDays(1),
Paths.get("/var/tmp/session")); Paths.get("/var/tmp/session"));
} }
protected HttpHandler newIncomingSessionHandler(HttpServerContext httpServerContext) { protected HttpHandler newIncomingSessionHandler(HttpRouterContext httpRouterContext) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Codec<Session> sessionCodec = httpServerContext.getAttributes().get(Codec.class, "sessioncodec"); Codec<Session> sessionCodec = httpRouterContext.getAttributes().get(Codec.class, "sessioncodec");
return new IncomingSessionHandler( return new IncomingSessionHandler(
getSecret(), getSecret(),
"HmacSHA1", "HmacSHA1",
@ -47,9 +47,9 @@ public class WebApplication extends BaseApplication {
() -> RandomUtil.randomString(16)); () -> RandomUtil.randomString(16));
} }
protected OutgoingSessionHandler newOutgoingSessionHandler(HttpServerContext httpServerContext) { protected OutgoingSessionHandler newOutgoingSessionHandler(HttpRouterContext httpRouterContext) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Codec<Session> sessionCodec = httpServerContext.getAttributes().get(Codec.class, "sessioncodec"); Codec<Session> sessionCodec = httpRouterContext.getAttributes().get(Codec.class, "sessioncodec");
return new OutgoingSessionHandler( return new OutgoingSessionHandler(
getSecret(), getSecret(),
"HmacSHA1", "HmacSHA1",

View file

@ -55,24 +55,22 @@ public class NettyHttps2ServerMultiRequestLoadTest {
.setHttpAddress(httpsAddress) .setHttpAddress(httpsAddress)
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/favicon.ico") .setPath("/favicon.ico")
.setHandler(ctx -> ctx.response() .setHandler(ctx ->
.setResponseStatus(HttpResponseStatus.NOT_FOUND) ctx.status(HttpResponseStatus.NOT_FOUND))
.build()
.flush())
.build()) .build())
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/secure") .setPath("/secure")
.setHandler(ctx -> { ctx.response() .setHandler(ctx -> {
.setResponseStatus(HttpResponseStatus.OK) ctx.status(HttpResponseStatus.OK)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setCharset(StandardCharsets.UTF_8); .charset(StandardCharsets.UTF_8)
ctx.write("secure domain " + .body("secure domain " +
" SNI host " + ctx.httpRequest().as(HttpsRequest.class).getSNIHost() + " " + " SNI host " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() + " " +
" SSL peer host " + ctx.httpRequest().as(HttpsRequest.class).getSSLSession() + " " + " SSL peer host " + ctx.getRequest().as(HttpsRequest.class).getSSLSession() + " " +
" base URL = " + ctx.request().getBaseURL() + " " + " base URL = " + ctx.getRequestBuilder().getBaseURL() + " " +
ctx.httpRequest().getParameter() + " " + ctx.getRequest().getParameter() + " " +
ctx.httpRequest().getLocalAddress() + " " + ctx.getRequest().getLocalAddress() + " " +
ctx.httpRequest().getRemoteAddress()); ctx.getRequest().getRemoteAddress());
}) })
.build()) .build())
.build()) .build())

View file

@ -56,24 +56,21 @@ public class NettyHttps2ServerTest {
.setHttpAddress(httpsAddress) .setHttpAddress(httpsAddress)
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/favicon.ico") .setPath("/favicon.ico")
.setHandler(ctx -> ctx.response() .setHandler(ctx -> ctx.status(HttpResponseStatus.NOT_FOUND))
.setResponseStatus(HttpResponseStatus.NOT_FOUND)
.build()
.flush())
.build()) .build())
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/secure") .setPath("/secure")
.setHandler(ctx -> { ctx.response() .setHandler(ctx -> {
.setResponseStatus(HttpResponseStatus.OK) ctx.status(HttpResponseStatus.OK)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setCharset(StandardCharsets.UTF_8); .charset(StandardCharsets.UTF_8)
ctx.write("secure domain " + .body("secure domain " +
" SNI host " + ctx.httpRequest().as(HttpsRequest.class).getSNIHost() + " " + " SNI host " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() + " " +
" SSL peer host " + ctx.httpRequest().as(HttpsRequest.class).getSSLSession() + " " + " SSL peer host " + ctx.getRequest().as(HttpsRequest.class).getSSLSession() + " " +
" base URL = " + ctx.request().getBaseURL() + " " + " base URL = " + ctx.getRequestBuilder().getBaseURL() + " " +
ctx.httpRequest().getParameter() + " " + ctx.getRequest().getParameter() + " " +
ctx.httpRequest().getLocalAddress() + " " + ctx.getRequest().getLocalAddress() + " " +
ctx.httpRequest().getRemoteAddress()); ctx.getRequest().getRemoteAddress());
}) })
.build()) .build())
.build()) .build())

View file

@ -57,27 +57,23 @@ public class NettyHttpsServerMultiRequestLoadTest {
.setHttpAddress(httpsAddress) .setHttpAddress(httpsAddress)
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/favicon.ico") .setPath("/favicon.ico")
.setHandler(ctx -> ctx.response() .setHandler(ctx -> ctx.status(HttpResponseStatus.NOT_FOUND))
.setResponseStatus(HttpResponseStatus.NOT_FOUND)
.build()
.flush())
.build()) .build())
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/secure") .setPath("/secure")
.setHandler(ctx -> { .setHandler(ctx -> {
logger.log(Level.INFO, "executing /secure"); logger.log(Level.INFO, "executing /secure");
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("secure domain: " +
ctx.write("secure domain: " + " SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() +
" SNI host = " + ctx.httpRequest().as(HttpsRequest.class).getSNIHost() + " SSL peer host = " + ctx.getRequest().as(HttpsRequest.class).getSSLSession() +
" SSL peer host = " + ctx.httpRequest().as(HttpsRequest.class).getSSLSession() + " base URL = " + ctx.getRequest().getBaseURL() +
" base URL = " + ctx.httpRequest().getBaseURL() + " parameter = " + ctx.getRequest().getParameter().allToString() +
" parameter = " + ctx.httpRequest().getParameter().allToString() +
" attributes = " + ctx.getAttributes() + " attributes = " + ctx.getAttributes() +
" local address = " + ctx.httpRequest().getLocalAddress() + " local address = " + ctx.getRequest().getLocalAddress() +
" remote address = " + ctx.httpRequest().getRemoteAddress()); " remote address = " + ctx.getRequest().getRemoteAddress());
}) })
.build()) .build())
.build()) .build())
@ -149,26 +145,22 @@ public class NettyHttpsServerMultiRequestLoadTest {
.setHttpAddress(httpsAddress) .setHttpAddress(httpsAddress)
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/favicon.ico") .setPath("/favicon.ico")
.setHandler(ctx -> ctx.response() .setHandler(ctx -> ctx.status(HttpResponseStatus.NOT_FOUND))
.setResponseStatus(HttpResponseStatus.NOT_FOUND)
.build()
.flush())
.build()) .build())
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/secure") .setPath("/secure")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("secure domain: " +
ctx.write("secure domain: " + " SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() +
" SNI host = " + ctx.httpRequest().as(HttpsRequest.class).getSNIHost() + " SSL session = " + ctx.getRequest().as(HttpsRequest.class).getSSLSession() +
" SSL session = " + ctx.httpRequest().as(HttpsRequest.class).getSSLSession() + " base URL = " + ctx.getRequest().getBaseURL() +
" base URL = " + ctx.httpRequest().getBaseURL() + " parameter = " + ctx.getRequest().getParameter().allToString() +
" parameter = " + ctx.httpRequest().getParameter().allToString() +
" attributes = " + ctx.getAttributes() + " attributes = " + ctx.getAttributes() +
" local address = " + ctx.httpRequest().getLocalAddress() + " local address = " + ctx.getRequest().getLocalAddress() +
" remote address = " + ctx.httpRequest().getRemoteAddress()); " remote address = " + ctx.getRequest().getRemoteAddress());
}) })
.build()) .build())
.build()) .build())

View file

@ -61,26 +61,23 @@ public class NettyHttpsServerTest {
.setHttpAddress(httpsAddress) .setHttpAddress(httpsAddress)
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/favicon.ico") .setPath("/favicon.ico")
.setHandler(ctx -> ctx.response() .setHandler(ctx ->
.setResponseStatus(HttpResponseStatus.NOT_FOUND) ctx.status(HttpResponseStatus.NOT_FOUND))
.build()
.flush())
.build()) .build())
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/secure") .setPath("/secure")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("secure domain: " +
ctx.write("secure domain: " + " SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() +
" SNI host = " + ctx.httpRequest().as(HttpsRequest.class).getSNIHost() + " SSL peer host = " + ctx.getRequest().as(HttpsRequest.class).getSSLSession() +
" SSL peer host = " + ctx.httpRequest().as(HttpsRequest.class).getSSLSession() + " base URL = " + ctx.getRequest().getBaseURL() +
" base URL = " + ctx.httpRequest().getBaseURL() + " parameter = " + ctx.getRequest().getParameter().allToString() +
" parameter = " + ctx.httpRequest().getParameter().allToString() +
" attributes = " + ctx.getAttributes() + " attributes = " + ctx.getAttributes() +
" local address = " + ctx.httpRequest().getLocalAddress() + " local address = " + ctx.getRequest().getLocalAddress() +
" remote address = " + ctx.httpRequest().getRemoteAddress()); " remote address = " + ctx.getRequest().getRemoteAddress());
}) })
.build()) .build())
.build()) .build())
@ -143,26 +140,22 @@ public class NettyHttpsServerTest {
.setHttpAddress(httpsAddress) .setHttpAddress(httpsAddress)
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/favicon.ico") .setPath("/favicon.ico")
.setHandler(ctx -> ctx.response() .setHandler(ctx -> ctx.status(HttpResponseStatus.NOT_FOUND))
.setResponseStatus(HttpResponseStatus.NOT_FOUND)
.build()
.flush())
.build()) .build())
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/secure") .setPath("/secure")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("secure domain: " +
ctx.write("secure domain: " + " SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() +
" SNI host = " + ctx.httpRequest().as(HttpsRequest.class).getSNIHost() + " SSL session = " + ctx.getRequest().as(HttpsRequest.class).getSSLSession() +
" SSL session = " + ctx.httpRequest().as(HttpsRequest.class).getSSLSession() + " base URL = " + ctx.getRequest().getBaseURL() +
" base URL = " + ctx.httpRequest().getBaseURL() + " parameter = " + ctx.getRequest().getParameter().allToString() +
" parameter = " + ctx.httpRequest().getParameter().allToString() +
" attributes = " + ctx.getAttributes() + " attributes = " + ctx.getAttributes() +
" local address = " + ctx.httpRequest().getLocalAddress() + " local address = " + ctx.getRequest().getLocalAddress() +
" remote address = " + ctx.httpRequest().getRemoteAddress()); " remote address = " + ctx.getRequest().getRemoteAddress());
}) })
.build()) .build())
.build()) .build())
@ -224,25 +217,21 @@ public class NettyHttpsServerTest {
.setHttpAddress(httpsAddress) .setHttpAddress(httpsAddress)
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/favicon.ico") .setPath("/favicon.ico")
.setHandler(ctx -> ctx.response() .setHandler(ctx -> ctx.status(HttpResponseStatus.NOT_FOUND))
.setResponseStatus(HttpResponseStatus.NOT_FOUND)
.build()
.flush())
.build()) .build())
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/secure") .setPath("/secure")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("secure domain " +
ctx.write("secure domain " + " SNI host " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() + " " +
" SNI host " + ctx.httpRequest().as(HttpsRequest.class).getSNIHost() + " " + " SSL peer host " + ctx.getRequest().as(HttpsRequest.class).getSSLSession() + " " +
" SSL peer host " + ctx.httpRequest().as(HttpsRequest.class).getSSLSession() + " " + " base URL = " + ctx.getRequest().getBaseURL() + " " +
" base URL = " + ctx.httpRequest().getBaseURL() + " " + ctx.getRequest().getParameter() + " " +
ctx.httpRequest().getParameter() + " " + ctx.getRequest().getLocalAddress() + " " +
ctx.httpRequest().getLocalAddress() + " " + ctx.getRequest().getRemoteAddress());
ctx.httpRequest().getRemoteAddress());
}) })
.build()) .build())
.build()) .build())

View file

@ -29,7 +29,7 @@ import org.xbib.net.http.HttpAddress;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpRequestBuilder; import org.xbib.net.http.server.HttpRequestBuilder;
import org.xbib.net.http.server.HttpResponseBuilder; import org.xbib.net.http.server.HttpResponseBuilder;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.HttpServer; import org.xbib.net.http.server.HttpServer;
import org.xbib.net.http.server.domain.HttpDomain; import org.xbib.net.http.server.domain.HttpDomain;
import org.xbib.net.http.server.route.HttpRouter; import org.xbib.net.http.server.route.HttpRouter;
@ -199,8 +199,8 @@ public class NettyHttpServer implements HttpServer {
HttpResponseStatus responseStatus) { HttpResponseStatus responseStatus) {
Callable<?> callable = (Callable<Object>) () -> { Callable<?> callable = (Callable<Object>) () -> {
HttpRouter router = builder.application.getRouter(); HttpRouter router = builder.application.getRouter();
HttpServerContext httpServerContext = builder.application.createContext(null, requestBuilder, responseBuilder); HttpRouterContext httpRouterContext = builder.application.createContext(null, requestBuilder, responseBuilder);
router.routeStatus(responseStatus, httpServerContext); router.routeStatus(responseStatus, httpRouterContext);
return true; return true;
}; };
builder.application.getExecutor().execute(callable); builder.application.getExecutor().execute(callable);

View file

@ -50,16 +50,15 @@ public class NettyHttp2ServerMultiRequestLoadTest {
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/domain") .setPath("/domain")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("domain: " +
ctx.write("domain: " + " base URL = " + ctx.getRequest().getBaseURL() +
" base URL = " + ctx.httpRequest().getBaseURL() + " parameter = " + ctx.getRequest().getParameter().allToString() +
" parameter = " + ctx.httpRequest().getParameter().allToString() +
" attributes = " + ctx.getAttributes() + " attributes = " + ctx.getAttributes() +
" local address = " + ctx.httpRequest().getLocalAddress() + " local address = " + ctx.getRequest().getLocalAddress() +
" remote address = " + ctx.httpRequest().getRemoteAddress()); " remote address = " + ctx.getRequest().getRemoteAddress());
}) })
.build()) .build())
.build()) .build())

View file

@ -48,15 +48,14 @@ public class NettyHttp2ServerTest {
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/domain") .setPath("/domain")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("Hello, here is my response: " +
ctx.write("Hello, here is my response: " + ctx.getRequest().getParameter() + " " +
ctx.httpRequest().getParameter() + " " + ctx.getRequest().getLocalAddress() + " " +
ctx.httpRequest().getLocalAddress() + " " + ctx.getRequest().getRemoteAddress())
ctx.httpRequest().getRemoteAddress()); .done();
ctx.done();
}) })
.build()) .build())
.build()) .build())

View file

@ -46,17 +46,16 @@ public class NettyHttpServerBodyTest {
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/domain") .setPath("/domain")
.setHandler(ctx -> { .setHandler(ctx -> {
String body = ctx.request().getBodyAsChars(StandardCharsets.UTF_8).toString(); String body = ctx.getRequestBuilder().getBodyAsChars(StandardCharsets.UTF_8).toString();
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("parameter = " + ctx.getRequest().getParameter().allToString() +
ctx.write("parameter = " + ctx.httpRequest().getParameter().allToString() + " local address = " + ctx.getRequest().getLocalAddress() +
" local address = " + ctx.httpRequest().getLocalAddress() + " remote address = " + ctx.getRequest().getRemoteAddress() +
" remote address = " + ctx.httpRequest().getRemoteAddress() +
" attributes = " + ctx.getAttributes() + " attributes = " + ctx.getAttributes() +
" body = " + body); " body = " + body)
ctx.done(); .done();
}) })
.build()) .build())
.build()) .build())

View file

@ -56,21 +56,19 @@ class NettyHttpServerByteOrderMarkTest {
.setMethod(HttpMethod.POST) .setMethod(HttpMethod.POST)
.setHandler(ctx -> { .setHandler(ctx -> {
logger.log(Level.FINEST, "handler starting"); logger.log(Level.FINEST, "handler starting");
String content = ctx.request().getBodyAsChars(StandardCharsets.UTF_8).toString(); String content = ctx.getRequestBuilder().getBodyAsChars(StandardCharsets.UTF_8).toString();
logger.log(Level.FINEST, "got content = " + content); logger.log(Level.FINEST, "got content = " + content);
logger.log(Level.FINEST, "got FORM params op = " + ctx.httpRequest().getParameter().getAll("op", Parameter.Domain.FORM)); logger.log(Level.FINEST, "got FORM params op = " + ctx.getRequest().getParameter().getAll("op", Parameter.Domain.FORM));
logger.log(Level.FINEST, "got FORM params key = " + ctx.httpRequest().getParameter().getAll("key", Parameter.Domain.FORM)); logger.log(Level.FINEST, "got FORM params key = " + ctx.getRequest().getParameter().getAll("key", Parameter.Domain.FORM));
logger.log(Level.FINEST, "got FORM params query = " + ctx.httpRequest().getParameter().getAll("query", Parameter.Domain.FORM)); logger.log(Level.FINEST, "got FORM params query = " + ctx.getRequest().getParameter().getAll("query", Parameter.Domain.FORM));
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("parameter = " + ctx.getRequest().getParameter().allToString() +
ctx.write("parameter = " + ctx.httpRequest().getParameter().allToString() + " local address = " + ctx.getRequest().getLocalAddress() +
" local address = " + ctx.httpRequest().getLocalAddress() + " remote address = " + ctx.getRequest().getRemoteAddress() +
" remote address = " + ctx.httpRequest().getRemoteAddress() +
" attributes = " + ctx.getAttributes() + " attributes = " + ctx.getAttributes() +
" content = " + content " content = " + content);
);
}) })
.build()) .build())
.build()) .build())

View file

@ -52,16 +52,14 @@ public class NettyHttpServerFailureTest {
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/domain") .setPath("/domain")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("domain" +
ctx.write("domain" + " parameter = " + ctx.getRequest().getParameter().allToString() +
" parameter = " + ctx.httpRequest().getParameter().allToString() + " local address = " + ctx.getRequest().getLocalAddress() +
" local address = " + ctx.httpRequest().getLocalAddress() + " remote address = " + ctx.getRequest().getRemoteAddress() +
" remote address = " + ctx.httpRequest().getRemoteAddress() + " attributes = " + ctx.getAttributes());
" attributes = " + ctx.getAttributes()
);
}) })
.build()) .build())
.build()) .build())

View file

@ -59,20 +59,18 @@ public class NettyHttpServerFileUploadTest {
.setMethod(HttpMethod.POST) .setMethod(HttpMethod.POST)
.setHandler(ctx -> { .setHandler(ctx -> {
logger.log(Level.FINEST, "handler starting"); logger.log(Level.FINEST, "handler starting");
String message = ctx.httpRequest().getMessages().stream() String message = ctx.getRequest().getMessages().stream()
.map(m -> StandardCharsets.UTF_8.decode(m.getByteBuffer())) .map(m -> StandardCharsets.UTF_8.decode(m.getByteBuffer()))
.collect(Collectors.joining()); .collect(Collectors.joining());
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("parameter = " + ctx.getRequest().getParameter().allToString() +
ctx.write("parameter = " + ctx.httpRequest().getParameter().allToString() + " local address = " + ctx.getRequest().getLocalAddress() +
" local address = " + ctx.httpRequest().getLocalAddress() + " remote address = " + ctx.getRequest().getRemoteAddress() +
" remote address = " + ctx.httpRequest().getRemoteAddress() +
" attributes = " + ctx.getAttributes() + " attributes = " + ctx.getAttributes() +
" message = " + message " message = " + message);
);
}) })
.build()) .build())
.build()) .build())
@ -139,7 +137,7 @@ public class NettyHttpServerFileUploadTest {
.setPath("/") .setPath("/")
.setMethod(HttpMethod.POST) .setMethod(HttpMethod.POST)
.setHandler(ctx -> { .setHandler(ctx -> {
List<org.xbib.net.http.server.Message> messages = ctx.httpRequest().getMessages(); List<org.xbib.net.http.server.Message> messages = ctx.getRequest().getMessages();
for (org.xbib.net.http.server.Message message : messages) { for (org.xbib.net.http.server.Message message : messages) {
if (message.getPath() != null) { if (message.getPath() != null) {
try (InputStream inputStream = Files.newInputStream(message.getPath()); try (InputStream inputStream = Files.newInputStream(message.getPath());
@ -148,16 +146,14 @@ public class NettyHttpServerFileUploadTest {
} }
} }
} }
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("parameter = " + ctx.getRequest().getParameter().allToString() +
ctx.write("parameter = " + ctx.httpRequest().getParameter().allToString() + " local address = " + ctx.getRequest().getLocalAddress() +
" local address = " + ctx.httpRequest().getLocalAddress() + " remote address = " + ctx.getRequest().getRemoteAddress() +
" remote address = " + ctx.httpRequest().getRemoteAddress() +
" attributes = " + ctx.getAttributes() + " attributes = " + ctx.getAttributes() +
" parts = " + messages.size() " parts = " + messages.size());
);
}) })
.build()) .build())
.build()) .build())

View file

@ -50,17 +50,16 @@ public class NettyHttpServerMultiRequestLoadTest {
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/domain") .setPath("/domain")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("domain: " +
ctx.write("domain: " + " base URL = " + ctx.getRequest().getBaseURL() +
" base URL = " + ctx.httpRequest().getBaseURL() + " parameter = " + ctx.getRequest().getParameter().allToString() +
" parameter = " + ctx.httpRequest().getParameter().allToString() +
" attributes = " + ctx.getAttributes() + " attributes = " + ctx.getAttributes() +
" local address = " + ctx.httpRequest().getLocalAddress() + " local address = " + ctx.getRequest().getLocalAddress() +
" remote address = " + ctx.httpRequest().getRemoteAddress()); " remote address = " + ctx.getRequest().getRemoteAddress())
ctx.done(); .done();
}) })
.build()) .build())
.build()) .build())

View file

@ -47,16 +47,15 @@ public class NettyHttpServerTest {
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/domain") .setPath("/domain")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("domain" +
ctx.write("domain" + " parameter = " + ctx.getRequest().getParameter().allToString() +
" parameter = " + ctx.httpRequest().getParameter().allToString() + " local address = " + ctx.getRequest().getLocalAddress() +
" local address = " + ctx.httpRequest().getLocalAddress() + " remote address = " + ctx.getRequest().getRemoteAddress() +
" remote address = " + ctx.httpRequest().getRemoteAddress() + " attributes = " + ctx.getAttributes())
" attributes = " + ctx.getAttributes()); .done();
ctx.done();
}) })
.build()) .build())
.build()) .build())

View file

@ -8,7 +8,7 @@ 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;
import org.xbib.net.http.HttpVersion; import org.xbib.net.http.HttpVersion;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.HttpServer; import org.xbib.net.http.server.HttpServer;
import java.io.IOException; import java.io.IOException;
@ -147,10 +147,10 @@ public class NioHttpServer implements HttpServer {
public void dispatch(org.xbib.net.http.server.HttpRequestBuilder requestBuilder, public void dispatch(org.xbib.net.http.server.HttpRequestBuilder requestBuilder,
org.xbib.net.http.server.HttpResponseBuilder responseBuilder, org.xbib.net.http.server.HttpResponseBuilder responseBuilder,
HttpResponseStatus responseStatus) { HttpResponseStatus responseStatus) {
HttpServerContext httpServerContext = builder.application.createContext(null, requestBuilder, responseBuilder); HttpRouterContext httpRouterContext = builder.application.createContext(null, requestBuilder, responseBuilder);
Callable<?> callable = (Callable<Object>) () -> { Callable<?> callable = (Callable<Object>) () -> {
HttpRouter router = builder.application.getRouter(); HttpRouter router = builder.application.getRouter();
router.routeStatus(responseStatus, httpServerContext); router.routeStatus(responseStatus, httpRouterContext);
return true; return true;
}; };
builder.application.getExecutor().execute(callable); builder.application.getExecutor().execute(callable);

View file

@ -34,14 +34,13 @@ public class NioHttpServerTest {
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/domain1") .setPath("/domain1")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("domain1 " +
ctx.write("domain1 " + ctx.getRequest().getParameter().toString() + " " +
ctx.httpRequest().getParameter().toString() + " " + ctx.getRequest().getLocalAddress() + " " +
ctx.httpRequest().getLocalAddress() + " " + ctx.getRequest().getRemoteAddress());
ctx.httpRequest().getRemoteAddress());
}) })
.build()) .build())
.build()) .build())
@ -50,14 +49,13 @@ public class NioHttpServerTest {
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/domain2") .setPath("/domain2")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("domain2 " +
ctx.write("domain2 " + ctx.getRequest().getParameter().toString() + " " +
ctx.httpRequest().getParameter().toString() + " " + ctx.getRequest().getLocalAddress() + " " +
ctx.httpRequest().getLocalAddress() + " " + ctx.getRequest().getRemoteAddress());
ctx.httpRequest().getRemoteAddress());
}) })
.build()) .build())
.build()) .build())

View file

@ -42,25 +42,21 @@ public class SimpleHttpsServerTest {
.setHttpAddress(httpsAddress) .setHttpAddress(httpsAddress)
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/favicon.ico") .setPath("/favicon.ico")
.setHandler(ctx -> ctx.response() .setHandler(ctx -> ctx.status(HttpResponseStatus.NOT_FOUND))
.setResponseStatus(HttpResponseStatus.NOT_FOUND)
.build()
.flush())
.build()) .build())
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/secure") .setPath("/secure")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("secure domain: " +
ctx.write("secure domain: " + " SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() +
" SNI host = " + ctx.httpRequest().as(HttpsRequest.class).getSNIHost() + " SSL peer host = " + ctx.getRequest().as(HttpsRequest.class).getSSLSession() +
" SSL peer host = " + ctx.httpRequest().as(HttpsRequest.class).getSSLSession() + " base URL = " + ctx.getRequest().getBaseURL() +
" base URL = " + ctx.httpRequest().getBaseURL() + " parameter = " + ctx.getRequest().getParameter() +
" parameter = " + ctx.httpRequest().getParameter() + " local address = " + ctx.getRequest().getLocalAddress() +
" local address = " + ctx.httpRequest().getLocalAddress() + " remote address = " + ctx.getRequest().getRemoteAddress());
" remote address = " + ctx.httpRequest().getRemoteAddress());
}) })
.build()) .build())
.build()) .build())

View file

@ -8,7 +8,7 @@ import org.xbib.net.SocketConfig;
import org.xbib.net.http.HttpAddress; import org.xbib.net.http.HttpAddress;
import org.xbib.net.http.HttpHeaderNames; import org.xbib.net.http.HttpHeaderNames;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
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.HttpVersion; import org.xbib.net.http.HttpVersion;
@ -149,10 +149,10 @@ public class SimpleHttpServer implements HttpServer {
public void dispatch(org.xbib.net.http.server.HttpRequestBuilder requestBuilder, public void dispatch(org.xbib.net.http.server.HttpRequestBuilder requestBuilder,
org.xbib.net.http.server.HttpResponseBuilder responseBuilder, org.xbib.net.http.server.HttpResponseBuilder responseBuilder,
HttpResponseStatus responseStatus) { HttpResponseStatus responseStatus) {
HttpServerContext httpServerContext = builder.application.createContext(null, requestBuilder, responseBuilder); HttpRouterContext httpRouterContext = builder.application.createContext(null, requestBuilder, responseBuilder);
Callable<?> callable = (Callable<Object>) () -> { Callable<?> callable = (Callable<Object>) () -> {
HttpRouter router = builder.application.getRouter(); HttpRouter router = builder.application.getRouter();
router.routeStatus(responseStatus, httpServerContext); router.routeStatus(responseStatus, httpRouterContext);
return true; return true;
}; };
builder.application.getExecutor().execute(callable); builder.application.getExecutor().execute(callable);

View file

@ -39,12 +39,11 @@ public class HttpRouterTest {
.setMethod(HttpMethod.DELETE) .setMethod(HttpMethod.DELETE)
.setPath("/demo") .setPath("/demo")
.setHandler(ctx -> { .setHandler(ctx -> {
Logger.getAnonymousLogger().log(Level.INFO, "got request: " + ctx.request().getRequestURI()); Logger.getAnonymousLogger().log(Level.INFO, "got request: " + ctx.getRequestBuilder().getRequestURI());
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body(ctx.getRequestBuilder().getRequestURI());
ctx.write(ctx.request().getRequestURI());
}) })
.build()) .build())
.build()) .build())

View file

@ -34,14 +34,13 @@ public class SimpleHttpServerTest {
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/domain1") .setPath("/domain1")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("domain1 " +
ctx.write("domain1 " + ctx.getRequest().getParameter() + " " +
ctx.httpRequest().getParameter() + " " + ctx.getRequest().getLocalAddress() + " " +
ctx.httpRequest().getLocalAddress() + " " + ctx.getRequest().getRemoteAddress());
ctx.httpRequest().getRemoteAddress());
}) })
.build()) .build())
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
@ -54,14 +53,13 @@ public class SimpleHttpServerTest {
.addService(BaseHttpService.builder() .addService(BaseHttpService.builder()
.setPath("/domain2") .setPath("/domain2")
.setHandler(ctx -> { .setHandler(ctx -> {
ctx.response() ctx.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
.setHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) .charset(StandardCharsets.UTF_8)
.setCharset(StandardCharsets.UTF_8); .body("domain2 " +
ctx.write("domain2 " + ctx.getRequest().getParameter() + " " +
ctx.httpRequest().getParameter() + " " + ctx.getRequest().getLocalAddress() + " " +
ctx.httpRequest().getLocalAddress() + " " + ctx.getRequest().getRemoteAddress());
ctx.httpRequest().getRemoteAddress());
}) })
.build()) .build())
.build()) .build())

View file

@ -9,6 +9,7 @@ import org.xbib.net.http.HttpHeaders;
import org.xbib.net.http.HttpMethod; import org.xbib.net.http.HttpMethod;
import org.xbib.net.http.HttpVersion; import org.xbib.net.http.HttpVersion;
import org.xbib.net.http.server.auth.BaseAttributes; import org.xbib.net.http.server.auth.BaseAttributes;
import org.xbib.net.http.server.route.HttpRouterContext;
public abstract class BaseHttpRequest implements HttpRequest { public abstract class BaseHttpRequest implements HttpRequest {
@ -92,8 +93,8 @@ public abstract class BaseHttpRequest implements HttpRequest {
} }
@Override @Override
public HttpServerContext getContext() { public HttpRouterContext getContext() {
return builder.httpServerContext; return builder.httpRouterContext;
} }
@Override @Override

View file

@ -14,10 +14,11 @@ import org.xbib.net.http.HttpAddress;
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.HttpVersion; import org.xbib.net.http.HttpVersion;
import org.xbib.net.http.server.route.HttpRouterContext;
public abstract class BaseHttpRequestBuilder implements HttpRequestBuilder { public abstract class BaseHttpRequestBuilder implements HttpRequestBuilder {
protected HttpServerContext httpServerContext; protected HttpRouterContext httpRouterContext;
protected HttpAddress httpAddress; protected HttpAddress httpAddress;
@ -59,11 +60,11 @@ public abstract class BaseHttpRequestBuilder implements HttpRequestBuilder {
} }
@Override @Override
public BaseHttpRequestBuilder setContext(HttpServerContext httpServerContext) { public BaseHttpRequestBuilder setContext(HttpRouterContext httpRouterContext) {
if (done) { if (done) {
return this; return this;
} }
this.httpServerContext = httpServerContext; this.httpRouterContext = httpRouterContext;
return this; return this;
} }

View file

@ -1,321 +0,0 @@
package org.xbib.net.http.server;
import java.io.IOException;
import java.io.InputStream;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
import java.nio.file.Path;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xbib.datastructures.json.tiny.Json;
import org.xbib.net.Attributes;
import org.xbib.net.Parameter;
import org.xbib.net.ParameterBuilder;
import org.xbib.net.URL;
import org.xbib.net.buffer.DataBuffer;
import org.xbib.net.http.HttpHeaderNames;
import org.xbib.net.http.HttpHeaderValues;
import org.xbib.net.http.HttpHeaders;
import org.xbib.net.http.HttpMethod;
import org.xbib.net.http.cookie.CookieBox;
import org.xbib.net.http.server.application.Application;
import org.xbib.net.http.server.auth.BaseAttributes;
import org.xbib.net.http.server.domain.HttpDomain;
import org.xbib.net.http.server.route.HttpRouteResolver;
import org.xbib.net.http.server.service.HttpService;
import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
public class BaseHttpServerContext implements HttpServerContext {
private static final Logger logger = Logger.getLogger(BaseHttpServerContext.class.getName());
private static final String PATH_SEPARATOR = "/";
private final Application application;
private final HttpRequestBuilder httpRequestBuilder;
private final HttpResponseBuilder httpResponseBuilder;
private final Attributes attributes;
private HttpRouteResolver.Result<HttpService> pathResolverResult;
private String contextPath;
private URL contextURL;
private HttpRequest httpRequest;
private boolean done;
private boolean failed;
private boolean next;
public BaseHttpServerContext(Application application,
HttpDomain domain,
HttpRequestBuilder httpRequestBuilder,
HttpResponseBuilder httpResponseBuilder) {
this.application = application;
this.httpRequestBuilder = httpRequestBuilder;
this.httpResponseBuilder = httpResponseBuilder;
this.attributes = new BaseAttributes();
this.attributes.put("application", application);
this.attributes.put("domain", domain);
this.attributes.put("requestbuilder", httpRequestBuilder);
this.attributes.put("responsebuilder", httpResponseBuilder);
this.attributes.put("ctx", this);
}
@Override
public Application getApplication() {
return application;
}
@Override
public HttpRequestBuilder request() {
return httpRequestBuilder;
}
@Override
public HttpResponseBuilder response() {
return httpResponseBuilder;
}
@Override
public HttpRequest httpRequest() {
return httpRequest;
}
@Override
public void setResolverResult(HttpRouteResolver.Result<HttpService> pathResolverResult) {
this.pathResolverResult = pathResolverResult;
if (pathResolverResult != null) {
attributes.put("context", pathResolverResult.getContext());
attributes.put("handler", pathResolverResult.getValue());
attributes.put("pathparams", pathResolverResult.getParameter());
String contextPath = pathResolverResult.getContext() != null ?
PATH_SEPARATOR + String.join(PATH_SEPARATOR, pathResolverResult.getContext()) : null;
setContextPath(contextPath);
setContextURL(request().getBaseURL().resolve(contextPath != null ? contextPath + "/" : ""));
} else {
// path resolver result null means "404 not found". Set default values.
attributes.put("context", null);
attributes.put("handler", null);
attributes.put("pathparams", null);
setContextPath(PATH_SEPARATOR);
setContextURL(request().getBaseURL());
}
httpRequest = createRequest();
attributes.put("request", httpRequest);
next = false;
}
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
@Override
public String getContextPath() {
return contextPath;
}
public void setContextURL(URL contextURL) {
this.contextURL = contextURL;
}
@Override
public URL getContextURL() {
return contextURL;
}
@Override
public Path resolve(String path) {
return application.resolve(path);
}
@Override
public Attributes getAttributes() {
return attributes;
}
@Override
public void done() {
this.done = true;
this.httpRequestBuilder.done();
this.httpResponseBuilder.done();
}
@Override
public boolean isDone() {
return done;
}
@Override
public boolean isFailed() {
return failed;
}
@Override
public void fail() {
this.failed = true;
}
public void next() {
this.next = true;
}
public boolean isNext() {
return next;
}
@Override
public void write() throws IOException {
httpResponseBuilder.write("");
}
@Override
public void write(String string) throws IOException {
httpResponseBuilder.write(string);
}
@Override
public void write(CharBuffer charBuffer, Charset charset) throws IOException {
httpResponseBuilder.write(charBuffer, charset);
}
@Override
public void write(DataBuffer dataBuffer) throws IOException {
httpResponseBuilder.write(dataBuffer);
}
@Override
public void write(InputStream inputStream, int bufferSize) throws IOException {
httpResponseBuilder.write(inputStream, bufferSize);
}
@Override
public void write(FileChannel fileChannel, int bufferSize) throws IOException {
httpResponseBuilder.write(fileChannel, bufferSize);
}
protected HttpRequest createRequest() {
HttpHeaders headers = httpRequestBuilder.getHeaders();
String mimeType = headers.get(CONTENT_TYPE);
Charset charset = StandardCharsets.UTF_8;
if (mimeType != null) {
charset = getCharset(mimeType, charset);
}
ParameterBuilder parameterBuilder = Parameter.builder().charset(charset);
// helper URL to collect parameters in request URI
URL url = URL.builder()
.charset(charset, CodingErrorAction.REPLACE)
.path(httpRequestBuilder.getRequestURI())
.build();
ParameterBuilder formParameterBuilder = Parameter.builder().domain(Parameter.Domain.FORM)
.enableDuplicates();
// https://www.w3.org/TR/html4/interact/forms.html#h-17.13.4
if (HttpMethod.POST.equals(httpRequestBuilder.getMethod()) &&
(mimeType != null && mimeType.contains(HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED))) {
Charset htmlCharset = getCharset(mimeType, StandardCharsets.ISO_8859_1);
CharBuffer charBuffer = httpRequestBuilder.getBodyAsChars(htmlCharset);
if (charBuffer != null) {
formParameterBuilder.addPercentEncodedBody(charBuffer.toString());
}
}
String contentType = httpRequestBuilder.getHeaders().get(HttpHeaderNames.CONTENT_TYPE);
if (contentType != null && contentType.contains(HttpHeaderValues.APPLICATION_JSON)) {
String content = httpRequestBuilder.getBodyAsChars(StandardCharsets.UTF_8).toString();
try {
Map<String, Object> map = Json.toMap(content);
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getValue() instanceof Iterable<?> iterable) {
iterable.forEach(it -> formParameterBuilder.add(entry.getKey(), it));
} else {
formParameterBuilder.add(entry.getKey(), entry.getValue());
}
}
} catch (Exception e) {
logger.log(Level.WARNING, "unable to decode json body: " + e.getMessage(), e);
}
}
CookieBox cookieBox = attributes.get(CookieBox.class, "incomingcookies");
ParameterBuilder cookieParameterBuilder = Parameter.builder().domain(Parameter.Domain.COOKIE);
if (cookieBox != null) {
cookieBox.forEach(c -> cookieParameterBuilder.add(c.name(), c.value()));
}
Parameter queryParameter = url.getQueryParams();
logger.log(Level.FINER, "adding query parameters = " + queryParameter.getDomain() + " " + queryParameter.allToString());
parameterBuilder.add(queryParameter);
Parameter formParameter = formParameterBuilder.build();
logger.log(Level.FINER, "adding form parameters = " + formParameter.getDomain() + " " + formParameter.allToString());
parameterBuilder.add(formParameter);
Parameter cookieParameter = cookieParameterBuilder.build();
logger.log(Level.FINER, "adding cookie parameters = " + cookieParameter.getDomain() + " " + cookieParameter.allToString());
parameterBuilder.add(cookieParameter);
if (pathResolverResult != null) {
Parameter pathParameter = pathResolverResult.getParameter();
logger.log(Level.FINER, "adding path parameters = " + pathParameter.getDomain() + " " + pathParameter.allToString());
parameterBuilder.add(pathParameter);
}
httpRequestBuilder.setParameter(parameterBuilder.build());
httpRequestBuilder.setContext(this);
return httpRequestBuilder.build();
}
private static Charset getCharset(String contentTypeValue, Charset defaultCharset) {
if (contentTypeValue != null) {
CharSequence charsetRaw = getCharsetAsSequence(contentTypeValue);
if (charsetRaw != null) {
if (charsetRaw.length() > 2) {
if (charsetRaw.charAt(0) == '"' && charsetRaw.charAt(charsetRaw.length() - 1) == '"') {
charsetRaw = charsetRaw.subSequence(1, charsetRaw.length() - 1);
}
}
try {
return Charset.forName(charsetRaw.toString());
} catch (IllegalCharsetNameException | UnsupportedCharsetException ignored) {
// just return the default charset
}
}
}
return defaultCharset;
}
private static CharSequence getCharsetAsSequence(String contentTypeValue) {
Objects.requireNonNull(contentTypeValue);
int indexOfCharset = contentTypeValue.indexOf("charset=");
if (indexOfCharset == -1) {
return null;
}
int indexOfEncoding = indexOfCharset + "charset=".length();
if (indexOfEncoding < contentTypeValue.length()) {
CharSequence charsetCandidate = contentTypeValue.subSequence(indexOfEncoding, contentTypeValue.length());
int indexOfSemicolon = charsetCandidate.toString().indexOf(";");
if (indexOfSemicolon == -1) {
return charsetCandidate;
}
return charsetCandidate.subSequence(0, indexOfSemicolon);
}
return null;
}
// user session
// request attributes
// locale
// principal
// parsed form data, multipart
}

View file

@ -2,47 +2,49 @@ package org.xbib.net.http.server;
import java.io.IOException; import java.io.IOException;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.route.BaseHttpRouterContext;
import org.xbib.net.http.server.route.HttpRouterContext;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class HttpException extends IOException { public class HttpException extends IOException {
private final HttpServerContext httpServerContext; private final HttpRouterContext httpRouterContext;
private final HttpResponseStatus httpResponseStatus; private final HttpResponseStatus httpResponseStatus;
public HttpException(HttpResponseBuilder httpResponseBuilder, public HttpException(HttpResponseBuilder httpResponseBuilder,
HttpResponseStatus httpResponseStatus) { HttpResponseStatus httpResponseStatus) {
this(httpResponseStatus.codeAsText(), this(httpResponseStatus.codeAsText(),
new BaseHttpServerContext(null, null, null, httpResponseBuilder), new BaseHttpRouterContext(null, null, null, httpResponseBuilder),
httpResponseStatus); httpResponseStatus);
} }
public HttpException(String message, public HttpException(String message,
HttpServerContext httpServerContext, HttpRouterContext httpRouterContext,
HttpResponseStatus httpResponseStatus) { HttpResponseStatus httpResponseStatus) {
super(message); super(message);
this.httpServerContext = httpServerContext; this.httpRouterContext = httpRouterContext;
this.httpResponseStatus = httpResponseStatus; this.httpResponseStatus = httpResponseStatus;
} }
public HttpException(String message, Throwable throwable, public HttpException(String message, Throwable throwable,
HttpServerContext httpServerContext, HttpRouterContext httpRouterContext,
HttpResponseStatus httpResponseStatus) { HttpResponseStatus httpResponseStatus) {
super(message, throwable); super(message, throwable);
this.httpServerContext = httpServerContext; this.httpRouterContext = httpRouterContext;
this.httpResponseStatus = httpResponseStatus; this.httpResponseStatus = httpResponseStatus;
} }
public HttpException(Throwable throwable, public HttpException(Throwable throwable,
HttpServerContext httpServerContext, HttpRouterContext httpRouterContext,
HttpResponseStatus httpResponseStatus) { HttpResponseStatus httpResponseStatus) {
super(throwable); super(throwable);
this.httpServerContext = httpServerContext; this.httpRouterContext = httpRouterContext;
this.httpResponseStatus = httpResponseStatus; this.httpResponseStatus = httpResponseStatus;
} }
public HttpServerContext getHttpServerContext() { public HttpRouterContext getHttpServerContext() {
return httpServerContext; return httpRouterContext;
} }
public HttpResponseStatus getResponseStatus() { public HttpResponseStatus getResponseStatus() {

View file

@ -1,9 +1,11 @@
package org.xbib.net.http.server; package org.xbib.net.http.server;
import org.xbib.net.http.server.route.HttpRouterContext;
import java.io.IOException; import java.io.IOException;
@FunctionalInterface @FunctionalInterface
public interface HttpHandler { public interface HttpHandler {
void handle(HttpServerContext httpServerContext) throws IOException; void handle(HttpRouterContext httpRouterContext) throws IOException;
} }

View file

@ -10,12 +10,13 @@ import org.xbib.net.URL;
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.HttpVersion; import org.xbib.net.http.HttpVersion;
import org.xbib.net.http.server.route.HttpRouterContext;
public interface HttpRequest extends Request { public interface HttpRequest extends Request {
URL getServerURL(); URL getServerURL();
HttpServerContext getContext(); HttpRouterContext getContext();
String getRequestURI(); String getRequestURI();

View file

@ -8,6 +8,7 @@ import org.xbib.net.http.HttpAddress;
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.HttpVersion; import org.xbib.net.http.HttpVersion;
import org.xbib.net.http.server.route.HttpRouterContext;
public interface HttpRequestBuilder { public interface HttpRequestBuilder {
@ -21,7 +22,7 @@ public interface HttpRequestBuilder {
HttpRequestBuilder setParameter(Parameter parameter); HttpRequestBuilder setParameter(Parameter parameter);
HttpRequestBuilder setContext(HttpServerContext context); HttpRequestBuilder setContext(HttpRouterContext context);
HttpRequestBuilder setVersion(HttpVersion version); HttpRequestBuilder setVersion(HttpVersion version);

View file

@ -1,59 +0,0 @@
package org.xbib.net.http.server;
import java.io.IOException;
import java.io.InputStream;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import org.xbib.net.Attributes;
import org.xbib.net.URL;
import org.xbib.net.buffer.DataBuffer;
import org.xbib.net.http.server.application.Application;
import org.xbib.net.http.server.route.HttpRouteResolver;
import org.xbib.net.http.server.service.HttpService;
public interface HttpServerContext {
Application getApplication();
HttpRequestBuilder request();
HttpResponseBuilder response();
void setResolverResult(HttpRouteResolver.Result<HttpService> result);
Attributes getAttributes();
void done();
boolean isDone();
void fail();
boolean isFailed();
void next();
boolean isNext();
HttpRequest httpRequest();
String getContextPath();
URL getContextURL();
Path resolve(String path);
void write() throws IOException;
void write(String string) throws IOException;
void write(CharBuffer charBuffer, Charset charset) throws IOException;
void write(DataBuffer dataBuffer) throws IOException;
void write(InputStream inputStream, int bufferSize) throws IOException;
void write(FileChannel fileChannel, int bufferSize) throws IOException;
}

View file

@ -1,11 +1,12 @@
package org.xbib.net.http.server; package org.xbib.net.http.server;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.route.HttpRouterContext;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class MissingHostHeaderException extends HttpException { public class MissingHostHeaderException extends HttpException {
public MissingHostHeaderException(String message, HttpServerContext httpServerContext) { public MissingHostHeaderException(String message, HttpRouterContext httpRouterContext) {
super(message, httpServerContext, HttpResponseStatus.BAD_REQUEST); super(message, httpRouterContext, HttpResponseStatus.BAD_REQUEST);
} }
} }

View file

@ -1,11 +1,12 @@
package org.xbib.net.http.server; package org.xbib.net.http.server;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.route.HttpRouterContext;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class UnknownExpectException extends HttpException { public class UnknownExpectException extends HttpException {
public UnknownExpectException(String message, HttpServerContext httpServerContext) { public UnknownExpectException(String message, HttpRouterContext httpRouterContext) {
super(message, httpServerContext, HttpResponseStatus.EXPECTATION_FAILED); super(message, httpRouterContext, HttpResponseStatus.EXPECTATION_FAILED);
} }
} }

View file

@ -10,7 +10,7 @@ import java.util.Set;
import org.xbib.net.http.HttpAddress; import org.xbib.net.http.HttpAddress;
import org.xbib.net.http.server.HttpRequestBuilder; import org.xbib.net.http.server.HttpRequestBuilder;
import org.xbib.net.http.server.HttpResponseBuilder; import org.xbib.net.http.server.HttpResponseBuilder;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.domain.HttpDomain; import org.xbib.net.http.server.domain.HttpDomain;
import org.xbib.net.http.server.executor.Executor; import org.xbib.net.http.server.executor.Executor;
import org.xbib.net.http.server.route.HttpRouter; import org.xbib.net.http.server.route.HttpRouter;
@ -40,13 +40,15 @@ public interface Application extends SessionListener, Resolver<Path>, Closeable
Collection<ApplicationModule> getModules(); Collection<ApplicationModule> getModules();
HttpServerContext createContext(HttpDomain domain, HttpRouterContext createContext(HttpDomain domain,
HttpRequestBuilder httpRequestBuilder, HttpRequestBuilder httpRequestBuilder,
HttpResponseBuilder httpResponseBuilder); HttpResponseBuilder httpResponseBuilder);
void onOpen(HttpServerContext httpServerContext); void onOpen(HttpRouterContext httpRouterContext);
void onClose(HttpServerContext httpServerContext); void onClose(HttpRouterContext httpRouterContext);
void releaseContext(HttpRouterContext httpRouterContext);
Executor getExecutor(); Executor getExecutor();

View file

@ -1,7 +1,7 @@
package org.xbib.net.http.server.application; package org.xbib.net.http.server.application;
import org.xbib.net.http.server.HttpRequest; import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.service.HttpService; import org.xbib.net.http.server.service.HttpService;
import org.xbib.net.http.server.session.Session; import org.xbib.net.http.server.session.Session;
@ -9,11 +9,11 @@ public interface ApplicationModule {
String getName(); String getName();
void onOpen(HttpServerContext httpServerContext); void onOpen(HttpRouterContext httpRouterContext);
void onOpen(HttpServerContext httpServerContext, HttpService httpService, HttpRequest httpRequest); void onOpen(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest);
void onClose(HttpServerContext httpServerContext); void onClose(HttpRouterContext httpRouterContext);
void onOpen(Session session); void onOpen(Session session);

View file

@ -16,12 +16,11 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.xbib.net.http.HttpAddress; import org.xbib.net.http.HttpAddress;
import org.xbib.net.http.cookie.SameSite; import org.xbib.net.http.cookie.SameSite;
import org.xbib.net.http.server.BaseHttpServerContext; import org.xbib.net.http.server.route.BaseHttpRouterContext;
import org.xbib.net.http.server.HttpException;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpRequestBuilder; import org.xbib.net.http.server.HttpRequestBuilder;
import org.xbib.net.http.server.HttpResponseBuilder; import org.xbib.net.http.server.HttpResponseBuilder;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.cookie.IncomingCookieHandler; import org.xbib.net.http.server.cookie.IncomingCookieHandler;
import org.xbib.net.http.server.cookie.OutgoingCookieHandler; import org.xbib.net.http.server.cookie.OutgoingCookieHandler;
import org.xbib.net.http.server.domain.HttpDomain; import org.xbib.net.http.server.domain.HttpDomain;
@ -44,30 +43,15 @@ public class BaseApplication implements Application {
protected BaseApplicationBuilder builder; protected BaseApplicationBuilder builder;
private final HttpRequestValidator httpRequestValidator;
protected final String sessionName; protected final String sessionName;
private final HttpHandler incomingCookieHandler;
private final HttpHandler outgoingCookieHandler;
private final HttpResponseRenderer httpResponseRenderer; private final HttpResponseRenderer httpResponseRenderer;
private Codec<Session> sessionCodec;
private HttpHandler incomingSessionHandler;
private HttpHandler outgoingSessionHandler;
protected List<ApplicationModule> applicationModuleList; protected List<ApplicationModule> applicationModuleList;
protected BaseApplication(BaseApplicationBuilder builder) { protected BaseApplication(BaseApplicationBuilder builder) {
this.builder = builder; this.builder = builder;
this.sessionName = getSettings().get("session.name", "SESS"); this.sessionName = getSettings().get("session.name", "SESS");
this.httpRequestValidator = newRequestValidator();
this.incomingCookieHandler = newIncomingCookieHandler();
this.outgoingCookieHandler = newOutgoingCookieHandler();
this.httpResponseRenderer = newResponseRenderer(); this.httpResponseRenderer = newResponseRenderer();
this.applicationModuleList = new ArrayList<>(); this.applicationModuleList = new ArrayList<>();
for (Map.Entry<String, Settings> entry : builder.settings.getGroups("module").entrySet()) { for (Map.Entry<String, Settings> entry : builder.settings.getGroups("module").entrySet()) {
@ -155,19 +139,29 @@ public class BaseApplication implements Application {
} }
@Override @Override
public HttpServerContext createContext(HttpDomain domain, public HttpRouterContext createContext(HttpDomain domain,
HttpRequestBuilder requestBuilder, HttpRequestBuilder requestBuilder,
HttpResponseBuilder responseBuilder) { HttpResponseBuilder responseBuilder) {
HttpServerContext httpServerContext = new BaseHttpServerContext(this, domain, requestBuilder, responseBuilder); HttpRouterContext httpRouterContext = new BaseHttpRouterContext(this, domain, requestBuilder, responseBuilder);
httpServerContext.getAttributes().put("requestbuilder", requestBuilder); httpRouterContext.addOpenHandler(newRequestValidator());
httpServerContext.getAttributes().put("responsebuilder", responseBuilder); httpRouterContext.addOpenHandler(newIncomingCookieHandler());
this.sessionCodec = newSessionCodec(httpServerContext); if (builder.sessionsEnabled) {
if (sessionCodec != null) { Codec<Session> sessionCodec = newSessionCodec(httpRouterContext);
httpServerContext.getAttributes().put("sessioncodec", sessionCodec); httpRouterContext.getAttributes().put("sessioncodec", sessionCodec);
httpRouterContext.addOpenHandler(newIncomingSessionHandler(sessionCodec));
httpRouterContext.addCloseHandler(newOutgoingSessionHandler(sessionCodec));
}
httpRouterContext.addCloseHandler(newOutgoingCookieHandler());
return httpRouterContext;
}
@Override
public void releaseContext(HttpRouterContext httpRouterContext) {
try {
httpRouterContext.close();
} catch (IOException e) {
throw new RuntimeException(e);
} }
this.incomingSessionHandler = newIncomingSessionHandler(httpServerContext);
this.outgoingSessionHandler = newOutgoingSessionHandler(httpServerContext);
return httpServerContext;
} }
protected HttpRequestValidator newRequestValidator() { protected HttpRequestValidator newRequestValidator() {
@ -186,13 +180,11 @@ public class BaseApplication implements Application {
return new HttpResponseRenderer(); return new HttpResponseRenderer();
} }
protected Codec<Session> newSessionCodec(HttpServerContext httpServerContext) { protected Codec<Session> newSessionCodec(HttpRouterContext httpRouterContext) {
return new MemoryPropertiesSessionCodec(sessionName,this, 1024, Duration.ofDays(1)); return new MemoryPropertiesSessionCodec(sessionName,this, 1024, Duration.ofDays(1));
} }
protected HttpHandler newIncomingSessionHandler(HttpServerContext httpServerContext) { protected HttpHandler newIncomingSessionHandler(Codec<Session> sessionCodec) {
@SuppressWarnings("unchecked")
Codec<Session> sessionCodec = httpServerContext.getAttributes().get(Codec.class, "sessioncodec");
return new IncomingSessionHandler( return new IncomingSessionHandler(
getSecret(), getSecret(),
"HmacSHA1", "HmacSHA1",
@ -204,9 +196,7 @@ public class BaseApplication implements Application {
() -> RandomUtil.randomString(16)); () -> RandomUtil.randomString(16));
} }
protected HttpHandler newOutgoingSessionHandler(HttpServerContext httpServerContext) { protected HttpHandler newOutgoingSessionHandler(Codec<Session> sessionCodec) {
@SuppressWarnings("unchecked")
Codec<Session> sessionCodec = httpServerContext.getAttributes().get(Codec.class, "sessioncodec");
return new OutgoingSessionHandler( return new OutgoingSessionHandler(
getSecret(), getSecret(),
"HmacSHA1", "HmacSHA1",
@ -235,47 +225,27 @@ public class BaseApplication implements Application {
} }
@Override @Override
public void onOpen(HttpServerContext httpServerContext) { public void onOpen(HttpRouterContext httpRouterContext) {
try { try {
if (httpRequestValidator != null) {
httpRequestValidator.handle(httpServerContext);
}
if (incomingCookieHandler != null) {
incomingCookieHandler.handle(httpServerContext);
}
if (builder.sessionsEnabled && incomingSessionHandler != null) {
incomingSessionHandler.handle(httpServerContext);
}
// call modules after request/cookie/session setup // call modules after request/cookie/session setup
applicationModuleList.forEach(module -> module.onOpen(httpServerContext)); applicationModuleList.forEach(module -> module.onOpen(httpRouterContext));
} catch (HttpException e) {
builder.httpRouter.routeException(e);
httpServerContext.fail();
} catch (Throwable t) { } catch (Throwable t) {
builder.httpRouter.routeToErrorHandler(httpServerContext, t); builder.httpRouter.routeToErrorHandler(httpRouterContext, t);
httpServerContext.fail(); httpRouterContext.fail();
} }
} }
@Override @Override
public void onClose(HttpServerContext httpServerContext) { public void onClose(HttpRouterContext httpRouterContext) {
try { try {
// call modules before session/cookie // call modules before session/cookie
applicationModuleList.forEach(module -> module.onClose(httpServerContext)); applicationModuleList.forEach(module -> module.onClose(httpRouterContext));
if (builder.sessionsEnabled && outgoingSessionHandler != null) {
outgoingSessionHandler.handle(httpServerContext);
}
if (outgoingCookieHandler != null) {
outgoingCookieHandler.handle(httpServerContext);
}
} catch (HttpException e) {
builder.httpRouter.routeException(e);
} catch (Throwable t) { } catch (Throwable t) {
builder.httpRouter.routeToErrorHandler(httpServerContext, t); builder.httpRouter.routeToErrorHandler(httpRouterContext, t);
} finally { } finally {
try { try {
if (httpResponseRenderer != null) { if (httpResponseRenderer != null) {
httpResponseRenderer.handle(httpServerContext); httpResponseRenderer.handle(httpRouterContext);
} }
} catch (IOException e) { } catch (IOException e) {
logger.log(Level.WARNING, e.getMessage(), e); logger.log(Level.WARNING, e.getMessage(), e);
@ -320,26 +290,6 @@ public class BaseApplication implements Application {
logger.log(Level.FINE, "application closing module " + module); logger.log(Level.FINE, "application closing module " + module);
module.onClose(); module.onClose();
}); });
if (outgoingSessionHandler != null && (outgoingSessionHandler instanceof Closeable)) {
logger.log(Level.FINE, "application closing outgoing session handler");
((Closeable) outgoingSessionHandler).close();
}
if (incomingSessionHandler != null && (incomingSessionHandler instanceof Closeable)) {
logger.log(Level.FINE, "application closing incoming session handler");
((Closeable) incomingSessionHandler).close();
}
if (sessionCodec != null && sessionCodec instanceof Closeable) {
logger.log(Level.FINE, "application closing session codec");
((Closeable) sessionCodec).close();
}
if (outgoingCookieHandler != null && (outgoingCookieHandler instanceof Closeable)) {
logger.log(Level.FINE, "application closing outgoing cookie handler");
((Closeable) outgoingCookieHandler).close();
}
if (incomingCookieHandler != null && (incomingCookieHandler instanceof Closeable)) {
logger.log(Level.FINE, "application closing incoming cookie handler");
((Closeable) incomingCookieHandler).close();
}
logger.log(Level.INFO, "application closed"); logger.log(Level.INFO, "application closed");
} }
} }

View file

@ -1,7 +1,7 @@
package org.xbib.net.http.server.application; package org.xbib.net.http.server.application;
import org.xbib.net.http.server.HttpRequest; import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.service.HttpService; import org.xbib.net.http.server.service.HttpService;
import org.xbib.net.http.server.session.Session; import org.xbib.net.http.server.session.Session;
import org.xbib.settings.Settings; import org.xbib.settings.Settings;
@ -26,15 +26,15 @@ public abstract class BaseApplicationModule implements ApplicationModule {
} }
@Override @Override
public void onOpen(HttpServerContext httpServerContext) { public void onOpen(HttpRouterContext httpRouterContext) {
} }
@Override @Override
public void onOpen(HttpServerContext httpServerContext, HttpService httpService, HttpRequest httpRequest) { public void onOpen(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest) {
} }
@Override @Override
public void onClose(HttpServerContext httpServerContext) { public void onClose(HttpRouterContext httpRouterContext) {
} }
@Override @Override

View file

@ -10,7 +10,7 @@ import org.xbib.net.http.HttpHeaderNames;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpRequest; import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
public class BasicAuthenticationHandler extends LoginAuthenticationHandler implements HttpHandler { public class BasicAuthenticationHandler extends LoginAuthenticationHandler implements HttpHandler {
@ -21,8 +21,8 @@ public class BasicAuthenticationHandler extends LoginAuthenticationHandler imple
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
HttpRequest httpRequest = context.httpRequest(); HttpRequest httpRequest = context.getRequest();
UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile"); UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile");
if (userProfile != null && userProfile.getUserId() != null) { if (userProfile != null && userProfile.getUserId() != null) {
return; return;
@ -49,7 +49,7 @@ public class BasicAuthenticationHandler extends LoginAuthenticationHandler imple
logger.log(Level.WARNING, "no authorization header"); logger.log(Level.WARNING, "no authorization header");
} }
logger.log(Level.INFO, "unauthenticated"); logger.log(Level.INFO, "unauthenticated");
context.response().setResponseStatus(HttpResponseStatus.UNAUTHORIZED) context.status(HttpResponseStatus.UNAUTHORIZED)
.setHeader("WWW-Authenticate", "Basic realm=\"" + securityRealm.getName() + "\""); .header("WWW-Authenticate", "Basic realm=\"" + securityRealm.getName() + "\"");
} }
} }

View file

@ -8,7 +8,7 @@ import org.xbib.net.SecurityRealm;
import org.xbib.net.URL; import org.xbib.net.URL;
import org.xbib.net.UserProfile; import org.xbib.net.UserProfile;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
public class FormAuthenticationHandler extends LoginAuthenticationHandler implements HttpHandler { public class FormAuthenticationHandler extends LoginAuthenticationHandler implements HttpHandler {
@ -35,7 +35,7 @@ public class FormAuthenticationHandler extends LoginAuthenticationHandler implem
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
if (loginPage == null) { if (loginPage == null) {
logger.log(Level.WARNING, "no loginPage configured"); logger.log(Level.WARNING, "no loginPage configured");
return; return;
@ -48,7 +48,7 @@ public class FormAuthenticationHandler extends LoginAuthenticationHandler implem
// always add an "anonymous" user profile // always add an "anonymous" user profile
userProfile = new BaseUserProfile(); userProfile = new BaseUserProfile();
context.getAttributes().put("userprofile", userProfile); context.getAttributes().put("userprofile", userProfile);
Parameter parameter = context.httpRequest().getParameter(); Parameter parameter = context.getRequest().getParameter();
if (!parameter.containsKey(usernameParameter, Parameter.Domain.FORM)) { if (!parameter.containsKey(usernameParameter, Parameter.Domain.FORM)) {
logger.log(Level.WARNING, "usernameParameter not set, unable to authenticate"); logger.log(Level.WARNING, "usernameParameter not set, unable to authenticate");
prepareFormAuthentication(context); prepareFormAuthentication(context);
@ -63,7 +63,7 @@ public class FormAuthenticationHandler extends LoginAuthenticationHandler implem
String password = parameter.getAsString(passwordParameter, Parameter.Domain.FORM); String password = parameter.getAsString(passwordParameter, Parameter.Domain.FORM);
logger.log(Level.FINE, "username and password found, ready for authentication"); logger.log(Level.FINE, "username and password found, ready for authentication");
try { try {
authenticate(userProfile, username, password, context.httpRequest()); authenticate(userProfile, username, password, context.getRequest());
logger.log(Level.FINE, "successful authentication"); logger.log(Level.FINE, "successful authentication");
return; return;
} catch (Exception e) { } catch (Exception e) {
@ -72,13 +72,13 @@ public class FormAuthenticationHandler extends LoginAuthenticationHandler implem
prepareFormAuthentication(context); prepareFormAuthentication(context);
} }
private void prepareFormAuthentication(HttpServerContext context) { private void prepareFormAuthentication(HttpRouterContext context) {
// this will redirect internally to login page, and back to the original path. // this will redirect internally to login page, and back to the original path.
// We need a full path resolve against the server URL. // We need a full path resolve against the server URL.
logger.log(Level.FINE, "templatePath = " + loginPage); logger.log(Level.FINE, "templatePath = " + loginPage);
context.getAttributes().put("templatePath", loginPage); context.getAttributes().put("templatePath", loginPage);
URL loc = context.getContextURL().resolve(context.httpRequest().getRequestURI()).normalize(); URL loc = context.getContextURL().resolve(context.getRequest().getRequestURI()).normalize();
logger.log(Level.FINE, "context URL = " + context.getContextURL() + " request URI = " + context.httpRequest().getRequestURI() + " loc = " + loc); logger.log(Level.FINE, "context URL = " + context.getContextURL() + " request URI = " + context.getRequest().getRequestURI() + " loc = " + loc);
context.getAttributes().put("originalPath", loc.toExternalForm()); context.getAttributes().put("originalPath", loc.toExternalForm());
} }
} }

View file

@ -13,7 +13,7 @@ import org.xbib.net.UserDetails;
import org.xbib.net.UserProfile; import org.xbib.net.UserProfile;
import org.xbib.net.UsersProvider; import org.xbib.net.UsersProvider;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
public class LoginAuthenticationHandler implements HttpHandler { public class LoginAuthenticationHandler implements HttpHandler {
@ -34,7 +34,7 @@ public class LoginAuthenticationHandler implements HttpHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile"); UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile");
if (userProfile != null && userProfile.getUserId() != null) { if (userProfile != null && userProfile.getUserId() != null) {
return; return;
@ -42,9 +42,9 @@ public class LoginAuthenticationHandler implements HttpHandler {
userProfile = new BaseUserProfile(); userProfile = new BaseUserProfile();
try { try {
authenticate(userProfile, authenticate(userProfile,
(String) context.httpRequest().getParameter().get(userParameterName, Parameter.Domain.FORM), (String) context.getRequest().getParameter().get(userParameterName, Parameter.Domain.FORM),
(String) context.httpRequest().getParameter().get(passwordParameterName, Parameter.Domain.FORM), (String) context.getRequest().getParameter().get(passwordParameterName, Parameter.Domain.FORM),
context.httpRequest()); context.getRequest());
context.getAttributes().put("userprofile", userProfile); context.getAttributes().put("userprofile", userProfile);
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "authentication error"); logger.log(Level.SEVERE, "authentication error");

View file

@ -6,7 +6,7 @@ import org.xbib.net.http.HttpHeaderNames;
import org.xbib.net.http.cookie.CookieBox; import org.xbib.net.http.cookie.CookieBox;
import org.xbib.net.http.server.HttpException; import org.xbib.net.http.server.HttpException;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
public class IncomingCookieHandler implements HttpHandler { public class IncomingCookieHandler implements HttpHandler {
@ -16,8 +16,8 @@ public class IncomingCookieHandler implements HttpHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws HttpException { public void handle(HttpRouterContext context) throws HttpException {
Collection<String> cookieStrings = context.request().getHeaders().getAll(HttpHeaderNames.COOKIE); Collection<String> cookieStrings = context.getRequestBuilder().getHeaders().getAll(HttpHeaderNames.COOKIE);
if (cookieStrings.isEmpty()) { if (cookieStrings.isEmpty()) {
return; return;
} }

View file

@ -6,7 +6,7 @@ import org.xbib.net.http.cookie.Cookie;
import org.xbib.net.http.cookie.CookieBox; import org.xbib.net.http.cookie.CookieBox;
import org.xbib.net.http.server.HttpException; import org.xbib.net.http.server.HttpException;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
public class OutgoingCookieHandler implements HttpHandler { public class OutgoingCookieHandler implements HttpHandler {
@ -16,11 +16,11 @@ public class OutgoingCookieHandler implements HttpHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws HttpException { public void handle(HttpRouterContext context) throws HttpException {
CookieBox cookieBox = context.getAttributes().get(CookieBox.class, "outgoingcookies"); CookieBox cookieBox = context.getAttributes().get(CookieBox.class, "outgoingcookies");
if (cookieBox != null) { if (cookieBox != null) {
for (Cookie cookie : cookieBox) { for (Cookie cookie : cookieBox) {
context.response().addCookie(cookie); context.cookie(cookie);
logger.log(Level.FINEST, "cookie prepared for outgoing = " + cookie); logger.log(Level.FINEST, "cookie prepared for outgoing = " + cookie);
} }
} }

View file

@ -6,7 +6,7 @@ import java.util.Objects;
import org.xbib.net.ParameterDefinition; import org.xbib.net.ParameterDefinition;
import org.xbib.net.http.HttpMethod; import org.xbib.net.http.HttpMethod;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.domain.HttpSecurityDomain; import org.xbib.net.http.server.domain.HttpSecurityDomain;
import org.xbib.net.http.server.service.HttpService; import org.xbib.net.http.server.service.HttpService;
@ -24,7 +24,7 @@ public class DecoratingHttpService implements HttpService {
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
handler.handle(context); handler.handle(context);
delegate.handle(context); delegate.handle(context);
} }

View file

@ -3,7 +3,9 @@ package org.xbib.net.http.server.handler;
import java.io.IOException; import java.io.IOException;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpErrorHandler; import org.xbib.net.http.server.HttpErrorHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
public class BadRequestHandler implements HttpErrorHandler { public class BadRequestHandler implements HttpErrorHandler {
@ -11,9 +13,10 @@ public class BadRequestHandler implements HttpErrorHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
context.response() context.status(HttpResponseStatus.BAD_REQUEST)
.setResponseStatus(HttpResponseStatus.BAD_REQUEST) .header(CONTENT_TYPE, "text/plain;charset=utf-8")
.write("Bad request"); .body("Bad request")
.done();
} }
} }

View file

@ -3,7 +3,9 @@ package org.xbib.net.http.server.handler;
import java.io.IOException; import java.io.IOException;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpErrorHandler; import org.xbib.net.http.server.HttpErrorHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
public class ForbiddenHandler implements HttpErrorHandler { public class ForbiddenHandler implements HttpErrorHandler {
@ -11,9 +13,10 @@ public class ForbiddenHandler implements HttpErrorHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
context.response() context.status(HttpResponseStatus.FORBIDDEN)
.setResponseStatus(HttpResponseStatus.FORBIDDEN) .header(CONTENT_TYPE, "text/plain;charset=utf-8")
.write("Forbidden"); .body("Forbidden")
.done();
} }
} }

View file

@ -6,7 +6,9 @@ import java.util.logging.Logger;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpErrorHandler; import org.xbib.net.http.server.HttpErrorHandler;
import org.xbib.net.http.server.HttpException; import org.xbib.net.http.server.HttpException;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
public class InternalServerErrorHandler implements HttpErrorHandler { public class InternalServerErrorHandler implements HttpErrorHandler {
@ -16,23 +18,22 @@ public class InternalServerErrorHandler implements HttpErrorHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
Throwable throwable = context.getAttributes().get(Throwable.class, "_throwable"); Throwable throwable = context.getAttributes().get(Throwable.class, "_throwable");
if (throwable != null) { if (throwable != null) {
logger.log(Level.SEVERE, throwable.getMessage(), throwable); logger.log(Level.SEVERE, throwable.getMessage(), throwable);
} }
HttpResponseStatus status = HttpResponseStatus.INTERNAL_SERVER_ERROR; HttpResponseStatus status = HttpResponseStatus.INTERNAL_SERVER_ERROR;
String message; String message;
if (throwable instanceof HttpException) { if (throwable instanceof HttpException httpException) {
HttpException httpException = (HttpException) throwable;
status = httpException.getResponseStatus(); status = httpException.getResponseStatus();
message = httpException.getMessage(); message = httpException.getMessage();
} else { } else {
message = throwable != null ? throwable.getMessage() : ""; message = throwable != null ? throwable.getMessage() : "";
} }
context.response() context.status(status)
.setResponseStatus(status) .header(CONTENT_TYPE, "text/plain;charset=utf-8")
.setContentType("text/plain;charset=utf-8") .body(message)
.write(message); .done();
} }
} }

View file

@ -3,7 +3,9 @@ package org.xbib.net.http.server.handler;
import java.io.IOException; import java.io.IOException;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpErrorHandler; import org.xbib.net.http.server.HttpErrorHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
public class NotFoundHandler implements HttpErrorHandler { public class NotFoundHandler implements HttpErrorHandler {
@ -11,10 +13,10 @@ public class NotFoundHandler implements HttpErrorHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
context.response() context.status(HttpResponseStatus.NOT_FOUND)
.setResponseStatus(HttpResponseStatus.NOT_FOUND) .header(CONTENT_TYPE, "text/plain;charset=utf-8")
.setContentType("text/plain;charset=utf-8") .body("Not found")
.write("Not found"); .done();
} }
} }

View file

@ -3,7 +3,9 @@ package org.xbib.net.http.server.handler;
import java.io.IOException; import java.io.IOException;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpErrorHandler; import org.xbib.net.http.server.HttpErrorHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
public class NotImplementedHandler implements HttpErrorHandler { public class NotImplementedHandler implements HttpErrorHandler {
@ -11,10 +13,10 @@ public class NotImplementedHandler implements HttpErrorHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
context.response() context.status(HttpResponseStatus.NOT_IMPLEMENTED)
.setResponseStatus(HttpResponseStatus.NOT_IMPLEMENTED) .header(CONTENT_TYPE, "text/plain;charset=utf-8")
.setContentType("text/plain;charset=utf-8") .body("Not implemented")
.write("Not implemented"); .done();
} }
} }

View file

@ -3,7 +3,9 @@ package org.xbib.net.http.server.handler;
import java.io.IOException; import java.io.IOException;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpErrorHandler; import org.xbib.net.http.server.HttpErrorHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
public class UnauthorizedHandler implements HttpErrorHandler { public class UnauthorizedHandler implements HttpErrorHandler {
@ -11,9 +13,10 @@ public class UnauthorizedHandler implements HttpErrorHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
context.response() context.status(HttpResponseStatus.UNAUTHORIZED)
.setResponseStatus(HttpResponseStatus.UNAUTHORIZED) .header(CONTENT_TYPE, "text/plain;charset=utf-8")
.write("Unauthorized"); .body("Unauthorized")
.done();
} }
} }

View file

@ -3,7 +3,9 @@ package org.xbib.net.http.server.handler;
import java.io.IOException; import java.io.IOException;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpErrorHandler; import org.xbib.net.http.server.HttpErrorHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
public class VersionNotSupportedHandler implements HttpErrorHandler { public class VersionNotSupportedHandler implements HttpErrorHandler {
@ -11,10 +13,10 @@ public class VersionNotSupportedHandler implements HttpErrorHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
context.response() context.status(HttpResponseStatus.HTTP_VERSION_NOT_SUPPORTED)
.setResponseStatus(HttpResponseStatus.HTTP_VERSION_NOT_SUPPORTED) .header(CONTENT_TYPE, "text/plain;charset=utf-8")
.setContentType("text/plain;charset=utf-8") .body("HTTP version not supported")
.write("HTTP version not supported"); .done();
} }
} }

View file

@ -11,7 +11,7 @@ import org.xbib.net.http.HttpHeaderNames;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpRequest; import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
public class CombinedFormatLogger implements HttpHandler { public class CombinedFormatLogger implements HttpHandler {
@ -21,14 +21,14 @@ public class CombinedFormatLogger implements HttpHandler {
"%1$s - %10$s - [%2$td/%2$tb/%2$tY:%2$tT %2$tz] \"%3$s %4$s %5$s\" %6$d %7$d \"%8$s\" \"%9$s\""; "%1$s - %10$s - [%2$td/%2$tb/%2$tY:%2$tT %2$tz] \"%3$s %4$s %5$s\" %6$d %7$d \"%8$s\" \"%9$s\"";
@Override @Override
public void handle(HttpServerContext httpServerContext) throws IOException { public void handle(HttpRouterContext httpRouterContext) throws IOException {
HttpRequest request = httpServerContext.httpRequest(); HttpRequest request = httpRouterContext.getRequest();
InetSocketAddress remote = httpServerContext.httpRequest().getRemoteAddress(); InetSocketAddress remote = httpRouterContext.getRequest().getRemoteAddress();
String inetAddressString = remote.getHostName() + ":" + remote.getPort(); String inetAddressString = remote.getHostName() + ":" + remote.getPort();
HttpResponseStatus httpResponseStatus = httpServerContext.response().getResponseStatus(); HttpResponseStatus httpResponseStatus = httpRouterContext.status();
int statusInteger = httpResponseStatus != null ? httpResponseStatus.code() : 0; int statusInteger = httpResponseStatus != null ? httpResponseStatus.code() : 0;
Long contentLength = httpServerContext.response().getLength(); Long contentLength = httpRouterContext.lengthInBytes();
UserProfile userProfile = httpServerContext.getAttributes().get(UserProfile.class, "userprofile"); UserProfile userProfile = httpRouterContext.getAttributes().get(UserProfile.class, "userprofile");
String user = userProfile != null ? userProfile.getEffectiveUserId() : ""; String user = userProfile != null ? userProfile.getEffectiveUserId() : "";
String referer = request.getHeaders().get(HttpHeaderNames.REFERER); String referer = request.getHeaders().get(HttpHeaderNames.REFERER);
referer = referer != null ? referer : ""; referer = referer != null ? referer : "";

View file

@ -10,7 +10,7 @@ import org.xbib.net.UserProfile;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpRequest; import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
public class CommonFormatLogger implements HttpHandler { public class CommonFormatLogger implements HttpHandler {
@ -20,16 +20,17 @@ public class CommonFormatLogger implements HttpHandler {
"%1$s - %10$s - [%2$td/%2$tb/%2$tY:%2$tT %2$tz] \"%3$s %4$s %5$s\" %6$d %7$d"; "%1$s - %10$s - [%2$td/%2$tb/%2$tY:%2$tT %2$tz] \"%3$s %4$s %5$s\" %6$d %7$d";
@Override @Override
public void handle(HttpServerContext httpServerContext) throws IOException { public void handle(HttpRouterContext httpRouterContext) throws IOException {
HttpRequest request = httpServerContext.httpRequest(); HttpRequest request = httpRouterContext.getRequest();
InetSocketAddress remote = httpServerContext.httpRequest().getRemoteAddress(); InetSocketAddress remote = httpRouterContext.getRequest().getRemoteAddress();
String inetAddressString = remote.getHostName() + ":" + remote.getPort(); String inetAddressString = remote.getHostName() + ":" + remote.getPort();
HttpResponseStatus httpResponseStatus = httpServerContext.response().getResponseStatus(); HttpResponseStatus httpResponseStatus = httpRouterContext.status();
int statusInteger = httpResponseStatus != null ? httpResponseStatus.code() : 0; int statusInteger = httpResponseStatus != null ? httpResponseStatus.code() : 0;
Long contentLength = httpServerContext.response().getLength(); Long contentLength = httpRouterContext.lengthInBytes();
UserProfile userProfile = httpServerContext.getAttributes().get(UserProfile.class, "userprofile"); UserProfile userProfile = httpRouterContext.getAttributes().get(UserProfile.class, "userprofile");
String user = userProfile != null ? userProfile.getEffectiveUserId() : ""; String user = userProfile != null ? userProfile.getEffectiveUserId() : "";
String message = String.format(Locale.US, LOG_FORMAT, String message = String.format(Locale.US,
LOG_FORMAT,
inetAddressString, inetAddressString,
ZonedDateTime.now(), ZonedDateTime.now(),
request.getMethod(), request.getMethod(),

View file

@ -2,8 +2,7 @@ package org.xbib.net.http.server.render;
import java.io.IOException; import java.io.IOException;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpResponse; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.HttpServerContext;
public class HttpResponseRenderer implements HttpHandler { public class HttpResponseRenderer implements HttpHandler {
@ -11,9 +10,7 @@ public class HttpResponseRenderer implements HttpHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
// here we do the heavy lifting of rendering all elements for the response context.flush();
HttpResponse httpResponse = context.response().build();
httpResponse.flush();
} }
} }

View file

@ -21,6 +21,7 @@ import java.util.logging.Logger;
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.DataBufferUtil; import org.xbib.net.buffer.DataBufferUtil;
import org.xbib.net.http.HttpHeaderNames; import org.xbib.net.http.HttpHeaderNames;
import org.xbib.net.http.HttpHeaders; import org.xbib.net.http.HttpHeaders;
@ -28,11 +29,12 @@ import org.xbib.net.http.HttpMethod;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpException; import org.xbib.net.http.server.HttpException;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpResponseBuilder; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.HttpServerContext;
import org.xbib.net.mime.MimeTypeService; import org.xbib.net.mime.MimeTypeService;
import org.xbib.net.util.DateTimeUtil; import org.xbib.net.util.DateTimeUtil;
import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
public abstract class AbstractResourceHandler implements HttpHandler { public abstract class AbstractResourceHandler implements HttpHandler {
protected static final MimeTypeService mimeTypeService = new MimeTypeService(); protected static final MimeTypeService mimeTypeService = new MimeTypeService();
@ -42,7 +44,7 @@ public abstract class AbstractResourceHandler implements HttpHandler {
public AbstractResourceHandler() { public AbstractResourceHandler() {
} }
protected abstract Resource createResource(HttpServerContext httpServerContext) throws IOException; protected abstract Resource createResource(HttpRouterContext httpRouterContext) throws IOException;
protected abstract boolean isETagResponseEnabled(); protected abstract boolean isETagResponseEnabled();
@ -53,7 +55,7 @@ public abstract class AbstractResourceHandler implements HttpHandler {
protected abstract int getMaxAgeSeconds(); protected abstract int getMaxAgeSeconds();
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
logger.log(Level.FINEST, () -> "handle: before creating resource " + this.getClass().getName()); logger.log(Level.FINEST, () -> "handle: before creating resource " + this.getClass().getName());
Resource resource = createResource(context); Resource resource = createResource(context);
logger.log(Level.FINEST, () -> "handle: resource = " + (resource != null ? resource.getClass().getName() + " " + resource : null)); logger.log(Level.FINEST, () -> "handle: resource = " + (resource != null ? resource.getClass().getName() + " " + resource : null));
@ -66,7 +68,7 @@ public abstract class AbstractResourceHandler implements HttpHandler {
} else if (resource.isDirectory()) { } else if (resource.isDirectory()) {
logger.log(Level.FINEST, "we have a directory request"); logger.log(Level.FINEST, "we have a directory request");
if (!resource.getResourcePath().isEmpty() && !resource.getResourcePath().endsWith("/")) { if (!resource.getResourcePath().isEmpty() && !resource.getResourcePath().endsWith("/")) {
URL url = context.request().getBaseURL(); URL url = context.getRequestBuilder().getBaseURL();
String loc = url.resolve(resource.getName() + '/') String loc = url.resolve(resource.getName() + '/')
.mutator() .mutator()
.query(url.getQuery()) .query(url.getQuery())
@ -74,19 +76,15 @@ public abstract class AbstractResourceHandler implements HttpHandler {
.build() .build()
.toString(); .toString();
logger.log(Level.FINEST, "client must add a /, external redirect to = " + loc); logger.log(Level.FINEST, "client must add a /, external redirect to = " + loc);
context.response() context.header(HttpHeaderNames.LOCATION, loc)
.addHeader(HttpHeaderNames.LOCATION, loc) .status(HttpResponseStatus.TEMPORARY_REDIRECT);
.setResponseStatus(HttpResponseStatus.TEMPORARY_REDIRECT) // 307
.build();
} else if (resource.isExistsIndexFile()) { } else if (resource.isExistsIndexFile()) {
// internal redirect to default index file in this directory // internal redirect to default index file in this directory
logger.log(Level.FINEST, "internal redirect to default index file in this directory: " + resource.getIndexFileName()); logger.log(Level.FINEST, "internal redirect to default index file in this directory: " + resource.getIndexFileName());
generateCacheableResource(context, resource); generateCacheableResource(context, resource);
} else { } else {
// send forbidden, we do not allow directory access // send forbidden, we do not allow directory access
context.response() context.status(HttpResponseStatus.FORBIDDEN);
.setResponseStatus(HttpResponseStatus.FORBIDDEN)
.build();
} }
context.done(); context.done();
} else { } else {
@ -95,24 +93,21 @@ public abstract class AbstractResourceHandler implements HttpHandler {
} }
} }
private void generateCacheableResource(HttpServerContext context, private void generateCacheableResource(HttpRouterContext context,
Resource resource) throws IOException { Resource resource) throws IOException {
// if resource is length of 0, there is nothing to send. Do not send any content // if resource is length of 0, there is nothing to send. Do not send any content
if (resource.getLength() == 0) { if (resource.getLength() == 0) {
logger.log(Level.FINEST, "the resource length is 0, return not found"); logger.log(Level.FINEST, "the resource length is 0, return not found");
context.response() context.status(HttpResponseStatus.NOT_FOUND);
.setResponseStatus(HttpResponseStatus.NOT_FOUND)
.build();
return; return;
} }
HttpHeaders headers = context.request().getHeaders(); HttpHeaders headers = context.getRequestBuilder().getHeaders();
logger.log(Level.FINEST, () -> "before generating resource, the response headers are " + context.response().getHeaders());
String contentType = resource.getMimeType(); String contentType = resource.getMimeType();
context.response().addHeader(HttpHeaderNames.CONTENT_TYPE, contentType); context.header(CONTENT_TYPE, contentType);
// heuristic for inline disposition // heuristic for inline disposition
String disposition; String disposition;
if (!contentType.startsWith("text") && !contentType.startsWith("image") && !contentType.startsWith("font")) { if (!contentType.startsWith("text") && !contentType.startsWith("image") && !contentType.startsWith("font")) {
String accept = context.request().getHeaders().get(HttpHeaderNames.ACCEPT); String accept = context.getRequestBuilder().getHeaders().get(HttpHeaderNames.ACCEPT);
disposition = accept != null && accepts(accept, contentType) ? "inline" : "attachment"; disposition = accept != null && accepts(accept, contentType) ? "inline" : "attachment";
} else { } else {
disposition = "inline"; disposition = "inline";
@ -120,22 +115,19 @@ public abstract class AbstractResourceHandler implements HttpHandler {
if (resource.getBaseName() != null && resource.getSuffix() != null) { if (resource.getBaseName() != null && resource.getSuffix() != null) {
String contentDisposition = disposition + ";filename=\"" + resource.getBaseName() + '.' + resource.getSuffix() + '"'; String contentDisposition = disposition + ";filename=\"" + resource.getBaseName() + '.' + resource.getSuffix() + '"';
logger.log(Level.FINEST, () -> "content type = " + contentType + " content disposition = " + contentDisposition); logger.log(Level.FINEST, () -> "content type = " + contentType + " content disposition = " + contentDisposition);
context.response() context.header(HttpHeaderNames.CONTENT_DISPOSITION, contentDisposition);
.addHeader(HttpHeaderNames.CONTENT_DISPOSITION, contentDisposition);
} }
long expirationMillis = System.currentTimeMillis() + 1000L * getMaxAgeSeconds(); long expirationMillis = System.currentTimeMillis() + 1000L * getMaxAgeSeconds();
String expires = DateTimeUtil.formatRfc1123(expirationMillis); String expires = DateTimeUtil.formatRfc1123(expirationMillis);
if (isCacheResponseEnabled()) { if (isCacheResponseEnabled()) {
String cacheControl = "public, max-age=" + getMaxAgeSeconds(); String cacheControl = "public, max-age=" + getMaxAgeSeconds();
logger.log(Level.FINEST, () -> "cache response, expires = " + expires + " cache control = " + cacheControl); logger.log(Level.FINEST, () -> "cache response, expires = " + expires + " cache control = " + cacheControl);
context.response() context.header(HttpHeaderNames.EXPIRES, expires)
.addHeader(HttpHeaderNames.EXPIRES, expires) .header(HttpHeaderNames.CACHE_CONTROL, cacheControl);
.addHeader(HttpHeaderNames.CACHE_CONTROL, cacheControl);
} else { } else {
logger.log(Level.FINEST, () -> "uncached response"); logger.log(Level.FINEST, () -> "uncached response");
context.response() context.header(HttpHeaderNames.EXPIRES, "0")
.addHeader(HttpHeaderNames.EXPIRES, "0") .header(HttpHeaderNames.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
.addHeader(HttpHeaderNames.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
} }
boolean sent = false; boolean sent = false;
if (isETagResponseEnabled()) { if (isETagResponseEnabled()) {
@ -146,43 +138,34 @@ public abstract class AbstractResourceHandler implements HttpHandler {
if (ifUnmodifiedSinceInstant != null && if (ifUnmodifiedSinceInstant != null &&
ifUnmodifiedSinceInstant.plusMillis(1000L).isAfter(lastModifiedInstant)) { ifUnmodifiedSinceInstant.plusMillis(1000L).isAfter(lastModifiedInstant)) {
logger.log(Level.FINEST, () -> "precondition failed, lastModified = " + lastModifiedInstant + " ifUnmodifiedSince = " + ifUnmodifiedSinceInstant); logger.log(Level.FINEST, () -> "precondition failed, lastModified = " + lastModifiedInstant + " ifUnmodifiedSince = " + ifUnmodifiedSinceInstant);
context.response() context.status(HttpResponseStatus.PRECONDITION_FAILED);
.setResponseStatus(HttpResponseStatus.PRECONDITION_FAILED)
.build();
return; return;
} }
String ifMatch = headers.get(HttpHeaderNames.IF_MATCH); String ifMatch = headers.get(HttpHeaderNames.IF_MATCH);
if (ifMatch != null && !matches(ifMatch, eTag)) { if (ifMatch != null && !matches(ifMatch, eTag)) {
logger.log(Level.FINEST, () -> "precondition failed, ifMatch = " + ifMatch); logger.log(Level.FINEST, () -> "precondition failed, ifMatch = " + ifMatch);
context.response() context.status(HttpResponseStatus.PRECONDITION_FAILED);
.setResponseStatus(HttpResponseStatus.PRECONDITION_FAILED)
.build();
return; return;
} }
String ifNoneMatch = headers.get(HttpHeaderNames.IF_NONE_MATCH); String ifNoneMatch = headers.get(HttpHeaderNames.IF_NONE_MATCH);
if (ifNoneMatch != null && matches(ifNoneMatch, eTag)) { if (ifNoneMatch != null && matches(ifNoneMatch, eTag)) {
logger.log(Level.FINEST, () -> "not modified, eTag = " + eTag); logger.log(Level.FINEST, () -> "not modified, eTag = " + eTag);
context.response() context.header(HttpHeaderNames.ETAG, eTag)
.addHeader(HttpHeaderNames.ETAG, eTag) .status(HttpResponseStatus.NOT_MODIFIED);
.setResponseStatus(HttpResponseStatus.NOT_MODIFIED)
.build();
return; return;
} }
Instant ifModifiedSinceInstant = DateTimeUtil.parseDate(headers.get(HttpHeaderNames.IF_MODIFIED_SINCE)); Instant ifModifiedSinceInstant = DateTimeUtil.parseDate(headers.get(HttpHeaderNames.IF_MODIFIED_SINCE));
if (ifModifiedSinceInstant != null && if (ifModifiedSinceInstant != null &&
ifModifiedSinceInstant.plusMillis(1000L).isAfter(lastModifiedInstant)) { ifModifiedSinceInstant.plusMillis(1000L).isAfter(lastModifiedInstant)) {
logger.log(Level.FINEST, () -> "not modified (after if-modified-since), eTag = " + eTag); logger.log(Level.FINEST, () -> "not modified (after if-modified-since), eTag = " + eTag);
context.response() context.header(HttpHeaderNames.ETAG, eTag)
.addHeader(HttpHeaderNames.ETAG, eTag) .status(HttpResponseStatus.NOT_MODIFIED);
.setResponseStatus(HttpResponseStatus.NOT_MODIFIED)
.build();
return; return;
} }
String lastModified = DateTimeUtil.formatRfc1123(lastModifiedInstant); String lastModified = DateTimeUtil.formatRfc1123(lastModifiedInstant);
logger.log(Level.FINEST, () -> "sending resource, lastModified = " + lastModified); logger.log(Level.FINEST, () -> "sending resource, lastModified = " + lastModified);
context.response() context.header(HttpHeaderNames.ETAG, eTag)
.addHeader(HttpHeaderNames.ETAG, eTag) .header(HttpHeaderNames.LAST_MODIFIED, lastModified);
.addHeader(HttpHeaderNames.LAST_MODIFIED, lastModified);
if (isRangeResponseEnabled()) { if (isRangeResponseEnabled()) {
performRangeResponse(context, resource, contentType, eTag, headers); performRangeResponse(context, resource, contentType, eTag, headers);
sent = true; sent = true;
@ -194,8 +177,7 @@ public abstract class AbstractResourceHandler implements HttpHandler {
long length = resource.getLength(); long length = resource.getLength();
if (length > 0L) { if (length > 0L) {
String string = Long.toString(resource.getLength()); String string = Long.toString(resource.getLength());
context.response() context.header(HttpHeaderNames.CONTENT_LENGTH, string);
.addHeader(HttpHeaderNames.CONTENT_LENGTH, string);
logger.log(Level.FINEST, "length is known = " + resource.getLength()); logger.log(Level.FINEST, "length is known = " + resource.getLength());
send(resource, HttpResponseStatus.OK, contentType, context, 0L, resource.getLength()); send(resource, HttpResponseStatus.OK, contentType, context, 0L, resource.getLength());
} else { } else {
@ -206,23 +188,21 @@ public abstract class AbstractResourceHandler implements HttpHandler {
logger.log(Level.FINEST, "generation done"); logger.log(Level.FINEST, "generation done");
} }
private void performRangeResponse(HttpServerContext context, private void performRangeResponse(HttpRouterContext context,
Resource resource, Resource resource,
String contentType, String contentType,
String eTag, String eTag,
HttpHeaders headers) throws IOException { HttpHeaders headers) throws IOException {
long length = resource.getLength(); long length = resource.getLength();
logger.log(Level.FINEST, "performing range response on resource = " + resource); logger.log(Level.FINEST, "performing range response on resource = " + resource);
context.response().addHeader(HttpHeaderNames.ACCEPT_RANGES, "bytes"); context.header(HttpHeaderNames.ACCEPT_RANGES, "bytes");
Range full = new Range(0, length - 1, length); Range full = new Range(0, length - 1, length);
List<Range> ranges = new ArrayList<>(); List<Range> ranges = new ArrayList<>();
String range = headers.get(HttpHeaderNames.RANGE); String range = headers.get(HttpHeaderNames.RANGE);
if (range != null) { if (range != null) {
if (!range.matches("^bytes=\\d*-\\d*(,\\d*-\\d*)*$")) { if (!range.matches("^bytes=\\d*-\\d*(,\\d*-\\d*)*$")) {
context.response() context.header(HttpHeaderNames.CONTENT_RANGE, "bytes */" + length)
.addHeader(HttpHeaderNames.CONTENT_RANGE, "bytes */" + length) .status(HttpResponseStatus.REQUESTED_RANGE_NOT_SATISFIABLE);
.setResponseStatus(HttpResponseStatus.REQUESTED_RANGE_NOT_SATISFIABLE)
.build();
return; return;
} }
String ifRange = headers.get(HttpHeaderNames.IF_RANGE); String ifRange = headers.get(HttpHeaderNames.IF_RANGE);
@ -247,10 +227,8 @@ public abstract class AbstractResourceHandler implements HttpHandler {
end = length - 1; end = length - 1;
} }
if (start > end) { if (start > end) {
context.response() context.header(HttpHeaderNames.CONTENT_RANGE, "bytes */" + length)
.addHeader(HttpHeaderNames.CONTENT_RANGE, "bytes */" + length) .status(HttpResponseStatus.REQUESTED_RANGE_NOT_SATISFIABLE);
.setResponseStatus(HttpResponseStatus.REQUESTED_RANGE_NOT_SATISFIABLE)
.build();
return; return;
} }
ranges.add(new Range(start, end, length)); ranges.add(new Range(start, end, length));
@ -258,23 +236,20 @@ public abstract class AbstractResourceHandler implements HttpHandler {
} }
} }
if (ranges.isEmpty() || ranges.get(0) == full) { if (ranges.isEmpty() || ranges.get(0) == full) {
context.response() context.header(HttpHeaderNames.CONTENT_RANGE, "bytes " + full.start + '-' + full.end + '/' + full.total)
.addHeader(HttpHeaderNames.CONTENT_RANGE, "bytes " + full.start + '-' + full.end + '/' + full.total) .header(HttpHeaderNames.CONTENT_LENGTH, Long.toString(full.length));
.addHeader(HttpHeaderNames.CONTENT_LENGTH, Long.toString(full.length));
send(resource, HttpResponseStatus.OK, contentType, context, full.start, full.length); send(resource, HttpResponseStatus.OK, contentType, context, full.start, full.length);
} else if (ranges.size() == 1) { } else if (ranges.size() == 1) {
Range r = ranges.get(0); Range r = ranges.get(0);
context.response() context.header(HttpHeaderNames.CONTENT_RANGE, "bytes " + r.start + '-' + r.end + '/' + r.total)
.addHeader(HttpHeaderNames.CONTENT_RANGE, "bytes " + r.start + '-' + r.end + '/' + r.total) .header(HttpHeaderNames.CONTENT_LENGTH, Long.toString(r.length));
.addHeader(HttpHeaderNames.CONTENT_LENGTH, Long.toString(r.length));
send(resource, HttpResponseStatus.PARTIAL_CONTENT, contentType, context, r.start, r.length); send(resource, HttpResponseStatus.PARTIAL_CONTENT, contentType, context, r.start, r.length);
} else { } else {
context.response() context.header(CONTENT_TYPE, "multipart/byteranges; boundary=MULTIPART_BOUNDARY");
.addHeader(HttpHeaderNames.CONTENT_TYPE, "multipart/byteranges; boundary=MULTIPART_BOUNDARY");
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (Range r : ranges) { for (Range r : ranges) {
try { try {
DataBuffer dataBuffer = readBuffer(context.response(), resource.getURL(), r.start, r.length); DataBuffer dataBuffer = readBuffer(context.getDataBufferFactory(), resource.getURL(), r.start, r.length);
sb.append('\n') sb.append('\n')
.append("--MULTIPART_BOUNDARY").append('\n') .append("--MULTIPART_BOUNDARY").append('\n')
.append("content-type: ").append(contentType).append('\n') .append("content-type: ").append(contentType).append('\n')
@ -287,10 +262,9 @@ public abstract class AbstractResourceHandler implements HttpHandler {
logger.log(Level.FINEST, e.getMessage(), e); logger.log(Level.FINEST, e.getMessage(), e);
} }
} }
context.response() context.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(CONTENT_TYPE, contentType)
.setContentType(contentType) .body(CharBuffer.wrap(sb), StandardCharsets.ISO_8859_1);
.write(CharBuffer.wrap(sb), StandardCharsets.ISO_8859_1);
} }
} }
@ -308,7 +282,7 @@ public abstract class AbstractResourceHandler implements HttpHandler {
protected void send(Resource resource, protected void send(Resource resource,
HttpResponseStatus httpResponseStatus, HttpResponseStatus httpResponseStatus,
String contentType, String contentType,
HttpServerContext context, HttpRouterContext context,
long offset, long offset,
long size) throws IOException { long size) throws IOException {
if (resource instanceof HttpServerResource) { if (resource instanceof HttpServerResource) {
@ -319,41 +293,31 @@ public abstract class AbstractResourceHandler implements HttpHandler {
URL url = resource.getURL(); URL url = resource.getURL();
logger.log(Level.FINEST, "sending URL = " + url + " offset = " + offset + " size = " + size); logger.log(Level.FINEST, "sending URL = " + url + " offset = " + offset + " size = " + size);
if (url == null) { if (url == null) {
context.response() context.status(HttpResponseStatus.NOT_FOUND);
.setResponseStatus(HttpResponseStatus.NOT_FOUND) } else if (context.getRequestBuilder().getMethod() == HttpMethod.HEAD) {
.build();
} else if (context.request().getMethod() == HttpMethod.HEAD) {
logger.log(Level.FINEST, "HEAD request, do not send body"); logger.log(Level.FINEST, "HEAD request, do not send body");
context.response() context.status(HttpResponseStatus.OK)
.setResponseStatus(HttpResponseStatus.OK) .header(CONTENT_TYPE, contentType);
.setContentType(contentType)
.build();
} else { } else {
if ("file".equals(url.getScheme())) { if ("file".equals(url.getScheme())) {
Path path = resource.getPath(); Path path = resource.getPath();
try (FileChannel fileChannel = (FileChannel) Files.newByteChannel(path)) { try (FileChannel fileChannel = (FileChannel) Files.newByteChannel(path)) {
send(fileChannel, httpResponseStatus, contentType, context.response(), offset, size); send(fileChannel, httpResponseStatus, contentType, context, offset, size);
} catch (IOException e) { } catch (IOException e) {
logger.log(Level.SEVERE, e.getMessage() + " path=" + path, e); logger.log(Level.SEVERE, e.getMessage() + " path=" + path, e);
context.response() context.status(HttpResponseStatus.NOT_FOUND);
.setResponseStatus(HttpResponseStatus.NOT_FOUND)
.build();
} }
} else { } else {
try (InputStream inputStream = url.openStream()) { try (InputStream inputStream = url.openStream()) {
if (inputStream != null) { if (inputStream != null) {
send(inputStream, httpResponseStatus, contentType, context.response(), offset, size); send(inputStream, httpResponseStatus, contentType, context, offset, size);
} else { } else {
logger.log(Level.WARNING, "input stream is null, url = " + url); logger.log(Level.WARNING, "input stream is null, url = " + url);
context.response() context.status(HttpResponseStatus.NOT_FOUND);
.setResponseStatus(HttpResponseStatus.NOT_FOUND)
.build();
} }
} catch (IOException e) { } catch (IOException e) {
logger.log(Level.SEVERE, e.getMessage() + " url=" + url, e); logger.log(Level.SEVERE, e.getMessage() + " url=" + url, e);
context.response() context.status(HttpResponseStatus.NOT_FOUND);
.setResponseStatus(HttpResponseStatus.NOT_FOUND)
.build();
} }
} }
} }
@ -362,18 +326,18 @@ public abstract class AbstractResourceHandler implements HttpHandler {
protected void send(FileChannel fileChannel, protected void send(FileChannel fileChannel,
HttpResponseStatus httpResponseStatus, HttpResponseStatus httpResponseStatus,
String contentType, String contentType,
HttpResponseBuilder responseBuilder, HttpRouterContext context,
long offset, long size) throws IOException { long offset, long size) throws IOException {
if (fileChannel == null ) { if (fileChannel == null ) {
logger.log(Level.WARNING, "file channel is null, generating not found"); logger.log(Level.WARNING, "file channel is null, generating not found");
responseBuilder.setResponseStatus(HttpResponseStatus.NOT_FOUND).build(); context.status(HttpResponseStatus.NOT_FOUND);
} else { } else {
fileChannel = fileChannel.position(offset); fileChannel = fileChannel.position(offset);
try (ReadableByteChannel channel = fileChannel) { try (ReadableByteChannel channel = fileChannel) {
DataBuffer dataBuffer = DataBufferUtil.readBuffer(responseBuilder.getDataBufferFactory(), channel, size); DataBuffer dataBuffer = DataBufferUtil.readBuffer(context.getDataBufferFactory(), channel, size);
responseBuilder.setResponseStatus(httpResponseStatus) context.status(httpResponseStatus)
.setContentType(contentType) .header(CONTENT_TYPE, contentType)
.write(dataBuffer); .body(dataBuffer);
} }
} }
} }
@ -381,36 +345,36 @@ public abstract class AbstractResourceHandler implements HttpHandler {
protected void send(InputStream inputStream, protected void send(InputStream inputStream,
HttpResponseStatus httpResponseStatus, HttpResponseStatus httpResponseStatus,
String contentType, String contentType,
HttpResponseBuilder responseBuilder, HttpRouterContext context,
long offset, long offset,
long size) throws IOException { long size) throws IOException {
if (inputStream == null) { if (inputStream == null) {
logger.log(Level.WARNING, "inputstream is null, generating not found"); logger.log(Level.WARNING, "inputstream is null, generating not found");
responseBuilder.setResponseStatus(HttpResponseStatus.NOT_FOUND).build(); context.status(HttpResponseStatus.NOT_FOUND);
} else { } else {
long n = inputStream.skip(offset); long n = inputStream.skip(offset);
try (ReadableByteChannel channel = Channels.newChannel(inputStream)) { try (ReadableByteChannel channel = Channels.newChannel(inputStream)) {
DataBuffer dataBuffer = DataBufferUtil.readBuffer(responseBuilder.getDataBufferFactory(), channel, size); DataBuffer dataBuffer = DataBufferUtil.readBuffer(context.getDataBufferFactory(), channel, size);
responseBuilder context.status(httpResponseStatus)
.setResponseStatus(httpResponseStatus) .header(CONTENT_TYPE, contentType)
.setContentType(contentType) .body(dataBuffer);
.write(dataBuffer);
} }
} }
} }
private DataBuffer readBuffer(HttpResponseBuilder responseBuilder, URL url, long offset, long size) throws IOException, URISyntaxException { private DataBuffer readBuffer(DataBufferFactory factory, URL url, long offset, long size)
throws IOException, URISyntaxException {
if ("file".equals(url.getScheme())) { if ("file".equals(url.getScheme())) {
Path path = Paths.get(url.toURI()); Path path = Paths.get(url.toURI());
try (SeekableByteChannel channel = Files.newByteChannel(path)) { try (SeekableByteChannel channel = Files.newByteChannel(path)) {
channel.position(offset); channel.position(offset);
return DataBufferUtil.readBuffer(responseBuilder.getDataBufferFactory(), channel, size); return DataBufferUtil.readBuffer(factory, channel, size);
} }
} else { } else {
try (InputStream inputStream = url.openStream()) { try (InputStream inputStream = url.openStream()) {
long n = inputStream.skip(offset); long n = inputStream.skip(offset);
try (ReadableByteChannel channel = Channels.newChannel(inputStream)) { try (ReadableByteChannel channel = Channels.newChannel(inputStream)) {
return DataBufferUtil.readBuffer(responseBuilder.getDataBufferFactory(), channel, size); return DataBufferUtil.readBuffer(factory, channel, size);
} }
} }
} }

View file

@ -9,7 +9,7 @@ import java.util.logging.Logger;
import org.xbib.net.PathNormalizer; import org.xbib.net.PathNormalizer;
import org.xbib.net.Resource; import org.xbib.net.Resource;
import org.xbib.net.URL; import org.xbib.net.URL;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
public class ClassLoaderResourceHandler extends AbstractResourceHandler { public class ClassLoaderResourceHandler extends AbstractResourceHandler {
@ -29,8 +29,8 @@ public class ClassLoaderResourceHandler extends AbstractResourceHandler {
} }
@Override @Override
protected Resource createResource(HttpServerContext httpServerContext) throws IOException { protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException {
return new ClassLoaderResource(httpServerContext); return new ClassLoaderResource(httpRouterContext);
} }
@Override @Override
@ -73,8 +73,8 @@ public class ClassLoaderResourceHandler extends AbstractResourceHandler {
private URL url; private URL url;
protected ClassLoaderResource(HttpServerContext httpServerContext) throws IOException { protected ClassLoaderResource(HttpRouterContext httpRouterContext) throws IOException {
String contextPath = httpServerContext.getContextPath(); String contextPath = httpRouterContext.getContextPath();
this.mimeType = mimeTypeService.getContentType(contextPath); this.mimeType = mimeTypeService.getContentType(contextPath);
this.resourcePath = contextPath.startsWith("/") ? contextPath.substring(1) : contextPath; this.resourcePath = contextPath.startsWith("/") ? contextPath.substring(1) : contextPath;
String path = resourcePrefix != null ? (resourcePrefix.endsWith("/") ? resourcePrefix : resourcePrefix + "/") : "/"; String path = resourcePrefix != null ? (resourcePrefix.endsWith("/") ? resourcePrefix : resourcePrefix + "/") : "/";

View file

@ -11,7 +11,7 @@ import java.util.logging.Logger;
import org.xbib.net.PathNormalizer; import org.xbib.net.PathNormalizer;
import org.xbib.net.Resource; import org.xbib.net.Resource;
import org.xbib.net.URL; import org.xbib.net.URL;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.application.Application; import org.xbib.net.http.server.application.Application;
public class FileResourceHandler extends AbstractResourceHandler { public class FileResourceHandler extends AbstractResourceHandler {
@ -35,23 +35,23 @@ public class FileResourceHandler extends AbstractResourceHandler {
} }
@Override @Override
protected Resource createResource(HttpServerContext httpServerContext) throws IOException { protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException {
String pathSpec = httpServerContext.getAttributes().containsKey("templatePath") ? String pathSpec = httpRouterContext.getAttributes().containsKey("templatePath") ?
(String) httpServerContext.getAttributes().get("templatePath") : (String) httpRouterContext.getAttributes().get("templatePath") :
pathNameOfResource != null ? pathNameOfResource : httpServerContext.getContextPath(); pathNameOfResource != null ? pathNameOfResource : httpRouterContext.getContextPath();
if (pathSpec == null || pathSpec.isEmpty()) { if (pathSpec == null || pathSpec.isEmpty()) {
throw new IllegalArgumentException("path must not be null or empty"); throw new IllegalArgumentException("path must not be null or empty");
} }
Resource resource = null; Resource resource = null;
if (pathSpec.endsWith("/")) { if (pathSpec.endsWith("/")) {
if (indexFileName != null) { if (indexFileName != null) {
resource = new FileResource(httpServerContext, pathSpec + indexFileName); resource = new FileResource(httpRouterContext, pathSpec + indexFileName);
} }
} else { } else {
resource = new FileResource(httpServerContext, pathSpec); resource = new FileResource(httpRouterContext, pathSpec);
if (resource.isDirectory() && resource.isExistsIndexFile()) { if (resource.isDirectory() && resource.isExistsIndexFile()) {
logger.log(Level.FINER, "we have a directory and existing index file, so we redirect internally"); logger.log(Level.FINER, "we have a directory and existing index file, so we redirect internally");
resource = new FileResource(httpServerContext, pathSpec + indexFileName); resource = new FileResource(httpRouterContext, pathSpec + indexFileName);
} }
} }
return resource; return resource;
@ -103,9 +103,9 @@ public class FileResourceHandler extends AbstractResourceHandler {
private final String suffix; private final String suffix;
protected FileResource(HttpServerContext httpServerContext, String resourcePath) throws IOException { protected FileResource(HttpRouterContext httpRouterContext, String resourcePath) throws IOException {
this.resourcePath = resourcePath; this.resourcePath = resourcePath;
Application application = httpServerContext.getAttributes().get(Application.class, "application"); Application application = httpRouterContext.getAttributes().get(Application.class, "application");
Path root = application.getHome(); Path root = application.getHome();
if (root == null) { if (root == null) {
throw new IllegalArgumentException("no home path set for template resource resolving"); throw new IllegalArgumentException("no home path set for template resource resolving");
@ -119,7 +119,7 @@ public class FileResourceHandler extends AbstractResourceHandler {
normalizedPath = normalizedPath.substring(1); normalizedPath = normalizedPath.substring(1);
} }
this.name = normalizedPath; this.name = normalizedPath;
this.path = httpServerContext.resolve(webRoot).resolve(normalizedPath); this.path = httpRouterContext.resolve(webRoot).resolve(normalizedPath);
} }
this.mimeType = mimeTypeService.getContentType(resourcePath); this.mimeType = mimeTypeService.getContentType(resourcePath);
if (Files.isDirectory(path) && getIndexFileName() != null) { if (Files.isDirectory(path) && getIndexFileName() != null) {

View file

@ -7,7 +7,7 @@ import java.time.Instant;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.xbib.net.URL; import org.xbib.net.URL;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.application.Application; import org.xbib.net.http.server.application.Application;
public class HtmlTemplateResource implements HttpServerResource { public class HtmlTemplateResource implements HttpServerResource {
@ -41,17 +41,17 @@ public class HtmlTemplateResource implements HttpServerResource {
protected final boolean negotiateLocale; protected final boolean negotiateLocale;
protected HtmlTemplateResource(HtmlTemplateResourceHandler templateResourceHandler, protected HtmlTemplateResource(HtmlTemplateResourceHandler templateResourceHandler,
HttpServerContext httpServerContext) throws IOException { HttpRouterContext httpRouterContext) throws IOException {
this.templateResourceHandler = templateResourceHandler; this.templateResourceHandler = templateResourceHandler;
String indexFileName = templateResourceHandler.getIndexFileName(); String indexFileName = templateResourceHandler.getIndexFileName();
Application application = httpServerContext.getAttributes().get(Application.class, "application"); Application application = httpRouterContext.getAttributes().get(Application.class, "application");
this.negotiateLocale = application.getSettings().getAsBoolean("negotiateLocale", false); this.negotiateLocale = application.getSettings().getAsBoolean("negotiateLocale", false);
Path root = templateResourceHandler.getRoot(); Path root = templateResourceHandler.getRoot();
root = root != null ? root : application.getHome(); root = root != null ? root : application.getHome();
if (root == null) { if (root == null) {
throw new IllegalArgumentException("no home path set for template resource resolving"); throw new IllegalArgumentException("no home path set for template resource resolving");
} }
this.resourcePath = httpServerContext.request().getRequestPath().substring(1); this.resourcePath = httpRouterContext.getRequestBuilder().getRequestPath().substring(1);
this.path = resourcePath.length() > 0 ? root.resolve(resourcePath) : root; this.path = resourcePath.length() > 0 ? root.resolve(resourcePath) : root;
logger.log(Level.FINEST, "class = " + getClass().getName() + logger.log(Level.FINEST, "class = " + getClass().getName() +
" root = " + root + " root = " + root +
@ -167,7 +167,7 @@ public class HtmlTemplateResource implements HttpServerResource {
} }
@Override @Override
public void render(HttpServerContext httpServerContext) throws IOException { public void render(HttpRouterContext httpRouterContext) throws IOException {
// to be overriden // to be overriden
} }
} }

View file

@ -3,7 +3,7 @@ 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.Resource; import org.xbib.net.Resource;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
public class HtmlTemplateResourceHandler extends AbstractResourceHandler { public class HtmlTemplateResourceHandler extends AbstractResourceHandler {
@ -22,8 +22,8 @@ public class HtmlTemplateResourceHandler extends AbstractResourceHandler {
} }
@Override @Override
protected Resource createResource(HttpServerContext httpServerContext) throws IOException { protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException {
return new HtmlTemplateResource(this, httpServerContext); return new HtmlTemplateResource(this, httpRouterContext);
} }
@Override @Override

View file

@ -2,9 +2,9 @@ package org.xbib.net.http.server.resource;
import java.io.IOException; import java.io.IOException;
import org.xbib.net.Resource; import org.xbib.net.Resource;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
public interface HttpServerResource extends Resource { public interface HttpServerResource extends Resource {
void render(HttpServerContext httpServerContext) throws IOException; void render(HttpRouterContext httpRouterContext) throws IOException;
} }

View file

@ -3,7 +3,7 @@ package org.xbib.net.http.server.resource;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpRequest; import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
public class MethodHandler implements HttpHandler { public class MethodHandler implements HttpHandler {
@ -23,7 +23,7 @@ public class MethodHandler implements HttpHandler {
} }
@Override @Override
public void handle(HttpServerContext context) { public void handle(HttpRouterContext context) {
try { try {
m.invoke(obj, context); m.invoke(obj, context);
} catch (Exception e) { } catch (Exception e) {

View file

@ -3,11 +3,11 @@ package org.xbib.net.http.server.resource;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import org.xbib.net.Resource; import org.xbib.net.Resource;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
public interface ResourceResolver { public interface ResourceResolver {
Resource resolveResource(HttpServerContext httpServerContext, Resource resolveResource(HttpRouterContext httpRouterContext,
String template, String template,
List<String> indexFiles) throws IOException; List<String> indexFiles) throws IOException;
} }

View file

@ -11,7 +11,7 @@ import org.xbib.net.Resource;
import org.xbib.net.URL; import org.xbib.net.URL;
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.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
public class WebRootResourceResolver implements ResourceResolver { public class WebRootResourceResolver implements ResourceResolver {
@ -25,12 +25,12 @@ public class WebRootResourceResolver implements ResourceResolver {
} }
@Override @Override
public Resource resolveResource(HttpServerContext httpServerContext, public Resource resolveResource(HttpRouterContext httpRouterContext,
String templateName, String templateName,
List<String> indexFiles) throws IOException { List<String> indexFiles) throws IOException {
String pathSpec = httpServerContext.getAttributes().containsKey("forwardedPath") ? String pathSpec = httpRouterContext.getAttributes().containsKey("forwardedPath") ?
(String) httpServerContext.getAttributes().get("forwardedPath") : (String) httpRouterContext.getAttributes().get("forwardedPath") :
templateName != null ? templateName : httpServerContext.httpRequest().getRequestPath(); templateName != null ? templateName : httpRouterContext.getRequest().getRequestPath();
if (pathSpec == null || pathSpec.isEmpty()) { if (pathSpec == null || pathSpec.isEmpty()) {
throw new IllegalArgumentException("path must not be null or empty"); throw new IllegalArgumentException("path must not be null or empty");
} }
@ -48,7 +48,7 @@ public class WebRootResourceResolver implements ResourceResolver {
resource = createResource(pathSpec); resource = createResource(pathSpec);
if (Files.isDirectory(resource.getPath())) { if (Files.isDirectory(resource.getPath())) {
// we need to move temporarily to the directory, and the browser must know about this. // we need to move temporarily to the directory, and the browser must know about this.
HttpRequest request = httpServerContext.httpRequest(); HttpRequest request = httpRouterContext.getRequest();
URL url = request.getBaseURL(); //response.server().getPublishURL(request); URL url = request.getBaseURL(); //response.server().getPublishURL(request);
String loc = url.resolve(resource.getName() + '/') String loc = url.resolve(resource.getName() + '/')
.mutator() .mutator()
@ -56,9 +56,8 @@ public class WebRootResourceResolver implements ResourceResolver {
.fragment(request.getBaseURL().getFragment()) .fragment(request.getBaseURL().getFragment())
.build() .build()
.toString(); .toString();
httpServerContext.response() httpRouterContext.status(HttpResponseStatus.TEMPORARY_REDIRECT)
.setResponseStatus(HttpResponseStatus.TEMPORARY_REDIRECT) .header("location", loc);
.setHeader("location", loc);
} }
} }
return resource; return resource;

View file

@ -1,9 +1,16 @@
package org.xbib.net.http.server.route; package org.xbib.net.http.server.route;
import java.io.IOException; import java.io.IOException;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.NavigableSet; import java.util.NavigableSet;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@ -12,23 +19,34 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.xbib.datastructures.common.LinkedHashSetMultiMap; import org.xbib.datastructures.common.LinkedHashSetMultiMap;
import org.xbib.datastructures.common.MultiMap; import org.xbib.datastructures.common.MultiMap;
import org.xbib.datastructures.json.tiny.Json;
import org.xbib.net.Parameter;
import org.xbib.net.ParameterBuilder;
import org.xbib.net.URL; import org.xbib.net.URL;
import org.xbib.net.http.HttpAddress; import org.xbib.net.http.HttpAddress;
import org.xbib.net.http.HttpHeaderNames;
import org.xbib.net.http.HttpHeaderValues;
import org.xbib.net.http.HttpHeaders;
import org.xbib.net.http.HttpMethod;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.cookie.CookieBox;
import org.xbib.net.http.server.HttpException; import org.xbib.net.http.server.HttpException;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpRequest; import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.HttpRequestBuilder; import org.xbib.net.http.server.HttpRequestBuilder;
import org.xbib.net.http.server.HttpResponseBuilder; import org.xbib.net.http.server.HttpResponseBuilder;
import org.xbib.net.http.server.HttpServerContext;
import org.xbib.net.http.server.application.Application; import org.xbib.net.http.server.application.Application;
import org.xbib.net.http.server.domain.HttpDomain; import org.xbib.net.http.server.domain.HttpDomain;
import org.xbib.net.http.server.handler.InternalServerErrorHandler; import org.xbib.net.http.server.handler.InternalServerErrorHandler;
import org.xbib.net.http.server.service.HttpService; import org.xbib.net.http.server.service.HttpService;
import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
import static org.xbib.net.http.HttpResponseStatus.NOT_FOUND; import static org.xbib.net.http.HttpResponseStatus.NOT_FOUND;
public class BaseHttpRouter implements HttpRouter { public class BaseHttpRouter implements HttpRouter {
private static final String PATH_SEPARATOR = "/";
private final Logger logger = Logger.getLogger(BaseHttpRouter.class.getName()); private final Logger logger = Logger.getLogger(BaseHttpRouter.class.getName());
private final BaseHttpRouterBuilder builder; private final BaseHttpRouterBuilder builder;
@ -76,51 +94,69 @@ public class BaseHttpRouter implements HttpRouter {
requestBuilder.getRequestPath(), requestBuilder.getRequestPath(),
true); true);
builder.httpRouteResolver.resolve(httpRoute, httpRouteResolverResults::add); builder.httpRouteResolver.resolve(httpRoute, httpRouteResolverResults::add);
HttpServerContext httpServerContext = application.createContext(httpDomain, requestBuilder, responseBuilder); HttpRouterContext httpRouterContext = application.createContext(httpDomain,
application.onOpen(httpServerContext); requestBuilder, responseBuilder);
// before open: invoke security, incoming cookie/session
httpRouterContext.getOpenHandlers().forEach(h -> {
try { try {
route(application, httpServerContext, httpRouteResolverResults); h.handle(httpRouterContext);
} catch (Exception e) {
routeToErrorHandler(httpRouterContext, e);
}
});
application.onOpen(httpRouterContext);
try {
route(application, httpRouterContext, httpRouteResolverResults);
} finally { } finally {
application.onClose(httpServerContext); application.onClose(httpRouterContext);
// outgoing cookie/session
httpRouterContext.getCloseHandlers().forEach(h -> {
try {
h.handle(httpRouterContext);
} catch (Exception e) {
routeToErrorHandler(httpRouterContext, e);
}
});
application.releaseContext(httpRouterContext);
} }
} }
protected void route(Application application, protected void route(Application application,
HttpServerContext httpServerContext, HttpRouterContext httpRouterContext,
List<HttpRouteResolver.Result<HttpService>> httpRouteResolverResults) { List<HttpRouteResolver.Result<HttpService>> httpRouteResolverResults) {
if (httpServerContext.isFailed()) { if (httpRouterContext.isFailed()) {
return; return;
} }
if (httpRouteResolverResults.isEmpty()) { if (httpRouteResolverResults.isEmpty()) {
logger.log(Level.FINE, "route resolver results is empty, generating a not found message"); logger.log(Level.FINE, "route resolver results is empty, generating a not found message");
httpServerContext.setResolverResult(null); setResolverResult(httpRouterContext, null);
routeStatus(NOT_FOUND, httpServerContext); routeStatus(NOT_FOUND, httpRouterContext);
return; return;
} }
for (HttpRouteResolver.Result<HttpService> httpRouteResolverResult : httpRouteResolverResults) { for (HttpRouteResolver.Result<HttpService> httpRouteResolverResult : httpRouteResolverResults) {
try { try {
// first: create the final request // first: create the final request
httpServerContext.setResolverResult(httpRouteResolverResult); setResolverResult(httpRouterContext, httpRouteResolverResult);
HttpService httpService = httpRouteResolverResult.getValue(); HttpService httpService = httpRouteResolverResult.getValue();
HttpRequest httpRequest = httpServerContext.httpRequest(); HttpRequest httpRequest = httpRouterContext.getRequest();
application.getModules().forEach(module -> module.onOpen(httpServerContext, httpService, httpRequest)); application.getModules().forEach(module -> module.onOpen(httpRouterContext, httpService, httpRequest));
// second: security check, authentication etc. // second: security check, authentication etc.
if (httpService.getSecurityDomain() != null) { if (httpService.getSecurityDomain() != null) {
logger.log(Level.FINEST, () -> "handling security domain service " + httpService); logger.log(Level.FINEST, () -> "handling security domain service " + httpService);
for (HttpHandler httpHandler : httpService.getSecurityDomain().getHandlers()) { for (HttpHandler httpHandler : httpService.getSecurityDomain().getHandlers()) {
logger.log(Level.FINEST, () -> "handling security domain handler " + httpHandler); logger.log(Level.FINEST, () -> "handling security domain handler " + httpHandler);
httpHandler.handle(httpServerContext); httpHandler.handle(httpRouterContext);
} }
} }
if (httpServerContext.isDone() || httpServerContext.isFailed()) { if (httpRouterContext.isDone() || httpRouterContext.isFailed()) {
break; break;
} }
// after security checks, accept service, open and execute service // after security checks, accept service, open and execute service
httpServerContext.getAttributes().put("service", httpService); httpRouterContext.getAttributes().put("service", httpService);
logger.log(Level.FINEST, () -> "handling service " + httpService); logger.log(Level.FINEST, () -> "handling service " + httpService);
httpService.handle(httpServerContext); httpService.handle(httpRouterContext);
// if service signals that work is done, break // if service signals that work is done, break
if (httpServerContext.isDone() || httpServerContext.isFailed()) { if (httpRouterContext.isDone() || httpRouterContext.isFailed()) {
break; break;
} }
} catch (HttpException e) { } catch (HttpException e) {
@ -129,12 +165,138 @@ public class BaseHttpRouter implements HttpRouter {
break; break;
} catch (Throwable t) { } catch (Throwable t) {
logger.log(Level.SEVERE, t.getMessage(), t); logger.log(Level.SEVERE, t.getMessage(), t);
routeToErrorHandler(httpServerContext, t); routeToErrorHandler(httpRouterContext, t);
break; break;
} }
} }
} }
protected void setResolverResult(HttpRouterContext httpRouterContext,
HttpRouteResolver.Result<HttpService> pathResolverResult) {
if (pathResolverResult != null) {
httpRouterContext.getAttributes().put("context", pathResolverResult.getContext());
httpRouterContext.getAttributes().put("handler", pathResolverResult.getValue());
httpRouterContext.getAttributes().put("pathparams", pathResolverResult.getParameter());
String contextPath = pathResolverResult.getContext() != null ?
PATH_SEPARATOR + String.join(PATH_SEPARATOR, pathResolverResult.getContext()) : null;
httpRouterContext.setContextPath(contextPath);
httpRouterContext.setContextURL(httpRouterContext.getRequestBuilder().getBaseURL().resolve(contextPath != null ? contextPath + "/" : ""));
} else {
// path resolver result null means "404 not found". Set default values.
httpRouterContext.getAttributes().put("context", null);
httpRouterContext.getAttributes().put("handler", null);
httpRouterContext.getAttributes().put("pathparams", null);
httpRouterContext.setContextPath(PATH_SEPARATOR);
httpRouterContext.setContextURL(httpRouterContext.getRequestBuilder().getBaseURL());
}
HttpRequest httpRequest = createRequest(httpRouterContext, pathResolverResult);
httpRouterContext.setRequest(httpRequest);
httpRouterContext.getAttributes().put("request", httpRequest);
}
protected HttpRequest createRequest(HttpRouterContext httpRouterContext,
HttpRouteResolver.Result<HttpService> pathResolverResult) {
HttpRequestBuilder httpRequestBuilder = httpRouterContext.getRequestBuilder();
HttpHeaders headers = httpRequestBuilder.getHeaders();
String mimeType = headers.get(CONTENT_TYPE);
Charset charset = StandardCharsets.UTF_8;
if (mimeType != null) {
charset = getCharset(mimeType, charset);
}
ParameterBuilder parameterBuilder = Parameter.builder().charset(charset);
// helper URL to collect parameters in request URI
URL url = URL.builder()
.charset(charset, CodingErrorAction.REPLACE)
.path(httpRequestBuilder.getRequestURI())
.build();
ParameterBuilder formParameterBuilder = Parameter.builder().domain(Parameter.Domain.FORM)
.enableDuplicates();
// https://www.w3.org/TR/html4/interact/forms.html#h-17.13.4
if (HttpMethod.POST.equals(httpRequestBuilder.getMethod()) &&
(mimeType != null && mimeType.contains(HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED))) {
Charset htmlCharset = getCharset(mimeType, StandardCharsets.ISO_8859_1);
CharBuffer charBuffer = httpRequestBuilder.getBodyAsChars(htmlCharset);
if (charBuffer != null) {
formParameterBuilder.addPercentEncodedBody(charBuffer.toString());
}
}
String contentType = httpRequestBuilder.getHeaders().get(HttpHeaderNames.CONTENT_TYPE);
if (contentType != null && contentType.contains(HttpHeaderValues.APPLICATION_JSON)) {
String content = httpRequestBuilder.getBodyAsChars(StandardCharsets.UTF_8).toString();
try {
Map<String, Object> map = Json.toMap(content);
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getValue() instanceof Iterable<?> iterable) {
iterable.forEach(it -> formParameterBuilder.add(entry.getKey(), it));
} else {
formParameterBuilder.add(entry.getKey(), entry.getValue());
}
}
} catch (Exception e) {
logger.log(Level.WARNING, "unable to decode json body: " + e.getMessage(), e);
}
}
CookieBox cookieBox = httpRouterContext.getAttributes().get(CookieBox.class, "incomingcookies");
ParameterBuilder cookieParameterBuilder = Parameter.builder().domain(Parameter.Domain.COOKIE);
if (cookieBox != null) {
cookieBox.forEach(c -> cookieParameterBuilder.add(c.name(), c.value()));
}
Parameter queryParameter = url.getQueryParams();
logger.log(Level.FINER, "adding query parameters = " + queryParameter.getDomain() + " " + queryParameter.allToString());
parameterBuilder.add(queryParameter);
Parameter formParameter = formParameterBuilder.build();
logger.log(Level.FINER, "adding form parameters = " + formParameter.getDomain() + " " + formParameter.allToString());
parameterBuilder.add(formParameter);
Parameter cookieParameter = cookieParameterBuilder.build();
logger.log(Level.FINER, "adding cookie parameters = " + cookieParameter.getDomain() + " " + cookieParameter.allToString());
parameterBuilder.add(cookieParameter);
if (pathResolverResult != null) {
Parameter pathParameter = pathResolverResult.getParameter();
logger.log(Level.FINER, "adding path parameters = " + pathParameter.getDomain() + " " + pathParameter.allToString());
parameterBuilder.add(pathParameter);
}
httpRequestBuilder.setParameter(parameterBuilder.build());
httpRequestBuilder.setContext(httpRouterContext);
return httpRequestBuilder.build();
}
private static Charset getCharset(String contentTypeValue, Charset defaultCharset) {
if (contentTypeValue != null) {
CharSequence charsetRaw = getCharsetAsSequence(contentTypeValue);
if (charsetRaw != null) {
if (charsetRaw.length() > 2) {
if (charsetRaw.charAt(0) == '"' && charsetRaw.charAt(charsetRaw.length() - 1) == '"') {
charsetRaw = charsetRaw.subSequence(1, charsetRaw.length() - 1);
}
}
try {
return Charset.forName(charsetRaw.toString());
} catch (IllegalCharsetNameException | UnsupportedCharsetException ignored) {
// just return the default charset
}
}
}
return defaultCharset;
}
private static CharSequence getCharsetAsSequence(String contentTypeValue) {
Objects.requireNonNull(contentTypeValue);
int indexOfCharset = contentTypeValue.indexOf("charset=");
if (indexOfCharset == -1) {
return null;
}
int indexOfEncoding = indexOfCharset + "charset=".length();
if (indexOfEncoding < contentTypeValue.length()) {
CharSequence charsetCandidate = contentTypeValue.subSequence(indexOfEncoding, contentTypeValue.length());
int indexOfSemicolon = charsetCandidate.toString().indexOf(";");
if (indexOfSemicolon == -1) {
return charsetCandidate;
}
return charsetCandidate.subSequence(0, indexOfSemicolon);
}
return null;
}
@Override @Override
public void routeException(HttpException e) { public void routeException(HttpException e) {
routeStatus(e.getResponseStatus(), e.getHttpServerContext()); routeStatus(e.getResponseStatus(), e.getHttpServerContext());
@ -142,7 +304,7 @@ public class BaseHttpRouter implements HttpRouter {
@Override @Override
public void routeStatus(HttpResponseStatus httpResponseStatus, public void routeStatus(HttpResponseStatus httpResponseStatus,
HttpServerContext httpServerContext) { HttpRouterContext httpRouterContext) {
logger.log(Level.FINER, "routing status " + httpResponseStatus); logger.log(Level.FINER, "routing status " + httpResponseStatus);
try { try {
HttpHandler httpHandler = getHandler(httpResponseStatus); HttpHandler httpHandler = getHandler(httpResponseStatus);
@ -150,9 +312,9 @@ public class BaseHttpRouter implements HttpRouter {
logger.log(Level.FINER, "handler for " + httpResponseStatus + " not present, using default error handler"); logger.log(Level.FINER, "handler for " + httpResponseStatus + " not present, using default error handler");
httpHandler = new InternalServerErrorHandler(); httpHandler = new InternalServerErrorHandler();
} }
httpServerContext.response().reset(); httpRouterContext.reset();
httpHandler.handle(httpServerContext); httpHandler.handle(httpRouterContext);
httpServerContext.done(); httpRouterContext.done();
logger.log(Level.FINER, "routing status " + httpResponseStatus + " done"); logger.log(Level.FINER, "routing status " + httpResponseStatus + " done");
} catch (IOException ioe) { } catch (IOException ioe) {
throw new IllegalStateException("unable to route response status, reason: " + ioe.getMessage(), ioe); throw new IllegalStateException("unable to route response status, reason: " + ioe.getMessage(), ioe);
@ -160,10 +322,10 @@ public class BaseHttpRouter implements HttpRouter {
} }
@Override @Override
public void routeToErrorHandler(HttpServerContext httpServerContext, Throwable t) { public void routeToErrorHandler(HttpRouterContext httpRouterContext, Throwable t) {
httpServerContext.getAttributes().put("_throwable", t); httpRouterContext.getAttributes().put("_throwable", t);
httpServerContext.fail(); httpRouterContext.fail();
routeStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR, httpServerContext); routeStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR, httpRouterContext);
} }
private HttpDomain findDomain(URL url) { private HttpDomain findDomain(URL url) {

View file

@ -0,0 +1,278 @@
package org.xbib.net.http.server.route;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xbib.net.Attributes;
import org.xbib.net.URL;
import org.xbib.net.buffer.DataBuffer;
import org.xbib.net.buffer.DataBufferFactory;
import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.cookie.Cookie;
import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.HttpRequestBuilder;
import org.xbib.net.http.server.HttpResponseBuilder;
import org.xbib.net.http.server.application.Application;
import org.xbib.net.http.server.auth.BaseAttributes;
import org.xbib.net.http.server.domain.HttpDomain;
public class BaseHttpRouterContext implements HttpRouterContext {
private static final Logger logger = Logger.getLogger(BaseHttpRouterContext.class.getName());
private final Application application;
private final HttpRequestBuilder httpRequestBuilder;
private final HttpResponseBuilder httpResponseBuilder;
private final Attributes attributes;
private final List<HttpHandler> openHandlers;
private final List<HttpHandler> closeHandlers;
private String contextPath;
private URL contextURL;
private HttpRequest httpRequest;
private boolean done;
private boolean failed;
private boolean next;
public BaseHttpRouterContext(Application application,
HttpDomain domain,
HttpRequestBuilder httpRequestBuilder,
HttpResponseBuilder httpResponseBuilder) {
this.application = application;
this.httpRequestBuilder = httpRequestBuilder;
this.httpResponseBuilder = httpResponseBuilder;
this.openHandlers = new LinkedList<>();
this.closeHandlers = new LinkedList<>();
this.attributes = new BaseAttributes();
this.attributes.put("application", application);
this.attributes.put("domain", domain);
this.attributes.put("requestbuilder", httpRequestBuilder);
this.attributes.put("responsebuilder", httpResponseBuilder);
this.attributes.put("ctx", this);
}
@Override
public void addOpenHandler(HttpHandler handler) {
this.openHandlers.add(handler);
}
@Override
public List<HttpHandler> getOpenHandlers() {
return openHandlers;
}
@Override
public void addCloseHandler(HttpHandler handler) {
this.closeHandlers.add(handler);
}
@Override
public List<HttpHandler> getCloseHandlers() {
return closeHandlers;
}
@Override
public Application getApplication() {
return application;
}
@Override
public HttpRequestBuilder getRequestBuilder() {
return httpRequestBuilder;
}
public HttpResponseBuilder getResponseBuilder() {
return httpResponseBuilder;
}
@Override
public HttpRequest getRequest() {
return httpRequest;
}
@Override
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
@Override
public String getContextPath() {
return contextPath;
}
@Override
public void setContextURL(URL contextURL) {
this.contextURL = contextURL;
}
@Override
public URL getContextURL() {
return contextURL;
}
@Override
public Path resolve(String path) {
return application.resolve(path);
}
@Override
public DataBufferFactory getDataBufferFactory() {
return httpResponseBuilder.getDataBufferFactory();
}
@Override
public BaseHttpRouterContext status(int statusCode) {
httpResponseBuilder.setResponseStatus(HttpResponseStatus.valueOf(statusCode));
return this;
}
@Override
public BaseHttpRouterContext status(HttpResponseStatus httpResponseStatus) {
httpResponseBuilder.setResponseStatus(httpResponseStatus);
return this;
}
@Override
public HttpResponseStatus status() {
return httpResponseBuilder.getResponseStatus();
}
@Override
public BaseHttpRouterContext charset(Charset charset) {
httpResponseBuilder.setCharset(charset);
return this;
}
@Override
public Attributes getAttributes() {
return attributes;
}
@Override
public void done() {
this.done = true;
this.httpRequestBuilder.done();
this.httpResponseBuilder.done();
}
@Override
public boolean isDone() {
return done;
}
@Override
public void reset() {
httpResponseBuilder.reset();
}
@Override
public boolean isFailed() {
return failed;
}
@Override
public void fail() {
this.failed = true;
}
public void next() {
this.next = true;
}
public boolean isNext() {
return next;
}
@Override
public void setRequest(HttpRequest httpRequest) {
this.httpRequest = httpRequest;
}
@Override
public BaseHttpRouterContext header(String name, String value) {
httpResponseBuilder.addHeader(name, value);
return this;
}
@Override
public HttpRouterContext cookie(Cookie cookie) {
httpResponseBuilder.addCookie(cookie);
return this;
}
@Override
public BaseHttpRouterContext body(String string) throws IOException {
httpResponseBuilder.write(string);
return this;
}
@Override
public BaseHttpRouterContext body(CharBuffer charBuffer, Charset charset) throws IOException {
httpResponseBuilder.write(charBuffer, charset);
return this;
}
@Override
public BaseHttpRouterContext body(DataBuffer dataBuffer) throws IOException {
httpResponseBuilder.write(dataBuffer);
return this;
}
@Override
public BaseHttpRouterContext body(InputStream inputStream, int bufferSize) throws IOException {
httpResponseBuilder.write(inputStream, bufferSize);
return this;
}
@Override
public BaseHttpRouterContext body(FileChannel fileChannel, int bufferSize) throws IOException {
httpResponseBuilder.write(fileChannel, bufferSize);
return this;
}
@Override
public long lengthInBytes() {
return httpResponseBuilder.getLength();
}
@Override
public void flush() throws IOException {
httpResponseBuilder.build().flush();
}
@Override
public void close() throws IOException {
for (HttpHandler httpHandler : openHandlers) {
if (httpHandler instanceof Closeable) {
logger.log(Level.FINE, "closing handler " + httpHandler);
((Closeable) httpHandler).close();
}
}
for (HttpHandler httpHandler : closeHandlers) {
if (httpHandler instanceof Closeable) {
logger.log(Level.FINE, "closing handler " + httpHandler);
((Closeable) httpHandler).close();
}
}
}
}

View file

@ -5,7 +5,6 @@ import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpException; import org.xbib.net.http.server.HttpException;
import org.xbib.net.http.server.HttpRequestBuilder; import org.xbib.net.http.server.HttpRequestBuilder;
import org.xbib.net.http.server.HttpResponseBuilder; import org.xbib.net.http.server.HttpResponseBuilder;
import org.xbib.net.http.server.HttpServerContext;
import org.xbib.net.http.server.application.Application; import org.xbib.net.http.server.application.Application;
import org.xbib.net.http.server.domain.HttpDomain; import org.xbib.net.http.server.domain.HttpDomain;
@ -17,9 +16,9 @@ public interface HttpRouter {
void route(Application application, HttpRequestBuilder requestBuilder, HttpResponseBuilder responseBuilder); void route(Application application, HttpRequestBuilder requestBuilder, HttpResponseBuilder responseBuilder);
void routeStatus(HttpResponseStatus httpResponseStatus, HttpServerContext httpServerContext); void routeStatus(HttpResponseStatus httpResponseStatus, HttpRouterContext httpRouterContext);
void routeToErrorHandler(HttpServerContext httpServerContext, Throwable t); void routeToErrorHandler(HttpRouterContext httpRouterContext, Throwable t);
void routeException(HttpException e); void routeException(HttpException e);

View file

@ -0,0 +1,98 @@
package org.xbib.net.http.server.route;
import java.io.IOException;
import java.io.InputStream;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.List;
import org.xbib.net.Attributes;
import org.xbib.net.URL;
import org.xbib.net.buffer.DataBuffer;
import org.xbib.net.buffer.DataBufferFactory;
import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.cookie.Cookie;
import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.HttpRequestBuilder;
import org.xbib.net.http.server.HttpResponseBuilder;
import org.xbib.net.http.server.application.Application;
public interface HttpRouterContext {
Application getApplication();
void addOpenHandler(HttpHandler handler);
List<HttpHandler> getOpenHandlers();
void addCloseHandler(HttpHandler handler);
List<HttpHandler> getCloseHandlers();
HttpRequestBuilder getRequestBuilder();
void setRequest(HttpRequest httpRequest);
HttpRequest getRequest();
//HttpResponseBuilder getResponseBuilder();
Attributes getAttributes();
void done();
boolean isDone();
void reset();
void fail();
boolean isFailed();
void next();
boolean isNext();
void setContextPath(String contextPath);
String getContextPath();
void setContextURL(URL url);
URL getContextURL();
Path resolve(String path);
DataBufferFactory getDataBufferFactory();
HttpRouterContext status(int statusCode);
HttpRouterContext status(HttpResponseStatus httpResponseStatus);
HttpResponseStatus status();
HttpRouterContext charset(Charset charset);
HttpRouterContext header(String name, String value);
HttpRouterContext cookie(Cookie cookie);
HttpRouterContext body(String string) throws IOException;
HttpRouterContext body(CharBuffer charBuffer, Charset charset) throws IOException;
HttpRouterContext body(DataBuffer dataBuffer) throws IOException;
HttpRouterContext body(InputStream inputStream, int bufferSize) throws IOException;
HttpRouterContext body(FileChannel fileChannel, int bufferSize) throws IOException;
long lengthInBytes();
void flush() throws IOException;
void close() throws IOException;
}

View file

@ -9,7 +9,7 @@ import org.xbib.net.http.HttpMethod;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpException; import org.xbib.net.http.server.HttpException;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.domain.HttpSecurityDomain; import org.xbib.net.http.server.domain.HttpSecurityDomain;
public class BaseHttpService implements HttpService { public class BaseHttpService implements HttpService {
@ -57,7 +57,7 @@ public class BaseHttpService implements HttpService {
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
if (builder.handlers != null) { if (builder.handlers != null) {
for (HttpHandler handler : builder.handlers) { for (HttpHandler handler : builder.handlers) {
handler.handle(context); handler.handle(context);

View file

@ -1,7 +1,7 @@
package org.xbib.net.http.server.service; package org.xbib.net.http.server.service;
import org.xbib.net.http.server.HttpServerConfig; import org.xbib.net.http.server.HttpServerConfig;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.decorate.Unwrappable; import org.xbib.net.http.server.decorate.Unwrappable;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
@ -11,7 +11,7 @@ public interface Service extends Unwrappable {
default void serviceAdded(HttpServerConfig cfg) throws Exception { default void serviceAdded(HttpServerConfig cfg) throws Exception {
} }
void serve(HttpServerContext ctx) throws Exception; void serve(HttpRouterContext ctx) throws Exception;
/** /**
* Unwraps this {@link Service} into the object of the specified {@code type}. * Unwraps this {@link Service} into the object of the specified {@code type}.

View file

@ -18,7 +18,7 @@ import org.xbib.net.http.cookie.Cookie;
import org.xbib.net.http.cookie.CookieBox; import org.xbib.net.http.cookie.CookieBox;
import org.xbib.net.http.server.HttpException; import org.xbib.net.http.server.HttpException;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.auth.BaseUserProfile; import org.xbib.net.http.server.auth.BaseUserProfile;
import org.xbib.net.http.server.cookie.CookieSignatureException; import org.xbib.net.http.server.cookie.CookieSignatureException;
import org.xbib.net.http.server.cookie.CookieSignatureUtil; import org.xbib.net.http.server.cookie.CookieSignatureUtil;
@ -66,8 +66,8 @@ public class IncomingSessionHandler implements HttpHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws HttpException { public void handle(HttpRouterContext context) throws HttpException {
String suffix = SessionUtil.extractExtension(context.request().getRequestPath()); String suffix = SessionUtil.extractExtension(context.getRequestBuilder().getRequestPath());
if (suffix != null && suffixes.contains(suffix)) { if (suffix != null && suffixes.contains(suffix)) {
return; return;
} }

View file

@ -20,7 +20,7 @@ import org.xbib.net.http.cookie.DefaultCookie;
import org.xbib.net.http.cookie.SameSite; import org.xbib.net.http.cookie.SameSite;
import org.xbib.net.http.server.HttpException; import org.xbib.net.http.server.HttpException;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.application.Application; import org.xbib.net.http.server.application.Application;
import org.xbib.net.http.server.cookie.CookieSignatureException; import org.xbib.net.http.server.cookie.CookieSignatureException;
import org.xbib.net.http.server.cookie.CookieSignatureUtil; import org.xbib.net.http.server.cookie.CookieSignatureUtil;
@ -77,12 +77,12 @@ public class OutgoingSessionHandler implements HttpHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws HttpException { public void handle(HttpRouterContext context) throws HttpException {
if (context.getContextURL() == null) { if (context.getContextURL() == null) {
// emergency message // emergency message
return; return;
} }
String suffix = SessionUtil.extractExtension(context.request().getRequestPath()); String suffix = SessionUtil.extractExtension(context.getRequestBuilder().getRequestPath());
if (suffix != null && suffixes.contains(suffix)) { if (suffix != null && suffixes.contains(suffix)) {
logger.log(Level.FINEST, () -> "suffix " + suffix + " blocking outgoing session handling"); logger.log(Level.FINEST, () -> "suffix " + suffix + " blocking outgoing session handling");
return; return;

View file

@ -42,8 +42,7 @@ public class FileJsonSessionCodec implements Codec<Session> {
SessionListener sessionListener, SessionListener sessionListener,
int sessionCacheSize, int sessionCacheSize,
Duration sessionDuration, Duration sessionDuration,
Path path Path path) {
) {
this.name = name; this.name = name;
this.sessionListener = sessionListener; this.sessionListener = sessionListener;
this.path = path; this.path = path;

View file

@ -1,6 +1,5 @@
package org.xbib.net.http.server.session.jdbc; package org.xbib.net.http.server.session.jdbc;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.sql.Connection; import java.sql.Connection;
@ -13,9 +12,6 @@ import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.xbib.net.http.server.persist.Codec; import org.xbib.net.http.server.persist.Codec;
import org.xbib.net.http.server.session.BaseSession; import org.xbib.net.http.server.session.BaseSession;
@ -23,7 +19,7 @@ import org.xbib.net.http.server.session.Session;
import org.xbib.net.http.server.session.SessionListener; import org.xbib.net.http.server.session.SessionListener;
import org.xbib.net.util.JsonUtil; import org.xbib.net.util.JsonUtil;
public class JdbcSessionCodec implements Codec<Session>, Closeable { public class JdbcSessionCodec implements Codec<Session> {
private final String name; private final String name;
@ -43,8 +39,6 @@ public class JdbcSessionCodec implements Codec<Session>, Closeable {
private final String purgeSessionStringStatement; private final String purgeSessionStringStatement;
private final ScheduledExecutorService scheduledExecutorService;
public JdbcSessionCodec(String name, public JdbcSessionCodec(String name,
SessionListener sessionListener, SessionListener sessionListener,
int sessionCacheSize, int sessionCacheSize,
@ -63,8 +57,6 @@ public class JdbcSessionCodec implements Codec<Session>, Closeable {
this.writeSessionStringStatement = writeSessionStringStatement; this.writeSessionStringStatement = writeSessionStringStatement;
this.deleteSessionStringStatement = deleteSessionStringStatement; this.deleteSessionStringStatement = deleteSessionStringStatement;
this.purgeSessionStringStatement = purgeSessionStringStatement; this.purgeSessionStringStatement = purgeSessionStringStatement;
this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
this.scheduledExecutorService.schedule(() -> purgeDatabase(sessionDuration.getSeconds()), 0L, TimeUnit.SECONDS);
} }
@Override @Override
@ -113,7 +105,30 @@ public class JdbcSessionCodec implements Codec<Session>, Closeable {
@Override @Override
public void purge(long expiredAfterSeconds) { public void purge(long expiredAfterSeconds) {
if (expiredAfterSeconds > 0L) { if (expiredAfterSeconds > 0L) {
purgeDatabase(expiredAfterSeconds); LocalDateTime now = LocalDateTime.now();
LocalDateTime expiredBefore = now.minusSeconds(expiredAfterSeconds);
List<String> list = new ArrayList<>();
try {
Connection connection = dataSource.getConnection();
try (PreparedStatement preparedStatement = connection.prepareStatement(purgeSessionStringStatement)) {
preparedStatement.setTimestamp(1, Timestamp.valueOf(expiredBefore)); // created
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
list.add(resultSet.getString(1));
}
resultSet.close();
}
try (PreparedStatement preparedStatement = connection.prepareStatement(deleteSessionStringStatement)) {
for (String key : list) {
if (key != null) {
preparedStatement.setString(1, key);
preparedStatement.execute();
}
}
}
} catch (SQLException e) {
throw new UncheckedIOException(new IOException(e));
}
} }
} }
@ -148,36 +163,4 @@ public class JdbcSessionCodec implements Codec<Session>, Closeable {
preparedStatement.execute(); preparedStatement.execute();
} }
} }
private void purgeDatabase(long seconds) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime expiredBefore = now.minusSeconds(seconds);
List<String> list = new ArrayList<>();
try {
Connection connection = dataSource.getConnection();
try (PreparedStatement preparedStatement = connection.prepareStatement(purgeSessionStringStatement)) {
preparedStatement.setTimestamp(1, Timestamp.valueOf(expiredBefore)); // created
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
list.add(resultSet.getString(1));
}
resultSet.close();
}
try (PreparedStatement preparedStatement = connection.prepareStatement(deleteSessionStringStatement)) {
for (String key : list) {
if (key != null) {
preparedStatement.setString(1, key);
preparedStatement.execute();
}
}
}
} catch (SQLException e) {
throw new UncheckedIOException(new IOException(e));
}
}
@Override
public void close() throws IOException {
this.scheduledExecutorService.shutdown();
}
} }

View file

@ -4,7 +4,7 @@ import org.xbib.datastructures.common.Pair;
import org.xbib.net.http.HttpHeaderNames; import org.xbib.net.http.HttpHeaderNames;
import org.xbib.net.http.server.HttpException; import org.xbib.net.http.server.HttpException;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.UnknownExpectException; import org.xbib.net.http.server.UnknownExpectException;
public class HttpRequestValidator implements HttpHandler { public class HttpRequestValidator implements HttpHandler {
@ -13,9 +13,9 @@ public class HttpRequestValidator implements HttpHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws HttpException { public void handle(HttpRouterContext context) throws HttpException {
boolean unknownExpect = false; boolean unknownExpect = false;
for (Pair<String, String> entry : context.request().getHeaders().entries()) { for (Pair<String, String> entry : context.getRequestBuilder().getHeaders().entries()) {
String name = entry.getKey(); String name = entry.getKey();
String value = entry.getValue(); String value = entry.getValue();
if (name.equalsIgnoreCase(HttpHeaderNames.EXPECT) && !"100-continue".equalsIgnoreCase(value)) { if (name.equalsIgnoreCase(HttpHeaderNames.EXPECT) && !"100-continue".equalsIgnoreCase(value)) {

View file

@ -4,7 +4,7 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.application.Application; import org.xbib.net.http.server.application.Application;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import java.io.IOException; import java.io.IOException;
@ -19,29 +19,29 @@ class GroovyHttpResonseStatusTemplateResource extends GroovyTemplateResource {
private final String message; private final String message;
protected GroovyHttpResonseStatusTemplateResource(GroovyTemplateResourceHandler handler, protected GroovyHttpResonseStatusTemplateResource(GroovyTemplateResourceHandler handler,
HttpServerContext httpServerContext, HttpRouterContext httpRouterContext,
String indexFileName, String indexFileName,
HttpResponseStatus httpResponseStatus, HttpResponseStatus httpResponseStatus,
String message) throws IOException { String message) throws IOException {
super(handler, httpServerContext); super(handler, httpRouterContext);
this.indexFileName = indexFileName; this.indexFileName = indexFileName;
this.httpResponseStatus = httpResponseStatus; this.httpResponseStatus = httpResponseStatus;
this.message = message; this.message = message;
} }
@Override @Override
public void render(HttpServerContext httpServerContext) throws IOException { public void render(HttpRouterContext httpRouterContext) throws IOException {
logger.log(Level.FINEST, "rendering HTTP status by Groovy"); logger.log(Level.FINEST, "rendering HTTP status by Groovy");
httpServerContext.getAttributes().put("_status", httpResponseStatus); httpRouterContext.getAttributes().put("_status", httpResponseStatus);
httpServerContext.getAttributes().put("_message", message); httpRouterContext.getAttributes().put("_message", message);
httpServerContext.getAttributes().put("_resource", this); httpRouterContext.getAttributes().put("_resource", this);
Application application = httpServerContext.getAttributes().get(Application.class, "application"); Application application = httpRouterContext.getAttributes().get(Application.class, "application");
GroovyMarkupTemplateHandler groovyMarkupTemplateHandler = new GroovyMarkupTemplateHandler(application); GroovyMarkupTemplateHandler groovyMarkupTemplateHandler = new GroovyMarkupTemplateHandler(application);
logger.log(Level.FINEST, "handle groovyMarkupTemplateHandler"); logger.log(Level.FINEST, "handle groovyMarkupTemplateHandler");
groovyMarkupTemplateHandler.handle(httpServerContext); groovyMarkupTemplateHandler.handle(httpRouterContext);
super.render(httpServerContext); super.render(httpRouterContext);
GroovyTemplateRenderer groovyTemplateRenderer = new GroovyTemplateRenderer(); GroovyTemplateRenderer groovyTemplateRenderer = new GroovyTemplateRenderer();
groovyTemplateRenderer.handle(httpServerContext); groovyTemplateRenderer.handle(httpRouterContext);
} }
@Override @Override

View file

@ -3,7 +3,7 @@ package org.xbib.net.http.template.groovy;
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.HttpErrorHandler; import org.xbib.net.http.server.HttpErrorHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import java.io.IOException; import java.io.IOException;
@ -24,8 +24,8 @@ public class GroovyHttpStatusHandler extends GroovyTemplateResourceHandler imple
} }
@Override @Override
protected Resource createResource(HttpServerContext httpServerContext) throws IOException { protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException {
return new GroovyHttpResonseStatusTemplateResource(this, httpServerContext, return new GroovyHttpResonseStatusTemplateResource(this, httpRouterContext,
templateName, httpResponseStatus, message); templateName, httpResponseStatus, message);
} }
} }

View file

@ -3,7 +3,7 @@ package org.xbib.net.http.template.groovy;
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.HttpException; import org.xbib.net.http.server.HttpException;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import java.io.IOException; import java.io.IOException;
import java.util.logging.Level; import java.util.logging.Level;
@ -20,12 +20,12 @@ public class GroovyInternalServerErrorHandler extends GroovyTemplateResourceHand
} }
@Override @Override
protected Resource createResource(HttpServerContext httpServerContext) throws IOException { protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException {
return new GroovyHttpResonseStatusTemplateResource(this, httpServerContext, templateName, return new GroovyHttpResonseStatusTemplateResource(this, httpRouterContext, templateName,
HttpResponseStatus.INTERNAL_SERVER_ERROR, createMessage(httpServerContext)); HttpResponseStatus.INTERNAL_SERVER_ERROR, createMessage(httpRouterContext));
} }
private String createMessage(HttpServerContext context) throws IOException { private String createMessage(HttpRouterContext context) throws IOException {
Throwable throwable = context.getAttributes().get(Throwable.class, "_throwable"); Throwable throwable = context.getAttributes().get(Throwable.class, "_throwable");
if (throwable != null) { if (throwable != null) {
logger.log(Level.SEVERE, throwable.getMessage(), throwable); logger.log(Level.SEVERE, throwable.getMessage(), throwable);

View file

@ -8,7 +8,7 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.xbib.net.http.server.application.Application; import org.xbib.net.http.server.application.Application;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.application.Resolver; import org.xbib.net.http.server.application.Resolver;
import java.io.IOException; import java.io.IOException;
@ -59,7 +59,7 @@ public class GroovyMarkupTemplateHandler implements HttpHandler {
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
DefaultTemplateResolver templateResolver = context.getAttributes().get(DefaultTemplateResolver.class, "templateresolver"); DefaultTemplateResolver templateResolver = context.getAttributes().get(DefaultTemplateResolver.class, "templateresolver");
if (templateResolver == null) { if (templateResolver == null) {
context.getAttributes().put("templateresolver", this.templateResolver); context.getAttributes().put("templateresolver", this.templateResolver);

View file

@ -4,7 +4,7 @@ import groovy.text.markup.BaseTemplate;
import org.xbib.net.http.server.application.BaseApplicationModule; import org.xbib.net.http.server.application.BaseApplicationModule;
import org.xbib.net.http.server.application.Application; import org.xbib.net.http.server.application.Application;
import org.xbib.net.http.server.HttpRequest; import org.xbib.net.http.server.HttpRequest;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
@ -50,25 +50,25 @@ public class GroovyTemplateApplicationModule extends BaseApplicationModule {
} }
@Override @Override
public void onOpen(HttpServerContext httpServerContext) { public void onOpen(HttpRouterContext httpRouterContext) {
try { try {
groovyMarkupTemplateHandler.handle(httpServerContext); groovyMarkupTemplateHandler.handle(httpRouterContext);
} catch (IOException e) { } catch (IOException e) {
throw new UncheckedIOException(e); throw new UncheckedIOException(e);
} }
} }
@Override @Override
public void onOpen(HttpServerContext httpServerContext, HttpService httpService, HttpRequest httpRequest) { public void onOpen(HttpRouterContext httpRouterContext, HttpService httpService, HttpRequest httpRequest) {
httpServerContext.getAttributes().put("request", httpRequest); httpRouterContext.getAttributes().put("request", httpRequest);
httpServerContext.getAttributes().put("params", httpRequest.getParameter().asSingleValuedMap()); httpRouterContext.getAttributes().put("params", httpRequest.getParameter().asSingleValuedMap());
application.getModules().forEach(module -> httpServerContext.getAttributes().put(module.getName(), module)); application.getModules().forEach(module -> httpRouterContext.getAttributes().put(module.getName(), module));
} }
@Override @Override
public void onClose(HttpServerContext httpServerContext) { public void onClose(HttpRouterContext httpRouterContext) {
try { try {
groovyTemplateRenderer.handle(httpServerContext); groovyTemplateRenderer.handle(httpRouterContext);
} catch (IOException e) { } catch (IOException e) {
throw new UncheckedIOException(e); throw new UncheckedIOException(e);
} }

View file

@ -4,7 +4,7 @@ import groovy.lang.Writable;
import org.xbib.net.buffer.DataBuffer; import org.xbib.net.buffer.DataBuffer;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.HttpHandler; import org.xbib.net.http.server.HttpHandler;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
@ -12,27 +12,28 @@ import java.io.OutputStreamWriter;
import java.io.Writer; import java.io.Writer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
public class GroovyTemplateRenderer implements HttpHandler { public class GroovyTemplateRenderer implements HttpHandler {
public GroovyTemplateRenderer() { public GroovyTemplateRenderer() {
} }
@Override @Override
public void handle(HttpServerContext context) throws IOException { public void handle(HttpRouterContext context) throws IOException {
Writable writable = context.getAttributes().get(Writable.class, "writable"); Writable writable = context.getAttributes().get(Writable.class, "writable");
if (writable != null) { if (writable != null) {
DataBuffer dataBuffer = context.response().getDataBufferFactory().allocateBuffer(); DataBuffer dataBuffer = context.getDataBufferFactory().allocateBuffer();
try (OutputStream outputStream = dataBuffer.asOutputStream()) { try (OutputStream outputStream = dataBuffer.asOutputStream()) {
Writer writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8); Writer writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
writable.writeTo(writer); writable.writeTo(writer);
} }
HttpResponseStatus httpResponseStatus = context.getAttributes().get(HttpResponseStatus.class, "_status", HttpResponseStatus.OK); HttpResponseStatus httpResponseStatus = context.getAttributes().get(HttpResponseStatus.class, "_status", HttpResponseStatus.OK);
context.response() context.status(httpResponseStatus)
.setResponseStatus(httpResponseStatus) .header("cache-control", "no-cache") // override default must-revalidate behavior
.setHeader("cache-control", "no-cache") // override default must-revalidate behavior .header("content-length", Integer.toString(dataBuffer.writePosition()))
.setHeader("content-length", Integer.toString(dataBuffer.writePosition())) .header(CONTENT_TYPE, "text/html; charset=" + StandardCharsets.UTF_8.displayName())
.setContentType("text/html; charset=" + StandardCharsets.UTF_8.displayName()) .body(dataBuffer);
.write(dataBuffer);
} }
} }
} }

View file

@ -8,7 +8,7 @@ import org.xbib.net.http.HttpHeaderNames;
import org.xbib.net.http.HttpResponseStatus; import org.xbib.net.http.HttpResponseStatus;
import org.xbib.net.http.server.application.Application; import org.xbib.net.http.server.application.Application;
import org.xbib.net.http.server.HttpException; import org.xbib.net.http.server.HttpException;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.service.HttpService; import org.xbib.net.http.server.service.HttpService;
import org.xbib.net.http.server.resource.negotiate.LocaleNegotiator; import org.xbib.net.http.server.resource.negotiate.LocaleNegotiator;
import org.xbib.net.http.server.resource.HtmlTemplateResource; import org.xbib.net.http.server.resource.HtmlTemplateResource;
@ -41,25 +41,25 @@ public class GroovyTemplateResource extends HtmlTemplateResource {
private static final ReentrantLock lock = new ReentrantLock(); private static final ReentrantLock lock = new ReentrantLock();
protected GroovyTemplateResource(HtmlTemplateResourceHandler templateResourceHandler, protected GroovyTemplateResource(HtmlTemplateResourceHandler templateResourceHandler,
HttpServerContext httpServerContext) throws IOException { HttpRouterContext httpRouterContext) throws IOException {
super(templateResourceHandler, httpServerContext); super(templateResourceHandler, httpRouterContext);
} }
@Override @Override
public void render(HttpServerContext httpServerContext) throws IOException { public void render(HttpRouterContext httpRouterContext) throws IOException {
logger.log(Level.FINEST, () -> "rendering groovy template, path = " + getPath() + " isExists = " + isExists() + " isDirectory =" + isDirectory() ); logger.log(Level.FINEST, () -> "rendering groovy template, path = " + getPath() + " isExists = " + isExists() + " isDirectory =" + isDirectory() );
Application application = httpServerContext.getAttributes().get(Application.class, "application"); Application application = httpRouterContext.getAttributes().get(Application.class, "application");
if (application == null) { if (application == null) {
logger.log(Level.WARNING, "application is null"); logger.log(Level.WARNING, "application is null");
return; return;
} }
TemplateEngine templateEngine = httpServerContext.getAttributes().get(TemplateEngine.class, "templateengine"); TemplateEngine templateEngine = httpRouterContext.getAttributes().get(TemplateEngine.class, "templateengine");
if (templateEngine == null) { if (templateEngine == null) {
logger.log(Level.WARNING, "template engine is null"); logger.log(Level.WARNING, "template engine is null");
return; return;
} }
Path templatePath = getPath(); Path templatePath = getPath();
HttpService service = httpServerContext.getAttributes().get(HttpService.class, "service"); HttpService service = httpRouterContext.getAttributes().get(HttpService.class, "service");
if (service instanceof GroovyTemplateService groovyTemplateService) { if (service instanceof GroovyTemplateService groovyTemplateService) {
if (groovyTemplateService.getTemplateName() != null) { if (groovyTemplateService.getTemplateName() != null) {
templatePath = application.resolve(groovyTemplateService.getTemplateName()); templatePath = application.resolve(groovyTemplateService.getTemplateName());
@ -69,7 +69,7 @@ public class GroovyTemplateResource extends HtmlTemplateResource {
} }
} }
// status response handlers have priority // status response handlers have priority
GroovyHttpResonseStatusTemplateResource resource = httpServerContext.getAttributes().get(GroovyHttpResonseStatusTemplateResource.class, "_resource"); GroovyHttpResonseStatusTemplateResource resource = httpRouterContext.getAttributes().get(GroovyHttpResonseStatusTemplateResource.class, "_resource");
if (resource != null) { if (resource != null) {
String indexFileName = resource.getIndexFileName(); String indexFileName = resource.getIndexFileName();
if (indexFileName != null) { if (indexFileName != null) {
@ -78,7 +78,7 @@ public class GroovyTemplateResource extends HtmlTemplateResource {
logger.log(Level.FINEST, "rendering Groovy HTTP status response with templatePath = " + templatePath); logger.log(Level.FINEST, "rendering Groovy HTTP status response with templatePath = " + templatePath);
} else { } else {
// override if 'templatePath' attribute is set // override if 'templatePath' attribute is set
String overridePath = httpServerContext.getAttributes().get(String.class, "templatePath"); String overridePath = httpRouterContext.getAttributes().get(String.class, "templatePath");
if (overridePath != null) { if (overridePath != null) {
logger.log(Level.FINEST, "found override templatePath = " + overridePath); logger.log(Level.FINEST, "found override templatePath = " + overridePath);
templatePath = application.resolve(overridePath); templatePath = application.resolve(overridePath);
@ -95,12 +95,12 @@ public class GroovyTemplateResource extends HtmlTemplateResource {
templatePath = getPath().resolve(getIndexFileName()); templatePath = getPath().resolve(getIndexFileName());
} else { } else {
logger.log(Level.WARNING, "unable to render a directory without index file name, this is forbidden"); logger.log(Level.WARNING, "unable to render a directory without index file name, this is forbidden");
throw new HttpException("forbidden", httpServerContext, HttpResponseStatus.FORBIDDEN); throw new HttpException("forbidden", httpRouterContext, HttpResponseStatus.FORBIDDEN);
} }
} }
if (templatePath == null) { if (templatePath == null) {
logger.log(Level.WARNING, "unable to render a null path"); logger.log(Level.WARNING, "unable to render a null path");
throw new HttpException("internal path error", httpServerContext, HttpResponseStatus.INTERNAL_SERVER_ERROR); throw new HttpException("internal path error", httpRouterContext, HttpResponseStatus.INTERNAL_SERVER_ERROR);
} }
templates.computeIfAbsent(templatePath, path -> { templates.computeIfAbsent(templatePath, path -> {
try { try {
@ -113,22 +113,22 @@ public class GroovyTemplateResource extends HtmlTemplateResource {
Template template = templates.get(templatePath); Template template = templates.get(templatePath);
Logger templateLogger = Logger.getLogger("template." + getName().replace('/', '.')); Logger templateLogger = Logger.getLogger("template." + getName().replace('/', '.'));
Binding binding = new Binding(); Binding binding = new Binding();
httpServerContext.getAttributes().forEach(binding::setVariable); httpRouterContext.getAttributes().forEach(binding::setVariable);
binding.setVariable("logger", templateLogger); binding.setVariable("logger", templateLogger);
binding.setVariable("log", templateLogger); binding.setVariable("log", templateLogger);
application.getModules().forEach(m -> binding.setVariable(m.getName(), m)); application.getModules().forEach(m -> binding.setVariable(m.getName(), m));
DefaultTemplateResolver templateResolver = httpServerContext.getAttributes().get(DefaultTemplateResolver.class, "templateresolver"); DefaultTemplateResolver templateResolver = httpRouterContext.getAttributes().get(DefaultTemplateResolver.class, "templateresolver");
if (templateResolver == null) { if (templateResolver == null) {
// for Groovy template engines without a resolver, no need to set a locale // for Groovy template engines without a resolver, no need to set a locale
Writable writable = template.make(binding.getVariables()); Writable writable = template.make(binding.getVariables());
httpServerContext.getAttributes().put("writable", writable); httpRouterContext.getAttributes().put("writable", writable);
return; return;
} }
if (!negotiateLocale) { if (!negotiateLocale) {
// if no locale negotiation configured, set always the applicaiton locale. This constant value never changes. // if no locale negotiation configured, set always the applicaiton locale. This constant value never changes.
templateResolver.setLocale(application.getLocale()); templateResolver.setLocale(application.getLocale());
Writable writable = template.make(binding.getVariables()); Writable writable = template.make(binding.getVariables());
httpServerContext.getAttributes().put("writable", writable); httpRouterContext.getAttributes().put("writable", writable);
return; return;
} }
// handle programmatic locale change plus template making under lock so no other request/response can interrupt us // handle programmatic locale change plus template making under lock so no other request/response can interrupt us
@ -137,7 +137,7 @@ public class GroovyTemplateResource extends HtmlTemplateResource {
lock.lock(); lock.lock();
templateResolver.setLocale(application.getLocale()); templateResolver.setLocale(application.getLocale());
// language from request overrides application locale // language from request overrides application locale
String acceptLanguage = httpServerContext.request().getHeaders().get(HttpHeaderNames.ACCEPT_LANGUAGE); String acceptLanguage = httpRouterContext.getRequestBuilder().getHeaders().get(HttpHeaderNames.ACCEPT_LANGUAGE);
if (acceptLanguage != null) { if (acceptLanguage != null) {
Locale negotiatedLocale = LocaleNegotiator.findLocale(acceptLanguage); Locale negotiatedLocale = LocaleNegotiator.findLocale(acceptLanguage);
if (negotiatedLocale != null) { if (negotiatedLocale != null) {
@ -146,12 +146,12 @@ public class GroovyTemplateResource extends HtmlTemplateResource {
} }
} }
Writable writable = template.make(binding.getVariables()); Writable writable = template.make(binding.getVariables());
httpServerContext.getAttributes().put("writable", writable); httpRouterContext.getAttributes().put("writable", writable);
} catch (Exception e) { } catch (Exception e) {
// fail silently by ignoring negotation // fail silently by ignoring negotation
templateResolver.setLocale(application.getLocale()); templateResolver.setLocale(application.getLocale());
Writable writable = template.make(binding.getVariables()); Writable writable = template.make(binding.getVariables());
httpServerContext.getAttributes().put("writable", writable); httpRouterContext.getAttributes().put("writable", writable);
} finally { } finally {
lock.unlock(); lock.unlock();
} }

View file

@ -1,7 +1,7 @@
package org.xbib.net.http.template.groovy; package org.xbib.net.http.template.groovy;
import org.xbib.net.Resource; import org.xbib.net.Resource;
import org.xbib.net.http.server.HttpServerContext; import org.xbib.net.http.server.route.HttpRouterContext;
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler; import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
import java.io.IOException; import java.io.IOException;
@ -18,7 +18,7 @@ public class GroovyTemplateResourceHandler extends HtmlTemplateResourceHandler {
} }
@Override @Override
protected Resource createResource(HttpServerContext httpServerContext) throws IOException { protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException {
return new GroovyTemplateResource(this, httpServerContext); return new GroovyTemplateResource(this, httpRouterContext);
} }
} }

View file

@ -1,12 +1,12 @@
dependencyResolutionManagement { dependencyResolutionManagement {
versionCatalogs { versionCatalogs {
libs { libs {
version('gradle', '8.0.2') version('gradle', '8.1.1')
version('junit', '5.9.2') version('junit', '5.9.2')
version('groovy', '4.0.11') version('groovy', '4.0.11')
version('netty', '4.1.91.Final') version('netty', '4.1.92.Final')
version('netty-tcnative', '2.0.59.Final') version('netty-tcnative', '2.0.60.Final')
version('datastructures', '2.0.0') version('datastructures', '2.3.0')
version('config', '5.0.2') version('config', '5.0.2')
version('net', '3.2.0') version('net', '3.2.0')
library('junit-jupiter-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit') library('junit-jupiter-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit')
@ -20,11 +20,10 @@ dependencyResolutionManagement {
library('netty-epoll', 'io.netty', 'netty-transport-native-epoll').versionRef('netty') library('netty-epoll', 'io.netty', 'netty-transport-native-epoll').versionRef('netty')
library('netty-kqueue', 'io.netty', 'netty-transport-native-kqueue').versionRef('netty') library('netty-kqueue', 'io.netty', 'netty-transport-native-kqueue').versionRef('netty')
library('netty-boringssl', 'io.netty', 'netty-tcnative-boringssl-static').versionRef('netty-tcnative') library('netty-boringssl', 'io.netty', 'netty-tcnative-boringssl-static').versionRef('netty-tcnative')
library('bouncycastle', 'org.bouncycastle', 'bcpkix-jdk18on').version('1.72') library('bouncycastle', 'org.bouncycastle', 'bcpkix-jdk18on').version('1.73')
library('conscrypt', 'org.conscrypt', 'conscrypt-openjdk-uber').version('2.5.2') library('conscrypt', 'org.conscrypt', 'conscrypt-openjdk-uber').version('2.5.2')
library('jackson', 'com.fasterxml.jackson.core', 'jackson-databind').version('2.12.7') library('jackson', 'com.fasterxml.jackson.core', 'jackson-databind').version('2.14.2')
library('jna', 'net.java.dev.jna', 'jna').version('5.12.1') library('jna', 'net.java.dev.jna', 'jna').version('5.13.0')
library('oracle', 'com.oracle.database.jdbc', 'ojdbc11').version('21.7.0.0')
library('groovy-templates', 'org.apache.groovy', 'groovy-templates').versionRef('groovy') library('groovy-templates', 'org.apache.groovy', 'groovy-templates').versionRef('groovy')
library('webjars-bootstrap', 'org.webjars', 'bootstrap').version('5.2.3') library('webjars-bootstrap', 'org.webjars', 'bootstrap').version('5.2.3')
library('webjars-jquery', 'org.webjars', 'jquery').version('3.6.4') library('webjars-jquery', 'org.webjars', 'jquery').version('3.6.4')
@ -39,8 +38,8 @@ dependencyResolutionManagement {
library('config', 'org.xbib', 'config').versionRef('config') library('config', 'org.xbib', 'config').versionRef('config')
library('settings-datastructures-json', 'org.xbib', 'settings-datastructures-json').versionRef('config') library('settings-datastructures-json', 'org.xbib', 'settings-datastructures-json').versionRef('config')
library('settings-datastructures-yaml', 'org.xbib', 'settings-datastructures-yaml').versionRef('config') library('settings-datastructures-yaml', 'org.xbib', 'settings-datastructures-yaml').versionRef('config')
library('jdbc-query', 'org.xbib', 'jdbc-query').version('1.0.0') library('jdbc-query', 'org.xbib', 'jdbc-query').version('1.1.0')
library('jdbc-connection-pool', 'org.xbib', 'jdbc-connection-pool').version('1.0.0') library('jdbc-connection-pool', 'org.xbib', 'jdbc-connection-pool').version('1.1.0')
library('event', 'org.xbib', 'event').version('0.0.1') library('event', 'org.xbib', 'event').version('0.0.1')
plugin('publish', 'com.gradle.plugin-publish').version('0.18.0') plugin('publish', 'com.gradle.plugin-publish').version('0.18.0')
} }