Clean up the new WebSocket package

This commit is contained in:
Trustin Lee 2012-01-19 13:12:45 +09:00
parent 59e5f2f262
commit c1aa8b4c7b
31 changed files with 414 additions and 436 deletions

View File

@ -27,7 +27,7 @@ public class BinaryWebSocketFrame extends WebSocketFrame {
* Creates a new empty binary frame.
*/
public BinaryWebSocketFrame() {
this.setBinaryData(ChannelBuffers.EMPTY_BUFFER);
setBinaryData(ChannelBuffers.EMPTY_BUFFER);
}
/**
@ -37,7 +37,7 @@ public class BinaryWebSocketFrame extends WebSocketFrame {
* the content of the frame.
*/
public BinaryWebSocketFrame(ChannelBuffer binaryData) {
this.setBinaryData(binaryData);
setBinaryData(binaryData);
}
/**
@ -51,9 +51,9 @@ public class BinaryWebSocketFrame extends WebSocketFrame {
* the content of the frame.
*/
public BinaryWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) {
this.setFinalFragment(finalFragment);
this.setRsv(rsv);
this.setBinaryData(binaryData);
setFinalFragment(finalFragment);
setRsv(rsv);
setBinaryData(binaryData);
}
@Override

View File

@ -26,7 +26,7 @@ public class CloseWebSocketFrame extends WebSocketFrame {
* Creates a new empty close frame.
*/
public CloseWebSocketFrame() {
this.setBinaryData(ChannelBuffers.EMPTY_BUFFER);
setBinaryData(ChannelBuffers.EMPTY_BUFFER);
}
/**
@ -38,8 +38,8 @@ public class CloseWebSocketFrame extends WebSocketFrame {
* reserved bits used for protocol extensions
*/
public CloseWebSocketFrame(boolean finalFragment, int rsv) {
this.setFinalFragment(finalFragment);
this.setRsv(rsv);
setFinalFragment(finalFragment);
setRsv(rsv);
}
@Override

View File

@ -31,7 +31,7 @@ public class ContinuationWebSocketFrame extends WebSocketFrame {
* Creates a new empty continuation frame.
*/
public ContinuationWebSocketFrame() {
this.setBinaryData(ChannelBuffers.EMPTY_BUFFER);
setBinaryData(ChannelBuffers.EMPTY_BUFFER);
}
/**
@ -41,7 +41,7 @@ public class ContinuationWebSocketFrame extends WebSocketFrame {
* the content of the frame.
*/
public ContinuationWebSocketFrame(ChannelBuffer binaryData) {
this.setBinaryData(binaryData);
setBinaryData(binaryData);
}
/**
@ -55,9 +55,9 @@ public class ContinuationWebSocketFrame extends WebSocketFrame {
* the content of the frame.
*/
public ContinuationWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) {
this.setFinalFragment(finalFragment);
this.setRsv(rsv);
this.setBinaryData(binaryData);
setFinalFragment(finalFragment);
setRsv(rsv);
setBinaryData(binaryData);
}
/**
@ -73,9 +73,9 @@ public class ContinuationWebSocketFrame extends WebSocketFrame {
* Aggregated text set by decoder on the final continuation frame of a fragmented text message
*/
public ContinuationWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData, String aggregatedText) {
this.setFinalFragment(finalFragment);
this.setRsv(rsv);
this.setBinaryData(binaryData);
setFinalFragment(finalFragment);
setRsv(rsv);
setBinaryData(binaryData);
this.aggregatedText = aggregatedText;
}
@ -90,19 +90,19 @@ public class ContinuationWebSocketFrame extends WebSocketFrame {
* text content of the frame.
*/
public ContinuationWebSocketFrame(boolean finalFragment, int rsv, String text) {
this.setFinalFragment(finalFragment);
this.setRsv(rsv);
this.setText(text);
setFinalFragment(finalFragment);
setRsv(rsv);
setText(text);
}
/**
* Returns the text data in this frame
*/
public String getText() {
if (this.getBinaryData() == null) {
if (getBinaryData() == null) {
return null;
}
return this.getBinaryData().toString(CharsetUtil.UTF_8);
return getBinaryData().toString(CharsetUtil.UTF_8);
}
/**
@ -113,9 +113,9 @@ public class ContinuationWebSocketFrame extends WebSocketFrame {
*/
public void setText(String text) {
if (text == null || text.isEmpty()) {
this.setBinaryData(ChannelBuffers.EMPTY_BUFFER);
setBinaryData(ChannelBuffers.EMPTY_BUFFER);
} else {
this.setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8));
setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8));
}
}

View File

@ -27,8 +27,8 @@ public class PingWebSocketFrame extends WebSocketFrame {
* Creates a new empty ping frame.
*/
public PingWebSocketFrame() {
this.setFinalFragment(true);
this.setBinaryData(ChannelBuffers.EMPTY_BUFFER);
setFinalFragment(true);
setBinaryData(ChannelBuffers.EMPTY_BUFFER);
}
/**
@ -38,7 +38,7 @@ public class PingWebSocketFrame extends WebSocketFrame {
* the content of the frame.
*/
public PingWebSocketFrame(ChannelBuffer binaryData) {
this.setBinaryData(binaryData);
setBinaryData(binaryData);
}
/**
@ -52,9 +52,9 @@ public class PingWebSocketFrame extends WebSocketFrame {
* the content of the frame.
*/
public PingWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) {
this.setFinalFragment(finalFragment);
this.setRsv(rsv);
this.setBinaryData(binaryData);
setFinalFragment(finalFragment);
setRsv(rsv);
setBinaryData(binaryData);
}
@Override

View File

@ -27,7 +27,7 @@ public class PongWebSocketFrame extends WebSocketFrame {
* Creates a new empty pong frame.
*/
public PongWebSocketFrame() {
this.setBinaryData(ChannelBuffers.EMPTY_BUFFER);
setBinaryData(ChannelBuffers.EMPTY_BUFFER);
}
/**
@ -37,7 +37,7 @@ public class PongWebSocketFrame extends WebSocketFrame {
* the content of the frame.
*/
public PongWebSocketFrame(ChannelBuffer binaryData) {
this.setBinaryData(binaryData);
setBinaryData(binaryData);
}
/**
@ -51,9 +51,9 @@ public class PongWebSocketFrame extends WebSocketFrame {
* the content of the frame.
*/
public PongWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) {
this.setFinalFragment(finalFragment);
this.setRsv(rsv);
this.setBinaryData(binaryData);
setFinalFragment(finalFragment);
setRsv(rsv);
setBinaryData(binaryData);
}
@Override

View File

