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 java.io.IOException;
19 import java.io.UnsupportedEncodingException;
20 import java.net.URLDecoder;
21 import java.nio.charset.Charset;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.TreeMap;
26
27 import org.jboss.netty.buffer.ChannelBuffer;
28 import org.jboss.netty.buffer.ChannelBuffers;
29 import org.jboss.netty.handler.codec.http.HttpChunk;
30 import org.jboss.netty.handler.codec.http.HttpConstants;
31 import org.jboss.netty.handler.codec.http.HttpHeaders;
32 import org.jboss.netty.handler.codec.http.HttpMethod;
33 import org.jboss.netty.handler.codec.http.HttpRequest;
34 import org.jboss.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadNoBackArrayException;
35 import org.jboss.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadOptimize;
36 import org.jboss.netty.handler.codec.http.multipart.HttpPostBodyUtil.TransferEncodingMechanism;
37 import org.jboss.netty.util.internal.CaseIgnoringComparator;
38
39
40
41
42 public class HttpPostRequestDecoder {
43
44
45
46 private final HttpDataFactory factory;
47
48
49
50
51 private final HttpRequest request;
52
53
54
55
56 private final Charset charset;
57
58
59
60
61 private boolean bodyToDecode;
62
63
64
65
66 private boolean isLastChunk;
67
68
69
70
71 private final List<InterfaceHttpData> bodyListHttpData = new ArrayList<InterfaceHttpData>();
72
73
74
75
76 private final Map<String, List<InterfaceHttpData>> bodyMapHttpData = new TreeMap<String, List<InterfaceHttpData>>(
77 CaseIgnoringComparator.INSTANCE);
78
79
80
81
82 private ChannelBuffer undecodedChunk;
83
84
85
86
87 private boolean isMultipart;
88
89
90
91
92 private int bodyListHttpDataRank;
93
94
95
96
97 private String multipartDataBoundary;
98
99
100
101
102
103 private String multipartMixedBoundary;
104
105
106
107
108 private MultiPartStatus currentStatus = MultiPartStatus.NOTSTARTED;
109
110
111
112
113 private Map<String, Attribute> currentFieldAttributes;
114
115
116
117
118 private FileUpload currentFileUpload;
119
120
121
122
123 private Attribute currentAttribute;
124
125
126
127
128
129
130
131
132 public HttpPostRequestDecoder(HttpRequest request)
133 throws ErrorDataDecoderException, IncompatibleDataDecoderException {
134 this(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE),
135 request, HttpConstants.DEFAULT_CHARSET);
136 }
137
138
139
140
141
142
143
144
145
146 public HttpPostRequestDecoder(HttpDataFactory factory, HttpRequest request)
147 throws ErrorDataDecoderException, IncompatibleDataDecoderException {
148 this(factory, request, HttpConstants.DEFAULT_CHARSET);
149 }
150
151
152
153
154
155
156
157
158
159
160 public HttpPostRequestDecoder(HttpDataFactory factory, HttpRequest request,
161 Charset charset) throws ErrorDataDecoderException,
162 IncompatibleDataDecoderException {
163 if (factory == null) {
164 throw new NullPointerException("factory");
165 }
166 if (request == null) {
167 throw new NullPointerException("request");
168 }
169 if (charset == null) {
170 throw new NullPointerException("charset");
171 }
172 this.request = request;
173 HttpMethod method = request.getMethod();
174 if (method.equals(HttpMethod.POST) || method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PATCH)) {
175 bodyToDecode = true;
176 }
177 this.charset = charset;
178 this.factory = factory;
179
180 if (this.request.containsHeader(HttpHeaders.Names.CONTENT_TYPE)) {
181 checkMultipart(this.request.getHeader(HttpHeaders.Names.CONTENT_TYPE));
182 } else {
183 isMultipart = false;
184 }
185 if (!bodyToDecode) {
186 throw new IncompatibleDataDecoderException("No Body to decode");
187 }
188 if (!this.request.isChunked()) {
189 undecodedChunk = this.request.getContent();
190 isLastChunk = true;
191 parseBody();
192 }
193 }
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232 private enum MultiPartStatus {
233 NOTSTARTED,
234 PREAMBLE,
235 HEADERDELIMITER,
236 DISPOSITION,
237 FIELD,
238 FILEUPLOAD,
239 MIXEDPREAMBLE,
240 MIXEDDELIMITER,
241 MIXEDDISPOSITION,
242 MIXEDFILEUPLOAD,
243 MIXEDCLOSEDELIMITER,
244 CLOSEDELIMITER,
245 PREEPILOGUE,
246 EPILOGUE
247 }
248
249
250
251
252
253
254 private void checkMultipart(String contentType)
255 throws ErrorDataDecoderException {
256
257 String[] headerContentType = splitHeaderContentType(contentType);
258 if (headerContentType[0].toLowerCase().startsWith(
259 HttpHeaders.Values.MULTIPART_FORM_DATA) &&
260 headerContentType[1].toLowerCase().startsWith(
261 HttpHeaders.Values.BOUNDARY)) {
262 String[] boundary = headerContentType[1].split("=");
263 if (boundary.length != 2) {
264 throw new ErrorDataDecoderException("Needs a boundary value");
265 }
266 multipartDataBoundary = "--" + boundary[1];
267 isMultipart = true;
268 currentStatus = MultiPartStatus.HEADERDELIMITER;
269 } else {
270 isMultipart = false;
271 }
272 }
273
274
275
276
277
278 public boolean isMultipart() {
279 return isMultipart;
280 }
281
282
283
284
285
286
287
288
289
290
291 public List<InterfaceHttpData> getBodyHttpDatas()
292 throws NotEnoughDataDecoderException {
293 if (!isLastChunk) {
294 throw new NotEnoughDataDecoderException();
295 }
296 return bodyListHttpData;
297 }
298
299
300
301
302
303
304
305
306
307
308
309 public List<InterfaceHttpData> getBodyHttpDatas(String name)
310 throws NotEnoughDataDecoderException {
311 if (!isLastChunk) {
312 throw new NotEnoughDataDecoderException();
313 }
314 return bodyMapHttpData.get(name);
315 }
316
317
318
319
320
321
322
323
324
325
326
327 public InterfaceHttpData getBodyHttpData(String name)
328 throws NotEnoughDataDecoderException {
329 if (!isLastChunk) {
330 throw new NotEnoughDataDecoderException();
331 }
332 List<InterfaceHttpData> list = bodyMapHttpData.get(name);
333 if (list != null) {
334 return list.get(0);
335 }
336 return null;
337 }
338
339
340
341
342
343
344
345 public void offer(HttpChunk chunk) throws ErrorDataDecoderException {
346 ChannelBuffer chunked = chunk.getContent();
347 if (undecodedChunk == null) {
348 undecodedChunk = chunked;
349 } else {
350
351
352 undecodedChunk = ChannelBuffers.wrappedBuffer(
353 undecodedChunk, chunked);
354 }
355 if (chunk.isLast()) {
356 isLastChunk = true;
357 }
358 parseBody();
359 }
360
361
362
363
364
365
366
367
368
369 public boolean hasNext() throws EndOfDataDecoderException {
370 if (currentStatus == MultiPartStatus.EPILOGUE) {
371
372 if (bodyListHttpDataRank >= bodyListHttpData.size()) {
373 throw new EndOfDataDecoderException();
374 }
375 }
376 return bodyListHttpData.size() > 0 &&
377 bodyListHttpDataRank < bodyListHttpData.size();
378 }
379
380
381
382
383
384
385
386
387 public InterfaceHttpData next() throws EndOfDataDecoderException {
388 if (hasNext()) {
389 return bodyListHttpData.get(bodyListHttpDataRank++);
390 }
391 return null;
392 }
393
394
395
396
397
398
399 private void parseBody() throws ErrorDataDecoderException {
400 if (currentStatus == MultiPartStatus.PREEPILOGUE ||
401 currentStatus == MultiPartStatus.EPILOGUE) {
402 if (isLastChunk) {
403 currentStatus = MultiPartStatus.EPILOGUE;
404 }
405 return;
406 }
407 if (isMultipart) {
408 parseBodyMultipart();
409 } else {
410 parseBodyAttributes();
411 }
412 }
413
414
415
416
417
418 private void addHttpData(InterfaceHttpData data) {
419 if (data == null) {
420 return;
421 }
422 List<InterfaceHttpData> datas = bodyMapHttpData.get(data.getName());
423 if (datas == null) {
424 datas = new ArrayList<InterfaceHttpData>(1);
425 bodyMapHttpData.put(data.getName(), datas);
426 }
427 datas.add(data);
428 bodyListHttpData.add(data);
429 }
430
431
432
433
434
435
436
437
438 private void parseBodyAttributesStandard() throws ErrorDataDecoderException {
439 int firstpos = undecodedChunk.readerIndex();
440 int currentpos = firstpos;
441 int equalpos = firstpos;
442 int ampersandpos = firstpos;
443 if (currentStatus == MultiPartStatus.NOTSTARTED) {
444 currentStatus = MultiPartStatus.DISPOSITION;
445 }
446 boolean contRead = true;
447 try {
448 while (undecodedChunk.readable() && contRead) {
449 char read = (char) undecodedChunk.readUnsignedByte();
450 currentpos++;
451 switch (currentStatus) {
452 case DISPOSITION:
453 if (read == '=') {
454 currentStatus = MultiPartStatus.FIELD;
455 equalpos = currentpos - 1;
456 String key = decodeAttribute(
457 undecodedChunk.toString(firstpos, equalpos - firstpos, charset),
458 charset);
459 currentAttribute = factory.createAttribute(request, key);
460 firstpos = currentpos;
461 } else if (read == '&') {
462 currentStatus = MultiPartStatus.DISPOSITION;
463 ampersandpos = currentpos - 1;
464 String key = decodeAttribute(
465 undecodedChunk.toString(firstpos, ampersandpos - firstpos, charset), charset);
466 currentAttribute = factory.createAttribute(request, key);
467 currentAttribute.setValue("");
468 addHttpData(currentAttribute);
469 currentAttribute = null;
470 firstpos = currentpos;
471 contRead = true;
472 }
473 break;
474 case FIELD:
475 if (read == '&') {
476 currentStatus = MultiPartStatus.DISPOSITION;
477 ampersandpos = currentpos - 1;
478 setFinalBuffer(undecodedChunk.slice(firstpos, ampersandpos - firstpos));
479 firstpos = currentpos;
480 contRead = true;
481 } else if (read == HttpConstants.CR) {
482 if (undecodedChunk.readable()) {
483 read = (char) undecodedChunk.readUnsignedByte();
484 currentpos++;
485 if (read == HttpConstants.LF) {
486 currentStatus = MultiPartStatus.PREEPILOGUE;
487 ampersandpos = currentpos - 2;
488 setFinalBuffer(
489 undecodedChunk.slice(firstpos, ampersandpos - firstpos));
490 firstpos = currentpos;
491 contRead = false;
492 } else {
493
494 contRead = false;
495 throw new ErrorDataDecoderException("Bad end of line");
496 }
497 } else {
498 currentpos--;
499 }
500 } else if (read == HttpConstants.LF) {
501 currentStatus = MultiPartStatus.PREEPILOGUE;
502 ampersandpos = currentpos - 1;
503 setFinalBuffer(
504 undecodedChunk.slice(firstpos, ampersandpos - firstpos));
505 firstpos = currentpos;
506 contRead = false;
507 }
508 break;
509 default:
510
511 contRead = false;
512 }
513 }
514 if (isLastChunk && currentAttribute != null) {
515
516 ampersandpos = currentpos;
517 if (ampersandpos > firstpos) {
518 setFinalBuffer(
519 undecodedChunk.slice(firstpos, ampersandpos - firstpos));
520 } else if (! currentAttribute.isCompleted()) {
521 setFinalBuffer(ChannelBuffers.EMPTY_BUFFER);
522 }
523 firstpos = currentpos;
524 currentStatus = MultiPartStatus.EPILOGUE;
525 return;
526 }
527 if (contRead && currentAttribute != null) {
528
529 if (currentStatus == MultiPartStatus.FIELD) {
530 currentAttribute.addContent(
531 undecodedChunk.slice(firstpos, currentpos - firstpos),
532 false);
533 firstpos = currentpos;
534 }
535 undecodedChunk.readerIndex(firstpos);
536 } else {
537
538 }
539 } catch (ErrorDataDecoderException e) {
540
541 undecodedChunk.readerIndex(firstpos);
542 throw e;
543 } catch (IOException e) {
544
545 undecodedChunk.readerIndex(firstpos);
546 throw new ErrorDataDecoderException(e);
547 }
548 }
549
550
551
552
553
554
555
556
557 private void parseBodyAttributes() throws ErrorDataDecoderException {
558 SeekAheadOptimize sao = null;
559 try {
560 sao = new SeekAheadOptimize(undecodedChunk);
561 } catch (SeekAheadNoBackArrayException e1) {
562 parseBodyAttributesStandard();
563 return;
564 }
565 int firstpos = undecodedChunk.readerIndex();
566 int currentpos = firstpos;
567 int equalpos = firstpos;
568 int ampersandpos = firstpos;
569 if (currentStatus == MultiPartStatus.NOTSTARTED) {
570 currentStatus = MultiPartStatus.DISPOSITION;
571 }
572 boolean contRead = true;
573 try {
574 loop:
575 while (sao.pos < sao.limit) {
576 char read = (char) (sao.bytes[sao.pos ++] & 0xFF);
577 currentpos ++;
578 switch (currentStatus) {
579 case DISPOSITION:
580 if (read == '=') {
581 currentStatus = MultiPartStatus.FIELD;
582 equalpos = currentpos - 1;
583 String key = decodeAttribute(
584 undecodedChunk.toString(firstpos, equalpos - firstpos, charset),
585 charset);
586 currentAttribute = factory.createAttribute(request, key);
587 firstpos = currentpos;
588 } else if (read == '&') {
589 currentStatus = MultiPartStatus.DISPOSITION;
590 ampersandpos = currentpos - 1;
591 String key = decodeAttribute(
592 undecodedChunk.toString(firstpos, ampersandpos - firstpos, charset), charset);
593 currentAttribute = factory.createAttribute(request, key);
594 currentAttribute.setValue("");
595 addHttpData(currentAttribute);
596 currentAttribute = null;
597 firstpos = currentpos;
598 contRead = true;
599 }
600 break;
601 case FIELD:
602 if (read == '&') {
603 currentStatus = MultiPartStatus.DISPOSITION;
604 ampersandpos = currentpos - 1;
605 setFinalBuffer(undecodedChunk.slice(firstpos, ampersandpos - firstpos));
606 firstpos = currentpos;
607 contRead = true;
608 } else if (read == HttpConstants.CR) {
609 if (sao.pos < sao.limit) {
610 read = (char) (sao.bytes[sao.pos ++] & 0xFF);
611 currentpos++;
612 if (read == HttpConstants.LF) {
613 currentStatus = MultiPartStatus.PREEPILOGUE;
614 ampersandpos = currentpos - 2;
615 sao.setReadPosition(0);
616 setFinalBuffer(
617 undecodedChunk.slice(firstpos, ampersandpos - firstpos));
618 firstpos = currentpos;
619 contRead = false;
620 break loop;
621 } else {
622
623 sao.setReadPosition(0);
624 contRead = false;
625 throw new ErrorDataDecoderException("Bad end of line");
626 }
627 } else {
628 if (sao.limit > 0) {
629 currentpos --;
630 }
631 }
632 } else if (read == HttpConstants.LF) {
633 currentStatus = MultiPartStatus.PREEPILOGUE;
634 ampersandpos = currentpos - 1;
635 sao.setReadPosition(0);
636 setFinalBuffer(
637 undecodedChunk.slice(firstpos, ampersandpos - firstpos));
638 firstpos = currentpos;
639 contRead = false;
640 break loop;
641 }
642 break;
643 default:
644
645 sao.setReadPosition(0);
646 contRead = false;
647 break loop;
648 }
649 }
650 if (isLastChunk && currentAttribute != null) {
651
652 ampersandpos = currentpos;
653 if (ampersandpos > firstpos) {
654 setFinalBuffer(
655 undecodedChunk.slice(firstpos, ampersandpos - firstpos));
656 } else if (! currentAttribute.isCompleted()) {
657 setFinalBuffer(ChannelBuffers.EMPTY_BUFFER);
658 }
659 firstpos = currentpos;
660 currentStatus = MultiPartStatus.EPILOGUE;
661 return;
662 }
663 if (contRead && currentAttribute != null) {
664
665 if (currentStatus == MultiPartStatus.FIELD) {
666 currentAttribute.addContent(
667 undecodedChunk.slice(firstpos, currentpos - firstpos),
668 false);
669 firstpos = currentpos;
670 }
671 undecodedChunk.readerIndex(firstpos);
672 } else {
673
674 }
675 } catch (ErrorDataDecoderException e) {
676
677 undecodedChunk.readerIndex(firstpos);
678 throw e;
679 } catch (IOException e) {
680
681 undecodedChunk.readerIndex(firstpos);
682 throw new ErrorDataDecoderException(e);
683 }
684 }
685
686 private void setFinalBuffer(ChannelBuffer buffer) throws ErrorDataDecoderException, IOException {
687 currentAttribute.addContent(buffer, true);
688 String value = decodeAttribute(
689 currentAttribute.getChannelBuffer().toString(charset),
690 charset);
691 currentAttribute.setValue(value);
692 addHttpData(currentAttribute);
693 currentAttribute = null;
694 }
695
696
697
698
699
700
701
702
703 private static String decodeAttribute(String s, Charset charset)
704 throws ErrorDataDecoderException {
705 if (s == null) {
706 return "";
707 }
708 try {
709 return URLDecoder.decode(s, charset.name());
710 } catch (UnsupportedEncodingException e) {
711 throw new ErrorDataDecoderException(charset.toString(), e);
712 } catch (IllegalArgumentException e) {
713 throw new ErrorDataDecoderException("Bad string: '" + s + "'", e);
714 }
715 }
716
717
718
719
720
721
722 private void parseBodyMultipart() throws ErrorDataDecoderException {
723 if (undecodedChunk == null || undecodedChunk.readableBytes() == 0) {
724
725 return;
726 }
727 InterfaceHttpData data = decodeMultipart(currentStatus);
728 while (data != null) {
729 addHttpData(data);
730 if (currentStatus == MultiPartStatus.PREEPILOGUE ||
731 currentStatus == MultiPartStatus.EPILOGUE) {
732 break;
733 }
734 data = decodeMultipart(currentStatus);
735 }
736 }
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754 private InterfaceHttpData decodeMultipart(MultiPartStatus state)
755 throws ErrorDataDecoderException {
756 switch (state) {
757 case NOTSTARTED:
758 throw new ErrorDataDecoderException(
759 "Should not be called with the current status");
760 case PREAMBLE:
761
762 throw new ErrorDataDecoderException(
763 "Should not be called with the current status");
764 case HEADERDELIMITER: {
765
766 return findMultipartDelimiter(multipartDataBoundary,
767 MultiPartStatus.DISPOSITION, MultiPartStatus.PREEPILOGUE);
768 }
769 case DISPOSITION: {
770
771
772
773
774
775
776
777
778
779 return findMultipartDisposition();
780 }
781 case FIELD: {
782
783 Charset localCharset = null;
784 Attribute charsetAttribute = currentFieldAttributes
785 .get(HttpHeaders.Values.CHARSET);
786 if (charsetAttribute != null) {
787 try {
788 localCharset = Charset.forName(charsetAttribute.getValue());
789 } catch (IOException e) {
790 throw new ErrorDataDecoderException(e);
791 }
792 }
793 Attribute nameAttribute = currentFieldAttributes
794 .get(HttpPostBodyUtil.NAME);
795 if (currentAttribute == null) {
796 try {
797 currentAttribute = factory.createAttribute(request, nameAttribute
798 .getValue());
799 } catch (NullPointerException e) {
800 throw new ErrorDataDecoderException(e);
801 } catch (IllegalArgumentException e) {
802 throw new ErrorDataDecoderException(e);
803 } catch (IOException e) {
804 throw new ErrorDataDecoderException(e);
805 }
806 if (localCharset != null) {
807 currentAttribute.setCharset(localCharset);
808 }
809 }
810
811 try {
812 loadFieldMultipart(multipartDataBoundary);
813 } catch (NotEnoughDataDecoderException e) {
814 return null;
815 }
816 Attribute finalAttribute = currentAttribute;
817 currentAttribute = null;
818 currentFieldAttributes = null;
819
820 currentStatus = MultiPartStatus.HEADERDELIMITER;
821 return finalAttribute;
822 }
823 case FILEUPLOAD: {
824
825 return getFileUpload(multipartDataBoundary);
826 }
827 case MIXEDDELIMITER: {
828
829
830 return findMultipartDelimiter(multipartMixedBoundary,
831 MultiPartStatus.MIXEDDISPOSITION,
832 MultiPartStatus.HEADERDELIMITER);
833 }
834 case MIXEDDISPOSITION: {
835 return findMultipartDisposition();
836 }
837 case MIXEDFILEUPLOAD: {
838
839 return getFileUpload(multipartMixedBoundary);
840 }
841 case PREEPILOGUE:
842 return null;
843 case EPILOGUE:
844 return null;
845 default:
846 throw new ErrorDataDecoderException("Shouldn't reach here.");
847 }
848 }
849
850
851
852
853 void skipControlCharacters() {
854 SeekAheadOptimize sao = null;
855 try {
856 sao = new SeekAheadOptimize(undecodedChunk);
857 } catch (SeekAheadNoBackArrayException e) {
858 skipControlCharactersStandard(undecodedChunk);
859 return;
860 }
861
862 while (sao.pos < sao.limit) {
863 char c = (char) (sao.bytes[sao.pos ++] & 0xFF);
864 if (!Character.isISOControl(c) && !Character.isWhitespace(c)) {
865 sao.setReadPosition(1);
866 return;
867 }
868 }
869 sao.setReadPosition(0);
870 }
871 static void skipControlCharactersStandard(ChannelBuffer buffer) {
872 for (;;) {
873 char c = (char) buffer.readUnsignedByte();
874 if (!Character.isISOControl(c) && !Character.isWhitespace(c)) {
875 buffer.readerIndex(buffer.readerIndex() - 1);
876 break;
877 }
878 }
879 }
880
881
882
883
884
885
886
887
888
889 private InterfaceHttpData findMultipartDelimiter(String delimiter,
890 MultiPartStatus dispositionStatus,
891 MultiPartStatus closeDelimiterStatus)
892 throws ErrorDataDecoderException {
893
894 int readerIndex = undecodedChunk.readerIndex();
895 skipControlCharacters();
896 skipOneLine();
897 String newline;
898 try {
899 newline = readDelimiter(delimiter);
900 } catch (NotEnoughDataDecoderException e) {
901 undecodedChunk.readerIndex(readerIndex);
902 return null;
903 }
904 if (newline.equals(delimiter)) {
905 currentStatus = dispositionStatus;
906 return decodeMultipart(dispositionStatus);
907 } else if (newline.equals(delimiter + "--")) {
908
909 currentStatus = closeDelimiterStatus;
910 if (currentStatus == MultiPartStatus.HEADERDELIMITER) {
911
912
913 currentFieldAttributes = null;
914 return decodeMultipart(MultiPartStatus.HEADERDELIMITER);
915 }
916 return null;
917 }
918 undecodedChunk.readerIndex(readerIndex);
919 throw new ErrorDataDecoderException("No Multipart delimiter found");
920 }
921
922
923
924
925
926
927 private InterfaceHttpData findMultipartDisposition()
928 throws ErrorDataDecoderException {
929 int readerIndex = undecodedChunk.readerIndex();
930 if (currentStatus == MultiPartStatus.DISPOSITION) {
931 currentFieldAttributes = new TreeMap<String, Attribute>(
932 CaseIgnoringComparator.INSTANCE);
933 }
934
935 while (!skipOneLine()) {
936 skipControlCharacters();
937 String newline;
938 try {
939 newline = readLine();
940 } catch (NotEnoughDataDecoderException e) {
941 undecodedChunk.readerIndex(readerIndex);
942 return null;
943 }
944 String[] contents = splitMultipartHeader(newline);
945 if (contents[0].equalsIgnoreCase(HttpPostBodyUtil.CONTENT_DISPOSITION)) {
946 boolean checkSecondArg = false;
947 if (currentStatus == MultiPartStatus.DISPOSITION) {
948 checkSecondArg = contents[1]
949 .equalsIgnoreCase(HttpPostBodyUtil.FORM_DATA);
950 } else {
951 checkSecondArg = contents[1]
952 .equalsIgnoreCase(HttpPostBodyUtil.ATTACHMENT) ||
953 contents[1]
954 .equalsIgnoreCase(HttpPostBodyUtil.FILE);
955 }
956 if (checkSecondArg) {
957
958 for (int i = 2; i < contents.length; i ++) {
959 String[] values = contents[i].split("=");
960 Attribute attribute;
961 try {
962 attribute = factory.createAttribute(request, values[0].trim(),
963 decodeAttribute(cleanString(values[1]), charset));
964 } catch (NullPointerException e) {
965 throw new ErrorDataDecoderException(e);
966 } catch (IllegalArgumentException e) {
967 throw new ErrorDataDecoderException(e);
968 }
969 currentFieldAttributes.put(attribute.getName(),
970 attribute);
971 }
972 }
973 } else if (contents[0]
974 .equalsIgnoreCase(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING)) {
975 Attribute attribute;
976 try {
977 attribute = factory.createAttribute(request,
978 HttpHeaders.Names.CONTENT_TRANSFER_ENCODING,
979 cleanString(contents[1]));
980 } catch (NullPointerException e) {
981 throw new ErrorDataDecoderException(e);
982 } catch (IllegalArgumentException e) {
983 throw new ErrorDataDecoderException(e);
984 }
985 currentFieldAttributes.put(
986 HttpHeaders.Names.CONTENT_TRANSFER_ENCODING, attribute);
987 } else if (contents[0]
988 .equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH)) {
989 Attribute attribute;
990 try {
991 attribute = factory.createAttribute(request,
992 HttpHeaders.Names.CONTENT_LENGTH,
993 cleanString(contents[1]));
994 } catch (NullPointerException e) {
995 throw new ErrorDataDecoderException(e);
996 } catch (IllegalArgumentException e) {
997 throw new ErrorDataDecoderException(e);
998 }
999 currentFieldAttributes.put(HttpHeaders.Names.CONTENT_LENGTH,
1000 attribute);
1001 } else if (contents[0].equalsIgnoreCase(HttpHeaders.Names.CONTENT_TYPE)) {
1002
1003 if (contents[1].equalsIgnoreCase(HttpPostBodyUtil.MULTIPART_MIXED)) {
1004 if (currentStatus == MultiPartStatus.DISPOSITION) {
1005 String[] values = contents[2].split("=");
1006 multipartMixedBoundary = "--" + values[1];
1007 currentStatus = MultiPartStatus.MIXEDDELIMITER;
1008 return decodeMultipart(MultiPartStatus.MIXEDDELIMITER);
1009 } else {
1010 throw new ErrorDataDecoderException(
1011 "Mixed Multipart found in a previous Mixed Multipart");
1012 }
1013 } else {
1014 for (int i = 1; i < contents.length; i ++) {
1015 if (contents[i].toLowerCase().startsWith(
1016 HttpHeaders.Values.CHARSET)) {
1017 String[] values = contents[i].split("=");
1018 Attribute attribute;
1019 try {
1020 attribute = factory.createAttribute(request,
1021 HttpHeaders.Values.CHARSET,
1022 cleanString(values[1]));
1023 } catch (NullPointerException e) {
1024 throw new ErrorDataDecoderException(e);
1025 } catch (IllegalArgumentException e) {
1026 throw new ErrorDataDecoderException(e);
1027 }
1028 currentFieldAttributes.put(HttpHeaders.Values.CHARSET,
1029 attribute);
1030 } else {
1031 Attribute attribute;
1032 try {
1033 attribute = factory.createAttribute(request,
1034 contents[0].trim(),
1035 decodeAttribute(cleanString(contents[i]), charset));
1036 } catch (NullPointerException e) {
1037 throw new ErrorDataDecoderException(e);
1038 } catch (IllegalArgumentException e) {
1039 throw new ErrorDataDecoderException(e);
1040 }
1041 currentFieldAttributes.put(attribute.getName(),
1042 attribute);
1043 }
1044 }
1045 }
1046 } else {
1047 throw new ErrorDataDecoderException("Unknown Params: " +
1048 newline);
1049 }
1050 }
1051
1052 Attribute filenameAttribute = currentFieldAttributes
1053 .get(HttpPostBodyUtil.FILENAME);
1054 if (currentStatus == MultiPartStatus.DISPOSITION) {
1055 if (filenameAttribute != null) {
1056
1057 currentStatus = MultiPartStatus.FILEUPLOAD;
1058
1059 return decodeMultipart(MultiPartStatus.FILEUPLOAD);
1060 } else {
1061
1062 currentStatus = MultiPartStatus.FIELD;
1063
1064 return decodeMultipart(MultiPartStatus.FIELD);
1065 }
1066 } else {
1067 if (filenameAttribute != null) {
1068
1069 currentStatus = MultiPartStatus.MIXEDFILEUPLOAD;
1070
1071 return decodeMultipart(MultiPartStatus.MIXEDFILEUPLOAD);
1072 } else {
1073
1074 throw new ErrorDataDecoderException("Filename not found");
1075 }
1076 }
1077 }
1078
1079
1080
1081
1082
1083
1084
1085 private InterfaceHttpData getFileUpload(String delimiter)
1086 throws ErrorDataDecoderException {
1087
1088
1089 Attribute encoding = currentFieldAttributes
1090 .get(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING);
1091 Charset localCharset = charset;
1092
1093 TransferEncodingMechanism mechanism = TransferEncodingMechanism.BIT7;
1094 if (encoding != null) {
1095 String code;
1096 try {
1097 code = encoding.getValue().toLowerCase();
1098 } catch (IOException e) {
1099 throw new ErrorDataDecoderException(e);
1100 }
1101 if (code.equals(HttpPostBodyUtil.TransferEncodingMechanism.BIT7.value)) {
1102 localCharset = HttpPostBodyUtil.US_ASCII;
1103 } else if (code.equals(HttpPostBodyUtil.TransferEncodingMechanism.BIT8.value)) {
1104 localCharset = HttpPostBodyUtil.ISO_8859_1;
1105 mechanism = TransferEncodingMechanism.BIT8;
1106 } else if (code
1107 .equals(HttpPostBodyUtil.TransferEncodingMechanism.BINARY.value)) {
1108
1109 mechanism = TransferEncodingMechanism.BINARY;
1110 } else {
1111 throw new ErrorDataDecoderException(
1112 "TransferEncoding Unknown: " + code);
1113 }
1114 }
1115 Attribute charsetAttribute = currentFieldAttributes
1116 .get(HttpHeaders.Values.CHARSET);
1117 if (charsetAttribute != null) {
1118 try {
1119 localCharset = Charset.forName(charsetAttribute.getValue());
1120 } catch (IOException e) {
1121 throw new ErrorDataDecoderException(e);
1122 }
1123 }
1124 if (currentFileUpload == null) {
1125 Attribute filenameAttribute = currentFieldAttributes
1126 .get(HttpPostBodyUtil.FILENAME);
1127 Attribute nameAttribute = currentFieldAttributes
1128 .get(HttpPostBodyUtil.NAME);
1129 Attribute contentTypeAttribute = currentFieldAttributes
1130 .get(HttpHeaders.Names.CONTENT_TYPE);
1131 if (contentTypeAttribute == null) {
1132 throw new ErrorDataDecoderException(
1133 "Content-Type is absent but required");
1134 }
1135 Attribute lengthAttribute = currentFieldAttributes
1136 .get(HttpHeaders.Names.CONTENT_LENGTH);
1137 long size;
1138 try {
1139 size = lengthAttribute != null? Long.parseLong(lengthAttribute
1140 .getValue()) : 0L;
1141 } catch (IOException e) {
1142 throw new ErrorDataDecoderException(e);
1143 } catch (NumberFormatException e) {
1144 size = 0;
1145 }
1146 try {
1147 currentFileUpload = factory.createFileUpload(
1148 request,
1149 nameAttribute.getValue(), filenameAttribute.getValue(),
1150 contentTypeAttribute.getValue(), mechanism.value,
1151 localCharset, size);
1152 } catch (NullPointerException e) {
1153 throw new ErrorDataDecoderException(e);
1154 } catch (IllegalArgumentException e) {
1155 throw new ErrorDataDecoderException(e);
1156 } catch (IOException e) {
1157 throw new ErrorDataDecoderException(e);
1158 }
1159 }
1160
1161 try {
1162 readFileUploadByteMultipart(delimiter);
1163 } catch (NotEnoughDataDecoderException e) {
1164
1165
1166
1167 return null;
1168 }
1169 if (currentFileUpload.isCompleted()) {
1170
1171 if (currentStatus == MultiPartStatus.FILEUPLOAD) {
1172 currentStatus = MultiPartStatus.HEADERDELIMITER;
1173 currentFieldAttributes = null;
1174 } else {
1175 currentStatus = MultiPartStatus.MIXEDDELIMITER;
1176 cleanMixedAttributes();
1177 }
1178 FileUpload fileUpload = currentFileUpload;
1179 currentFileUpload = null;
1180 return fileUpload;
1181 }
1182
1183
1184
1185 return null;
1186 }
1187
1188
1189
1190
1191 public void cleanFiles() {
1192 factory.cleanRequestHttpDatas(request);
1193 }
1194
1195
1196
1197
1198 public void removeHttpDataFromClean(InterfaceHttpData data) {
1199 factory.removeHttpDataFromClean(request, data);
1200 }
1201
1202
1203
1204
1205 private void cleanMixedAttributes() {
1206 currentFieldAttributes.remove(HttpHeaders.Values.CHARSET);
1207 currentFieldAttributes.remove(HttpHeaders.Names.CONTENT_LENGTH);
1208 currentFieldAttributes.remove(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING);
1209 currentFieldAttributes.remove(HttpHeaders.Names.CONTENT_TYPE);
1210 currentFieldAttributes.remove(HttpPostBodyUtil.FILENAME);
1211 }
1212
1213
1214
1215
1216
1217
1218
1219 private String readLineStandard() throws NotEnoughDataDecoderException {
1220 int readerIndex = undecodedChunk.readerIndex();
1221 try {
1222 StringBuilder sb = new StringBuilder(64);
1223 while (undecodedChunk.readable()) {
1224 byte nextByte = undecodedChunk.readByte();
1225 if (nextByte == HttpConstants.CR) {
1226 nextByte = undecodedChunk.readByte();
1227 if (nextByte == HttpConstants.LF) {
1228 return sb.toString();
1229 }
1230 } else if (nextByte == HttpConstants.LF) {
1231 return sb.toString();
1232 } else {
1233 sb.append((char) nextByte);
1234 }
1235 }
1236 } catch (IndexOutOfBoundsException e) {
1237 undecodedChunk.readerIndex(readerIndex);
1238 throw new NotEnoughDataDecoderException(e);
1239 }
1240 undecodedChunk.readerIndex(readerIndex);
1241 throw new NotEnoughDataDecoderException();
1242 }
1243
1244
1245
1246
1247
1248
1249 private String readLine() throws NotEnoughDataDecoderException {
1250 SeekAheadOptimize sao = null;
1251 try {
1252 sao = new SeekAheadOptimize(undecodedChunk);
1253 } catch (SeekAheadNoBackArrayException e1) {
1254 return readLineStandard();
1255 }
1256 int readerIndex = undecodedChunk.readerIndex();
1257 try {
1258 StringBuilder sb = new StringBuilder(64);
1259 while (sao.pos < sao.limit) {
1260 byte nextByte = sao.bytes[sao.pos ++];
1261 if (nextByte == HttpConstants.CR) {
1262 if (sao.pos < sao.limit) {
1263 nextByte = sao.bytes[sao.pos ++];
1264 if (nextByte == HttpConstants.LF) {
1265 sao.setReadPosition(0);
1266 return sb.toString();
1267 }
1268 } else {
1269 sb.append((char) nextByte);
1270 }
1271 } else if (nextByte == HttpConstants.LF) {
1272 sao.setReadPosition(0);
1273 return sb.toString();
1274 } else {
1275 sb.append((char) nextByte);
1276 }
1277 }
1278 } catch (IndexOutOfBoundsException e) {
1279 undecodedChunk.readerIndex(readerIndex);
1280 throw new NotEnoughDataDecoderException(e);
1281 }
1282 undecodedChunk.readerIndex(readerIndex);
1283 throw new NotEnoughDataDecoderException();
1284 }
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297 private String readDelimiterStandard(String delimiter) throws NotEnoughDataDecoderException {
1298 int readerIndex = undecodedChunk.readerIndex();
1299 try {
1300 StringBuilder sb = new StringBuilder(64);
1301 int delimiterPos = 0;
1302 int len = delimiter.length();
1303 while (undecodedChunk.readable() && delimiterPos < len) {
1304 byte nextByte = undecodedChunk.readByte();
1305 if (nextByte == delimiter.charAt(delimiterPos)) {
1306 delimiterPos++;
1307 sb.append((char) nextByte);
1308 } else {
1309
1310 undecodedChunk.readerIndex(readerIndex);
1311 throw new NotEnoughDataDecoderException();
1312 }
1313 }
1314
1315 if (undecodedChunk.readable()) {
1316 byte nextByte = undecodedChunk.readByte();
1317
1318 if (nextByte == HttpConstants.CR) {
1319 nextByte = undecodedChunk.readByte();
1320 if (nextByte == HttpConstants.LF) {
1321 return sb.toString();
1322 } else {
1323
1324
1325 undecodedChunk.readerIndex(readerIndex);
1326 throw new NotEnoughDataDecoderException();
1327 }
1328 } else if (nextByte == HttpConstants.LF) {
1329 return sb.toString();
1330 } else if (nextByte == '-') {
1331 sb.append((char) nextByte);
1332
1333 nextByte = undecodedChunk.readByte();
1334 if (nextByte == '-') {
1335 sb.append((char) nextByte);
1336
1337 if (undecodedChunk.readable()) {
1338 nextByte = undecodedChunk.readByte();
1339 if (nextByte == HttpConstants.CR) {
1340 nextByte = undecodedChunk.readByte();
1341 if (nextByte == HttpConstants.LF) {
1342 return sb.toString();
1343 } else {
1344
1345
1346 undecodedChunk.readerIndex(readerIndex);
1347 throw new NotEnoughDataDecoderException();
1348 }
1349 } else if (nextByte == HttpConstants.LF) {
1350 return sb.toString();
1351 } else {
1352
1353
1354 undecodedChunk.readerIndex(undecodedChunk.readerIndex() - 1);
1355 return sb.toString();
1356 }
1357 }
1358
1359
1360
1361 return sb.toString();
1362 }
1363
1364
1365 }
1366 }
1367 } catch (IndexOutOfBoundsException e) {
1368 undecodedChunk.readerIndex(readerIndex);
1369 throw new NotEnoughDataDecoderException(e);
1370 }
1371 undecodedChunk.readerIndex(readerIndex);
1372 throw new NotEnoughDataDecoderException();
1373 }
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385 private String readDelimiter(String delimiter) throws NotEnoughDataDecoderException {
1386 SeekAheadOptimize sao = null;
1387 try {
1388 sao = new SeekAheadOptimize(undecodedChunk);
1389 } catch (SeekAheadNoBackArrayException e1) {
1390 return readDelimiterStandard(delimiter);
1391 }
1392 int readerIndex = undecodedChunk.readerIndex();
1393 int delimiterPos = 0;
1394 int len = delimiter.length();
1395 try {
1396 StringBuilder sb = new StringBuilder(64);
1397
1398 while (sao.pos < sao.limit && delimiterPos < len) {
1399 byte nextByte = sao.bytes[sao.pos ++];
1400 if (nextByte == delimiter.charAt(delimiterPos)) {
1401 delimiterPos++;
1402 sb.append((char) nextByte);
1403 } else {
1404
1405 undecodedChunk.readerIndex(readerIndex);
1406 throw new NotEnoughDataDecoderException();
1407 }
1408 }
1409
1410 if (sao.pos < sao.limit) {
1411 byte nextByte = sao.bytes[sao.pos ++];
1412 if (nextByte == HttpConstants.CR) {
1413
1414 if (sao.pos < sao.limit) {
1415 nextByte = sao.bytes[sao.pos ++];
1416 if (nextByte == HttpConstants.LF) {
1417 sao.setReadPosition(0);
1418 return sb.toString();
1419 }
1420 } else {
1421
1422
1423 undecodedChunk.readerIndex(readerIndex);
1424 throw new NotEnoughDataDecoderException();
1425 }
1426 } else if (nextByte == HttpConstants.LF) {
1427
1428 sao.setReadPosition(0);
1429 return sb.toString();
1430 } else if (nextByte == '-') {
1431 sb.append((char) nextByte);
1432
1433 if (sao.pos < sao.limit) {
1434 nextByte = sao.bytes[sao.pos ++];
1435 if (nextByte == '-') {
1436 sb.append((char) nextByte);
1437
1438 if (sao.pos < sao.limit) {
1439 nextByte = sao.bytes[sao.pos++];
1440 if (nextByte == HttpConstants.CR) {
1441 if (sao.pos < sao.limit) {
1442 nextByte = sao.bytes[sao.pos++];
1443 if (nextByte == HttpConstants.LF) {
1444 sao.setReadPosition(0);
1445 return sb.toString();
1446 }
1447 } else {
1448
1449
1450 undecodedChunk.readerIndex(readerIndex);
1451 throw new NotEnoughDataDecoderException();
1452 }
1453 } else if (nextByte == HttpConstants.LF) {
1454 sao.setReadPosition(0);
1455 return sb.toString();
1456 } else {
1457
1458
1459 sao.setReadPosition(1);
1460 return sb.toString();
1461 }
1462 }
1463
1464
1465
1466 sao.setReadPosition(0);
1467 return sb.toString();
1468 }
1469
1470
1471 }
1472 }
1473 }
1474 } catch (IndexOutOfBoundsException e) {
1475 undecodedChunk.readerIndex(readerIndex);
1476 throw new NotEnoughDataDecoderException(e);
1477 }
1478 undecodedChunk.readerIndex(readerIndex);
1479 throw new NotEnoughDataDecoderException();
1480 }
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490 private void readFileUploadByteMultipartStandard(String delimiter)
1491 throws NotEnoughDataDecoderException, ErrorDataDecoderException {
1492 int readerIndex = undecodedChunk.readerIndex();
1493
1494 boolean newLine = true;
1495 int index = 0;
1496 int lastPosition = undecodedChunk.readerIndex();
1497 boolean found = false;
1498 while (undecodedChunk.readable()) {
1499 byte nextByte = undecodedChunk.readByte();
1500 if (newLine) {
1501
1502 if (nextByte == delimiter.codePointAt(index)) {
1503 index ++;
1504 if (delimiter.length() == index) {
1505 found = true;
1506 break;
1507 }
1508 continue;
1509 } else {
1510 newLine = false;
1511 index = 0;
1512
1513 if (nextByte == HttpConstants.CR) {
1514 if (undecodedChunk.readable()) {
1515 nextByte = undecodedChunk.readByte();
1516 if (nextByte == HttpConstants.LF) {
1517 newLine = true;
1518 index = 0;
1519 lastPosition = undecodedChunk.readerIndex() - 2;
1520 }
1521 }
1522 } else if (nextByte == HttpConstants.LF) {
1523 newLine = true;
1524 index = 0;
1525 lastPosition = undecodedChunk.readerIndex() - 1;
1526 } else {
1527
1528 lastPosition = undecodedChunk.readerIndex();
1529 }
1530 }
1531 } else {
1532
1533 if (nextByte == HttpConstants.CR) {
1534 if (undecodedChunk.readable()) {
1535 nextByte = undecodedChunk.readByte();
1536 if (nextByte == HttpConstants.LF) {
1537 newLine = true;
1538 index = 0;
1539 lastPosition = undecodedChunk.readerIndex() - 2;
1540 }
1541 }
1542 } else if (nextByte == HttpConstants.LF) {
1543 newLine = true;
1544 index = 0;
1545 lastPosition = undecodedChunk.readerIndex() - 1;
1546 } else {
1547
1548 lastPosition = undecodedChunk.readerIndex();
1549 }
1550 }
1551 }
1552 ChannelBuffer buffer = undecodedChunk.slice(readerIndex, lastPosition -
1553 readerIndex);
1554 if (found) {
1555
1556 try {
1557 currentFileUpload.addContent(buffer, true);
1558
1559 undecodedChunk.readerIndex(lastPosition);
1560 } catch (IOException e) {
1561 throw new ErrorDataDecoderException(e);
1562 }
1563 } else {
1564
1565 try {
1566 currentFileUpload.addContent(buffer, false);
1567
1568 undecodedChunk.readerIndex(lastPosition);
1569 throw new NotEnoughDataDecoderException();
1570 } catch (IOException e) {
1571 throw new ErrorDataDecoderException(e);
1572 }
1573 }
1574 }
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584 private void readFileUploadByteMultipart(String delimiter)
1585 throws NotEnoughDataDecoderException, ErrorDataDecoderException {
1586 SeekAheadOptimize sao = null;
1587 try {
1588 sao = new SeekAheadOptimize(undecodedChunk);
1589 } catch (SeekAheadNoBackArrayException e1) {
1590 readFileUploadByteMultipartStandard(delimiter);
1591 return;
1592 }
1593 int readerIndex = undecodedChunk.readerIndex();
1594
1595 boolean newLine = true;
1596 int index = 0;
1597 int lastPosition = undecodedChunk.readerIndex();
1598 int setReadPosition = -1;
1599 boolean found = false;
1600
1601 while (sao.pos < sao.limit) {
1602 byte nextByte = sao.bytes[sao.pos ++];
1603 if (newLine) {
1604
1605 if (nextByte == delimiter.codePointAt(index)) {
1606 index ++;
1607 if (delimiter.length() == index) {
1608 found = true;
1609 sao.setReadPosition(0);
1610 break;
1611 }
1612 continue;
1613 } else {
1614 newLine = false;
1615 index = 0;
1616
1617 if (nextByte == HttpConstants.CR) {
1618 if (sao.pos < sao.limit) {
1619 nextByte = sao.bytes[sao.pos ++];
1620 if (nextByte == HttpConstants.LF) {
1621 newLine = true;
1622 index = 0;
1623 setReadPosition = sao.pos;
1624 lastPosition = sao.pos - 2;
1625 }
1626 } else {
1627
1628 setReadPosition = sao.pos;
1629 lastPosition = sao.pos;
1630 }
1631 } else if (nextByte == HttpConstants.LF) {
1632 newLine = true;
1633 index = 0;
1634 setReadPosition = sao.pos;
1635 lastPosition = sao.pos - 1;
1636 } else {
1637
1638 setReadPosition = sao.pos;
1639 lastPosition = sao.pos;
1640 }
1641 }
1642 } else {
1643
1644 if (nextByte == HttpConstants.CR) {
1645 if (sao.pos < sao.limit) {
1646 nextByte = sao.bytes[sao.pos ++];
1647 if (nextByte == HttpConstants.LF) {
1648 newLine = true;
1649 index = 0;
1650 setReadPosition = sao.pos;
1651 lastPosition = sao.pos - 2;
1652 }
1653 } else {
1654
1655 setReadPosition = sao.pos;
1656 lastPosition = sao.pos;
1657 }
1658 } else if (nextByte == HttpConstants.LF) {
1659 newLine = true;
1660 index = 0;
1661 setReadPosition = sao.pos;
1662 lastPosition = sao.pos - 1;
1663 } else {
1664
1665 setReadPosition = sao.pos;
1666 lastPosition = sao.pos;
1667 }
1668 }
1669 }
1670 if (setReadPosition > 0) {
1671 sao.pos = setReadPosition;
1672 sao.setReadPosition(0);
1673 }
1674 ChannelBuffer buffer = undecodedChunk.slice(readerIndex, lastPosition - readerIndex);
1675 if (found) {
1676
1677 try {
1678 currentFileUpload.addContent(buffer, true);
1679
1680 undecodedChunk.readerIndex(lastPosition);
1681 } catch (IOException e) {
1682 throw new ErrorDataDecoderException(e);
1683 }
1684 } else {
1685
1686 try {
1687 currentFileUpload.addContent(buffer, false);
1688
1689 undecodedChunk.readerIndex(lastPosition);
1690 throw new NotEnoughDataDecoderException();
1691 } catch (IOException e) {
1692 throw new ErrorDataDecoderException(e);
1693 }
1694 }
1695 }
1696
1697
1698
1699
1700
1701
1702 private void loadFieldMultipartStandard(String delimiter)
1703 throws NotEnoughDataDecoderException, ErrorDataDecoderException {
1704 int readerIndex = undecodedChunk.readerIndex();
1705 try {
1706
1707 boolean newLine = true;
1708 int index = 0;
1709 int lastPosition = undecodedChunk.readerIndex();
1710 boolean found = false;
1711 while (undecodedChunk.readable()) {
1712 byte nextByte = undecodedChunk.readByte();
1713 if (newLine) {
1714
1715 if (nextByte == delimiter.codePointAt(index)) {
1716 index ++;
1717 if (delimiter.length() == index) {
1718 found = true;
1719 break;
1720 }
1721 continue;
1722 } else {
1723 newLine = false;
1724 index = 0;
1725
1726 if (nextByte == HttpConstants.CR) {
1727 if (undecodedChunk.readable()) {
1728 nextByte = undecodedChunk.readByte();
1729 if (nextByte == HttpConstants.LF) {
1730 newLine = true;
1731 index = 0;
1732 lastPosition = undecodedChunk.readerIndex() - 2;
1733 }
1734 }
1735 } else if (nextByte == HttpConstants.LF) {
1736 newLine = true;
1737 index = 0;
1738 lastPosition = undecodedChunk.readerIndex() - 1;
1739 } else {
1740 lastPosition = undecodedChunk.readerIndex();
1741 }
1742 }
1743 } else {
1744
1745 if (nextByte == HttpConstants.CR) {
1746 if (undecodedChunk.readable()) {
1747 nextByte = undecodedChunk.readByte();
1748 if (nextByte == HttpConstants.LF) {
1749 newLine = true;
1750 index = 0;
1751 lastPosition = undecodedChunk.readerIndex() - 2;
1752 }
1753 }
1754 } else if (nextByte == HttpConstants.LF) {
1755 newLine = true;
1756 index = 0;
1757 lastPosition = undecodedChunk.readerIndex() - 1;
1758 } else {
1759 lastPosition = undecodedChunk.readerIndex();
1760 }
1761 }
1762 }
1763 if (found) {
1764
1765
1766
1767 try {
1768 currentAttribute.addContent(
1769 undecodedChunk.slice(readerIndex, lastPosition - readerIndex),
1770 true);
1771 } catch (IOException e) {
1772 throw new ErrorDataDecoderException(e);
1773 }
1774 undecodedChunk.readerIndex(lastPosition);
1775 } else {
1776 try {
1777 currentAttribute.addContent(
1778 undecodedChunk.slice(readerIndex, lastPosition - readerIndex),
1779 false);
1780 } catch (IOException e) {
1781 throw new ErrorDataDecoderException(e);
1782 }
1783 undecodedChunk.readerIndex(lastPosition);
1784 throw new NotEnoughDataDecoderException();
1785 }
1786 } catch (IndexOutOfBoundsException e) {
1787 undecodedChunk.readerIndex(readerIndex);
1788 throw new NotEnoughDataDecoderException(e);
1789 }
1790 }
1791
1792
1793
1794
1795
1796
1797 private void loadFieldMultipart(String delimiter)
1798 throws NotEnoughDataDecoderException, ErrorDataDecoderException {
1799 SeekAheadOptimize sao = null;
1800 try {
1801 sao = new SeekAheadOptimize(undecodedChunk);
1802 } catch (SeekAheadNoBackArrayException e1) {
1803 loadFieldMultipartStandard(delimiter);
1804 return;
1805 }
1806 int readerIndex = undecodedChunk.readerIndex();
1807 try {
1808
1809 boolean newLine = true;
1810 int index = 0;
1811 int lastPosition = undecodedChunk.readerIndex();
1812 int setReadPosition = -1;
1813 boolean found = false;
1814
1815 while (sao.pos < sao.limit) {
1816 byte nextByte = sao.bytes[sao.pos ++];
1817 if (newLine) {
1818
1819 if (nextByte == delimiter.codePointAt(index)) {
1820 index ++;
1821 if (delimiter.length() == index) {
1822 found = true;
1823 sao.setReadPosition(0);
1824 break;
1825 }
1826 continue;
1827 } else {
1828 newLine = false;
1829 index = 0;
1830
1831 if (nextByte == HttpConstants.CR) {
1832 if (sao.pos < sao.limit) {
1833 nextByte = sao.bytes[sao.pos ++];
1834 if (nextByte == HttpConstants.LF) {
1835 newLine = true;
1836 index = 0;
1837 lastPosition = sao.pos - 2;
1838 setReadPosition = sao.pos;
1839 }
1840 } else {
1841 lastPosition = sao.pos;
1842 setReadPosition = sao.pos;
1843 }
1844 } else if (nextByte == HttpConstants.LF) {
1845 newLine = true;
1846 index = 0;
1847 lastPosition = sao.pos - 1;
1848 setReadPosition = sao.pos;
1849 } else {
1850 lastPosition = sao.pos;
1851 setReadPosition = sao.pos;
1852 }
1853 }
1854 } else {
1855
1856 if (nextByte == HttpConstants.CR) {
1857 if (sao.pos < sao.limit) {
1858 nextByte = sao.bytes[sao.pos ++];
1859 if (nextByte == HttpConstants.LF) {
1860 newLine = true;
1861 index = 0;
1862 lastPosition = sao.pos - 2;
1863 setReadPosition = sao.pos;
1864 }
1865 } else {
1866 lastPosition = sao.pos;
1867 setReadPosition = sao.pos;
1868 }
1869 } else if (nextByte == HttpConstants.LF) {
1870 newLine = true;
1871 index = 0;
1872 lastPosition = sao.pos - 1;
1873 setReadPosition = sao.pos;
1874 } else {
1875 lastPosition = sao.pos;
1876 setReadPosition = sao.pos;
1877 }
1878 }
1879 }
1880 if (setReadPosition > 0) {
1881 sao.pos = setReadPosition;
1882 sao.setReadPosition(0);
1883 }
1884 if (found) {
1885
1886
1887
1888 try {
1889 currentAttribute.addContent(
1890 undecodedChunk.slice(readerIndex, lastPosition - readerIndex), true);
1891 } catch (IOException e) {
1892 throw new ErrorDataDecoderException(e);
1893 }
1894 undecodedChunk.readerIndex(lastPosition);
1895 } else {
1896 try {
1897 currentAttribute.addContent(
1898 undecodedChunk.slice(readerIndex, lastPosition - readerIndex), false);
1899 } catch (IOException e) {
1900 throw new ErrorDataDecoderException(e);
1901 }
1902 undecodedChunk.readerIndex(lastPosition);
1903 throw new NotEnoughDataDecoderException();
1904 }
1905 } catch (IndexOutOfBoundsException e) {
1906 undecodedChunk.readerIndex(readerIndex);
1907 throw new NotEnoughDataDecoderException(e);
1908 }
1909 }
1910
1911
1912
1913
1914
1915 private static String cleanString(String field) {
1916 StringBuilder sb = new StringBuilder(field.length());
1917 int i = 0;
1918 for (i = 0; i < field.length(); i ++) {
1919 char nextChar = field.charAt(i);
1920 if (nextChar == HttpConstants.COLON) {
1921 sb.append(HttpConstants.SP);
1922 } else if (nextChar == HttpConstants.COMMA) {
1923 sb.append(HttpConstants.SP);
1924 } else if (nextChar == HttpConstants.EQUALS) {
1925 sb.append(HttpConstants.SP);
1926 } else if (nextChar == HttpConstants.SEMICOLON) {
1927 sb.append(HttpConstants.SP);
1928 } else if (nextChar == HttpConstants.HT) {
1929 sb.append(HttpConstants.SP);
1930 } else if (nextChar == HttpConstants.DOUBLE_QUOTE) {
1931
1932 } else {
1933 sb.append(nextChar);
1934 }
1935 }
1936 return sb.toString().trim();
1937 }
1938
1939
1940
1941
1942
1943 private boolean skipOneLine() {
1944 if (!undecodedChunk.readable()) {
1945 return false;
1946 }
1947 byte nextByte = undecodedChunk.readByte();
1948 if (nextByte == HttpConstants.CR) {
1949 if (!undecodedChunk.readable()) {
1950 undecodedChunk.readerIndex(undecodedChunk.readerIndex() - 1);
1951 return false;
1952 }
1953 nextByte = undecodedChunk.readByte();
1954 if (nextByte == HttpConstants.LF) {
1955 return true;
1956 }
1957 undecodedChunk.readerIndex(undecodedChunk.readerIndex() - 2);
1958 return false;
1959 } else if (nextByte == HttpConstants.LF) {
1960 return true;
1961 }
1962 undecodedChunk.readerIndex(undecodedChunk.readerIndex() - 1);
1963 return false;
1964 }
1965
1966
1967
1968
1969
1970
1971 private static String[] splitHeaderContentType(String sb) {
1972 int size = sb.length();
1973 int aStart;
1974 int aEnd;
1975 int bStart;
1976 int bEnd;
1977 aStart = HttpPostBodyUtil.findNonWhitespace(sb, 0);
1978 aEnd = HttpPostBodyUtil.findWhitespace(sb, aStart);
1979 if (aEnd >= size) {
1980 return new String[] { sb, "" };
1981 }
1982 if (sb.charAt(aEnd) == ';') {
1983 aEnd --;
1984 }
1985 bStart = HttpPostBodyUtil.findNonWhitespace(sb, aEnd);
1986 bEnd = HttpPostBodyUtil.findEndOfString(sb);
1987 return new String[] { sb.substring(aStart, aEnd),
1988 sb.substring(bStart, bEnd) };
1989 }
1990
1991
1992
1993
1994
1995
1996
1997 private static String[] splitMultipartHeader(String sb) {
1998 ArrayList<String> headers = new ArrayList<String>(1);
1999 int nameStart;
2000 int nameEnd;
2001 int colonEnd;
2002 int valueStart;
2003 int valueEnd;
2004 nameStart = HttpPostBodyUtil.findNonWhitespace(sb, 0);
2005 for (nameEnd = nameStart; nameEnd < sb.length(); nameEnd ++) {
2006 char ch = sb.charAt(nameEnd);
2007 if (ch == ':' || Character.isWhitespace(ch)) {
2008 break;
2009 }
2010 }
2011 for (colonEnd = nameEnd; colonEnd < sb.length(); colonEnd ++) {
2012 if (sb.charAt(colonEnd) == ':') {
2013 colonEnd ++;
2014 break;
2015 }
2016 }
2017 valueStart = HttpPostBodyUtil.findNonWhitespace(sb, colonEnd);
2018 valueEnd = HttpPostBodyUtil.findEndOfString(sb);
2019 headers.add(sb.substring(nameStart, nameEnd));
2020 String svalue = sb.substring(valueStart, valueEnd);
2021 String[] values = null;
2022 if (svalue.indexOf(";") >= 0) {
2023 values = svalue.split(";");
2024 } else {
2025 values = svalue.split(",");
2026 }
2027 for (String value: values) {
2028 headers.add(value.trim());
2029 }
2030 String[] array = new String[headers.size()];
2031 for (int i = 0; i < headers.size(); i ++) {
2032 array[i] = headers.get(i);
2033 }
2034 return array;
2035 }
2036
2037
2038
2039
2040
2041 public static class NotEnoughDataDecoderException extends Exception {
2042
2043
2044 private static final long serialVersionUID = -7846841864603865638L;
2045
2046
2047
2048 public NotEnoughDataDecoderException() {
2049 }
2050
2051
2052
2053
2054 public NotEnoughDataDecoderException(String arg0) {
2055 super(arg0);
2056 }
2057
2058
2059
2060
2061 public NotEnoughDataDecoderException(Throwable arg0) {
2062 super(arg0);
2063 }
2064
2065
2066
2067
2068
2069 public NotEnoughDataDecoderException(String arg0, Throwable arg1) {
2070 super(arg0, arg1);
2071 }
2072 }
2073
2074
2075
2076
2077 public static class EndOfDataDecoderException extends Exception {
2078
2079
2080 private static final long serialVersionUID = 1336267941020800769L;
2081
2082 }
2083
2084
2085
2086
2087 public static class ErrorDataDecoderException extends Exception {
2088
2089
2090 private static final long serialVersionUID = 5020247425493164465L;
2091
2092
2093
2094 public ErrorDataDecoderException() {
2095 }
2096
2097
2098
2099
2100 public ErrorDataDecoderException(String arg0) {
2101 super(arg0);
2102 }
2103
2104
2105
2106
2107 public ErrorDataDecoderException(Throwable arg0) {
2108 super(arg0);
2109 }
2110
2111
2112
2113
2114
2115 public ErrorDataDecoderException(String arg0, Throwable arg1) {
2116 super(arg0, arg1);
2117 }
2118 }
2119
2120
2121
2122
2123 public static class IncompatibleDataDecoderException extends Exception {
2124
2125
2126 private static final long serialVersionUID = -953268047926250267L;
2127
2128
2129
2130 public IncompatibleDataDecoderException() {
2131 }
2132
2133
2134
2135
2136 public IncompatibleDataDecoderException(String arg0) {
2137 super(arg0);
2138 }
2139
2140
2141
2142
2143 public IncompatibleDataDecoderException(Throwable arg0) {
2144 super(arg0);
2145 }
2146
2147
2148
2149
2150
2151 public IncompatibleDataDecoderException(String arg0, Throwable arg1) {
2152 super(arg0, arg1);
2153 }
2154 }
2155 }