michael@0: /* michael@0: * ==================================================================== michael@0: * Licensed to the Apache Software Foundation (ASF) under one michael@0: * or more contributor license agreements. See the NOTICE file michael@0: * distributed with this work for additional information michael@0: * regarding copyright ownership. The ASF licenses this file michael@0: * to you under the Apache License, Version 2.0 (the michael@0: * "License"); you may not use this file except in compliance michael@0: * with the License. You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, michael@0: * software distributed under the License is distributed on an michael@0: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY michael@0: * KIND, either express or implied. See the License for the michael@0: * specific language governing permissions and limitations michael@0: * under the License. michael@0: * ==================================================================== michael@0: * michael@0: * This software consists of voluntary contributions made by many michael@0: * individuals on behalf of the Apache Software Foundation. For more michael@0: * information on the Apache Software Foundation, please see michael@0: * . michael@0: * michael@0: */ michael@0: michael@0: package ch.boye.httpclientandroidlib.impl.conn; michael@0: michael@0: import java.io.IOException; michael@0: import java.net.Socket; michael@0: import java.util.HashMap; michael@0: import java.util.Map; michael@0: michael@0: import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; michael@0: michael@0: import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog; michael@0: /* LogFactory removed by HttpClient for Android script. */ michael@0: import ch.boye.httpclientandroidlib.Header; michael@0: import ch.boye.httpclientandroidlib.HttpException; michael@0: import ch.boye.httpclientandroidlib.HttpHost; michael@0: import ch.boye.httpclientandroidlib.HttpRequest; michael@0: import ch.boye.httpclientandroidlib.HttpResponse; michael@0: import ch.boye.httpclientandroidlib.HttpResponseFactory; michael@0: import ch.boye.httpclientandroidlib.params.HttpParams; michael@0: import ch.boye.httpclientandroidlib.params.HttpProtocolParams; michael@0: import ch.boye.httpclientandroidlib.protocol.HttpContext; michael@0: import ch.boye.httpclientandroidlib.impl.SocketHttpClientConnection; michael@0: import ch.boye.httpclientandroidlib.io.HttpMessageParser; michael@0: import ch.boye.httpclientandroidlib.io.SessionInputBuffer; michael@0: import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; michael@0: michael@0: import ch.boye.httpclientandroidlib.conn.OperatedClientConnection; michael@0: michael@0: /** michael@0: * Default implementation of an operated client connection. michael@0: *

michael@0: * The following parameters can be used to customize the behavior of this michael@0: * class: michael@0: *

michael@0: * michael@0: * @since 4.0 michael@0: */ michael@0: @NotThreadSafe // connSecure, targetHost michael@0: public class DefaultClientConnection extends SocketHttpClientConnection michael@0: implements OperatedClientConnection, HttpContext { michael@0: michael@0: public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass()); michael@0: public HttpClientAndroidLog headerLog = new HttpClientAndroidLog("ch.boye.httpclientandroidlib.headers"); michael@0: public HttpClientAndroidLog wireLog = new HttpClientAndroidLog("ch.boye.httpclientandroidlib.wire"); michael@0: michael@0: /** The unconnected socket */ michael@0: private volatile Socket socket; michael@0: michael@0: /** The target host of this connection. */ michael@0: private HttpHost targetHost; michael@0: michael@0: /** Whether this connection is secure. */ michael@0: private boolean connSecure; michael@0: michael@0: /** True if this connection was shutdown. */ michael@0: private volatile boolean shutdown; michael@0: michael@0: /** connection specific attributes */ michael@0: private final Map attributes; michael@0: michael@0: public DefaultClientConnection() { michael@0: super(); michael@0: this.attributes = new HashMap(); michael@0: } michael@0: michael@0: public final HttpHost getTargetHost() { michael@0: return this.targetHost; michael@0: } michael@0: michael@0: public final boolean isSecure() { michael@0: return this.connSecure; michael@0: } michael@0: michael@0: @Override michael@0: public final Socket getSocket() { michael@0: return this.socket; michael@0: } michael@0: michael@0: public void opening(Socket sock, HttpHost target) throws IOException { michael@0: assertNotOpen(); michael@0: this.socket = sock; michael@0: this.targetHost = target; michael@0: michael@0: // Check for shutdown after assigning socket, so that michael@0: if (this.shutdown) { michael@0: sock.close(); // allow this to throw... michael@0: // ...but if it doesn't, explicitly throw one ourselves. michael@0: throw new IOException("Connection already shutdown"); michael@0: } michael@0: } michael@0: michael@0: public void openCompleted(boolean secure, HttpParams params) throws IOException { michael@0: assertNotOpen(); michael@0: if (params == null) { michael@0: throw new IllegalArgumentException michael@0: ("Parameters must not be null."); michael@0: } michael@0: this.connSecure = secure; michael@0: bind(this.socket, params); michael@0: } michael@0: michael@0: /** michael@0: * Force-closes this connection. michael@0: * If the connection is still in the process of being open (the method michael@0: * {@link #opening opening} was already called but michael@0: * {@link #openCompleted openCompleted} was not), the associated michael@0: * socket that is being connected to a remote address will be closed. michael@0: * That will interrupt a thread that is blocked on connecting michael@0: * the socket. michael@0: * If the connection is not yet open, this will prevent the connection michael@0: * from being opened. michael@0: * michael@0: * @throws IOException in case of a problem michael@0: */ michael@0: @Override michael@0: public void shutdown() throws IOException { michael@0: shutdown = true; michael@0: try { michael@0: super.shutdown(); michael@0: log.debug("Connection shut down"); michael@0: Socket sock = this.socket; // copy volatile attribute michael@0: if (sock != null) michael@0: sock.close(); michael@0: } catch (IOException ex) { michael@0: log.debug("I/O error shutting down connection", ex); michael@0: } michael@0: } michael@0: michael@0: @Override michael@0: public void close() throws IOException { michael@0: try { michael@0: super.close(); michael@0: log.debug("Connection closed"); michael@0: } catch (IOException ex) { michael@0: log.debug("I/O error closing connection", ex); michael@0: } michael@0: } michael@0: michael@0: @Override michael@0: protected SessionInputBuffer createSessionInputBuffer( michael@0: final Socket socket, michael@0: int buffersize, michael@0: final HttpParams params) throws IOException { michael@0: if (buffersize == -1) { michael@0: buffersize = 8192; michael@0: } michael@0: SessionInputBuffer inbuffer = super.createSessionInputBuffer( michael@0: socket, michael@0: buffersize, michael@0: params); michael@0: if (wireLog.isDebugEnabled()) { michael@0: inbuffer = new LoggingSessionInputBuffer( michael@0: inbuffer, michael@0: new Wire(wireLog), michael@0: HttpProtocolParams.getHttpElementCharset(params)); michael@0: } michael@0: return inbuffer; michael@0: } michael@0: michael@0: @Override michael@0: protected SessionOutputBuffer createSessionOutputBuffer( michael@0: final Socket socket, michael@0: int buffersize, michael@0: final HttpParams params) throws IOException { michael@0: if (buffersize == -1) { michael@0: buffersize = 8192; michael@0: } michael@0: SessionOutputBuffer outbuffer = super.createSessionOutputBuffer( michael@0: socket, michael@0: buffersize, michael@0: params); michael@0: if (wireLog.isDebugEnabled()) { michael@0: outbuffer = new LoggingSessionOutputBuffer( michael@0: outbuffer, michael@0: new Wire(wireLog), michael@0: HttpProtocolParams.getHttpElementCharset(params)); michael@0: } michael@0: return outbuffer; michael@0: } michael@0: michael@0: @Override michael@0: protected HttpMessageParser createResponseParser( michael@0: final SessionInputBuffer buffer, michael@0: final HttpResponseFactory responseFactory, michael@0: final HttpParams params) { michael@0: // override in derived class to specify a line parser michael@0: return new DefaultResponseParser michael@0: (buffer, null, responseFactory, params); michael@0: } michael@0: michael@0: public void update(Socket sock, HttpHost target, michael@0: boolean secure, HttpParams params) michael@0: throws IOException { michael@0: michael@0: assertOpen(); michael@0: if (target == null) { michael@0: throw new IllegalArgumentException michael@0: ("Target host must not be null."); michael@0: } michael@0: if (params == null) { michael@0: throw new IllegalArgumentException michael@0: ("Parameters must not be null."); michael@0: } michael@0: michael@0: if (sock != null) { michael@0: this.socket = sock; michael@0: bind(sock, params); michael@0: } michael@0: targetHost = target; michael@0: connSecure = secure; michael@0: } michael@0: michael@0: @Override michael@0: public HttpResponse receiveResponseHeader() throws HttpException, IOException { michael@0: HttpResponse response = super.receiveResponseHeader(); michael@0: if (log.isDebugEnabled()) { michael@0: log.debug("Receiving response: " + response.getStatusLine()); michael@0: } michael@0: if (headerLog.isDebugEnabled()) { michael@0: headerLog.debug("<< " + response.getStatusLine().toString()); michael@0: Header[] headers = response.getAllHeaders(); michael@0: for (Header header : headers) { michael@0: headerLog.debug("<< " + header.toString()); michael@0: } michael@0: } michael@0: return response; michael@0: } michael@0: michael@0: @Override michael@0: public void sendRequestHeader(HttpRequest request) throws HttpException, IOException { michael@0: if (log.isDebugEnabled()) { michael@0: log.debug("Sending request: " + request.getRequestLine()); michael@0: } michael@0: super.sendRequestHeader(request); michael@0: if (headerLog.isDebugEnabled()) { michael@0: headerLog.debug(">> " + request.getRequestLine().toString()); michael@0: Header[] headers = request.getAllHeaders(); michael@0: for (Header header : headers) { michael@0: headerLog.debug(">> " + header.toString()); michael@0: } michael@0: } michael@0: } michael@0: michael@0: public Object getAttribute(final String id) { michael@0: return this.attributes.get(id); michael@0: } michael@0: michael@0: public Object removeAttribute(final String id) { michael@0: return this.attributes.remove(id); michael@0: } michael@0: michael@0: public void setAttribute(final String id, final Object obj) { michael@0: this.attributes.put(id, obj); michael@0: } michael@0: michael@0: }