1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.example.http.websocketx.server;
17
18 import io.netty5.buffer.api.Buffer;
19 import io.netty5.channel.ChannelFutureListeners;
20 import io.netty5.channel.ChannelHandlerContext;
21 import io.netty5.channel.ChannelPipeline;
22 import io.netty5.channel.SimpleChannelInboundHandler;
23 import io.netty5.handler.codec.http.DefaultFullHttpResponse;
24 import io.netty5.handler.codec.http.FullHttpRequest;
25 import io.netty5.handler.codec.http.FullHttpResponse;
26 import io.netty5.handler.codec.http.HttpHeaderNames;
27 import io.netty5.handler.codec.http.HttpRequest;
28 import io.netty5.handler.codec.http.HttpUtil;
29 import io.netty5.handler.ssl.SslHandler;
30 import io.netty5.util.CharsetUtil;
31
32 import static io.netty5.handler.codec.http.HttpHeaderNames.CONNECTION;
33 import static io.netty5.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
34 import static io.netty5.handler.codec.http.HttpHeaderValues.CLOSE;
35 import static io.netty5.handler.codec.http.HttpHeaderValues.KEEP_ALIVE;
36 import static io.netty5.handler.codec.http.HttpMethod.GET;
37 import static io.netty5.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
38 import static io.netty5.handler.codec.http.HttpResponseStatus.FORBIDDEN;
39 import static io.netty5.handler.codec.http.HttpResponseStatus.NOT_FOUND;
40 import static io.netty5.handler.codec.http.HttpResponseStatus.OK;
41 import static io.netty5.handler.codec.http.HttpVersion.HTTP_1_0;
42 import static io.netty5.handler.codec.http.HttpVersion.HTTP_1_1;
43
44
45
46
47 public class WebSocketIndexPageHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
48
49 private final String websocketPath;
50
51 public WebSocketIndexPageHandler(String websocketPath) {
52 this.websocketPath = websocketPath;
53 }
54
55 @Override
56 protected void messageReceived(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
57
58 if (!req.decoderResult().isSuccess()) {
59 sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST,
60 ctx.bufferAllocator().allocate(0)));
61 return;
62 }
63
64
65 if (!GET.equals(req.method())) {
66 sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN,
67 ctx.bufferAllocator().allocate(0)));
68 return;
69 }
70
71
72 if ("/".equals(req.uri()) || "/index.html".equals(req.uri())) {
73 String webSocketLocation = getWebSocketLocation(ctx.pipeline(), req, websocketPath);
74 Buffer content = WebSocketServerIndexPage.getContent(ctx.bufferAllocator(), webSocketLocation);
75 FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
76
77 res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
78 HttpUtil.setContentLength(res, content.readableBytes());
79
80 sendHttpResponse(ctx, req, res);
81 } else {
82 sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND,
83 ctx.bufferAllocator().allocate(0)));
84 }
85 }
86
87 @Override
88 public void channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
89 cause.printStackTrace();
90 ctx.close();
91 }
92
93 private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
94
95 if (res.status().code() != 200) {
96 res.payload().writeCharSequence(res.status().toString(), CharsetUtil.UTF_8);
97 HttpUtil.setContentLength(res, res.payload().readableBytes());
98 }
99
100
101 if (!HttpUtil.isKeepAlive(req) || res.status().code() != 200) {
102
103 res.headers().set(CONNECTION, CLOSE);
104 ctx.writeAndFlush(res).addListener(ctx, ChannelFutureListeners.CLOSE);
105 } else {
106 if (req.protocolVersion().equals(HTTP_1_0)) {
107 res.headers().set(CONNECTION, KEEP_ALIVE);
108 }
109 ctx.writeAndFlush(res);
110 }
111 }
112
113 private static String getWebSocketLocation(ChannelPipeline cp, HttpRequest req, String path) {
114 String protocol = "ws";
115 if (cp.get(SslHandler.class) != null) {
116
117 protocol = "wss";
118 }
119 return protocol + "://" + req.headers().get(HttpHeaderNames.HOST) + path;
120 }
121 }