index.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. 'use strict';
  2. var url = require('url');
  3. exports = module.exports = function historyApiFallback(options) {
  4. options = options || {};
  5. var logger = getLogger(options);
  6. return function(req, res, next) {
  7. var headers = req.headers;
  8. if (req.method !== 'GET') {
  9. logger(
  10. 'Not rewriting',
  11. req.method,
  12. req.url,
  13. 'because the method is not GET.'
  14. );
  15. return next();
  16. } else if (!headers || typeof headers.accept !== 'string') {
  17. logger(
  18. 'Not rewriting',
  19. req.method,
  20. req.url,
  21. 'because the client did not send an HTTP accept header.'
  22. );
  23. return next();
  24. } else if (headers.accept.indexOf('application/json') === 0) {
  25. logger(
  26. 'Not rewriting',
  27. req.method,
  28. req.url,
  29. 'because the client prefers JSON.'
  30. );
  31. return next();
  32. } else if (!acceptsHtml(headers.accept, options)) {
  33. logger(
  34. 'Not rewriting',
  35. req.method,
  36. req.url,
  37. 'because the client does not accept HTML.'
  38. );
  39. return next();
  40. }
  41. var parsedUrl = url.parse(req.url);
  42. var rewriteTarget;
  43. options.rewrites = options.rewrites || [];
  44. for (var i = 0; i < options.rewrites.length; i++) {
  45. var rewrite = options.rewrites[i];
  46. var match = parsedUrl.pathname.match(rewrite.from);
  47. if (match !== null) {
  48. rewriteTarget = evaluateRewriteRule(parsedUrl, match, rewrite.to, req);
  49. logger('Rewriting', req.method, req.url, 'to', rewriteTarget);
  50. req.url = rewriteTarget;
  51. return next();
  52. }
  53. }
  54. var pathname = parsedUrl.pathname;
  55. if (pathname.lastIndexOf('.') > pathname.lastIndexOf('/') &&
  56. options.disableDotRule !== true) {
  57. logger(
  58. 'Not rewriting',
  59. req.method,
  60. req.url,
  61. 'because the path includes a dot (.) character.'
  62. );
  63. return next();
  64. }
  65. rewriteTarget = options.index || '/index.html';
  66. logger('Rewriting', req.method, req.url, 'to', rewriteTarget);
  67. req.url = rewriteTarget;
  68. next();
  69. };
  70. };
  71. function evaluateRewriteRule(parsedUrl, match, rule, req) {
  72. if (typeof rule === 'string') {
  73. return rule;
  74. } else if (typeof rule !== 'function') {
  75. throw new Error('Rewrite rule can only be of type string of function.');
  76. }
  77. return rule({
  78. parsedUrl: parsedUrl,
  79. match: match,
  80. request: req
  81. });
  82. }
  83. function acceptsHtml(header, options) {
  84. options.htmlAcceptHeaders = options.htmlAcceptHeaders || ['text/html', '*/*'];
  85. for (var i = 0; i < options.htmlAcceptHeaders.length; i++) {
  86. if (header.indexOf(options.htmlAcceptHeaders[i]) !== -1) {
  87. return true;
  88. }
  89. }
  90. return false;
  91. }
  92. function getLogger(options) {
  93. if (options && options.logger) {
  94. return options.logger;
  95. } else if (options && options.verbose) {
  96. return console.log.bind(console);
  97. }
  98. return function(){};
  99. }