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