core/src/main/java/com/digitalpebble/stormcrawler/protocol/HttpRobotRulesParser.java
@Override
    public BaseRobotRules getRobotRulesSet(Protocol http, URL url) {

        String cacheKey = getCacheKey(url);

        // check in the error cache first
        BaseRobotRules robotRules = ERRORCACHE.getIfPresent(cacheKey);
        if (robotRules != null) {
            return robotRules;
        }

        // now try the proper cache
        robotRules = CACHE.getIfPresent(cacheKey);
        if (robotRules != null) {
            return robotRules;
        }

        boolean cacheRule = true;
        URL redir = null;

        String keyredir = null;

        LOG.debug("Cache miss {} for {}", cacheKey, url);
        List<Integer> bytesFetched = new LinkedList<>();
        try {
            ProtocolResponse response = http.getProtocolOutput(new URL(url,
                    "/robots.txt").toString(), Metadata.empty);
            int code = response.getStatusCode();
            bytesFetched.add(response.getContent() != null ? response
                    .getContent().length : 0);
            // try one level of redirection ?
            if (code == 301 || code == 302 || code == 307 || code == 308) {
                String redirection = response.getMetadata().getFirstValue(
                        HttpHeaders.LOCATION);
                if (StringUtils.isNotBlank(redirection)) {
                    if (!redirection.startsWith("http")) {
                        // RFC says it should be absolute, but apparently it
                        // isn't
                        redir = new URL(url, redirection);
                    } else {
                        redir = new URL(redirection);
                    }
                    // try from the cache
                    keyredir = getCacheKey(redir);
                    if (cacheKey.equalsIgnoreCase(keyredir)) {
                        keyredir = null;
                    } else {
                        RobotRules cachedRediRobotRules = CACHE
                                .getIfPresent(keyredir);
                        if (cachedRediRobotRules != null) {
                            // cache also for the redirected host
                            // but only if the robots.txt file is at the root
                            if (redir.getPath().equals("/robots.txt")) {
                                LOG.debug(
                                        "Caching robots for {} under key {} in cache",
                                        redir, keyredir);
                                CACHE.put(keyredir, cachedRediRobotRules);
                            }
                            return cachedRediRobotRules;
                        }
                    }

                    response = http.getProtocolOutput(redir.toString(),
                            Metadata.empty);
                    code = response.getStatusCode();
                    bytesFetched.add(response.getContent() != null ? response
                            .getContent().length : 0);
                }
            }
            if (code == 200) // found rules: parse them
            {
                String ct = response.getMetadata().getFirstValue(
                        HttpHeaders.CONTENT_TYPE);
                robotRules = parseRules(url.toString(), response.getContent(),
                        ct, agentNames);
            } else if ((code == 403) && (!allowForbidden)) {
                robotRules = FORBID_ALL_RULES; // use forbid all
            } else if (code >= 500) {
                cacheRule = false;
                robotRules = EMPTY_RULES;
            } else
                robotRules = EMPTY_RULES; // use default rules
        } catch (Throwable t) {
            LOG.info("Couldn't get robots.txt for {} : {}", url, t.toString());
            cacheRule = false;
            robotRules = EMPTY_RULES;
        }

        Cache<String, RobotRules> cacheToUse = CACHE;
        String cacheName = "success";
        if (!cacheRule) {
            cacheToUse = ERRORCACHE;
            cacheName = "error";
        }

        RobotRules cached = new RobotRules(robotRules);

        LOG.debug("Caching robots for {} under key {} in cache {}", url,
                cacheKey, cacheName);
        cacheToUse.put(cacheKey, cached);

        // cache robot for redirections
        // get here only if the target has not been found in the cache
        if (keyredir != null) {
            // cache also for the redirected host
            // but only if the robots.txt file is at the root
            if (redir.getPath().equals("/robots.txt")) {
                LOG.debug("Caching robots for {} under key {} in cache {}",
                        redir, keyredir, cacheName);
                cacheToUse.put(keyredir, cached);
            }
        }

        RobotRules live = new RobotRules(robotRules);
        live.setContentLengthFetched(Ints.toArray(bytesFetched));
        return live;
    }
