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 | }
|
---|