@ -28,7 +28,7 @@ public class TextWebSocketFrame extends WebSocketFrame {
* Creates a new empty text frame.
*/
public TextWebSocketFrame() {
this.setBinaryData(ChannelBuffers.EMPTY_BUFFER);
setBinaryData(ChannelBuffers.EMPTY_BUFFER);
}
/**
@ -39,9 +39,9 @@ public class TextWebSocketFrame extends WebSocketFrame {
*/
public TextWebSocketFrame(String text) {
if (text == null || text.isEmpty()) {
this.setBinaryData(ChannelBuffers.EMPTY_BUFFER);
setBinaryData(ChannelBuffers.EMPTY_BUFFER);
} else {
this.setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8));
setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8));
}
}
@ -52,7 +52,7 @@ public class TextWebSocketFrame extends WebSocketFrame {
* the content of the frame. Must be UTF-8 encoded
*/
public TextWebSocketFrame(ChannelBuffer binaryData) {
this.setBinaryData(binaryData);
setBinaryData(binaryData);
}
/**
@ -66,12 +66,12 @@ public class TextWebSocketFrame extends WebSocketFrame {
* String to put in the frame
*/
public TextWebSocketFrame(boolean finalFragment, int rsv, String text) {
this.setFinalFragment(finalFragment);
this.setRsv(rsv);
setFinalFragment(finalFragment);
setRsv(rsv);
if (text == null || text.isEmpty()) {
this.setBinaryData(ChannelBuffers.EMPTY_BUFFER);
setBinaryData(ChannelBuffers.EMPTY_BUFFER);
} else {
this.setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8));
setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8));
}
}
@ -86,19 +86,19 @@ public class TextWebSocketFrame extends WebSocketFrame {
* the content of the frame. Must be UTF-8 encoded
*/
public TextWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) {
this.setFinalFragment(finalFragment);
this.setRsv(rsv);
this.setBinaryData(binaryData);
setFinalFragment(finalFragment);
setRsv(rsv);
setBinaryData(binaryData);
}
/**
* Returns the text data in this frame
*/
public String getText() {
if (this.getBinaryData() == null) {
if (getBinaryData() == null) {
return null;
}
return this.getBinaryData().toString(CharsetUtil.UTF_8);
return getBinaryData().toString(CharsetUtil.UTF_8);
}
/**
@ -111,7 +111,7 @@ public class TextWebSocketFrame extends WebSocketFrame {
if (text == null) {
throw new NullPointerException("text");
}
this.setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8));
setBinaryData(ChannelBuffers.copiedBuffer(text, CharsetUtil.UTF_8));
}
@Override

View File

@ -60,7 +60,7 @@ final class UTF8Output {
public void write(int b) {
byte type = TYPES[b & 0xFF];
codep = (state != UTF8_ACCEPT) ? (b & 0x3f) | (codep << 6) : (0xff >> type) & b;
codep = state != UTF8_ACCEPT ? b & 0x3f | codep << 6 : 0xff >> type & b;
state = STATES[state + type];

View File

@ -33,7 +33,7 @@ import io.netty.handler.codec.replay.VoidEnum;
*/
public class WebSocket00FrameDecoder extends ReplayingDecoder<VoidEnum> {
public static final int DEFAULT_MAX_FRAME_SIZE = 16384;
private static final int DEFAULT_MAX_FRAME_SIZE = 16384;
private final int maxFrameSize;
private boolean receivedClosingHandshake;
@ -70,7 +70,7 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder<VoidEnum> {
return decodeBinaryFrame(type, buffer);
} else {
// Decode a 0xff terminated UTF-8 string
return decodeTextFrame(type, buffer);
return decodeTextFrame(buffer);
}
}
@ -92,7 +92,7 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder<VoidEnum> {
}
} while ((b & 0x80) == 0x80);
if (type == ((byte) 0xFF) && frameSize == 0) {
if (type == (byte) 0xFF && frameSize == 0) {
receivedClosingHandshake = true;
return new CloseWebSocketFrame();
}
@ -100,7 +100,7 @@ public class WebSocket00FrameDecoder extends ReplayingDecoder<VoidEnum> {
return new BinaryWebSocketFrame(buffer.readBytes((int) frameSize));
}
private WebSocketFrame decodeTextFrame(byte type, ChannelBuffer buffer) throws TooLongFrameException {
private WebSocketFrame decodeTextFrame(ChannelBuffer buffer) throws TooLongFrameException {
int ridx = buffer.readerIndex();
int rbytes = actualReadableBytes();
int delimPos = buffer.indexOf(ridx, ridx + rbytes, (byte) 0xFF);

View File

@ -75,8 +75,8 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
private int framePayloadBytesRead;
private ChannelBuffer maskingKey;
private boolean allowExtensions;
private boolean maskedPayload;
private final boolean allowExtensions;
private final boolean maskedPayload;
private boolean receivedClosingHandshake;
public enum State {
@ -129,12 +129,12 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
boolean frameMasked = (b & 0x80) != 0;
int framePayloadLen1 = b & 0x7F;
if (frameRsv != 0 && !this.allowExtensions) {
if (frameRsv != 0 && !allowExtensions) {
protocolViolation(channel, "RSV != 0 and no extension negotiated, RSV:" + frameRsv);
return null;
}
if (this.maskedPayload && !frameMasked) {
if (maskedPayload && !frameMasked) {
protocolViolation(channel, "unmasked client to server frame");
return null;
}
@ -211,7 +211,7 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
checkpoint(State.MASKING_KEY);
case MASKING_KEY:
if (this.maskedPayload) {
if (maskedPayload) {
maskingKey = buffer.readBytes(4);
}
checkpoint(State.PAYLOAD);
@ -236,7 +236,7 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
framePayload = channel.getConfig().getBufferFactory().getBuffer(toFrameLength(framePayloadLength));
}
framePayload.writeBytes(payloadBuffer);
framePayloadBytesRead = framePayloadBytesRead + rbytes;
framePayloadBytesRead += rbytes;
// Return null to wait for more bytes to arrive
return null;
@ -258,7 +258,7 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
}
// Unmask data if needed
if (this.maskedPayload) {
if (maskedPayload) {
unmask(framePayload);
}
@ -269,7 +269,7 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
} else if (frameOpcode == OPCODE_PONG) {
return new PongWebSocketFrame(frameFinalFlag, frameRsv, framePayload);
} else if (frameOpcode == OPCODE_CLOSE) {
this.receivedClosingHandshake = true;
receivedClosingHandshake = true;
return new CloseWebSocketFrame(frameFinalFlag, frameRsv);
}

View File

@ -66,7 +66,7 @@ public class WebSocket08FrameEncoder extends OneToOneEncoder {
private static final byte OPCODE_PING = 0x9;
private static final byte OPCODE_PONG = 0xA;
private boolean maskPayload;
private final boolean maskPayload;
/**
* Constructor
@ -82,7 +82,7 @@ public class WebSocket08FrameEncoder extends OneToOneEncoder {
@Override
protected Object encode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
byte[] mask = null;
byte[] mask;
if (msg instanceof WebSocketFrame) {
WebSocketFrame frame = (WebSocketFrame) msg;
@ -118,7 +118,7 @@ public class WebSocket08FrameEncoder extends OneToOneEncoder {
if (frame.isFinalFragment()) {
b0 |= 1 << 7;
}
b0 |= (frame.getRsv() % 8) << 4;
b0 |= frame.getRsv() % 8 << 4;
b0 |= opcode % 128;
ChannelBuffer header;
@ -129,27 +129,27 @@ public class WebSocket08FrameEncoder extends OneToOneEncoder {
+ length);
}
int maskLength = this.maskPayload ? 4 : 0;
int maskLength = maskPayload ? 4 : 0;
if (length <= 125) {
header = ChannelBuffers.buffer(2 + maskLength);
header.writeByte(b0);
byte b = (byte) (this.maskPayload ? (0x80 | (byte) length) : (byte) length);
byte b = (byte) (maskPayload ? 0x80 | (byte) length : (byte) length);
header.writeByte(b);
} else if (length <= 0xFFFF) {
header = ChannelBuffers.buffer(4 + maskLength);
header.writeByte(b0);
header.writeByte(this.maskPayload ? 0xFE : 126);
header.writeByte((length >>> 8) & 0xFF);
header.writeByte(maskPayload ? 0xFE : 126);
header.writeByte(length >>> 8 & 0xFF);
header.writeByte(length & 0xFF);
} else {
header = ChannelBuffers.buffer(10 + maskLength);
header.writeByte(b0);
header.writeByte(this.maskPayload ? 0xFF : 127);
header.writeByte(maskPayload ? 0xFF : 127);
header.writeLong(length);
}
// Write payload
if (this.maskPayload) {
if (maskPayload) {
Integer random = (int) (Math.random() * Integer.MAX_VALUE);
mask = ByteBuffer.allocate(4).putInt(random).array();
header.writeBytes(mask);

View File

@ -23,6 +23,7 @@ import java.util.Map;
import io.netty.buffer.ChannelBuffer;
import io.netty.buffer.ChannelBuffers;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.base64.Base64;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.util.CharsetUtil;
@ -32,35 +33,44 @@ import io.netty.util.CharsetUtil;
*/
public abstract class WebSocketClientHandshaker {
private URI webSocketURL;
private final URI webSocketUrl;
private WebSocketVersion version = WebSocketVersion.UNKNOWN;
private final WebSocketVersion version;
private boolean openingHandshakeCompleted;
private boolean handshakeComplete;
private String subProtocolRequest;
private final String expectedSubprotocol;
private String subProtocolResponse;
private String actualSubprotocol;
protected Map<String, String> customHeaders;
protected final Map<String, String> customHeaders;
public WebSocketClientHandshaker(URI webSocketURL, WebSocketVersion version, String subProtocol,
/**
* Base constructor
*
* @param webSocketUrl
* URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be
* sent to this URL.
* @param version
* Version of web socket specification to use to connect to the server
* @param subprotocol
* Sub protocol request sent to the server.
* @param customHeaders
* Map of custom headers to add to the client request
*/
public WebSocketClientHandshaker(URI webSocketUrl, WebSocketVersion version, String subprotocol,
Map<String, String> customHeaders) {
this.webSocketURL = webSocketURL;
this.webSocketUrl = webSocketUrl;
this.version = version;
this.subProtocolRequest = subProtocol;
expectedSubprotocol = subprotocol;
this.customHeaders = customHeaders;
}
/**
* Returns the URI to the web socket. e.g. "ws://myhost.com/path"
*/
public URI getWebSocketURL() {
return webSocketURL;
}
protected void setWebSocketURL(URI webSocketURL) {
this.webSocketURL = webSocketURL;
public URI getWebSocketUrl() {
return webSocketUrl;
}
/**
@ -70,133 +80,50 @@ public abstract class WebSocketClientHandshaker {
return version;
}
protected void setVersion(WebSocketVersion version) {
this.version = version;
}
/**
* Flag to indicate if the opening handshake is complete
*/
public boolean isOpeningHandshakeCompleted() {
return openingHandshakeCompleted;
public boolean isHandshakeComplete() {
return handshakeComplete;
}
protected void setOpenningHandshakeCompleted(boolean openningHandshakeCompleted) {
this.openingHandshakeCompleted = openningHandshakeCompleted;
protected void setHandshakeComplete() {
handshakeComplete = true;
}
/**
* Returns the sub protocol request sent to the server as specified in the constructor
*/
public String getSubProtocolRequest() {
return subProtocolRequest;
}
protected void setSubProtocolRequest(String subProtocolRequest) {
this.subProtocolRequest = subProtocolRequest;
public String getExpectedSubprotocol() {
return expectedSubprotocol;
}
/**
* Returns the sub protocol response and sent by the server. Only available after end of handshake.
*/
public String getSubProtocolResponse() {
return subProtocolResponse;
public String getActualSubprotocol() {
return actualSubprotocol;
}
protected void setSubProtocolResponse(String subProtocolResponse) {
this.subProtocolResponse = subProtocolResponse;
protected void setActualSubprotocol(String actualSubprotocol) {
this.actualSubprotocol = actualSubprotocol;
}
/**
* Performs the opening handshake
* Begins the opening handshake
*
* @param channel
* Channel
*/
public abstract void performOpeningHandshake(Channel channel);
public abstract ChannelFuture handshake(Channel channel);
/**
* Performs the closing handshake
* Validates and finishes the opening handshake initiated by {@link #handshake}}.
*
* @param channel
* Channel
* @param response
* HTTP response containing the closing handshake details
*/
public abstract void performClosingHandshake(Channel channel, HttpResponse response)
throws WebSocketHandshakeException;
/**
* Performs an MD5 hash
*
* @param bytes
* Data to hash
* @return Hashed data
*/
protected byte[] md5(byte[] bytes) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
return md.digest(bytes);
} catch (NoSuchAlgorithmException e) {
throw new InternalError("MD5 not supported on this platform");
}
}
/**
* Performs an SHA-1 hash
*
* @param bytes
* Data to hash
* @return Hashed data
*/
protected byte[] sha1(byte[] bytes) {
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
return md.digest(bytes);
} catch (NoSuchAlgorithmException e) {
throw new InternalError("SHA-1 not supported on this platform");
}
}
/**
* Base 64 encoding
*
* @param bytes
* Bytes to encode
* @return encoded string
*/
protected String base64Encode(byte[] bytes) {
ChannelBuffer hashed = ChannelBuffers.wrappedBuffer(bytes);
return Base64.encode(hashed).toString(CharsetUtil.UTF_8);
}
/**
* Creates some random bytes
*
* @param size
* Number of random bytes to create
* @return random bytes
*/
protected byte[] createRandomBytes(int size) {
byte[] bytes = new byte[size];
for (int i = 0; i < size; i++) {
bytes[i] = (byte) createRandomNumber(0, 255);
}
return bytes;
}
/**
* Generates a random number
*
* @param min
* Minimum value
* @param max
* Maximum value
* @return Random number
*/
protected int createRandomNumber(int min, int max) {
return (int) (Math.random() * max + min);
}
public abstract void finishHandshake(Channel channel, HttpResponse response);
}

View File

@ -22,6 +22,7 @@ import java.util.Map;
import io.netty.buffer.ChannelBuffers;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values;
@ -55,14 +56,14 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
* sent to this URL.
* @param version
* Version of web socket specification to use to connect to the server
* @param subProtocol
* @param subprotocol
* Sub protocol request sent to the server.
* @param customHeaders
* Map of custom headers to add to the client request
*/
public WebSocketClientHandshaker00(URI webSocketURL, WebSocketVersion version, String subProtocol,
public WebSocketClientHandshaker00(URI webSocketURL, WebSocketVersion version, String subprotocol,
Map<String, String> customHeaders) {
super(webSocketURL, version, subProtocol, customHeaders);
super(webSocketURL, version, subprotocol, customHeaders);
}
@ -87,16 +88,16 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
* Channel into which we can write our request
*/
@Override
public void performOpeningHandshake(Channel channel) {
public ChannelFuture handshake(Channel channel) {
// Make keys
int spaces1 = createRandomNumber(1, 12);
int spaces2 = createRandomNumber(1, 12);
int spaces1 = WebSocketUtil.randomNumber(1, 12);
int spaces2 = WebSocketUtil.randomNumber(1, 12);
int max1 = Integer.MAX_VALUE / spaces1;
int max2 = Integer.MAX_VALUE / spaces2;
int number1 = createRandomNumber(0, max1);
int number2 = createRandomNumber(0, max2);
int number1 = WebSocketUtil.randomNumber(0, max1);
int number2 = WebSocketUtil.randomNumber(0, max2);
int product1 = number1 * spaces1;
int product2 = number2 * spaces2;
@ -110,7 +111,7 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
key1 = insertSpaces(key1, spaces1);
key2 = insertSpaces(key2, spaces2);
byte[] key3 = createRandomBytes(8);
byte[] key3 = WebSocketUtil.randomBytes(8);
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.putInt(number1);
@ -123,10 +124,10 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
System.arraycopy(number1Array, 0, challenge, 0, 4);
System.arraycopy(number2Array, 0, challenge, 4, 4);
System.arraycopy(key3, 0, challenge, 8, 8);
this.expectedChallengeResponseBytes = md5(challenge);
expectedChallengeResponseBytes = WebSocketUtil.md5(challenge);
// Get path
URI wsURL = this.getWebSocketURL();
URI wsURL = getWebSocketUrl();
String path = wsURL.getPath();
if (wsURL.getQuery() != null && wsURL.getQuery().length() > 0) {
path = wsURL.getPath() + "?" + wsURL.getQuery();
@ -140,8 +141,8 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
request.addHeader(Names.ORIGIN, "http://" + wsURL.getHost());
request.addHeader(Names.SEC_WEBSOCKET_KEY1, key1);
request.addHeader(Names.SEC_WEBSOCKET_KEY2, key2);
if (this.getSubProtocolRequest() != null && !this.getSubProtocolRequest().equals("")) {
request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, this.getSubProtocolRequest());
if (getExpectedSubprotocol() != null && !getExpectedSubprotocol().equals("")) {
request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, getExpectedSubprotocol());
}
if (customHeaders != null) {
@ -152,9 +153,11 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
request.setContent(ChannelBuffers.copiedBuffer(key3));
channel.write(request);
ChannelFuture future = channel.write(request);
channel.getPipeline().replace(HttpRequestEncoder.class, "ws-encoder", new WebSocket00FrameEncoder());
return future;
}
/**
@ -180,7 +183,7 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
* @throws WebSocketHandshakeException
*/
@Override
public void performClosingHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException {
public void finishHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException {
final HttpResponseStatus status = new HttpResponseStatus(101, "WebSocket Protocol Handshake");
if (!response.getStatus().equals(status)) {
@ -205,28 +208,28 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
}
String protocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
this.setSubProtocolResponse(protocol);
setActualSubprotocol(protocol);
channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder", new WebSocket00FrameDecoder());
this.setOpenningHandshakeCompleted(true);
setHandshakeComplete();
}
private String insertRandomCharacters(String key) {
int count = createRandomNumber(1, 12);
int count = WebSocketUtil.randomNumber(1, 12);
char[] randomChars = new char[count];
int randCount = 0;
while (randCount < count) {
int rand = (int) (Math.random() * 0x7e + 0x21);
if (((0x21 < rand) && (rand < 0x2f)) || ((0x3a < rand) && (rand < 0x7e))) {
if (0x21 < rand && rand < 0x2f || 0x3a < rand && rand < 0x7e) {
randomChars[randCount] = (char) rand;
randCount += 1;
}
}
for (int i = 0; i < count; i++) {
int split = createRandomNumber(0, key.length());
int split = WebSocketUtil.randomNumber(0, key.length());
String part1 = key.substring(0, split);
String part2 = key.substring(split);
key = part1 + randomChars[i] + part2;
@ -237,7 +240,7 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
private String insertSpaces(String key, int spaces) {
for (int i = 0; i < spaces; i++) {
int split = createRandomNumber(1, key.length() - 1);
int split = WebSocketUtil.randomNumber(1, key.length() - 1);
String part1 = key.substring(0, split);
String part2 = key.substring(split);
key = part1 + " " + part2;

View File

@ -19,6 +19,7 @@ import java.net.URI;
import java.util.Map;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values;
@ -50,7 +51,7 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
private static final String protocol = null;
private boolean allowExtensions;
private final boolean allowExtensions;
/**
* Constructor specifying the destination web socket location and version to initiate
@ -60,16 +61,16 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
* sent to this URL.
* @param version
* Version of web socket specification to use to connect to the server
* @param subProtocol
* @param subprotocol
* Sub protocol request sent to the server.
* @param allowExtensions
* Allow extensions to be used in the reserved bits of the web socket frame
* @param customHeaders
* Map of custom headers to add to the client request
*/
public WebSocketClientHandshaker08(URI webSocketURL, WebSocketVersion version, String subProtocol,
public WebSocketClientHandshaker08(URI webSocketURL, WebSocketVersion version, String subprotocol,
boolean allowExtensions, Map<String, String> customHeaders) {
super(webSocketURL, version, subProtocol, customHeaders);
super(webSocketURL, version, subprotocol, customHeaders);
this.allowExtensions = allowExtensions;
}
@ -94,25 +95,25 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
* Channel into which we can write our request
*/
@Override
public void performOpeningHandshake(Channel channel) {
public ChannelFuture handshake(Channel channel) {
// Get path
URI wsURL = this.getWebSocketURL();
URI wsURL = getWebSocketUrl();
String path = wsURL.getPath();
if (wsURL.getQuery() != null && wsURL.getQuery().length() > 0) {
path = wsURL.getPath() + "?" + wsURL.getQuery();
}
// Get 16 bit nonce and base 64 encode it
byte[] nonce = createRandomBytes(16);
String key = base64Encode(nonce);
byte[] nonce = WebSocketUtil.randomBytes(16);
String key = WebSocketUtil.base64(nonce);
String acceptSeed = key + MAGIC_GUID;
byte[] sha1 = sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII));
this.expectedChallengeResponseString = base64Encode(sha1);
byte[] sha1 = WebSocketUtil.sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII));
expectedChallengeResponseString = WebSocketUtil.base64(sha1);
if (logger.isDebugEnabled()) {
logger.debug(String.format("WS Version 08 Client Handshake key: %s. Expected response: %s.", key,
this.expectedChallengeResponseString));
expectedChallengeResponseString));
}
// Format request
@ -133,9 +134,11 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
}
}
channel.write(request);
ChannelFuture future = channel.write(request);
channel.getPipeline().replace(HttpRequestEncoder.class, "ws-encoder", new WebSocket08FrameEncoder(true));
return future;
}
/**
@ -158,8 +161,8 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
* @throws WebSocketHandshakeException
*/
@Override
public void performClosingHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException {
final HttpResponseStatus status = new HttpResponseStatus(101, "Switching Protocols");
public void finishHandshake(Channel channel, HttpResponse response) {
final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS;
if (!response.getStatus().equals(status)) {
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus());
@ -178,15 +181,14 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
}
String accept = response.getHeader(Names.SEC_WEBSOCKET_ACCEPT);
if (accept == null || !accept.equals(this.expectedChallengeResponseString)) {
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept,
this.expectedChallengeResponseString));
expectedChallengeResponseString));
}
channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder",
new WebSocket08FrameDecoder(false, this.allowExtensions));
new WebSocket08FrameDecoder(false, allowExtensions));
this.setOpenningHandshakeCompleted(true);
setHandshakeComplete();
}
}

View File

@ -19,6 +19,7 @@ import java.net.URI;
import java.util.Map;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values;
@ -50,7 +51,7 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
private static final String protocol = null;
private boolean allowExtensions;
private final boolean allowExtensions;
/**
* Constructor specifying the destination web socket location and version to initiate
@ -60,16 +61,16 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
* sent to this URL.
* @param version
* Version of web socket specification to use to connect to the server
* @param subProtocol
* @param subprotocol
* Sub protocol request sent to the server.
* @param allowExtensions
* Allow extensions to be used in the reserved bits of the web socket frame
* @param customHeaders
* Map of custom headers to add to the client request
*/
public WebSocketClientHandshaker13(URI webSocketURL, WebSocketVersion version, String subProtocol,
public WebSocketClientHandshaker13(URI webSocketURL, WebSocketVersion version, String subprotocol,
boolean allowExtensions, Map<String, String> customHeaders) {
super(webSocketURL, version, subProtocol, customHeaders);
super(webSocketURL, version, subprotocol, customHeaders);
this.allowExtensions = allowExtensions;
}
@ -94,25 +95,25 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
* Channel into which we can write our request
*/
@Override
public void performOpeningHandshake(Channel channel) {
public ChannelFuture handshake(Channel channel) {
// Get path
URI wsURL = this.getWebSocketURL();
URI wsURL = getWebSocketUrl();
String path = wsURL.getPath();
if (wsURL.getQuery() != null && wsURL.getQuery().length() > 0) {
path = wsURL.getPath() + "?" + wsURL.getQuery();
}
// Get 16 bit nonce and base 64 encode it
byte[] nonce = createRandomBytes(16);
String key = base64Encode(nonce);
byte[] nonce = WebSocketUtil.randomBytes(16);
String key = WebSocketUtil.base64(nonce);
String acceptSeed = key + MAGIC_GUID;
byte[] sha1 = sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII));
this.expectedChallengeResponseString = base64Encode(sha1);
byte[] sha1 = WebSocketUtil.sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII));
expectedChallengeResponseString = WebSocketUtil.base64(sha1);
if (logger.isDebugEnabled()) {
logger.debug(String.format("WS Version 13 Client Handshake key: %s. Expected response: %s.", key,
this.expectedChallengeResponseString));
expectedChallengeResponseString));
}
// Format request
@ -132,9 +133,12 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
request.addHeader(header, customHeaders.get(header));
}
}
channel.write(request);
ChannelFuture future = channel.write(request);
channel.getPipeline().replace(HttpRequestEncoder.class, "ws-encoder", new WebSocket13FrameEncoder(true));
return future;
}
/**
@ -157,8 +161,8 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
* @throws WebSocketHandshakeException
*/
@Override
public void performClosingHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException {
final HttpResponseStatus status = new HttpResponseStatus(101, "Switching Protocols");
public void finishHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException {
final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS;
if (!response.getStatus().equals(status)) {
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus());
@ -177,15 +181,14 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
}
String accept = response.getHeader(Names.SEC_WEBSOCKET_ACCEPT);
if (accept == null || !accept.equals(this.expectedChallengeResponseString)) {
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept,
this.expectedChallengeResponseString));
expectedChallengeResponseString));
}
channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder",
new WebSocket13FrameDecoder(false, this.allowExtensions));
new WebSocket13FrameDecoder(false, allowExtensions));
this.setOpenningHandshakeCompleted(true);
setHandshakeComplete();
}
}

