Index: examples/org/apache/http/examples/client/DnsOverrideClient.java =================================================================== --- examples/org/apache/http/examples/client/DnsOverrideClient.java (revision 0) +++ examples/org/apache/http/examples/client/DnsOverrideClient.java (revision 0) @@ -0,0 +1,36 @@ +package org.apache.http.examples.client; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.InMemoryDnsOverriderImpl; +import org.apache.http.impl.conn.PoolingClientDnsOverrideConnManager; +import org.apache.http.impl.conn.SchemeRegistryFactory; +import org.apache.http.util.EntityUtils; + +public class DnsOverrideClient { + + public static void main(String[] args) throws Exception { + InMemoryDnsOverriderImpl dnsOverrider = new InMemoryDnsOverriderImpl(); + dnsOverrider.add("www.google.ro", "74.125.39.105"); + dnsOverrider.add("somehost.example.org", "74.125.39.105"); + + DefaultHttpClient httpclient = new DefaultHttpClient( + new PoolingClientDnsOverrideConnManager( + SchemeRegistryFactory.createDefault(), dnsOverrider)); + + HttpGet httpget = new HttpGet("http://somehost.example.org/"); + HttpResponse response = httpclient.execute(httpget); + HttpEntity entity = response.getEntity(); + + System.out.println("----------------------------------------"); + System.out.println(response.getStatusLine()); + if (entity != null) { + System.out.println("Response content length: " + + entity.getContentLength()); + } + System.out.println(EntityUtils.toString(entity)); + } + +} Index: examples/org/apache/http/examples/conn/DnsOverriderConnectDirect.java =================================================================== --- examples/org/apache/http/examples/conn/DnsOverriderConnectDirect.java (revision 0) +++ examples/org/apache/http/examples/conn/DnsOverriderConnectDirect.java (revision 0) @@ -0,0 +1,90 @@ +package org.apache.http.examples.conn; + +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.HttpVersion; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.conn.ClientConnectionOperator; +import org.apache.http.conn.OperatedClientConnection; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.impl.conn.DnsOverriderClientConnectionOperator; +import org.apache.http.impl.conn.InMemoryDnsOverriderImpl; +import org.apache.http.message.BasicHttpRequest; +import org.apache.http.params.HttpParams; +import org.apache.http.params.HttpProtocolParams; +import org.apache.http.params.SyncBasicHttpParams; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HttpContext; + +/** + * How to open a direct connection using {@link ClientConnectionOperator + * ClientConnectionOperator} configured with an {@link InMemoryDnsOverriderImpl} + * DNS resolver. + * + */ +public class DnsOverriderConnectDirect { + + public static void main(String[] args) throws Exception { + // this host will be resolved to a Google public IP + // using an InMemory DNS Resolver + HttpHost target = new HttpHost("somehost.example.org", 80, "http"); + + // some general setup + // Register the "http" protocol scheme, it is required + // by the default operator to look up socket factories. + SchemeRegistry supportedSchemes = new SchemeRegistry(); + supportedSchemes.register(new Scheme("http", 80, PlainSocketFactory + .getSocketFactory())); + + // Prepare parameters. + // Since this example doesn't use the full core framework, + // only few parameters are actually required. + HttpParams params = new SyncBasicHttpParams(); + HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); + HttpProtocolParams.setUseExpectContinue(params, false); + + // prepare an in-memory DNS overrider + InMemoryDnsOverriderImpl dnsOverrider = new InMemoryDnsOverriderImpl(); + dnsOverrider.add("www.google.ro", "74.125.39.105"); + dnsOverrider.add("somehost.example.org", "74.125.39.105"); + + + // one operator can be used for many connections + ClientConnectionOperator scop = new DnsOverriderClientConnectionOperator( + supportedSchemes, dnsOverrider); + + HttpRequest req = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1); + req.addHeader("Host", target.getHostName()); + + HttpContext ctx = new BasicHttpContext(); + + OperatedClientConnection conn = scop.createConnection(); + try { + System.out.println("opening connection to " + target); + scop.openConnection(conn, target, null, ctx, params); + System.out.println("sending request"); + conn.sendRequestHeader(req); + // there is no request entity + conn.flush(); + + System.out.println("receiving response header"); + HttpResponse rsp = conn.receiveResponseHeader(); + + System.out.println("----------------------------------------"); + System.out.println(rsp.getStatusLine()); + Header[] headers = rsp.getAllHeaders(); + for (int i = 0; i < headers.length; i++) { + System.out.println(headers[i]); + } + System.out.println("----------------------------------------"); + } finally { + System.out.println("closing connection"); + conn.close(); + } + } + +} Index: main/java/org/apache/http/impl/conn/DnsOverrider.java =================================================================== --- main/java/org/apache/http/impl/conn/DnsOverrider.java (revision 0) +++ main/java/org/apache/http/impl/conn/DnsOverrider.java (revision 0) @@ -0,0 +1,26 @@ +package org.apache.http.impl.conn; + +import java.net.InetAddress; + +/** + * Users may implement this interface to override the normal DNS lookup offered + * by the OS. + * + */ +public interface DnsOverrider { + + /** + * Returns the IP address for the specified host name, or null if the given + * host is not recognized or the associated IP address cannot be used to + * build an InetAddress instance. + * + * @see InetAddress + * + * @param host + * The hostname to be resolved by the overrider. + * @return The IP address associated to the given hostname, or null if the + * hostname is not configured in the overrider implementation. + */ + InetAddress[] resolve(String host); + +} Index: main/java/org/apache/http/impl/conn/DnsOverriderClientConnectionOperator.java =================================================================== --- main/java/org/apache/http/impl/conn/DnsOverriderClientConnectionOperator.java (revision 0) +++ main/java/org/apache/http/impl/conn/DnsOverriderClientConnectionOperator.java (revision 0) @@ -0,0 +1,62 @@ +package org.apache.http.impl.conn; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.apache.http.conn.scheme.SchemeRegistry; + +/** + * Class extending the DefaultClientConnectionOperator that provides a way to + * use custom ways of DNS lookups. + * + * @see DefaultClientConnectionOperator + */ +public class DnsOverriderClientConnectionOperator extends + DefaultClientConnectionOperator { + + /** the custom-configured DNS lookup mechanism. */ + private DnsOverrider dnsOverrider; + + /** + * Creates a new client connection operator for the given scheme registry + * that will use the given DNS own lookup. + * + * @param schemes + * the scheme registry + * @param dnsOverrider + * the own DNS lookup mechanism + */ + public DnsOverriderClientConnectionOperator(final SchemeRegistry schemes, + DnsOverrider dnsOverrider) { + super(schemes); + if (dnsOverrider == null) { + throw new IllegalArgumentException("DNS Overrider may not be null."); + } + this.dnsOverrider = dnsOverrider; + } + + /** + * Tries to resolve the given host name against the configured DNS + * overrider. If the host name is not configured, the default DNS lookup + * (usually configured at the OS level) is used. + * + * @param host + * host name to resolve + * @return array of IP addresses + * @throws UnknownHostException + * UnknownHostException if no IP address for the host could be + * determined. + * + */ + protected InetAddress[] resolveHostname(final String host) + throws UnknownHostException { + InetAddress[] overridenAddress = dnsOverrider.resolve(host); + + if (overridenAddress == null) { + return super.resolveHostname(host); + } + + return overridenAddress; + } + +} Index: main/java/org/apache/http/impl/conn/InMemoryDnsOverriderImpl.java =================================================================== --- main/java/org/apache/http/impl/conn/InMemoryDnsOverriderImpl.java (revision 0) +++ main/java/org/apache/http/impl/conn/InMemoryDnsOverriderImpl.java (revision 0) @@ -0,0 +1,90 @@ +package org.apache.http.impl.conn; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.http.conn.util.InetAddressUtils; + +/** + * In-memory DNS overrider implementation that will be built programatically + * using the {@link InMemoryDnsOverriderImpl#add(String, String) method}. + * + * Currently this class suports only IPv4 addresses. + * + */ +public class InMemoryDnsOverriderImpl implements DnsOverrider { + + /** Logger associated to this class. */ + private static final Log log = LogFactory + .getLog(InMemoryDnsOverriderImpl.class); + + /** + * In-memory collection that will hold the associations between a host name + * and an array of InetAddress instances. + */ + private Map dnsMap; + + /** + * Builds an DNS overrider that will resolve the host names against a + * collection held in-memory. + */ + public InMemoryDnsOverriderImpl() { + dnsMap = new HashMap(); + } + + /** + * Associates the given IP address to the given host in this DNS overrider. + * + * @param host + * The host name to be associated with the given IP. + * @param ip + * IPv4 address to be resolved by this DNS overrider to the given + * host name. + * + * @throws IllegalArgumentException + * if the given IP is not a valid IPv4 address or an InetAddress + * instance cannot be built based on the given IPv4 address. + * + * @see InetAddress#getByAddress + */ + public void add(final String host, final String ip) { + if (!InetAddressUtils.isIPv4Address(ip)) { + throw new IllegalArgumentException(ip + + " must be a valid IPv4 address"); + } + + String[] ipParts = ip.split("\\."); + + byte[] byteIpAddress = new byte[4]; + for (int i = 0; i < 4; i++) { + byteIpAddress[i] = Byte.parseByte(ipParts[i]); + } + + try { + dnsMap.put( + host, + new InetAddress[] { InetAddress.getByAddress(byteIpAddress) }); + } catch (UnknownHostException e) { + log.error("Unable to build InetAddress for " + ip, e); + throw new IllegalArgumentException(e); + } + + } + + /** + * {@inheritDoc} + */ + public InetAddress[] resolve(String host) { + InetAddress[] resolvedAddresses = dnsMap.get(host); + if(log.isInfoEnabled()){ + log.info("Resolving " + host + " to " + Arrays.deepToString(resolvedAddresses)); + } + return resolvedAddresses; + } + +} Index: main/java/org/apache/http/impl/conn/PoolingClientConnectionManager.java =================================================================== --- main/java/org/apache/http/impl/conn/PoolingClientConnectionManager.java (revision 1164682) +++ main/java/org/apache/http/impl/conn/PoolingClientConnectionManager.java (working copy) @@ -96,6 +96,18 @@ this.operator = createConnectionOperator(schemeRegistry); this.pool = new HttpConnPool(this.log, 2, 20, timeToLive, tunit); } + + public PoolingClientConnectionManager( + final SchemeRegistry schemeRegistry, + final long timeToLive, final TimeUnit tunit, final ClientConnectionOperator operator) { + super(); + if (schemeRegistry == null) { + throw new IllegalArgumentException("Scheme registry may not be null"); + } + this.schemeRegistry = schemeRegistry; + this.operator = operator; + this.pool = new HttpConnPool(this.log, 2, 20, timeToLive, tunit); + } @Override protected void finalize() throws Throwable { Index: main/java/org/apache/http/impl/conn/PoolingClientDnsOverrideConnManager.java =================================================================== --- main/java/org/apache/http/impl/conn/PoolingClientDnsOverrideConnManager.java (revision 0) +++ main/java/org/apache/http/impl/conn/PoolingClientDnsOverrideConnManager.java (revision 0) @@ -0,0 +1,13 @@ +package org.apache.http.impl.conn; + +import java.util.concurrent.TimeUnit; + +import org.apache.http.conn.scheme.SchemeRegistry; + +public class PoolingClientDnsOverrideConnManager extends PoolingClientConnectionManager{ + + public PoolingClientDnsOverrideConnManager(final SchemeRegistry schRegistry,final DnsOverrider dnsOverrider){ + super(schRegistry, -1, TimeUnit.MILLISECONDS, new DnsOverriderClientConnectionOperator(schRegistry,dnsOverrider)); + } + +}