Search in sources :

Example 1 with ExtensionStack

use of org.eclipse.jetty.websocket.common.extensions.ExtensionStack in project jetty.project by eclipse.

the class WebSocketUpgradeRequest method upgrade.

@Override
public void upgrade(HttpResponse response, HttpConnectionOverHTTP oldConn) {
    if (!this.getHeaders().get(HttpHeader.UPGRADE).equalsIgnoreCase("websocket")) {
        // Not my upgrade
        throw new HttpResponseException("Not WebSocket Upgrade", response);
    }
    // Check the Accept hash
    String reqKey = this.getHeaders().get(HttpHeader.SEC_WEBSOCKET_KEY);
    String expectedHash = AcceptHash.hashKey(reqKey);
    String respHash = response.getHeaders().get(HttpHeader.SEC_WEBSOCKET_ACCEPT);
    if (expectedHash.equalsIgnoreCase(respHash) == false) {
        throw new HttpResponseException("Invalid Sec-WebSocket-Accept hash", response);
    }
    // We can upgrade
    EndPoint endp = oldConn.getEndPoint();
    WebSocketClientConnection connection = new WebSocketClientConnection(endp, wsClient.getExecutor(), wsClient.getScheduler(), localEndpoint.getPolicy(), wsClient.getBufferPool());
    URI requestURI = this.getURI();
    WebSocketSession session = getSessionFactory().createSession(requestURI, localEndpoint, connection);
    session.setUpgradeRequest(new ClientUpgradeRequest(this));
    session.setUpgradeResponse(new ClientUpgradeResponse(response));
    connection.addListener(session);
    ExtensionStack extensionStack = new ExtensionStack(getExtensionFactory());
    List<ExtensionConfig> extensions = new ArrayList<>();
    HttpField extField = response.getHeaders().getField(HttpHeader.SEC_WEBSOCKET_EXTENSIONS);
    if (extField != null) {
        String[] extValues = extField.getValues();
        if (extValues != null) {
            for (String extVal : extValues) {
                QuotedStringTokenizer tok = new QuotedStringTokenizer(extVal, ",");
                while (tok.hasMoreTokens()) {
                    extensions.add(ExtensionConfig.parse(tok.nextToken()));
                }
            }
        }
    }
    extensionStack.negotiate(extensions);
    extensionStack.configure(connection.getParser());
    extensionStack.configure(connection.getGenerator());
    // Setup Incoming Routing
    connection.setNextIncomingFrames(extensionStack);
    extensionStack.setNextIncoming(session);
    // Setup Outgoing Routing
    session.setOutgoingHandler(extensionStack);
    extensionStack.setNextOutgoing(connection);
    session.addManaged(extensionStack);
    session.setFuture(fut);
    wsClient.addManaged(session);
    if (upgradeListener != null) {
        upgradeListener.onHandshakeResponse(new ClientUpgradeResponse(response));
    }
    // Now swap out the connection
    endp.upgrade(connection);
}
Also used : ArrayList(java.util.ArrayList) WebSocketClientConnection(org.eclipse.jetty.websocket.client.io.WebSocketClientConnection) HttpResponseException(org.eclipse.jetty.client.HttpResponseException) EndPoint(org.eclipse.jetty.io.EndPoint) URI(java.net.URI) ExtensionStack(org.eclipse.jetty.websocket.common.extensions.ExtensionStack) WebSocketSession(org.eclipse.jetty.websocket.common.WebSocketSession) QuotedStringTokenizer(org.eclipse.jetty.util.QuotedStringTokenizer) ExtensionConfig(org.eclipse.jetty.websocket.api.extensions.ExtensionConfig) HttpField(org.eclipse.jetty.http.HttpField)

Example 2 with ExtensionStack

use of org.eclipse.jetty.websocket.common.extensions.ExtensionStack in project jetty.project by eclipse.

the class BlockheadClient method expectUpgradeResponse.

