1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.example.http.snoop;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.Unpooled;
20 import io.netty.channel.ChannelFutureListener;
21 import io.netty.channel.ChannelHandlerContext;
22 import io.netty.channel.SimpleChannelInboundHandler;
23 import io.netty.handler.codec.DecoderResult;
24 import io.netty.handler.codec.http.Cookie;
25 import io.netty.handler.codec.http.CookieDecoder;
26 import io.netty.handler.codec.http.DefaultFullHttpResponse;
27 import io.netty.handler.codec.http.FullHttpResponse;
28 import io.netty.handler.codec.http.HttpContent;
29 import io.netty.handler.codec.http.HttpHeaders;
30 import io.netty.handler.codec.http.HttpObject;
31 import io.netty.handler.codec.http.HttpRequest;
32 import io.netty.handler.codec.http.LastHttpContent;
33 import io.netty.handler.codec.http.QueryStringDecoder;
34 import io.netty.handler.codec.http.ServerCookieEncoder;
35 import io.netty.util.CharsetUtil;
36
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Map.Entry;
40 import java.util.Set;
41
42 import static io.netty.handler.codec.http.HttpHeaders.Names.*;
43 import static io.netty.handler.codec.http.HttpResponseStatus.*;
44 import static io.netty.handler.codec.http.HttpVersion.*;
45
46 public class HttpSnoopServerHandler extends SimpleChannelInboundHandler<Object> {
47
48 private HttpRequest request;
49
50 private final StringBuilder buf = new StringBuilder();
51
52 @Override
53 public void channelReadComplete(ChannelHandlerContext ctx) {
54 ctx.flush();
55 }
56
57 @Override
58 protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
59 if (msg instanceof HttpRequest) {
60 HttpRequest request = this.request = (HttpRequest) msg;
61
62 if (HttpHeaders.is100ContinueExpected(request)) {
63 send100Continue(ctx);
64 }
65
66 buf.setLength(0);
67 buf.append("WELCOME TO THE WILD WILD WEB SERVER\r\n");
68 buf.append("===================================\r\n");
69
70 buf.append("VERSION: ").append(request.getProtocolVersion()).append("\r\n");
71 buf.append("HOSTNAME: ").append(HttpHeaders.getHost(request, "unknown")).append("\r\n");
72 buf.append("REQUEST_URI: ").append(request.getUri()).append("\r\n\r\n");
73
74 HttpHeaders headers = request.headers();
75 if (!headers.isEmpty()) {
76 for (Map.Entry<String, String> h: headers) {
77 String key = h.getKey();
78 String value = h.getValue();
79 buf.append("HEADER: ").append(key).append(" = ").append(value).append("\r\n");
80 }
81 buf.append("\r\n");
82 }
83
84 QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri());
85 Map<String, List<String>> params = queryStringDecoder.parameters();
86 if (!params.isEmpty()) {
87 for (Entry<String, List<String>> p: params.entrySet()) {
88 String key = p.getKey();
89 List<String> vals = p.getValue();
90 for (String val : vals) {
91 buf.append("PARAM: ").append(key).append(" = ").append(val).append("\r\n");
92 }
93 }
94 buf.append("\r\n");
95 }
96
97 appendDecoderResult(buf, request);
98 }
99
100 if (msg instanceof HttpContent) {
101 HttpContent httpContent = (HttpContent) msg;
102
103 ByteBuf content = httpContent.content();
104 if (content.isReadable()) {
105 buf.append("CONTENT: ");
106 buf.append(content.toString(CharsetUtil.UTF_8));
107 buf.append("\r\n");
108 appendDecoderResult(buf, request);
109 }
110
111 if (msg instanceof LastHttpContent) {
112 buf.append("END OF CONTENT\r\n");
113
114 LastHttpContent trailer = (LastHttpContent) msg;
115 if (!trailer.trailingHeaders().isEmpty()) {
116 buf.append("\r\n");
117 for (String name: trailer.trailingHeaders().names()) {
118 for (String value: trailer.trailingHeaders().getAll(name)) {
119 buf.append("TRAILING HEADER: ");
120 buf.append(name).append(" = ").append(value).append("\r\n");
121 }
122 }
123 buf.append("\r\n");
124 }
125
126 if (!writeResponse(trailer, ctx)) {
127
128 ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
129 }
130 }
131 }
132 }
133
134 private static void appendDecoderResult(StringBuilder buf, HttpObject o) {
135 DecoderResult result = o.getDecoderResult();
136 if (result.isSuccess()) {
137 return;
138 }
139
140 buf.append(".. WITH DECODER FAILURE: ");
141 buf.append(result.cause());
142 buf.append("\r\n");
143 }
144
145 private boolean writeResponse(HttpObject currentObj, ChannelHandlerContext ctx) {
146
147 boolean keepAlive = HttpHeaders.isKeepAlive(request);
148
149 FullHttpResponse response = new DefaultFullHttpResponse(
150 HTTP_1_1, currentObj.getDecoderResult().isSuccess()? OK : BAD_REQUEST,
151 Unpooled.copiedBuffer(buf.toString(), CharsetUtil.UTF_8));
152
153 response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
154
155 if (keepAlive) {
156
157 response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
158
159
160 response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
161 }
162
163
164 String cookieString = request.headers().get(COOKIE);
165 if (cookieString != null) {
166 Set<Cookie> cookies = CookieDecoder.decode(cookieString);
167 if (!cookies.isEmpty()) {
168
169 for (Cookie cookie: cookies) {
170 response.headers().add(SET_COOKIE, ServerCookieEncoder.encode(cookie));
171 }
172 }
173 } else {
174
175 response.headers().add(SET_COOKIE, ServerCookieEncoder.encode("key1", "value1"));
176 response.headers().add(SET_COOKIE, ServerCookieEncoder.encode("key2", "value2"));
177 }
178
179
180 ctx.write(response);
181
182 return keepAlive;
183 }
184
185 private static void send100Continue(ChannelHandlerContext ctx) {
186 FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, CONTINUE);
187 ctx.write(response);
188 }
189
190 @Override
191 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
192 cause.printStackTrace();
193 ctx.close();
194 }
195 }