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