commit
7397bba454
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user