All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.lightbody.bmp.proxy.http.BrowserMobHostNameResolver Maven / Gradle / Ivy

package net.lightbody.bmp.proxy.http;

import org.apache.http.conn.scheme.HostNameResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xbill.DNS.ARecord;
import org.xbill.DNS.Address;
import org.xbill.DNS.Cache;
import org.xbill.DNS.Credibility;
import org.xbill.DNS.ExtendedResolver;
import org.xbill.DNS.Lookup;
import org.xbill.DNS.Name;
import org.xbill.DNS.Record;
import org.xbill.DNS.Resolver;
import org.xbill.DNS.TextParseException;
import org.xbill.DNS.Type;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class BrowserMobHostNameResolver implements HostNameResolver {
    protected final Logger logger = LoggerFactory.getLogger(BrowserMobHostNameResolver.class);
    private final Map remappings = new ConcurrentHashMap();
    private final Map> reverseMapping = new ConcurrentHashMap>();

    private Cache cache;
    private Resolver resolver;

    public BrowserMobHostNameResolver(Cache cache) {
        this.cache = cache;
        resolver = new ExtendedResolver();
        remappings.put("localhost", "127.0.0.1");
    }

    @Override
    public InetAddress resolve(String hostname) throws IOException {
        String remapping = remappings.get(hostname);
        if (remapping != null) {
            hostname = remapping;
        }

        try {
            return Address.getByAddress(hostname);
        } catch (UnknownHostException e) {
            // that's fine, this just means it's not an IP address and we gotta look it up, which is common
        }

        boolean isCached = this.isCached(hostname);

        Lookup lookup = new Lookup(Name.fromString(hostname), Type.A);
        lookup.setCache(cache);
        lookup.setResolver(resolver);

        Date start = new Date();
        Record[] records = lookup.run();
        Date end = new Date();

        if (records == null || records.length == 0) {
            throw new UnknownHostException(hostname);
        }

        // assembly the addr object
        ARecord a = (ARecord) records[0];
        InetAddress addr = InetAddress.getByAddress(hostname, a.getAddress().getAddress());

        if (!isCached) {
            // TODO: Associate the the host name with the connection. We do this because when using persistent
            // connections there won't be a lookup on the 2nd, 3rd, etc requests, and as such we wouldn't be able to
            // know what IP address we were requesting.
            RequestInfo.get().dns(start, end, addr.getHostAddress());
        } else {
            // if it is a cached hit, we just record zero since we don't want
            // to skew the data with method call timings (specially under load)
            RequestInfo.get().dns(end, end, addr.getHostAddress());
        }

        return addr;
    }

    public void remap(String source, String target) {
        remappings.put(source, target);
        List list = reverseMapping.get(target);
        if (list == null) {
            list = new ArrayList<>();
        }
        list.add(source);
        reverseMapping.put(target, list);
    }

    public String remapping(String host) {
        return remappings.get(host);
    }

    public List original(String host) {
        return reverseMapping.get(host);
    }

    public void clearCache() {
        this.cache.clearCache();
    }

    public void setCacheTimeout(int timeout) {
        cache.setMaxCache(timeout);
    }

    public boolean isCached(String hostname) throws TextParseException {
        return cache.lookupRecords(Name.fromString(hostname), Type.ANY, 3).isSuccessful();
    }

    public void addHostToCacheAs(String hostname, String ipAddress) throws UnknownHostException, TextParseException {
        //add an ending period assuming the hostname is truly an absolute hostname
        Name host = new Name(hostname + ".");
        //putting in a good long TTL, and using an A record, but AAAA might be desired as well for IPv6
        Record aRec = new ARecord(host, Type.A, 9999999, getInetAddressFromString(ipAddress));
        Lookup.getDefaultCache(Type.A).addRecord(aRec, Credibility.NORMAL);
    }

    private InetAddress getInetAddressFromString(String ip) throws UnknownHostException {
        //Assume we are using IPv4
        byte[] bytes = new byte[4];
        String[] ipParts = ip.split("\\.");
        InetAddress addr = null;
        //if we only have one part, it must actually be a hostname, rather than a real IP
        if (ipParts.length <= 1) {
            addr = InetAddress.getByName(ip);
        } else {
            for (int i = 0; i < ipParts.length; i++) {
                bytes[i] = Byte.parseByte(ipParts[i]);
            }
            addr = InetAddress.getByAddress(bytes);
        }
        return addr;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy