353073 Support fake fragements, so that frames may be larger than buffers
This commit is contained in:
parent
d63294bfe4
commit
c07e14840c
|
@ -148,7 +148,10 @@ public interface WebSocket
|
||||||
byte textOpcode();
|
byte textOpcode();
|
||||||
byte continuationOpcode();
|
byte continuationOpcode();
|
||||||
byte finMask();
|
byte finMask();
|
||||||
|
String getProtocol();
|
||||||
|
void setFakeFragments(boolean fake);
|
||||||
|
|
||||||
|
boolean isFakeFragments();
|
||||||
boolean isControl(byte opcode);
|
boolean isControl(byte opcode);
|
||||||
boolean isText(byte opcode);
|
boolean isText(byte opcode);
|
||||||
boolean isBinary(byte opcode);
|
boolean isBinary(byte opcode);
|
||||||
|
|
|
@ -530,4 +530,16 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFakeFragments(boolean fake)
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFakeFragments()
|
||||||
|
{
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -491,6 +491,15 @@ public class WebSocketConnectionD06 extends AbstractConnection implements WebSoc
|
||||||
{
|
{
|
||||||
return this.getClass().getSimpleName()+"@"+_endp.getLocalAddr()+":"+_endp.getLocalPort()+"<->"+_endp.getRemoteAddr()+":"+_endp.getRemotePort();
|
return this.getClass().getSimpleName()+"@"+_endp.getLocalAddr()+":"+_endp.getLocalPort()+"<->"+_endp.getRemoteAddr()+":"+_endp.getRemotePort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFakeFragments(boolean fake)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFakeFragments()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
|
@ -45,7 +45,8 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
||||||
final static byte OP_TEXT = 0x01;
|
final static byte OP_TEXT = 0x01;
|
||||||
final static byte OP_BINARY = 0x02;
|
final static byte OP_BINARY = 0x02;
|
||||||
final static byte OP_EXT_DATA = 0x03;
|
final static byte OP_EXT_DATA = 0x03;
|
||||||
|
|
||||||
|
final static byte OP_CONTROL = 0x08;
|
||||||
final static byte OP_CLOSE = 0x08;
|
final static byte OP_CLOSE = 0x08;
|
||||||
final static byte OP_PING = 0x09;
|
final static byte OP_PING = 0x09;
|
||||||
final static byte OP_PONG = 0x0A;
|
final static byte OP_PONG = 0x0A;
|
||||||
|
@ -60,16 +61,18 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
||||||
final static int CLOSE_NOCLOSE=1006;
|
final static int CLOSE_NOCLOSE=1006;
|
||||||
final static int CLOSE_NOTUTF8=1007;
|
final static int CLOSE_NOTUTF8=1007;
|
||||||
|
|
||||||
|
final static int FLAG_FIN=0x8;
|
||||||
|
|
||||||
final static int VERSION=8;
|
final static int VERSION=8;
|
||||||
|
|
||||||
static boolean isLastFrame(byte flags)
|
static boolean isLastFrame(byte flags)
|
||||||
{
|
{
|
||||||
return (flags&0x8)!=0;
|
return (flags&FLAG_FIN)!=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isControlFrame(byte opcode)
|
static boolean isControlFrame(byte opcode)
|
||||||
{
|
{
|
||||||
return (opcode&0x8)!=0;
|
return (opcode&OP_CONTROL)!=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static byte[] MAGIC;
|
private final static byte[] MAGIC;
|
||||||
|
@ -87,8 +90,8 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
||||||
private final String _protocol;
|
private final String _protocol;
|
||||||
private final int _draft;
|
private final int _draft;
|
||||||
private int _close;
|
private int _close;
|
||||||
private boolean _closedIn;
|
private volatile boolean _closedIn;
|
||||||
private boolean _closedOut;
|
private volatile boolean _closedOut;
|
||||||
private int _maxTextMessageSize;
|
private int _maxTextMessageSize;
|
||||||
private int _maxBinaryMessageSize=-1;
|
private int _maxBinaryMessageSize=-1;
|
||||||
|
|
||||||
|
@ -105,12 +108,12 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final WebSocketParser.FrameHandler _frameHandler= new FrameHandlerD07();
|
private final WebSocketParser.FrameHandler _frameHandler= new WSFrameHandler();
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private final WebSocket.FrameConnection _connection = new FrameConnectionD10();
|
private final WebSocket.FrameConnection _connection = new WSFrameConnection();
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -341,7 +344,6 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
||||||
_close=code;
|
_close=code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (closed)
|
if (closed)
|
||||||
|
@ -360,7 +362,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
||||||
byte[] bytes = ("xx"+(message==null?"":message)).getBytes(StringUtil.__ISO_8859_1);
|
byte[] bytes = ("xx"+(message==null?"":message)).getBytes(StringUtil.__ISO_8859_1);
|
||||||
bytes[0]=(byte)(code/0x100);
|
bytes[0]=(byte)(code/0x100);
|
||||||
bytes[1]=(byte)(code%0x100);
|
bytes[1]=(byte)(code%0x100);
|
||||||
_outbound.addFrame((byte)0x8,WebSocketConnectionD10.OP_CLOSE,bytes,0,bytes.length);
|
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD10.OP_CLOSE,bytes,0,bytes.length);
|
||||||
}
|
}
|
||||||
_outbound.flush();
|
_outbound.flush();
|
||||||
|
|
||||||
|
@ -390,29 +392,29 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private class FrameConnectionD10 implements WebSocket.FrameConnection
|
private class WSFrameConnection implements WebSocket.FrameConnection
|
||||||
{
|
{
|
||||||
volatile boolean _disconnecting;
|
volatile boolean _disconnecting;
|
||||||
int _maxTextMessage=WebSocketConnectionD10.this._maxTextMessageSize;
|
int _maxTextMessage=WebSocketConnectionD10.this._maxTextMessageSize;
|
||||||
int _maxBinaryMessage=WebSocketConnectionD10.this._maxBinaryMessageSize;
|
int _maxBinaryMessage=WebSocketConnectionD10.this._maxBinaryMessageSize;
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public synchronized void sendMessage(String content) throws IOException
|
public void sendMessage(String content) throws IOException
|
||||||
{
|
{
|
||||||
if (_closedOut)
|
if (_closedOut)
|
||||||
throw new IOException("closing");
|
throw new IOException("closing");
|
||||||
byte[] data = content.getBytes(StringUtil.__UTF8);
|
byte[] data = content.getBytes(StringUtil.__UTF8);
|
||||||
_outbound.addFrame((byte)0x8,WebSocketConnectionD10.OP_TEXT,data,0,data.length);
|
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD10.OP_TEXT,data,0,data.length);
|
||||||
checkWriteable();
|
checkWriteable();
|
||||||
_idle.access(_endp);
|
_idle.access(_endp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public synchronized void sendMessage(byte[] content, int offset, int length) throws IOException
|
public void sendMessage(byte[] content, int offset, int length) throws IOException
|
||||||
{
|
{
|
||||||
if (_closedOut)
|
if (_closedOut)
|
||||||
throw new IOException("closing");
|
throw new IOException("closing");
|
||||||
_outbound.addFrame((byte)0x8,WebSocketConnectionD10.OP_BINARY,content,offset,length);
|
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD10.OP_BINARY,content,offset,length);
|
||||||
checkWriteable();
|
checkWriteable();
|
||||||
_idle.access(_endp);
|
_idle.access(_endp);
|
||||||
}
|
}
|
||||||
|
@ -432,7 +434,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
||||||
{
|
{
|
||||||
if (_closedOut)
|
if (_closedOut)
|
||||||
throw new IOException("closing");
|
throw new IOException("closing");
|
||||||
_outbound.addFrame((byte)0x8,ctrl,data,offset,length);
|
_outbound.addFrame((byte)FLAG_FIN,ctrl,data,offset,length);
|
||||||
checkWriteable();
|
checkWriteable();
|
||||||
_idle.access(_endp);
|
_idle.access(_endp);
|
||||||
}
|
}
|
||||||
|
@ -509,7 +511,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public byte finMask()
|
public byte finMask()
|
||||||
{
|
{
|
||||||
return 0x8;
|
return FLAG_FIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -559,6 +561,18 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
||||||
{
|
{
|
||||||
close(CLOSE_NORMAL,null);
|
close(CLOSE_NORMAL,null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void setFakeFragments(boolean fake)
|
||||||
|
{
|
||||||
|
_parser.setFakeFragments(fake);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public boolean isFakeFragments()
|
||||||
|
{
|
||||||
|
return _parser.isFakeFragments();
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public String toString()
|
public String toString()
|
||||||
|
@ -570,7 +584,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private class FrameHandlerD07 implements WebSocketParser.FrameHandler
|
private class WSFrameHandler implements WebSocketParser.FrameHandler
|
||||||
{
|
{
|
||||||
private final Utf8StringBuilder _utf8 = new Utf8StringBuilder();
|
private final Utf8StringBuilder _utf8 = new Utf8StringBuilder();
|
||||||
private ByteArrayBuffer _aggregate;
|
private ByteArrayBuffer _aggregate;
|
||||||
|
@ -585,175 +599,174 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
||||||
// Ignore incoming after a close
|
// Ignore incoming after a close
|
||||||
if (_closedIn)
|
if (_closedIn)
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte[] array=buffer.array();
|
byte[] array=buffer.array();
|
||||||
|
|
||||||
// Deliver frame if websocket is a FrameWebSocket
|
// Deliver frame if websocket is a FrameWebSocket
|
||||||
if (_onFrame!=null)
|
if (_onFrame!=null)
|
||||||
|
{
|
||||||
|
if (_onFrame.onFrame(flags,opcode,array,buffer.getIndex(),buffer.length()))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_onControl!=null && isControlFrame(opcode))
|
||||||
|
{
|
||||||
|
if (_onControl.onControl(opcode,array,buffer.getIndex(),buffer.length()))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(opcode)
|
||||||
|
{
|
||||||
|
case WebSocketConnectionD10.OP_CONTINUATION:
|
||||||
{
|
{
|
||||||
if (_onFrame.onFrame(flags,opcode,array,buffer.getIndex(),buffer.length()))
|
// If text, append to the message buffer
|
||||||
return;
|
if (_opcode==WebSocketConnectionD10.OP_TEXT && _connection.getMaxTextMessageSize()>=0)
|
||||||
}
|
|
||||||
|
|
||||||
if (_onControl!=null && isControlFrame(opcode))
|
|
||||||
{
|
|
||||||
if (_onControl.onControl(opcode,array,buffer.getIndex(),buffer.length()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(opcode)
|
|
||||||
{
|
|
||||||
case WebSocketConnectionD10.OP_CONTINUATION:
|
|
||||||
{
|
{
|
||||||
// If text, append to the message buffer
|
if (_utf8.append(buffer.array(),buffer.getIndex(),buffer.length(),_connection.getMaxTextMessageSize()))
|
||||||
if (_opcode==WebSocketConnectionD10.OP_TEXT && _connection.getMaxTextMessageSize()>=0)
|
|
||||||
{
|
{
|
||||||
if (_utf8.append(buffer.array(),buffer.getIndex(),buffer.length(),_connection.getMaxTextMessageSize()))
|
// If this is the last fragment, deliver the text buffer
|
||||||
|
if (lastFrame && _onTextMessage!=null)
|
||||||
{
|
{
|
||||||
// If this is the last fragment, deliver the text buffer
|
_opcode=-1;
|
||||||
if (lastFrame && _onTextMessage!=null)
|
String msg =_utf8.toString();
|
||||||
|
_utf8.reset();
|
||||||
|
_onTextMessage.onMessage(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_connection.close(WebSocketConnectionD10.CLOSE_LARGE,"Text message size > "+_connection.getMaxTextMessageSize()+" chars");
|
||||||
|
_utf8.reset();
|
||||||
|
_opcode=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_opcode>=0 && _connection.getMaxBinaryMessageSize()>=0)
|
||||||
|
{
|
||||||
|
if (_aggregate.space()<_aggregate.length())
|
||||||
|
{
|
||||||
|
_connection.close(WebSocketConnectionD10.CLOSE_LARGE,"Message size > "+_connection.getMaxBinaryMessageSize());
|
||||||
|
_aggregate.clear();
|
||||||
|
_opcode=-1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_aggregate.put(buffer);
|
||||||
|
|
||||||
|
// If this is the last fragment, deliver
|
||||||
|
if (lastFrame && _onBinaryMessage!=null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_onBinaryMessage.onMessage(_aggregate.array(),_aggregate.getIndex(),_aggregate.length());
|
||||||
|
}
|
||||||
|
finally
|
||||||
{
|
{
|
||||||
_opcode=-1;
|
_opcode=-1;
|
||||||
String msg =_utf8.toString();
|
_aggregate.clear();
|
||||||
_utf8.reset();
|
|
||||||
_onTextMessage.onMessage(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_connection.close(WebSocketConnectionD10.CLOSE_LARGE,"Text message size > "+_connection.getMaxTextMessageSize()+" chars");
|
|
||||||
_utf8.reset();
|
|
||||||
_opcode=-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (_opcode>=0 && _connection.getMaxBinaryMessageSize()>=0)
|
|
||||||
{
|
|
||||||
if (_aggregate.space()<_aggregate.length())
|
|
||||||
{
|
|
||||||
_connection.close(WebSocketConnectionD10.CLOSE_LARGE,"Message size > "+_connection.getMaxBinaryMessageSize());
|
|
||||||
_aggregate.clear();
|
|
||||||
_opcode=-1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_aggregate.put(buffer);
|
|
||||||
|
|
||||||
// If this is the last fragment, deliver
|
|
||||||
if (lastFrame && _onBinaryMessage!=null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_onBinaryMessage.onMessage(_aggregate.array(),_aggregate.getIndex(),_aggregate.length());
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_opcode=-1;
|
|
||||||
_aggregate.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case WebSocketConnectionD10.OP_PING:
|
break;
|
||||||
{
|
|
||||||
Log.debug("PING {}",this);
|
|
||||||
if (!_closedOut)
|
|
||||||
_connection.sendControl(WebSocketConnectionD10.OP_PONG,buffer.array(),buffer.getIndex(),buffer.length());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WebSocketConnectionD10.OP_PONG:
|
|
||||||
{
|
|
||||||
Log.debug("PONG {}",this);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case WebSocketConnectionD10.OP_CLOSE:
|
|
||||||
{
|
|
||||||
int code=WebSocketConnectionD10.CLOSE_NOCODE;
|
|
||||||
String message=null;
|
|
||||||
if (buffer.length()>=2)
|
|
||||||
{
|
|
||||||
code=buffer.array()[buffer.getIndex()]*0x100+buffer.array()[buffer.getIndex()+1];
|
|
||||||
if (buffer.length()>2)
|
|
||||||
message=new String(buffer.array(),buffer.getIndex()+2,buffer.length()-2,StringUtil.__UTF8);
|
|
||||||
}
|
|
||||||
closeIn(code,message);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
case WebSocketConnectionD10.OP_TEXT:
|
|
||||||
{
|
|
||||||
if(_onTextMessage!=null)
|
|
||||||
{
|
|
||||||
if (lastFrame)
|
|
||||||
{
|
|
||||||
// Deliver the message
|
|
||||||
_onTextMessage.onMessage(buffer.toString(StringUtil.__UTF8));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_connection.getMaxTextMessageSize()>=0)
|
|
||||||
{
|
|
||||||
// If this is a text fragment, append to buffer
|
|
||||||
if (_utf8.append(buffer.array(),buffer.getIndex(),buffer.length(),_connection.getMaxTextMessageSize()))
|
|
||||||
_opcode=WebSocketConnectionD10.OP_TEXT;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_utf8.reset();
|
|
||||||
_opcode=-1;
|
|
||||||
_connection.close(WebSocketConnectionD10.CLOSE_LARGE,"Text message size > "+_connection.getMaxTextMessageSize()+" chars");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
if (_onBinaryMessage!=null)
|
|
||||||
{
|
|
||||||
if (lastFrame)
|
|
||||||
{
|
|
||||||
_onBinaryMessage.onMessage(array,buffer.getIndex(),buffer.length());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_connection.getMaxBinaryMessageSize()>=0)
|
|
||||||
{
|
|
||||||
if (buffer.length()>_connection.getMaxBinaryMessageSize())
|
|
||||||
{
|
|
||||||
_connection.close(WebSocketConnectionD10.CLOSE_LARGE,"Message size > "+_connection.getMaxBinaryMessageSize());
|
|
||||||
if (_aggregate!=null)
|
|
||||||
_aggregate.clear();
|
|
||||||
_opcode=-1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_opcode=opcode;
|
|
||||||
if (_aggregate==null)
|
|
||||||
_aggregate=new ByteArrayBuffer(_connection.getMaxBinaryMessageSize());
|
|
||||||
_aggregate.put(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
case WebSocketConnectionD10.OP_PING:
|
||||||
|
{
|
||||||
|
Log.debug("PING {}",this);
|
||||||
|
if (!_closedOut)
|
||||||
|
_connection.sendControl(WebSocketConnectionD10.OP_PONG,buffer.array(),buffer.getIndex(),buffer.length());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WebSocketConnectionD10.OP_PONG:
|
||||||
|
{
|
||||||
|
Log.debug("PONG {}",this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WebSocketConnectionD10.OP_CLOSE:
|
||||||
|
{
|
||||||
|
int code=WebSocketConnectionD10.CLOSE_NOCODE;
|
||||||
|
String message=null;
|
||||||
|
if (buffer.length()>=2)
|
||||||
|
{
|
||||||
|
code=buffer.array()[buffer.getIndex()]*0x100+buffer.array()[buffer.getIndex()+1];
|
||||||
|
if (buffer.length()>2)
|
||||||
|
message=new String(buffer.array(),buffer.getIndex()+2,buffer.length()-2,StringUtil.__UTF8);
|
||||||
|
}
|
||||||
|
closeIn(code,message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case WebSocketConnectionD10.OP_TEXT:
|
||||||
|
{
|
||||||
|
if(_onTextMessage!=null)
|
||||||
|
{
|
||||||
|
if (lastFrame)
|
||||||
|
{
|
||||||
|
// Deliver the message
|
||||||
|
_onTextMessage.onMessage(buffer.toString(StringUtil.__UTF8));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_connection.getMaxTextMessageSize()>=0)
|
||||||
|
{
|
||||||
|
// If this is a text fragment, append to buffer
|
||||||
|
if (_utf8.append(buffer.array(),buffer.getIndex(),buffer.length(),_connection.getMaxTextMessageSize()))
|
||||||
|
_opcode=WebSocketConnectionD10.OP_TEXT;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_utf8.reset();
|
||||||
|
_opcode=-1;
|
||||||
|
_connection.close(WebSocketConnectionD10.CLOSE_LARGE,"Text message size > "+_connection.getMaxTextMessageSize()+" chars");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (_onBinaryMessage!=null)
|
||||||
|
{
|
||||||
|
if (lastFrame)
|
||||||
|
{
|
||||||
|
_onBinaryMessage.onMessage(array,buffer.getIndex(),buffer.length());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_connection.getMaxBinaryMessageSize()>=0)
|
||||||
|
{
|
||||||
|
if (buffer.length()>_connection.getMaxBinaryMessageSize())
|
||||||
|
{
|
||||||
|
_connection.close(WebSocketConnectionD10.CLOSE_LARGE,"Message size > "+_connection.getMaxBinaryMessageSize());
|
||||||
|
if (_aggregate!=null)
|
||||||
|
_aggregate.clear();
|
||||||
|
_opcode=-1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_opcode=opcode;
|
||||||
|
if (_aggregate==null)
|
||||||
|
_aggregate=new ByteArrayBuffer(_connection.getMaxBinaryMessageSize());
|
||||||
|
_aggregate.put(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(ThreadDeath th)
|
}
|
||||||
{
|
catch(ThreadDeath th)
|
||||||
throw th;
|
{
|
||||||
}
|
throw th;
|
||||||
catch(Throwable th)
|
}
|
||||||
{
|
catch(Throwable th)
|
||||||
Log.warn(th);
|
{
|
||||||
}
|
Log.warn(th);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,6 @@ public class WebSocketParserD10 implements WebSocketParser
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
private final WebSocketBuffers _buffers;
|
private final WebSocketBuffers _buffers;
|
||||||
private final EndPoint _endp;
|
private final EndPoint _endp;
|
||||||
private final FrameHandler _handler;
|
private final FrameHandler _handler;
|
||||||
|
@ -61,6 +60,7 @@ public class WebSocketParserD10 implements WebSocketParser
|
||||||
private final byte[] _mask = new byte[4];
|
private final byte[] _mask = new byte[4];
|
||||||
private int _m;
|
private int _m;
|
||||||
private boolean _skip;
|
private boolean _skip;
|
||||||
|
private boolean _fakeFragments=true;
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
|
@ -79,6 +79,24 @@ public class WebSocketParserD10 implements WebSocketParser
|
||||||
_state=State.START;
|
_state=State.START;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @return True if fake fragments should be created for frames larger than the buffer.
|
||||||
|
*/
|
||||||
|
public boolean isFakeFragments()
|
||||||
|
{
|
||||||
|
return _fakeFragments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @param fakeFragments True if fake fragments should be created for frames larger than the buffer.
|
||||||
|
*/
|
||||||
|
public void setFakeFragments(boolean fakeFragments)
|
||||||
|
{
|
||||||
|
_fakeFragments = fakeFragments;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public boolean isBufferEmpty()
|
public boolean isBufferEmpty()
|
||||||
{
|
{
|
||||||
|
@ -120,7 +138,33 @@ public class WebSocketParserD10 implements WebSocketParser
|
||||||
|
|
||||||
// if no space, then the data is too big for buffer
|
// if no space, then the data is too big for buffer
|
||||||
if (_buffer.space() == 0)
|
if (_buffer.space() == 0)
|
||||||
|
{
|
||||||
|
// Can we send a fake frame?
|
||||||
|
if (_fakeFragments && _state==State.DATA)
|
||||||
|
{
|
||||||
|
Buffer data =_buffer.get(4*(available/4));
|
||||||
|
_buffer.compact();
|
||||||
|
if (_masked)
|
||||||
|
{
|
||||||
|
if (data.array()==null)
|
||||||
|
data=_buffer.asMutableBuffer();
|
||||||
|
byte[] array = data.array();
|
||||||
|
final int end=data.putIndex();
|
||||||
|
for (int i=data.getIndex();i<end;i++)
|
||||||
|
array[i]^=_mask[_m++%4];
|
||||||
|
}
|
||||||
|
|
||||||
|
// System.err.printf("%s %s %s >>\n",TypeUtil.toHexString(_flags),TypeUtil.toHexString(_opcode),data.length());
|
||||||
|
events++;
|
||||||
|
_bytesNeeded-=data.length();
|
||||||
|
_handler.onFrame((byte)(_flags&(0xff^WebSocketConnectionD10.FLAG_FIN)), _opcode, data);
|
||||||
|
|
||||||
|
_opcode=WebSocketConnectionD10.OP_CONTINUATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_buffer.space() == 0)
|
||||||
throw new IllegalStateException("FULL: "+_state+" "+_bytesNeeded+">"+_buffer.capacity());
|
throw new IllegalStateException("FULL: "+_state+" "+_bytesNeeded+">"+_buffer.capacity());
|
||||||
|
}
|
||||||
|
|
||||||
// catch IOExceptions (probably EOF) and try to parse what we have
|
// catch IOExceptions (probably EOF) and try to parse what we have
|
||||||
try
|
try
|
||||||
|
@ -200,7 +244,7 @@ public class WebSocketParserD10 implements WebSocketParser
|
||||||
_length = _length*0x100 + (0xff&b);
|
_length = _length*0x100 + (0xff&b);
|
||||||
if (--_bytesNeeded==0)
|
if (--_bytesNeeded==0)
|
||||||
{
|
{
|
||||||
if (_length>_buffer.capacity())
|
if (_length>_buffer.capacity() && !_fakeFragments)
|
||||||
{
|
{
|
||||||
events++;
|
events++;
|
||||||
_handler.close(WebSocketConnectionD10.CLOSE_LARGE,"frame size "+_length+">"+_buffer.capacity());
|
_handler.close(WebSocketConnectionD10.CLOSE_LARGE,"frame size "+_length+">"+_buffer.capacity());
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class WebSocketParserD10Test
|
||||||
{
|
{
|
||||||
private MaskedByteArrayBuffer _in;
|
private MaskedByteArrayBuffer _in;
|
||||||
private Handler _handler;
|
private Handler _handler;
|
||||||
private WebSocketParser _parser;
|
private WebSocketParserD10 _parser;
|
||||||
private byte[] _mask = new byte[] {(byte)0x00,(byte)0xF0,(byte)0x0F,(byte)0xFF};
|
private byte[] _mask = new byte[] {(byte)0x00,(byte)0xF0,(byte)0x0F,(byte)0xFF};
|
||||||
private int _m;
|
private int _m;
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ public class WebSocketParserD10Test
|
||||||
endPoint.setNonBlocking(true);
|
endPoint.setNonBlocking(true);
|
||||||
_handler = new Handler();
|
_handler = new Handler();
|
||||||
_parser=new WebSocketParserD10(buffers, endPoint,_handler,true);
|
_parser=new WebSocketParserD10(buffers, endPoint,_handler,true);
|
||||||
|
_parser.setFakeFragments(false);
|
||||||
_in = new MaskedByteArrayBuffer();
|
_in = new MaskedByteArrayBuffer();
|
||||||
|
|
||||||
endPoint.setIn(_in);
|
endPoint.setIn(_in);
|
||||||
|
@ -250,6 +251,7 @@ public class WebSocketParserD10Test
|
||||||
public void testFrameTooLarge() throws Exception
|
public void testFrameTooLarge() throws Exception
|
||||||
{
|
{
|
||||||
// Buffers are only 1024, so this frame is too large
|
// Buffers are only 1024, so this frame is too large
|
||||||
|
_parser.setFakeFragments(false);
|
||||||
|
|
||||||
_in.putUnmasked((byte)0x81);
|
_in.putUnmasked((byte)0x81);
|
||||||
_in.putUnmasked((byte)(0x80|0x7E));
|
_in.putUnmasked((byte)(0x80|0x7E));
|
||||||
|
@ -287,6 +289,27 @@ public class WebSocketParserD10Test
|
||||||
assertEquals(1024,_handler._data.get(0).length());
|
assertEquals(1024,_handler._data.get(0).length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFakeFragement() throws Exception
|
||||||
|
{
|
||||||
|
// Buffers are only 1024, so this frame will be fake fragmented
|
||||||
|
_parser.setFakeFragments(true);
|
||||||
|
|
||||||
|
_in.putUnmasked((byte)0x81);
|
||||||
|
_in.putUnmasked((byte)(0x80|0x7E));
|
||||||
|
_in.putUnmasked((byte)(2048>>8));
|
||||||
|
_in.putUnmasked((byte)(2048&0xff));
|
||||||
|
_in.sendMask();
|
||||||
|
for (int i=0;i<2048;i++)
|
||||||
|
_in.put((byte)'a');
|
||||||
|
|
||||||
|
int progress =_parser.parseNext();
|
||||||
|
assertTrue(progress>0);
|
||||||
|
|
||||||
|
assertEquals(2,_handler._frames);
|
||||||
|
assertEquals(WebSocketConnectionD10.OP_CONTINUATION,_handler._opcode);
|
||||||
|
}
|
||||||
|
|
||||||
private class Handler implements WebSocketParser.FrameHandler
|
private class Handler implements WebSocketParser.FrameHandler
|
||||||
{
|
{
|
||||||
Utf8StringBuilder _utf8 = new Utf8StringBuilder();
|
Utf8StringBuilder _utf8 = new Utf8StringBuilder();
|
||||||
|
@ -295,9 +318,11 @@ public class WebSocketParserD10Test
|
||||||
private byte _opcode;
|
private byte _opcode;
|
||||||
int _code;
|
int _code;
|
||||||
String _message;
|
String _message;
|
||||||
|
int _frames;
|
||||||
|
|
||||||
public void onFrame(byte flags, byte opcode, Buffer buffer)
|
public void onFrame(byte flags, byte opcode, Buffer buffer)
|
||||||
{
|
{
|
||||||
|
_frames++;
|
||||||
_flags=flags;
|
_flags=flags;
|
||||||
_opcode=opcode;
|
_opcode=opcode;
|
||||||
if ((flags&0x8)==0)
|
if ((flags&0x8)==0)
|
||||||
|
|
Loading…
Reference in New Issue