/*******************************************************************************
* Copyright (c) 2011 Intalio, Inc.
* ======================================================================
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*******************************************************************************/
package org.eclipse.jetty.websocket.helper;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.URI;
import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.log.StdErrLog;
import org.junit.Assert;
import static org.hamcrest.Matchers.is;
public class SafariD00
{
private static final Logger LOG = Log.getLogger(SafariD00.class);
private URI uri;
private SocketAddress endpoint;
private Socket socket;
private OutputStream out;
private InputStream in;
public SafariD00(URI uri)
{
if (LOG instanceof StdErrLog)
{
((StdErrLog)LOG).setLevel(StdErrLog.LEVEL_DEBUG);
}
this.uri = uri;
this.endpoint = new InetSocketAddress(uri.getHost(),uri.getPort());
}
/**
* Open the Socket to the destination endpoint and
*
* @return the open java Socket.
* @throws IOException
*/
public Socket connect() throws IOException
{
LOG.info("Connecting to endpoint: " + endpoint);
socket = new Socket();
socket.setTcpNoDelay(true);
socket.connect(endpoint,1000);
out = socket.getOutputStream();
in = socket.getInputStream();
return socket;
}
/**
* Issue an Http websocket (Draft-0) upgrade request (using an example request captured from OSX/Safari)
*
* @throws UnsupportedEncodingException
*/
public void issueHandshake() throws IOException
{
LOG.debug("Issuing Handshake");
StringBuilder req = new StringBuilder();
req.append("GET ").append(uri.getPath()).append(" HTTP/1.1\r\n");
req.append("Upgrade: WebSocket\r\n");
req.append("Connection: Upgrade\r\n");
req.append("Host: ").append(uri.getHost()).append(":").append(uri.getPort()).append("\r\n");
req.append("Origin: http://www.google.com/\r\n");
req.append("Sec-WebSocket-Key1: 15{ft :6@87 0 M 5 c901\r\n");
req.append("Sec-WebSocket-Key2: 3? C;7~0 8 \" 3 2105 6 `_ {\r\n");
req.append("\r\n");
LOG.debug("Request:" + req);
byte reqBytes[] = req.toString().getBytes("UTF-8");
byte hixieBytes[] = TypeUtil.fromHexString("e739617916c9daf3");
byte buf[] = new byte[reqBytes.length + hixieBytes.length];
System.arraycopy(reqBytes,0,buf,0,reqBytes.length);
System.arraycopy(hixieBytes,0,buf,reqBytes.length,hixieBytes.length);
// Send HTTP GET Request (with hixie bytes)
out.write(buf,0,buf.length);
out.flush();
socket.setSoTimeout(10000);
// Read HTTP 101 Upgrade / Handshake Response
InputStreamReader reader = new InputStreamReader(in);
LOG.debug("Reading http headers");
int crlfs = 0;
while (true)
{
int read = in.read();
if (read == '\r' || read == '\n')
++crlfs;
else
crlfs = 0;
if (crlfs == 4)
break;
}
// Read expected handshake hixie bytes
byte hixieHandshakeExpected[] = TypeUtil.fromHexString("c7438d956cf611a6af70603e6fa54809");
byte hixieHandshake[] = new byte[hixieHandshakeExpected.length];
Assert.assertThat("Hixie handshake buffer size",hixieHandshake.length,is(16));
LOG.debug("Reading hixie handshake bytes");
int bytesRead = 0;
while (bytesRead < hixieHandshake.length)
{
int val = in.read();
if (val >= 0)
{
hixieHandshake[bytesRead++] = (byte)val;
}
}
Assert.assertThat("Read hixie handshake bytes",bytesRead,is(hixieHandshake.length));
}
public void sendMessage(String... msgs) throws IOException
{
int len = 0;
for (String msg : msgs)
{
LOG.debug("sending message: " + msg);
len += (msg.length() + 2);
}
ByteArrayBuffer buf = new ByteArrayBuffer(len);
for (String msg : msgs)
{
buf.put((byte)0x00);
buf.put(msg.getBytes("UTF-8"));
buf.put((byte)0xFF);
}
out.write(buf.array());
out.flush();
}
public void disconnect() throws IOException
{
LOG.debug("disconnect");
socket.close();
}
}