1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.example.http.websocketx.server;
17
18 import org.jboss.netty.buffer.ChannelBuffer;
19 import org.jboss.netty.buffer.ChannelBuffers;
20 import org.jboss.netty.channel.ChannelFuture;
21 import org.jboss.netty.channel.ChannelFutureListener;
22 import org.jboss.netty.channel.ChannelHandlerContext;
23 import org.jboss.netty.channel.ExceptionEvent;
24 import org.jboss.netty.channel.MessageEvent;
25 import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
26 import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
27 import org.jboss.netty.handler.codec.http.HttpRequest;
28 import org.jboss.netty.handler.codec.http.HttpResponse;
29 import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
30 import org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame;
31 import org.jboss.netty.handler.codec.http.websocketx.PongWebSocketFrame;
32 import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame;
33 import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame;
34 import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
35 import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
36 import org.jboss.netty.util.CharsetUtil;
37
38 import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*;
39 import static org.jboss.netty.handler.codec.http.HttpHeaders.*;
40 import static org.jboss.netty.handler.codec.http.HttpMethod.*;
41 import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
42 import static org.jboss.netty.handler.codec.http.HttpVersion.*;
43
44
45
46
47 public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
48
49 private static final String WEBSOCKET_PATH = "/websocket";
50
51 private WebSocketServerHandshaker handshaker;
52
53 @Override
54 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
55 Object msg = e.getMessage();
56 if (msg instanceof HttpRequest) {
57 handleHttpRequest(ctx, (HttpRequest) msg);
58 } else if (msg instanceof WebSocketFrame) {
59 handleWebSocketFrame(ctx, (WebSocketFrame) msg);
60 }
61 }
62
63 private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) {
64
65 if (req.getMethod() != GET) {
66 sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
67 return;
68 }
69
70
71 if ("/".equals(req.getUri())) {
72 HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK);
73
74 ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req));
75
76 res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
77 setContentLength(res, content.readableBytes());
78
79 res.setContent(content);
80 sendHttpResponse(ctx, req, res);
81 return;
82 }
83 if ("/favicon.ico".equals(req.getUri())) {
84 HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND);
85 sendHttpResponse(ctx, req, res);
86 return;
87 }
88
89
90 WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
91 getWebSocketLocation(req), null, false);
92 handshaker = wsFactory.newHandshaker(req);
93 if (handshaker == null) {
94 wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel());
95 } else {
96 handshaker.handshake(ctx.getChannel(), req).addListener(WebSocketServerHandshaker.HANDSHAKE_LISTENER);
97 }
98 }
99
100 private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
101
102 if (frame instanceof CloseWebSocketFrame) {
103 handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame);
104 return;
105 }
106 if (frame instanceof PingWebSocketFrame) {
107 ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData()));
108 return;
109 }
110 if (!(frame instanceof TextWebSocketFrame)) {
111 throw new UnsupportedOperationException(
112 String.format("%s frame types not supported", frame.getClass().getName()));
113 }
114
115
116 String request = ((TextWebSocketFrame) frame).getText();
117 System.err.println(String.format("Channel %s received %s", ctx.getChannel().getId(), request));
118 ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase()));
119 }
120
121 private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
122
123 if (res.getStatus().getCode() != 200) {
124 res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8));
125 setContentLength(res, res.getContent().readableBytes());
126 }
127
128
129 ChannelFuture f = ctx.getChannel().write(res);
130 if (!isKeepAlive(req) || res.getStatus().getCode() != 200) {
131 f.addListener(ChannelFutureListener.CLOSE);
132 }
133 }
134
135 @Override
136 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
137 e.getCause().printStackTrace();
138 e.getChannel().close();
139 }
140
141 private static String getWebSocketLocation(HttpRequest req) {
142 String location = req.headers().get(HOST) + WEBSOCKET_PATH;
143 if (WebSocketServer.SSL) {
144 return "wss://" + location;
145 } else {
146 return "ws://" + location;
147 }
148 }
149 }