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.HttpResponseStatus.*;
|
||||||
import static org.jboss.netty.handler.codec.http.HttpVersion.*;
|
import static org.jboss.netty.handler.codec.http.HttpVersion.*;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
import org.jboss.netty.buffer.ChannelBuffer;
|
import org.jboss.netty.buffer.ChannelBuffer;
|
||||||
import org.jboss.netty.buffer.ChannelBuffers;
|
import org.jboss.netty.buffer.ChannelBuffers;
|
||||||
import org.jboss.netty.channel.ChannelFuture;
|
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.
|
// Allow only GET methods.
|
||||||
if (req.getMethod() != GET) {
|
if (req.getMethod() != GET) {
|
||||||
sendHttpResponse(
|
sendHttpResponse(
|
||||||
@ -98,12 +100,41 @@ public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
|
|||||||
new HttpResponseStatus(101, "Web Socket Protocol Handshake"));
|
new HttpResponseStatus(101, "Web Socket Protocol Handshake"));
|
||||||
res.addHeader(Names.UPGRADE, WEBSOCKET);
|
res.addHeader(Names.UPGRADE, WEBSOCKET);
|
||||||
res.addHeader(CONNECTION, Values.UPGRADE);
|
res.addHeader(CONNECTION, Values.UPGRADE);
|
||||||
|
|
||||||
|
// 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_ORIGIN, req.getHeader(ORIGIN));
|
||||||
res.addHeader(WEBSOCKET_LOCATION, getWebSocketLocation(req));
|
res.addHeader(WEBSOCKET_LOCATION, getWebSocketLocation(req));
|
||||||
String protocol = req.getHeader(WEBSOCKET_PROTOCOL);
|
String protocol = req.getHeader(WEBSOCKET_PROTOCOL);
|
||||||
if (protocol != null) {
|
if (protocol != null) {
|
||||||
res.addHeader(WEBSOCKET_PROTOCOL, protocol);
|
res.addHeader(WEBSOCKET_PROTOCOL, protocol);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Upgrade the connection and send the handshake response.
|
// Upgrade the connection and send the handshake response.
|
||||||
ChannelPipeline p = ctx.getChannel().getPipeline();
|
ChannelPipeline p = ctx.getChannel().getPipeline();
|
||||||
|
@ -213,6 +213,26 @@ public class HttpHeaders {
|
|||||||
* {@code "Retry-After"}
|
* {@code "Retry-After"}
|
||||||
*/
|
*/
|
||||||
public static final String RETRY_AFTER = "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"}
|
* {@code "Server"}
|
||||||
*/
|
*/
|
||||||
@ -604,6 +624,24 @@ public class HttpHeaders {
|
|||||||
if (contentLength != null) {
|
if (contentLength != null) {
|
||||||
return Long.parseLong(contentLength);
|
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;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user