View File

@ -31,7 +31,7 @@ public class WebSocketClientHandshakerFactory {
* sent to this URL.
* @param version
* Version of web socket specification to use to connect to the server
* @param subProtocol
* @param subprotocol
* Sub protocol request sent to the server. Null if no sub-protocol support is required.
* @param allowExtensions
* Allow extensions to be used in the reserved bits of the web socket frame
@ -39,16 +39,16 @@ public class WebSocketClientHandshakerFactory {
* Custom HTTP headers to send during the handshake
* @throws WebSocketHandshakeException
*/
public WebSocketClientHandshaker newHandshaker(URI webSocketURL, WebSocketVersion version, String subProtocol,
public WebSocketClientHandshaker newHandshaker(URI webSocketURL, WebSocketVersion version, String subprotocol,
boolean allowExtensions, Map<String, String> customHeaders) throws WebSocketHandshakeException {
if (version == WebSocketVersion.V13) {
return new WebSocketClientHandshaker13(webSocketURL, version, subProtocol, allowExtensions, customHeaders);
return new WebSocketClientHandshaker13(webSocketURL, version, subprotocol, allowExtensions, customHeaders);
}
if (version == WebSocketVersion.V08) {
return new WebSocketClientHandshaker08(webSocketURL, version, subProtocol, allowExtensions, customHeaders);
return new WebSocketClientHandshaker08(webSocketURL, version, subprotocol, allowExtensions, customHeaders);
}
if (version == WebSocketVersion.V00) {
return new WebSocketClientHandshaker00(webSocketURL, version, subProtocol, customHeaders);
return new WebSocketClientHandshaker00(webSocketURL, version, subprotocol, customHeaders);
}
throw new WebSocketHandshakeException("Protocol version " + version.toString() + " not supported.");

View File

@ -18,7 +18,7 @@ package io.netty.handler.codec.http.websocketx;
/**
* Exception during handshaking process
*/
public class WebSocketHandshakeException extends Exception {
public class WebSocketHandshakeException extends RuntimeException {
private static final long serialVersionUID = 1L;

View File

@ -17,10 +17,13 @@ package io.netty.handler.codec.http.websocketx;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashSet;
import java.util.Set;
import io.netty.buffer.ChannelBuffer;
import io.netty.buffer.ChannelBuffers;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.base64.Base64;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.util.CharsetUtil;
@ -30,55 +33,54 @@ import io.netty.util.CharsetUtil;
*/
public abstract class WebSocketServerHandshaker {
private String webSocketURL;
private final String webSocketUrl;
private String subProtocols;
private final String[] subprotocols;
private String[] subProtocolsArray;
private WebSocketVersion version = WebSocketVersion.UNKNOWN;
private final WebSocketVersion version;
/**
* Constructor specifying the destination web socket location
*
* @param webSocketURL
* @param version
* the protocol version
* @param webSocketUrl
* URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be
* sent to this URL.
* @param subProtocols
* @param subprotocols
* CSV of supported protocols. Null if sub protocols not supported.
*/
public WebSocketServerHandshaker(String webSocketURL, String subProtocols) {
this.webSocketURL = webSocketURL;
this.subProtocols = subProtocols;
if (this.subProtocols != null) {
this.subProtocolsArray = subProtocols.split(",");
for (int i = 0; i < this.subProtocolsArray.length; i++) {
this.subProtocolsArray[i] = this.subProtocolsArray[i].trim();
protected WebSocketServerHandshaker(
WebSocketVersion version, String webSocketUrl, String subprotocols) {
this.version = version;
this.webSocketUrl = webSocketUrl;
if (subprotocols != null) {
String[] subprotocolArray = subprotocols.split(",");
for (int i = 0; i < subprotocolArray.length; i++) {
subprotocolArray[i] = subprotocolArray[i].trim();
}
this.subprotocols = subprotocolArray;
} else {
this.subprotocols = new String[0];
}
}
/**
* Returns the URL of the web socket
*/
public String getWebSocketURL() {
return webSocketURL;
}
public void setWebSocketURL(String webSocketURL) {
this.webSocketURL = webSocketURL;
public String getWebSocketUrl() {
return webSocketUrl;
}
/**
* Returns the CSV of supported sub protocols
*/
public String getSubProtocols() {
return subProtocols;
}
public void setSubProtocols(String subProtocols) {
this.subProtocols = subProtocols;
public Set<String> getSubprotocols() {
Set<String> ret = new LinkedHashSet<String>();
for (String p: this.subprotocols) {
ret.add(p);
}
return ret;
}
/**
@ -88,10 +90,6 @@ public abstract class WebSocketServerHandshaker {
return version;
}
public void setVersion(WebSocketVersion version) {
this.version = version;
}
/**
* Performs the opening handshake
*
@ -99,9 +97,8 @@ public abstract class WebSocketServerHandshaker {
* Channel
* @param req
* HTTP Request
* @throws NoSuchAlgorithmException
*/
public abstract void performOpeningHandshake(Channel channel, HttpRequest req);
public abstract ChannelFuture handshake(Channel channel, HttpRequest req);
/**
* Performs the closing handshake
@ -111,71 +108,27 @@ public abstract class WebSocketServerHandshaker {
* @param frame
* Closing Frame that was received
*/
public abstract void performClosingHandshake(Channel channel, CloseWebSocketFrame frame);
/**
* Performs an MD5 hash
*
* @param bytes
* Data to hash
* @return Hashed data
*/
protected byte[] md5(byte[] bytes) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
return md.digest(bytes);
} catch (NoSuchAlgorithmException e) {
throw new InternalError("MD5 not supported on this platform");
}
}
/**
* SHA-1 hashing. Instance this we think it is not thread safe
*
* @param bytes
* byte to hash
* @return hashed
*/
protected byte[] sha1(byte[] bytes) {
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
return md.digest(bytes);
} catch (NoSuchAlgorithmException e) {
throw new InternalError("SHA-1 not supported on this platform");
}
}
/**
* Base 64 encoding
*
* @param bytes
* Bytes to encode
* @return encoded string
*/
protected String base64Encode(byte[] bytes) {
ChannelBuffer hashed = ChannelBuffers.wrappedBuffer(bytes);
return Base64.encode(hashed).toString(CharsetUtil.UTF_8);
}
public abstract ChannelFuture close(Channel channel, CloseWebSocketFrame frame);
/**
* Selects the first matching supported sub protocol
*
* @param requestedSubProtocol
* @param requestedSubprotocols
* CSV of protocols to be supported. e.g. "chat, superchat"
* @return First matching supported sub protocol. Null if not found.
*/
protected String selectSubProtocol(String requestedSubProtocol) {
if (requestedSubProtocol == null || this.subProtocolsArray == null) {
protected String selectSubprotocol(String requestedSubprotocols) {
if (requestedSubprotocols == null || subprotocols.length == 0) {
return null;
}
String[] requesteSubProtocolsArray = requestedSubProtocol.split(",");
for (int i = 0; i < requesteSubProtocolsArray.length; i++) {
String requesteSubProtocol = requesteSubProtocolsArray[i].trim();
String[] requesteSubprotocolArray = requestedSubprotocols.split(",");
for (String p: requesteSubprotocolArray) {
String requestedSubprotocol = p.trim();
for (String supportedSubProtocol : this.subProtocolsArray) {
if (requesteSubProtocol.equals(supportedSubProtocol)) {
return requesteSubProtocol;
for (String supportedSubprotocol: subprotocols) {
if (requestedSubprotocol.equals(supportedSubprotocol)) {
return requestedSubprotocol;
}
}
}

View File

@ -15,34 +15,24 @@
*/
package io.netty.handler.codec.http.websocketx;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaders.Names.ORIGIN;
import static io.netty.handler.codec.http.HttpHeaders.Names.SEC_WEBSOCKET_KEY1;
import static io.netty.handler.codec.http.HttpHeaders.Names.SEC_WEBSOCKET_KEY2;
import static io.netty.handler.codec.http.HttpHeaders.Names.SEC_WEBSOCKET_LOCATION;
import static io.netty.handler.codec.http.HttpHeaders.Names.SEC_WEBSOCKET_ORIGIN;
import static io.netty.handler.codec.http.HttpHeaders.Names.SEC_WEBSOCKET_PROTOCOL;
import static io.netty.handler.codec.http.HttpHeaders.Names.WEBSOCKET_LOCATION;
import static io.netty.handler.codec.http.HttpHeaders.Names.WEBSOCKET_ORIGIN;
import static io.netty.handler.codec.http.HttpHeaders.Names.WEBSOCKET_PROTOCOL;
import static io.netty.handler.codec.http.HttpHeaders.Values.WEBSOCKET;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import java.security.NoSuchAlgorithmException;
import static io.netty.handler.codec.http.HttpHeaders.Names.*;
import static io.netty.handler.codec.http.HttpHeaders.Values.*;
import static io.netty.handler.codec.http.HttpVersion.*;
import io.netty.buffer.ChannelBuffer;
import io.netty.buffer.ChannelBuffers;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.HttpChunkAggregator;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.HttpChunkAggregator;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
@ -66,11 +56,11 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
* @param webSocketURL
* URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be
* sent to this URL.
* @param subProtocols
* @param subprotocols
* CSV of supported protocols
*/
public WebSocketServerHandshaker00(String webSocketURL, String subProtocols) {
super(webSocketURL, subProtocols);
public WebSocketServerHandshaker00(String webSocketURL, String subprotocols) {
super(WebSocketVersion.V00, webSocketURL, subprotocols);
}
/**
@ -117,20 +107,18 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
* Channel
* @param req
* HTTP request
* @throws NoSuchAlgorithmException
*/
@Override
public void performOpeningHandshake(Channel channel, HttpRequest req) {
public ChannelFuture handshake(Channel channel, HttpRequest req) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Channel %s WS Version 00 server handshake", channel.getId()));
}
this.setVersion(WebSocketVersion.V00);
// Serve the WebSocket handshake request.
if (!Values.UPGRADE.equalsIgnoreCase(req.getHeader(CONNECTION))
|| !WEBSOCKET.equalsIgnoreCase(req.getHeader(Names.UPGRADE))) {
return;
throw new WebSocketHandshakeException("not a WebSocket handshake request: missing upgrade");
}
// Hixie 75 does not contain these headers while Hixie 76 does
@ -146,10 +134,10 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
if (isHixie76) {
// New handshake method with a challenge:
res.addHeader(SEC_WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
res.addHeader(SEC_WEBSOCKET_LOCATION, this.getWebSocketURL());
res.addHeader(SEC_WEBSOCKET_LOCATION, getWebSocketUrl());
String protocol = req.getHeader(SEC_WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(SEC_WEBSOCKET_PROTOCOL, selectSubProtocol(protocol));
res.addHeader(SEC_WEBSOCKET_PROTOCOL, selectSubprotocol(protocol));
}
// Calculate the answer of the challenge.
@ -162,15 +150,15 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
input.writeInt(a);
input.writeInt(b);
input.writeLong(c);
ChannelBuffer output = ChannelBuffers.wrappedBuffer(this.md5(input.array()));
ChannelBuffer output = ChannelBuffers.wrappedBuffer(WebSocketUtil.md5(input.array()));
res.setContent(output);
} else {
// Old Hixie 75 handshake method with no challenge:
res.addHeader(WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
res.addHeader(WEBSOCKET_LOCATION, this.getWebSocketURL());
res.addHeader(WEBSOCKET_LOCATION, getWebSocketUrl());
String protocol = req.getHeader(WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(WEBSOCKET_PROTOCOL, selectSubProtocol(protocol));
res.addHeader(WEBSOCKET_PROTOCOL, selectSubprotocol(protocol));
}
}
@ -179,9 +167,11 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
p.remove(HttpChunkAggregator.class);
p.replace(HttpRequestDecoder.class, "wsdecoder", new WebSocket00FrameDecoder());
channel.write(res);
ChannelFuture future = channel.write(res);
p.replace(HttpResponseEncoder.class, "wsencoder", new WebSocket00FrameEncoder());
return future;
}
/**
@ -193,7 +183,7 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
* Web Socket frame that was received
*/
@Override
public void performClosingHandshake(Channel channel, CloseWebSocketFrame frame) {
channel.write(frame);
public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) {
return channel.write(frame);
}
}

View File

@ -15,23 +15,21 @@
*/
package io.netty.handler.codec.http.websocketx;
import static io.netty.handler.codec.http.HttpHeaders.Values.WEBSOCKET;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import java.security.NoSuchAlgorithmException;
import static io.netty.handler.codec.http.HttpHeaders.Values.*;
import static io.netty.handler.codec.http.HttpVersion.*;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.HttpChunkAggregator;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.HttpChunkAggregator;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
import io.netty.util.CharsetUtil;
@ -49,7 +47,7 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
public static final String WEBSOCKET_08_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private boolean allowExtensions;
private final boolean allowExtensions;
/**
* Constructor specifying the destination web socket location
@ -57,13 +55,13 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
* @param webSocketURL
* URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be
* sent to this URL.
* @param subProtocols
* @param subprotocols
* CSV of supported protocols
* @param allowExtensions
* Allow extensions to be used in the reserved bits of the web socket frame
*/
public WebSocketServerHandshaker08(String webSocketURL, String subProtocols, boolean allowExtensions) {
super(webSocketURL, subProtocols);
public WebSocketServerHandshaker08(String webSocketURL, String subprotocols, boolean allowExtensions) {
super(WebSocketVersion.V08, webSocketURL, subprotocols);
this.allowExtensions = allowExtensions;
}
@ -105,48 +103,46 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
* Channel
* @param req
* HTTP request
* @throws NoSuchAlgorithmException
*/
@Override
public void performOpeningHandshake(Channel channel, HttpRequest req) {
public ChannelFuture handshake(Channel channel, HttpRequest req) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Channel %s WS Version 8 server handshake", channel.getId()));
}
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, new HttpResponseStatus(101, "Switching Protocols"));
this.setVersion(WebSocketVersion.V08);
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS);
String key = req.getHeader(Names.SEC_WEBSOCKET_KEY);
if (key == null) {
res.setStatus(HttpResponseStatus.BAD_REQUEST);
return;
throw new WebSocketHandshakeException("not a WebSocket request: missing key");
}
String acceptSeed = key + WEBSOCKET_08_ACCEPT_GUID;
byte[] sha1 = sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII));
String accept = base64Encode(sha1);
byte[] sha1 = WebSocketUtil.sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII));
String accept = WebSocketUtil.base64(sha1);
if (logger.isDebugEnabled()) {
logger.debug(String.format("WS Version 8 Server Handshake key: %s. Response: %s.", key, accept));
}
res.setStatus(new HttpResponseStatus(101, "Switching Protocols"));
res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS);
res.addHeader(Names.UPGRADE, WEBSOCKET.toLowerCase());
res.addHeader(Names.CONNECTION, Names.UPGRADE);
res.addHeader(Names.SEC_WEBSOCKET_ACCEPT, accept);
String protocol = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, this.selectSubProtocol(protocol));
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, selectSubprotocol(protocol));
}
channel.write(res);
ChannelFuture future = channel.write(res);
// Upgrade the connection and send the handshake response.
ChannelPipeline p = channel.getPipeline();
p.remove(HttpChunkAggregator.class);
p.replace(HttpRequestDecoder.class, "wsdecoder", new WebSocket08FrameDecoder(true, this.allowExtensions));
p.replace(HttpRequestDecoder.class, "wsdecoder", new WebSocket08FrameDecoder(true, allowExtensions));
p.replace(HttpResponseEncoder.class, "wsencoder", new WebSocket08FrameEncoder(false));
return future;
}
/**
@ -158,9 +154,10 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
* Web Socket frame that was received
*/
@Override
public void performClosingHandshake(Channel channel, CloseWebSocketFrame frame) {
public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) {
ChannelFuture f = channel.write(frame);
f.addListener(ChannelFutureListener.CLOSE);
return f;
}
}

View File

@ -18,8 +18,6 @@ package io.netty.handler.codec.http.websocketx;
import static io.netty.handler.codec.http.HttpHeaders.Values.WEBSOCKET;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import java.security.NoSuchAlgorithmException;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
@ -50,7 +48,7 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
public static final String WEBSOCKET_13_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private boolean allowExtensions;
private final boolean allowExtensions;
/**
* Constructor specifying the destination web socket location
@ -58,13 +56,13 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
* @param webSocketURL
* URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be
* sent to this URL.
* @param subProtocols
* @param subprotocols
* CSV of supported protocols
* @param allowExtensions
* Allow extensions to be used in the reserved bits of the web socket frame
*/
public WebSocketServerHandshaker13(String webSocketURL, String subProtocols, boolean allowExtensions) {
super(webSocketURL, subProtocols);
public WebSocketServerHandshaker13(String webSocketURL, String subprotocols, boolean allowExtensions) {
super(WebSocketVersion.V13, webSocketURL, subprotocols);
this.allowExtensions = allowExtensions;
}
@ -106,48 +104,46 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
* Channel
* @param req
* HTTP request
* @throws NoSuchAlgorithmException
*/
@Override
public void performOpeningHandshake(Channel channel, HttpRequest req) {
public ChannelFuture handshake(Channel channel, HttpRequest req) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Channel %s WS Version 13 server handshake", channel.getId()));
}
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, new HttpResponseStatus(101, "Switching Protocols"));
this.setVersion(WebSocketVersion.V13);
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS);
String key = req.getHeader(Names.SEC_WEBSOCKET_KEY);
if (key == null) {
res.setStatus(HttpResponseStatus.BAD_REQUEST);
return;
throw new WebSocketHandshakeException("not a WebSocket request: missing key");
}
String acceptSeed = key + WEBSOCKET_13_ACCEPT_GUID;
byte[] sha1 = sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII));
String accept = base64Encode(sha1);
byte[] sha1 = WebSocketUtil.sha1(acceptSeed.getBytes(CharsetUtil.US_ASCII));
String accept = WebSocketUtil.base64(sha1);
if (logger.isDebugEnabled()) {
logger.debug(String.format("WS Version 13 Server Handshake key: %s. Response: %s.", key, accept));
}
res.setStatus(new HttpResponseStatus(101, "Switching Protocols"));
res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS);
res.addHeader(Names.UPGRADE, WEBSOCKET.toLowerCase());
res.addHeader(Names.CONNECTION, Names.UPGRADE);
res.addHeader(Names.SEC_WEBSOCKET_ACCEPT, accept);
String protocol = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, this.selectSubProtocol(protocol));
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, selectSubprotocol(protocol));
}
channel.write(res);
ChannelFuture future = channel.write(res);
// Upgrade the connection and send the handshake response.
ChannelPipeline p = channel.getPipeline();
p.remove(HttpChunkAggregator.class);
p.replace(HttpRequestDecoder.class, "wsdecoder", new WebSocket13FrameDecoder(true, this.allowExtensions));
p.replace(HttpRequestDecoder.class, "wsdecoder", new WebSocket13FrameDecoder(true, allowExtensions));
p.replace(HttpResponseEncoder.class, "wsencoder", new WebSocket13FrameEncoder(false));
return future;
}
/**
@ -159,9 +155,10 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
* Web Socket frame that was received
*/
@Override
public void performClosingHandshake(Channel channel, CloseWebSocketFrame frame) {
public ChannelFuture close(Channel channel, CloseWebSocketFrame frame) {
ChannelFuture f = channel.write(frame);
f.addListener(ChannelFutureListener.CLOSE);
return f;
}
}

