1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.codec.http.multipart;
17
18 import org.jboss.netty.handler.codec.http.HttpChunk;
19 import org.jboss.netty.handler.codec.http.HttpConstants;
20 import org.jboss.netty.handler.codec.http.HttpHeaders;
21 import org.jboss.netty.handler.codec.http.HttpRequest;
22 import org.jboss.netty.util.internal.StringUtil;
23
24 import java.nio.charset.Charset;
25 import java.util.List;
26
27
28
29
30 @SuppressWarnings("deprecation")
31 public class HttpPostRequestDecoder implements InterfaceHttpPostRequestDecoder {
32
33
34
35 private final InterfaceHttpPostRequestDecoder decoder;
36
37
38
39
40
41
42
43
44 public HttpPostRequestDecoder(HttpRequest request)
45 throws ErrorDataDecoderException, IncompatibleDataDecoderException {
46 this(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE),
47 request, HttpConstants.DEFAULT_CHARSET);
48 }
49
50
51
52
53
54
55
56
57
58 public HttpPostRequestDecoder(HttpDataFactory factory, HttpRequest request)
59 throws ErrorDataDecoderException, IncompatibleDataDecoderException {
60 this(factory, request, HttpConstants.DEFAULT_CHARSET);
61 }
62
63
64
65
66
67
68
69
70
71
72 public HttpPostRequestDecoder(HttpDataFactory factory, HttpRequest request,
73 Charset charset) throws ErrorDataDecoderException,
74 IncompatibleDataDecoderException {
75 if (factory == null) {
76 throw new NullPointerException("factory");
77 }
78 if (request == null) {
79 throw new NullPointerException("request");
80 }
81 if (charset == null) {
82 throw new NullPointerException("charset");
83 }
84
85 if (isMultipart(request)) {
86 decoder = new HttpPostMultipartRequestDecoder(factory, request, charset);
87 } else {
88 decoder = new HttpPostStandardRequestDecoder(factory, request, charset);
89 }
90 }
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 protected enum MultiPartStatus {
130 NOTSTARTED,
131 PREAMBLE,
132 HEADERDELIMITER,
133 DISPOSITION,
134 FIELD,
135 FILEUPLOAD,
136 MIXEDPREAMBLE,
137 MIXEDDELIMITER,
138 MIXEDDISPOSITION,
139 MIXEDFILEUPLOAD,
140 MIXEDCLOSEDELIMITER,
141 CLOSEDELIMITER,
142 PREEPILOGUE,
143 EPILOGUE
144 }
145
146
147
148
149
150
151 public static boolean isMultipart(HttpRequest request) throws ErrorDataDecoderException {
152 if (request.headers().contains(HttpHeaders.Names.CONTENT_TYPE)) {
153 return getMultipartDataBoundary(request.headers().get(HttpHeaders.Names.CONTENT_TYPE)) != null;
154 } else {
155 return false;
156 }
157 }
158
159
160
161
162
163
164 protected static String[] getMultipartDataBoundary(String contentType)
165 throws ErrorDataDecoderException {
166
167 String[] headerContentType = splitHeaderContentType(contentType);
168 if (headerContentType[0].toLowerCase().startsWith(
169 HttpHeaders.Values.MULTIPART_FORM_DATA)) {
170 int mrank = 1, crank = 2;
171 if (headerContentType[1].toLowerCase().startsWith(
172 HttpHeaders.Values.BOUNDARY.toString())) {
173 mrank = 1;
174 crank = 2;
175 } else if (headerContentType[2].toLowerCase().startsWith(
176 HttpHeaders.Values.BOUNDARY.toString())) {
177 mrank = 2;
178 crank = 1;
179 } else {
180 return null;
181 }
182 String boundary = StringUtil.substringAfter(headerContentType[mrank], '=');
183 if (boundary == null) {
184 throw new ErrorDataDecoderException("Needs a boundary value");
185 }
186 if (boundary.charAt(0) == '"') {
187 String bound = boundary.trim();
188 int index = bound.length() - 1;
189 if (bound.charAt(index) == '"') {
190 boundary = bound.substring(1, index);
191 }
192 }
193 if (headerContentType[crank].toLowerCase().startsWith(
194 HttpHeaders.Values.CHARSET.toString())) {
195 String charset = StringUtil.substringAfter(headerContentType[crank], '=');
196 if (charset != null) {
197 return new String[] {"--" + boundary, charset};
198 }
199 }
200 return new String[] {"--" + boundary};
201 }
202 return null;
203 }
204
205
206
207
208
209 public boolean isMultipart() {
210 return decoder.isMultipart();
211 }
212
213
214
215
216
217
218
219
220
221
222 public List<InterfaceHttpData> getBodyHttpDatas()
223 throws NotEnoughDataDecoderException {
224 return decoder.getBodyHttpDatas();
225 }
226
227
228
229
230
231
232
233
234
235
236 public List<InterfaceHttpData> getBodyHttpDatas(String name)
237 throws NotEnoughDataDecoderException {
238 return decoder.getBodyHttpDatas(name);
239 }
240
241
242
243
244
245
246
247
248
249
250 public InterfaceHttpData getBodyHttpData(String name)
251 throws NotEnoughDataDecoderException {
252 return decoder.getBodyHttpData(name);
253 }
254
255
256
257
258
259
260
261 public void offer(HttpChunk chunk) throws ErrorDataDecoderException {
262 decoder.offer(chunk);
263 }
264
265
266
267
268
269
270
271
272
273 public boolean hasNext() throws EndOfDataDecoderException {
274 return decoder.hasNext();
275 }
276
277
278
279
280
281
282
283
284 public InterfaceHttpData next() throws EndOfDataDecoderException {
285 return decoder.next();
286 }
287
288
289
290
291 public void cleanFiles() {
292 decoder.cleanFiles();
293 }
294
295
296
297
298 public void removeHttpDataFromClean(InterfaceHttpData data) {
299 decoder.removeHttpDataFromClean(data);
300 }
301
302
303
304
305
306 private static String[] splitHeaderContentType(String sb) {
307 int aStart;
308 int aEnd;
309 int bStart;
310 int bEnd;
311 int cStart;
312 int cEnd;
313 aStart = HttpPostBodyUtil.findNonWhitespace(sb, 0);
314 aEnd = sb.indexOf(';');
315 if (aEnd == -1) {
316 return new String[] { sb, "", "" };
317 }
318 bStart = HttpPostBodyUtil.findNonWhitespace(sb, aEnd + 1);
319 if (sb.charAt(aEnd - 1) == ' ') {
320 aEnd--;
321 }
322 bEnd = sb.indexOf(';', bStart);
323 if (bEnd == -1) {
324 bEnd = HttpPostBodyUtil.findEndOfString(sb);
325 return new String[] { sb.substring(aStart, aEnd), sb.substring(bStart, bEnd), "" };
326 }
327 cStart = HttpPostBodyUtil.findNonWhitespace(sb, bEnd + 1);
328 if (sb.charAt(bEnd - 1) == ' ') {
329 bEnd--;
330 }
331 cEnd = HttpPostBodyUtil.findEndOfString(sb);
332 return new String[] { sb.substring(aStart, aEnd), sb.substring(bStart, bEnd), sb.substring(cStart, cEnd) };
333 }
334
335
336
337
338
339 public static class NotEnoughDataDecoderException extends Exception {
340 private static final long serialVersionUID = -7846841864603865638L;
341
342 public NotEnoughDataDecoderException() {
343 }
344
345 public NotEnoughDataDecoderException(String msg) {
346 super(msg);
347 }
348
349 public NotEnoughDataDecoderException(Throwable cause) {
350 super(cause);
351 }
352
353 public NotEnoughDataDecoderException(String msg, Throwable cause) {
354 super(msg, cause);
355 }
356 }
357
358
359
360
361 public static class EndOfDataDecoderException extends Exception {
362 private static final long serialVersionUID = 1336267941020800769L;
363 }
364
365
366
367
368 public static class ErrorDataDecoderException extends Exception {
369 private static final long serialVersionUID = 5020247425493164465L;
370
371 public ErrorDataDecoderException() {
372 }
373
374 public ErrorDataDecoderException(String msg) {
375 super(msg);
376 }
377
378 public ErrorDataDecoderException(Throwable cause) {
379 super(cause);
380 }
381
382 public ErrorDataDecoderException(String msg, Throwable cause) {
383 super(msg, cause);
384 }
385 }
386
387
388
389
390 @Deprecated
391 public static class IncompatibleDataDecoderException extends Exception {
392 private static final long serialVersionUID = -953268047926250267L;
393
394 public IncompatibleDataDecoderException() {
395 }
396
397 public IncompatibleDataDecoderException(String msg) {
398 super(msg);
399 }
400
401 public IncompatibleDataDecoderException(Throwable cause) {
402 super(cause);
403 }
404
405 public IncompatibleDataDecoderException(String msg, Throwable cause) {
406 super(msg, cause);
407 }
408 }
409 }