@Override
    public BaseRobotRules getRobotRulesSet(Protocol http, URL url) {

        String cacheKey = getCacheKey(url);

        // check in the error cache first
        BaseRobotRules robotRules = ERRORCACHE.getIfPresent(cacheKey);
        if (robotRules != null) {
            return robotRules;
        }

        // now try the proper cache
        robotRules = CACHE.getIfPresent(cacheKey);
        if (robotRules != null) {
            return robotRules;
        }

        boolean cacheRule = true;
        URL redir = null;

        String keyredir = null;

        LOG.debug("Cache miss {} for {}", cacheKey, url);
        List<Integer> bytesFetched = new LinkedList<>();
        try {
            ProtocolResponse response = http.getProtocolOutput(new URL(url,
                    "/robots.txt").toString(), Metadata.empty);
            int code = response.getStatusCode();
            bytesFetched.add(response.getContent() != null ? response
                    .getContent().length : 0);
            // try one level of redirection ?
            if (code == 301 || code == 302 || code == 307 || code == 308) {
                String redirection = response.getMetadata().getFirstValue(
                        HttpHeaders.LOCATION);
                if (StringUtils.isNotBlank(redirection)) {
                    if (!redirection.startsWith("http")) {
                        // RFC says it should be absolute, but apparently it
                        // isn't
                        redir = new URL(url, redirection);
                    } else {
                        redir = new URL(redirection);
                    }
                    // try from the cache
                    keyredir = getCacheKey(redir);
                    if (cacheKey.equalsIgnoreCase(keyredir)) {
                        keyredir = null;
                    } else {
                        RobotRules cachedRediRobotRules = CACHE
                                .getIfPresent(keyredir);
                        if (cachedRediRobotRules != null) {
                            // cache also for the redirected host
                            // but only if the robots.txt file is at the root
                            if (redir.getPath().equals("/robots.txt")) {
                                LOG.debug(
                                        "Caching robots for {} under key {} in cache",
                                        redir, keyredir);
                                CACHE.put(keyredir, cachedRediRobotRules);
                            }
                            return cachedRediRobotRules;
                        }
                    }

                    response = http.getProtocolOutput(redir.toString(),
                            Metadata.empty);
                    code = response.getStatusCode();
                    bytesFetched.add(response.getContent() != null ? response
                            .getContent().length : 0);
                }
            }
            if (code == 200) // found rules: parse them
            {
                String ct = response.getMetadata().getFirstValue(
                        HttpHeaders.CONTENT_TYPE);
                robotRules = parseRules(url.toString(), response.getContent(),
                        ct, agentNames);
            } else if ((code == 403) && (!allowForbidden)) {
                robotRules = FORBID_ALL_RULES; // use forbid all
            } else if (code >= 500) {
                cacheRule = false;
                robotRules = EMPTY_RULES;
            } else
                robotRules = EMPTY_RULES; // use default rules
        } catch (Throwable t) {
            LOG.info("Couldn't get robots.txt for {} : {}", url, t.toString());
            cacheRule = false;
            robotRules = EMPTY_RULES;
        }

        Cache<String, RobotRules> cacheToUse = CACHE;
        String cacheName = "success";
        if (!cacheRule) {
            cacheToUse = ERRORCACHE;
            cacheName = "error";
        }

        RobotRules cached = new RobotRules(robotRules);

        LOG.debug("Caching robots for {} under key {} in cache {}", url,
                cacheKey, cacheName);
        cacheToUse.put(cacheKey, cached);

        // cache robot for redirections
        // get here only if the target has not been found in the cache
        if (keyredir != null) {
            // cache also for the redirected host
            // but only if the robots.txt file is at the root
            if (redir.getPath().equals("/robots.txt")) {
                LOG.debug("Caching robots for {} under key {} in cache {}",
                        redir, keyredir, cacheName);
                cacheToUse.put(keyredir, cached);
            }
        }

        RobotRules live = new RobotRules(robotRules);
        live.setContentLengthFetched(Ints.toArray(bytesFetched));
        return live;
    }
Get the rules from robots.txt which applies for the given {@code url}.
Robot rules are cached for a unique combination of host, protocol, and
port. If no rules are found in the cache, a HTTP request is send to fetch
{{protocol://host:port/robots.txt}}. The robots.txt is then parsed and
the rules are cached to avoid re-fetching and re-parsing it again.

@param http
The {@link Protocol} object
@param url
URL robots.txt applies to

@return {@link BaseRobotRules} holding the rules from robots.txt