add persist session handler, remove hebis test code
This commit is contained in:
parent
b1fb1cff50
commit
30926d6052
12 changed files with 118 additions and 98 deletions
|
@ -1,5 +1,5 @@
|
|||
group = org.xbib
|
||||
name = net-http
|
||||
version = 3.4.1
|
||||
version = 3.4.2
|
||||
|
||||
org.gradle.warning.mode = ALL
|
||||
|
|
|
@ -117,29 +117,6 @@ class Https1Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHebisGetRequest() throws Exception {
|
||||
// we test HEBIS here with strange certificate setup and TLS 1.2 only
|
||||
NettyHttpClientConfig config = new NettyHttpsClientConfig()
|
||||
.setDebug(true);
|
||||
try (NettyHttpClient client = NettyHttpClient.builder()
|
||||
.setConfig(config)
|
||||
.build()){
|
||||
HttpRequest request = HttpRequest.post()
|
||||
.setURL("https://hebis.rz.uni-frankfurt.de/HEBCGI/vuefl_recv_data.pl")
|
||||
.setResponseListener(resp ->
|
||||
logger.log(Level.INFO,
|
||||
"got response: " +
|
||||
" status = " + resp.getStatus() +
|
||||
" headers = " + resp.getHeaders() +
|
||||
" body = " + resp.getBodyAsChars(StandardCharsets.UTF_8) +
|
||||
" ssl = " + dumpCertificates((HttpsResponse) resp))
|
||||
)
|
||||
.build();
|
||||
client.execute(request).get().close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSequentialRequests() throws Exception {
|
||||
NettyHttpClientConfig config = new NettyHttpsClientConfig()
|
||||
|
|
|
@ -43,19 +43,6 @@ public class JdkClientTest {
|
|||
logger.log(Level.INFO, response.body());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHebisGetRequest() throws Exception {
|
||||
HttpClient httpClient = HttpClient.newBuilder()
|
||||
.version(HttpClient.Version.HTTP_1_1)
|
||||
.build();
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(new URI("https://hebis.rz.uni-frankfurt.de/HEBCGI/vuefl_recv_data.pl"))
|
||||
.build();
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
logger.log(Level.INFO, Integer.toString(response.statusCode()));
|
||||
logger.log(Level.INFO, response.body());
|
||||
}
|
||||
|
||||
private static HttpRequest.BodyPublisher buildFormDataFromMap(Map<String, Object> data) {
|
||||
var builder = new StringBuilder();
|
||||
for (Map.Entry<String, Object> entry : data.entrySet()) {
|
||||
|
|
|
@ -3,16 +3,11 @@ package org.xbib.net.http.server.application.web;
|
|||
import java.nio.file.Paths;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.xbib.net.http.cookie.SameSite;
|
||||
import org.xbib.net.http.server.application.BaseApplication;
|
||||
import org.xbib.net.http.server.HttpHandler;
|
||||
import org.xbib.net.http.server.route.HttpRouterContext;
|
||||
import org.xbib.net.http.server.persist.Codec;
|
||||
import org.xbib.net.http.server.session.IncomingSessionHandler;
|
||||
import org.xbib.net.http.server.session.OutgoingSessionHandler;
|
||||
import org.xbib.net.http.server.session.Session;
|
||||
import org.xbib.net.http.server.session.file.FileJsonSessionCodec;
|
||||
import org.xbib.net.util.RandomUtil;
|
||||
|
||||
public class WebApplication extends BaseApplication {
|
||||
|
||||
|
@ -28,39 +23,9 @@ public class WebApplication extends BaseApplication {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Codec<Session> newSessionCodec(HttpRouterContext httpRouterContext) {
|
||||
return new FileJsonSessionCodec(sessionName, this, 1024, Duration.ofDays(1),
|
||||
Paths.get("/var/tmp/session"));
|
||||
}
|
||||
|
||||
protected HttpHandler newIncomingSessionHandler(HttpRouterContext httpRouterContext) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Codec<Session> sessionCodec = httpRouterContext.getAttributes().get(Codec.class, "sessioncodec");
|
||||
return new IncomingSessionHandler(
|
||||
getSecret(),
|
||||
"HmacSHA1",
|
||||
sessionName,
|
||||
sessionCodec,
|
||||
getStaticFileSuffixes(),
|
||||
"user_id",
|
||||
"e_user_id",
|
||||
() -> RandomUtil.randomString(16));
|
||||
}
|
||||
|
||||
protected OutgoingSessionHandler newOutgoingSessionHandler(HttpRouterContext httpRouterContext) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Codec<Session> sessionCodec = httpRouterContext.getAttributes().get(Codec.class, "sessioncodec");
|
||||
return new OutgoingSessionHandler(
|
||||
getSecret(),
|
||||
"HmacSHA1",
|
||||
sessionName,
|
||||
sessionCodec,
|
||||
getStaticFileSuffixes(),
|
||||
"user_id",
|
||||
"e_user_id",
|
||||
Duration.ofDays(1),
|
||||
true,
|
||||
false,
|
||||
SameSite.LAX);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package org.xbib.net.http.server.application;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
@ -30,6 +29,7 @@ import org.xbib.net.http.server.render.HttpResponseRenderer;
|
|||
import org.xbib.net.http.server.route.HttpRouter;
|
||||
import org.xbib.net.http.server.session.IncomingSessionHandler;
|
||||
import org.xbib.net.http.server.session.OutgoingSessionHandler;
|
||||
import org.xbib.net.http.server.session.PersistSessionHandler;
|
||||
import org.xbib.net.http.server.session.Session;
|
||||
import org.xbib.net.http.server.session.memory.MemoryPropertiesSessionCodec;
|
||||
import org.xbib.net.http.server.validate.HttpRequestValidator;
|
||||
|
@ -149,7 +149,8 @@ public class BaseApplication implements Application {
|
|||
Codec<Session> sessionCodec = newSessionCodec(httpRouterContext);
|
||||
httpRouterContext.getAttributes().put("sessioncodec", sessionCodec);
|
||||
httpRouterContext.addOpenHandler(newIncomingSessionHandler(sessionCodec));
|
||||
httpRouterContext.addCloseHandler(newOutgoingSessionHandler(sessionCodec));
|
||||
httpRouterContext.addCloseHandler(newOutgoingSessionHandler());
|
||||
httpRouterContext.addReleaseHandler(newPersistSessionHandler(sessionCodec));
|
||||
}
|
||||
httpRouterContext.addCloseHandler(newOutgoingCookieHandler());
|
||||
return httpRouterContext;
|
||||
|
@ -196,12 +197,11 @@ public class BaseApplication implements Application {
|
|||
() -> RandomUtil.randomString(16));
|
||||
}
|
||||
|
||||
protected HttpHandler newOutgoingSessionHandler(Codec<Session> sessionCodec) {
|
||||
protected HttpHandler newOutgoingSessionHandler() {
|
||||
return new OutgoingSessionHandler(
|
||||
getSecret(),
|
||||
"HmacSHA1",
|
||||
sessionName,
|
||||
sessionCodec,
|
||||
getStaticFileSuffixes(),
|
||||
"user_id",
|
||||
"e_user_id",
|
||||
|
@ -212,6 +212,10 @@ public class BaseApplication implements Application {
|
|||
);
|
||||
}
|
||||
|
||||
protected HttpHandler newPersistSessionHandler(Codec<Session> sessionCodec) {
|
||||
return new PersistSessionHandler(sessionCodec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreated(Session session) {
|
||||
logger.log(Level.FINER, "session name = " + sessionName + " created = " + session);
|
||||
|
|
|
@ -108,8 +108,6 @@ public class BaseHttpRouter implements HttpRouter {
|
|||
try {
|
||||
route(application, httpRouterContext, httpRouteResolverResults);
|
||||
} finally {
|
||||
application.onClose(httpRouterContext);
|
||||
// outgoing cookie/session
|
||||
httpRouterContext.getCloseHandlers().forEach(h -> {
|
||||
try {
|
||||
h.handle(httpRouterContext);
|
||||
|
@ -117,6 +115,14 @@ public class BaseHttpRouter implements HttpRouter {
|
|||
routeToErrorHandler(httpRouterContext, e);
|
||||
}
|
||||
});
|
||||
application.onClose(httpRouterContext);
|
||||
httpRouterContext.getReleaseHandlers().forEach(h -> {
|
||||
try {
|
||||
h.handle(httpRouterContext);
|
||||
} catch (Exception e) {
|
||||
routeToErrorHandler(httpRouterContext, e);
|
||||
}
|
||||
});
|
||||
application.releaseContext(httpRouterContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ public class BaseHttpRouterContext implements HttpRouterContext {
|
|||
|
||||
private final List<HttpHandler> closeHandlers;
|
||||
|
||||
private final List<HttpHandler> releaseeHandlers;
|
||||
|
||||
private String contextPath;
|
||||
|
||||
private URL contextURL;
|
||||
|
@ -63,6 +65,7 @@ public class BaseHttpRouterContext implements HttpRouterContext {
|
|||
this.httpResponseBuilder = httpResponseBuilder;
|
||||
this.openHandlers = new LinkedList<>();
|
||||
this.closeHandlers = new LinkedList<>();
|
||||
this.releaseeHandlers = new LinkedList<>();
|
||||
this.attributes = new BaseAttributes();
|
||||
this.attributes.put("application", application);
|
||||
this.attributes.put("domain", domain);
|
||||
|
@ -91,6 +94,16 @@ public class BaseHttpRouterContext implements HttpRouterContext {
|
|||
return closeHandlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReleaseHandler(HttpHandler handler) {
|
||||
this.releaseeHandlers.add(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HttpHandler> getReleaseHandlers() {
|
||||
return releaseeHandlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Application getApplication() {
|
||||
return application;
|
||||
|
|
|
@ -17,7 +17,6 @@ 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 {
|
||||
|
@ -32,14 +31,16 @@ public interface HttpRouterContext {
|
|||
|
||||
List<HttpHandler> getCloseHandlers();
|
||||
|
||||
void addReleaseHandler(HttpHandler handler);
|
||||
|
||||
List<HttpHandler> getReleaseHandlers();
|
||||
|
||||
HttpRequestBuilder getRequestBuilder();
|
||||
|
||||
void setRequest(HttpRequest httpRequest);
|
||||
|
||||
HttpRequest getRequest();
|
||||
|
||||
//HttpResponseBuilder getResponseBuilder();
|
||||
|
||||
Attributes getAttributes();
|
||||
|
||||
void done();
|
||||
|
|
|
@ -71,6 +71,7 @@ public class IncomingSessionHandler implements HttpHandler {
|
|||
if (suffix != null && suffixes.contains(suffix)) {
|
||||
return;
|
||||
}
|
||||
Map<String, Object> payload = null;
|
||||
Session session = null;
|
||||
CookieBox cookieBox = context.getAttributes().get(CookieBox.class, "incomingcookies");
|
||||
if (cookieBox != null) {
|
||||
|
@ -78,13 +79,8 @@ public class IncomingSessionHandler implements HttpHandler {
|
|||
if (cookie.name().equals(sessionCookieName)) {
|
||||
if (session == null) {
|
||||
try {
|
||||
Map<String, Object> payload = decodeCookie(cookie);
|
||||
logger.log(Level.FINER, "cookie decoded");
|
||||
payload = decodeCookie(cookie);
|
||||
session = toSession(payload);
|
||||
UserProfile userProfile = newUserProfile(payload, session);
|
||||
if (userProfile != null) {
|
||||
context.getAttributes().put("userprofile", userProfile);
|
||||
}
|
||||
} catch (CookieSignatureException e) {
|
||||
// set exception in context to discard broken cookie later and render exception message
|
||||
context.getAttributes().put("_throwable", e);
|
||||
|
@ -93,7 +89,7 @@ public class IncomingSessionHandler implements HttpHandler {
|
|||
throw new HttpException("unable to create session", context, HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
} else {
|
||||
logger.log(Level.WARNING, "received extra session cookie, something is wrong, ignoring");
|
||||
logger.log(Level.WARNING, "received extra session cookie of same name, something is wrong, ignoring");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,8 +102,14 @@ public class IncomingSessionHandler implements HttpHandler {
|
|||
throw new HttpException("unable to create session", context, HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
if (payload != null) {
|
||||
UserProfile userProfile = newUserProfile(payload, session);
|
||||
if (userProfile != null) {
|
||||
context.getAttributes().put("userprofile", userProfile);
|
||||
}
|
||||
}
|
||||
logger.log(Level.FINEST, "incoming session ID = " + session.id() + " keys = " + session.keySet());
|
||||
context.getAttributes().put("session", session);
|
||||
logger.log(Level.FINEST, "incoming session " + session.id());
|
||||
}
|
||||
|
||||
private Map<String, Object> decodeCookie(Cookie cookie) throws IOException,
|
||||
|
|
|
@ -24,7 +24,6 @@ import org.xbib.net.http.server.route.HttpRouterContext;
|
|||
import org.xbib.net.http.server.application.Application;
|
||||
import org.xbib.net.http.server.cookie.CookieSignatureException;
|
||||
import org.xbib.net.http.server.cookie.CookieSignatureUtil;
|
||||
import org.xbib.net.http.server.persist.Codec;
|
||||
|
||||
public class OutgoingSessionHandler implements HttpHandler {
|
||||
|
||||
|
@ -38,8 +37,6 @@ public class OutgoingSessionHandler implements HttpHandler {
|
|||
|
||||
private final Duration sessionDuration;
|
||||
|
||||
private final Codec<Session> sessionCodec;
|
||||
|
||||
private final Set<String> suffixes;
|
||||
|
||||
private final String sessionUserName;
|
||||
|
@ -55,7 +52,6 @@ public class OutgoingSessionHandler implements HttpHandler {
|
|||
public OutgoingSessionHandler(String sessionSecret,
|
||||
String sessionCookieAlgorithm,
|
||||
String sessionCookieName,
|
||||
Codec<Session> sessionCodec,
|
||||
Set<String> suffixes,
|
||||
String sessionUserName,
|
||||
String sessionEffectiveUserName,
|
||||
|
@ -66,7 +62,6 @@ public class OutgoingSessionHandler implements HttpHandler {
|
|||
this.sessionSecret = sessionSecret;
|
||||
this.sessionCookieAlgorithm = sessionCookieAlgorithm;
|
||||
this.sessionCookieName = sessionCookieName;
|
||||
this.sessionCodec = sessionCodec;
|
||||
this.suffixes = suffixes;
|
||||
this.sessionUserName = sessionUserName;
|
||||
this.sessionEffectiveUserName = sessionEffectiveUserName;
|
||||
|
@ -113,17 +108,16 @@ public class OutgoingSessionHandler implements HttpHandler {
|
|||
session.put(sessionEffectiveUserName, userProfile.getEffectiveUserId());
|
||||
}
|
||||
}
|
||||
sessionCodec.write(session.id(), session);
|
||||
Cookie cookie = encodeCookie(session, host, path);
|
||||
if (cookie != null) {
|
||||
cookieBox.add(cookie);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
throw new HttpException("unable to create session cookie", context, HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
throw new HttpException("unable to create session data for cookie", context, HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
logger.log(Level.FINEST, "outgoing cookies = " + cookieBox);
|
||||
logger.log(Level.FINEST, "prepared outgoing cookies = " + cookieBox);
|
||||
context.getAttributes().put("outgoingcookies", cookieBox);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package org.xbib.net.http.server.session;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.xbib.net.http.HttpResponseStatus;
|
||||
import org.xbib.net.http.server.HttpException;
|
||||
import org.xbib.net.http.server.HttpHandler;
|
||||
import org.xbib.net.http.server.persist.Codec;
|
||||
import org.xbib.net.http.server.route.HttpRouterContext;
|
||||
|
||||
public class PersistSessionHandler implements HttpHandler {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(PersistSessionHandler.class.getName());
|
||||
|
||||
private final Codec<Session> sessionCodec;
|
||||
|
||||
public PersistSessionHandler(Codec<Session> sessionCodec) {
|
||||
this.sessionCodec = sessionCodec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpRouterContext context) throws IOException {
|
||||
Session session = context.getAttributes().get(Session.class, "session");
|
||||
if (session != null) {
|
||||
try {
|
||||
logger.log(Level.FINEST, "writing session id " + session.id() + " keys = " + session.keySet());
|
||||
sessionCodec.write(session.id(), session);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
throw new HttpException("unable to create session data for cookie", context, HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package org.xbib.net.http.server.session;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Duration;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.net.http.server.persist.Codec;
|
||||
import org.xbib.net.http.server.session.file.FileJsonSessionCodec;
|
||||
import org.xbib.net.util.RandomUtil;
|
||||
|
||||
public class JsonSessionTest {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(JsonSessionTest.class.getName());
|
||||
|
||||
@Test
|
||||
void testJsonSession() throws IOException {
|
||||
Codec<Session> sessionCodec = newSessionCodec();
|
||||
Session session = create(sessionCodec, () -> RandomUtil.randomString(16));
|
||||
session.put("a", "b");
|
||||
sessionCodec.write(session.id(), session);
|
||||
Session session1 = sessionCodec.read(session.id());
|
||||
logger.log(Level.INFO, session1.get("a").toString());
|
||||
}
|
||||
|
||||
private Codec<Session> newSessionCodec() {
|
||||
return new FileJsonSessionCodec("SESSION-TEST", null, 1024,
|
||||
Duration.ofDays(1), Paths.get("/var/tmp/session-test"));
|
||||
}
|
||||
|
||||
private Session create(Codec<Session> sessionCodec, Supplier<String> sessionIdGenerator) throws IOException {
|
||||
return sessionCodec.create(sessionIdGenerator.get());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue