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