/* (non-Javadoc)
     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#expectUpgradeResponse()
     */
@Override
public HttpResponse expectUpgradeResponse() throws IOException {
    HttpResponse response = readResponseHeader();
    if (LOG.isDebugEnabled()) {
        LOG.debug("Response Header: {}{}", '\n', response);
    }
    Assert.assertThat("Response Status Code", response.getStatusCode(), is(101));
    Assert.assertThat("Response Status Reason", response.getStatusReason(), is("Switching Protocols"));
    Assert.assertThat("Response Header[Upgrade]", response.getHeader("Upgrade"), is("WebSocket"));
    Assert.assertThat("Response Header[Connection]", response.getHeader("Connection"), is("Upgrade"));
    // Validate the Sec-WebSocket-Accept
    String acceptKey = response.getHeader("Sec-WebSocket-Accept");
    Assert.assertThat("Response Header[Sec-WebSocket-Accept Exists]", acceptKey, notNullValue());
    String reqKey = REQUEST_HASH_KEY;
    String expectedHash = AcceptHash.hashKey(reqKey);
    Assert.assertThat("Valid Sec-WebSocket-Accept Hash?", acceptKey, is(expectedHash));
    // collect extensions configured in response header
    List<ExtensionConfig> configs = getExtensionConfigs(response);
    extensionStack = new ExtensionStack(this.extensionFactory);
    extensionStack.negotiate(configs);
    // Setup Frame Reader
    this.frameReader = new FrameReadingThread();
    this.frameReader.start();
    // Start with default routing
    // the websocket layer
    extensionStack.setNextIncoming(frameReader);
    // the network layer
    extensionStack.setNextOutgoing(outgoing);
    // Configure Parser / Generator
    extensionStack.configure(parser);
    extensionStack.configure(generator);
    // Start Stack
    try {
        extensionStack.start();
    } catch (Exception e) {
        throw new IOException("Unable to start Extension Stack");
    }
    // configure parser
    parser.setIncomingFramesHandler(extensionStack);
    ioState.onOpened();
    LOG.debug("outgoing = {}", outgoing);
    LOG.debug("incoming = {}", extensionStack);
    return response;
}
Also used : ExtensionConfig(org.eclipse.jetty.websocket.api.extensions.ExtensionConfig) IOException(java.io.IOException) ExtensionStack(org.eclipse.jetty.websocket.common.extensions.ExtensionStack) URISyntaxException(java.net.URISyntaxException) EOFException(java.io.EOFException) SocketTimeoutException(java.net.SocketTimeoutException) IOException(java.io.IOException)

Example 3 with ExtensionStack

use of org.eclipse.jetty.websocket.common.extensions.ExtensionStack in project jetty.project by eclipse.

the class ExtensionStackProcessingTest method testDeflateFrameExtension.

