package org.waveprotocol.box.server.rpc; import java.io.IOException; import java.security.SecureRandom; import java.util.Random; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.inject.Singleton; @Singleton public class TransientSessionFilter implements Filter { public static final String REQUEST_ATTR_TSESSION_ID = "org.waveprotocol.box.server.rpc.TransientSessionId"; public static final String DEFAULT_COOKIE_NAME = "TSESSIONID"; public static final String DEFAULT_COOKIE_DOMAIN = ""; public static final String PARAM_COOKIE_DOMAIN = "CookieDomain"; public static final String PARAM_COOKIE_NAME = "CookieName"; private static final String QUERY_PARAM_NAME = "tid"; private String confCookieName = DEFAULT_COOKIE_NAME; private String confCookieDomain = ""; private Random _random; private boolean _weakRandom; public TransientSessionFilter() { super(); } /* * Taken from Jetty */ private void initRandom() { if (_random == null) { try { _random = new SecureRandom(); } catch (Exception e) { _random = new Random(); _weakRandom = true; } } else _random.setSeed(_random.nextLong() ^ System.currentTimeMillis() ^ hashCode() ^ Runtime.getRuntime().freeMemory()); } private String newId(HttpServletRequest request, long created) { synchronized (this) { // pick a new unique ID! String id = null; while (id == null || id.length() == 0) { long r0 = _weakRandom ? (hashCode() ^ Runtime.getRuntime().freeMemory() ^ _random.nextInt() ^ (((long) request.hashCode()) << 32)) : _random.nextLong(); if (r0 < 0) r0 = -r0; long r1 = _weakRandom ? (hashCode() ^ Runtime.getRuntime().freeMemory() ^ _random.nextInt() ^ (((long) request.hashCode()) << 32)) : _random.nextLong(); if (r1 < 0) r1 = -r1; id = Long.toString(r0, 36) + Long.toString(r1, 36); } return id; } } @Override public void init(FilterConfig filterConfig) throws ServletException { initRandom(); String initParam = filterConfig.getInitParameter(PARAM_COOKIE_NAME); confCookieName = initParam != null ? initParam : DEFAULT_COOKIE_NAME; initParam = filterConfig.getInitParameter(PARAM_COOKIE_DOMAIN); confCookieDomain = initParam != null ? initParam : DEFAULT_COOKIE_DOMAIN; } protected Cookie getTSCookie(Cookie[] cookies) { Cookie tsCookie = null; for (Cookie c:cookies) { if (c.getName().equals(DEFAULT_COOKIE_NAME)) tsCookie = c; } return tsCookie; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; Cookie tsCookie = req.getCookies() != null ? getTSCookie(req.getCookies()) : null; String urlPart = null; if (req.getQueryString() != null && req.getQueryString().contains(QUERY_PARAM_NAME + "=")) { urlPart = req.getQueryString(); } else if (req.getRequestURI() != null && req.getRequestURI().contains(QUERY_PARAM_NAME + "=")) { urlPart = req.getRequestURI(); } String tsParam = null; if (urlPart != null) { String s = urlPart; int start = s.indexOf(QUERY_PARAM_NAME + "=") + QUERY_PARAM_NAME.length() + 1; int end = s.indexOf(";", start) > 0 ? s.indexOf(";", start) : urlPart.length(); s = s.substring(start,end); if (s != null && !s.isEmpty()) tsParam = s; } String tsessionId = null; if (tsCookie == null) { if (tsParam == null) { tsessionId = newId(req, System.currentTimeMillis()); tsCookie = new Cookie(confCookieName, tsessionId); tsCookie.setDomain(confCookieDomain);; tsCookie.setMaxAge(-1); res.addCookie(tsCookie); } else { tsessionId = tsParam; } } else { tsessionId = tsCookie.getValue(); } request.setAttribute(REQUEST_ATTR_TSESSION_ID, tsessionId); try { chain.doFilter(request, response); } finally { } } @Override public void destroy() { } }