Merge branch 'jetty-9' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project into jetty-9

This commit is contained in:
Joakim Erdfelt 2012-07-06 15:53:56 -07:00
commit c4029ba5df
4 changed files with 89 additions and 150 deletions

View File

@ -49,17 +49,70 @@ public class FrameGenerator
this.policy = policy;
}
public void assertFrameValid(WebSocketFrame frame)
{
/*
* RFC 6455 Section 5.2
*
* MUST be 0 unless an extension is negotiated that defines meanings for non-zero values. If a nonzero value is received and none of the negotiated
* extensions defines the meaning of such a nonzero value, the receiving endpoint MUST _Fail the WebSocket Connection_.
*/
if (frame.isRsv1())
{
// TODO: extensions can negotiate this (somehow)
throw new ProtocolException("RSV1 not allowed to be set");
}
if (frame.isRsv2())
{
// TODO: extensions can negotiate this (somehow)
throw new ProtocolException("RSV2 not allowed to be set");
}
if (frame.isRsv3())
{
// TODO: extensions can negotiate this (somehow)
throw new ProtocolException("RSV3 not allowed to be set");
}
if (frame.getOpCode().isControlFrame())
{
/*
* RFC 6455 Section 5.5
*
* All control frames MUST have a payload length of 125 bytes or less and MUST NOT be fragmented.
*/
if (frame.getPayloadLength() > 125)
{
throw new ProtocolException("Invalid control frame payload length");
}
if (!frame.isFin())
{
throw new ProtocolException("Control Frames must be FIN=true");
}
/*
* RFC 6455 Section 5.5.1
*
* close frame payload is specially formatted which is checked in CloseInfo
*/
if (frame.getOpCode() == OpCode.CLOSE)
{
new CloseInfo(frame.getPayloadData(),true);
}
}
}
public ByteBuffer generate(ByteBuffer buffer, WebSocketFrame frame)
{
LOG.debug(String.format("Generate.Frame[opcode=%s,fin=%b,cont=%b,rsv1=%b,rsv2=%b,rsv3=%b,mask=%b,plength=%d]",frame.getOpCode().toString(),
frame.isFin(),frame.isContinuation(),frame.isRsv1(),frame.isRsv2(),frame.isRsv3(),frame.isMasked(),frame.getPayloadLength()));
byte b;
assertFrameValid(frame);
if ( frame.getOpCode().isControlFrame() && !frame.isFin() )
{
throw new ProtocolException("Control Frames must be FIN=true");
}
byte b;
// Setup fin thru opcode
b = 0x00;
@ -70,20 +123,14 @@ public class FrameGenerator
if (frame.isRsv1())
{
b |= 0x40; // 0100_0000
// TODO: extensions can negotiate this (somehow)
throw new ProtocolException("RSV1 not allowed to be set");
}
if (frame.isRsv2())
{
b |= 0x20; // 0010_0000
// TODO: extensions can negotiate this (somehow)
throw new ProtocolException("RSV2 not allowed to be set");
}
if (frame.isRsv3())
{
b |= 0x10;
// TODO: extensions can negotiate this (somehow)
throw new ProtocolException("RSV3 not allowed to be set");
}
byte opcode = frame.getOpCode().getCode();
@ -145,31 +192,12 @@ public class FrameGenerator
// masking key
if (frame.isMasked())
{
// TODO: figure out maskgen
buffer.put(frame.getMask());
}
// now the payload itself
// call back into masking check/method on this class?
// remember the position
int positionPrePayload = buffer.position();
if (frame.getOpCode().isControlFrame())
{
if (frame.getPayloadLength() > 125)
{
throw new ProtocolException("Invalid control frame payload length");
}
}
if (frame.getOpCode() == OpCode.CLOSE)
{
// validate the close
new CloseInfo(frame.getPayloadData(),true);
}
// copy payload
if (frame.hasPayload())
{

View File

@ -4,17 +4,36 @@ import java.nio.ByteBuffer;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.websocket.api.PolicyViolationException;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.generator.FrameGenerator;
/**
* The FrameBuilder applies a builder pattern to constructing WebSocketFrame classes.
*
* WARNING: It is possible to build bad frames using this builder which is the intent
* WARNING: It is possible to build bad frames using this builder which is intended
*
*/
public class FrameBuilder
{
public class DirtyGenerator extends FrameGenerator
{
public DirtyGenerator()
{
super(WebSocketPolicy.newServerPolicy());
}
@Override
public void assertFrameValid(WebSocketFrame frame)
{
/*
* we desire the ability to craft bad frames so ignore frame validation
*/
}
}
public static FrameBuilder binary()
{
return new FrameBuilder(new WebSocketFrame(OpCode.BINARY));
@ -102,6 +121,8 @@ public class FrameBuilder
return new FrameBuilder(new WebSocketFrame(OpCode.TEXT)).payload(text.getBytes(StringUtil.__UTF8_CHARSET));
}
DirtyGenerator generator = new DirtyGenerator();
private WebSocketFrame frame;
public FrameBuilder(WebSocketFrame frame)
@ -129,122 +150,7 @@ public class FrameBuilder
public void fill(ByteBuffer buffer)
{
byte b;
// Setup fin thru opcode
b = 0x00;
if (frame.isFin())
{
b |= 0x80; // 1000_0000
}
if (frame.isRsv1())
{
b |= 0x40; // 0100_0000
// TODO: extensions can negotiate this (somehow)
throw new PolicyViolationException("RSV1 not allowed to be set");
}
if (frame.isRsv2())
{
b |= 0x20; // 0010_0000
// TODO: extensions can negotiate this (somehow)
throw new PolicyViolationException("RSV2 not allowed to be set");
}
if (frame.isRsv3())
{
b |= 0x10;
// TODO: extensions can negotiate this (somehow)
throw new PolicyViolationException("RSV3 not allowed to be set");
}
byte opcode = frame.getOpCode().getCode();
if (frame.isContinuation())
{
// Continuations are not the same OPCODE
opcode = OpCode.CONTINUATION.getCode();
}
b |= opcode & 0x0F;
buffer.put(b);
// is masked
b = 0x00;
b |= (frame.isMasked()?0x80:0x00);
// payload lengths
int payloadLength = frame.getPayloadLength();
/*
* if length is over 65535 then its a 7 + 64 bit length
*/
if (payloadLength > 0xFF_FF)
{
// we have a 64 bit length
b |= 0x7F;
buffer.put(b); // indicate 8 byte length
buffer.put((byte)0); //
buffer.put((byte)0); // anything over an
buffer.put((byte)0); // int is just
buffer.put((byte)0); // intsane!
buffer.put((byte)((payloadLength >> 24) & 0xFF));
buffer.put((byte)((payloadLength >> 16) & 0xFF));
buffer.put((byte)((payloadLength >> 8) & 0xFF));
buffer.put((byte)(payloadLength & 0xFF));
}
/*
* if payload is ge 126 we have a 7 + 16 bit length
*/
else if (payloadLength >= 0x7E)
{
b |= 0x7E;
buffer.put(b); // indicate 2 byte length
buffer.put((byte)(payloadLength >> 8));
buffer.put((byte)(payloadLength & 0xFF));
}
/*
* we have a 7 bit length
*/
else
{
b |= (payloadLength & 0x7F);
buffer.put(b);
}
// masking key
if (frame.isMasked())
{
// TODO: figure out maskgen
buffer.put(frame.getMask());
}
// now the payload itself
// remember the position
int positionPrePayload = buffer.position();
// generate payload
if (frame.getPayloadLength() > 0)
{
buffer.put(frame.getPayloadData());
}
int positionPostPayload = buffer.position();
// mask it if needed
if (frame.isMasked())
{
// move back to remembered position.
int size = positionPostPayload - positionPrePayload;
byte[] mask = frame.getMask();
int pos;
for (int i = 0; i < size; i++)
{
pos = positionPrePayload + i;
// Mask each byte by its absolute position in the bytebuffer
buffer.put(pos,(byte)(buffer.get(pos) ^ mask[i % 4]));
}
}
generator.generate(buffer,frame);
BufferUtil.flipToFlush(buffer,0);
}

View File

@ -48,4 +48,5 @@ public class FrameBuilderTest
Assert.assertArrayEquals(expected,actual);
}
}

View File

@ -12,6 +12,7 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
@ -174,8 +175,10 @@ public class TestABCase7_9
* Test the requirement of issuing
*/
@Test
public void testCase7_9_XInvalidCloseStatusCodesWithBuilder() throws Exception
public void testCase7_9_XInvalidCloseStatusCodesWithReason() throws Exception
{
String reason = "closing time";
BlockheadClient client = new BlockheadClient(server.getServerUri());
try
{
@ -191,12 +194,13 @@ public class TestABCase7_9
// Create Close Frame manually, as we are testing the server's behavior of a bad client.
buf.put((byte)(0x80 | OpCode.CLOSE.getCode()));
buf.put((byte)(0x80 | 2));
buf.put((byte)(0x80 | 2 + reason.length()));
byte mask[] = new byte[]
{ 0x44, 0x44, 0x44, 0x44 };
buf.put(mask);
int position = buf.position();
buf.putChar((char)this.invalidStatusCode);
buf.put(reason.getBytes(StringUtil.__UTF8_CHARSET));
remask(buf,position,mask);
BufferUtil.flipToFlush(buf,0);
client.writeRaw(buf);