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