001: /*
002: * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/httpcore/tags/4.0-beta1/module-nio/src/main/java/org/apache/http/impl/nio/reactor/SessionInputBufferImpl.java $
003: * $Revision: 594116 $
004: * $Date: 2007-11-12 14:35:43 +0100 (Mon, 12 Nov 2007) $
005: *
006: * ====================================================================
007: * Licensed to the Apache Software Foundation (ASF) under one
008: * or more contributor license agreements. See the NOTICE file
009: * distributed with this work for additional information
010: * regarding copyright ownership. The ASF licenses this file
011: * to you under the Apache License, Version 2.0 (the
012: * "License"); you may not use this file except in compliance
013: * with the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing,
018: * software distributed under the License is distributed on an
019: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
020: * KIND, either express or implied. See the License for the
021: * specific language governing permissions and limitations
022: * under the License.
023: * ====================================================================
024: *
025: * This software consists of voluntary contributions made by many
026: * individuals on behalf of the Apache Software Foundation. For more
027: * information on the Apache Software Foundation, please see
028: * <http://www.apache.org/>.
029: *
030: */
031:
032: package org.apache.http.impl.nio.reactor;
033:
034: import java.io.IOException;
035: import java.nio.ByteBuffer;
036: import java.nio.CharBuffer;
037: import java.nio.channels.ReadableByteChannel;
038: import java.nio.channels.WritableByteChannel;
039: import java.nio.charset.CharacterCodingException;
040: import java.nio.charset.Charset;
041: import java.nio.charset.CharsetDecoder;
042: import java.nio.charset.CoderResult;
043:
044: import org.apache.http.nio.reactor.SessionInputBuffer;
045: import org.apache.http.nio.util.ByteBufferAllocator;
046: import org.apache.http.nio.util.ExpandableBuffer;
047: import org.apache.http.nio.util.HeapByteBufferAllocator;
048: import org.apache.http.params.HttpParams;
049: import org.apache.http.params.HttpProtocolParams;
050: import org.apache.http.protocol.HTTP;
051: import org.apache.http.util.CharArrayBuffer;
052:
053: public class SessionInputBufferImpl extends ExpandableBuffer implements
054: SessionInputBuffer {
055:
056: private CharBuffer charbuffer = null;
057: private Charset charset = null;
058: private CharsetDecoder chardecoder = null;
059:
060: public SessionInputBufferImpl(int buffersize, int linebuffersize,
061: final ByteBufferAllocator allocator, final HttpParams params) {
062: super (buffersize, allocator);
063: this .charbuffer = CharBuffer.allocate(linebuffersize);
064: this .charset = Charset.forName(HttpProtocolParams
065: .getHttpElementCharset(params));
066: this .chardecoder = this .charset.newDecoder();
067: }
068:
069: public SessionInputBufferImpl(int buffersize, int linebuffersize,
070: final HttpParams params) {
071: this (buffersize, linebuffersize, new HeapByteBufferAllocator(),
072: params);
073: }
074:
075: public int fill(final ReadableByteChannel channel)
076: throws IOException {
077: if (channel == null) {
078: throw new IllegalArgumentException(
079: "Channel may not be null");
080: }
081: setInputMode();
082: if (!this .buffer.hasRemaining()) {
083: expand();
084: }
085: int readNo = channel.read(this .buffer);
086: return readNo;
087: }
088:
089: public int read() {
090: setOutputMode();
091: return this .buffer.get() & 0xff;
092: }
093:
094: public int read(final ByteBuffer dst, int maxLen) {
095: if (dst == null) {
096: return 0;
097: }
098: setOutputMode();
099: int len = Math.min(dst.remaining(), maxLen);
100: int chunk = Math.min(this .buffer.remaining(), len);
101: for (int i = 0; i < chunk; i++) {
102: dst.put(this .buffer.get());
103: }
104: return chunk;
105: }
106:
107: public int read(final ByteBuffer dst) {
108: if (dst == null) {
109: return 0;
110: }
111: return read(dst, dst.remaining());
112: }
113:
114: public int read(final WritableByteChannel dst, int maxLen)
115: throws IOException {
116: if (dst == null) {
117: return 0;
118: }
119: setOutputMode();
120: int bytesRead;
121: if (this .buffer.remaining() > maxLen) {
122: int oldLimit = this .buffer.limit();
123: int newLimit = oldLimit
124: - (this .buffer.remaining() - maxLen);
125: this .buffer.limit(newLimit);
126: bytesRead = dst.write(this .buffer);
127: this .buffer.limit(oldLimit);
128: } else {
129: bytesRead = dst.write(this .buffer);
130: }
131: return bytesRead;
132: }
133:
134: public int read(final WritableByteChannel dst) throws IOException {
135: if (dst == null) {
136: return 0;
137: }
138: setOutputMode();
139: return dst.write(this .buffer);
140: }
141:
142: public boolean readLine(final CharArrayBuffer linebuffer,
143: boolean endOfStream) throws CharacterCodingException {
144:
145: setOutputMode();
146: // See if there is LF char present in the buffer
147: int pos = -1;
148: boolean hasLine = false;
149: for (int i = this .buffer.position(); i < this .buffer.limit(); i++) {
150: int b = this .buffer.get(i);
151: if (b == HTTP.LF) {
152: hasLine = true;
153: pos = i + 1;
154: break;
155: }
156: }
157: if (!hasLine) {
158: if (endOfStream && this .buffer.hasRemaining()) {
159: // No more data. Get the rest
160: pos = this .buffer.limit();
161: } else {
162: // Either no complete line present in the buffer
163: // or no more data is expected
164: return false;
165: }
166: }
167: int origLimit = this .buffer.limit();
168: this .buffer.limit(pos);
169:
170: int len = this .buffer.limit() - this .buffer.position();
171: // Ensure capacity of len assuming ASCII as the most likely charset
172: linebuffer.ensureCapacity(len);
173:
174: this .chardecoder.reset();
175:
176: for (;;) {
177: CoderResult result = this .chardecoder.decode(this .buffer,
178: this .charbuffer, true);
179: if (result.isError()) {
180: result.throwException();
181: }
182: if (result.isOverflow()) {
183: this .charbuffer.flip();
184: linebuffer.append(this .charbuffer.array(),
185: this .charbuffer.position(), this .charbuffer
186: .remaining());
187: this .charbuffer.clear();
188: }
189: if (result.isUnderflow()) {
190: break;
191: }
192: }
193: this .buffer.limit(origLimit);
194:
195: // flush the decoder
196: this .chardecoder.flush(this .charbuffer);
197: this .charbuffer.flip();
198: // append the decoded content to the line buffer
199: if (this .charbuffer.hasRemaining()) {
200: linebuffer.append(this .charbuffer.array(), this .charbuffer
201: .position(), this .charbuffer.remaining());
202: }
203:
204: // discard LF if found
205: int l = linebuffer.length();
206: if (l > 0) {
207: if (linebuffer.charAt(l - 1) == HTTP.LF) {
208: l--;
209: linebuffer.setLength(l);
210: }
211: // discard CR if found
212: if (l > 0) {
213: if (linebuffer.charAt(l - 1) == HTTP.CR) {
214: l--;
215: linebuffer.setLength(l);
216: }
217: }
218: }
219: return true;
220: }
221:
222: public String readLine(boolean endOfStream)
223: throws CharacterCodingException {
224: CharArrayBuffer charbuffer = new CharArrayBuffer(64);
225: boolean found = readLine(charbuffer, endOfStream);
226: if (found) {
227: return charbuffer.toString();
228: } else {
229: return null;
230: }
231: }
232:
233: }
|