Index: C:/depot/Tools/commons-httpclient-trunk/src/java/org/apache/commons/httpclient/HostConfiguration.java =================================================================== --- C:/depot/Tools/commons-httpclient-trunk/src/java/org/apache/commons/httpclient/HostConfiguration.java (revision 508748) +++ C:/depot/Tools/commons-httpclient-trunk/src/java/org/apache/commons/httpclient/HostConfiguration.java (working copy) @@ -238,8 +238,22 @@ * @param port The port * @param protocol The protocol. */ - public synchronized void setHost(final String host, int port, final String protocol) { - this.host = new HttpHost(host, port, Protocol.getProtocol(protocol)); + public synchronized void setHost(final String host, int port, final String scheme) { + Protocol newProtocol = null; + if (this.host != null) { + final Protocol oldProtocol = this.host.getProtocol(); + if (oldProtocol != null) { + final String oldScheme = oldProtocol.getScheme(); + if (oldScheme == scheme || (oldScheme != null && oldScheme.equalsIgnoreCase(scheme))) { + // The old protocol has the desired scheme. + newProtocol = oldProtocol; // Retain the protocol. + } + } + } + if (newProtocol == null) { + newProtocol = Protocol.getProtocol(scheme); + } + this.host = new HttpHost(host, port, newProtocol); } /** Index: C:/depot/Tools/commons-httpclient-trunk/src/test/org/apache/commons/httpclient/TestHostConfiguration.java =================================================================== --- C:/depot/Tools/commons-httpclient-trunk/src/test/org/apache/commons/httpclient/TestHostConfiguration.java (revision 508748) +++ C:/depot/Tools/commons-httpclient-trunk/src/test/org/apache/commons/httpclient/TestHostConfiguration.java (working copy) @@ -29,13 +29,17 @@ package org.apache.commons.httpclient; import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; import java.net.UnknownHostException; import junit.framework.Test; 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.server.SimpleProxy; /** @@ -160,4 +164,70 @@ } } + /** + * Test that a specialized socket factory, supplied in a HostConfiguration, + * is used to execute a method with an absolute URI with the same scheme as + * the Protocol. + *

+ * This feature supports specialized SSL authentication strategies, without + * using Protocol.registerProtocol. Registration is bad because it's global + * (Protocol.PROTOCOLS is static), which makes it hard to integrate modules + * (e.g. web applications in a servlet container) with different strategies. + */ + public void testAbsoluteURLUsesSocketFactory() throws IOException { + /** + * The intended use involves a 'good' factory in the HostConfiguration + * and a 'bad' factory registered with Protocol. But this test does the + * reverse, to avoid interfering with other test cases (by registering a + * bad factory). That is, the HostConfiguration contains a BadFactory, + * and this test expects a 'bad' outcome. + */ + this.server.setHttpService(new EchoService()); + Protocol protocol = new Protocol("http", new BadFactory(), 80); + HttpHost host = new HttpHost(this.server.getLocalAddress(), this.server.getLocalPort(), protocol); + this.client.getHostConfiguration().setHost(host); + final GetMethod method = new GetMethod(host.toURI() + "/test/"); + try { + this.client.executeMethod(method); + fail("HostConfiguration.host.protocol.socketFactory was ignored"); + } catch (IOException actual) { + assertEquals("IOException message", BadFactory.MESSAGE, actual.getMessage()); + } finally { + method.releaseConnection(); + } + // Next, try a different scheme. BadFactory should not be used. + protocol = new Protocol("https", new BadFactory(), 443); + host = new HttpHost(host.getHostName(), host.getPort(), protocol); + this.client.getHostConfiguration().setHost(host); + try { + this.client.executeMethod(method); + assertEquals("HTTP status", HttpStatus.SC_OK, method.getStatusCode()); + } finally { + method.releaseConnection(); + } + } + + /** A silly factory that merely throws exceptions. */ + public static class BadFactory implements ProtocolSocketFactory { + + public static final String MESSAGE = "bad factory; no biscuit"; + + public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, + HttpConnectionParams params) throws IOException, UnknownHostException, + ConnectTimeoutException + { + throw new IOException(MESSAGE); + } + + public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) + throws IOException, UnknownHostException + { + throw new IOException(MESSAGE); + } + + public Socket createSocket(String host, int port) throws IOException, UnknownHostException + { + throw new IOException(MESSAGE); + } + } }