1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.example.http.upload;
17
18 import org.jboss.netty.buffer.ChannelBuffer;
19 import org.jboss.netty.buffer.ChannelBuffers;
20 import org.jboss.netty.channel.Channel;
21 import org.jboss.netty.channel.ChannelFuture;
22 import org.jboss.netty.channel.ChannelFutureListener;
23 import org.jboss.netty.channel.ChannelHandlerContext;
24 import org.jboss.netty.channel.ChannelStateEvent;
25 import org.jboss.netty.channel.Channels;
26 import org.jboss.netty.channel.ExceptionEvent;
27 import org.jboss.netty.channel.MessageEvent;
28 import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
29 import org.jboss.netty.handler.codec.http.cookie.Cookie;
30 import org.jboss.netty.handler.codec.http.cookie.ServerCookieDecoder;
31 import org.jboss.netty.handler.codec.http.cookie.ServerCookieEncoder;
32 import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
33 import org.jboss.netty.handler.codec.http.HttpChunk;
34 import org.jboss.netty.handler.codec.http.HttpHeaders;
35 import org.jboss.netty.handler.codec.http.HttpRequest;
36 import org.jboss.netty.handler.codec.http.HttpResponse;
37 import org.jboss.netty.handler.codec.http.HttpResponseStatus;
38 import org.jboss.netty.handler.codec.http.HttpVersion;
39 import org.jboss.netty.handler.codec.http.QueryStringDecoder;
40 import org.jboss.netty.handler.codec.http.multipart.Attribute;
41 import org.jboss.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
42 import org.jboss.netty.handler.codec.http.multipart.DiskAttribute;
43 import org.jboss.netty.handler.codec.http.multipart.DiskFileUpload;
44 import org.jboss.netty.handler.codec.http.multipart.FileUpload;
45 import org.jboss.netty.handler.codec.http.multipart.HttpDataFactory;
46 import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
47 import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.EndOfDataDecoderException;
48 import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException;
49 import org.jboss.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException;
50 import org.jboss.netty.handler.codec.http.multipart.InterfaceHttpData;
51 import org.jboss.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;
52 import org.jboss.netty.util.CharsetUtil;
53
54 import java.io.IOException;
55 import java.net.URI;
56 import java.util.Collections;
57 import java.util.List;
58 import java.util.Map;
59 import java.util.Map.Entry;
60 import java.util.Set;
61
62 public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
63
64 private static final HttpDataFactory factory =
65 new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);
66
67 static {
68
69
70 DiskFileUpload.deleteOnExitTemporaryFile = true;
71
72
73 DiskFileUpload.baseDirectory = null;
74 DiskAttribute.deleteOnExitTemporaryFile = true;
75
76 DiskAttribute.baseDirectory = null;
77 }
78
79 private final StringBuilder responseContent = new StringBuilder();
80 private HttpPostRequestDecoder decoder;
81 private HttpRequest request;
82 private boolean readingChunks;
83
84 @Override
85 public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) {
86 if (decoder != null) {
87 decoder.cleanFiles();
88 }
89 }
90
91 @Override
92 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
93 if (!readingChunks) {
94
95 if (decoder != null) {
96 decoder.cleanFiles();
97 decoder = null;
98 }
99
100 HttpRequest request = this.request = (HttpRequest) e.getMessage();
101 URI uri = new URI(request.getUri());
102 if (!uri.getPath().startsWith("/form")) {
103
104 writeMenu(e);
105 return;
106 }
107 responseContent.setLength(0);
108 responseContent.append("WELCOME TO THE WILD WILD WEB SERVER\r\n");
109 responseContent.append("===================================\r\n");
110 responseContent.append("VERSION: " + request.getProtocolVersion().getText() + "\r\n");
111 responseContent.append("REQUEST_URI: " + request.getUri() + "\r\n\r\n");
112 responseContent.append("\r\n\r\n");
113
114
115 for (Entry<String, String> entry: request.headers()) {
116 responseContent.append("HEADER: " + entry.getKey() + '=' + entry.getValue() + "\r\n");
117 }
118 responseContent.append("\r\n\r\n");
119
120
121 Set<Cookie> cookies;
122 String value = request.headers().get(HttpHeaders.Names.COOKIE);
123 if (value == null) {
124 cookies = Collections.emptySet();
125 } else {
126 cookies = ServerCookieDecoder.STRICT.decode(value);
127 }
128 for (Cookie cookie: cookies) {
129 responseContent.append("COOKIE: " + cookie + "\r\n");
130 }
131 responseContent.append("\r\n\r\n");
132
133 QueryStringDecoder decoderQuery = new QueryStringDecoder(request.getUri());
134 Map<String, List<String>> uriAttributes = decoderQuery.getParameters();
135 for (Entry<String, List<String>> attr: uriAttributes.entrySet()) {
136 for (String attrVal: attr.getValue()) {
137 responseContent.append("URI: " + attr.getKey() + '=' + attrVal + "\r\n");
138 }
139 }
140 responseContent.append("\r\n\r\n");
141
142
143 try {
144 decoder = new HttpPostRequestDecoder(factory, request);
145 } catch (ErrorDataDecoderException e1) {
146 e1.printStackTrace();
147 responseContent.append(e1.getMessage());
148 writeResponse(e.getChannel());
149 Channels.close(e.getChannel());
150 return;
151 }
152
153 responseContent.append("Is Chunked: " + request.isChunked() + "\r\n");
154 responseContent.append("IsMultipart: " + decoder.isMultipart() + "\r\n");
155 if (request.isChunked()) {
156
157 responseContent.append("Chunks: ");
158 readingChunks = true;
159 } else {
160
161 readHttpDataAllReceive(e.getChannel());
162 responseContent.append("\r\n\r\nEND OF NOT CHUNKED CONTENT\r\n");
163 writeResponse(e.getChannel());
164 }
165 } else {
166
167 HttpChunk chunk = (HttpChunk) e.getMessage();
168 try {
169 decoder.offer(chunk);
170 } catch (ErrorDataDecoderException e1) {
171 e1.printStackTrace();
172 responseContent.append(e1.getMessage());
173 writeResponse(e.getChannel());
174 Channels.close(e.getChannel());
175 return;
176 }
177 responseContent.append('o');
178
179 readHttpDataChunkByChunk();
180
181 if (chunk.isLast()) {
182 readHttpDataAllReceive(e.getChannel());
183 writeResponse(e.getChannel());
184 readingChunks = false;
185 }
186 }
187 }
188
189
190
191
192 private void readHttpDataAllReceive(Channel channel) {
193 List<InterfaceHttpData> datas;
194 try {
195 datas = decoder.getBodyHttpDatas();
196 } catch (NotEnoughDataDecoderException e1) {
197
198 e1.printStackTrace();
199 responseContent.append(e1.getMessage());
200 writeResponse(channel);
201 Channels.close(channel);
202 return;
203 }
204 for (InterfaceHttpData data: datas) {
205 writeHttpData(data);
206 }
207 responseContent.append("\r\n\r\nEND OF CONTENT AT FINAL END\r\n");
208 }
209
210
211
212
213
214 private void readHttpDataChunkByChunk() {
215 try {
216 while (decoder.hasNext()) {
217 InterfaceHttpData data = decoder.next();
218 if (data != null) {
219
220 writeHttpData(data);
221 }
222 }
223 } catch (EndOfDataDecoderException e1) {
224
225 responseContent.append("\r\n\r\nEND OF CONTENT CHUNK BY CHUNK\r\n\r\n");
226 }
227 }
228
229 private void writeHttpData(InterfaceHttpData data) {
230 if (data.getHttpDataType() == HttpDataType.Attribute) {
231 Attribute attribute = (Attribute) data;
232 String value;
233 try {
234 value = attribute.getValue();
235 } catch (IOException e1) {
236
237 e1.printStackTrace();
238 responseContent.append("\r\nBODY Attribute: " +
239 attribute.getHttpDataType().name() + ": " +
240 attribute.getName() + " Error while reading value: " +
241 e1.getMessage() + "\r\n");
242 return;
243 }
244 if (value.length() > 100) {
245 responseContent.append("\r\nBODY Attribute: " +
246 attribute.getHttpDataType().name() + ": " + attribute.getName() + " data too long\r\n");
247 } else {
248 responseContent.append(
249 "\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ": " + attribute + "\r\n");
250 }
251 } else {
252 responseContent.append(
253 "\r\nBODY FileUpload: " + data.getHttpDataType().name() + ": " + data + "\r\n");
254 if (data.getHttpDataType() == HttpDataType.FileUpload) {
255 FileUpload fileUpload = (FileUpload) data;
256 if (fileUpload.isCompleted()) {
257 if (fileUpload.length() < 10000) {
258 responseContent.append("\tContent of file\r\n");
259 try {
260 responseContent.append(fileUpload.getString(fileUpload.getCharset()));
261 } catch (IOException e1) {
262
263 e1.printStackTrace();
264 }
265 responseContent.append("\r\n");
266 } else {
267 responseContent.append(
268 "\tFile too long to be printed out:" + fileUpload.length() + "\r\n");
269 }
270
271
272
273
274
275
276 } else {
277 responseContent.append("\tFile to be continued but should not!\r\n");
278 }
279 }
280 }
281 }
282
283 private void writeResponse(Channel channel) {
284
285 ChannelBuffer buf = ChannelBuffers.copiedBuffer(responseContent.toString(), CharsetUtil.UTF_8);
286 responseContent.setLength(0);
287
288
289 boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(
290 request.headers().get(HttpHeaders.Names.CONNECTION)) ||
291 request.getProtocolVersion().equals(HttpVersion.HTTP_1_0) &&
292 !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.headers().get(HttpHeaders.Names.CONNECTION));
293
294
295 HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
296 response.setContent(buf);
297 response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=UTF-8");
298
299 if (!close) {
300
301
302 response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(buf.readableBytes()));
303 }
304
305 Set<Cookie> cookies;
306 String value = request.headers().get(HttpHeaders.Names.COOKIE);
307 if (value == null) {
308 cookies = Collections.emptySet();
309 } else {
310 cookies = ServerCookieDecoder.STRICT.decode(value);
311 }
312 if (!cookies.isEmpty()) {
313 response.headers().add(HttpHeaders.Names.SET_COOKIE, ServerCookieEncoder.STRICT.encode(cookies));
314 }
315
316 ChannelFuture future = channel.write(response);
317
318 if (close) {
319 future.addListener(ChannelFutureListener.CLOSE);
320 }
321 }
322
323 private void writeMenu(MessageEvent e) {
324
325
326 responseContent.setLength(0);
327
328
329 responseContent.append("<html>");
330 responseContent.append("<head>");
331 responseContent.append("<title>Netty Test Form</title>\r\n");
332 responseContent.append("</head>\r\n");
333 responseContent.append("<body bgcolor=white><style>td{font-size: 12pt;}</style>");
334
335 responseContent.append("<table border=\"0\">");
336 responseContent.append("<tr>");
337 responseContent.append("<td>");
338 responseContent.append("<h1>Netty Test Form</h1>");
339 responseContent.append("Choose one FORM");
340 responseContent.append("</td>");
341 responseContent.append("</tr>");
342 responseContent.append("</table>\r\n");
343
344
345 responseContent.append("<CENTER>GET FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
346 responseContent.append("<FORM ACTION=\"/formget\" METHOD=\"GET\">");
347 responseContent.append("<input type=hidden name=getform value=\"GET\">");
348 responseContent.append("<table border=\"0\">");
349 responseContent.append("<tr><td>Fill with value:<br> <input type=text name=\"info\" size=10></td></tr>");
350 responseContent.append("<tr><td>Fill with value:<br> <input type=text name=\"secondinfo\" size=20>");
351 responseContent.append("<tr><td>Fill with value:<br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
352 responseContent.append("</td></tr>");
353 responseContent.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>");
354 responseContent.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
355 responseContent.append("</table></FORM>\r\n");
356 responseContent.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
357
358
359 responseContent.append("<CENTER>POST FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
360 responseContent.append("<FORM ACTION=\"/formpost\" METHOD=\"POST\">");
361 responseContent.append("<input type=hidden name=getform value=\"POST\">");
362 responseContent.append("<table border=\"0\">");
363 responseContent.append("<tr><td>Fill with value:<br> <input type=text name=\"info\" size=10></td></tr>");
364 responseContent.append("<tr><td>Fill with value:<br> <input type=text name=\"secondinfo\" size=20>");
365 responseContent.append("<tr><td>Fill with value:<br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
366 responseContent.append("<tr><td>Fill with file (only file name will be transmitted): <br> ");
367 responseContent.append("<input type=file name=\"myfile\">");
368 responseContent.append("</td></tr>");
369 responseContent.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>");
370 responseContent.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
371 responseContent.append("</table></FORM>\r\n");
372 responseContent.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
373
374
375 responseContent.append("<CENTER>POST MULTIPART FORM<HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
376 responseContent.append("<FORM ACTION=\"/formpostmultipart\" ENCTYPE=\"multipart/form-data\" METHOD=\"POST\">");
377 responseContent.append("<input type=hidden name=getform value=\"POST\">");
378 responseContent.append("<table border=\"0\">");
379 responseContent.append("<tr><td>Fill with value:<br> <input type=text name=\"info\" size=10></td></tr>");
380 responseContent.append("<tr><td>Fill with value:<br> <input type=text name=\"secondinfo\" size=20>");
381 responseContent.append("<tr><td>Fill with value:<br> <textarea name=\"thirdinfo\" cols=40 rows=10></textarea>");
382 responseContent.append("<tr><td>Fill with file: <br> <input type=file name=\"myfile\">");
383 responseContent.append("</td></tr>");
384 responseContent.append("<tr><td><INPUT TYPE=\"submit\" NAME=\"Send\" VALUE=\"Send\"></INPUT></td>");
385 responseContent.append("<td><INPUT TYPE=\"reset\" NAME=\"Clear\" VALUE=\"Clear\" ></INPUT></td></tr>");
386 responseContent.append("</table></FORM>\r\n");
387 responseContent.append("<CENTER><HR WIDTH=\"75%\" NOSHADE color=\"blue\"></CENTER>");
388
389 responseContent.append("</body>");
390 responseContent.append("</html>");
391
392 ChannelBuffer buf = ChannelBuffers.copiedBuffer(responseContent.toString(), CharsetUtil.UTF_8);
393
394 HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
395 response.setContent(buf);
396 response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/html; charset=UTF-8");
397 response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(buf.readableBytes()));
398
399 e.getChannel().write(response);
400 }
401
402 @Override
403 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
404 e.getCause().printStackTrace();
405 e.getChannel().close();
406 }
407 }