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.hc.core5.http.impl.nio;
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.Charset;
36 import java.nio.charset.CharsetDecoder;
37 import java.nio.charset.CoderResult;
38
39 import org.apache.hc.core5.http.Chars;
40 import org.apache.hc.core5.http.MessageConstraintException;
41 import org.apache.hc.core5.http.nio.SessionInputBuffer;
42 import org.apache.hc.core5.util.Args;
43 import org.apache.hc.core5.util.CharArrayBuffer;
44
45 class SessionInputBufferImpl extends ExpandableBuffer implements SessionInputBuffer {
46
47 private final CharsetDecoder charDecoder;
48 private final int lineBuffersize;
49 private final int maxLineLen;
50
51 private CharBuffer charbuffer;
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public SessionInputBufferImpl(
66 final int bufferSize,
67 final int lineBuffersize,
68 final int maxLineLen,
69 final CharsetDecoder charDecoder) {
70 super(bufferSize);
71 this.lineBuffersize = Args.positive(lineBuffersize, "Line buffer size");
72 this.maxLineLen = maxLineLen > 0 ? maxLineLen : 0;
73 this.charDecoder = charDecoder;
74 }
75
76
77
78
79 public SessionInputBufferImpl(
80 final int bufferSize,
81 final int lineBuffersize,
82 final int maxLineLen,
83 final Charset charset) {
84 this(bufferSize, lineBuffersize, maxLineLen, charset != null ? charset.newDecoder() : null);
85 }
86
87
88
89
90 public SessionInputBufferImpl(
91 final int bufferSize,
92 final int lineBuffersize,
93 final int maxLineLen) {
94 this(bufferSize, lineBuffersize, maxLineLen, (CharsetDecoder) null);
95 }
96
97
98
99
100 public SessionInputBufferImpl(
101 final int bufferSize,
102 final int lineBuffersize) {
103 this(bufferSize, lineBuffersize, 0, (CharsetDecoder) null);
104 }
105
106
107
108
109 public SessionInputBufferImpl(final int bufferSize) {
110 this(bufferSize, 256);
111 }
112
113 @Override
114 public int length() {
115 return super.length();
116 }
117
118 @Override
119 public boolean hasData() {
120 return super.hasData();
121 }
122
123 @Override
124 public int capacity() {
125 return super.capacity();
126 }
127
128 public void put(final ByteBuffer src) {
129 if (src != null && src.hasRemaining()) {
130 setInputMode();
131 ensureAdjustedCapacity(buffer().position() + src.remaining());
132 buffer().put(src);
133 }
134 }
135
136 @Override
137 public int fill(final ReadableByteChannel channel) throws IOException {
138 Args.notNull(channel, "Channel");
139 setInputMode();
140 if (!buffer().hasRemaining()) {
141 expand();
142 }
143 return channel.read(buffer());
144 }
145
146 @Override
147 public int read() {
148 setOutputMode();
149 return buffer().get() & 0xff;
150 }
151
152 @Override
153 public int read(final ByteBuffer dst, final int maxLen) {
154 if (dst == null) {
155 return 0;
156 }
157 setOutputMode();
158 final int len = Math.min(dst.remaining(), maxLen);
159 final int chunk = Math.min(buffer().remaining(), len);
160 if (buffer().remaining() > chunk) {
161 final int oldLimit = buffer().limit();
162 final int newLimit = buffer().position() + chunk;
163 buffer().limit(newLimit);
164 dst.put(buffer());
165 buffer().limit(oldLimit);
166 return len;
167 }
168 dst.put(buffer());
169 return chunk;
170 }
171
172 @Override
173 public int read(final ByteBuffer dst) {
174 if (dst == null) {
175 return 0;
176 }
177 return read(dst, dst.remaining());
178 }
179
180 @Override
181 public int read(final WritableByteChannel dst, final int maxLen) throws IOException {
182 if (dst == null) {
183 return 0;
184 }
185 setOutputMode();
186 final int bytesRead;
187 if (buffer().remaining() > maxLen) {
188 final int oldLimit = buffer().limit();
189 final int newLimit = oldLimit - (buffer().remaining() - maxLen);
190 buffer().limit(newLimit);
191 bytesRead = dst.write(buffer());
192 buffer().limit(oldLimit);
193 } else {
194 bytesRead = dst.write(buffer());
195 }
196 return bytesRead;
197 }
198
199 @Override
200 public int read(final WritableByteChannel dst) throws IOException {
201 if (dst == null) {
202 return 0;
203 }
204 setOutputMode();
205 return dst.write(buffer());
206 }
207
208 @Override
209 public boolean readLine(
210 final CharArrayBuffer lineBuffer,
211 final boolean endOfStream) throws IOException {
212
213 setOutputMode();
214
215 int pos = -1;
216 for (int i = buffer().position(); i < buffer().limit(); i++) {
217 final int b = buffer().get(i);
218 if (b == Chars.LF) {
219 pos = i + 1;
220 break;
221 }
222 }
223
224 if (this.maxLineLen > 0) {
225 final int currentLen = (pos > 0 ? pos : buffer().limit()) - buffer().position();
226 if (currentLen >= this.maxLineLen) {
227 throw new MessageConstraintException("Maximum line length limit exceeded");
228 }
229 }
230
231 if (pos == -1) {
232 if (endOfStream && buffer().hasRemaining()) {
233
234 pos = buffer().limit();
235 } else {
236
237
238 return false;
239 }
240 }
241 final int origLimit = buffer().limit();
242 buffer().limit(pos);
243
244 final int requiredCapacity = buffer().limit() - buffer().position();
245
246 lineBuffer.ensureCapacity(requiredCapacity);
247
248 if (this.charDecoder == null) {
249 if (buffer().hasArray()) {
250 final byte[] b = buffer().array();
251 final int off = buffer().position();
252 final int len = buffer().remaining();
253 lineBuffer.append(b, buffer().arrayOffset() + off, len);
254 buffer().position(off + len);
255 } else {
256 while (buffer().hasRemaining()) {
257 lineBuffer.append((char) (buffer().get() & 0xff));
258 }
259 }
260 } else {
261 if (this.charbuffer == null) {
262 this.charbuffer = CharBuffer.allocate(this.lineBuffersize);
263 }
264 this.charDecoder.reset();
265
266 for (;;) {
267 final CoderResult result = this.charDecoder.decode(
268 buffer(),
269 this.charbuffer,
270 true);
271 if (result.isError()) {
272 result.throwException();
273 }
274 if (result.isOverflow()) {
275 this.charbuffer.flip();
276 lineBuffer.append(
277 this.charbuffer.array(),
278 this.charbuffer.arrayOffset() + this.charbuffer.position(),
279 this.charbuffer.remaining());
280 this.charbuffer.clear();
281 }
282 if (result.isUnderflow()) {
283 break;
284 }
285 }
286
287
288 this.charDecoder.flush(this.charbuffer);
289 this.charbuffer.flip();
290
291 if (this.charbuffer.hasRemaining()) {
292 lineBuffer.append(
293 this.charbuffer.array(),
294 this.charbuffer.arrayOffset() + this.charbuffer.position(),
295 this.charbuffer.remaining());
296 }
297
298 }
299 buffer().limit(origLimit);
300
301
302 int l = lineBuffer.length();
303 if (l > 0) {
304 if (lineBuffer.charAt(l - 1) == Chars.LF) {
305 l--;
306 lineBuffer.setLength(l);
307 }
308
309 if (l > 0 && lineBuffer.charAt(l - 1) == Chars.CR) {
310 l--;
311 lineBuffer.setLength(l);
312 }
313 }
314 return true;
315 }
316
317 }