/* * 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 negotiatedExtensions; private String subProtocol; private Transformation transformation; private Map 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 negotiatedExtensionsPhase2, String subProtocol, Transformation transformation, Map 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); } }