Search in sources :

Example 1 with WsHandshakeResponse

use of org.apache.tomcat.websocket.WsHandshakeResponse in project tomcat70 by apache.

the class UpgradeUtil method doUpgrade.

public static void doUpgrade(WsServerContainer sc, HttpServletRequest req, HttpServletResponse resp, ServerEndpointConfig sec, Map<String, String> pathParams) throws ServletException, IOException {
    // Validate the rest of the headers and reject the request if that
    // validation fails
    String key;
    String subProtocol = null;
    if (!headerContainsToken(req, Constants.CONNECTION_HEADER_NAME, Constants.CONNECTION_HEADER_VALUE)) {
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
        return;
    }
    if (!headerContainsToken(req, Constants.WS_VERSION_HEADER_NAME, Constants.WS_VERSION_HEADER_VALUE)) {
        resp.setStatus(426);
        resp.setHeader(Constants.WS_VERSION_HEADER_NAME, Constants.WS_VERSION_HEADER_VALUE);
        return;
    }
    key = req.getHeader(Constants.WS_KEY_HEADER_NAME);
    if (key == null) {
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
        return;
    }
    // Origin check
    String origin = req.getHeader(Constants.ORIGIN_HEADER_NAME);
    if (!sec.getConfigurator().checkOrigin(origin)) {
        resp.sendError(HttpServletResponse.SC_FORBIDDEN);
        return;
    }
    // Sub-protocols
    List<String> subProtocols = getTokensFromHeader(req, Constants.WS_PROTOCOL_HEADER_NAME);
    subProtocol = sec.getConfigurator().getNegotiatedSubprotocol(sec.getSubprotocols(), subProtocols);
    // Extensions
    // Should normally only be one header but handle the case of multiple
    // headers
    List<Extension> extensionsRequested = new ArrayList<Extension>();
    Enumeration<String> extHeaders = req.getHeaders(Constants.WS_EXTENSIONS_HEADER_NAME);
    while (extHeaders.hasMoreElements()) {
        Util.parseExtensionHeader(extensionsRequested, extHeaders.nextElement());
    }
    // Negotiation phase 1. By default this simply filters out the
    // extensions that the server does not support but applications could
    // use a custom configurator to do more than this.
    List<Extension> installedExtensions = null;
    if (sec.getExtensions().size() == 0) {
        installedExtensions = Constants.INSTALLED_EXTENSIONS;
    } else {
        installedExtensions = new ArrayList<Extension>();
        installedExtensions.addAll(sec.getExtensions());
        installedExtensions.addAll(Constants.INSTALLED_EXTENSIONS);
    }
    List<Extension> negotiatedExtensionsPhase1 = sec.getConfigurator().getNegotiatedExtensions(installedExtensions, extensionsRequested);
    // Negotiation phase 2. Create the Transformations that will be applied
    // to this connection. Note than an extension may be dropped at this
    // point if the client has requested a configuration that the server is
    // unable to support.
    List<Transformation> transformations = createTransformations(negotiatedExtensionsPhase1);
    List<Extension> negotiatedExtensionsPhase2;
    if (transformations.isEmpty()) {
        negotiatedExtensionsPhase2 = Collections.emptyList();
    } else {
        negotiatedExtensionsPhase2 = new ArrayList<Extension>(transformations.size());
        for (Transformation t : transformations) {
            negotiatedExtensionsPhase2.add(t.getExtensionResponse());
        }
    }
    // Build the transformation pipeline
    Transformation transformation = null;
    StringBuilder responseHeaderExtensions = new StringBuilder();
    boolean first = true;
    for (Transformation t : transformations) {
        if (first) {
            first = false;
        } else {
            responseHeaderExtensions.append(',');
        }
        append(responseHeaderExtensions, t.getExtensionResponse());
        if (transformation == null) {
            transformation = t;
        } else {
            transformation.setNext(t);
        }
    }
    // Now we have the full pipeline, validate the use of the RSV bits.
    if (transformation != null && !transformation.validateRsvBits(0)) {
        throw new ServletException(sm.getString("upgradeUtil.incompatibleRsv"));
    }
    // If we got this far, all is good. Accept the connection.
    resp.setHeader(Constants.UPGRADE_HEADER_NAME, Constants.UPGRADE_HEADER_VALUE);
    resp.setHeader(Constants.CONNECTION_HEADER_NAME, Constants.CONNECTION_HEADER_VALUE);
    resp.setHeader(HandshakeResponse.SEC_WEBSOCKET_ACCEPT, getWebSocketAccept(key));
    if (subProtocol != null && subProtocol.length() > 0) {
        // RFC6455 4.2.2 explicitly states "" is not valid here
        resp.setHeader(Constants.WS_PROTOCOL_HEADER_NAME, subProtocol);
    }
    if (!transformations.isEmpty()) {
        resp.setHeader(Constants.WS_EXTENSIONS_HEADER_NAME, responseHeaderExtensions.toString());
    }
    WsHandshakeRequest wsRequest = new WsHandshakeRequest(req, pathParams);
    WsHandshakeResponse wsResponse = new WsHandshakeResponse();
    WsPerSessionServerEndpointConfig perSessionServerEndpointConfig = new WsPerSessionServerEndpointConfig(sec);
    sec.getConfigurator().modifyHandshake(perSessionServerEndpointConfig, wsRequest, wsResponse);
    wsRequest.finished();
    // Add any additional headers
    for (Entry<String, List<String>> entry : wsResponse.getHeaders().entrySet()) {
        for (String headerValue : entry.getValue()) {
            resp.addHeader(entry.getKey(), headerValue);
        }
    }
    Endpoint ep;
    try {
        Class<?> clazz = sec.getEndpointClass();
        if (Endpoint.class.isAssignableFrom(clazz)) {
            ep = (Endpoint) sec.getConfigurator().getEndpointInstance(clazz);
        } else {
            ep = new PojoEndpointServer();
            // Need to make path params available to POJO
            perSessionServerEndpointConfig.getUserProperties().put(PojoEndpointServer.POJO_PATH_PARAM_KEY, pathParams);
        }
    } catch (InstantiationException e) {
        throw new ServletException(e);
    }
    // Small hack until the Servlet API provides a way to do this.
    ServletRequest inner = req;
    // Unwrap the request
    while (inner instanceof ServletRequestWrapper) {
        inner = ((ServletRequestWrapper) inner).getRequest();
    }
    if (inner instanceof RequestFacade) {
        WsHttpUpgradeHandler wsHandler = ((RequestFacade) inner).upgrade(WsHttpUpgradeHandler.class);
        wsHandler.preInit(ep, perSessionServerEndpointConfig, sc, wsRequest, negotiatedExtensionsPhase2, subProtocol, transformation, pathParams, req.isSecure());
    } else {
        throw new ServletException("Upgrade failed");
    }
}
Also used : HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletRequest(javax.servlet.ServletRequest) Transformation(org.apache.tomcat.websocket.Transformation) ArrayList(java.util.ArrayList) PojoEndpointServer(org.apache.tomcat.websocket.pojo.PojoEndpointServer) ServletException(javax.servlet.ServletException) Endpoint(javax.websocket.Endpoint) ArrayList(java.util.ArrayList) List(java.util.List) WsHandshakeResponse(org.apache.tomcat.websocket.WsHandshakeResponse) ServletRequestWrapper(javax.servlet.ServletRequestWrapper) RequestFacade(org.apache.catalina.connector.RequestFacade) Extension(javax.websocket.Extension)

