1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.example.portunification;
17
18 import io.netty5.buffer.api.Buffer;
19 import io.netty5.channel.ChannelHandlerContext;
20 import io.netty5.channel.ChannelPipeline;
21 import io.netty5.example.factorial.BigIntegerDecoder;
22 import io.netty5.example.factorial.FactorialServerHandler;
23 import io.netty5.example.factorial.NumberEncoder;
24 import io.netty5.example.http.snoop.HttpSnoopServerHandler;
25 import io.netty5.handler.codec.ByteToMessageDecoder;
26 import io.netty5.handler.codec.compression.ZlibCodecFactory;
27 import io.netty5.handler.codec.compression.ZlibWrapper;
28 import io.netty5.handler.codec.http.HttpContentCompressor;
29 import io.netty5.handler.codec.http.HttpRequestDecoder;
30 import io.netty5.handler.codec.http.HttpResponseEncoder;
31 import io.netty5.handler.ssl.SslContext;
32 import io.netty5.handler.ssl.SslHandler;
33
34
35
36
37
38 public class PortUnificationServerHandler extends ByteToMessageDecoder {
39
40 private final SslContext sslCtx;
41 private final boolean detectSsl;
42 private final boolean detectGzip;
43
44 public PortUnificationServerHandler(SslContext sslCtx) {
45 this(sslCtx, true, true);
46 }
47
48 private PortUnificationServerHandler(SslContext sslCtx, boolean detectSsl, boolean detectGzip) {
49 this.sslCtx = sslCtx;
50 this.detectSsl = detectSsl;
51 this.detectGzip = detectGzip;
52 }
53
54 @Override
55 protected void decode(ChannelHandlerContext ctx, Buffer in) throws Exception {
56
57 if (in.readableBytes() < 5) {
58 return;
59 }
60
61 if (isSsl(in)) {
62 enableSsl(ctx);
63 } else {
64 final int magic1 = in.getUnsignedByte(in.readerOffset());
65 final int magic2 = in.getUnsignedByte(in.readerOffset() + 1);
66 if (isGzip(magic1, magic2)) {
67 enableGzip(ctx);
68 } else if (isHttp(magic1, magic2)) {
69 switchToHttp(ctx);
70 } else if (isFactorial(magic1)) {
71 switchToFactorial(ctx);
72 } else {
73
74 in.resetOffsets();
75 ctx.close();
76 }
77 }
78 }
79
80 private boolean isSsl(Buffer buf) {
81 if (detectSsl) {
82 return SslHandler.isEncrypted(buf);
83 }
84 return false;
85 }
86
87 private boolean isGzip(int magic1, int magic2) {
88 if (detectGzip) {
89 return magic1 == 31 && magic2 == 139;
90 }
91 return false;
92 }
93
94 private static boolean isHttp(int magic1, int magic2) {
95 return
96 magic1 == 'G' && magic2 == 'E' ||
97 magic1 == 'P' && magic2 == 'O' ||
98 magic1 == 'P' && magic2 == 'U' ||
99 magic1 == 'H' && magic2 == 'E' ||
100 magic1 == 'O' && magic2 == 'P' ||
101 magic1 == 'P' && magic2 == 'A' ||
102 magic1 == 'D' && magic2 == 'E' ||
103 magic1 == 'T' && magic2 == 'R' ||
104 magic1 == 'C' && magic2 == 'O';
105 }
106
107 private static boolean isFactorial(int magic1) {
108 return magic1 == 'F';
109 }
110
111 private void enableSsl(ChannelHandlerContext ctx) {
112 ChannelPipeline p = ctx.pipeline();
113 p.addLast("ssl", sslCtx.newHandler(ctx.bufferAllocator()));
114 p.addLast("unificationA", new PortUnificationServerHandler(sslCtx, false, detectGzip));
115 p.remove(this);
116 }
117
118 private void enableGzip(ChannelHandlerContext ctx) {
119 ChannelPipeline p = ctx.pipeline();
120 p.addLast("gzipdeflater", ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
121 p.addLast("gzipinflater", ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
122 p.addLast("unificationB", new PortUnificationServerHandler(sslCtx, detectSsl, false));
123 p.remove(this);
124 }
125
126 private void switchToHttp(ChannelHandlerContext ctx) {
127 ChannelPipeline p = ctx.pipeline();
128 p.addLast("decoder", new HttpRequestDecoder());
129 p.addLast("encoder", new HttpResponseEncoder());
130 p.addLast("deflater", new HttpContentCompressor());
131 p.addLast("handler", new HttpSnoopServerHandler());
132 p.remove(this);
133 }
134
135 private void switchToFactorial(ChannelHandlerContext ctx) {
136 ChannelPipeline p = ctx.pipeline();
137 p.addLast("decoder", new BigIntegerDecoder());
138 p.addLast("encoder", new NumberEncoder());
139 p.addLast("handler", new FactorialServerHandler());
140 p.remove(this);
141 }
142 }