1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.codec.http.multipart;
17
18 import org.jboss.netty.buffer.ChannelBuffer;
19 import org.jboss.netty.buffer.ChannelBuffers;
20 import org.jboss.netty.handler.codec.http.DefaultHttpChunk;
21 import org.jboss.netty.handler.codec.http.HttpChunk;
22 import org.jboss.netty.handler.codec.http.HttpConstants;
23 import org.jboss.netty.handler.codec.http.HttpHeaders;
24 import org.jboss.netty.handler.codec.http.HttpMethod;
25 import org.jboss.netty.handler.codec.http.HttpRequest;
26 import org.jboss.netty.handler.stream.ChunkedInput;
27
28 import java.io.File;
29 import java.io.IOException;
30 import java.io.UnsupportedEncodingException;
31 import java.net.URLEncoder;
32 import java.nio.charset.Charset;
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.ListIterator;
37 import java.util.Map;
38 import java.util.Random;
39 import java.util.regex.Pattern;
40
41
42
43
44 public class HttpPostRequestEncoder implements ChunkedInput {
45
46
47
48
49 public enum EncoderMode {
50
51
52
53
54 RFC1738,
55
56
57
58
59 RFC3986
60 }
61
62 private static final Map<Pattern, String> percentEncodings = new HashMap<Pattern, String>();
63
64 static {
65 percentEncodings.put(Pattern.compile("\\*"), "%2A");
66 percentEncodings.put(Pattern.compile("\\+"), "%20");
67 percentEncodings.put(Pattern.compile("%7E"), "~");
68 }
69
70
71
72
73 private final HttpDataFactory factory;
74
75
76
77
78 private final HttpRequest request;
79
80
81
82
83 private final Charset charset;
84
85
86
87
88 private boolean isChunked;
89
90
91
92
93 private final List<InterfaceHttpData> bodyListDatas;
94
95
96
97 private final List<InterfaceHttpData> multipartHttpDatas;
98
99
100
101
102 private final boolean isMultipart;
103
104
105
106
107 private String multipartDataBoundary;
108
109
110
111
112
113 private String multipartMixedBoundary;
114
115
116
117 private boolean headerFinalized;
118
119 private final EncoderMode encoderMode;
120
121
122
123
124
125
126
127
128 public HttpPostRequestEncoder(HttpRequest request, boolean multipart)
129 throws ErrorDataEncoderException {
130 this(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE),
131 request, multipart, HttpConstants.DEFAULT_CHARSET);
132 }
133
134
135
136
137
138
139
140
141
142 public HttpPostRequestEncoder(HttpDataFactory factory, HttpRequest request, boolean multipart)
143 throws ErrorDataEncoderException {
144 this(factory, request, multipart, HttpConstants.DEFAULT_CHARSET);
145 }
146
147
148
149
150
151
152
153
154
155
156 public HttpPostRequestEncoder(HttpDataFactory factory, HttpRequest request,
157 boolean multipart, Charset charset) throws ErrorDataEncoderException {
158 this(factory, request, multipart, charset, EncoderMode.RFC1738);
159 }
160
161
162
163
164
165
166
167
168
169
170
171 public HttpPostRequestEncoder(HttpDataFactory factory, HttpRequest request, boolean multipart,
172 Charset charset, EncoderMode encoderMode) throws ErrorDataEncoderException {
173 if (factory == null) {
174 throw new NullPointerException("factory");
175 }
176 if (request == null) {
177 throw new NullPointerException("request");
178 }
179 if (charset == null) {
180 throw new NullPointerException("charset");
181 }
182 if (request.getMethod() != HttpMethod.POST) {
183 throw new ErrorDataEncoderException("Cannot create a Encoder if not a POST");
184 }
185 this.request = request;
186 this.charset = charset;
187 this.factory = factory;
188 this.encoderMode = encoderMode;
189
190 bodyListDatas = new ArrayList<InterfaceHttpData>();
191
192 isLastChunk = false;
193 isLastChunkSent = false;
194 isMultipart = multipart;
195 multipartHttpDatas = new ArrayList<InterfaceHttpData>();
196 if (isMultipart) {
197 initDataMultipart();
198 }
199 }
200
201
202
203 public void cleanFiles() {
204 factory.cleanRequestHttpDatas(request);
205 }
206
207
208
209
210 private boolean isLastChunk;
211
212
213
214 private boolean isLastChunkSent;
215
216
217
218 private FileUpload currentFileUpload;
219
220
221
222 private boolean duringMixedMode;
223
224
225
226
227 private long globalBodySize;
228
229
230
231
232
233 public boolean isMultipart() {
234 return isMultipart;
235 }
236
237
238
239
240 private void initDataMultipart() {
241 multipartDataBoundary = getNewMultipartDelimiter();
242 }
243
244
245
246
247 private void initMixedMultipart() {
248 multipartMixedBoundary = getNewMultipartDelimiter();
249 }
250
251
252
253
254
255 private static String getNewMultipartDelimiter() {
256
257 Random random = new Random();
258 return Long.toHexString(random.nextLong()).toLowerCase();
259 }
260
261
262
263
264
265
266 public List<InterfaceHttpData> getBodyListAttributes() {
267 return bodyListDatas;
268 }
269
270
271
272
273
274
275 public void setBodyHttpDatas(List<InterfaceHttpData> datas)
276 throws ErrorDataEncoderException {
277 if (datas == null) {
278 throw new NullPointerException("datas");
279 }
280 globalBodySize = 0;
281 bodyListDatas.clear();
282 currentFileUpload = null;
283 duringMixedMode = false;
284 multipartHttpDatas.clear();
285 for (InterfaceHttpData data: datas) {
286 addBodyHttpData(data);
287 }
288 }
289
290
291
292
293
294
295
296
297 public void addBodyAttribute(String name, String value)
298 throws ErrorDataEncoderException {
299 if (name == null) {
300 throw new NullPointerException("name");
301 }
302 String svalue = value;
303 if (value == null) {
304 svalue = "";
305 }
306 Attribute data = factory.createAttribute(request, name, svalue);
307 addBodyHttpData(data);
308 }
309
310
311
312
313
314
315
316
317
318
319 public void addBodyFileUpload(String name, File file, String contentType, boolean isText)
320 throws ErrorDataEncoderException {
321 if (name == null) {
322 throw new NullPointerException("name");
323 }
324 if (file == null) {
325 throw new NullPointerException("file");
326 }
327 String scontentType = contentType;
328 String contentTransferEncoding = null;
329 if (contentType == null) {
330 if (isText) {
331 scontentType = HttpPostBodyUtil.DEFAULT_TEXT_CONTENT_TYPE;
332 } else {
333 scontentType = HttpPostBodyUtil.DEFAULT_BINARY_CONTENT_TYPE;
334 }
335 }
336 if (!isText) {
337 contentTransferEncoding = HttpPostBodyUtil.TransferEncodingMechanism.BINARY.value();
338 }
339 FileUpload fileUpload = factory.createFileUpload(request, name, file.getName(),
340 scontentType, contentTransferEncoding, null, file.length());
341 try {
342 fileUpload.setContent(file);
343 } catch (IOException e) {
344 throw new ErrorDataEncoderException(e);
345 }
346 addBodyHttpData(fileUpload);
347 }
348
349
350
351
352
353
354
355
356
357
358 public void addBodyFileUploads(String name, File[] file, String[] contentType, boolean[] isText)
359 throws ErrorDataEncoderException {
360 if (file.length != contentType.length && file.length != isText.length) {
361 throw new NullPointerException("Different array length");
362 }
363 for (int i = 0; i < file.length; i++) {
364 addBodyFileUpload(name, file[i], contentType[i], isText[i]);
365 }
366 }
367
368
369
370
371
372
373 public void addBodyHttpData(InterfaceHttpData data)
374 throws ErrorDataEncoderException {
375 if (headerFinalized) {
376 throw new ErrorDataEncoderException("Cannot add value once finalized");
377 }
378 if (data == null) {
379 throw new NullPointerException("data");
380 }
381 bodyListDatas.add(data);
382 if (! isMultipart) {
383 if (data instanceof Attribute) {
384 Attribute attribute = (Attribute) data;
385 try {
386
387 String key = encodeAttribute(attribute.getName(), charset);
388 String value = encodeAttribute(attribute.getValue(), charset);
389 Attribute newattribute = factory.createAttribute(request, key, value);
390 multipartHttpDatas.add(newattribute);
391 globalBodySize += newattribute.getName().length() + 1 +
392 newattribute.length() + 1;
393 } catch (IOException e) {
394 throw new ErrorDataEncoderException(e);
395 }
396 } else if (data instanceof FileUpload) {
397
398 FileUpload fileUpload = (FileUpload) data;
399
400 String key = encodeAttribute(fileUpload.getName(), charset);
401 String value = encodeAttribute(fileUpload.getFilename(), charset);
402 Attribute newattribute = factory.createAttribute(request, key, value);
403 multipartHttpDatas.add(newattribute);
404 globalBodySize += newattribute.getName().length() + 1 +
405 newattribute.length() + 1;
406 }
407 return;
408 }
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441 if (data instanceof Attribute) {
442 if (duringMixedMode) {
443 InternalAttribute internal = new InternalAttribute();
444 internal.addValue("\r\n--" + multipartMixedBoundary + "--");
445 multipartHttpDatas.add(internal);
446 multipartMixedBoundary = null;
447 currentFileUpload = null;
448 duringMixedMode = false;
449 }
450 InternalAttribute internal = new InternalAttribute();
451 if (!multipartHttpDatas.isEmpty()) {
452
453 internal.addValue("\r\n");
454 }
455 internal.addValue("--" + multipartDataBoundary + "\r\n");
456
457 Attribute attribute = (Attribute) data;
458 internal.addValue(HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
459 HttpPostBodyUtil.FORM_DATA + "; " +
460 HttpPostBodyUtil.NAME + "=\"" +
461 encodeAttribute(attribute.getName(), charset) + "\"\r\n");
462 Charset localcharset = attribute.getCharset();
463 if (localcharset != null) {
464
465 internal.addValue(HttpHeaders.Names.CONTENT_TYPE + ": " +
466 HttpHeaders.Values.CHARSET + '=' + localcharset + "\r\n");
467 }
468
469 internal.addValue("\r\n");
470 multipartHttpDatas.add(internal);
471 multipartHttpDatas.add(data);
472 globalBodySize += attribute.length() + internal.size();
473 } else if (data instanceof FileUpload) {
474 FileUpload fileUpload = (FileUpload) data;
475 InternalAttribute internal = new InternalAttribute();
476 if (!multipartHttpDatas.isEmpty()) {
477
478 internal.addValue("\r\n");
479 }
480 boolean localMixed;
481 if (duringMixedMode) {
482 if (currentFileUpload != null &&
483 currentFileUpload.getName().equals(fileUpload.getName())) {
484
485
486 localMixed = true;
487 } else {
488
489
490
491
492 internal.addValue("--" + multipartMixedBoundary + "--");
493 multipartHttpDatas.add(internal);
494 multipartMixedBoundary = null;
495
496 internal = new InternalAttribute();
497 internal.addValue("\r\n");
498 localMixed = false;
499
500 currentFileUpload = fileUpload;
501 duringMixedMode = false;
502 }
503 } else {
504 if (currentFileUpload != null &&
505 currentFileUpload.getName().equals(fileUpload.getName())) {
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524 initMixedMultipart();
525 InternalAttribute pastAttribute =
526 (InternalAttribute) multipartHttpDatas.get(multipartHttpDatas.size() - 2);
527
528 globalBodySize -= pastAttribute.size();
529 String replacement = HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
530 HttpPostBodyUtil.FORM_DATA + "; " + HttpPostBodyUtil.NAME + "=\"" +
531 encodeAttribute(fileUpload.getName(), charset) + "\"\r\n";
532 replacement += HttpHeaders.Names.CONTENT_TYPE + ": " +
533 HttpPostBodyUtil.MULTIPART_MIXED + "; " + HttpHeaders.Values.BOUNDARY +
534 '=' + multipartMixedBoundary + "\r\n\r\n";
535 replacement += "--" + multipartMixedBoundary + "\r\n";
536 replacement += HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
537 HttpPostBodyUtil.FILE + "; " + HttpPostBodyUtil.FILENAME + "=\"" +
538 encodeAttribute(fileUpload.getFilename(), charset) +
539 "\"\r\n";
540 pastAttribute.setValue(replacement, 1);
541
542 globalBodySize += pastAttribute.size();
543
544
545
546
547 localMixed = true;
548 duringMixedMode = true;
549 } else {
550
551
552 localMixed = false;
553 currentFileUpload = fileUpload;
554 duringMixedMode = false;
555 }
556 }
557
558 if (localMixed) {
559
560
561 internal.addValue("--" + multipartMixedBoundary + "\r\n");
562
563 internal.addValue(HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
564 HttpPostBodyUtil.FILE + "; " + HttpPostBodyUtil.FILENAME + "=\"" +
565 encodeAttribute(fileUpload.getFilename(), charset) +
566 "\"\r\n");
567 } else {
568 internal.addValue("--" + multipartDataBoundary + "\r\n");
569
570 internal.addValue(HttpPostBodyUtil.CONTENT_DISPOSITION + ": " +
571 HttpPostBodyUtil.FORM_DATA + "; " + HttpPostBodyUtil.NAME + "=\"" +
572 encodeAttribute(fileUpload.getName(), charset) + "\"; " +
573 HttpPostBodyUtil.FILENAME + "=\"" +
574 encodeAttribute(fileUpload.getFilename(), charset) +
575 "\"\r\n");
576 }
577
578
579
580 internal.addValue(HttpHeaders.Names.CONTENT_TYPE + ": " +
581 fileUpload.getContentType());
582 String contentTransferEncoding = fileUpload.getContentTransferEncoding();
583 if (contentTransferEncoding != null &&
584 contentTransferEncoding.equals(
585 HttpPostBodyUtil.TransferEncodingMechanism.BINARY.value())) {
586 internal.addValue("\r\n" + HttpHeaders.Names.CONTENT_TRANSFER_ENCODING +
587 ": " + HttpPostBodyUtil.TransferEncodingMechanism.BINARY.value() +
588 "\r\n\r\n");
589 } else if (fileUpload.getCharset() != null) {
590 internal.addValue("; " + HttpHeaders.Values.CHARSET + '=' +
591 fileUpload.getCharset() + "\r\n\r\n");
592 } else {
593 internal.addValue("\r\n\r\n");
594 }
595 multipartHttpDatas.add(internal);
596 multipartHttpDatas.add(data);
597 globalBodySize += fileUpload.length() + internal.size();
598 }
599 }
600
601
602
603
604 private ListIterator<InterfaceHttpData> iterator;
605
606
607
608
609
610
611
612
613
614
615
616
617 public HttpRequest finalizeRequest() throws ErrorDataEncoderException {
618
619 if (! headerFinalized) {
620 if (isMultipart) {
621 InternalAttribute internal = new InternalAttribute();
622 if (duringMixedMode) {
623 internal.addValue("\r\n--" + multipartMixedBoundary + "--");
624 }
625 internal.addValue("\r\n--" + multipartDataBoundary + "--\r\n");
626 multipartHttpDatas.add(internal);
627 multipartMixedBoundary = null;
628 currentFileUpload = null;
629 duringMixedMode = false;
630 globalBodySize += internal.size();
631 }
632 headerFinalized = true;
633 } else {
634 throw new ErrorDataEncoderException("Header already encoded");
635 }
636 List<String> contentTypes = request.getHeaders(HttpHeaders.Names.CONTENT_TYPE);
637 List<String> transferEncoding =
638 request.getHeaders(HttpHeaders.Names.TRANSFER_ENCODING);
639 if (contentTypes != null) {
640 request.removeHeader(HttpHeaders.Names.CONTENT_TYPE);
641 for (String contentType: contentTypes) {
642
643 if (contentType.toLowerCase().startsWith(
644 HttpHeaders.Values.MULTIPART_FORM_DATA)) {
645
646 } else if (contentType.toLowerCase().startsWith(
647 HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED)) {
648
649 } else {
650 request.addHeader(HttpHeaders.Names.CONTENT_TYPE, contentType);
651 }
652 }
653 }
654 if (isMultipart) {
655 String value = HttpHeaders.Values.MULTIPART_FORM_DATA + "; " +
656 HttpHeaders.Values.BOUNDARY + '=' + multipartDataBoundary;
657 request.addHeader(HttpHeaders.Names.CONTENT_TYPE, value);
658 } else {
659
660 request.addHeader(HttpHeaders.Names.CONTENT_TYPE,
661 HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED);
662 }
663
664 long realSize = globalBodySize;
665 if (isMultipart) {
666 iterator = multipartHttpDatas.listIterator();
667 } else {
668 realSize -= 1;
669 iterator = multipartHttpDatas.listIterator();
670 }
671 request.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String
672 .valueOf(realSize));
673 if (realSize > HttpPostBodyUtil.chunkSize || isMultipart) {
674 isChunked = true;
675 if (transferEncoding != null) {
676 request.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
677 for (String v: transferEncoding) {
678 if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) {
679
680 } else {
681 request.addHeader(HttpHeaders.Names.TRANSFER_ENCODING, v);
682 }
683 }
684 }
685 request.addHeader(HttpHeaders.Names.TRANSFER_ENCODING,
686 HttpHeaders.Values.CHUNKED);
687 request.setContent(ChannelBuffers.EMPTY_BUFFER);
688 } else {
689
690 HttpChunk chunk = nextChunk();
691 request.setContent(chunk.getContent());
692 }
693 return request;
694 }
695
696
697
698
699 public boolean isChunked() {
700 return isChunked;
701 }
702
703
704
705
706
707
708 private String encodeAttribute(String s, Charset charset)
709 throws ErrorDataEncoderException {
710 if (s == null) {
711 return "";
712 }
713 try {
714 String encoded = URLEncoder.encode(s, charset.name());
715 if (encoderMode == EncoderMode.RFC3986) {
716 for (Map.Entry<Pattern, String> entry : percentEncodings.entrySet()) {
717 String replacement = entry.getValue();
718 encoded = entry.getKey().matcher(encoded).replaceAll(replacement);
719 }
720 }
721 return encoded;
722 } catch (UnsupportedEncodingException e) {
723 throw new ErrorDataEncoderException(charset.name(), e);
724 }
725 }
726
727
728
729
730 private ChannelBuffer currentBuffer;
731
732
733
734 private InterfaceHttpData currentData;
735
736
737
738 private boolean isKey = true;
739
740
741
742
743
744
745 private ChannelBuffer fillChannelBuffer() {
746 int length = currentBuffer.readableBytes();
747 if (length > HttpPostBodyUtil.chunkSize) {
748 ChannelBuffer slice =
749 currentBuffer.slice(currentBuffer.readerIndex(), HttpPostBodyUtil.chunkSize);
750 currentBuffer.skipBytes(HttpPostBodyUtil.chunkSize);
751 return slice;
752 } else {
753
754 ChannelBuffer slice = currentBuffer;
755 currentBuffer = null;
756 return slice;
757 }
758 }
759
760
761
762
763
764
765
766
767
768
769 private HttpChunk encodeNextChunkMultipart(int sizeleft) throws ErrorDataEncoderException {
770 if (currentData == null) {
771 return null;
772 }
773 ChannelBuffer buffer;
774 if (currentData instanceof InternalAttribute) {
775 String internal = currentData.toString();
776 byte[] bytes;
777 try {
778 bytes = internal.getBytes("ASCII");
779 } catch (UnsupportedEncodingException e) {
780 throw new ErrorDataEncoderException(e);
781 }
782 buffer = ChannelBuffers.wrappedBuffer(bytes);
783 currentData = null;
784 } else {
785 if (currentData instanceof Attribute) {
786 try {
787 buffer = ((Attribute) currentData).getChunk(sizeleft);
788 } catch (IOException e) {
789 throw new ErrorDataEncoderException(e);
790 }
791 } else {
792 try {
793 buffer = ((HttpData) currentData).getChunk(sizeleft);
794 } catch (IOException e) {
795 throw new ErrorDataEncoderException(e);
796 }
797 }
798 if (buffer.capacity() == 0) {
799
800 currentData = null;
801 return null;
802 }
803 }
804 if (currentBuffer == null) {
805 currentBuffer = buffer;
806 } else {
807 currentBuffer = ChannelBuffers.wrappedBuffer(currentBuffer,
808 buffer);
809 }
810 if (currentBuffer.readableBytes() < HttpPostBodyUtil.chunkSize) {
811 currentData = null;
812 return null;
813 }
814 buffer = fillChannelBuffer();
815 return new DefaultHttpChunk(buffer);
816 }
817
818
819
820
821
822
823
824
825
826
827 private HttpChunk encodeNextChunkUrlEncoded(int sizeleft) throws ErrorDataEncoderException {
828 if (currentData == null) {
829 return null;
830 }
831 int size = sizeleft;
832 ChannelBuffer buffer;
833 if (isKey) {
834
835 String key = currentData.getName();
836 buffer = ChannelBuffers.wrappedBuffer(key.getBytes());
837 isKey = false;
838 if (currentBuffer == null) {
839 currentBuffer = ChannelBuffers.wrappedBuffer(
840 buffer, ChannelBuffers.wrappedBuffer("=".getBytes()));
841
842 size -= buffer.readableBytes() + 1;
843 } else {
844 currentBuffer = ChannelBuffers.wrappedBuffer(currentBuffer,
845 buffer, ChannelBuffers.wrappedBuffer("=".getBytes()));
846
847 size -= buffer.readableBytes() + 1;
848 }
849 if (currentBuffer.readableBytes() >= HttpPostBodyUtil.chunkSize) {
850 buffer = fillChannelBuffer();
851 return new DefaultHttpChunk(buffer);
852 }
853 }
854 try {
855 buffer = ((HttpData) currentData).getChunk(size);
856 } catch (IOException e) {
857 throw new ErrorDataEncoderException(e);
858 }
859 ChannelBuffer delimiter = null;
860 if (buffer.readableBytes() < size) {
861
862 isKey = true;
863 delimiter = iterator.hasNext() ?
864 ChannelBuffers.wrappedBuffer("&".getBytes()) :
865 null;
866 }
867 if (buffer.capacity() == 0) {
868
869 currentData = null;
870 if (currentBuffer == null) {
871 currentBuffer = delimiter;
872 } else {
873 if (delimiter != null) {
874 currentBuffer = ChannelBuffers.wrappedBuffer(currentBuffer,
875 delimiter);
876 }
877 }
878 if (currentBuffer.readableBytes() >= HttpPostBodyUtil.chunkSize) {
879 buffer = fillChannelBuffer();
880 return new DefaultHttpChunk(buffer);
881 }
882 return null;
883 }
884 if (currentBuffer == null) {
885 if (delimiter != null) {
886 currentBuffer = ChannelBuffers.wrappedBuffer(buffer,
887 delimiter);
888 } else {
889 currentBuffer = buffer;
890 }
891 } else {
892 if (delimiter != null) {
893 currentBuffer = ChannelBuffers.wrappedBuffer(currentBuffer,
894 buffer, delimiter);
895 } else {
896 currentBuffer = ChannelBuffers.wrappedBuffer(currentBuffer,
897 buffer);
898 }
899 }
900 if (currentBuffer.readableBytes() < HttpPostBodyUtil.chunkSize) {
901
902 currentData = null;
903 isKey = true;
904 return null;
905 }
906 buffer = fillChannelBuffer();
907
908 return new DefaultHttpChunk(buffer);
909 }
910
911 public void close() throws Exception {
912
913 }
914
915
916
917
918
919
920
921
922 public HttpChunk nextChunk() throws ErrorDataEncoderException {
923 if (isLastChunk) {
924 isLastChunkSent = true;
925 return new DefaultHttpChunk(ChannelBuffers.EMPTY_BUFFER);
926 }
927 ChannelBuffer buffer;
928 int size = HttpPostBodyUtil.chunkSize;
929
930 if (currentBuffer != null) {
931 size -= currentBuffer.readableBytes();
932 }
933 if (size <= 0) {
934
935 buffer = fillChannelBuffer();
936 return new DefaultHttpChunk(buffer);
937 }
938
939 if (currentData != null) {
940
941 if (isMultipart) {
942 HttpChunk chunk = encodeNextChunkMultipart(size);
943 if (chunk != null) {
944 return chunk;
945 }
946 } else {
947 HttpChunk chunk = encodeNextChunkUrlEncoded(size);
948 if (chunk != null) {
949
950 return chunk;
951 }
952 }
953 size = HttpPostBodyUtil.chunkSize - currentBuffer.readableBytes();
954 }
955 if (! iterator.hasNext()) {
956 isLastChunk = true;
957
958 buffer = currentBuffer;
959 currentBuffer = null;
960 return new DefaultHttpChunk(buffer);
961 }
962 while (size > 0 && iterator.hasNext()) {
963 currentData = iterator.next();
964 HttpChunk chunk;
965 if (isMultipart) {
966 chunk = encodeNextChunkMultipart(size);
967 } else {
968 chunk = encodeNextChunkUrlEncoded(size);
969 }
970 if (chunk == null) {
971
972 size = HttpPostBodyUtil.chunkSize - currentBuffer.readableBytes();
973 continue;
974 }
975
976 return chunk;
977 }
978
979 isLastChunk = true;
980 if (currentBuffer == null) {
981 isLastChunkSent = true;
982
983 return new DefaultHttpChunk(ChannelBuffers.EMPTY_BUFFER);
984 }
985
986 buffer = currentBuffer;
987 currentBuffer = null;
988 return new DefaultHttpChunk(buffer);
989 }
990
991 public boolean isEndOfInput() throws Exception {
992 return isLastChunkSent;
993 }
994
995 public boolean hasNextChunk() throws Exception {
996 return !isLastChunkSent;
997 }
998
999
1000
1001
1002 public static class ErrorDataEncoderException extends Exception {
1003 private static final long serialVersionUID = 5020247425493164465L;
1004
1005 public ErrorDataEncoderException() {
1006 }
1007
1008 public ErrorDataEncoderException(String msg) {
1009 super(msg);
1010 }
1011
1012 public ErrorDataEncoderException(Throwable cause) {
1013 super(cause);
1014 }
1015
1016 public ErrorDataEncoderException(String msg, Throwable cause) {
1017 super(msg, cause);
1018 }
1019 }
1020 }