This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 0e887b7729184fc65a71798175554f62dbcae876 Author: Mark Thomas <ma...@apache.org> AuthorDate: Fri Apr 30 14:36:52 2021 +0100 Refactor server end point creation to WsSession The is an interim step towards the fix for BZ 65262 --- java/org/apache/tomcat/websocket/WsSession.java | 185 +++++++++++++++++++++ .../tomcat/websocket/WsWebSocketContainer.java | 6 +- .../tomcat/websocket/server/UpgradeUtil.java | 16 +- .../websocket/server/WsHttpUpgradeHandler.java | 8 +- 4 files changed, 192 insertions(+), 23 deletions(-) diff --git a/java/org/apache/tomcat/websocket/WsSession.java b/java/org/apache/tomcat/websocket/WsSession.java index c185e8a..2085cb3 100644 --- a/java/org/apache/tomcat/websocket/WsSession.java +++ b/java/org/apache/tomcat/websocket/WsSession.java @@ -30,6 +30,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; +import jakarta.websocket.ClientEndpointConfig; import jakarta.websocket.CloseReason; import jakarta.websocket.CloseReason.CloseCode; import jakarta.websocket.CloseReason.CloseCodes; @@ -53,6 +54,7 @@ import org.apache.tomcat.InstanceManager; import org.apache.tomcat.InstanceManagerBindings; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.websocket.pojo.PojoEndpointServer; public class WsSession implements Session { @@ -101,6 +103,186 @@ public class WsSession implements Session { private volatile long lastActiveWrite = System.currentTimeMillis(); private Map<FutureToSendHandler, FutureToSendHandler> futures = new ConcurrentHashMap<>(); + + /** + * Creates a new WebSocket session for communication between the provided + * client and remote end points. The result of + * {@link Thread#getContextClassLoader()} at the time this constructor is + * called will be used when calling + * {@link Endpoint#onClose(Session, CloseReason)}. + * + * @param localEndpoint The end point managed by this code + * @param wsRemoteEndpoint The other / remote end point + * @param wsWebSocketContainer The container that created this session + * @param negotiatedExtensions The agreed extensions to use for this session + * @param subProtocol The agreed sub-protocol to use for this + * session + * @param pathParameters The path parameters associated with the + * request that initiated this session or + * <code>null</code> if this is a client session + * @param secure Was this session initiated over a secure + * connection? + * @param clientEndpointConfig The configuration information for the client + * end point + * @throws DeploymentException if an invalid encode is specified + */ + public WsSession(Endpoint localEndpoint, + WsRemoteEndpointImplBase wsRemoteEndpoint, + WsWebSocketContainer wsWebSocketContainer, + List<Extension> negotiatedExtensions, String subProtocol, Map<String, String> pathParameters, + boolean secure, ClientEndpointConfig clientEndpointConfig) throws DeploymentException { + this.localEndpoint = localEndpoint; + this.wsRemoteEndpoint = wsRemoteEndpoint; + this.wsRemoteEndpoint.setSession(this); + this.remoteEndpointAsync = new WsRemoteEndpointAsync(wsRemoteEndpoint); + this.remoteEndpointBasic = new WsRemoteEndpointBasic(wsRemoteEndpoint); + this.webSocketContainer = wsWebSocketContainer; + applicationClassLoader = Thread.currentThread().getContextClassLoader(); + wsRemoteEndpoint.setSendTimeout(wsWebSocketContainer.getDefaultAsyncSendTimeout()); + this.maxBinaryMessageBufferSize = webSocketContainer.getDefaultMaxBinaryMessageBufferSize(); + this.maxTextMessageBufferSize = webSocketContainer.getDefaultMaxTextMessageBufferSize(); + this.maxIdleTimeout = webSocketContainer.getDefaultMaxSessionIdleTimeout(); + this.requestUri = null; + this.requestParameterMap = Collections.emptyMap(); + this.queryString = null; + this.userPrincipal = null; + this.httpSessionId = null; + this.negotiatedExtensions = negotiatedExtensions; + if (subProtocol == null) { + this.subProtocol = ""; + } else { + this.subProtocol = subProtocol; + } + this.pathParameters = pathParameters; + this.secure = secure; + this.wsRemoteEndpoint.setEncoders(clientEndpointConfig); + this.endpointConfig = clientEndpointConfig; + + this.userProperties.putAll(endpointConfig.getUserProperties()); + this.id = Long.toHexString(ids.getAndIncrement()); + + InstanceManager instanceManager = webSocketContainer.getInstanceManager(); + if (instanceManager == null) { + instanceManager = InstanceManagerBindings.get(applicationClassLoader); + } + if (instanceManager != null) { + try { + instanceManager.newInstance(localEndpoint); + } catch (Exception e) { + throw new DeploymentException(sm.getString("wsSession.instanceNew"), e); + } + } + + if (log.isDebugEnabled()) { + log.debug(sm.getString("wsSession.created", id)); + } + } + + + /** + * Creates a new WebSocket session for communication between the provided + * server and remote end points. The result of + * {@link Thread#getContextClassLoader()} at the time this constructor is + * called will be used when calling + * {@link Endpoint#onClose(Session, CloseReason)}. + * + * @param wsRemoteEndpoint The other / remote end point + * @param wsWebSocketContainer The container that created this session + * @param requestUri The URI used to connect to this end point or + * <code>null</code> is this is a client session + * @param requestParameterMap The parameters associated with the request + * that initiated this session or + * <code>null</code> if this is a client session + * @param queryString The query string associated with the request + * that initiated this session or + * <code>null</code> if this is a client session + * @param userPrincipal The principal associated with the request + * that initiated this session or + * <code>null</code> if this is a client session + * @param httpSessionId The HTTP session ID associated with the + * request that initiated this session or + * <code>null</code> if this is a client session + * @param negotiatedExtensions The agreed extensions to use for this session + * @param subProtocol The agreed sub-protocol to use for this + * session + * @param pathParameters The path parameters associated with the + * request that initiated this session or + * <code>null</code> if this is a client session + * @param secure Was this session initiated over a secure + * connection? + * @param serverEndpointConfig The configuration information for the server + * end point + * @throws DeploymentException if an invalid encode is specified + */ + public WsSession(WsRemoteEndpointImplBase wsRemoteEndpoint, + WsWebSocketContainer wsWebSocketContainer, + URI requestUri, Map<String, List<String>> requestParameterMap, + String queryString, Principal userPrincipal, String httpSessionId, + List<Extension> negotiatedExtensions, String subProtocol, Map<String, String> pathParameters, + boolean secure, ServerEndpointConfig serverEndpointConfig) throws DeploymentException { + + try { + Class<?> clazz = serverEndpointConfig.getEndpointClass(); + if (Endpoint.class.isAssignableFrom(clazz)) { + this.localEndpoint = (Endpoint) serverEndpointConfig.getConfigurator().getEndpointInstance(clazz); + } else { + this.localEndpoint = new PojoEndpointServer(pathParameters); + } + } catch (InstantiationException e) { + throw new DeploymentException(sm.getString("wsSession.instanceNew"), e); + } + + this.wsRemoteEndpoint = wsRemoteEndpoint; + this.wsRemoteEndpoint.setSession(this); + this.remoteEndpointAsync = new WsRemoteEndpointAsync(wsRemoteEndpoint); + this.remoteEndpointBasic = new WsRemoteEndpointBasic(wsRemoteEndpoint); + this.webSocketContainer = wsWebSocketContainer; + applicationClassLoader = Thread.currentThread().getContextClassLoader(); + wsRemoteEndpoint.setSendTimeout(wsWebSocketContainer.getDefaultAsyncSendTimeout()); + this.maxBinaryMessageBufferSize = webSocketContainer.getDefaultMaxBinaryMessageBufferSize(); + this.maxTextMessageBufferSize = webSocketContainer.getDefaultMaxTextMessageBufferSize(); + this.maxIdleTimeout = webSocketContainer.getDefaultMaxSessionIdleTimeout(); + this.requestUri = requestUri; + if (requestParameterMap == null) { + this.requestParameterMap = Collections.emptyMap(); + } else { + this.requestParameterMap = requestParameterMap; + } + this.queryString = queryString; + this.userPrincipal = userPrincipal; + this.httpSessionId = httpSessionId; + this.negotiatedExtensions = negotiatedExtensions; + if (subProtocol == null) { + this.subProtocol = ""; + } else { + this.subProtocol = subProtocol; + } + this.pathParameters = pathParameters; + this.secure = secure; + this.wsRemoteEndpoint.setEncoders(serverEndpointConfig); + this.endpointConfig = serverEndpointConfig; + + this.userProperties.putAll(endpointConfig.getUserProperties()); + this.id = Long.toHexString(ids.getAndIncrement()); + + InstanceManager instanceManager = webSocketContainer.getInstanceManager(); + if (instanceManager == null) { + instanceManager = InstanceManagerBindings.get(applicationClassLoader); + } + if (instanceManager != null) { + try { + instanceManager.newInstance(localEndpoint); + } catch (Exception e) { + throw new DeploymentException(sm.getString("wsSession.instanceNew"), e); + } + } + + if (log.isDebugEnabled()) { + log.debug(sm.getString("wsSession.created", id)); + } + } + + /** * Creates a new WebSocket session for communication between the two * provided end points. The result of {@link Thread#getContextClassLoader()} @@ -135,7 +317,10 @@ public class WsSession implements Session { * @param endpointConfig The configuration information for the * endpoint * @throws DeploymentException if an invalid encode is specified + * + * @deprecated Unused. This will be removed in Tomcat 10.1 */ + @Deprecated public WsSession(Endpoint localEndpoint, WsRemoteEndpointImplBase wsRemoteEndpoint, WsWebSocketContainer wsWebSocketContainer, diff --git a/java/org/apache/tomcat/websocket/WsWebSocketContainer.java b/java/org/apache/tomcat/websocket/WsWebSocketContainer.java index e6dc4b3..71d2f70 100644 --- a/java/org/apache/tomcat/websocket/WsWebSocketContainer.java +++ b/java/org/apache/tomcat/websocket/WsWebSocketContainer.java @@ -506,10 +506,8 @@ public class WsWebSocketContainer implements WebSocketContainer, BackgroundProce // Switch to WebSocket WsRemoteEndpointImplClient wsRemoteEndpointClient = new WsRemoteEndpointImplClient(channel); - WsSession wsSession = new WsSession(endpoint, wsRemoteEndpointClient, - this, null, null, null, null, null, extensionsAgreed, - subProtocol, Collections.<String,String>emptyMap(), secure, - clientEndpointConfiguration); + WsSession wsSession = new WsSession(endpoint, wsRemoteEndpointClient, this, extensionsAgreed, subProtocol, + Collections.<String,String>emptyMap(), secure, clientEndpointConfiguration); WsFrameClient wsFrameClient = new WsFrameClient(response, channel, wsSession, transformation); diff --git a/java/org/apache/tomcat/websocket/server/UpgradeUtil.java b/java/org/apache/tomcat/websocket/server/UpgradeUtil.java index e0cff21..5a07c93 100644 --- a/java/org/apache/tomcat/websocket/server/UpgradeUtil.java +++ b/java/org/apache/tomcat/websocket/server/UpgradeUtil.java @@ -31,7 +31,6 @@ import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import jakarta.websocket.Endpoint; import jakarta.websocket.Extension; import jakarta.websocket.HandshakeResponse; import jakarta.websocket.server.ServerEndpointConfig; @@ -44,7 +43,6 @@ import org.apache.tomcat.websocket.Transformation; import org.apache.tomcat.websocket.TransformationFactory; import org.apache.tomcat.websocket.Util; import org.apache.tomcat.websocket.WsHandshakeResponse; -import org.apache.tomcat.websocket.pojo.PojoEndpointServer; public class UpgradeUtil { @@ -215,21 +213,9 @@ public class UpgradeUtil { } } - Endpoint ep; - try { - Class<?> clazz = sec.getEndpointClass(); - if (Endpoint.class.isAssignableFrom(clazz)) { - ep = (Endpoint) sec.getConfigurator().getEndpointInstance(clazz); - } else { - ep = new PojoEndpointServer(pathParams); - } - } catch (InstantiationException e) { - throw new ServletException(e); - } - WsHttpUpgradeHandler wsHandler = req.upgrade(WsHttpUpgradeHandler.class); - wsHandler.preInit(ep, perSessionServerEndpointConfig, sc, wsRequest, + wsHandler.preInit(perSessionServerEndpointConfig, sc, wsRequest, negotiatedExtensionsPhase2, subProtocol, transformation, pathParams, req.isSecure()); diff --git a/java/org/apache/tomcat/websocket/server/WsHttpUpgradeHandler.java b/java/org/apache/tomcat/websocket/server/WsHttpUpgradeHandler.java index 4f28a0e..1d29a7d 100644 --- a/java/org/apache/tomcat/websocket/server/WsHttpUpgradeHandler.java +++ b/java/org/apache/tomcat/websocket/server/WsHttpUpgradeHandler.java @@ -82,12 +82,11 @@ public class WsHttpUpgradeHandler implements InternalHttpUpgradeHandler { } - public void preInit(Endpoint ep, ServerEndpointConfig serverEndpointConfig, + public void preInit(ServerEndpointConfig serverEndpointConfig, WsServerContainer wsc, WsHandshakeRequest handshakeRequest, List<Extension> negotiatedExtensionsPhase2, String subProtocol, Transformation transformation, Map<String,String> pathParameters, boolean secure) { - this.ep = ep; this.serverEndpointConfig = serverEndpointConfig; this.webSocketContainer = wsc; this.handshakeRequest = handshakeRequest; @@ -101,7 +100,7 @@ public class WsHttpUpgradeHandler implements InternalHttpUpgradeHandler { @Override public void init(WebConnection connection) { - if (ep == null) { + if (serverEndpointConfig == null) { throw new IllegalStateException( sm.getString("wsHttpUpgradeHandler.noPreInit")); } @@ -120,13 +119,14 @@ public class WsHttpUpgradeHandler implements InternalHttpUpgradeHandler { t.setContextClassLoader(applicationClassLoader); try { wsRemoteEndpointServer = new WsRemoteEndpointImplServer(socketWrapper, upgradeInfo, webSocketContainer); - wsSession = new WsSession(ep, wsRemoteEndpointServer, + wsSession = new WsSession(wsRemoteEndpointServer, webSocketContainer, handshakeRequest.getRequestURI(), handshakeRequest.getParameterMap(), handshakeRequest.getQueryString(), handshakeRequest.getUserPrincipal(), httpSessionId, negotiatedExtensions, subProtocol, pathParameters, secure, serverEndpointConfig); + ep = wsSession.getLocal(); wsFrame = new WsFrameServer(socketWrapper, upgradeInfo, wsSession, transformation, applicationClassLoader); // WsFrame adds the necessary final transformations. Copy the --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org