Index: contrib/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/contrib/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java,v retrieving revision 1.4 diff -u -r1.4 EasySSLProtocolSocketFactory.java --- contrib/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java 22 Feb 2004 18:08:45 -0000 1.4 +++ contrib/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java 12 Apr 2004 21:40:18 -0000 @@ -36,6 +36,11 @@ import com.sun.net.ssl.SSLContext; import com.sun.net.ssl.TrustManager; +import org.apache.commons.httpclient.ConnectTimeoutException; +import org.apache.commons.httpclient.HttpClientError; +import org.apache.commons.httpclient.params.HttpConnectionParams; +import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory; +import org.apache.commons.httpclient.protocol.ReflectionSocketFactory; import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -64,6 +69,7 @@ /** Log object for this class. */ private static final Log LOG = LogFactory.getLog(EasySSLProtocolSocketFactory.class); + private static SSLContext SSL_CONTEXT_SINGLETON = null; /** * Constructor for EasySSLProtocolSocketFactory. * @@ -81,21 +87,26 @@ super(); } - private static SSLSocketFactory getEasySSLSocketFactory() { - SSLContext context = null; + private static SSLContext createEasySSLContext() { try { - context = SSLContext.getInstance("SSL"); + SSLContext context = SSLContext.getInstance("SSL"); context.init( null, new TrustManager[] {new EasyX509TrustManager(null)}, null); + return context; } catch (Exception e) { LOG.error(e.getMessage(), e); - throw new RuntimeException(e.toString()); + throw new HttpClientError(e.toString()); } - return context.getSocketFactory(); } + private static SSLSocketFactory getEasySSLSocketFactory() { + if (SSL_CONTEXT_SINGLETON == null) { + SSL_CONTEXT_SINGLETON = createEasySSLContext(); + } + return SSL_CONTEXT_SINGLETON.getSocketFactory(); + } /** * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int) @@ -114,6 +125,54 @@ clientPort ); return socket; + } + + /** + * Attempts to get a new socket connection to the given host within the given time limit. + *
+ * This method employs several techniques to circumvent the limitations of older JREs that + * do not support connect timeout. When running in JRE 1.4 or above reflection is used to + * call Socket#connect(SocketAddress endpoint, int timeout) method. When executing in older + * JREs a controller thread is executed. The controller thread attempts to create a new socket + * within the given limit of time. If socket constructor does not return until the timeout + * expires, the controller terminates and throws an {@link ConnectTimeoutException} + *
+ * + * @param host the host name/IP + * @param port the port on the host + * @param clientHost the local host name/IP to bind the socket to + * @param clientPort 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 + */ + public Socket createSocket( + final String host, + final int port, + final InetAddress localAddress, + final int localPort, + final HttpConnectionParams params + ) throws IOException, UnknownHostException, ConnectTimeoutException { + if (params == null) { + throw new IllegalArgumentException("Parameters may not be null"); + } + int timeout = params.getConnectionTimeout(); + if (timeout == 0) { + return createSocket(host, port, localAddress, localPort); + } else { + // To be eventually deprecated when migrated to Java 1.4 or above + Socket socket = ReflectionSocketFactory.createSocket( + "javax.net.ssl.SSLSocketFactory", host, port, localAddress, localPort, timeout); + if (socket == null) { + socket = ControllerThreadSocketFactory.createSocket( + this, host, port, localAddress, localPort, timeout); + } + return socket; + } } /** Index: contrib/org/apache/commons/httpclient/contrib/ssl/StrictSSLProtocolSocketFactory.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/contrib/org/apache/commons/httpclient/contrib/ssl/StrictSSLProtocolSocketFactory.java,v retrieving revision 1.3 diff -u -r1.3 StrictSSLProtocolSocketFactory.java --- contrib/org/apache/commons/httpclient/contrib/ssl/StrictSSLProtocolSocketFactory.java 22 Feb 2004 18:08:45 -0000 1.3 +++ contrib/org/apache/commons/httpclient/contrib/ssl/StrictSSLProtocolSocketFactory.java 12 Apr 2004 21:40:19 -0000 @@ -1,5 +1,5 @@ /* - * $Header: /home/cvspublic/jakarta-commons/httpclient/src/contrib/org/apache/commons/httpclient/contrib/ssl/StrictSSLProtocolSocketFactory.java,v 1.3 2004/02/22 18:08:45 olegk Exp $ + * $Header: /home/cvs/jakarta-commons/httpclient/src/contrib/org/apache/commons/httpclient/contrib/ssl/StrictSSLProtocolSocketFactory.java,v 1.3 2004/02/22 18:08:45 olegk Exp $ * $Revision: 1.3 $ * $Date: 2004/02/22 18:08:45 $ * @@ -54,6 +54,10 @@ import javax.net.ssl.SSLSocketFactory; import javax.security.cert.X509Certificate; +import org.apache.commons.httpclient.ConnectTimeoutException; +import org.apache.commons.httpclient.params.HttpConnectionParams; +import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory; +import org.apache.commons.httpclient.protocol.ReflectionSocketFactory; import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -159,6 +163,55 @@ verifyHostname(sslSocket); return sslSocket; + } + + /** + * Attempts to get a new socket connection to the given host within the given time limit. + *+ * This method employs several techniques to circumvent the limitations of older JREs that + * do not support connect timeout. When running in JRE 1.4 or above reflection is used to + * call Socket#connect(SocketAddress endpoint, int timeout) method. When executing in older + * JREs a controller thread is executed. The controller thread attempts to create a new socket + * within the given limit of time. If socket constructor does not return until the timeout + * expires, the controller terminates and throws an {@link ConnectTimeoutException} + *
+ * + * @param host the host name/IP + * @param port the port on the host + * @param clientHost the local host name/IP to bind the socket to + * @param clientPort 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 + */ + public Socket createSocket( + final String host, + final int port, + final InetAddress localAddress, + final int localPort, + final HttpConnectionParams params + ) throws IOException, UnknownHostException, ConnectTimeoutException { + if (params == null) { + throw new IllegalArgumentException("Parameters may not be null"); + } + int timeout = params.getConnectionTimeout(); + if (timeout == 0) { + return createSocket(host, port, localAddress, localPort); + } else { + // To be eventually deprecated when migrated to Java 1.4 or above + SSLSocket sslSocket = (SSLSocket) ReflectionSocketFactory.createSocket( + "javax.net.ssl.SSLSocketFactory", host, port, localAddress, localPort, timeout); + if (sslSocket == null) { + sslSocket = (SSLSocket) ControllerThreadSocketFactory.createSocket( + this, host, port, localAddress, localPort, timeout); + } + verifyHostname(sslSocket); + return sslSocket; + } } /** Index: java/org/apache/commons/httpclient/HttpConnection.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnection.java,v retrieving revision 1.85 diff -u -r1.85 HttpConnection.java --- java/org/apache/commons/httpclient/HttpConnection.java 22 Feb 2004 18:08:45 -0000 1.85 +++ java/org/apache/commons/httpclient/HttpConnection.java 12 Apr 2004 21:40:23 -0000 @@ -48,7 +48,6 @@ import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; import org.apache.commons.httpclient.util.EncodingUtil; -import org.apache.commons.httpclient.util.TimeoutController; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -632,41 +631,18 @@ final int port = (proxyHostName == null) ? portNumber : proxyPortNumber; assertNotOpen(); try { - if (null == socket) { - - + if (this.socket == null) { usingSecureSocket = isSecure() && !isProxied(); - // use the protocol's socket factory unless this is a secure // proxied connection final ProtocolSocketFactory socketFactory = (isSecure() && isProxied() ? new DefaultProtocolSocketFactory() : protocolInUse.getSocketFactory()); - - if (this.params.getConnectionTimeout() == 0) { - if (localAddress != null) { - socket = socketFactory.createSocket(host, port, localAddress, 0); - } else { - socket = socketFactory.createSocket(host, port); - } - } else { - SocketTask task = new SocketTask() { - public void doit() throws IOException { - if (localAddress != null) { - setSocket(socketFactory.createSocket(host, port, localAddress, 0)); - } else { - setSocket(socketFactory.createSocket(host, port)); - } - } - }; - TimeoutController.execute(task, this.params.getConnectionTimeout()); - socket = task.getSocket(); - if (task.exception != null) { - throw task.exception; - } - } - + this.socket = socketFactory.createSocket( + host, port, + localAddress, 0, + this.params); } /* @@ -703,16 +679,6 @@ // so close everything out closeSocketAndStreams(); throw e; - } catch (TimeoutController.TimeoutException e) { - StringBuffer buffer = new StringBuffer(); - buffer.append("The host "); - buffer.append(host); - buffer.append(":"); - buffer.append(port); - buffer.append(" did not accept the connection within timeout of "); - buffer.append(this.params.getConnectionTimeout()); - buffer.append(" milliseconds"); - throw new ConnectTimeoutException(buffer.toString()); } } @@ -1134,7 +1100,6 @@ void setLocked(boolean locked) { this.locked = locked; } - // ------------------------------------------------------ Protected Methods /** @@ -1238,47 +1203,6 @@ */ public void setSendBufferSize(int sendBufferSize) throws SocketException { this.params.setSendBufferSize(sendBufferSize); - } - - /** - * Helper class for wrapping socket based tasks. - */ - private abstract class SocketTask implements Runnable { - - /** The socket */ - private Socket socket; - /** The exception */ - private IOException exception; - - /** - * Set the socket. - * @param newSocket The new socket. - */ - protected void setSocket(final Socket newSocket) { - socket = newSocket; - } - - /** - * Return the socket. - * @return Socket The socket. - */ - protected Socket getSocket() { - return socket; - } - /** - * Perform the logic. - * @throws IOException If an IO problem occurs - */ - public abstract void doit() throws IOException; - - /** Execute the logic in this object and keep track of any exceptions. */ - public void run() { - try { - doit(); - } catch (IOException e) { - exception = e; - } - } } /** Index: java/org/apache/commons/httpclient/protocol/ControllerThreadSocketFactory.java =================================================================== RCS file: java/org/apache/commons/httpclient/protocol/ControllerThreadSocketFactory.java diff -N java/org/apache/commons/httpclient/protocol/ControllerThreadSocketFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ java/org/apache/commons/httpclient/protocol/ControllerThreadSocketFactory.java 12 Apr 2004 21:40:24 -0000 @@ -0,0 +1,163 @@ +/* + * $Header$ + * $Revision$ + * $Date$ + * + * ==================================================================== + * + * Copyright 2002-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + *+ * This method employs several techniques to circumvent the limitations of older JREs that + * do not support connect timeout. When running in JRE 1.4 or above reflection is used to + * call Socket#connect(SocketAddress endpoint, int timeout) method. When executing in older + * JREs a controller thread is executed. The controller thread attempts to create a new socket + * within the given limit of time. If socket constructor does not return until the timeout + * expires, the controller terminates and throws an {@link ConnectTimeoutException} + *
+ * + * @param host the host name/IP + * @param port the port on the host + * @param clientHost the local host name/IP to bind the socket to + * @param clientPort 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 + */ + public Socket createSocket( + final String host, + final int port, + final InetAddress localAddress, + final int localPort, + final HttpConnectionParams params + ) throws IOException, UnknownHostException, ConnectTimeoutException { + if (params == null) { + throw new IllegalArgumentException("Parameters may not be null"); + } + int timeout = params.getConnectionTimeout(); + if (timeout == 0) { + return createSocket(host, port, localAddress, localPort); + } else { + // To be eventually deprecated when migrated to Java 1.4 or above + Socket socket = ReflectionSocketFactory.createSocket( + "javax.net.SocketFactory", host, port, localAddress, localPort, timeout); + if (socket == null) { + socket = ControllerThreadSocketFactory.createSocket( + this, host, port, localAddress, localPort, timeout); + } + return socket; + } } /** Index: java/org/apache/commons/httpclient/protocol/ProtocolSocketFactory.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/ProtocolSocketFactory.java,v retrieving revision 1.7 diff -u -r1.7 ProtocolSocketFactory.java --- java/org/apache/commons/httpclient/protocol/ProtocolSocketFactory.java 22 Feb 2004 18:08:49 -0000 1.7 +++ java/org/apache/commons/httpclient/protocol/ProtocolSocketFactory.java 12 Apr 2004 21:40:25 -0000 @@ -1,5 +1,5 @@ /* - * $Header: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/ProtocolSocketFactory.java,v 1.7 2004/02/22 18:08:49 olegk Exp $ + * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/protocol/ProtocolSocketFactory.java,v 1.7 2004/02/22 18:08:49 olegk Exp $ * $Revision: 1.7 $ * $Date: 2004/02/22 18:08:49 $ * @@ -36,6 +36,9 @@ import java.net.Socket; import java.net.UnknownHostException; +import org.apache.commons.httpclient.ConnectTimeoutException; +import org.apache.commons.httpclient.params.HttpConnectionParams; + /** * A factory for creating Sockets. * @@ -74,6 +77,31 @@ InetAddress clientHost, int clientPort ) throws IOException, UnknownHostException; + + /** + * Gets a new socket connection to the given host. + * + * @param host the host name/IP + * @param port the port on the host + * @param clientHost the local host name/IP to bind the socket to + * @param clientPort the port on the local machine + * @param timeout the timeout value to be used in milliseconds + * + * @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 + */ + Socket createSocket( + String host, + int port, + InetAddress clientHost, + int clientPort, + HttpConnectionParams params + ) throws IOException, UnknownHostException, ConnectTimeoutException; /** * Gets a new socket connection to the given host. Index: java/org/apache/commons/httpclient/protocol/ReflectionSocketFactory.java =================================================================== RCS file: java/org/apache/commons/httpclient/protocol/ReflectionSocketFactory.java diff -N java/org/apache/commons/httpclient/protocol/ReflectionSocketFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ java/org/apache/commons/httpclient/protocol/ReflectionSocketFactory.java 12 Apr 2004 21:40:25 -0000 @@ -0,0 +1,152 @@ +/* + * $Header$ + * $Revision$ + * $Date$ + * + * ==================================================================== + * + * Copyright 2002-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + *+ * This method employs several techniques to circumvent the limitations of older JREs that + * do not support connect timeout. When running in JRE 1.4 or above reflection is used to + * call Socket#connect(SocketAddress endpoint, int timeout) method. When executing in older + * JREs a controller thread is executed. The controller thread attempts to create a new socket + * within the given limit of time. If socket constructor does not return until the timeout + * expires, the controller terminates and throws an {@link ConnectTimeoutException} + *
+ * + * @param host the host name/IP + * @param port the port on the host + * @param clientHost the local host name/IP to bind the socket to + * @param clientPort 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 + */ + public Socket createSocket( + final String host, + final int port, + final InetAddress localAddress, + final int localPort, + final HttpConnectionParams params + ) throws IOException, UnknownHostException, ConnectTimeoutException { + if (params == null) { + throw new IllegalArgumentException("Parameters may not be null"); + } + int timeout = params.getConnectionTimeout(); + if (timeout == 0) { + return createSocket(host, port, localAddress, localPort); + } else { + // To be eventually deprecated when migrated to Java 1.4 or above + Socket socket = ReflectionSocketFactory.createSocket( + "javax.net.ssl.SSLSocketFactory", host, port, localAddress, localPort, timeout); + if (socket == null) { + socket = ControllerThreadSocketFactory.createSocket( + this, host, port, localAddress, localPort, timeout); + } + return socket; + } } /** Index: test/org/apache/commons/httpclient/TestHttpConnection.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpConnection.java,v retrieving revision 1.15 diff -u -r1.15 TestHttpConnection.java --- test/org/apache/commons/httpclient/TestHttpConnection.java 22 Feb 2004 18:08:49 -0000 1.15 +++ test/org/apache/commons/httpclient/TestHttpConnection.java 12 Apr 2004 21:40:27 -0000 @@ -41,8 +41,10 @@ import junit.framework.TestSuite; import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.params.HttpConnectionParams; import org.apache.commons.httpclient.protocol.Protocol; import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; +import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory; /** * @@ -189,8 +191,8 @@ public Socket createSocket( String host, int port, - InetAddress clientHost, - int clientPort + InetAddress localAddress, + int localPort ) throws IOException, UnknownHostException { synchronized (this) { @@ -198,7 +200,32 @@ this.wait(delay); } catch (InterruptedException e) {} } - return realFactory.createSocket(host, port, clientHost, clientPort); + return realFactory.createSocket(host, port, localAddress, localPort); + } + + public Socket createSocket( + final String host, + final int port, + final InetAddress localAddress, + final int localPort, + final HttpConnectionParams params + ) throws IOException, UnknownHostException { + + if (params == null) { + throw new IllegalArgumentException("Parameters may not be null"); + } + int timeout = params.getConnectionTimeout(); + ControllerThreadSocketFactory.SocketTask task = new ControllerThreadSocketFactory.SocketTask() { + public void doit() throws IOException { + synchronized (this) { + try { + this.wait(delay); + } catch (InterruptedException e) {} + } + setSocket(realFactory.createSocket(host, port, localAddress, localPort)); + } + }; + return ControllerThreadSocketFactory.createSocket(task, timeout); } public Socket createSocket(String host, int port) Index: test/org/apache/commons/httpclient/TestHttpConnectionManager.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpConnectionManager.java,v retrieving revision 1.20 diff -u -r1.20 TestHttpConnectionManager.java --- test/org/apache/commons/httpclient/TestHttpConnectionManager.java 8 Apr 2004 22:25:11 -0000 1.20 +++ test/org/apache/commons/httpclient/TestHttpConnectionManager.java 12 Apr 2004 21:40:29 -0000 @@ -1,5 +1,5 @@ /* - * $Header: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpConnectionManager.java,v 1.20 2004/04/08 22:25:11 olegk Exp $ + * $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpConnectionManager.java,v 1.20 2004/04/08 22:25:11 olegk Exp $ * $Revision: 1.20 $ * $Date: 2004/04/08 22:25:11 $ * ==================================================================== @@ -41,6 +41,7 @@ import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.params.HttpConnectionManagerParams; +import org.apache.commons.httpclient.params.HttpConnectionParams; import org.apache.commons.httpclient.protocol.Protocol; import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; @@ -683,6 +684,11 @@ throw new IllegalStateException("createSocket() should never have been called."); } + public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort, + HttpConnectionParams params) + throws IOException, UnknownHostException { + throw new IllegalStateException("createSocket() should never have been called."); + } } static class GetConnectionThread extends Thread {