Merge pull request #117 from veebs/WSTidyUp

WebSocket tidy up
This commit is contained in:
Vibul Imtarnasan 2011-12-11 03:07:47 -08:00
commit 7397bba454
12 changed files with 42 additions and 371 deletions

View File

@ -1,46 +0,0 @@
/*
* 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.example.http.websocket;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.socket.nio.NioServerSocketChannelFactory;
/**
* An HTTP server which serves Web Socket requests at:
*
* http://localhost:8080/websocket
*
* Open your browser at http://localhost:8080/, then the demo page will be
* loaded and a Web Socket connection will be made automatically.
*/
public class WebSocketServer {
public static void main(String[] args) {
// Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
// Set up the event pipeline factory.
bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory());
// Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(8080));
}
}

View File

@ -1,182 +0,0 @@
/*
* 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.example.http.websocket;
import static io.netty.handler.codec.http.HttpHeaders.*;
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.HttpMethod.*;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpVersion.*;
import java.security.MessageDigest;
import io.netty.buffer.ChannelBuffer;
import io.netty.buffer.ChannelBuffers;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ExceptionEvent;
import io.netty.channel.MessageEvent;
import io.netty.channel.SimpleChannelUpstreamHandler;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
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.handler.codec.http.websocket.DefaultWebSocketFrame;
import io.netty.handler.codec.http.websocket.WebSocketFrame;
import io.netty.handler.codec.http.websocket.WebSocketFrameDecoder;
import io.netty.handler.codec.http.websocket.WebSocketFrameEncoder;
import io.netty.util.CharsetUtil;
/**
*/
public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
private static final String WEBSOCKET_PATH = "/websocket";
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
Object msg = e.getMessage();
if (msg instanceof HttpRequest) {
handleHttpRequest(ctx, (HttpRequest) msg);
} else if (msg instanceof WebSocketFrame) {
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
}
}
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
// Allow only GET methods.
if (req.getMethod() != GET) {
sendHttpResponse(
ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
return;
}
// Send the demo page.
if (req.getUri().equals("/")) {
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK);
ChannelBuffer content =
WebSocketServerIndexPage.getContent(getWebSocketLocation(req));
res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8");
setContentLength(res, content.readableBytes());
res.setContent(content);
sendHttpResponse(ctx, req, res);
return;
}
// Serve the WebSocket handshake request.
if (req.getUri().equals(WEBSOCKET_PATH) &&
Values.UPGRADE.equalsIgnoreCase(req.getHeader(CONNECTION)) &&
WEBSOCKET.equalsIgnoreCase(req.getHeader(Names.UPGRADE))) {
// Create the WebSocket handshake response.
HttpResponse res = new DefaultHttpResponse(
HTTP_1_1,
new HttpResponseStatus(101, "Web Socket Protocol Handshake"));
res.addHeader(Names.UPGRADE, WEBSOCKET);
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()));
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.
ChannelPipeline p = ctx.getChannel().getPipeline();
p.remove("aggregator");
p.replace("decoder", "wsdecoder", new WebSocketFrameDecoder());
ctx.getChannel().write(res);
p.replace("encoder", "wsencoder", new WebSocketFrameEncoder());
return;
}
// Send an error page otherwise.
sendHttpResponse(
ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
}
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
// Send the uppercased string back.
ctx.getChannel().write(
new DefaultWebSocketFrame(frame.getTextData().toUpperCase()));
}
private void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
// Generate an error page if response status code is not OK (200).
if (res.getStatus().getCode() != 200) {
res.setContent(
ChannelBuffers.copiedBuffer(
res.getStatus().toString(), CharsetUtil.UTF_8));
setContentLength(res, res.getContent().readableBytes());
}
// Send the response and close the connection if necessary.
ChannelFuture f = ctx.getChannel().write(res);
if (!isKeepAlive(req) || res.getStatus().getCode() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
e.getCause().printStackTrace();
e.getChannel().close();
}
private String getWebSocketLocation(HttpRequest req) {
return "ws://" + req.getHeader(HttpHeaders.Names.HOST) + WEBSOCKET_PATH;
}
}

View File

@ -1,62 +0,0 @@
/*
* 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.example.http.websocket;
import io.netty.buffer.ChannelBuffer;
import io.netty.buffer.ChannelBuffers;
import io.netty.util.CharsetUtil;
/**
* Generates the demo HTML page which is served at http://localhost:8080/
*/
public class WebSocketServerIndexPage {
private static final String NEWLINE = "\r\n";
public static ChannelBuffer getContent(String webSocketLocation) {
return ChannelBuffers.copiedBuffer(
"<html><head><title>Web Socket Test</title></head>" + NEWLINE +
"<body>" + NEWLINE +
"<script type=\"text/javascript\">" + NEWLINE +
"var socket;" + NEWLINE +
"if (window.WebSocket) {" + NEWLINE +
" socket = new WebSocket(\"" + webSocketLocation + "\");" + NEWLINE +
" socket.onmessage = function(event) { alert(event.data); };" + NEWLINE +
" socket.onopen = function(event) { alert(\"Web Socket opened!\"); };" + NEWLINE +
" socket.onclose = function(event) { alert(\"Web Socket closed.\"); };" + NEWLINE +
"} else {" + NEWLINE +
" alert(\"Your browser does not support Web Socket.\");" + NEWLINE +
"}" + NEWLINE +
NEWLINE +
"function send(message) {" + NEWLINE +
" if (!window.WebSocket) { return; }" + NEWLINE +
" if (socket.readyState == WebSocket.OPEN) {" + NEWLINE +
" socket.send(message);" + NEWLINE +
" } else {" + NEWLINE +
" alert(\"The socket is not open.\");" + NEWLINE +
" }" + NEWLINE +
"}" + NEWLINE +
"</script>" + NEWLINE +
"<form onsubmit=\"return false;\">" + NEWLINE +
"<input type=\"text\" name=\"message\" value=\"Hello, World!\"/>" +
"<input type=\"button\" value=\"Send Web Socket Data\" onclick=\"send(this.form.message.value)\" />" + NEWLINE +
"</form>" + NEWLINE +
"</body>" + NEWLINE +
"</html>" + NEWLINE,
CharsetUtil.US_ASCII);
}
}

View File

@ -1,39 +0,0 @@
/*
* 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.example.http.websocket;
import static io.netty.channel.Channels.*;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPipelineFactory;
import io.netty.handler.codec.http.HttpChunkAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
/**
*/
public class WebSocketServerPipelineFactory implements ChannelPipelineFactory {
@Override
public ChannelPipeline getPipeline() throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("handler", new WebSocketServerHandler());
return pipeline;
}
}

View File

@ -47,6 +47,6 @@ public class WebSocketServer {
// Bind and start to accept incoming connections. // Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(9000)); bootstrap.bind(new InetSocketAddress(9000));
System.out.println("Web Socket Server started on 9000. Open your browser and navigate to http://localhost:9000/"); System.out.println("Web Socket Server started on localhost:9000.");
} }
} }

View File

@ -55,8 +55,9 @@ public class App {
MyCallbackHandler callbackHandler = new MyCallbackHandler(); MyCallbackHandler callbackHandler = new MyCallbackHandler();
WebSocketClientFactory factory = new WebSocketClientFactory(); WebSocketClientFactory factory = new WebSocketClientFactory();
// Connect with spec version 17 (try changing it to V10 or V00 and it will // Connect with spec version 17. You can change it to V10 or V00.
// still work ... fingers crossed ;-) // If you change it to V00, ping is not supported and remember to change HttpResponseDecoder to
// WebSocketHttpResponseDecoder in the pipeline.
WebSocketClient client = factory.newClient(new URI("ws://localhost:8080/websocket"), WebSocketClient client = factory.newClient(new URI("ws://localhost:8080/websocket"),
WebSocketSpecificationVersion.V17, callbackHandler); WebSocketSpecificationVersion.V17, callbackHandler);
@ -72,7 +73,7 @@ public class App {
} }
Thread.sleep(1000); Thread.sleep(1000);
// Ping // Ping - only supported for V10 and up.
System.out.println("WebSocket Client sending ping"); System.out.println("WebSocket Client sending ping");
client.send(new PingWebSocketFrame(ChannelBuffers.copiedBuffer(new byte[] { 1, 2, 3, 4, 5, 6 }))); client.send(new PingWebSocketFrame(ChannelBuffers.copiedBuffer(new byte[] { 1, 2, 3, 4, 5, 6 })));
Thread.sleep(1000); Thread.sleep(1000);