@Test
public void testDeflateFrameExtension() throws Exception {
    assumeDeflateFrameAvailable();
    ClientEndpointConfig config = ClientEndpointConfig.Builder.create().extensions(Arrays.<Extension>asList(new JsrExtension("deflate-frame"))).build();
    final String content = "deflate_me";
    final CountDownLatch messageLatch = new CountDownLatch(1);
    URI uri = URI.create("ws://localhost:" + connector.getLocalPort());
    Session session = client.connectToServer(new EndpointAdapter() {

        @Override
        public void onMessage(String message) {
            Assert.assertEquals(content, message);
            messageLatch.countDown();
        }
    }, config, uri);
    // Make sure everything is wired properly.
    OutgoingFrames firstOut = ((JsrSession) session).getOutgoingHandler();
    Assert.assertTrue(firstOut instanceof ExtensionStack);
    ExtensionStack extensionStack = (ExtensionStack) firstOut;
    Assert.assertTrue(extensionStack.isRunning());
    OutgoingFrames secondOut = extensionStack.getNextOutgoing();
    Assert.assertTrue(secondOut instanceof DeflateFrameExtension);
    DeflateFrameExtension deflateExtension = (DeflateFrameExtension) secondOut;
    Assert.assertTrue(deflateExtension.isRunning());
    OutgoingFrames thirdOut = deflateExtension.getNextOutgoing();
    Assert.assertTrue(thirdOut instanceof WebSocketClientConnection);
    final CountDownLatch latch = new CountDownLatch(1);
    session.getAsyncRemote().sendText(content, new SendHandler() {

        @Override
        public void onResult(SendResult result) {
            latch.countDown();
        }
    });
    Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
    Assert.assertTrue(messageLatch.await(5, TimeUnit.SECONDS));
}
Also used : SendHandler(javax.websocket.SendHandler) WebSocketClientConnection(org.eclipse.jetty.websocket.client.io.WebSocketClientConnection) JsrSession(org.eclipse.jetty.websocket.jsr356.JsrSession) CountDownLatch(java.util.concurrent.CountDownLatch) URI(java.net.URI) ExtensionStack(org.eclipse.jetty.websocket.common.extensions.ExtensionStack) JsrExtension(org.eclipse.jetty.websocket.jsr356.JsrExtension) Extension(javax.websocket.Extension) DeflateFrameExtension(org.eclipse.jetty.websocket.common.extensions.compress.DeflateFrameExtension) JsrExtension(org.eclipse.jetty.websocket.jsr356.JsrExtension) SendResult(javax.websocket.SendResult) OutgoingFrames(org.eclipse.jetty.websocket.api.extensions.OutgoingFrames) ClientEndpointConfig(javax.websocket.ClientEndpointConfig) DeflateFrameExtension(org.eclipse.jetty.websocket.common.extensions.compress.DeflateFrameExtension) Session(javax.websocket.Session) JsrSession(org.eclipse.jetty.websocket.jsr356.JsrSession) Test(org.junit.Test)

Example 4 with ExtensionStack

use of org.eclipse.jetty.websocket.common.extensions.ExtensionStack in project jetty.project by eclipse.

the class WebSocketServerFactory method upgrade.

/**
     * Upgrade the request/response to a WebSocket Connection.
     * <p/>
     * This method will not normally return, but will instead throw a UpgradeConnectionException, to exit HTTP handling and initiate WebSocket handling of the
     * connection.
     *
     * @param http the raw http connection
     * @param request The request to upgrade
     * @param response The response to upgrade
     * @param driver The websocket handler implementation to use
     */
