contentTypeChecker.js 6.6 KB

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