Files

150 lines
4.5 KiB
JavaScript

var debug = require('debug')('ylt:cdnDetector');
var Q = require('q');
var url = require('url');
var dns = require('dns');
var cdnDetector = require('cdn-detector');
// This module checks my multiple ways if a request was served by a CDN
var CDNDetector = function() {
function detectCDN(entry) {
var urlObject = url.parse(entry.url);
debug('Start checking CDN for %s, host is %s', entry.url, urlObject.host);
// 1st, the fastest check: the domain is directly recognized as a CDN
return checkDomainDirectly(entry)
.fail(function() {
// 2nd, check the response headers
return checkHeaders(entry)
.fail(function() {
// 3rd, check the Name Servers
return checkNameServers(entry)
.fail(function(entry) {
// None of the above worked, we didn't find any trace of a CDN
return entry;
});
})
});
}
return {
detectCDN: detectCDN
};
// Compares the URL's domain to a list of know CDN, just in case
function checkDomainDirectly(entry) {
var deferred = Q.defer();
var result = checkHostname(url.parse(entry.url).host);
if (result === null) {
deferred.reject(entry);
} else {
entry.weightCheck.cdn = result;
deferred.resolve(entry);
}
return deferred.promise;
}
// Compares a list of HTTP response headers to a matching list
// For example, if there is an X-Akamai-Request-Id header, we know it is Akamai
function checkHeaders(entry) {
var deferred = Q.defer();
var result = cdnDetector.detectFromHeaders(entry.weightCheck.headers);
debug('Headers of %s were compared to the list. Result: %s', entry.url, JSON.stringify(result));
if (result === null) {
deferred.reject(entry);
} else {
entry.weightCheck.cdn = result.cdn;
deferred.resolve(entry);
}
return deferred.promise;
}
function checkNameServers(entry) {
var deferred = Q.defer();
var hostname = url.parse(entry.url).host;
// Send a request to get the Name Servers list
// https://nodejs.org/api/dns.html#dns_dns_resolvens_hostname_callback
dns.resolveNs(hostname, function(error, nameServers) {
if (error) {
debug(error);
debug('Could not find Name Servers for %s', hostname);
deferred.reject(entry);
} else {
debug('Name Servers for %s are ["%s"]', hostname, nameServers.join('", "'));
var cdn = nameServers.map(checkHostname).find(function(entry) {
return entry !== null;
});
if (cdn) {
entry.weightCheck.cdn = cdn;
deferred.resolve(entry);
} else {
deferred.reject(entry);
}
}
});
return deferred.promise;
}
// Compares the hostname to a matching list of hostnames
function checkHostname(hostname) {
var result = cdnDetector.detectFromHostname(hostname);
debug('Hostname %s was compared to the list. Result: %s', hostname, JSON.stringify(result));
return result ? result.cdn : null;
}
// Find an IP address with a DNS lookup
function getIP(hostname) {
var deferred = Q.defer();
// https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback
dns.lookup(hostname, {family: 4}, function(error, address) {
if (error) {
debug('Could not find IP address for %s', hostname);
} else {
debug('The IP address for %s is %s', hostname, address);
}
deferred.resolve(error ? null : address);
});
return deferred.promise;
}
// Compares the IP address agains a list of IP ranges
function checkIPAddress(address) {
var deferred = Q.defer();
var result = cdnDetector.detectFromHeaders(headers);
debug('Headers were compared to the list. Result: %s', JSON.stringify(result));
if (result === null) {
deferred.reject();
} else {
deferred.resolve(result.cdn);
}
return deferred.promise;
}
function saveCDN(cdnName) {
}
};
module.exports = new CDNDetector();