All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.grizzly.websockets.draft76.HandShake76 Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package org.glassfish.grizzly.websockets.draft76;

import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.Random;

import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.http.HttpContent;
import org.glassfish.grizzly.http.HttpHeader;
import org.glassfish.grizzly.http.HttpRequestPacket;
import org.glassfish.grizzly.http.HttpResponsePacket;
import org.glassfish.grizzly.http.util.MimeHeaders;
import org.glassfish.grizzly.memory.HeapBuffer;
import org.glassfish.grizzly.websockets.HandShake;
import org.glassfish.grizzly.websockets.HandshakeException;
import org.glassfish.grizzly.websockets.WebSocketApplication;
import org.glassfish.grizzly.websockets.WebSocketEngine;
import org.glassfish.grizzly.websockets.WebSocketException;

public class HandShake76 extends HandShake {
    // Draft 76 headers
    public static final String SEC_WS_KEY1_HEADER = "Sec-WebSocket-Key1";
    public static final String SEC_WS_KEY2_HEADER = "Sec-WebSocket-Key2";
    public static final String SERVER_SEC_WS_ORIGIN_HEADER = "Sec-WebSocket-Origin";
    public static final String SERVER_SEC_WS_LOCATION_HEADER = "Sec-WebSocket-Location";
    private static final int KEY3_SIZE = 8;
    private final SecKey key1;
    private final SecKey key2;
    private final byte[] key3;
    private byte[] serverSecKey;
    private static final Random random = new Random();

    public HandShake76(URI uri) {
        super(uri);
        if(isSecure() && getPort() != 443 || !isSecure() && getPort() != 80) {
            setServerHostName(getServerHostName() + ":" + getPort());
        }
        key1 = SecKey.generateSecKey();
        key2 = SecKey.generateSecKey();
        key3 = new byte[KEY3_SIZE];
        random.nextBytes(key3);
    }

    public HandShake76(HttpContent message) {
        super((HttpRequestPacket) message.getHttpHeader());
        final HttpRequestPacket request = (HttpRequestPacket) message.getHttpHeader();
        final MimeHeaders headers = request.getHeaders();
        key1 = SecKey.parse(headers.getHeader(SEC_WS_KEY1_HEADER));
        key2 = SecKey.parse(headers.getHeader(SEC_WS_KEY2_HEADER));
        key3 = new byte[KEY3_SIZE];

        message.getContent().get(key3);

        serverSecKey = key3 == null ? null : SecKey.generateServerKey(key1, key2, key3);
    }

    @Override
    public HttpContent composeHeaders() {
        final HttpContent httpContent = super.composeHeaders();
        final HttpHeader header = httpContent.getHttpHeader();
        header
//        final HttpRequestPacket.Builder builder = HttpRequestPacket.builder()
            .addHeader(WebSocketEngine.CLIENT_WS_ORIGIN_HEADER, getOrigin());
        header
            .addHeader(SEC_WS_KEY1_HEADER, key1.getSecKey());
        header
            .addHeader(SEC_WS_KEY2_HEADER, key2.getSecKey());
//        httpContent.append(HttpContent.builder(builder.build()).build());
        return httpContent;
    }

    @Override
    public void initiate(FilterChainContext ctx) throws IOException {
        ctx.write(composeHeaders());
        ctx.write(HeapBuffer.wrap(key3));
    }

    @Override
    public void validateServerResponse(HttpResponsePacket headers) {
        super.validateServerResponse(headers);

        final String serverLocation = headers.getHeader(SERVER_SEC_WS_LOCATION_HEADER);
        if(!getLocation().equals(serverLocation)) {
            throw new HandshakeException(String.format("Location field from server doesn't match: client '%s' vs. server '%s'",
                    getLocation(), serverLocation));
        }
        final byte[] clientKey = SecKey.generateServerKey(key1, key2, key3);
        final Buffer buffer = null; // = content.getContent();
        byte[] serverKey = new byte[16];
        buffer.get(serverKey);
        if (!Arrays.equals(clientKey, serverKey)) {
            throw new HandshakeException(String.format("Security keys do not match: client '%s' vs. server '%s'",
                    Arrays.toString(clientKey), Arrays.toString(serverKey)));
        }
    }

    @Override
    public void respond(FilterChainContext ctx, WebSocketApplication app, HttpResponsePacket response) {
        super.respond(ctx, app, response);
        final HeapBuffer buffer = HeapBuffer.wrap(serverSecKey);
        try {
            ctx.write(buffer);
        } catch (IOException e) {
            throw new WebSocketException(e.getMessage(), e);
        }
    }

    @Override
    public void setHeaders(HttpResponsePacket response) {
        response.setReasonPhrase("WebSocket Protocol Handshake");
        response.setHeader("Upgrade", "WebSocket");
        response.setHeader(SERVER_SEC_WS_LOCATION_HEADER, getLocation());
        response.setHeader(SERVER_SEC_WS_ORIGIN_HEADER, getOrigin());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy