1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.codec.http.websocketx;
17
18 import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1;
19
20 import org.jboss.netty.buffer.ChannelBuffers;
21 import org.jboss.netty.channel.ChannelFutureListener;
22 import org.jboss.netty.channel.ChannelHandler;
23 import org.jboss.netty.channel.ChannelHandlerContext;
24 import org.jboss.netty.channel.ChannelPipeline;
25 import org.jboss.netty.channel.ExceptionEvent;
26 import org.jboss.netty.channel.LifeCycleAwareChannelHandler;
27 import org.jboss.netty.channel.MessageEvent;
28 import org.jboss.netty.channel.SimpleChannelHandler;
29 import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
30 import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
31 import org.jboss.netty.handler.codec.http.HttpResponseStatus;
32
33
34
35
36
37 public class WebSocketServerProtocolHandler extends SimpleChannelUpstreamHandler implements
38 LifeCycleAwareChannelHandler {
39
40 private final String websocketPath;
41 private final String subprotocols;
42 private final boolean allowExtensions;
43
44 public WebSocketServerProtocolHandler(String websocketPath) {
45 this(websocketPath, null, false);
46 }
47
48 public WebSocketServerProtocolHandler(String websocketPath, String subprotocols) {
49 this(websocketPath, subprotocols, false);
50 }
51
52 public WebSocketServerProtocolHandler(String websocketPath, String subprotocols, boolean allowExtensions) {
53 this.websocketPath = websocketPath;
54 this.subprotocols = subprotocols;
55 this.allowExtensions = allowExtensions;
56 }
57
58 public void afterAdd(ChannelHandlerContext ctx) throws Exception {
59 ChannelPipeline cp = ctx.getPipeline();
60 if (cp.get(WebSocketServerProtocolHandshakeHandler.class) == null) {
61
62 ctx.getPipeline().addBefore(ctx.getName(), WebSocketServerProtocolHandshakeHandler.class.getName(),
63 new WebSocketServerProtocolHandshakeHandler(websocketPath, subprotocols, allowExtensions));
64 }
65 }
66
67 @Override
68 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
69 if (e.getMessage() instanceof WebSocketFrame) {
70 WebSocketFrame frame = (WebSocketFrame) e.getMessage();
71 if (frame instanceof CloseWebSocketFrame) {
72 WebSocketServerHandshaker handshaker = getHandshaker(ctx);
73 handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame);
74 return;
75 } else if (frame instanceof PingWebSocketFrame) {
76 ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData()));
77 return;
78 }
79 }
80 ctx.sendUpstream(e);
81 }
82
83 @Override
84 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
85 if (e.getCause() instanceof WebSocketHandshakeException) {
86 DefaultHttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.BAD_REQUEST);
87 response.setContent(ChannelBuffers.wrappedBuffer(e.getCause().getMessage().getBytes()));
88 ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE);
89 } else {
90 ctx.getChannel().close();
91 }
92 }
93
94 static WebSocketServerHandshaker getHandshaker(ChannelHandlerContext ctx) {
95 return (WebSocketServerHandshaker) ctx.getAttachment();
96 }
97
98 static void setHandshaker(ChannelHandlerContext ctx, WebSocketServerHandshaker handshaker) {
99 ctx.setAttachment(handshaker);
100 }
101
102 static ChannelHandler forbiddenHttpRequestResponder() {
103 return new SimpleChannelHandler() {
104 @Override
105 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
106 if (!(e.getMessage() instanceof WebSocketFrame)) {
107 DefaultHttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.FORBIDDEN);
108 ctx.getChannel().write(response);
109 } else {
110 ctx.sendUpstream(e);
111 }
112 }
113 };
114 }
115
116 public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
117 }
118
119
120 public void beforeRemove(ChannelHandlerContext ctx) throws Exception {
121 }
122
123 public void afterRemove(ChannelHandlerContext ctx) throws Exception {
124 }
125
126 }