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