1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.impl.nio.codecs;
29
30 import java.io.IOException;
31 import java.nio.ByteBuffer;
32 import java.nio.channels.WritableByteChannel;
33
34 import org.apache.http.impl.io.HttpTransportMetricsImpl;
35 import org.apache.http.io.BufferInfo;
36 import org.apache.http.nio.reactor.SessionOutputBuffer;
37 import org.apache.http.util.CharArrayBuffer;
38
39
40
41
42
43
44
45 public class ChunkEncoder extends AbstractContentEncoder {
46
47 private final int fragHint;
48 private final CharArrayBuffer lineBuffer;
49
50 private final BufferInfo bufferinfo;
51
52
53
54
55
56
57
58
59
60
61
62 public ChunkEncoder(
63 final WritableByteChannel channel,
64 final SessionOutputBuffer buffer,
65 final HttpTransportMetricsImpl metrics,
66 final int fragementSizeHint) {
67 super(channel, buffer, metrics);
68 this.fragHint = fragementSizeHint > 0 ? fragementSizeHint : 0;
69 this.lineBuffer = new CharArrayBuffer(16);
70 if (buffer instanceof BufferInfo) {
71 this.bufferinfo = (BufferInfo) buffer;
72 } else {
73 this.bufferinfo = null;
74 }
75 }
76
77 public ChunkEncoder(
78 final WritableByteChannel channel,
79 final SessionOutputBuffer buffer,
80 final HttpTransportMetricsImpl metrics) {
81 this(channel, buffer, metrics, 0);
82 }
83
84 @Override
85 public int write(final ByteBuffer src) throws IOException {
86 if (src == null) {
87 return 0;
88 }
89 assertNotCompleted();
90
91 int total = 0;
92 while (src.hasRemaining()) {
93 int chunk = src.remaining();
94 int avail;
95 if (this.bufferinfo != null) {
96 avail = this.bufferinfo.available();
97 } else {
98 avail = 4096;
99 }
100
101
102
103
104 avail -= 12;
105 if (avail > 0) {
106 if (avail < chunk) {
107
108 chunk = avail;
109 this.lineBuffer.clear();
110 this.lineBuffer.append(Integer.toHexString(chunk));
111 this.buffer.writeLine(this.lineBuffer);
112 final int oldlimit = src.limit();
113 src.limit(src.position() + chunk);
114 this.buffer.write(src);
115 src.limit(oldlimit);
116 } else {
117
118 this.lineBuffer.clear();
119 this.lineBuffer.append(Integer.toHexString(chunk));
120 this.buffer.writeLine(this.lineBuffer);
121 this.buffer.write(src);
122 }
123 this.lineBuffer.clear();
124 this.buffer.writeLine(this.lineBuffer);
125 total += chunk;
126 }
127 if (this.buffer.length() >= this.fragHint || src.hasRemaining()) {
128 final int bytesWritten = flushToChannel();
129 if (bytesWritten == 0) {
130 break;
131 }
132 }
133 }
134 return total;
135 }
136
137 @Override
138 public void complete() throws IOException {
139 assertNotCompleted();
140 this.lineBuffer.clear();
141 this.lineBuffer.append("0");
142 this.buffer.writeLine(this.lineBuffer);
143 this.lineBuffer.clear();
144 this.buffer.writeLine(this.lineBuffer);
145 super.complete();
146 }
147
148 @Override
149 public String toString() {
150 final StringBuilder sb = new StringBuilder();
151 sb.append("[chunk-coded; completed: ");
152 sb.append(isCompleted());
153 sb.append("]");
154 return sb.toString();
155 }
156
157 }