package org.jboss.pitbull.internal.client.websocket.protocol.ietf13;
import org.jboss.pitbull.StatusCode;
import org.jboss.pitbull.client.ClientInvocation;
import org.jboss.pitbull.client.HandshakeFailure;
import org.jboss.pitbull.client.HttpConnectionFactory;
import org.jboss.pitbull.client.WebSocketBuilder;
import org.jboss.pitbull.internal.NotImplementedYetException;
import org.jboss.pitbull.internal.client.ClientConnectionImpl;
import org.jboss.pitbull.internal.client.ClientResponseImpl;
import org.jboss.pitbull.internal.nio.socket.BufferedBlockingInputStream;
import org.jboss.pitbull.internal.nio.socket.BufferedBlockingOutputStream;
import org.jboss.pitbull.internal.nio.websocket.WebSocketImpl;
import org.jboss.pitbull.internal.nio.websocket.impl.oio.ClosingStrategy;
import org.jboss.pitbull.internal.nio.websocket.impl.oio.OioWebSocket;
import org.jboss.pitbull.internal.nio.websocket.impl.oio.internal.protocol.ietf13.Hybi13Handshake;
import org.jboss.pitbull.internal.nio.websocket.impl.oio.internal.util.Base64;
import org.jboss.pitbull.websocket.WebSocket;
import org.jboss.pitbull.websocket.WebSocketVersion;
import java.io.IOException;
import java.util.Random;
import static org.jboss.pitbull.internal.nio.websocket.impl.oio.internal.WebSocketHeaders.*;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Hybi13WebSocketBuilder extends WebSocketBuilder
{
protected Random random = new Random();
@Override
protected WebSocket doConnect() throws IOException
{
final ClientConnectionImpl connection;
if (secured)
{
if (trustStore == null) connection = (ClientConnectionImpl) HttpConnectionFactory.https(host, port);
else throw new NotImplementedYetException("wss with truststore not implemented yet");
}
else
{
connection = (ClientConnectionImpl) HttpConnectionFactory.http(host, port);
}
try
{
ClientInvocation invocation = connection.request(path).get();
invocation.header("Upgrade", "websocket");
invocation.header("Connection", "upgrade");
byte[] key = new byte[16];
random.nextBytes(key);
String encodedKey = Base64.encodeBase64String(key);
invocation.header(SEC_WEBSOCKET_KEY.getCanonicalHeaderName(), encodedKey);
if (origin != null) invocation.header(ORIGIN.getCanonicalHeaderName(), origin);
invocation.header(SEC_WEBSOCKET_VERSION.getCanonicalHeaderName(), WebSocketVersion.HYBI_13.getCode());
if (protocol != null) invocation.header(SEC_WEBSOCKET_PROTOCOL.getCanonicalHeaderName(), protocol);
ClientResponseImpl response = (ClientResponseImpl) invocation.invoke();
if (response.getStatus() != StatusCode.SWITCHING_PROTOCOLS)
{
throw new HandshakeFailure("Error making handshake: " + response.getStatus(), response);
}
String upgrade = response.getHeaders().getFirstHeader("Upgrade");
if (!"websocket".equalsIgnoreCase(upgrade))
{
throw new HandshakeFailure("Incorrect Upgrade heaader", response);
}
String accept = response.getHeaders().getFirstHeader(SEC_WEBSOCKET_ACCEPT.getCanonicalHeaderName());
if (accept == null)
{
throw new HandshakeFailure("No value for header: " + SEC_WEBSOCKET_ACCEPT.getCanonicalHeaderName());
}
Hybi13Handshake handshake = new Hybi13Handshake();
String solution = handshake.solve(encodedKey);
if (!solution.equals(accept.trim()))
{
throw new HandshakeFailure(SEC_WEBSOCKET_ACCEPT.getCanonicalHeaderName() + " does not meet expect value", response);
}
String chosenProtocol = response.getHeaders().getFirstHeader(SEC_WEBSOCKET_PROTOCOL.getCanonicalHeaderName());
if (protocol != null)
{
boolean match = false;
String[] split = protocol.split(",");
for (String p : split)
{
if (p.equals(chosenProtocol))
{
match = true;
break;
}
}
if (!match)
{
throw new HandshakeFailure("No protocol match", response);
}
}
OioWebSocket oioWebSocket = handshake.getClientWebSocket(
uri,
new BufferedBlockingInputStream(connection.getChannel(), response.getBuffer()),
new BufferedBlockingOutputStream((connection.getChannel())),
new ClosingStrategy()
{
@Override
public void doClose() throws IOException
{
connection.close();
}
}
);
return new WebSocketImpl(connection, oioWebSocket);
}
catch (IOException e)
{
connection.close();
throw e;
}
catch (RuntimeException e)
{
connection.close();
throw e;
}
}
}