Refactoring out the contents of the .api.WebSocket class in prep for rethink of original API class

This commit is contained in:
Joakim Erdfelt 2012-06-21 14:25:58 -07:00
parent aaf27d7e2a
commit 5a529ad4a2
9 changed files with 176 additions and 75 deletions

View File

@ -0,0 +1,56 @@
package org.eclipse.jetty.websocket.api;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import org.eclipse.jetty.util.B64Code;
import org.eclipse.jetty.util.StringUtil;
/**
* Logic for working with the <code>Sec-WebSocket-Accept</code> and <code>Sec-WebSocket-Accept</code> headers.
* <p>
* This is kept separate from Connection objects to facilitate difference in behavior between client and server, as well as making testing easier.
*/
public class AcceptHash
{
/**
* Globally Unique Identifier for use in WebSocket handshake within <code>Sec-WebSocket-Accept</code> and <code>Sec-WebSocket-Key</code> http headers.
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-1.3">Opening Handshake (Section 1.3)</a>
*/
private final static byte[] MAGIC;
static
{
try
{
MAGIC = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".getBytes(StringUtil.__ISO_8859_1);
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e);
}
}
/**
* Concatenate the provided key with the Magic GUID and return the Base64 encoded form.
*
* @param key
* the key to hash
* @return the <code>Sec-WebSocket-Accept</code> header response (per opening handshake spec)
*/
public static String hashKey(String key)
{
try
{
MessageDigest md = MessageDigest.getInstance("SHA1");
md.update(key.getBytes("UTF-8"));
md.update(MAGIC);
return new String(B64Code.encode(md.digest()));
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}

View File

@ -5,16 +5,16 @@ public class PolicyViolationException extends CloseException
{
public PolicyViolationException(String message)
{
super(WebSocket.CLOSE_POLICY_VIOLATION,message);
super(StatusCode.POLICY_VIOLATION,message);
}
public PolicyViolationException(String message, Throwable t)
{
super(WebSocket.CLOSE_POLICY_VIOLATION,message,t);
super(StatusCode.POLICY_VIOLATION,message,t);
}
public PolicyViolationException(Throwable t)
{
super(WebSocket.CLOSE_POLICY_VIOLATION,t);
super(StatusCode.POLICY_VIOLATION,t);
}
}

View File

@ -0,0 +1,95 @@
package org.eclipse.jetty.websocket.api;
/**
* The <a href="https://tools.ietf.org/html/rfc6455#section-7.4">RFC 6455 specified status codes</a>.
*/
public class StatusCode
{
/**
* 1000 indicates a normal closure, meaning that the purpose for which the connection was established has been fulfilled.
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
*/
public final static short NORMAL = 1000;
/**
* 1001 indicates that an endpoint is "going away", such as a server going down or a browser having navigated away from a page.
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
*/
public final static short SHUTDOWN = 1001;
/**
* 1002 indicates that an endpoint is terminating the connection due to a protocol error.
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
*/
public final static short PROTOCOL = 1002;
/**
* 1003 indicates that an endpoint is terminating the connection because it has received a type of data it cannot accept (e.g., an endpoint that understands
* only text data MAY send this if it receives a binary message).
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
*/
public final static short BAD_DATA = 1003;
/**
* Reserved. The specific meaning might be defined in the future.
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
*/
public final static short UNDEFINED = 1004;
/**
* 1005 is a reserved value and MUST NOT be set as a status code in a Close control frame by an endpoint. It is designated for use in applications expecting
* a status code to indicate that no status code was actually present.
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
*/
public final static short NO_CODE = 1005;
/**
* 1006 is a reserved value and MUST NOT be set as a status code in a Close control frame by an endpoint. It is designated for use in applications expecting
* a status code to indicate that the connection was closed abnormally, e.g., without sending or receiving a Close control frame.
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
*/
public final static short NO_CLOSE = 1006;
/**
* 1007 indicates that an endpoint is terminating the connection because it has received data within a message that was not consistent with the type of the
* message (e.g., non-UTF-8 [<a href="https://tools.ietf.org/html/rfc3629">RFC3629</a>] data within a text message).
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
*/
public final static short BAD_PAYLOAD = 1007;
/**
* 1008 indicates that an endpoint is terminating the connection because it has received a message that violates its policy. This is a generic status code
* that can be returned when there is no other more suitable status code (e.g., 1003 or 1009) or if there is a need to hide specific details about the
* policy.
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
*/
public final static short POLICY_VIOLATION = 1008;
/**
* 1009 indicates that an endpoint is terminating the connection because it has received a message that is too big for it to process.
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
*/
public final static short MESSAGE_TOO_LARGE = 1009;
/**
* 1010 indicates that an endpoint (client) is terminating the connection because it has expected the server to negotiate one or more extension, but the
* server didn't return them in the response message of the WebSocket handshake. The list of extensions that are needed SHOULD appear in the /reason/ part
* of the Close frame. Note that this status code is not used by the server, because it can fail the WebSocket handshake instead.
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
*/
public final static short REQUIRED_EXTENSION = 1010;
/**
* 1011 indicates that a server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
*/
public final static short SERVER_ERROR = 1011;
/**
* 1015 is a reserved value and MUST NOT be set as a status code in a Close control frame by an endpoint. It is designated for use in applications expecting
* a status code to indicate that the connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified).
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455, Section 7.4.1 Defined Status Codes</a>.
*/
public final static short FAILED_TLS_HANDSHAKE = 1015;
}

View File

@ -1,10 +1,5 @@
package org.eclipse.jetty.websocket.api;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import org.eclipse.jetty.util.B64Code;
import org.eclipse.jetty.util.StringUtil;
/**
* Constants for WebSocket protocol as-defined in <a href="https://tools.ietf.org/html/rfc6455">RFC-6455</a>.
@ -15,57 +10,4 @@ public class WebSocket
* Per <a href="https://tools.ietf.org/html/rfc6455#section-1.3">RFC 6455, section 1.3</a> - Opening Handshake - this version is "13"
*/
public final static int VERSION = 13;
/**
* Globally Unique Identifier for use in WebSocket handshake within <code>Sec-WebSocket-Accept</code> and <code>Sec-WebSocket-Key</code> http headers.
* <p>
* See <a href="https://tools.ietf.org/html/rfc6455#section-1.3">Opening Handshake (Section 1.3)</a>
*/
private final static byte[] MAGIC;
public final static short CLOSE_NORMAL = 1000;
public final static short CLOSE_SHUTDOWN = 1001;
public final static short CLOSE_PROTOCOL = 1002;
public final static short CLOSE_BAD_DATA = 1003;
public final static short CLOSE_UNDEFINED = 1004;
public final static short CLOSE_NO_CODE = 1005;
public final static short CLOSE_NO_CLOSE = 1006;
public final static short CLOSE_BAD_PAYLOAD = 1007;
public final static short CLOSE_POLICY_VIOLATION = 1008;
public final static short CLOSE_MESSAGE_TOO_LARGE = 1009;
public final static short CLOSE_REQUIRED_EXTENSION = 1010;
public final static short CLOSE_SERVER_ERROR = 1011;
public final static short CLOSE_FAILED_TLS_HANDSHAKE = 1015;
static
{
try
{
MAGIC = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".getBytes(StringUtil.__ISO_8859_1);
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e);
}
}
/**
* Concatenate the provided key with the Magic GUID and return the Base64 encoded form.
* @param key the key to hash
* @return the <code>Sec-WebSocket-Accept</code> header response (per opening handshake spec)
*/
public static String hashKey(String key)
{
try
{
MessageDigest md = MessageDigest.getInstance("SHA1");
md.update(key.getBytes("UTF-8"));
md.update(MAGIC);
return new String(B64Code.encode(md.digest()));
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}

View File

@ -1,7 +1,7 @@
package org.eclipse.jetty.websocket.frames;
import org.eclipse.jetty.websocket.api.OpCode;
import org.eclipse.jetty.websocket.api.WebSocket;
import org.eclipse.jetty.websocket.api.StatusCode;
/**
* Representation of a <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">Close Frame (0x08)</a>.
@ -13,7 +13,7 @@ public class CloseFrame extends ControlFrame
public CloseFrame()
{
this(WebSocket.CLOSE_NORMAL); // TODO: evaluate default (or unspecified status code)
this(StatusCode.NORMAL); // TODO: evaluate default (or unspecified status code)
}
public CloseFrame(short statusCode)

View File

@ -6,7 +6,7 @@ import java.nio.ByteBuffer;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.websocket.Debug;
import org.eclipse.jetty.websocket.api.WebSocket;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.frames.CloseFrame;
@ -24,7 +24,7 @@ public class ClosePayloadParserTest
byte utf[] = expectedReason.getBytes(StringUtil.__UTF8_CHARSET);
ByteBuffer payload = ByteBuffer.allocate(utf.length + 2);
payload.putShort(WebSocket.CLOSE_NORMAL);
payload.putShort(StatusCode.NORMAL);
payload.put(utf,0,utf.length);
payload.flip();
@ -44,7 +44,7 @@ public class ClosePayloadParserTest
capture.assertNoErrors();
capture.assertHasFrame(CloseFrame.class,1);
CloseFrame txt = (CloseFrame)capture.getFrames().get(0);
Assert.assertThat("CloseFrame.statusCode",txt.getStatusCode(),is(WebSocket.CLOSE_NORMAL));
Assert.assertThat("CloseFrame.statusCode",txt.getStatusCode(),is(StatusCode.NORMAL));
Assert.assertThat("CloseFrame.data",txt.getReason(),is(expectedReason));
}
}

View File

@ -7,7 +7,7 @@ import java.util.Arrays;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.websocket.api.PolicyViolationException;
import org.eclipse.jetty.websocket.api.WebSocket;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.frames.TextFrame;
@ -43,7 +43,7 @@ public class TextPayloadParserTest
capture.assertHasNoFrames();
PolicyViolationException err = (PolicyViolationException)capture.getErrors().get(0);
Assert.assertThat("Error.closeCode",err.getCloseCode(),is(WebSocket.CLOSE_POLICY_VIOLATION));
Assert.assertThat("Error.closeCode",err.getCloseCode(),is(StatusCode.POLICY_VIOLATION));
}
@Test

View File

@ -40,7 +40,9 @@ import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.Utf8StringBuilder;
import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.api.AcceptHash;
import org.eclipse.jetty.websocket.api.OpCode;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
@ -929,7 +931,7 @@ public class WebSocketMessageRFC6455Test
@Test
public void testHash()
{
assertEquals("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",org.eclipse.jetty.websocket.api.WebSocket.hashKey("dGhlIHNhbXBsZSBub25jZQ=="));
assertEquals("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",AcceptHash.hashKey("dGhlIHNhbXBsZSBub25jZQ=="));
}
@Test
@ -1096,7 +1098,7 @@ public class WebSocketMessageRFC6455Test
assertEquals(0x80 | OpCode.CLOSE.getCode(),input.read());
assertEquals(19,input.read());
int code=((0xff&input.read())*0x100)+(0xff&input.read());
assertEquals(org.eclipse.jetty.websocket.api.WebSocket.CLOSE_MESSAGE_TOO_LARGE,code);
assertEquals(StatusCode.MESSAGE_TOO_LARGE,code);
lookFor("Message size > 15",input);
}
@ -1146,7 +1148,7 @@ public class WebSocketMessageRFC6455Test
assertEquals(0x80 | OpCode.CLOSE.getCode(),input.read());
assertEquals(19,input.read());
int code=((0xff&input.read())*0x100)+(0xff&input.read());
assertEquals(org.eclipse.jetty.websocket.api.WebSocket.CLOSE_MESSAGE_TOO_LARGE,code);
assertEquals(StatusCode.MESSAGE_TOO_LARGE,code);
lookFor("Message size > 15",input);
}
@ -1210,7 +1212,7 @@ public class WebSocketMessageRFC6455Test
assertEquals(0x80 | OpCode.CLOSE.getCode(),input.read());
assertEquals(30,input.read());
int code=((0xff&input.read())*0x100)+(0xff&input.read());
assertEquals(org.eclipse.jetty.websocket.api.WebSocket.CLOSE_MESSAGE_TOO_LARGE,code);
assertEquals(StatusCode.MESSAGE_TOO_LARGE,code);
lookFor("Text message size > 15 chars",input);
}
@ -1264,7 +1266,7 @@ public class WebSocketMessageRFC6455Test
assertEquals(0x80 | OpCode.CLOSE.getCode(),input.read());
assertEquals(30,input.read());
int code=((0xff&input.read())*0x100)+(0xff&input.read());
assertEquals(org.eclipse.jetty.websocket.api.WebSocket.CLOSE_MESSAGE_TOO_LARGE,code);
assertEquals(StatusCode.MESSAGE_TOO_LARGE,code);
lookFor("Text message size > 15 chars",input);
}
@ -1319,7 +1321,7 @@ public class WebSocketMessageRFC6455Test
assertEquals(0x80 | OpCode.CLOSE.getCode(),input.read());
assertEquals(33,input.read());
int code=((0xff&input.read())*0x100)+(0xff&input.read());
assertEquals(org.eclipse.jetty.websocket.api.WebSocket.CLOSE_MESSAGE_TOO_LARGE,code);
assertEquals(StatusCode.MESSAGE_TOO_LARGE,code);
lookFor("Text message size > 10240 chars",input);
}
@ -1366,7 +1368,7 @@ public class WebSocketMessageRFC6455Test
assertEquals(0x80 | OpCode.CLOSE.getCode(),input.read());
assertEquals(15,input.read());
int code=((0xff&input.read())*0x100)+(0xff&input.read());
assertEquals(org.eclipse.jetty.websocket.api.WebSocket.CLOSE_BAD_PAYLOAD,code);
assertEquals(StatusCode.BAD_PAYLOAD,code);
lookFor("Invalid UTF-8",input);
}

View File

@ -0,0 +1,6 @@
package org.eclipse.jetty.websocket.server;
public class WebSocketServletTest
{
}