package io.undertow.servlet.core;
import java.security.AccessController;
import java.util.HashSet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.session.Session;
import io.undertow.server.session.SessionListener;
import io.undertow.servlet.api.Deployment;
import io.undertow.servlet.api.ThreadSetupHandler;
import io.undertow.servlet.handlers.ServletRequestContext;
import io.undertow.servlet.spec.HttpSessionImpl;
public class SessionListenerBridge implements SessionListener {
public static final String IO_UNDERTOW = "io.undertow";
private final ApplicationListeners applicationListeners;
private final ServletContext servletContext;
private final ThreadSetupHandler.Action<Void, Session> destroyedAction;
public SessionListenerBridge(final Deployment deployment, final ApplicationListeners applicationListeners, final ServletContext servletContext) {
this.applicationListeners = applicationListeners;
this.servletContext = servletContext;
this.destroyedAction = deployment.createThreadSetupAction(new ThreadSetupHandler.Action<Void, Session>() {
@Override
public Void call(HttpServerExchange exchange, Session session) throws ServletException {
doDestroy(session);
return null;
}
});
}
@Override
public void sessionCreated(final Session session, final HttpServerExchange exchange) {
final HttpSessionImpl httpSession = SecurityActions.forSession(session, servletContext, true);
applicationListeners.sessionCreated(httpSession);
}
@Override
public void sessionDestroyed(final Session session, final HttpServerExchange exchange, final SessionDestroyedReason reason) {
if (reason == SessionDestroyedReason.TIMEOUT) {
try {
destroyedAction.call(exchange, session);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
doDestroy(session);
}
ServletRequestContext current = SecurityActions.currentServletRequestContext();
Session underlying = null;
if (current != null && current.getSession() != null) {
if (System.getSecurityManager() == null) {
underlying = current.getSession().getSession();
} else {
underlying = AccessController.doPrivileged(new HttpSessionImpl.UnwrapSessionAction(current.getSession()));
}
}
if (current != null && underlying == session) {
current.setSession(null);
}
}
private void doDestroy(Session session) {
final HttpSessionImpl httpSession = SecurityActions.forSession(session, servletContext, false);
applicationListeners.sessionDestroyed(httpSession);
HashSet<String> names = new HashSet<>(session.getAttributeNames());
for (String attribute : names) {
session.removeAttribute(attribute);
}
}
@Override
public void attributeAdded(final Session session, final String name, final Object value) {
if (name.startsWith(IO_UNDERTOW)) {
return;
}
final HttpSessionImpl httpSession = SecurityActions.forSession(session, servletContext, false);
applicationListeners.httpSessionAttributeAdded(httpSession, name, value);
if (value instanceof HttpSessionBindingListener) {
((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(httpSession, name, value));
}
}
@Override
public void attributeUpdated(final Session session, final String name, final Object value, final Object old) {
if (name.startsWith(IO_UNDERTOW)) {
return;
}
final HttpSessionImpl httpSession = SecurityActions.forSession(session, servletContext, false);
if (old != value) {
if (old instanceof HttpSessionBindingListener) {
((HttpSessionBindingListener) old).valueUnbound(new HttpSessionBindingEvent(httpSession, name, old));
}
applicationListeners.httpSessionAttributeReplaced(httpSession, name, old);
}
if (value instanceof HttpSessionBindingListener) {
((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(httpSession, name, value));
}
}
@Override
public void attributeRemoved(final Session session, final String name, final Object old) {
if (name.startsWith(IO_UNDERTOW)) {
return;
}
final HttpSessionImpl httpSession = SecurityActions.forSession(session, servletContext, false);
if (old != null) {
applicationListeners.httpSessionAttributeRemoved(httpSession, name, old);
if (old instanceof HttpSessionBindingListener) {
((HttpSessionBindingListener) old).valueUnbound(new HttpSessionBindingEvent(httpSession, name, old));
}
}
}
@Override
public void sessionIdChanged(Session session, String oldSessionId) {
}
}