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