View File

@ -30,9 +30,9 @@ public class WebSocketServerHandshakerFactory {
private final String webSocketURL;
private final String subProtocols;
private final String subprotocols;
private boolean allowExtensions;
private final boolean allowExtensions;
/**
* Constructor specifying the destination web socket location
@ -40,14 +40,14 @@ public class WebSocketServerHandshakerFactory {
* @param webSocketURL
* URL for web socket communications. e.g "ws://myhost.com/mypath". Subsequent web socket frames will be
* sent to this URL.
* @param subProtocols
* @param subprotocols
* CSV of supported protocols. Null if sub protocols not supported.
* @param allowExtensions
* Allow extensions to be used in the reserved bits of the web socket frame
*/
public WebSocketServerHandshakerFactory(String webSocketURL, String subProtocols, boolean allowExtensions) {
public WebSocketServerHandshakerFactory(String webSocketURL, String subprotocols, boolean allowExtensions) {
this.webSocketURL = webSocketURL;
this.subProtocols = subProtocols;
this.subprotocols = subprotocols;
this.allowExtensions = allowExtensions;
}
@ -63,16 +63,16 @@ public class WebSocketServerHandshakerFactory {
if (version != null) {
if (version.equals(WebSocketVersion.V13.toHttpHeaderValue())) {
// Version 13 of the wire protocol - RFC 6455 (version 17 of the draft hybi specification).
return new WebSocketServerHandshaker13(webSocketURL, subProtocols, this.allowExtensions);
return new WebSocketServerHandshaker13(webSocketURL, subprotocols, allowExtensions);
} else if (version.equals(WebSocketVersion.V08.toHttpHeaderValue())) {
// Version 8 of the wire protocol - version 10 of the draft hybi specification.
return new WebSocketServerHandshaker08(webSocketURL, subProtocols, this.allowExtensions);
return new WebSocketServerHandshaker08(webSocketURL, subprotocols, allowExtensions);
} else {
return null;
}
} else {
// Assume version 00 where version header was not specified
return new WebSocketServerHandshaker00(webSocketURL, subProtocols);
return new WebSocketServerHandshaker00(webSocketURL, subprotocols);
}
}
@ -83,8 +83,9 @@ public class WebSocketServerHandshakerFactory {
* Channel
*/
public void sendUnsupportedWebSocketVersionResponse(Channel channel) {
HttpResponse res = new DefaultHttpResponse(HttpVersion.HTTP_1_1, new HttpResponseStatus(101,
"Switching Protocols"));
HttpResponse res = new DefaultHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.SWITCHING_PROTOCOLS);
res.setStatus(HttpResponseStatus.UPGRADE_REQUIRED);
res.setHeader(Names.SEC_WEBSOCKET_VERSION, WebSocketVersion.V13.toHttpHeaderValue());
channel.write(res);

View File

@ -0,0 +1,109 @@
/*
* Copyright 2011 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.http.websocketx;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import io.netty.buffer.ChannelBuffer;
import io.netty.buffer.ChannelBuffers;
import io.netty.handler.codec.base64.Base64;
import io.netty.util.CharsetUtil;
/**
* TODO Document me.
*/
final class WebSocketUtil {
/**
* Performs an MD5 hash
*
* @param bytes
* Data to hash
* @return Hashed data
*/
static byte[] md5(byte[] bytes) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
return md.digest(bytes);
} catch (NoSuchAlgorithmException e) {
throw new InternalError("MD5 not supported on this platform");
}
}
/**
* Performs an SHA-1 hash
*
* @param bytes
* Data to hash
* @return Hashed data
*/
static byte[] sha1(byte[] bytes) {
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
return md.digest(bytes);
} catch (NoSuchAlgorithmException e) {
throw new InternalError("SHA-1 not supported on this platform");
}
}
/**
* Base 64 encoding
*
* @param bytes
* Bytes to encode
* @return encoded string
*/
static String base64(byte[] bytes) {
ChannelBuffer hashed = ChannelBuffers.wrappedBuffer(bytes);
return Base64.encode(hashed).toString(CharsetUtil.UTF_8);
}
/**
* Creates some random bytes
*
* @param size
* Number of random bytes to create
* @return random bytes
*/
static byte[] randomBytes(int size) {
byte[] bytes = new byte[size];
for (int i = 0; i < size; i++) {
bytes[i] = (byte) randomNumber(0, 255);
}
return bytes;
}
/**
* Generates a random number
*
* @param min
* Minimum value
* @param max
* Maximum value
* @return Random number
*/
static int randomNumber(int min, int max) {
return (int) (Math.random() * max + min);
}
private WebSocketUtil() {
// Unused
}
}

View File

@ -57,6 +57,6 @@ public enum WebSocketVersion {
} else if (this == V13) {
return "13";
}
throw new IllegalArgumentException(this.toString() + " does not have a HttpHeaderValue.");
throw new IllegalStateException("Unknown web socket version: " + this);
}
}

View File

@ -76,7 +76,7 @@ public class WebSocketServerHandshaker00Test {
req.setContent(buffer);
WebSocketServerHandshaker00 handsaker = new WebSocketServerHandshaker00("ws://example.com/chat", "chat");
handsaker.performOpeningHandshake(channelMock, req);
handsaker.handshake(channelMock, req);
Assert.assertEquals("ws://example.com/chat", res.getValue().getHeader(Names.SEC_WEBSOCKET_LOCATION));
Assert.assertEquals("chat", res.getValue().getHeader(Names.SEC_WEBSOCKET_PROTOCOL));

View File

@ -69,7 +69,7 @@ public class WebSocketServerHandshaker08Test {
req.setHeader(Names.SEC_WEBSOCKET_VERSION, "8");
WebSocketServerHandshaker08 handsaker = new WebSocketServerHandshaker08("ws://example.com/chat", "chat", false);
handsaker.performOpeningHandshake(channelMock, req);
handsaker.handshake(channelMock, req);
Assert.assertEquals("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", res.getValue().getHeader(Names.SEC_WEBSOCKET_ACCEPT));
Assert.assertEquals("chat", res.getValue().getHeader(Names.SEC_WEBSOCKET_PROTOCOL));

View File

@ -68,7 +68,7 @@ public class WebSocketServerHandshaker13Test {
req.setHeader(Names.SEC_WEBSOCKET_PROTOCOL, "chat, superchat");
req.setHeader(Names.SEC_WEBSOCKET_VERSION, "13");
WebSocketServerHandshaker13 handsaker = new WebSocketServerHandshaker13("ws://example.com/chat", "chat", false);
handsaker.performOpeningHandshake(channelMock, req);
handsaker.handshake(channelMock, req);
Assert.assertEquals("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", res.getValue().getHeader(Names.SEC_WEBSOCKET_ACCEPT));
Assert.assertEquals("chat", res.getValue().getHeader(Names.SEC_WEBSOCKET_PROTOCOL));

View File

@ -76,7 +76,7 @@ public class AutobahnServerHandler extends SimpleChannelUpstreamHandler {
if (this.handshaker == null) {
wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel());
} else {
this.handshaker.performOpeningHandshake(ctx.getChannel(), req);
this.handshaker.handshake(ctx.getChannel(), req);
}
}
@ -85,7 +85,7 @@ public class AutobahnServerHandler extends SimpleChannelUpstreamHandler {
.format("Channel %s received %s", ctx.getChannel().getId(), frame.getClass().getSimpleName()));
if (frame instanceof CloseWebSocketFrame) {
this.handshaker.performClosingHandshake(ctx.getChannel(), (CloseWebSocketFrame) frame);
this.handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame);
} else if (frame instanceof PingWebSocketFrame) {
ctx.getChannel().write(
new PongWebSocketFrame(frame.isFinalFragment(), frame.getRsv(), frame.getBinaryData()));

View File

@ -97,21 +97,17 @@ public class WebSocketClient {
Channel ch = future.getChannel();
handshaker.performOpeningHandshake(ch);
Thread.sleep(1000);
handshaker.handshake(ch).awaitUninterruptibly();
// Send 10 messages and wait for responses
System.out.println("WebSocket Client sending message");
for (int i = 0; i < 10; i++) {
ch.write(new TextWebSocketFrame("Message #" + i));
}
Thread.sleep(1000);
// Ping
System.out.println("WebSocket Client sending ping");
ch.write(new PingWebSocketFrame(ChannelBuffers.copiedBuffer(new byte[] { 1, 2, 3, 4, 5, 6 })));
Thread.sleep(1000);
ch.write(new PingWebSocketFrame(ChannelBuffers.copiedBuffer(new byte[]{1, 2, 3, 4, 5, 6})));
// Close
System.out.println("WebSocket Client sending close");

View File

@ -52,8 +52,8 @@ public class WebSocketClientHandler extends SimpleChannelUpstreamHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
Channel ch = ctx.getChannel();
if (!handshaker.isOpeningHandshakeCompleted()) {
handshaker.performClosingHandshake(ch, (HttpResponse) e.getMessage());
if (!handshaker.isHandshakeComplete()) {
handshaker.finishHandshake(ch, (HttpResponse) e.getMessage());
System.out.println("WebSocket Client connected!");
return;
}

View File

@ -96,7 +96,7 @@ public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
if (this.handshaker == null) {
wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel());
} else {
this.handshaker.performOpeningHandshake(ctx.getChannel(), req);
this.handshaker.handshake(ctx.getChannel(), req);
}
}
@ -104,7 +104,7 @@ public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
// Check for closing frame
if (frame instanceof CloseWebSocketFrame) {
this.handshaker.performClosingHandshake(ctx.getChannel(), (CloseWebSocketFrame) frame);
this.handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame);
return;
} else if (frame instanceof PingWebSocketFrame) {
ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData()));

View File

@ -96,7 +96,7 @@ public class WebSocketSslServerHandler extends SimpleChannelUpstreamHandler {
if (this.handshaker == null) {
wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel());
} else {
this.handshaker.performOpeningHandshake(ctx.getChannel(), req);
this.handshaker.handshake(ctx.getChannel(), req);
}
}
@ -104,7 +104,7 @@ public class WebSocketSslServerHandler extends SimpleChannelUpstreamHandler {
// Check for closing frame
if (frame instanceof CloseWebSocketFrame) {
this.handshaker.performClosingHandshake(ctx.getChannel(), (CloseWebSocketFrame) frame);
this.handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame);
return;
} else if (frame instanceof PingWebSocketFrame) {
ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData()));