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