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.CharsetDecoder;
38 import java.nio.charset.CoderResult;
39
40 import org.apache.http.annotation.NotThreadSafe;
41 import org.apache.http.nio.reactor.SessionInputBuffer;
42 import org.apache.http.nio.util.ByteBufferAllocator;
43 import org.apache.http.nio.util.ExpandableBuffer;
44 import org.apache.http.nio.util.HeapByteBufferAllocator;
45 import org.apache.http.params.HttpParams;
46 import org.apache.http.params.HttpProtocolParams;
47 import org.apache.http.protocol.HTTP;
48 import org.apache.http.util.CharArrayBuffer;
49
50
51
52
53
54
55
56
57
58
59
60
61
62 @NotThreadSafe
63 public class SessionInputBufferImpl extends ExpandableBuffer implements SessionInputBuffer {
64
65 private CharBuffer charbuffer = null;
66 private Charset charset = null;
67 private CharsetDecoder chardecoder = null;
68
69 public SessionInputBufferImpl(
70 int buffersize,
71 int linebuffersize,
72 final ByteBufferAllocator allocator,
73 final HttpParams params) {
74 super(buffersize, allocator);
75 this.charbuffer = CharBuffer.allocate(linebuffersize);
76 this.charset = Charset.forName(HttpProtocolParams.getHttpElementCharset(params));
77 this.chardecoder = this.charset.newDecoder();
78 this.chardecoder.onMalformedInput(HttpProtocolParams.getMalformedInputAction(params));
79 this.chardecoder.onUnmappableCharacter(HttpProtocolParams.getUnmappableInputAction(params));
80 }
81
82 public SessionInputBufferImpl(
83 int buffersize,
84 int linebuffersize,
85 final HttpParams params) {
86 this(buffersize, linebuffersize, new HeapByteBufferAllocator(), params);
87 }
88
89 public int fill(final ReadableByteChannel channel) throws IOException {
90 if (channel == null) {
91 throw new IllegalArgumentException("Channel may not be null");
92 }
93 setInputMode();
94 if (!this.buffer.hasRemaining()) {
95 expand();
96 }
97 int readNo = channel.read(this.buffer);
98 return readNo;
99 }
100
101 public int read() {
102 setOutputMode();
103 return this.buffer.get() & 0xff;
104 }
105
106 public int read(final ByteBuffer dst, int maxLen) {
107 if (dst == null) {
108 return 0;
109 }
110 setOutputMode();
111 int len = Math.min(dst.remaining(), maxLen);
112 int chunk = Math.min(this.buffer.remaining(), len);
113 for (int i = 0; i < chunk; i++) {
114 dst.put(this.buffer.get());
115 }
116 return chunk;
117 }
118
119 public int read(final ByteBuffer dst) {
120 if (dst == null) {
121 return 0;
122 }
123 return read(dst, dst.remaining());
124 }
125
126 public int read(final WritableByteChannel dst, int maxLen) throws IOException {
127 if (dst == null) {
128 return 0;
129 }
130 setOutputMode();
131 int bytesRead;
132 if (this.buffer.remaining() > maxLen) {
133 int oldLimit = this.buffer.limit();
134 int newLimit = oldLimit - (this.buffer.remaining() - maxLen);
135 this.buffer.limit(newLimit);
136 bytesRead = dst.write(this.buffer);
137 this.buffer.limit(oldLimit);
138 } else {
139 bytesRead = dst.write(this.buffer);
140 }
141 return bytesRead;
142 }
143
144 public int read(final WritableByteChannel dst) throws IOException {
145 if (dst == null) {
146 return 0;
147 }
148 setOutputMode();
149 return dst.write(this.buffer);
150 }
151
152 public boolean readLine(
153 final CharArrayBuffer linebuffer,
154 boolean endOfStream) throws CharacterCodingException {
155
156 setOutputMode();
157
158 int pos = -1;
159 boolean hasLine = false;
160 for (int i = this.buffer.position(); i < this.buffer.limit(); i++) {
161 int b = this.buffer.get(i);
162 if (b == HTTP.LF) {
163 hasLine = true;
164 pos = i + 1;
165 break;
166 }
167 }
168 if (!hasLine) {
169 if (endOfStream && this.buffer.hasRemaining()) {
170
171 pos = this.buffer.limit();
172 } else {
173
174
175 return false;
176 }
177 }
178 int origLimit = this.buffer.limit();
179 this.buffer.limit(pos);
180
181 int len = this.buffer.limit() - this.buffer.position();
182
183 linebuffer.ensureCapacity(len);
184
185 this.chardecoder.reset();
186
187 for (;;) {
188 CoderResult result = this.chardecoder.decode(
189 this.buffer,
190 this.charbuffer,
191 true);
192 if (result.isError()) {
193 result.throwException();
194 }
195 if (result.isOverflow()) {
196 this.charbuffer.flip();
197 linebuffer.append(
198 this.charbuffer.array(),
199 this.charbuffer.position(),
200 this.charbuffer.remaining());
201 this.charbuffer.clear();
202 }
203 if (result.isUnderflow()) {
204 break;
205 }
206 }
207 this.buffer.limit(origLimit);
208
209
210 this.chardecoder.flush(this.charbuffer);
211 this.charbuffer.flip();
212
213 if (this.charbuffer.hasRemaining()) {
214 linebuffer.append(
215 this.charbuffer.array(),
216 this.charbuffer.position(),
217 this.charbuffer.remaining());
218 }
219
220
221 int l = linebuffer.length();
222 if (l > 0) {
223 if (linebuffer.charAt(l - 1) == HTTP.LF) {
224 l--;
225 linebuffer.setLength(l);
226 }
227
228 if (l > 0) {
229 if (linebuffer.charAt(l - 1) == HTTP.CR) {
230 l--;
231 linebuffer.setLength(l);
232 }
233 }
234 }
235 return true;
236 }
237
238 public String readLine(boolean endOfStream) throws CharacterCodingException {
239 CharArrayBuffer charbuffer = new CharArrayBuffer(64);
240 boolean found = readLine(charbuffer, endOfStream);
241 if (found) {
242 return charbuffer.toString();
243 } else {
244 return null;
245 }
246 }
247
248 }