refactoring HttpServerContext into HttpRouterContext
This commit is contained in:
parent
8786e768e1
commit
6c10666fe5
84 changed files with 1206 additions and 1179 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
||||||
}
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() + "\"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 : "";
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 + "/") : "/";
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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}.
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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')
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue