324369 Implement draft-ietf-hybi-thewebsocketprotocol-01

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@2245 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Greg Wilkins 2010-09-03 07:05:53 +00:00
parent f3c64a9c26
commit 1596451908
14 changed files with 87 additions and 33 deletions

View File

@ -94,6 +94,10 @@ public class WebSocketUpgradeTest extends TestCase
public void onMessage(byte frame, byte[] data, int offset, int length)
{
}
public void onFragment(boolean more, byte opcode, byte[] data, int offset, int length)
{
}
};
@ -245,5 +249,9 @@ public class WebSocketUpgradeTest extends TestCase
{
_outbound.sendMessage(msg);
}
public void onFragment(boolean more, byte opcode, byte[] data, int offset, int length)
{
}
}
}

View File

@ -7,16 +7,17 @@ public interface WebSocket
public final byte LENGTH_FRAME=(byte)0x80;
public final byte SENTINEL_FRAME=(byte)0x00;
void onConnect(Outbound outbound);
void onMessage(byte frame,String data);
void onMessage(byte frame,byte[] data, int offset, int length);
void onMessage(byte opcode,String data);
void onFragment(boolean more,byte opcode,byte[] data, int offset, int length);
void onMessage(byte opcode,byte[] data, int offset, int length);
void onDisconnect();
public interface Outbound
{
void sendMessage(String data) throws IOException;
void sendMessage(byte frame,String data) throws IOException;
void sendMessage(byte frame,byte[] data) throws IOException;
void sendMessage(byte frame,byte[] data, int offset, int length) throws IOException;
void sendMessage(byte opcode,String data) throws IOException;
void sendMessage(byte opcode,byte[] data, int offset, int length) throws IOException;
void sendFragment(boolean more,byte opcode,byte[] data, int offset, int length) throws IOException;
void disconnect();
boolean isOpen();
}

View File

@ -3,10 +3,7 @@ package org.eclipse.jetty.websocket;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.zip.Checksum;
import org.eclipse.jetty.http.HttpParser;
import org.eclipse.jetty.http.security.Credential.MD5;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.ByteArrayBuffer;
@ -14,10 +11,8 @@ import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.Utf8StringBuilder;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.thread.Timeout;
public class WebSocketConnection implements Connection, WebSocket.Outbound
{
@ -51,6 +46,7 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound
_websocket = websocket;
final WebSocketParser.FrameHandler handler = new WebSocketParser.FrameHandler()
{
boolean _fragmented=false;
Utf8StringBuilder _utf8 = new Utf8StringBuilder();
public void onFrame(boolean more, byte flags, byte opcode, Buffer buffer)
@ -62,23 +58,38 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound
if (opcode==0)
{
if (more)
{
_utf8.append(buffer.array(),buffer.getIndex(),buffer.length());
else if (_utf8.length()==0)
_websocket.onMessage(opcode,buffer.toString("utf-8"));
else
_fragmented=true;
}
else if (_fragmented)
{
_utf8.append(buffer.array(),buffer.getIndex(),buffer.length());
_websocket.onMessage(opcode,_utf8.toString());
_utf8.reset();
_fragmented=false;
}
else
{
_websocket.onMessage(opcode,buffer.toString("utf-8"));
}
}
else
{
if (more)
throw new IllegalStateException("not implemented");
{
_websocket.onFragment(true,opcode,array,buffer.getIndex(),buffer.length());
}
else if (_fragmented)
{
_websocket.onFragment(false,opcode,array,buffer.getIndex(),buffer.length());
}
else
{
_websocket.onMessage(opcode,array,buffer.getIndex(),buffer.length());
}
}
}
catch(ThreadDeath th)
{
throw th;
@ -262,14 +273,17 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound
_idle.access(_endp);
}
public void sendMessage(byte frame, byte[] content) throws IOException
public void sendMessage(byte opcode, byte[] content, int offset, int length) throws IOException
{
sendMessage(frame, content, 0, content.length);
_generator.addFrame(opcode,content,offset,length,_endp.getMaxIdleTime());
_generator.flush();
checkWriteable();
_idle.access(_endp);
}
public void sendMessage(byte frame, byte[] content, int offset, int length) throws IOException
public void sendFragment(boolean more,byte opcode, byte[] content, int offset, int length) throws IOException
{
_generator.addFrame(frame,content,offset,length,_endp.getMaxIdleTime());
_generator.addFragment(more,opcode,content,offset,length,_endp.getMaxIdleTime());
_generator.flush();
checkWriteable();
_idle.access(_endp);

View File

@ -13,6 +13,6 @@ public interface WebSocketGenerator
boolean isBufferEmpty();
void addFrame(byte opcode, String content, int maxIdleTime) throws IOException;
void addFrame(byte opcode, byte[] content, int offset, int length, int maxIdleTime) throws IOException;
void addFrame(byte opcode, byte[] content, int maxIdleTime)throws IOException;
void addFragment(boolean more,byte opcode, byte[] content, int offset, int length, int maxIdleTime) throws IOException;
int flush(int maxIdleTime) throws IOException;
}

View File

@ -29,11 +29,6 @@ public class WebSocketGeneratorD00 implements WebSocketGenerator
_endp=endp;
}
public synchronized void addFrame(byte frame,byte[] content, int blockFor) throws IOException
{
addFrame(frame,content,0,content.length,blockFor);
}
public synchronized void addFrame(byte opcode,byte[] content, int offset, int length, int blockFor) throws IOException
{
if (_buffer==null)
@ -165,4 +160,11 @@ public class WebSocketGeneratorD00 implements WebSocketGenerator
return _buffer==null || _buffer.length()==0;
}
public void addFragment(boolean more, byte opcode, byte[] content, int offset, int length, int maxIdleTime) throws IOException
{
if (more)
throw new UnsupportedOperationException("fragmented");
addFrame(opcode,content,offset,length,maxIdleTime);
}
}

