Index: src/java/org/apache/http/conn/SocketFactory.java =================================================================== --- src/java/org/apache/http/conn/SocketFactory.java (revision 490517) +++ src/java/org/apache/http/conn/SocketFactory.java (working copy) @@ -39,43 +39,61 @@ import org.apache.http.params.HttpParams; /** - * A factory for creating Sockets. + * A factory for creating and connecting sockets. + * The factory encapsulates the logic for establishing a socket connection. + *
+ * Both {@link java.lang.Object#equals(java.lang.Object) Object.equals()} + * and {@link java.lang.Object#hashCode() Object.hashCode()} + * must be overridden for the correct operation of some connection managers. * - *

Both {@link java.lang.Object#equals(java.lang.Object) Object.equals()} and - * {@link java.lang.Object#hashCode() Object.hashCode()} should be overridden appropriately. - * Protocol socket factories are used to uniquely identify Protocols and - * HostConfigurations, and equals() and hashCode() are - * required for the correct operation of some connection managers.

- * - * @see Scheme - * + * @author Roland Weber * @author Michael Becke * @author Mike Bowler - * - * @since 2.0 */ public interface SocketFactory { /** - * Gets a new socket connection to the given host. + * Creates a new, unconnected socket. + * The socket can subsequently be passed to + * {@link #createSocket(Socket,String,int,InetAddress,int,HttpParams) + * createSocket(Socket,...)}. + * + * @return a new socket * - * @param host the host name/IP - * @param port the port on the host - * @param localAddress the local host name/IP to bind the socket to - * @param localPort the port on the local machine - * @param params {@link HttpParams Http parameters} + * @throws IOException if an I/O error occurs while creating the socket + */ + Socket createSocket() + throws IOException + ; + + + /** + * Creates a socket connected to the given host. * - * @return Socket a new socket + * @param sock the socket to connect, as obtained from + * {@link #createSocket createSocket}. + * null indicates that a new socket + * should be created and connected. + * @param host the host to connect to + * @param port the port to connect to on the host + * @param localAddress the local address to bind the socket to, or + * null for any + * @param localPort the port on the local machine, + * 0 or a negative number for any + * @param params additional {@link HttpParams parameters} for connecting * - * @throws IOException if an I/O error occurs while creating the socket - * @throws UnknownHostException if the IP address of the host cannot be - * determined - * @throws ConnectTimeoutException if socket cannot be connected within the - * given time limit + * @return the connected socket. The returned object may be different + * from the sock argument if this factory supports + * a layered protocol. * - * @since 3.0 + * @throws IOException if an I/O error occurs + * @throws UnknownHostException if the IP address of the target host + * can not be determined + * @throws ConnectTimeoutException if the socket cannot be connected + * within the time limit defined in the params */ Socket createSocket( + Socket sock, String host, int port, InetAddress localAddress, Index: src/java/org/apache/http/conn/ssl/SSLSocketFactory.java =================================================================== --- src/java/org/apache/http/conn/ssl/SSLSocketFactory.java (revision 490517) +++ src/java/org/apache/http/conn/ssl/SSLSocketFactory.java (working copy) @@ -56,6 +56,8 @@ import java.security.UnrecoverableKeyException; /** + * Secure socket factory based on {@link javax.net.ssl JSSE} + *. *

* SSLProtocolSocketFactory can be used to validate the identity of the HTTPS * server against a list of trusted certificates and to authenticate to the HTTPS @@ -230,44 +232,63 @@ return tmfactory.getTrustManagers(); } - /** - * Attempts to get a new socket connection to the given host within the given time limit. - * - * @param host the host name/IP - * @param port the port on the host - * @param localAddress the local host name/IP to bind the socket to - * @param localPort the port on the local machine - * @param params {@link HttpConnectionParams Http connection parameters} - * - * @return Socket a new socket - * - * @throws IOException if an I/O error occurs while creating the socket - * @throws UnknownHostException if the IP address of the host cannot be - * determined - * @throws ConnectTimeoutException if socket cannot be connected within the - * given time limit - * - * @since 3.0 - */ + + // non-javadoc, see interface org.apache.http.conn.SocketFactory + public Socket createSocket() + throws IOException { + + // the cast makes sure that the factory is working as expected + return (SSLSocket) this.socketfactory.createSocket(); + } + + + // non-javadoc, see interface org.apache.http.conn.SocketFactory public Socket createSocket( + final Socket sock, final String host, final int port, final InetAddress localAddress, - final int localPort, + int localPort, final HttpParams params - ) throws IOException, UnknownHostException, ConnectTimeoutException { + ) throws IOException { + + if (host == null) { + throw new IllegalArgumentException("Target host may not be null."); + } if (params == null) { - throw new IllegalArgumentException("Parameters may not be null"); + throw new IllegalArgumentException("Parameters may not be null."); } - SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(); - if (localAddress != null) { - sslSocket.bind(new InetSocketAddress(localAddress, localPort)); + + // resolve the target hostname first + final InetSocketAddress target = new InetSocketAddress(host, port); + + SSLSocket sslock = (SSLSocket) + ((sock != null) ? sock : createSocket()); + + if ((localAddress != null) || (localPort > 0)) { + + // we need to bind explicitly + if (localPort < 0) + localPort = 0; // indicates "any" + + InetSocketAddress isa = + new InetSocketAddress(localAddress, localPort); + sslock.bind(isa); } + int timeout = HttpConnectionParams.getConnectionTimeout(params); - sslSocket.connect(new InetSocketAddress(host, port), timeout); - hostnameVerifier.verify(host, sslSocket); - // verifyHostName() didn't blowup - good! - return sslSocket; + sslock.connect(target, timeout); + + try { + hostnameVerifier.verify(host, sslock); + // verifyHostName() didn't blowup - good! + } catch (IOException iox) { + // close the socket before re-throwing the exception + try { sslock.close(); } catch (Exception x) { /*ignore*/ } + throw iox; + } + + return sslock; } /** Index: src/java/org/apache/http/conn/impl/DefaultHttpHostConnection.java =================================================================== --- src/java/org/apache/http/conn/impl/DefaultHttpHostConnection.java (revision 490517) +++ src/java/org/apache/http/conn/impl/DefaultHttpHostConnection.java (working copy) @@ -157,7 +157,7 @@ } socketFactory = scheme.getSocketFactory(); Socket socket = socketFactory.createSocket( - hostname, port, + null, hostname, port, this.hostconf.getLocalAddress(), 0, params); // Bind connection to the socket Index: src/java/org/apache/http/conn/PlainSocketFactory.java =================================================================== --- src/java/org/apache/http/conn/PlainSocketFactory.java (revision 490517) +++ src/java/org/apache/http/conn/PlainSocketFactory.java (working copy) @@ -33,6 +33,7 @@ import java.io.IOException; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; @@ -40,85 +41,96 @@ import org.apache.http.params.HttpParams; /** - * The default class for creating protocol sockets. This class just uses the - * {@link java.net.Socket socket} constructors. + * The default class for creating sockets. + * This class just uses the {@link java.net.Socket socket} API + * in Java 1.4 or greater. * + * @author Roland Weber * @author Michael Becke - * - * @since 2.0 */ -public class PlainSocketFactory implements SocketFactory { +public final class PlainSocketFactory implements SocketFactory { /** * The factory singleton. */ - private static final PlainSocketFactory DEFAULT_FACTORY = new PlainSocketFactory(); - + private static final + PlainSocketFactory DEFAULT_FACTORY = new PlainSocketFactory(); + /** - * Gets an singleton instance of the DefaultProtocolSocketFactory. - * @return a DefaultProtocolSocketFactory + * Gets the singleton instance of this class. + * @return the one and only plain socket factory */ - public static PlainSocketFactory getSocketFactory() { + public static final PlainSocketFactory getSocketFactory() { return DEFAULT_FACTORY; } - + /** - * Constructor for DefaultProtocolSocketFactory. + * Restricted default constructor. */ private PlainSocketFactory() { super(); } - /** - * Attempts to get a new socket connection to using old (pre Java 1.4) IO mode. - * This socket factory does not support connect timeout as it requires Java 1.4 - * functionality. - * - * @param host the host name/IP - * @param port the port on the host - * @param localAddress the local host name/IP to bind the socket to - * @param localPort the port on the local machine - * @param params {@link HttpConnectionParams Http connection parameters} - * - * @return Socket a new socket - * - * @throws IOException if an I/O error occurs while creating the socket - * @throws UnknownHostException if the IP address of the host cannot be - * @throws IllegalStateException if connection timeout is set - * determined - * - * @since 3.0 - */ - public Socket createSocket( - final String host, - final int port, - final InetAddress localAddress, - final int localPort, - final HttpParams params - ) throws IOException, UnknownHostException { + + // non-javadoc, see interface org.apache.http.conn.SocketFactory + public Socket createSocket() { + return new Socket(); + } + + // non-javadoc, see interface org.apache.http.conn.SocketFactory + public Socket createSocket(Socket sock, String host, int port, + InetAddress localAddress, int localPort, + HttpParams params) + throws IOException { + + if (host == null) { + throw new IllegalArgumentException("Target host may not be null."); + } if (params == null) { - throw new IllegalArgumentException("Parameters may not be null"); + throw new IllegalArgumentException("Parameters may not be null."); } - int timeout = HttpConnectionParams.getConnectionTimeout(params); - if (timeout != 0) { - throw new IllegalStateException("Connection timeout is not supported in old IO mode"); + + // resolve the target hostname first + final InetSocketAddress target = new InetSocketAddress(host, port); + + if (sock == null) + sock = createSocket(); + + if ((localAddress != null) || (localPort > 0)) { + + // we need to bind explicitly + if (localPort < 0) + localPort = 0; // indicates "any" + + InetSocketAddress isa = + new InetSocketAddress(localAddress, localPort); + sock.bind(isa); } - if (localAddress != null) { - return new Socket(host, port, localAddress, localPort); - } else { - return new Socket(host, port); - } - } + int timeout = HttpConnectionParams.getConnectionTimeout(params); + sock.connect(target, timeout); + + return sock; + + } // createSocket(sock,host,...) + + /** - * All instances of DefaultProtocolSocketFactory are the same. + * Compares this factory with an object. + * There is only one instance of this class. + * + * @param obj the object to compare with + * + * @return iff the argument is this object */ public boolean equals(Object obj) { - return ((obj != null) && obj.getClass().equals(PlainSocketFactory.class)); + return (obj == this); } /** - * All instances of DefaultProtocolSocketFactory have the same hash code. + * Obtains a hash code for this object. + * All instances of this class have the same hash code. + * There is only one instance of this class. */ public int hashCode() { return PlainSocketFactory.class.hashCode();