private boolean upgrade(HttpConnection http, ServletUpgradeRequest request, ServletUpgradeResponse response, EventDriver driver) throws IOException {
    if (!"websocket".equalsIgnoreCase(request.getHeader("Upgrade"))) {
        throw new IllegalStateException("Not a 'WebSocket: Upgrade' request");
    }
    if (!"HTTP/1.1".equals(request.getHttpVersion())) {
        throw new IllegalStateException("Not a 'HTTP/1.1' request");
    }
    int version = request.getHeaderInt("Sec-WebSocket-Version");
    if (version < 0) {
        // Old pre-RFC version specifications (header not present in RFC-6455)
        version = request.getHeaderInt("Sec-WebSocket-Draft");
    }
    WebSocketHandshake handshaker = handshakes.get(version);
    if (handshaker == null) {
        StringBuilder warn = new StringBuilder();
        warn.append("Client ").append(request.getRemoteAddress());
        warn.append(" (:").append(request.getRemotePort());
        warn.append(") User Agent: ");
        String ua = request.getHeader("User-Agent");
        if (ua == null) {
            warn.append("[unset] ");
        } else {
            warn.append('"').append(StringUtil.sanitizeXmlString(ua)).append("\" ");
        }
        warn.append("requested WebSocket version [").append(version);
        warn.append("], Jetty supports version");
        if (handshakes.size() > 1) {
            warn.append('s');
        }
        warn.append(": [").append(supportedVersions).append("]");
        LOG.warn(warn.toString());
        // Per RFC 6455 - 4.4 - Supporting Multiple Versions of WebSocket Protocol
        // Using the examples as outlined
        response.setHeader("Sec-WebSocket-Version", supportedVersions);
        response.sendError(HttpStatus.BAD_REQUEST_400, "Unsupported websocket version specification");
        return false;
    }
    // Initialize / Negotiate Extensions
    ExtensionStack extensionStack = new ExtensionStack(getExtensionFactory());
    // Usually from a Configurator.
    if (response.isExtensionsNegotiated()) {
        // Use pre-negotiated extension list from response
        extensionStack.negotiate(response.getExtensions());
    } else {
        // Use raw extension list from request
        extensionStack.negotiate(request.getExtensions());
    }
    // Get original HTTP connection
    EndPoint endp = http.getEndPoint();
    Connector connector = http.getConnector();
    Executor executor = connector.getExecutor();
    ByteBufferPool bufferPool = connector.getByteBufferPool();
    // Setup websocket connection
    AbstractWebSocketConnection wsConnection = new WebSocketServerConnection(endp, executor, scheduler, driver.getPolicy(), bufferPool);
    extensionStack.setPolicy(driver.getPolicy());
    extensionStack.configure(wsConnection.getParser());
    extensionStack.configure(wsConnection.getGenerator());
    if (LOG.isDebugEnabled()) {
        LOG.debug("HttpConnection: {}", http);
        LOG.debug("WebSocketConnection: {}", wsConnection);
    }
    // Setup Session
    WebSocketSession session = createSession(request.getRequestURI(), driver, wsConnection);
    session.setUpgradeRequest(request);
    // set true negotiated extension list back to response
    response.setExtensions(extensionStack.getNegotiatedExtensions());
    session.setUpgradeResponse(response);
    wsConnection.addListener(session);
    // Setup Incoming Routing
    wsConnection.setNextIncomingFrames(extensionStack);
    extensionStack.setNextIncoming(session);
    // Setup Outgoing Routing
    session.setOutgoingHandler(extensionStack);
    extensionStack.setNextOutgoing(wsConnection);
    // Start Components
    session.addManaged(extensionStack);
    this.addManaged(session);
    if (session.isFailed()) {
        throw new IOException("Session failed to start");
    }
    // Tell jetty about the new upgraded connection
    request.setServletAttribute(HttpConnection.UPGRADE_CONNECTION_ATTRIBUTE, wsConnection);
    if (LOG.isDebugEnabled())
        LOG.debug("Handshake Response: {}", handshaker);
    if (getSendServerVersion(connector))
        response.setHeader("Server", HttpConfiguration.SERVER_VERSION);
    // Process (version specific) handshake response
    handshaker.doHandshakeResponse(request, response);
    if (LOG.isDebugEnabled())
        LOG.debug("Websocket upgrade {} {} {} {}", request.getRequestURI(), version, response.getAcceptedSubProtocol(), wsConnection);
    return true;
}
Also used : ByteBufferPool(org.eclipse.jetty.io.ByteBufferPool) MappedByteBufferPool(org.eclipse.jetty.io.MappedByteBufferPool) Connector(org.eclipse.jetty.server.Connector) EndPoint(org.eclipse.jetty.io.EndPoint) IOException(java.io.IOException) ExtensionStack(org.eclipse.jetty.websocket.common.extensions.ExtensionStack) EndPoint(org.eclipse.jetty.io.EndPoint) AbstractWebSocketConnection(org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection) WebSocketSession(org.eclipse.jetty.websocket.common.WebSocketSession) Executor(java.util.concurrent.Executor)

Example 5 with ExtensionStack

use of org.eclipse.jetty.websocket.common.extensions.ExtensionStack in project jetty.project by eclipse.

