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