456956 Reduce ThreadLocal.remove() weak reference garbage

removed getCurrentChannel thread local
This commit is contained in:
Greg Wilkins 2015-01-08 15:03:05 +01:00
parent 12f84c9592
commit c23f21c761
20 changed files with 55 additions and 111 deletions

View File

@ -34,14 +34,13 @@ import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.servlet.ServletRequest;
import org.eclipse.jetty.jaas.callback.ObjectCallback;
import org.eclipse.jetty.jaas.callback.RequestParameterCallback;
import org.eclipse.jetty.security.DefaultIdentityService;
import org.eclipse.jetty.security.IdentityService;
import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
@ -181,7 +180,8 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
}
/* ------------------------------------------------------------ */
public UserIdentity login(final String username,final Object credentials)
@Override
public UserIdentity login(final String username,final Object credentials, final ServletRequest request)
{
try
{
@ -209,19 +209,11 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
((ObjectCallback)callback).setObject(credentials);
}
else if (callback instanceof RequestParameterCallback)
{
HttpChannel channel = HttpChannel.getCurrentHttpChannel();
if (channel == null)
return;
Request request = channel.getRequest();
if (request != null)
{
RequestParameterCallback rpc = (RequestParameterCallback)callback;
if (request!=null)
rpc.setParameterValues(Arrays.asList(request.getParameterValues(rpc.getParameterName())));
}
}
else
throw new UnsupportedCallbackException(callback);
}
@ -230,7 +222,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
}
else
{
Class clazz = Loader.loadClass(getClass(), _callbackHandlerClass);
Class<?> clazz = Loader.loadClass(getClass(), _callbackHandlerClass);
callbackHandler = (CallbackHandler)clazz.newInstance();
}
//set up the login context

View File

