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

org.webbitserver.netty.Hybi Maven / Gradle / Ivy

package org.webbitserver.netty;

import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.webbitserver.helpers.Base64;

import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.UPGRADE;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Values.WEBSOCKET;

public class Hybi implements WebSocketVersion {
    public static final String SEC_WEBSOCKET_VERSION = "Sec-WebSocket-Version";
    public static final String SEC_WEBSOCKET_ACCEPT = "Sec-WebSocket-Accept";
    public static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key";
    private static final Charset ASCII = Charset.forName("ASCII");
    private static final String ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    private static final int MIN_HYBI_VERSION = 8;
    private static final MessageDigest SHA1;

    static {
        try {
            SHA1 = MessageDigest.getInstance("SHA1");
        } catch (NoSuchAlgorithmException e) {
            throw new InternalError("SHA-1 not supported on this platform");
        }
    }

    private final HttpRequest req;
    private final HttpResponse res;

    public Hybi(HttpRequest req, HttpResponse res) {
        this.req = req;
        this.res = res;
    }

    @Override
    public boolean matches() {
        return getHybiVersion() != null;
    }

    @Override
    public void prepareHandshakeResponse(NettyWebSocketConnection webSocketConnection) {
        webSocketConnection.setHybiWebSocketVersion(getHybiVersion());

        if (getHybiVersion() < MIN_HYBI_VERSION) {
            res.setStatus(HttpResponseStatus.UPGRADE_REQUIRED);
            res.setHeader(SEC_WEBSOCKET_VERSION, String.valueOf(MIN_HYBI_VERSION));
            return;
        }

        String key = req.getHeader(SEC_WEBSOCKET_KEY);
        if (key == null) {
            res.setStatus(HttpResponseStatus.BAD_REQUEST);
            return;
        }

        String accept = Base64.encode(sha1(key + ACCEPT_GUID));

        res.setStatus(new HttpResponseStatus(101, "Switching Protocols"));
        res.addHeader(UPGRADE, WEBSOCKET.toLowerCase());
        res.addHeader(CONNECTION, UPGRADE);
        res.addHeader(SEC_WEBSOCKET_ACCEPT, accept);
    }

    @Override
    public ChannelHandler createDecoder() {
        return HybiWebSocketFrameDecoder.serverSide();
    }

    @Override
    public ChannelHandler createEncoder() {
        return new HybiWebSocketFrameEncoder();
    }

    private Integer getHybiVersion() {
        return req.containsHeader(SEC_WEBSOCKET_VERSION) ? Integer.parseInt(req.getHeader(SEC_WEBSOCKET_VERSION).trim()) : null;
    }

    private byte[] sha1(String s) {
        return SHA1.digest(s.getBytes(ASCII));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy