Fixed issue: NETTY-330 HttpMessageDecoder cannot decode new handshake messages
* HttpHeaders.getContentLength() returns 10 and 18 for WebSocket handshake messages * Updated the WebSocket server example to support the new handshake method
This commit is contained in:
parent
c35c9eb1c3
commit
e0545ba583
@ -22,6 +22,8 @@ import static org.jboss.netty.handler.codec.http.HttpMethod.*;
|
||||
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
|
||||
import static org.jboss.netty.handler.codec.http.HttpVersion.*;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.buffer.ChannelBuffers;
|
||||
import org.jboss.netty.channel.ChannelFuture;
|
||||
@ -64,7 +66,7 @@ public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) {
|
||||
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
|
||||
// Allow only GET methods.
|
||||
if (req.getMethod() != GET) {
|
||||
sendHttpResponse(
|
||||
@ -98,11 +100,40 @@ public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
|
||||
new HttpResponseStatus(101, "Web Socket Protocol Handshake"));
|
||||
res.addHeader(Names.UPGRADE, WEBSOCKET);
|
||||
res.addHeader(CONNECTION, Values.UPGRADE);
|
||||
res.addHeader(WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
|
||||
res.addHeader(WEBSOCKET_LOCATION, getWebSocketLocation(req));
|
||||
String protocol = req.getHeader(WEBSOCKET_PROTOCOL);
|
||||
if (protocol != null) {
|
||||
res.addHeader(WEBSOCKET_PROTOCOL, protocol);
|
||||
|
||||
// Fill in the headers and contents depending on handshake method.
|
||||
if (req.containsHeader(SEC_WEBSOCKET_KEY1) &&
|
||||
req.containsHeader(SEC_WEBSOCKET_KEY2)) {
|
||||
// New handshake method with a challenge:
|
||||
res.addHeader(SEC_WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
|
||||
res.addHeader(SEC_WEBSOCKET_LOCATION, getWebSocketLocation(req));
|
||||
String protocol = req.getHeader(SEC_WEBSOCKET_PROTOCOL);
|
||||
if (protocol != null) {
|
||||
res.addHeader(SEC_WEBSOCKET_PROTOCOL, protocol);
|
||||
}
|
||||
|
||||
// Calculate the answer of the challenge.
|
||||
String key1 = req.getHeader(SEC_WEBSOCKET_KEY1);
|
||||
String key2 = req.getHeader(SEC_WEBSOCKET_KEY2);
|
||||
int a = (int) (Long.parseLong(key1.replaceAll("[^0-9]", "")) / key1.replaceAll("[^ ]", "").length());
|
||||
int b = (int) (Long.parseLong(key2.replaceAll("[^0-9]", "")) / key2.replaceAll("[^ ]", "").length());
|
||||
long c = req.getContent().readLong();
|
||||
ChannelBuffer input = ChannelBuffers.buffer(16);
|
||||
input.writeInt(a);
|
||||
input.writeInt(b);
|
||||
input.writeLong(c);
|
||||
ChannelBuffer output = ChannelBuffers.wrappedBuffer(
|
||||
MessageDigest.getInstance("MD5").digest(input.array()),
|
||||
new byte[] { '\r', '\n' });
|
||||
res.setContent(output);
|
||||
} else {
|
||||
// Old handshake method with no challenge:
|
||||
res.addHeader(WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
|
||||
res.addHeader(WEBSOCKET_LOCATION, getWebSocketLocation(req));
|
||||
String protocol = req.getHeader(WEBSOCKET_PROTOCOL);
|
||||
if (protocol != null) {
|
||||
res.addHeader(WEBSOCKET_PROTOCOL, protocol);
|
||||
}
|
||||
}
|
||||
|
||||
// Upgrade the connection and send the handshake response.
|
||||
|
@ -213,6 +213,26 @@ public class HttpHeaders {
|
||||
* {@code "Retry-After"}
|
||||
*/
|
||||
public static final String RETRY_AFTER = "Retry-After";
|
||||
/**
|
||||
* {@code "Sec-WebSocket-Key1"}
|
||||
*/
|
||||
public static final String SEC_WEBSOCKET_KEY1 = "Sec-WebSocket-Key1";
|
||||
/**
|
||||
* {@code "Sec-WebSocket-Key2"}
|
||||
*/
|
||||
public static final String SEC_WEBSOCKET_KEY2 = "Sec-WebSocket-Key2";
|
||||
/**
|
||||
* {@code "Sec-WebSocket-Location"}
|
||||
*/
|
||||
public static final String SEC_WEBSOCKET_LOCATION = "Sec-WebSocket-Location";
|
||||
/**
|
||||
* {@code "Sec-WebSocket-Origin"}
|
||||
*/
|
||||
public static final String SEC_WEBSOCKET_ORIGIN = "Sec-WebSocket-Origin";
|
||||
/**
|
||||
* {@code "Sec-WebSocket-Protocol"}
|
||||
*/
|
||||
public static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol";
|
||||
/**
|
||||
* {@code "Server"}
|
||||
*/
|
||||
@ -604,6 +624,24 @@ public class HttpHeaders {
|
||||
if (contentLength != null) {
|
||||
return Long.parseLong(contentLength);
|
||||
}
|
||||
|
||||
// WebSockset messages have constant content-lengths.
|
||||
if (message instanceof HttpRequest) {
|
||||
HttpRequest req = (HttpRequest) message;
|
||||
if (HttpMethod.GET.equals(req.getMethod()) &&
|
||||
req.containsHeader(Names.SEC_WEBSOCKET_KEY1) &&
|
||||
req.containsHeader(Names.SEC_WEBSOCKET_KEY2)) {
|
||||
return 10;
|
||||
}
|
||||
} else if (message instanceof HttpResponse) {
|
||||
HttpResponse res = (HttpResponse) message;
|
||||
if (res.getStatus().getCode() == 101 &&
|
||||
res.containsHeader(Names.SEC_WEBSOCKET_ORIGIN) &&
|
||||
res.containsHeader(Names.SEC_WEBSOCKET_LOCATION)) {
|
||||
return 18;
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user