diff options
author | Max Romanov <max.romanov@nginx.com> | 2019-09-05 15:27:32 +0300 |
---|---|---|
committer | Max Romanov <max.romanov@nginx.com> | 2019-09-05 15:27:32 +0300 |
commit | 2b8cab1e2478547398ad9c2fe68e025c180cac54 (patch) | |
tree | d317fcf9ee52f0f8967116f531784ae533b0ae5a /src/java/nginx/unit/websocket/server/WsHttpUpgradeHandler.java | |
parent | 3e23afb0d205e503f6cc7d852e34d07da9a5b7f7 (diff) | |
download | unit-2b8cab1e2478547398ad9c2fe68e025c180cac54.tar.gz unit-2b8cab1e2478547398ad9c2fe68e025c180cac54.tar.bz2 |
Java: introducing websocket support.
Diffstat (limited to 'src/java/nginx/unit/websocket/server/WsHttpUpgradeHandler.java')
-rw-r--r-- | src/java/nginx/unit/websocket/server/WsHttpUpgradeHandler.java | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/src/java/nginx/unit/websocket/server/WsHttpUpgradeHandler.java b/src/java/nginx/unit/websocket/server/WsHttpUpgradeHandler.java new file mode 100644 index 00000000..cc39ab73 --- /dev/null +++ b/src/java/nginx/unit/websocket/server/WsHttpUpgradeHandler.java @@ -0,0 +1,172 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package nginx.unit.websocket.server; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpUpgradeHandler; +import javax.servlet.http.WebConnection; +import javax.websocket.CloseReason; +import javax.websocket.CloseReason.CloseCodes; +import javax.websocket.DeploymentException; +import javax.websocket.Endpoint; +import javax.websocket.EndpointConfig; +import javax.websocket.Extension; + +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +import org.apache.tomcat.util.res.StringManager; + +import nginx.unit.websocket.Transformation; +import nginx.unit.websocket.WsIOException; +import nginx.unit.websocket.WsSession; + +import nginx.unit.Request; + +/** + * Servlet 3.1 HTTP upgrade handler for WebSocket connections. + */ +public class WsHttpUpgradeHandler implements HttpUpgradeHandler { + + private final Log log = LogFactory.getLog(WsHttpUpgradeHandler.class); // must not be static + private static final StringManager sm = StringManager.getManager(WsHttpUpgradeHandler.class); + + private final ClassLoader applicationClassLoader; + + private Endpoint ep; + private EndpointConfig endpointConfig; + private WsServerContainer webSocketContainer; + private WsHandshakeRequest handshakeRequest; + private List<Extension> negotiatedExtensions; + private String subProtocol; + private Transformation transformation; + private Map<String,String> pathParameters; + private boolean secure; + private WebConnection connection; + private WsRemoteEndpointImplServer wsRemoteEndpointServer; + private WsSession wsSession; + + + public WsHttpUpgradeHandler() { + applicationClassLoader = Thread.currentThread().getContextClassLoader(); + } + + public void preInit(Endpoint ep, EndpointConfig endpointConfig, + WsServerContainer wsc, WsHandshakeRequest handshakeRequest, + List<Extension> negotiatedExtensionsPhase2, String subProtocol, + Transformation transformation, Map<String,String> pathParameters, + boolean secure) { + this.ep = ep; + this.endpointConfig = endpointConfig; + this.webSocketContainer = wsc; + this.handshakeRequest = handshakeRequest; + this.negotiatedExtensions = negotiatedExtensionsPhase2; + this.subProtocol = subProtocol; + this.transformation = transformation; + this.pathParameters = pathParameters; + this.secure = secure; + } + + + @Override + public void init(WebConnection connection) { + if (ep == null) { + throw new IllegalStateException( + sm.getString("wsHttpUpgradeHandler.noPreInit")); + } + + String httpSessionId = null; + Object session = handshakeRequest.getHttpSession(); + if (session != null ) { + httpSessionId = ((HttpSession) session).getId(); + } + + nginx.unit.Context.trace("UpgradeHandler.init(" + connection + ")"); + +/* + // Need to call onOpen using the web application's class loader + // Create the frame using the application's class loader so it can pick + // up application specific config from the ServerContainerImpl + Thread t = Thread.currentThread(); + ClassLoader cl = t.getContextClassLoader(); + t.setContextClassLoader(applicationClassLoader); +*/ + try { + Request r = (Request) handshakeRequest.getAttribute(Request.BARE); + + wsRemoteEndpointServer = new WsRemoteEndpointImplServer(webSocketContainer); + wsSession = new WsSession(ep, wsRemoteEndpointServer, + webSocketContainer, handshakeRequest.getRequestURI(), + handshakeRequest.getParameterMap(), + handshakeRequest.getQueryString(), + handshakeRequest.getUserPrincipal(), httpSessionId, + negotiatedExtensions, subProtocol, pathParameters, secure, + endpointConfig, r); + + ep.onOpen(wsSession, endpointConfig); + webSocketContainer.registerSession(ep, wsSession); + } catch (DeploymentException e) { + throw new IllegalArgumentException(e); +/* + } finally { + t.setContextClassLoader(cl); +*/ + } + } + + + + @Override + public void destroy() { + if (connection != null) { + try { + connection.close(); + } catch (Exception e) { + log.error(sm.getString("wsHttpUpgradeHandler.destroyFailed"), e); + } + } + } + + + private void onError(Throwable throwable) { + // Need to call onError using the web application's class loader + Thread t = Thread.currentThread(); + ClassLoader cl = t.getContextClassLoader(); + t.setContextClassLoader(applicationClassLoader); + try { + ep.onError(wsSession, throwable); + } finally { + t.setContextClassLoader(cl); + } + } + + + private void close(CloseReason cr) { + /* + * Any call to this method is a result of a problem reading from the + * client. At this point that state of the connection is unknown. + * Attempt to send a close frame to the client and then close the socket + * immediately. There is no point in waiting for a close frame from the + * client because there is no guarantee that we can recover from + * whatever messed up state the client put the connection into. + */ + wsSession.onClose(cr); + } +} |