Example 2 with WsHandshakeResponse

use of org.apache.tomcat.websocket.WsHandshakeResponse in project tomcat by apache.

the class UpgradeUtil method doUpgrade.

public static void doUpgrade(WsServerContainer sc, HttpServletRequest req, HttpServletResponse resp, ServerEndpointConfig sec, Map<String, String> pathParams) throws ServletException, IOException {
    // Validate the rest of the headers and reject the request if that
    // validation fails
    String key;
    String subProtocol = null;
    if (!headerContainsToken(req, Constants.CONNECTION_HEADER_NAME, Constants.CONNECTION_HEADER_VALUE)) {
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
        return;
    }
    if (!headerContainsToken(req, Constants.WS_VERSION_HEADER_NAME, Constants.WS_VERSION_HEADER_VALUE)) {
        resp.setStatus(426);
        resp.setHeader(Constants.WS_VERSION_HEADER_NAME, Constants.WS_VERSION_HEADER_VALUE);
        return;
    }
    key = req.getHeader(Constants.WS_KEY_HEADER_NAME);
    if (key == null) {
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
        return;
    }
    // Origin check
    String origin = req.getHeader(Constants.ORIGIN_HEADER_NAME);
    if (!sec.getConfigurator().checkOrigin(origin)) {
        resp.sendError(HttpServletResponse.SC_FORBIDDEN);
        return;
    }
    // Sub-protocols
    List<String> subProtocols = getTokensFromHeader(req, Constants.WS_PROTOCOL_HEADER_NAME);
    subProtocol = sec.getConfigurator().getNegotiatedSubprotocol(sec.getSubprotocols(), subProtocols);
    // Extensions
    // Should normally only be one header but handle the case of multiple
    // headers
    List<Extension> extensionsRequested = new ArrayList<>();
    Enumeration<String> extHeaders = req.getHeaders(Constants.WS_EXTENSIONS_HEADER_NAME);
    while (extHeaders.hasMoreElements()) {
        Util.parseExtensionHeader(extensionsRequested, extHeaders.nextElement());
    }
    // Negotiation phase 1. By default this simply filters out the
    // extensions that the server does not support but applications could
    // use a custom configurator to do more than this.
    List<Extension> installedExtensions = null;
    if (sec.getExtensions().size() == 0) {
        installedExtensions = Constants.INSTALLED_EXTENSIONS;
    } else {
        installedExtensions = new ArrayList<>();
        installedExtensions.addAll(sec.getExtensions());
        installedExtensions.addAll(Constants.INSTALLED_EXTENSIONS);
    }
    List<Extension> negotiatedExtensionsPhase1 = sec.getConfigurator().getNegotiatedExtensions(installedExtensions, extensionsRequested);
    // Negotiation phase 2. Create the Transformations that will be applied
    // to this connection. Note than an extension may be dropped at this
    // point if the client has requested a configuration that the server is
    // unable to support.
    List<Transformation> transformations = createTransformations(negotiatedExtensionsPhase1);
    List<Extension> negotiatedExtensionsPhase2;
    if (transformations.isEmpty()) {
        negotiatedExtensionsPhase2 = Collections.emptyList();
    } else {
        negotiatedExtensionsPhase2 = new ArrayList<>(transformations.size());
        for (Transformation t : transformations) {
            negotiatedExtensionsPhase2.add(t.getExtensionResponse());
        }
    }
    // Build the transformation pipeline
    Transformation transformation = null;
    StringBuilder responseHeaderExtensions = new StringBuilder();
    boolean first = true;
    for (Transformation t : transformations) {
        if (first) {
            first = false;
        } else {
            responseHeaderExtensions.append(',');
        }
        append(responseHeaderExtensions, t.getExtensionResponse());
        if (transformation == null) {
            transformation = t;
        } else {
            transformation.setNext(t);
        }
    }
    // Now we have the full pipeline, validate the use of the RSV bits.
    if (transformation != null && !transformation.validateRsvBits(0)) {
        throw new ServletException(sm.getString("upgradeUtil.incompatibleRsv"));
    }
    // If we got this far, all is good. Accept the connection.
    resp.setHeader(Constants.UPGRADE_HEADER_NAME, Constants.UPGRADE_HEADER_VALUE);
    resp.setHeader(Constants.CONNECTION_HEADER_NAME, Constants.CONNECTION_HEADER_VALUE);
    resp.setHeader(HandshakeResponse.SEC_WEBSOCKET_ACCEPT, getWebSocketAccept(key));
    if (subProtocol != null && subProtocol.length() > 0) {
        // RFC6455 4.2.2 explicitly states "" is not valid here
        resp.setHeader(Constants.WS_PROTOCOL_HEADER_NAME, subProtocol);
    }
    if (!transformations.isEmpty()) {
        resp.setHeader(Constants.WS_EXTENSIONS_HEADER_NAME, responseHeaderExtensions.toString());
    }
    // Add method mapping to user properties
    if (!Endpoint.class.isAssignableFrom(sec.getEndpointClass()) && sec.getUserProperties().get(org.apache.tomcat.websocket.pojo.Constants.POJO_METHOD_MAPPING_KEY) == null) {
        // directly. Need to add the method mapping.
        try {
            PojoMethodMapping methodMapping = new PojoMethodMapping(sec.getEndpointClass(), sec.getDecoders(), sec.getPath(), sc.getInstanceManager(Thread.currentThread().getContextClassLoader()));
            if (methodMapping.getOnClose() != null || methodMapping.getOnOpen() != null || methodMapping.getOnError() != null || methodMapping.hasMessageHandlers()) {
                sec.getUserProperties().put(org.apache.tomcat.websocket.pojo.Constants.POJO_METHOD_MAPPING_KEY, methodMapping);
            }
        } catch (DeploymentException e) {
            throw new ServletException(sm.getString("upgradeUtil.pojoMapFail", sec.getEndpointClass().getName()), e);
        }
    }
    WsPerSessionServerEndpointConfig perSessionServerEndpointConfig = new WsPerSessionServerEndpointConfig(sec);
    WsHandshakeRequest wsRequest = new WsHandshakeRequest(req, pathParams);
    WsHandshakeResponse wsResponse = new WsHandshakeResponse();
    sec.getConfigurator().modifyHandshake(perSessionServerEndpointConfig, wsRequest, wsResponse);
    wsRequest.finished();
    // Add any additional headers
    for (Entry<String, List<String>> entry : wsResponse.getHeaders().entrySet()) {
        for (String headerValue : entry.getValue()) {
            resp.addHeader(entry.getKey(), headerValue);
        }
    }
    WsHttpUpgradeHandler wsHandler = req.upgrade(WsHttpUpgradeHandler.class);
    wsHandler.preInit(perSessionServerEndpointConfig, sc, wsRequest, negotiatedExtensionsPhase2, subProtocol, transformation, pathParams, req.isSecure());
}
Also used : Transformation(org.apache.tomcat.websocket.Transformation) WsHandshakeResponse(org.apache.tomcat.websocket.WsHandshakeResponse) ArrayList(java.util.ArrayList) Extension(jakarta.websocket.Extension) ServletException(jakarta.servlet.ServletException) DeploymentException(jakarta.websocket.DeploymentException) ArrayList(java.util.ArrayList) List(java.util.List) PojoMethodMapping(org.apache.tomcat.websocket.pojo.PojoMethodMapping)

Aggregations

ArrayList (java.util.ArrayList)2 List (java.util.List)2 Transformation (org.apache.tomcat.websocket.Transformation)2 WsHandshakeResponse (org.apache.tomcat.websocket.WsHandshakeResponse)2 ServletException (jakarta.servlet.ServletException)1 DeploymentException (jakarta.websocket.DeploymentException)1 Extension (jakarta.websocket.Extension)1 ServletException (javax.servlet.ServletException)1 ServletRequest (javax.servlet.ServletRequest)1 ServletRequestWrapper (javax.servlet.ServletRequestWrapper)1 HttpServletRequest (javax.servlet.http.HttpServletRequest)1 Endpoint (javax.websocket.Endpoint)1 Extension (javax.websocket.Extension)1 RequestFacade (org.apache.catalina.connector.RequestFacade)1 PojoEndpointServer (org.apache.tomcat.websocket.pojo.PojoEndpointServer)1 PojoMethodMapping (org.apache.tomcat.websocket.pojo.PojoMethodMapping)1