contentTypeChecker.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. var debug = require('debug')('ylt:contentTypeChecker');
  2. var Q = require('q');
  3. var isJpg = require('is-jpg');
  4. var isPng = require('is-png');
  5. var isSvg = require('is-svg');
  6. var isGif = require('is-gif');
  7. var isWoff = require('is-woff');
  8. var isWoff2 = require('is-woff2');
  9. var isOtf = require('is-otf');
  10. var isTtf = require('is-ttf');
  11. var isEot = require('is-eot');
  12. var ContentTypeChecker = function() {
  13. function checkContentType(entry) {
  14. var deferred = Q.defer();
  15. debug('Entering contentTypeChecker');
  16. // Ignore very small files as they are generally tracking pixels
  17. if (entry.weightCheck && entry.weightCheck.body && entry.weightCheck.bodySize > 100) {
  18. var foundType;
  19. try {
  20. foundType = findContentType(entry.weightCheck.body);
  21. if (!entry.contentType || entry.contentType === '') {
  22. if (foundType === null) {
  23. debug('ContentType is empty for file %s', entry.url);
  24. } else {
  25. debug('ContentType is empty for file %s. It should be %s.', entry.url, foundType.mimes[0]);
  26. entry.oldContentType = null;
  27. rewriteContentType(entry, foundType);
  28. }
  29. } else {
  30. if (foundType !== null && foundType.mimes.indexOf(entry.contentType) === -1) {
  31. debug('ContentType %s is wrong for %s. It should be %s.', entry.contentType, entry.url, foundType.mimes[0]);
  32. entry.oldContentType = entry.contentType;
  33. rewriteContentType(entry, foundType);
  34. }
  35. }
  36. } catch(err) {
  37. debug('Error while analyzing the contentType of %s', entry.url);
  38. debug(err);
  39. }
  40. }
  41. deferred.resolve(entry);
  42. return deferred.promise;
  43. }
  44. function findContentType(body) {
  45. var buffer = new Buffer(body, 'binary');
  46. if (isJpg(buffer)) {
  47. return contentTypes.jpeg;
  48. }
  49. if (isPng(buffer)) {
  50. return contentTypes.png;
  51. }
  52. // https://github.com/sindresorhus/is-svg/issues/7
  53. if (/<svg/.test(body) && isSvg(body)) {
  54. return contentTypes.svg;
  55. }
  56. if (isGif(buffer)) {
  57. return contentTypes.gif;
  58. }
  59. if (isWoff(buffer)) {
  60. return contentTypes.woff;
  61. }
  62. if (isWoff2(buffer)) {
  63. return contentTypes.woff2;
  64. }
  65. if (isOtf(buffer)) {
  66. return contentTypes.otf;
  67. }
  68. if (isTtf(buffer)) {
  69. return contentTypes.ttf;
  70. }
  71. if (isEot(buffer)) {
  72. return contentTypes.eot;
  73. }
  74. return null;
  75. }
  76. function rewriteContentType(entry, contentTypeObj) {
  77. delete(entry.isHTML);
  78. delete(entry.isXML);
  79. delete(entry.isCSS);
  80. delete(entry.isJS);
  81. delete(entry.isJSON);
  82. delete(entry.isImage);
  83. delete(entry.isSVG);
  84. delete(entry.isVideo);
  85. delete(entry.isWebFont);
  86. delete(entry.isTTF);
  87. delete(entry.isFavicon);
  88. entry.contentType = contentTypeObj.mimes[0];
  89. contentTypeObj.updateFn(entry);
  90. }
  91. var contentTypes = {
  92. jpeg: {
  93. mimes: ['image/jpeg'],
  94. updateFn: function(entry) {
  95. entry.type = 'image';
  96. entry.isImage = true;
  97. }
  98. },
  99. png: {
  100. mimes: ['image/png'],
  101. updateFn: function(entry) {
  102. entry.type = 'image';
  103. entry.isImage = true;
  104. }
  105. },
  106. svg: {
  107. mimes: ['image/svg+xml'],
  108. updateFn: function(entry) {
  109. entry.type = 'image';
  110. entry.isImage = true;
  111. entry.isSVG = true;
  112. }
  113. },
  114. gif: {
  115. mimes: ['image/gif'],
  116. updateFn: function(entry) {
  117. entry.type = 'image';
  118. entry.isImage = true;
  119. }
  120. },
  121. woff: {
  122. mimes: ['application/x-font-woff', 'application/font-woff', 'font/woff'],
  123. updateFn: function(entry) {
  124. entry.type = 'webfont';
  125. entry.isWebFont = true;
  126. }
  127. },
  128. woff2: {
  129. mimes: ['font/woff2', 'application/x-font-woff2', 'application/font-woff2'],
  130. updateFn: function(entry) {
  131. entry.type = 'webfont';
  132. entry.isWebFont = true;
  133. }
  134. },
  135. otf: {
  136. mimes: ['application/x-font-otf', 'font/otf', 'font/opentype', 'application/x-font-opentype'],
  137. updateFn: function(entry) {
  138. entry.type = 'webfont';
  139. entry.isWebFont = true;
  140. }
  141. },
  142. ttf: {
  143. mimes: ['application/x-font-ttf', 'font/ttf', 'application/x-font-truetype'],
  144. updateFn: function(entry) {
  145. entry.type = 'webfont';
  146. entry.isWebFont = true;
  147. }
  148. },
  149. eot: {
  150. mimes: ['application/vnd.ms-fontobject', 'font/eot'],
  151. updateFn: function(entry) {
  152. entry.type = 'webfont';
  153. entry.isWebFont = true;
  154. }
  155. }
  156. };
  157. return {
  158. checkContentType: checkContentType,
  159. findContentType: findContentType
  160. };
  161. };
  162. module.exports = new ContentTypeChecker();