cdnDetector.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. var debug = require('debug')('ylt:cdnDetector');
  2. var Q = require('q');
  3. var url = require('url');
  4. var dns = require('dns');
  5. var cdnDetector = require('cdn-detector');
  6. // This module checks my multiple ways if a request was served by a CDN
  7. var CDNDetector = function() {
  8. function detectCDN(entry) {
  9. var urlObject = url.parse(entry.url);
  10. debug('Start checking CDN for %s, host is %s', entry.url, urlObject.host);
  11. // 1st, the fastest check: the domain is directly recognized as a CDN
  12. return checkDomainDirectly(entry)
  13. .fail(function() {
  14. // 2nd, check the response headers
  15. return checkHeaders(entry)
  16. .fail(function() {
  17. // 3rd, check the Name Servers
  18. return checkNameServers(entry)
  19. .fail(function(entry) {
  20. // None of the above worked, we didn't find any trace of a CDN
  21. return entry;
  22. });
  23. })
  24. });
  25. }
  26. return {
  27. detectCDN: detectCDN
  28. };
  29. // Compares the URL's domain to a list of know CDN, just in case
  30. function checkDomainDirectly(entry) {
  31. var deferred = Q.defer();
  32. var result = checkHostname(url.parse(entry.url).host);
  33. if (result === null) {
  34. deferred.reject(entry);
  35. } else {
  36. entry.weightCheck.cdn = result;
  37. deferred.resolve(entry);
  38. }
  39. return deferred.promise;
  40. }
  41. // Compares a list of HTTP response headers to a matching list
  42. // For example, if there is an X-Akamai-Request-Id header, we know it is Akamai
  43. function checkHeaders(entry) {
  44. var deferred = Q.defer();
  45. var result = cdnDetector.detectFromHeaders(entry.weightCheck.headers);
  46. debug('Headers of %s were compared to the list. Result: %s', entry.url, JSON.stringify(result));
  47. if (result === null) {
  48. deferred.reject(entry);
  49. } else {
  50. entry.weightCheck.cdn = result.cdn;
  51. deferred.resolve(entry);
  52. }
  53. return deferred.promise;
  54. }
  55. function checkNameServers(entry) {
  56. var deferred = Q.defer();
  57. var hostname = url.parse(entry.url).host;
  58. // Send a request to get the Name Servers list
  59. // https://nodejs.org/api/dns.html#dns_dns_resolvens_hostname_callback
  60. dns.resolveNs(hostname, function(error, nameServers) {
  61. if (error) {
  62. debug(error);
  63. debug('Could not find Name Servers for %s', hostname);
  64. deferred.reject(entry);
  65. } else {
  66. debug('Name Servers for %s are ["%s"]', hostname, nameServers.join('", "'));
  67. var cdn = nameServers.map(checkHostname).find(function(entry) {
  68. return entry !== null;
  69. });
  70. if (cdn) {
  71. entry.weightCheck.cdn = cdn;
  72. deferred.resolve(entry);
  73. } else {
  74. deferred.reject(entry);
  75. }
  76. }
  77. });
  78. return deferred.promise;
  79. }
  80. // Compares the hostname to a matching list of hostnames
  81. function checkHostname(hostname) {
  82. var result = cdnDetector.detectFromHostname(hostname);
  83. debug('Hostname %s was compared to the list. Result: %s', hostname, JSON.stringify(result));
  84. return result ? result.cdn : null;
  85. }
  86. // Find an IP address with a DNS lookup
  87. function getIP(hostname) {
  88. var deferred = Q.defer();
  89. // https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback
  90. dns.lookup(hostname, {family: 4}, function(error, address) {
  91. if (error) {
  92. debug('Could not find IP address for %s', hostname);
  93. } else {
  94. debug('The IP address for %s is %s', hostname, address);
  95. }
  96. deferred.resolve(error ? null : address);
  97. });
  98. return deferred.promise;
  99. }
  100. // Compares the IP address agains a list of IP ranges
  101. function checkIPAddress(address) {
  102. var deferred = Q.defer();
  103. var result = cdnDetector.detectFromHeaders(headers);
  104. debug('Headers were compared to the list. Result: %s', JSON.stringify(result));
  105. if (result === null) {
  106. deferred.reject();
  107. } else {
  108. deferred.resolve(result.cdn);
  109. }
  110. return deferred.promise;
  111. }
  112. function saveCDN(cdnName) {
  113. }
  114. };
  115. module.exports = new CDNDetector();