I am developing a Java web application that will run on a secure intranet and does not require a user login. The application does, however, keep conversational state in an HttpSession
. User input is not persisted to the database until they explicitly click a save button at some stage in the conversation. Until then, their input is retained in the HttpSession
object. If their session expires, the user must be directed to a page that informs them of the session expiry.
This is working fine except for a problem with the redirect. When a user allows their session to sit idle for longer than the time defined in <session-timeout>
, the session expires as expected. However, my attempt to redirect the user to a simple "Your session has expired" page seems to have backfired. The redirect works alright, but unless the user closes all the open browser windows on their desktop (not just the ones that were open to my web app page) they will continue being redirected to the "session expired" page forever.
Here are my constraints:
- Client workstations use Internet Explorer. This is company-wide and will not change anytime soon.
- Users will have mulitple instances of IE open on their desktop as part of their normal workflow. Telling them to close all instances of IE is not acceptable.
- Not using any AJAX components in this web app
I've implemented the redirect with a Java Servlet Filter
. Here are the relevant code snippets:
@Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain filterChain)
throws IOException, ServletException {
Validate.notNull(filterConfig);
Validate.isTrue(request instanceof HttpServletRequest);
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String requestedSessionId = httpServletRequest.getRequestedSessionId();
logger.info("requestedSessionId: " + requestedSessionId);
HttpSession httpSession = httpServletRequest.getSession(false);
if (requestedSessionId == null) {
// No need to do anything here if no session exists yet
logger.debug("No session exists yet");
filterChain.doFilter(request, response);
} else {
if (httpSession == null) {
Validate.isTrue(response instanceof HttpServletResponse);
HttpServletResponse httpServletResponse =
(HttpServletResponse) response;
handleSessionExpired(
httpServletRequest,
httpServletResponse);
} else {
if (logger.isDebugEnabled()) {
logger.debug("Session OK | requested URL: " +
httpServletRequest.getRequestURL().toString());
}
filterChain.doFilter(request, response);
}
}
}
}
private void handleSessionExpired(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse)
throws IOException {
logger.warn("expired session | id: " +
httpServletRequest.getRequestedSessionId());
String expirationPageURL =
httpServletRequest.getContextPath() + "/" +
"SessionExpiredNotification.html";
httpServletResponse.sendRedirect(expirationPageURL);
}
The SessionExpiredNotification.html
page is meant to be the end of the line. The user should close this browser window and open a new one if they want to start a new conversation. The problem is that the new browser window still wants to use the old session id value that was associated with the now invalidated session whenever the user has any other instances of Internet Explorer open on their desktop. This isn't specific to IE, as I have confirmed that Firefox behaves exactly the same way.
When this code is reached in my Filter
:
String requestedSessionId = httpServletRequest.getRequestedSessionId();
logger.info("requestedSessionId: " + requestedSessionId);
I can see that the client-side browser is still holding on to the old session id value and requesting it over and over again.
I'm not sure if it is relevant, but my web application container is Tomcat 6.x.
MY QUESTION:
How can the server web app signal the client workstation that a session id is no longer valid such that the client will discard it?