contentTypeChecker.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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 isWebp = require('is-webp');
  8. var isWoff = require('is-woff');
  9. var isWoff2 = require('is-woff2');
  10. var isOtf = require('is-otf');
  11. var isTtf = require('is-ttf');
  12. var isEot = require('is-eot');
  13. var ContentTypeChecker = function() {
  14. function checkContentType(entry) {
  15. var deferred = Q.defer();
  16. debug('Entering contentTypeChecker');
  17. debug(entry);
  18. // Setting isSomething values:
  19. switch(entry.type) {
  20. case 'html':
  21. entry.isHTML = true;
  22. break;
  23. case 'xml':
  24. entry.isXML = true;
  25. break;
  26. case 'css':
  27. entry.isCSS = true;
  28. break;
  29. case 'js':
  30. entry.isJS = true;
  31. break;
  32. case 'json':
  33. entry.isJSON = true;
  34. break;
  35. case 'image':
  36. entry.isImage = true;
  37. break;
  38. case 'webfont':
  39. entry.isWebFont = true;
  40. break;
  41. case 'video':
  42. entry.isVideo = true;
  43. break;
  44. case 'favicon':
  45. entry.isFavicon = true;
  46. break;
  47. }
  48. // Now let's check for mistakes by analysing body content. It happens more often then we think!
  49. // Ignore very small files as they are generally tracking pixels
  50. if (entry.weightCheck && entry.weightCheck.bodyBuffer && entry.weightCheck.bodySize > 100) {
  51. var foundType;
  52. try {
  53. foundType = findContentType(entry.weightCheck.bodyBuffer);
  54. if (foundType !== null && foundType.type !== entry.type) {
  55. debug('Content type %s is wrong for %s. It should be %s.', entry.type, entry.ulr, foundType.type);
  56. rewriteContentType(entry, foundType);
  57. }
  58. } catch(err) {
  59. debug('Error while analyzing the contentType of %s', entry.url);
  60. debug(err);
  61. }
  62. }
  63. deferred.resolve(entry);
  64. return deferred.promise;
  65. }
  66. function findContentType(bodyBuffer) {
  67. var bodyStr = bodyBuffer.toString();
  68. if (isJpg(bodyBuffer)) {
  69. return contentTypes.jpeg;
  70. }
  71. if (isPng(bodyBuffer)) {
  72. return contentTypes.png;
  73. }
  74. // https://github.com/sindresorhus/is-svg/issues/7
  75. if (/<svg/.test(bodyStr) && isSvg(bodyStr)) {
  76. return contentTypes.svg;
  77. }
  78. if (isGif(bodyBuffer)) {
  79. return contentTypes.gif;
  80. }
  81. if (isWebp(bodyBuffer)) {
  82. return contentTypes.webp;
  83. }
  84. if (isWoff(bodyBuffer)) {
  85. return contentTypes.woff;
  86. }
  87. if (isWoff2(bodyBuffer)) {
  88. return contentTypes.woff2;
  89. }
  90. if (isOtf(bodyBuffer)) {
  91. return contentTypes.otf;
  92. }
  93. if (isTtf(bodyBuffer)) {
  94. return contentTypes.ttf;
  95. }
  96. if (isEot(bodyBuffer)) {
  97. return contentTypes.eot;
  98. }
  99. return null;
  100. }
  101. function rewriteContentType(entry, contentTypeObj) {
  102. delete(entry.isHTML);
  103. delete(entry.isXML);
  104. delete(entry.isCSS);
  105. delete(entry.isJS);
  106. delete(entry.isJSON);
  107. delete(entry.isImage);
  108. delete(entry.isSVG);
  109. delete(entry.isVideo);
  110. delete(entry.isWebFont);
  111. delete(entry.isTTF);
  112. delete(entry.isFavicon);
  113. entry.contentType = contentTypeObj.mimes[0];
  114. contentTypeObj.updateFn(entry);
  115. }
  116. var contentTypes = {
  117. jpeg: {
  118. type: 'image',
  119. mimes: ['image/jpeg'],
  120. updateFn: function(entry) {
  121. entry.type = 'image';
  122. entry.isImage = true;
  123. }
  124. },
  125. png: {
  126. type: 'image',
  127. mimes: ['image/png'],
  128. updateFn: function(entry) {
  129. entry.type = 'image';
  130. entry.isImage = true;
  131. }
  132. },
  133. svg: {
  134. type: 'image',
  135. mimes: ['image/svg+xml'],
  136. updateFn: function(entry) {
  137. entry.type = 'image';
  138. entry.isImage = true;
  139. entry.isSVG = true;
  140. }
  141. },
  142. gif: {
  143. type: 'image',
  144. mimes: ['image/gif'],
  145. updateFn: function(entry) {
  146. entry.type = 'image';
  147. entry.isImage = true;
  148. }
  149. },
  150. webp: {
  151. type: 'image',
  152. mimes: ['image/webp'],
  153. updateFn: function(entry) {
  154. entry.type = 'image';
  155. entry.isImage = true;
  156. }
  157. },
  158. woff: {
  159. type: 'webfont',
  160. mimes: ['application/x-font-woff', 'application/font-woff', 'font/woff'],
  161. updateFn: function(entry) {
  162. entry.type = 'webfont';
  163. entry.isWebFont = true;
  164. }
  165. },
  166. woff2: {
  167. type: 'webfont',
  168. mimes: ['font/woff2', 'application/x-font-woff2', 'application/font-woff2'],
  169. updateFn: function(entry) {
  170. entry.type = 'webfont';
  171. entry.isWebFont = true;
  172. }
  173. },
  174. otf: {
  175. type: 'webfont',
  176. mimes: ['application/x-font-otf', 'font/otf', 'font/opentype', 'application/x-font-opentype'],
  177. updateFn: function(entry) {
  178. entry.type = 'webfont';
  179. entry.isWebFont = true;
  180. }
  181. },
  182. ttf: {
  183. type: 'webfont',
  184. mimes: ['application/x-font-ttf', 'font/ttf', 'application/x-font-truetype'],
  185. updateFn: function(entry) {
  186. entry.type = 'webfont';
  187. entry.isWebFont = true;
  188. }
  189. },
  190. eot: {
  191. type: 'webfont',
  192. mimes: ['application/vnd.ms-fontobject', 'font/eot'],
  193. updateFn: function(entry) {
  194. entry.type = 'webfont';
  195. entry.isWebFont = true;
  196. }
  197. }
  198. };
  199. return {
  200. checkContentType: checkContentType,
  201. findContentType: findContentType
  202. };
  203. };
  204. module.exports = new ContentTypeChecker();