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.reactor;
29
30 import java.io.IOException;
31 import java.nio.ByteBuffer;
32 import java.nio.CharBuffer;
33 import java.nio.channels.ReadableByteChannel;
34 import java.nio.channels.WritableByteChannel;
35 import java.nio.charset.CharacterCodingException;
36 import java.nio.charset.Charset;
37 import java.nio.charset.CharsetEncoder;
38 import java.nio.charset.CoderResult;
39 import java.nio.charset.CodingErrorAction;
40
41 import org.apache.http.annotation.NotThreadSafe;
42 import org.apache.http.nio.reactor.SessionOutputBuffer;
43 import org.apache.http.nio.util.ByteBufferAllocator;
44 import org.apache.http.nio.util.ExpandableBuffer;
45 import org.apache.http.nio.util.HeapByteBufferAllocator;
46 import org.apache.http.params.CoreProtocolPNames;
47 import org.apache.http.params.HttpParams;
48 import org.apache.http.protocol.HTTP;
49 import org.apache.http.util.Args;
50 import org.apache.http.util.CharArrayBuffer;
51 import org.apache.http.util.CharsetUtils;
52
53
54
55
56
57
58
59 @SuppressWarnings("deprecation")
60 @NotThreadSafe
61 public class SessionOutputBufferImpl extends ExpandableBuffer implements SessionOutputBuffer {
62
63 private static final byte[] CRLF = new byte[] {HTTP.CR, HTTP.LF};
64
65 private final CharsetEncoder charencoder;
66 private final int lineBuffersize;
67
68 private CharBuffer charbuffer;
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 public SessionOutputBufferImpl(
84 final int buffersize,
85 final int lineBuffersize,
86 final CharsetEncoder charencoder,
87 final ByteBufferAllocator allocator) {
88 super(buffersize, allocator != null ? allocator : HeapByteBufferAllocator.INSTANCE);
89 this.lineBuffersize = Args.positive(lineBuffersize, "Line buffer size");
90 this.charencoder = charencoder;
91 }
92
93
94
95
96
97
98 @Deprecated
99 public SessionOutputBufferImpl(
100 final int buffersize,
101 final int lineBuffersize,
102 final ByteBufferAllocator allocator,
103 final HttpParams params) {
104 super(buffersize, allocator);
105 this.lineBuffersize = Args.positive(lineBuffersize, "Line buffer size");
106 final String charsetName = (String) params.getParameter(CoreProtocolPNames.HTTP_ELEMENT_CHARSET);
107 final Charset charset = CharsetUtils.lookup(charsetName);
108 if (charset != null) {
109 this.charencoder = charset.newEncoder();
110 final CodingErrorAction a1 = (CodingErrorAction) params.getParameter(
111 CoreProtocolPNames.HTTP_MALFORMED_INPUT_ACTION);
112 this.charencoder.onMalformedInput(a1 != null ? a1 : CodingErrorAction.REPORT);
113 final CodingErrorAction a2 = (CodingErrorAction) params.getParameter(
114 CoreProtocolPNames.HTTP_UNMAPPABLE_INPUT_ACTION);
115 this.charencoder.onUnmappableCharacter(a2 != null? a2 : CodingErrorAction.REPORT);
116 } else {
117 this.charencoder = null;
118 }
119 }
120
121
122
123
124
125 @Deprecated
126 public SessionOutputBufferImpl(
127 final int buffersize,
128 final int linebuffersize,
129 final HttpParams params) {
130 this(buffersize, linebuffersize, HeapByteBufferAllocator.INSTANCE, params);
131 }
132
133
134
135
136 public SessionOutputBufferImpl(final int buffersize) {
137 this(buffersize, 256, null, HeapByteBufferAllocator.INSTANCE);
138 }
139
140
141
142
143 public SessionOutputBufferImpl(
144 final int buffersize,
145 final int linebuffersize,
146 final Charset charset) {
147 this(buffersize, linebuffersize,
148 charset != null ? charset.newEncoder() : null, HeapByteBufferAllocator.INSTANCE);
149 }
150
151
152
153
154 public SessionOutputBufferImpl(
155 final int buffersize,
156 final int linebuffersize) {
157 this(buffersize, linebuffersize, null, HeapByteBufferAllocator.INSTANCE);
158 }
159
160 public void reset(final HttpParams params) {
161 clear();
162 }
163
164 public int flush(final WritableByteChannel channel) throws IOException {
165 Args.notNull(channel, "Channel");
166 setOutputMode();
167 final int noWritten = channel.write(this.buffer);
168 return noWritten;
169 }
170
171 public void write(final ByteBuffer src) {
172 if (src == null) {
173 return;
174 }
175 setInputMode();
176 final int requiredCapacity = this.buffer.position() + src.remaining();
177 ensureCapacity(requiredCapacity);
178 this.buffer.put(src);
179 }
180
181 public void write(final ReadableByteChannel src) throws IOException {
182 if (src == null) {
183 return;
184 }
185 setInputMode();
186 src.read(this.buffer);
187 }
188
189 private void write(final byte[] b) {
190 if (b == null) {
191 return;
192 }
193 setInputMode();
194 final int off = 0;
195 final int len = b.length;
196 final int requiredCapacity = this.buffer.position() + len;
197 ensureCapacity(requiredCapacity);
198 this.buffer.put(b, off, len);
199 }
200
201 private void writeCRLF() {
202 write(CRLF);
203 }
204
205 public void writeLine(final CharArrayBuffer linebuffer) throws CharacterCodingException {
206 if (linebuffer == null) {
207 return;
208 }
209 setInputMode();
210
211 if (linebuffer.length() > 0 ) {
212 if (this.charencoder == null) {
213 final int requiredCapacity = this.buffer.position() + linebuffer.length();
214 ensureCapacity(requiredCapacity);
215 if (this.buffer.hasArray()) {
216 final byte[] b = this.buffer.array();
217 final int len = linebuffer.length();
218 final int off = this.buffer.position();
219 for (int i = 0; i < len; i++) {
220 b[off + i] = (byte) linebuffer.charAt(i);
221 }
222 this.buffer.position(off + len);
223 } else {
224 for (int i = 0; i < linebuffer.length(); i++) {
225 this.buffer.put((byte) linebuffer.charAt(i));
226 }
227 }
228 } else {
229 if (this.charbuffer == null) {
230 this.charbuffer = CharBuffer.allocate(this.lineBuffersize);
231 }
232 this.charencoder.reset();
233
234 int remaining = linebuffer.length();
235 int offset = 0;
236 while (remaining > 0) {
237 int l = this.charbuffer.remaining();
238 boolean eol = false;
239 if (remaining <= l) {
240 l = remaining;
241
242 eol = true;
243 }
244 this.charbuffer.put(linebuffer.buffer(), offset, l);
245 this.charbuffer.flip();
246
247 boolean retry = true;
248 while (retry) {
249 final CoderResult result = this.charencoder.encode(this.charbuffer, this.buffer, eol);
250 if (result.isError()) {
251 result.throwException();
252 }
253 if (result.isOverflow()) {
254 expand();
255 }
256 retry = !result.isUnderflow();
257 }
258 this.charbuffer.compact();
259 offset += l;
260 remaining -= l;
261 }
262
263 boolean retry = true;
264 while (retry) {
265 final CoderResult result = this.charencoder.flush(this.buffer);
266 if (result.isError()) {
267 result.throwException();
268 }
269 if (result.isOverflow()) {
270 expand();
271 }
272 retry = !result.isUnderflow();
273 }
274 }
275 }
276 writeCRLF();
277 }
278
279 public void writeLine(final String s) throws IOException {
280 if (s == null) {
281 return;
282 }
283 if (s.length() > 0) {
284 final CharArrayBuffer tmp = new CharArrayBuffer(s.length());
285 tmp.append(s);
286 writeLine(tmp);
287 } else {
288 write(CRLF);
289 }
290 }
291
292 }