View File

@ -28,6 +28,7 @@ import io.netty.channel.ChannelPipelineFactory;
import io.netty.channel.Channels; import io.netty.channel.Channels;
import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.channel.socket.nio.NioClientSocketChannelFactory;
import io.netty.handler.codec.http.HttpRequestEncoder; import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.websocketx.WebSocketSpecificationVersion; import io.netty.handler.codec.http.websocketx.WebSocketSpecificationVersion;
import java.net.URI; import java.net.URI;
@ -45,7 +46,7 @@ public class WebSocketClientFactory {
Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
/** /**
* Create a new WebSocket client * Create a new WebSocket client.
* *
* @param url * @param url
* URL to connect to. * URL to connect to.
@ -72,7 +73,11 @@ public class WebSocketClientFactory {
@Override @Override
public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline(); ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new WebSocketHttpResponseDecoder());
// If you wish to support HyBi V00, you need to use WebSocketHttpResponseDecoder instead for
// HttpResponseDecoder.
pipeline.addLast("decoder", new HttpResponseDecoder());
pipeline.addLast("encoder", new HttpRequestEncoder()); pipeline.addLast("encoder", new HttpRequestEncoder());
pipeline.addLast("ws-handler", clientHandler); pipeline.addLast("ws-handler", clientHandler);
return pipeline; return pipeline;

View File

@ -66,7 +66,7 @@ public class WebSocketClientHandler extends SimpleChannelUpstreamHandler impleme
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
channel = e.getChannel(); channel = e.getChannel();
this.handshaker = new WebSocketClientHandshakerFactory().newHandshaker(url, version, null, false); this.handshaker = new WebSocketClientHandshakerFactory().newHandshaker(url, version, null, false);
handshaker.performOpeningHandshake(ctx, channel); handshaker.performOpeningHandshake(channel);
} }
@Override @Override
@ -77,7 +77,7 @@ public class WebSocketClientHandler extends SimpleChannelUpstreamHandler impleme
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
if (!handshaker.isOpeningHandshakeCompleted()) { if (!handshaker.isOpeningHandshakeCompleted()) {
handshaker.performClosingHandshake(ctx, (HttpResponse) e.getMessage()); handshaker.performClosingHandshake(ctx.getChannel(), (HttpResponse) e.getMessage());
callback.onConnect(this); callback.onConnect(this);
return; return;
} }

View File

@ -22,7 +22,6 @@ import java.security.NoSuchAlgorithmException;
import io.netty.buffer.ChannelBuffer; import io.netty.buffer.ChannelBuffer;
import io.netty.buffer.ChannelBuffers; import io.netty.buffer.ChannelBuffers;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.base64.Base64; import io.netty.handler.codec.base64.Base64;
import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponse;
import io.netty.util.CharsetUtil; import io.netty.util.CharsetUtil;
@ -114,22 +113,20 @@ public abstract class WebSocketClientHandshaker {
/** /**
* Performs the opening handshake * Performs the opening handshake
* *
* @param ctx
* Channel context
* @param channel * @param channel
* Channel * Channel
*/ */
public abstract void performOpeningHandshake(ChannelHandlerContext ctx, Channel channel); public abstract void performOpeningHandshake(Channel channel);
/** /**
* Performs the closing handshake * Performs the closing handshake
* *
* @param ctx * @param channel
* Channel context * Channel
* @param response * @param response
* HTTP response containing the closing handshake details * HTTP response containing the closing handshake details
*/ */
public abstract void performClosingHandshake(ChannelHandlerContext ctx, HttpResponse response) throws WebSocketHandshakeException; public abstract void performClosingHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException;
/** /**
* Performs an MD5 hash * Performs an MD5 hash

View File

@ -21,13 +21,14 @@ import java.util.Arrays;
import io.netty.buffer.ChannelBuffers; import io.netty.buffer.ChannelBuffers;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names; import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values; import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.HttpVersion;
@ -81,13 +82,11 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
* ^n:ds[4U * ^n:ds[4U
* </pre> * </pre>
* *
* @param ctx
* Channel context
* @param channel * @param channel
* Channel into which we can write our request * Channel into which we can write our request
*/ */
@Override @Override
public void performOpeningHandshake(ChannelHandlerContext ctx, Channel channel) { public void performOpeningHandshake(Channel channel) {
// Make keys // Make keys
int spaces1 = createRandomNumber(1, 12); int spaces1 = createRandomNumber(1, 12);
int spaces2 = createRandomNumber(1, 12); int spaces2 = createRandomNumber(1, 12);
@ -147,7 +146,7 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
channel.write(request); channel.write(request);
ctx.getPipeline().replace("encoder", "ws-encoder", new WebSocket00FrameEncoder()); channel.getPipeline().replace(HttpRequestEncoder.class, "ws-encoder", new WebSocket00FrameEncoder());
} }
/** /**
@ -166,15 +165,15 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
* 8jKS'y:G*Co,Wxa- * 8jKS'y:G*Co,Wxa-
* </pre> * </pre>
* *
* @param ctx * @param channel
* Channel context * Channel
* @param response * @param response
* HTTP response returned from the server for the request sent by * HTTP response returned from the server for the request sent by
* beginOpeningHandshake00(). * beginOpeningHandshake00().
* @throws WebSocketHandshakeException * @throws WebSocketHandshakeException
*/ */
@Override @Override
public void performClosingHandshake(ChannelHandlerContext ctx, HttpResponse response) throws WebSocketHandshakeException { public void performClosingHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException {
final HttpResponseStatus status = new HttpResponseStatus(101, "WebSocket Protocol Handshake"); final HttpResponseStatus status = new HttpResponseStatus(101, "WebSocket Protocol Handshake");
if (!response.getStatus().equals(status)) { if (!response.getStatus().equals(status)) {
@ -199,7 +198,7 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
String protocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL); String protocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
this.setSubProtocolResponse(protocol); this.setSubProtocolResponse(protocol);
ctx.getPipeline().replace("decoder", "ws-decoder", new WebSocket00FrameDecoder()); channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder", new WebSocket00FrameDecoder());
this.setOpenningHandshakeCompleted(true); this.setOpenningHandshakeCompleted(true);
} }

View File

@ -18,13 +18,14 @@ package io.netty.handler.codec.http.websocketx;
import java.net.URI; import java.net.URI;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names; import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values; import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.HttpVersion;
import io.netty.logging.InternalLogger; import io.netty.logging.InternalLogger;
@ -90,13 +91,11 @@ public class WebSocketClientHandshaker10 extends WebSocketClientHandshaker {
* Sec-WebSocket-Version: 8 * Sec-WebSocket-Version: 8
* </pre> * </pre>
* *
* @param ctx
* Channel context
* @param channel * @param channel
* Channel into which we can write our request * Channel into which we can write our request
*/ */
@Override @Override
public void performOpeningHandshake(ChannelHandlerContext ctx, Channel channel) { public void performOpeningHandshake(Channel channel) {
// Get path // Get path
URI wsURL = this.getWebSocketURL(); URI wsURL = this.getWebSocketURL();
String path = wsURL.getPath(); String path = wsURL.getPath();
@ -130,7 +129,7 @@ public class WebSocketClientHandshaker10 extends WebSocketClientHandshaker {
channel.write(request); channel.write(request);
ctx.getPipeline().replace("encoder", "ws-encoder", new WebSocket08FrameEncoder(true)); channel.getPipeline().replace(HttpRequestEncoder.class, "ws-encoder", new WebSocket08FrameEncoder(true));
} }
/** /**
@ -146,15 +145,15 @@ public class WebSocketClientHandshaker10 extends WebSocketClientHandshaker {
* Sec-WebSocket-Protocol: chat * Sec-WebSocket-Protocol: chat
* </pre> * </pre>
* *
* @param ctx * @param channel
* Channel context * Channel
* @param response * @param response
* HTTP response returned from the server for the request sent by * HTTP response returned from the server for the request sent by
* beginOpeningHandshake00(). * beginOpeningHandshake00().
* @throws WebSocketHandshakeException * @throws WebSocketHandshakeException
*/ */
@Override @Override
public void performClosingHandshake(ChannelHandlerContext ctx, HttpResponse response) throws WebSocketHandshakeException { public void performClosingHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException {
final HttpResponseStatus status = new HttpResponseStatus(101, "Switching Protocols"); final HttpResponseStatus status = new HttpResponseStatus(101, "Switching Protocols");
if (!response.getStatus().equals(status)) { if (!response.getStatus().equals(status)) {
@ -176,7 +175,7 @@ public class WebSocketClientHandshaker10 extends WebSocketClientHandshaker {
throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, this.expectedChallengeResponseString)); throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, this.expectedChallengeResponseString));
} }
ctx.getPipeline().replace("decoder", "ws-decoder", new WebSocket08FrameDecoder(false, this.allowExtensions)); channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder", new WebSocket08FrameDecoder(false, this.allowExtensions));
this.setOpenningHandshakeCompleted(true); this.setOpenningHandshakeCompleted(true);
} }

View File

@ -18,13 +18,14 @@ package io.netty.handler.codec.http.websocketx;
import java.net.URI; import java.net.URI;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names; import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values; import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.HttpVersion;
import io.netty.logging.InternalLogger; import io.netty.logging.InternalLogger;
@ -90,13 +91,11 @@ public class WebSocketClientHandshaker17 extends WebSocketClientHandshaker {
* Sec-WebSocket-Version: 13 * Sec-WebSocket-Version: 13
* </pre> * </pre>
* *
* @param ctx
* Channel context
* @param channel * @param channel
* Channel into which we can write our request * Channel into which we can write our request
*/ */
@Override @Override
public void performOpeningHandshake(ChannelHandlerContext ctx, Channel channel) { public void performOpeningHandshake(Channel channel) {
// Get path // Get path
URI wsURL = this.getWebSocketURL(); URI wsURL = this.getWebSocketURL();
String path = wsURL.getPath(); String path = wsURL.getPath();
@ -130,7 +129,7 @@ public class WebSocketClientHandshaker17 extends WebSocketClientHandshaker {
channel.write(request); channel.write(request);
ctx.getPipeline().replace("encoder", "ws-encoder", new WebSocket13FrameEncoder(true)); channel.getPipeline().replace(HttpRequestEncoder.class, "ws-encoder", new WebSocket13FrameEncoder(true));
} }
/** /**
@ -146,15 +145,15 @@ public class WebSocketClientHandshaker17 extends WebSocketClientHandshaker {
* Sec-WebSocket-Protocol: chat * Sec-WebSocket-Protocol: chat
* </pre> * </pre>
* *
* @param ctx * @param channel
* Channel context * Channel
* @param response * @param response
* HTTP response returned from the server for the request sent by * HTTP response returned from the server for the request sent by
* beginOpeningHandshake00(). * beginOpeningHandshake00().
* @throws WebSocketHandshakeException * @throws WebSocketHandshakeException
*/ */
@Override @Override
public void performClosingHandshake(ChannelHandlerContext ctx, HttpResponse response) throws WebSocketHandshakeException { public void performClosingHandshake(Channel channel, HttpResponse response) throws WebSocketHandshakeException {
final HttpResponseStatus status = new HttpResponseStatus(101, "Switching Protocols"); final HttpResponseStatus status = new HttpResponseStatus(101, "Switching Protocols");
if (!response.getStatus().equals(status)) { if (!response.getStatus().equals(status)) {
@ -176,7 +175,7 @@ public class WebSocketClientHandshaker17 extends WebSocketClientHandshaker {
throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, this.expectedChallengeResponseString)); throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, this.expectedChallengeResponseString));
} }
ctx.getPipeline().replace("decoder", "ws-decoder", new WebSocket13FrameDecoder(false, this.allowExtensions)); channel.getPipeline().replace(HttpResponseDecoder.class, "ws-decoder", new WebSocket13FrameDecoder(false, this.allowExtensions));
this.setOpenningHandshakeCompleted(true); this.setOpenningHandshakeCompleted(true);
} }