View File

@ -36,7 +36,13 @@ public class WebSocketGeneratorD01 implements WebSocketGenerator
addFrame(opcode,content,0,content.length,blockFor);
}
public synchronized void addFrame(byte opcode,byte[] content, int offset, int length, int blockFor) throws IOException
{
addFragment(false,opcode,content,offset,length,blockFor);
}
public synchronized void addFragment(boolean more, byte opcode, byte[] content, int offset, int length, int blockFor) throws IOException
{
if (_buffer==null)
_buffer=_buffers.getDirectBuffer();
@ -55,6 +61,8 @@ public class WebSocketGeneratorD01 implements WebSocketGenerator
fragment=_buffer.capacity()-10;
bufferPut((byte)(0x80|opcode), blockFor);
}
else if (more)
bufferPut((byte)(0x80|opcode), blockFor);
else
bufferPut(opcode, blockFor);
@ -178,4 +186,5 @@ public class WebSocketGeneratorD01 implements WebSocketGenerator
{
return _buffer==null || _buffer.length()==0;
}
}

View File

@ -56,7 +56,7 @@ public class WebSocketGeneratorD00Test
for (int i=0;i<b.length;i++)
b[i]=(byte)('0'+(i%10));
_generator.addFrame((byte)0xf,b,0);
_generator.addFrame((byte)0xf,b,0,b.length,0);
_generator.flush();
assertEquals(0x0f,_out.get());
@ -74,7 +74,7 @@ public class WebSocketGeneratorD00Test
for (int i=0;i<b.length;i++)
b[i]=(byte)('0'+(i%10));
_generator.addFrame((byte)0xf,b,0);
_generator.addFrame((byte)0xf,b,0,b.length,0);
_generator.flush();
assertEquals(0x8f,_out.get()&0xff);

View File

@ -53,7 +53,9 @@ public class WebSocketGeneratorD01Test
@Test
public void testOneBuffer() throws Exception
{
_generator.addFrame((byte)0x84,"Hell\uFF4F W\uFF4Frld".getBytes(StringUtil.__UTF8),0);
String string = "Hell\uFF4F W\uFF4Frld";
byte[] bytes=string.getBytes(StringUtil.__UTF8);
_generator.addFrame((byte)0x84,bytes,0,bytes.length,0);
_generator.flush();
assertEquals(0x84,0xff&_out.get());
assertEquals(15,0xff&_out.get());
@ -81,7 +83,7 @@ public class WebSocketGeneratorD01Test
for (int i=0;i<b.length;i++)
b[i]=(byte)('0'+(i%10));
_generator.addFrame((byte)0x85,b,0);
_generator.addFrame((byte)0x85,b,0,b.length,0);
_generator.flush();
assertEquals(0x85,0xff&_out.get());

View File

@ -126,6 +126,10 @@ public class WebSocketLoadTest
}
}
public void onFragment(boolean more, byte opcode, byte[] data, int offset, int length)
{
}
public void onMessage(byte frame, byte[] data, int offset, int length)
{
}

View File

@ -147,7 +147,7 @@ public class WebSocketMessageTest
for (int i = 0; i < 64 * 1024 / text.length(); ++i)
message.append(text);
byte[] data = message.toString().getBytes("UTF-8");
_serverWebSocket.outbound.sendMessage(WebSocket.LENGTH_FRAME, data);
_serverWebSocket.outbound.sendMessage(WebSocket.LENGTH_FRAME, data,0,data.length);
// Length of the message is 65536, so the length will be encoded as 0x84 0x80 0x00
int frame = input.read();
@ -194,5 +194,9 @@ public class WebSocketMessageTest
public void onDisconnect()
{
}
public void onFragment(boolean more, byte opcode, byte[] data, int offset, int length)
{
}
}
}

View File

@ -117,7 +117,6 @@ public class WebSocketParserD01Test
string += ". The end.";
byte[] bytes = string.getBytes("UTF-8");
System.err.println(Long.toHexString(bytes.length));
in.put((byte)0x00);
in.put((byte)0x7F);

View File

@ -137,7 +137,6 @@ public class WebSocketTest
ByteArrayBuffer out = _connector.getResponses(buffer,true);
String response = StringUtil.printable(out.asArray());
System.err.println(response);
assertTrue(response.startsWith("HTTP/1.1 101 Web Socket Protocol Handshake"));
assertTrue(response.contains("Upgrade: WebSocket"));
@ -181,5 +180,9 @@ public class WebSocketTest
{
_disconnected=true;
}
public void onFragment(boolean more, byte opcode, byte[] data, int offset, int length)
{
}
}
}

View File

@ -77,6 +77,10 @@ public class WebSocketTestServer extends Server
{
_webSockets.remove(this);
}
public void onFragment(boolean more, byte opcode, byte[] data, int offset, int length)
{
}
}
public static void main(String[] args)

View File

@ -74,5 +74,9 @@ public class WebSocketChatServlet extends WebSocketServlet
// Log.info(this+" onDisconnect");
_members.remove(this);
}
public void onFragment(boolean more, byte opcode, byte[] data, int offset, int length)
{
}
}
}