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 
32 package org.apache.http.impl.io;
33 
34 import java.io.IOException;
35 import java.io.InputStream;
36 
37 import org.apache.http.io.SessionInputBuffer;
38 import org.apache.http.io.HttpTransportMetrics;
39 import org.apache.http.params.CoreConnectionPNames;
40 import org.apache.http.params.HttpParams;
41 import org.apache.http.params.HttpProtocolParams;
42 import org.apache.http.protocol.HTTP;
43 import org.apache.http.util.ByteArrayBuffer;
44 import 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
58 public 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 
init(final InputStream instream, int buffersize, final HttpParams params)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 
fillBuffer()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 
hasBufferedData()118     protected boolean hasBufferedData() {
119         return this.bufferpos < this.bufferlen;
120     }
121 
read()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 
read(final byte[] b, int off, int len)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 
read(final byte[] b)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 
locateLF()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 
readLine(final CharArrayBuffer charbuffer)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 
lineFromLineBuffer(final CharArrayBuffer charbuffer)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 
lineFromReadBuffer(final CharArrayBuffer charbuffer, int pos)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 
readLine()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 
getMetrics()276     public HttpTransportMetrics getMetrics() {
277         return this.metrics;
278     }
279 
280 }
281