the class BlockheadServerConnection method upgrade.

public List<String> upgrade() throws IOException {
    List<String> requestLines = readRequestLines();
    List<ExtensionConfig> extensionConfigs = parseExtensions(requestLines);
    String key = parseWebSocketKey(requestLines);
    LOG.debug("Client Request Extensions: {}", extensionConfigs);
    LOG.debug("Client Request Key: {}", key);
    Assert.assertThat("Request: Sec-WebSocket-Key", key, notNullValue());
    // collect extensions configured in response header
    ExtensionStack extensionStack = new ExtensionStack(extensionRegistry);
    extensionStack.negotiate(extensionConfigs);
    // Start with default routing
    extensionStack.setNextIncoming(this);
    extensionStack.setNextOutgoing(this);
    // Configure Parser / Generator
    extensionStack.configure(parser);
    extensionStack.configure(generator);
    // Start Stack
    try {
        extensionStack.start();
    } catch (Exception e) {
        throw new IOException("Unable to start Extension Stack");
    }
    // Configure Parser
    parser.setIncomingFramesHandler(extensionStack);
    // Setup Response
    StringBuilder resp = new StringBuilder();
    resp.append("HTTP/1.1 101 Upgrade\r\n");
    resp.append("Connection: upgrade\r\n");
    resp.append("Content-Length: 0\r\n");
    resp.append("Sec-WebSocket-Accept: ");
    resp.append(AcceptHash.hashKey(key)).append("\r\n");
    if (extensionStack.hasNegotiatedExtensions()) {
        // Respond to used extensions
        resp.append("Sec-WebSocket-Extensions: ");
        boolean delim = false;
        for (ExtensionConfig ext : extensionStack.getNegotiatedExtensions()) {
            if (delim) {
                resp.append(", ");
            }
            resp.append(ext.getParameterizedName());
            delim = true;
        }
        resp.append("\r\n");
    }
    if (extraResponseHeaders.size() > 0) {
        for (Map.Entry<String, String> xheader : extraResponseHeaders.entrySet()) {
            resp.append(xheader.getKey());
            resp.append(": ");
            resp.append(xheader.getValue());
            resp.append("\r\n");
        }
    }
    resp.append("\r\n");
    // Write Response
    LOG.debug("Response: {}", resp.toString());
    write(resp.toString().getBytes());
    return requestLines;
}
Also used : ExtensionConfig(org.eclipse.jetty.websocket.api.extensions.ExtensionConfig) IOException(java.io.IOException) ExtensionStack(org.eclipse.jetty.websocket.common.extensions.ExtensionStack) HashMap(java.util.HashMap) Map(java.util.Map) TimeoutException(java.util.concurrent.TimeoutException) SocketException(java.net.SocketException) IOException(java.io.IOException)

Aggregations

ExtensionStack (org.eclipse.jetty.websocket.common.extensions.ExtensionStack)5 IOException (java.io.IOException)3 ExtensionConfig (org.eclipse.jetty.websocket.api.extensions.ExtensionConfig)3 URI (java.net.URI)2 EndPoint (org.eclipse.jetty.io.EndPoint)2 WebSocketClientConnection (org.eclipse.jetty.websocket.client.io.WebSocketClientConnection)2 WebSocketSession (org.eclipse.jetty.websocket.common.WebSocketSession)2 EOFException (java.io.EOFException)1 SocketException (java.net.SocketException)1 SocketTimeoutException (java.net.SocketTimeoutException)1 URISyntaxException (java.net.URISyntaxException)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 CountDownLatch (java.util.concurrent.CountDownLatch)1 Executor (java.util.concurrent.Executor)1 TimeoutException (java.util.concurrent.TimeoutException)1 ClientEndpointConfig (javax.websocket.ClientEndpointConfig)1 Extension (javax.websocket.Extension)1 SendHandler (javax.websocket.SendHandler)1