Home | History | Annotate | Download | only in io
      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 
     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