@ -121,7 +121,7 @@ public class JaspiAuthenticator extends LoginAuthenticator
@Override
public UserIdentity login(String username, Object password, ServletRequest request)
{
UserIdentity user = _loginService.login(username, password);
UserIdentity user = _loginService.login(username, password, request);
if (user != null)
{
renewSession((HttpServletRequest)request, null);

View File

@ -74,7 +74,7 @@ public class ServletCallbackHandler implements CallbackHandler
PasswordValidationCallback passwordValidationCallback = (PasswordValidationCallback) callback;
Subject subject = passwordValidationCallback.getSubject();
UserIdentity user = _loginService.login(passwordValidationCallback.getUsername(),passwordValidationCallback.getPassword());
UserIdentity user = _loginService.login(passwordValidationCallback.getUsername(),passwordValidationCallback.getPassword(), null);
if (user!=null)
{
@ -91,7 +91,7 @@ public class ServletCallbackHandler implements CallbackHandler
credentialValidationCallback.getUsername(),
credentialValidationCallback.getCredential());
UserIdentity user = _loginService.login(credentialValidationCallback.getUsername(),credentialValidationCallback.getCredential());
UserIdentity user = _loginService.login(credentialValidationCallback.getUsername(),credentialValidationCallback.getCredential(), null);
if (user!=null)
{

View File

@ -32,6 +32,7 @@ import java.util.Locale;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.servlet.ServletRequest;
import javax.sql.DataSource;
import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
@ -337,7 +338,7 @@ public class DataSourceLoginService extends MappedLoginService
/* ------------------------------------------------------------ */
@Override
public UserIdentity login(String username, Object credentials)
public UserIdentity login(String username, Object credentials, ServletRequest request)
{
long now = System.currentTimeMillis();
if (now - _lastPurge > _cacheMs || _cacheMs == 0)
@ -346,7 +347,7 @@ public class DataSourceLoginService extends MappedLoginService
_lastPurge = now;
}
return super.login(username,credentials);
return super.login(username,credentials, request);
}
/* ------------------------------------------------------------ */

View File

@ -675,7 +675,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
if (dataConstraint == null || dataConstraint == UserDataConstraint.None)
return true;
HttpConfiguration httpConfig = HttpChannel.getCurrentHttpChannel().getHttpConfiguration();
HttpConfiguration httpConfig = Request.getBaseRequest(request).getHttpChannel().getHttpConfiguration();
if (dataConstraint == UserDataConstraint.Confidential || dataConstraint == UserDataConstraint.Integral)
{

View File

@ -29,6 +29,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.servlet.ServletRequest;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.log.Log;
@ -210,7 +212,7 @@ public class JDBCLoginService extends MappedLoginService
/* ------------------------------------------------------------ */
@Override
public UserIdentity login(String username, Object credentials)
public UserIdentity login(String username, Object credentials, ServletRequest request)
{
long now = System.currentTimeMillis();
if (now - _lastHashPurge > _cacheTime || _cacheTime == 0)
@ -220,7 +222,7 @@ public class JDBCLoginService extends MappedLoginService
closeConnection();
}
return super.login(username,credentials);
return super.login(username,credentials, request);
}
/* ------------------------------------------------------------ */

View File

@ -18,6 +18,8 @@
package org.eclipse.jetty.security;
import javax.servlet.ServletRequest;
import org.eclipse.jetty.server.UserIdentity;
@ -42,14 +44,15 @@ public interface LoginService
/** Login a user.
* @param username The user name
* @param credentials The users credentials
* @param request TODO
* @return A UserIdentity if the credentials matched, otherwise null
*/
UserIdentity login(String username,Object credentials);
UserIdentity login(String username,Object credentials, ServletRequest request);
/* ------------------------------------------------------------ */
/** Validate a user identity.
* Validate that a UserIdentity previously created by a call
* to {@link #login(String, Object)} is still valid.
* to {@link #login(String, Object, ServletRequest)} is still valid.
* @param user The user to validate
* @return true if authentication has not been revoked for the user.
*/

View File

@ -27,6 +27,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.security.auth.Subject;
import javax.servlet.ServletRequest;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
@ -208,9 +209,9 @@ public abstract class MappedLoginService extends AbstractLifeCycle implements Lo
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.security.LoginService#login(java.lang.String, java.lang.Object)
* @see org.eclipse.jetty.security.LoginService#login(java.lang.String, java.lang.Object, ServletRequest)
*/
public UserIdentity login(String username, Object credentials)
public UserIdentity login(String username, Object credentials, ServletRequest request)
{
if (username == null)
return null;

View File

@ -309,33 +309,6 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
getInitParameter(name)==null)
setInitParameter(name,context.getInitParameter(name));
}
//register a session listener to handle securing sessions when authentication is performed
context.getContextHandler().addEventListener(new HttpSessionListener()
{
@Override
public void sessionDestroyed(HttpSessionEvent se)
{
}
@Override
public void sessionCreated(HttpSessionEvent se)
{
//if current request is authenticated, then as we have just created the session, mark it as secure, as it has not yet been returned to a user
HttpChannel channel = HttpChannel.getCurrentHttpChannel();
if (channel == null)
return;
Request request = channel.getRequest();
if (request == null)
return;
if (request.isSecure())
{
se.getSession().setAttribute(AbstractSession.SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
}
}
});
}
// complicated resolution of login and identity service to handle

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.security;
import java.util.Properties;
import javax.security.auth.Subject;
import javax.servlet.ServletRequest;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.B64Code;
@ -112,7 +113,7 @@ public class SpnegoLoginService extends AbstractLifeCycle implements LoginServic
* username will be null since the credentials will contain all the relevant info
*/
@Override
public UserIdentity login(String username, Object credentials)
public UserIdentity login(String username, Object credentials, ServletRequest request)
{
String encodedAuthToken = (String)credentials;

View File

@ -235,7 +235,7 @@ public class FormAuthenticator extends LoginAuthenticator
//restore the original request's method on this request
if (LOG.isDebugEnabled()) LOG.debug("Restoring original method {} for {} with method {}", method, juri,httpRequest.getMethod());
Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
Request base_request = Request.getBaseRequest(request);
base_request.setMethod(method);
}
@ -245,6 +245,9 @@ public class FormAuthenticator extends LoginAuthenticator
{
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
Request base_request = Request.getBaseRequest(request);
Response base_response = base_request.getResponse();
String uri = request.getRequestURI();
if (uri==null)
uri=URIUtil.SLASH;
@ -289,8 +292,6 @@ public class FormAuthenticator extends LoginAuthenticator
LOG.debug("authenticated {}->{}",form_auth,nuri);
response.setContentLength(0);
Request base_request = Request.getBaseRequest(req);
Response base_response = base_request.getResponse();
int redirectCode = (base_request.getHttpVersion().getVersion() < HttpVersion.HTTP_1_1.getVersion() ? HttpServletResponse.SC_MOVED_TEMPORARILY : HttpServletResponse.SC_SEE_OTHER);
base_response.sendRedirect(redirectCode, response.encodeRedirectURL(nuri));
return form_auth;
@ -316,8 +317,6 @@ public class FormAuthenticator extends LoginAuthenticator
else
{
LOG.debug("auth failed {}->{}",username,_formErrorPage);
Response base_response = HttpChannel.getCurrentHttpChannel().getResponse();
Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
int redirectCode = (base_request.getHttpVersion().getVersion() < HttpVersion.HTTP_1_1.getVersion() ? HttpServletResponse.SC_MOVED_TEMPORARILY : HttpServletResponse.SC_SEE_OTHER);
base_response.sendRedirect(redirectCode, response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),_formErrorPage)));
}
@ -357,7 +356,6 @@ public class FormAuthenticator extends LoginAuthenticator
if (j_post!=null)
{
LOG.debug("auth rePOST {}->{}",authentication,j_uri);
Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
base_request.setContentParameters(j_post);
}
session.removeAttribute(__J_URI);
@ -392,7 +390,6 @@ public class FormAuthenticator extends LoginAuthenticator
if (MimeTypes.Type.FORM_ENCODED.is(req.getContentType()) && HttpMethod.POST.is(request.getMethod()))
{
Request base_request = (req instanceof Request)?(Request)req:HttpChannel.getCurrentHttpChannel().getRequest();
MultiMap<String> formParameters = new MultiMap<>();
base_request.extractFormParameters(formParameters);
session.setAttribute(__J_POST, formParameters);
@ -412,8 +409,6 @@ public class FormAuthenticator extends LoginAuthenticator
else
{
LOG.debug("challenge {}->{}",session.getId(),_formLoginPage);
Response base_response = HttpChannel.getCurrentHttpChannel().getResponse();
Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
int redirectCode = (base_request.getHttpVersion().getVersion() < HttpVersion.HTTP_1_1.getVersion() ? HttpServletResponse.SC_MOVED_TEMPORARILY : HttpServletResponse.SC_SEE_OTHER);
base_response.sendRedirect(redirectCode, response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),_formLoginPage)));
}

