1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/io/AbstractSessionOutputBuffer.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,241 @@ 1.4 +/* 1.5 + * ==================================================================== 1.6 + * Licensed to the Apache Software Foundation (ASF) under one 1.7 + * or more contributor license agreements. See the NOTICE file 1.8 + * distributed with this work for additional information 1.9 + * regarding copyright ownership. The ASF licenses this file 1.10 + * to you under the Apache License, Version 2.0 (the 1.11 + * "License"); you may not use this file except in compliance 1.12 + * with the License. You may obtain a copy of the License at 1.13 + * 1.14 + * http://www.apache.org/licenses/LICENSE-2.0 1.15 + * 1.16 + * Unless required by applicable law or agreed to in writing, 1.17 + * software distributed under the License is distributed on an 1.18 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 1.19 + * KIND, either express or implied. See the License for the 1.20 + * specific language governing permissions and limitations 1.21 + * under the License. 1.22 + * ==================================================================== 1.23 + * 1.24 + * This software consists of voluntary contributions made by many 1.25 + * individuals on behalf of the Apache Software Foundation. For more 1.26 + * information on the Apache Software Foundation, please see 1.27 + * <http://www.apache.org/>. 1.28 + * 1.29 + */ 1.30 + 1.31 +package ch.boye.httpclientandroidlib.impl.io; 1.32 + 1.33 +import java.io.IOException; 1.34 +import java.io.OutputStream; 1.35 + 1.36 +import ch.boye.httpclientandroidlib.io.BufferInfo; 1.37 +import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; 1.38 +import ch.boye.httpclientandroidlib.io.HttpTransportMetrics; 1.39 +import ch.boye.httpclientandroidlib.params.CoreConnectionPNames; 1.40 +import ch.boye.httpclientandroidlib.params.HttpParams; 1.41 +import ch.boye.httpclientandroidlib.params.HttpProtocolParams; 1.42 +import ch.boye.httpclientandroidlib.protocol.HTTP; 1.43 +import ch.boye.httpclientandroidlib.util.ByteArrayBuffer; 1.44 +import ch.boye.httpclientandroidlib.util.CharArrayBuffer; 1.45 + 1.46 +/** 1.47 + * Abstract base class for session output buffers that stream data to 1.48 + * an arbitrary {@link OutputStream}. This class buffers small chunks of 1.49 + * output data in an internal byte array for optimal output performance. 1.50 + * <p> 1.51 + * {@link #writeLine(CharArrayBuffer)} and {@link #writeLine(String)} methods 1.52 + * of this class use CR-LF as a line delimiter. 1.53 + * <p> 1.54 + * The following parameters can be used to customize the behavior of this 1.55 + * class: 1.56 + * <ul> 1.57 + * <li>{@link ch.boye.httpclientandroidlib.params.CoreProtocolPNames#HTTP_ELEMENT_CHARSET}</li> 1.58 + * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MIN_CHUNK_LIMIT}</li> 1.59 + * </ul> 1.60 + * <p> 1.61 + * 1.62 + * @since 4.0 1.63 + */ 1.64 +public abstract class AbstractSessionOutputBuffer implements SessionOutputBuffer, BufferInfo { 1.65 + 1.66 + private static final byte[] CRLF = new byte[] {HTTP.CR, HTTP.LF}; 1.67 + 1.68 + private OutputStream outstream; 1.69 + private ByteArrayBuffer buffer; 1.70 + 1.71 + private String charset = HTTP.US_ASCII; 1.72 + private boolean ascii = true; 1.73 + private int minChunkLimit = 512; 1.74 + 1.75 + private HttpTransportMetricsImpl metrics; 1.76 + 1.77 + /** 1.78 + * Initializes this session output buffer. 1.79 + * 1.80 + * @param outstream the destination output stream. 1.81 + * @param buffersize the size of the internal buffer. 1.82 + * @param params HTTP parameters. 1.83 + */ 1.84 + protected void init(final OutputStream outstream, int buffersize, final HttpParams params) { 1.85 + if (outstream == null) { 1.86 + throw new IllegalArgumentException("Input stream may not be null"); 1.87 + } 1.88 + if (buffersize <= 0) { 1.89 + throw new IllegalArgumentException("Buffer size may not be negative or zero"); 1.90 + } 1.91 + if (params == null) { 1.92 + throw new IllegalArgumentException("HTTP parameters may not be null"); 1.93 + } 1.94 + this.outstream = outstream; 1.95 + this.buffer = new ByteArrayBuffer(buffersize); 1.96 + this.charset = HttpProtocolParams.getHttpElementCharset(params); 1.97 + this.ascii = this.charset.equalsIgnoreCase(HTTP.US_ASCII) 1.98 + || this.charset.equalsIgnoreCase(HTTP.ASCII); 1.99 + this.minChunkLimit = params.getIntParameter(CoreConnectionPNames.MIN_CHUNK_LIMIT, 512); 1.100 + this.metrics = createTransportMetrics(); 1.101 + } 1.102 + 1.103 + /** 1.104 + * @since 4.1 1.105 + */ 1.106 + protected HttpTransportMetricsImpl createTransportMetrics() { 1.107 + return new HttpTransportMetricsImpl(); 1.108 + } 1.109 + 1.110 + /** 1.111 + * @since 4.`1 1.112 + */ 1.113 + public int capacity() { 1.114 + return this.buffer.capacity(); 1.115 + } 1.116 + 1.117 + /** 1.118 + * @since 4.1 1.119 + */ 1.120 + public int length() { 1.121 + return this.buffer.length(); 1.122 + } 1.123 + 1.124 + /** 1.125 + * @since 4.1 1.126 + */ 1.127 + public int available() { 1.128 + return capacity() - length(); 1.129 + } 1.130 + 1.131 + protected void flushBuffer() throws IOException { 1.132 + int len = this.buffer.length(); 1.133 + if (len > 0) { 1.134 + this.outstream.write(this.buffer.buffer(), 0, len); 1.135 + this.buffer.clear(); 1.136 + this.metrics.incrementBytesTransferred(len); 1.137 + } 1.138 + } 1.139 + 1.140 + public void flush() throws IOException { 1.141 + flushBuffer(); 1.142 + this.outstream.flush(); 1.143 + } 1.144 + 1.145 + public void write(final byte[] b, int off, int len) throws IOException { 1.146 + if (b == null) { 1.147 + return; 1.148 + } 1.149 + // Do not want to buffer large-ish chunks 1.150 + // if the byte array is larger then MIN_CHUNK_LIMIT 1.151 + // write it directly to the output stream 1.152 + if (len > this.minChunkLimit || len > this.buffer.capacity()) { 1.153 + // flush the buffer 1.154 + flushBuffer(); 1.155 + // write directly to the out stream 1.156 + this.outstream.write(b, off, len); 1.157 + this.metrics.incrementBytesTransferred(len); 1.158 + } else { 1.159 + // Do not let the buffer grow unnecessarily 1.160 + int freecapacity = this.buffer.capacity() - this.buffer.length(); 1.161 + if (len > freecapacity) { 1.162 + // flush the buffer 1.163 + flushBuffer(); 1.164 + } 1.165 + // buffer 1.166 + this.buffer.append(b, off, len); 1.167 + } 1.168 + } 1.169 + 1.170 + public void write(final byte[] b) throws IOException { 1.171 + if (b == null) { 1.172 + return; 1.173 + } 1.174 + write(b, 0, b.length); 1.175 + } 1.176 + 1.177 + public void write(int b) throws IOException { 1.178 + if (this.buffer.isFull()) { 1.179 + flushBuffer(); 1.180 + } 1.181 + this.buffer.append(b); 1.182 + } 1.183 + 1.184 + /** 1.185 + * Writes characters from the specified string followed by a line delimiter 1.186 + * to this session buffer. 1.187 + * <p> 1.188 + * This method uses CR-LF as a line delimiter. 1.189 + * 1.190 + * @param s the line. 1.191 + * @exception IOException if an I/O error occurs. 1.192 + */ 1.193 + public void writeLine(final String s) throws IOException { 1.194 + if (s == null) { 1.195 + return; 1.196 + } 1.197 + if (s.length() > 0) { 1.198 + write(s.getBytes(this.charset)); 1.199 + } 1.200 + write(CRLF); 1.201 + } 1.202 + 1.203 + /** 1.204 + * Writes characters from the specified char array followed by a line 1.205 + * delimiter to this session buffer. 1.206 + * <p> 1.207 + * This method uses CR-LF as a line delimiter. 1.208 + * 1.209 + * @param s the buffer containing chars of the line. 1.210 + * @exception IOException if an I/O error occurs. 1.211 + */ 1.212 + public void writeLine(final CharArrayBuffer s) throws IOException { 1.213 + if (s == null) { 1.214 + return; 1.215 + } 1.216 + if (this.ascii) { 1.217 + int off = 0; 1.218 + int remaining = s.length(); 1.219 + while (remaining > 0) { 1.220 + int chunk = this.buffer.capacity() - this.buffer.length(); 1.221 + chunk = Math.min(chunk, remaining); 1.222 + if (chunk > 0) { 1.223 + this.buffer.append(s, off, chunk); 1.224 + } 1.225 + if (this.buffer.isFull()) { 1.226 + flushBuffer(); 1.227 + } 1.228 + off += chunk; 1.229 + remaining -= chunk; 1.230 + } 1.231 + } else { 1.232 + // This is VERY memory inefficient, BUT since non-ASCII charsets are 1.233 + // NOT meant to be used anyway, there's no point optimizing it 1.234 + byte[] tmp = s.toString().getBytes(this.charset); 1.235 + write(tmp); 1.236 + } 1.237 + write(CRLF); 1.238 + } 1.239 + 1.240 + public HttpTransportMetrics getMetrics() { 1.241 + return this.metrics; 1.242 + } 1.243 + 1.244 +}