1a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath/* 2a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Copyright (C) 2008 The Android Open Source Project 3a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * 4a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Licensed under the Apache License, Version 2.0 (the "License"); 5a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * you may not use this file except in compliance with the License. 6a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * You may obtain a copy of the License at 7a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * 8a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 9a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * 10a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Unless required by applicable law or agreed to in writing, software 11a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, 12a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * See the License for the specific language governing permissions and 14a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * limitations under the License. 15a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 16a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 17a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathpackage android.net.http; 18a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 19a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.HttpConnection; 20a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.HttpClientConnection; 21a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.HttpConnectionMetrics; 22a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.HttpEntity; 23a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.HttpEntityEnclosingRequest; 24a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.HttpException; 25a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.HttpInetConnection; 26a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.HttpRequest; 27a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.HttpResponse; 28a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.NoHttpResponseException; 29a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.StatusLine; 30a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.entity.BasicHttpEntity; 31a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.entity.ContentLengthStrategy; 32a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.impl.HttpConnectionMetricsImpl; 33a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.impl.entity.EntitySerializer; 34a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.impl.entity.StrictContentLengthStrategy; 35a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.impl.io.ChunkedInputStream; 36a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.impl.io.ContentLengthInputStream; 37a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.impl.io.HttpRequestWriter; 38a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.impl.io.IdentityInputStream; 39a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.impl.io.SocketInputBuffer; 40a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.impl.io.SocketOutputBuffer; 41a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.io.HttpMessageWriter; 42a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.io.SessionInputBuffer; 43a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.io.SessionOutputBuffer; 44a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.message.BasicLineParser; 45a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.message.ParserCursor; 46a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.params.CoreConnectionPNames; 47a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.params.HttpConnectionParams; 48a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.params.HttpParams; 49a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.ParseException; 50a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport org.apache.http.util.CharArrayBuffer; 51a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 52a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport java.io.IOException; 53a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport java.net.InetAddress; 54a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport java.net.Socket; 55a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathimport java.net.SocketException; 56a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 57a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath/** 58a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * A alternate class for (@link DefaultHttpClientConnection). 59a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * It has better performance than DefaultHttpClientConnection 60a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 61a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamathpublic class AndroidHttpClientConnection 62a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath implements HttpInetConnection, HttpConnection { 63a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 64a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private SessionInputBuffer inbuffer = null; 65a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private SessionOutputBuffer outbuffer = null; 66a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private int maxHeaderCount; 67a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // store CoreConnectionPNames.MAX_LINE_LENGTH for performance 68a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private int maxLineLength; 69a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 70a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private final EntitySerializer entityserializer; 71a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 72a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private HttpMessageWriter requestWriter = null; 73a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private HttpConnectionMetricsImpl metrics = null; 74a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private volatile boolean open; 75a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private Socket socket = null; 76a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 77a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public AndroidHttpClientConnection() { 78a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.entityserializer = new EntitySerializer( 79a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath new StrictContentLengthStrategy()); 80a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 81a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 82a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 83a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Bind socket and set HttpParams to AndroidHttpClientConnection 84a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param socket outgoing socket 85a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param params HttpParams 86a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @throws IOException 87a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 88a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void bind( 89a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath final Socket socket, 90a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath final HttpParams params) throws IOException { 91a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (socket == null) { 92a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath throw new IllegalArgumentException("Socket may not be null"); 93a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 94a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (params == null) { 95a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath throw new IllegalArgumentException("HTTP parameters may not be null"); 96a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 97a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath assertNotOpen(); 98a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath socket.setTcpNoDelay(HttpConnectionParams.getTcpNoDelay(params)); 99a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath socket.setSoTimeout(HttpConnectionParams.getSoTimeout(params)); 100a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 101a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath int linger = HttpConnectionParams.getLinger(params); 102a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (linger >= 0) { 103a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath socket.setSoLinger(linger > 0, linger); 104a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 105a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.socket = socket; 106a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 107a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath int buffersize = HttpConnectionParams.getSocketBufferSize(params); 108a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.inbuffer = new SocketInputBuffer(socket, buffersize, params); 109a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.outbuffer = new SocketOutputBuffer(socket, buffersize, params); 110a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 111a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath maxHeaderCount = params.getIntParameter( 112a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath CoreConnectionPNames.MAX_HEADER_COUNT, -1); 113a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath maxLineLength = params.getIntParameter( 114a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath CoreConnectionPNames.MAX_LINE_LENGTH, -1); 115a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 116a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.requestWriter = new HttpRequestWriter(outbuffer, null, params); 117a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 118a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.metrics = new HttpConnectionMetricsImpl( 119a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath inbuffer.getMetrics(), 120a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath outbuffer.getMetrics()); 121a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 122a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.open = true; 123a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 124a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 125a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath @Override 126a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public String toString() { 127a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath StringBuilder buffer = new StringBuilder(); 128a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath buffer.append(getClass().getSimpleName()).append("["); 129a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (isOpen()) { 130a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath buffer.append(getRemotePort()); 131a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 132a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath buffer.append("closed"); 133a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 134a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath buffer.append("]"); 135a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return buffer.toString(); 136a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 137a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 138a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 139a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private void assertNotOpen() { 140a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (this.open) { 141a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath throw new IllegalStateException("Connection is already open"); 142a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 143a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 144a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 145a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private void assertOpen() { 146a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (!this.open) { 147a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath throw new IllegalStateException("Connection is not open"); 148a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 149a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 150a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 151a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public boolean isOpen() { 152a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // to make this method useful, we want to check if the socket is connected 153a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return (this.open && this.socket != null && this.socket.isConnected()); 154a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 155a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 156a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public InetAddress getLocalAddress() { 157a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (this.socket != null) { 158a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return this.socket.getLocalAddress(); 159a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 160a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return null; 161a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 162a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 163a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 164a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public int getLocalPort() { 165a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (this.socket != null) { 166a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return this.socket.getLocalPort(); 167a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 168a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return -1; 169a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 170a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 171a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 172a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public InetAddress getRemoteAddress() { 173a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (this.socket != null) { 174a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return this.socket.getInetAddress(); 175a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 176a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return null; 177a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 178a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 179a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 180a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public int getRemotePort() { 181a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (this.socket != null) { 182a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return this.socket.getPort(); 183a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 184a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return -1; 185a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 186a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 187a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 188a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void setSocketTimeout(int timeout) { 189a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath assertOpen(); 190a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (this.socket != null) { 191a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath try { 192a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.socket.setSoTimeout(timeout); 193a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } catch (SocketException ignore) { 194a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // It is not quite clear from the original documentation if there are any 195a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // other legitimate cases for a socket exception to be thrown when setting 196a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // SO_TIMEOUT besides the socket being already closed 197a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 198a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 199a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 200a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 201a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public int getSocketTimeout() { 202a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (this.socket != null) { 203a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath try { 204a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return this.socket.getSoTimeout(); 205a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } catch (SocketException ignore) { 206a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return -1; 207a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 208a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 209a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return -1; 210a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 211a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 212a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 213a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void shutdown() throws IOException { 214a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.open = false; 215a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath Socket tmpsocket = this.socket; 216a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (tmpsocket != null) { 217a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath tmpsocket.close(); 218a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 219a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 220a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 221a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void close() throws IOException { 222a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (!this.open) { 223a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return; 224a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 225a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.open = false; 226a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath doFlush(); 227a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath try { 228a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath try { 229a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.socket.shutdownOutput(); 230a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } catch (IOException ignore) { 231a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 232a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath try { 233a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.socket.shutdownInput(); 234a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } catch (IOException ignore) { 235a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 236a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } catch (UnsupportedOperationException ignore) { 237a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // if one isn't supported, the other one isn't either 238a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 239a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.socket.close(); 240a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 241a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 242a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 243a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Sends the request line and all headers over the connection. 244a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param request the request whose headers to send. 245a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @throws HttpException 246a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @throws IOException 247a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 248a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void sendRequestHeader(final HttpRequest request) 249a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath throws HttpException, IOException { 250a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (request == null) { 251a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath throw new IllegalArgumentException("HTTP request may not be null"); 252a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 253a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath assertOpen(); 254a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.requestWriter.write(request); 255a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.metrics.incrementRequestCount(); 256a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 257a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 258a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 259a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Sends the request entity over the connection. 260a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param request the request whose entity to send. 261a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @throws HttpException 262a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @throws IOException 263a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 264a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void sendRequestEntity(final HttpEntityEnclosingRequest request) 265a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath throws HttpException, IOException { 266a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (request == null) { 267a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath throw new IllegalArgumentException("HTTP request may not be null"); 268a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 269a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath assertOpen(); 270a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (request.getEntity() == null) { 271a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return; 272a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 273a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.entityserializer.serialize( 274a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.outbuffer, 275a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath request, 276a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath request.getEntity()); 277a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 278a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 279a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath protected void doFlush() throws IOException { 280a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.outbuffer.flush(); 281a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 282a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 283a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public void flush() throws IOException { 284a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath assertOpen(); 285a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath doFlush(); 286a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 287a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 288a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 289a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Parses the response headers and adds them to the 290a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * given {@code headers} object, and returns the response StatusLine 291a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param headers store parsed header to headers. 292a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @throws IOException 293a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @return StatusLine 294a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @see HttpClientConnection#receiveResponseHeader() 295a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 296a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public StatusLine parseResponseHeader(Headers headers) 297a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath throws IOException, ParseException { 298a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath assertOpen(); 299a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 300a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath CharArrayBuffer current = new CharArrayBuffer(64); 301a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 302a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (inbuffer.readLine(current) == -1) { 303a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath throw new NoHttpResponseException("The target server failed to respond"); 304a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 305a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 306a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // Create the status line from the status string 307a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath StatusLine statusline = BasicLineParser.DEFAULT.parseStatusLine( 308a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath current, new ParserCursor(0, current.length())); 309a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 310a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (HttpLog.LOGV) HttpLog.v("read: " + statusline); 311a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath int statusCode = statusline.getStatusCode(); 312a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 313a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // Parse header body 314a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath CharArrayBuffer previous = null; 315a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath int headerNumber = 0; 316a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath while(true) { 317a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (current == null) { 318a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath current = new CharArrayBuffer(64); 319a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 320a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // This must be he buffer used to parse the status 321a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath current.clear(); 322a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 323a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath int l = inbuffer.readLine(current); 324a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (l == -1 || current.length() < 1) { 325a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath break; 326a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 327a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // Parse the header name and value 328a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // Check for folded headers first 329a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2 330a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // discussion on folded headers 331a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath char first = current.charAt(0); 332a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if ((first == ' ' || first == '\t') && previous != null) { 333a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // we have continuation folded header 334a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // so append value 335a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath int start = 0; 336a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath int length = current.length(); 337a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath while (start < length) { 338a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath char ch = current.charAt(start); 339a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (ch != ' ' && ch != '\t') { 340a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath break; 341a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 342a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath start++; 343a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 344a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (maxLineLength > 0 && 345a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath previous.length() + 1 + current.length() - start > 346a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath maxLineLength) { 347a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath throw new IOException("Maximum line length limit exceeded"); 348a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 349a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath previous.append(' '); 350a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath previous.append(current, start, current.length() - start); 351a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 352a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (previous != null) { 353a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath headers.parseHeader(previous); 354a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 355a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath headerNumber++; 356a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath previous = current; 357a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath current = null; 358a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 359a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (maxHeaderCount > 0 && headerNumber >= maxHeaderCount) { 360a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath throw new IOException("Maximum header count exceeded"); 361a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 362a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 363a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 364a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (previous != null) { 365a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath headers.parseHeader(previous); 366a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 367a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 368a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (statusCode >= 200) { 369a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.metrics.incrementResponseCount(); 370a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 371a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return statusline; 372a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 373a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 374a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 375a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Return the next response entity. 376a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @param headers contains values for parsing entity 377a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @see HttpClientConnection#receiveResponseEntity(HttpResponse response) 378a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 379a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public HttpEntity receiveResponseEntity(final Headers headers) { 380a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath assertOpen(); 381a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath BasicHttpEntity entity = new BasicHttpEntity(); 382a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 383a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath long len = determineLength(headers); 384a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (len == ContentLengthStrategy.CHUNKED) { 385a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entity.setChunked(true); 386a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entity.setContentLength(-1); 387a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entity.setContent(new ChunkedInputStream(inbuffer)); 388a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else if (len == ContentLengthStrategy.IDENTITY) { 389a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entity.setChunked(false); 390a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entity.setContentLength(-1); 391a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entity.setContent(new IdentityInputStream(inbuffer)); 392a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 393a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entity.setChunked(false); 394a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entity.setContentLength(len); 395a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entity.setContent(new ContentLengthInputStream(inbuffer, len)); 396a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 397a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 398a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath String contentTypeHeader = headers.getContentType(); 399a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (contentTypeHeader != null) { 400a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entity.setContentType(contentTypeHeader); 401a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 402a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath String contentEncodingHeader = headers.getContentEncoding(); 403a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (contentEncodingHeader != null) { 404a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath entity.setContentEncoding(contentEncodingHeader); 405a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 406a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 407a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return entity; 408a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 409a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 410a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath private long determineLength(final Headers headers) { 411a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath long transferEncoding = headers.getTransferEncoding(); 412a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // We use Transfer-Encoding if present and ignore Content-Length. 413a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath // RFC2616, 4.4 item number 3 414a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (transferEncoding < Headers.NO_TRANSFER_ENCODING) { 415a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return transferEncoding; 416a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 417a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath long contentlen = headers.getContentLength(); 418a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath if (contentlen > Headers.NO_CONTENT_LENGTH) { 419a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return contentlen; 420a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } else { 421a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return ContentLengthStrategy.IDENTITY; 422a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 423a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 424a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 425a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 426a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 427a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Checks whether this connection has gone down. 428a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Network connections may get closed during some time of inactivity 429a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * for several reasons. The next time a read is attempted on such a 430a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * connection it will throw an IOException. 431a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * This method tries to alleviate this inconvenience by trying to 432a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * find out if a connection is still usable. Implementations may do 433a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * that by attempting a read with a very small timeout. Thus this 434a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * method may block for a small amount of time before returning a result. 435a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * It is therefore an <i>expensive</i> operation. 436a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * 437a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @return <code>true</code> if attempts to use this connection are 438a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * likely to succeed, or <code>false</code> if they are likely 439a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * to fail and this connection should be closed 440a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 441a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public boolean isStale() { 442a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath assertOpen(); 443a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath try { 444a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath this.inbuffer.isDataAvailable(1); 445a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return false; 446a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } catch (IOException ex) { 447a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return true; 448a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 449a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 450a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath 451a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath /** 452a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * Returns a collection of connection metrcis 453a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath * @return HttpConnectionMetrics 454a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath */ 455a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath public HttpConnectionMetrics getMetrics() { 456a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath return this.metrics; 457a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath } 458a8b46a3d3b6ed1488df10740653829283572903bNarayan Kamath} 459