View File

@ -58,7 +58,7 @@ public abstract class LoginAuthenticator implements Authenticator
/* ------------------------------------------------------------ */
public UserIdentity login(String username, Object password, ServletRequest request)
{
UserIdentity user = _loginService.login(username,password);
UserIdentity user = _loginService.login(username,password, request);
if (user!=null)
{
renewSession((HttpServletRequest)request, (request instanceof Request? ((Request)request).getResponse() : null));
@ -109,14 +109,14 @@ public abstract class LoginAuthenticator implements Authenticator
{
//if we should renew sessions, and there is an existing session that may have been seen by non-authenticated users
//(indicated by SESSION_SECURED not being set on the session) then we should change id
if (httpSession.getAttribute(AbstractSession.SESSION_KNOWN_ONLY_TO_AUTHENTICATED)!=Boolean.TRUE)
if (httpSession.getAttribute(AbstractSession.SESSION_CREATED_SECURE)!=Boolean.TRUE)
{
if (httpSession instanceof AbstractSession)
{
AbstractSession abstractSession = (AbstractSession)httpSession;
String oldId = abstractSession.getId();
abstractSession.renewId(request);
abstractSession.setAttribute(AbstractSession.SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
abstractSession.setAttribute(AbstractSession.SESSION_CREATED_SECURE, Boolean.TRUE);
if (abstractSession.isIdChanged() && response != null && (response instanceof Response))
((Response)response).addCookie(abstractSession.getSessionManager().getSessionCookie(abstractSession, request.getContextPath(), request.isSecure()));
LOG.debug("renew {}->{}",oldId,abstractSession.getId());

View File

@ -71,7 +71,7 @@ public class SessionAuthentication extends AbstractUserAuthentication implements
if (login_service==null)
throw new IllegalStateException("!LoginService");
_userIdentity=login_service.login(_name,_credentials);
_userIdentity=login_service.login(_name,_credentials, null);
LOG.debug("Deserialized and relogged in {}",this);
}
@ -89,7 +89,7 @@ public class SessionAuthentication extends AbstractUserAuthentication implements
if (security!=null)
security.logout(this);
if (_session!=null)
_session.removeAttribute(AbstractSession.SESSION_KNOWN_ONLY_TO_AUTHENTICATED);
_session.removeAttribute(AbstractSession.SESSION_CREATED_SECURE);
}
@Override

View File

@ -20,7 +20,9 @@ package org.eclipse.jetty.security;
import java.io.IOException;
import java.util.Arrays;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -436,7 +438,7 @@ public class DataConstraintsTest
}
@Override
public UserIdentity login(String username, Object credentials)
public UserIdentity login(String username, Object credentials, ServletRequest request)
{
if("admin".equals(username) && "password".equals(credentials))
return new DefaultUserIdentity(null,null,new String[] { "admin" } );

View File

@ -65,25 +65,6 @@ import org.eclipse.jetty.util.thread.Scheduler;
public class HttpChannel implements Runnable, HttpOutput.Interceptor
{
private static final Logger LOG = Log.getLogger(HttpChannel.class);
private static final ThreadLocal<HttpChannel> __currentChannel = new ThreadLocal<>();
/**
* Get the current channel that this thread is dispatched to.
* @see Request#getAttribute(String) for a more general way to access the HttpChannel
* @return the current HttpChannel or null
*/
public static HttpChannel getCurrentHttpChannel()
{
return __currentChannel.get();
}
protected static HttpChannel setCurrentHttpChannel(HttpChannel channel)
{
HttpChannel last=__currentChannel.get();
__currentChannel.set(channel);
return last;
}
private final AtomicBoolean _committed = new AtomicBoolean();
private final AtomicInteger _requests = new AtomicInteger();
private final Connector _connector;
@ -246,8 +227,6 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
*/
public boolean handle()
{
final HttpChannel last = setCurrentHttpChannel(this);
String threadName = null;
if (LOG.isDebugEnabled())
{
@ -420,7 +399,6 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
}
finally
{
setCurrentHttpChannel(last);
if (threadName != null && LOG.isDebugEnabled())
Thread.currentThread().setName(threadName);
}

View File

@ -136,7 +136,7 @@ public class Request implements HttpServletRequest
/* ------------------------------------------------------------ */
/**
* Obtain the base {@link Request} instance of a {@link ServletRequest}, by
* coercion, unwrapping or thread local.
* coercion, unwrapping or special attribute.
* @param request The request
* @return the base {@link Request} instance of a {@link ServletRequest}.
*/
@ -145,13 +145,17 @@ public class Request implements HttpServletRequest
if (request instanceof Request)
return (Request)request;
Object channel = request.getAttribute(HttpChannel.class.getName());
if (channel instanceof HttpChannel)
return ((HttpChannel)channel).getRequest();
while (request instanceof ServletRequestWrapper)
request=((ServletRequestWrapper)request).getRequest();
if (request instanceof Request)
return (Request)request;
return HttpChannel.getCurrentHttpChannel().getRequest();
return null;
}
@ -536,11 +540,11 @@ public class Request implements HttpServletRequest
{
if (name.startsWith("org.eclipse.jetty"))
{
if ("org.eclipse.jetty.server.Server".equals(name))
if (Server.class.getName().equals(name))
return _channel.getServer();
if ("org.eclipse.jetty.server.HttpChannel".equals(name))
if (HttpChannel.class.getName().equals(name))
return _channel;
if ("org.eclipse.jetty.server.HttpConnection".equals(name) &&
if (HttpConnection.class.getName().equals(name) &&
_channel.getHttpTransport() instanceof HttpConnection)
return _channel.getHttpTransport();
}
@ -1497,7 +1501,7 @@ public class Request implements HttpServletRequest
AbstractSession abstractSession = ((AbstractSession)session);
abstractSession.renewId(this);
if (getRemoteUser() != null)
abstractSession.setAttribute(AbstractSession.SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
abstractSession.setAttribute(AbstractSession.SESSION_CREATED_SECURE, Boolean.TRUE);
if (abstractSession.isIdChanged())
_channel.getResponse().addCookie(_sessionManager.getSessionCookie(abstractSession, getContextPath(), isSecure()));
}

View File

@ -81,15 +81,6 @@ public class Response implements HttpServletResponse
}
};
/* ------------------------------------------------------------ */
public static Response getResponse(HttpServletResponse response)
{
if (response instanceof Response)
return (Response)response;
return HttpChannel.getCurrentHttpChannel().getResponse();
}
public enum OutputType
{
NONE, STREAM, WRITER

View File

@ -311,8 +311,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
String path = context==null?baseRequest.getRequestURI():URIUtil.addPaths(baseRequest.getServletPath(),baseRequest.getPathInfo());
LOG.debug("{} handle {} in {}",this,baseRequest,context);
HttpChannel channel = HttpChannel.getCurrentHttpChannel();
HttpOutput out = channel.getResponse().getHttpOutput();
HttpOutput out = baseRequest.getResponse().getHttpOutput();
// Are we already being gzipped?
HttpOutput.Interceptor interceptor = out.getInterceptor();
while (interceptor!=null)
@ -382,7 +381,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
}
// install interceptor and handle
out.setInterceptor(new GzipHttpOutputInterceptor(this,_vary,channel,out.getInterceptor()));
out.setInterceptor(new GzipHttpOutputInterceptor(this,_vary,baseRequest.getHttpChannel(),out.getInterceptor()));
_handler.handle(target,baseRequest, request, response);
}

View File

@ -45,7 +45,7 @@ import org.eclipse.jetty.util.log.Logger;
public abstract class AbstractSession implements AbstractSessionManager.SessionIf
{
final static Logger LOG = SessionHandler.LOG;
public final static String SESSION_KNOWN_ONLY_TO_AUTHENTICATED="org.eclipse.jetty.security.sessionKnownOnlytoAuthenticated";
public final static String SESSION_CREATED_SECURE="org.eclipse.jetty.security.sessionCreatedSecure";
private String _clusterId; // ID without any node (ie "worker") id appended
private String _nodeId; // ID of session with node(ie "worker") id appended
private final AbstractSessionManager _manager;

View File

@ -563,6 +563,8 @@ public abstract class AbstractSessionManager extends ContainerLifeCycle implemen
{
AbstractSession session=newSession(request);
session.setMaxInactiveInterval(_dftMaxIdleSecs);
if (request.isSecure())
session.setAttribute(AbstractSession.SESSION_CREATED_SECURE, Boolean.TRUE);
addSession(session,true);
return session;
}