1/*
2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/AbstractSessionInputBuffer.java $
3 * $Revision: 576077 $
4 * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
5 *
6 * ====================================================================
7 * Licensed to the Apache Software Foundation (ASF) under one
8 * or more contributor license agreements.  See the NOTICE file
9 * distributed with this work for additional information
10 * regarding copyright ownership.  The ASF licenses this file
11 * to you under the Apache License, Version 2.0 (the
12 * "License"); you may not use this file except in compliance
13 * with the License.  You may obtain a copy of the License at
14 *
15 *   http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing,
18 * software distributed under the License is distributed on an
19 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 * KIND, either express or implied.  See the License for the
21 * specific language governing permissions and limitations
22 * under the License.
23 * ====================================================================
24 *
25 * This software consists of voluntary contributions made by many
26 * individuals on behalf of the Apache Software Foundation.  For more
27 * information on the Apache Software Foundation, please see
28 * <http://www.apache.org/>.
29 *
30 */
31
32package org.apache.http.impl.io;
33
34import java.io.IOException;
35import java.io.InputStream;
36
37import org.apache.http.io.SessionInputBuffer;
38import org.apache.http.io.HttpTransportMetrics;
39import org.apache.http.params.CoreConnectionPNames;
40import org.apache.http.params.HttpParams;
41import org.apache.http.params.HttpProtocolParams;
42import org.apache.http.protocol.HTTP;
43import org.apache.http.util.ByteArrayBuffer;
44import org.apache.http.util.CharArrayBuffer;
45
46/**
47 * Abstract base class for session input buffers that stream data
48 * from a {@link InputStream}.
49 *
50 * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
51 *
52 *
53 * @deprecated Please use {@link java.net.URL#openConnection} instead.
54 *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
55 *     for further details.
56 */
57@Deprecated
58public abstract class AbstractSessionInputBuffer implements SessionInputBuffer {
59
60    private InputStream instream;
61    private byte[] buffer;
62    private int bufferpos;
63    private int bufferlen;
64
65    private ByteArrayBuffer linebuffer = null;
66
67    private String charset = HTTP.US_ASCII;
68    private boolean ascii = true;
69    private int maxLineLen = -1;
70
71    private HttpTransportMetricsImpl metrics;
72
73    protected void init(final InputStream instream, int buffersize, final HttpParams params) {
74        if (instream == null) {
75            throw new IllegalArgumentException("Input stream may not be null");
76        }
77        if (buffersize <= 0) {
78            throw new IllegalArgumentException("Buffer size may not be negative or zero");
79        }
80        if (params == null) {
81            throw new IllegalArgumentException("HTTP parameters may not be null");
82        }
83        this.instream = instream;
84        this.buffer = new byte[buffersize];
85        this.bufferpos = 0;
86        this.bufferlen = 0;
87        this.linebuffer = new ByteArrayBuffer(buffersize);
88        this.charset = HttpProtocolParams.getHttpElementCharset(params);
89        this.ascii = this.charset.equalsIgnoreCase(HTTP.US_ASCII)
90                     || this.charset.equalsIgnoreCase(HTTP.ASCII);
91        this.maxLineLen = params.getIntParameter(CoreConnectionPNames.MAX_LINE_LENGTH, -1);
92        this.metrics = new HttpTransportMetricsImpl();
93    }
94
95    protected int fillBuffer() throws IOException {
96        // compact the buffer if necessary
97        if (this.bufferpos > 0) {
98            int len = this.bufferlen - this.bufferpos;
99            if (len > 0) {
100                System.arraycopy(this.buffer, this.bufferpos, this.buffer, 0, len);
101            }
102            this.bufferpos = 0;
103            this.bufferlen = len;
104        }
105        int l;
106        int off = this.bufferlen;
107        int len = this.buffer.length - off;
108        l = this.instream.read(this.buffer, off, len);
109        if (l == -1) {
110            return -1;
111        } else {
112            this.bufferlen = off + l;
113            this.metrics.incrementBytesTransferred(l);
114            return l;
115        }
116    }
117
118    protected boolean hasBufferedData() {
119        return this.bufferpos < this.bufferlen;
120    }
121
122    public int read() throws IOException {
123        int noRead = 0;
124        while (!hasBufferedData()) {
125            noRead = fillBuffer();
126            if (noRead == -1) {
127                return -1;
128            }
129        }
130        return this.buffer[this.bufferpos++] & 0xff;
131    }
132
133    public int read(final byte[] b, int off, int len) throws IOException {
134        if (b == null) {
135            return 0;
136        }
137        int noRead = 0;
138        while (!hasBufferedData()) {
139            noRead = fillBuffer();
140            if (noRead == -1) {
141                return -1;
142            }
143        }
144        int chunk = this.bufferlen - this.bufferpos;
145        if (chunk > len) {
146            chunk = len;
147        }
148        System.arraycopy(this.buffer, this.bufferpos, b, off, chunk);
149        this.bufferpos += chunk;
150        return chunk;
151    }
152
153    public int read(final byte[] b) throws IOException {
154        if (b == null) {
155            return 0;
156        }
157        return read(b, 0, b.length);
158    }
159
160    private int locateLF() {
161        for (int i = this.bufferpos; i < this.bufferlen; i++) {
162            if (this.buffer[i] == HTTP.LF) {
163                return i;
164            }
165        }
166        return -1;
167    }
168
169    public int readLine(final CharArrayBuffer charbuffer) throws IOException {
170        if (charbuffer == null) {
171            throw new IllegalArgumentException("Char array buffer may not be null");
172        }
173        this.linebuffer.clear();
174        int noRead = 0;
175        boolean retry = true;
176        while (retry) {
177            // attempt to find end of line (LF)
178            int i = locateLF();
179            if (i != -1) {
180                // end of line found.
181                if (this.linebuffer.isEmpty()) {
182                    // the entire line is preset in the read buffer
183                    return lineFromReadBuffer(charbuffer, i);
184                }
185                retry = false;
186                int len = i + 1 - this.bufferpos;
187                this.linebuffer.append(this.buffer, this.bufferpos, len);
188                this.bufferpos = i + 1;
189            } else {
190                // end of line not found
191                if (hasBufferedData()) {
192                    int len = this.bufferlen - this.bufferpos;
193                    this.linebuffer.append(this.buffer, this.bufferpos, len);
194                    this.bufferpos = this.bufferlen;
195                }
196                noRead = fillBuffer();
197                if (noRead == -1) {
198                    retry = false;
199                }
200            }
201            if (this.maxLineLen > 0 && this.linebuffer.length() >= this.maxLineLen) {
202                throw new IOException("Maximum line length limit exceeded");
203            }
204        }
205        if (noRead == -1 && this.linebuffer.isEmpty()) {
206            // indicate the end of stream
207            return -1;
208        }
209        return lineFromLineBuffer(charbuffer);
210    }
211
212    private int lineFromLineBuffer(final CharArrayBuffer charbuffer)
213            throws IOException {
214        // discard LF if found
215        int l = this.linebuffer.length();
216        if (l > 0) {
217            if (this.linebuffer.byteAt(l - 1) == HTTP.LF) {
218                l--;
219                this.linebuffer.setLength(l);
220            }
221            // discard CR if found
222            if (l > 0) {
223                if (this.linebuffer.byteAt(l - 1) == HTTP.CR) {
224                    l--;
225                    this.linebuffer.setLength(l);
226                }
227            }
228        }
229        l = this.linebuffer.length();
230        if (this.ascii) {
231            charbuffer.append(this.linebuffer, 0, l);
232        } else {
233            // This is VERY memory inefficient, BUT since non-ASCII charsets are
234            // NOT meant to be used anyway, there's no point optimizing it
235            String s = new String(this.linebuffer.buffer(), 0, l, this.charset);
236            charbuffer.append(s);
237        }
238        return l;
239    }
240
241    private int lineFromReadBuffer(final CharArrayBuffer charbuffer, int pos)
242            throws IOException {
243        int off = this.bufferpos;
244        int len;
245        this.bufferpos = pos + 1;
246        // BEGIN android-changed
247        // The first test below was fixed to not try to skip beyond the
248        // start of the live part of the buffer.
249        if (pos > off && this.buffer[pos - 1] == HTTP.CR) {
250            // skip CR if found
251            pos--;
252        }
253        // END android-changed
254        len = pos - off;
255        if (this.ascii) {
256            charbuffer.append(this.buffer, off, len);
257        } else {
258            // This is VERY memory inefficient, BUT since non-ASCII charsets are
259            // NOT meant to be used anyway, there's no point optimizing it
260            String s = new String(this.buffer, off, len, this.charset);
261            charbuffer.append(s);
262        }
263        return len;
264    }
265
266    public String readLine() throws IOException {
267        CharArrayBuffer charbuffer = new CharArrayBuffer(64);
268        int l = readLine(charbuffer);
269        if (l != -1) {
270            return charbuffer.toString();
271        } else {
272            return null;
273        }
274    }
275
276    public HttpTransportMetrics getMetrics() {
277        return this.metrics;
278    }
279
280}
281