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 static final int MAX_CONTENT_LENGTH = 65536;
44
45 private final SslContext sslCtx;
46 private final boolean detectSsl;
47 private final boolean detectGzip;
48
49 public PortUnificationServerHandler(SslContext sslCtx) {
50 this(sslCtx, true, true);
51 }
52
53 private PortUnificationServerHandler(SslContext sslCtx, boolean detectSsl, boolean detectGzip) {
54 this.sslCtx = sslCtx;
55 this.detectSsl = detectSsl;
56 this.detectGzip = detectGzip;
57 }
58
59 @Override
60 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
61
62 if (in.readableBytes() < 5) {
63 return;
64 }
65
66 if (isSsl(in)) {
67 enableSsl(ctx);
68 } else {
69 final int magic1 = in.getUnsignedByte(in.readerIndex());
70 final int magic2 = in.getUnsignedByte(in.readerIndex() + 1);
71 if (isGzip(magic1, magic2)) {
72 enableGzip(ctx);
73 } else if (isHttp(magic1, magic2)) {
74 switchToHttp(ctx);
75 } else if (isFactorial(magic1)) {
76 switchToFactorial(ctx);
77 } else {
78
79 in.clear();
80 ctx.close();
81 }
82 }
83 }
84
85 private boolean isSsl(ByteBuf buf) {
86 if (detectSsl) {
87 return SslHandler.isEncrypted(buf, false);
88 }
89 return false;
90 }
91
92 private boolean isGzip(int magic1, int magic2) {
93 if (detectGzip) {
94 return magic1 == 31 && magic2 == 139;
95 }
96 return false;
97 }
98
99 private static boolean isHttp(int magic1, int magic2) {
100 return
101 magic1 == 'G' && magic2 == 'E' ||
102 magic1 == 'P' && magic2 == 'O' ||
103 magic1 == 'P' && magic2 == 'U' ||
104 magic1 == 'H' && magic2 == 'E' ||
105 magic1 == 'O' && magic2 == 'P' ||
106 magic1 == 'P' && magic2 == 'A' ||
107 magic1 == 'D' && magic2 == 'E' ||
108 magic1 == 'T' && magic2 == 'R' ||
109 magic1 == 'C' && magic2 == 'O';
110 }
111
112 private static boolean isFactorial(int magic1) {
113 return magic1 == 'F';
114 }
115
116 private void enableSsl(ChannelHandlerContext ctx) {
117 ChannelPipeline p = ctx.pipeline();
118 p.addLast("ssl", sslCtx.newHandler(ctx.alloc()));
119 p.addLast("unificationA", new PortUnificationServerHandler(sslCtx, false, detectGzip));
120 p.remove(this);
121 }
122
123 private void enableGzip(ChannelHandlerContext ctx) {
124 ChannelPipeline p = ctx.pipeline();
125 p.addLast("gzipdeflater", ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
126 p.addLast("gzipinflater", ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP, MAX_CONTENT_LENGTH));
127 p.addLast("unificationB", new PortUnificationServerHandler(sslCtx, detectSsl, false));
128 p.remove(this);
129 }
130
131 private void switchToHttp(ChannelHandlerContext ctx) {
132 ChannelPipeline p = ctx.pipeline();
133 p.addLast("decoder", new HttpRequestDecoder());
134 p.addLast("encoder", new HttpResponseEncoder());
135 p.addLast("deflater", new HttpContentCompressor((CompressionOptions[]) null));
136 p.addLast("handler", new HttpSnoopServerHandler());
137 p.remove(this);
138 }
139
140 private void switchToFactorial(ChannelHandlerContext ctx) {
141 ChannelPipeline p = ctx.pipeline();
142 p.addLast("decoder", new BigIntegerDecoder());
143 p.addLast("encoder", new NumberEncoder());
144 p.addLast("handler", new FactorialServerHandler());
145 p.remove(this);
146 }
147 }