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