Repository navigation
Expand file tree
/
Copy pathredirect.js
More file actions
97 lines (86 loc) · 3.06 KB
/
Copy pathredirect.js
File metadata and controls
97 lines (86 loc) · 3.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const {doRedirect} = require('./env');
const redirectsYaml = require('redirects-yaml');
const YAML = require('js-yaml');
const fs = require('fs');
const path = require('path');
// Included for types only.
// eslint-disable-next-line no-unused-vars
const express = require('express');
/**
* @param {redirectsYaml.RedirectLine[]} redirects
* @param {string[]=} staticPaths
*/
function buildCheckHandlerInternal(redirects, staticPaths = undefined) {
let checker = () => true;
if (staticPaths) {
// Ensure that staticPath is never blank (this ensures it's always ".").
const alwaysStaticPaths = staticPaths.map(staticPath => staticPath || '.');
checker = s => {
for (const staticPath of alwaysStaticPaths) {
// This is passed the folder name, not "/index.html". We just assume that any folder that
// exists can be redirected to.
const check = path.join(staticPath, s);
if (fs.existsSync(check)) {
return true;
}
}
return false;
};
}
return redirectsYaml.buildHandlers(redirects, checker);
}
/**
* Builds HTTP middleware that serves redirects for a redirects.yaml
* configuration file.
*
* @param {string} filename to load configuration from
* @param {string[]=} staticPaths to check if content exists
* @param {number=} code to use
* @return {express.RequestHandler}
*/
function buildRedirectHandler(filename, staticPaths = undefined, code = 301) {
const raw = YAML.load(fs.readFileSync(filename, 'utf-8'));
const {redirects} =
/** @type {{ redirects: redirectsYaml.RedirectLine[] }} */ (raw);
const handler = buildCheckHandlerInternal(redirects, staticPaths);
/** @type {express.RequestHandler} */
return (req, res, next) => {
const target = handler(req.url);
if (target !== null && target !== req.url) {
return doRedirect(res, target, code);
}
// If we didn't match normally but the URL contains a dot, then check it again with those
// replaced with underscores. There are various bad links to APIs with ".", when the generated
// pages actually use "_".
if (req.url.includes('.')) {
let update = req.url.replace(/\./g, '_');
if (update.endsWith('_html')) {
update = update.slice(0, -5) + '.html';
}
const target = handler(update);
if (target !== null && target !== req.url) {
return doRedirect(res, target, code);
}
}
return next();
};
}
module.exports = {
buildCheckHandlerInternal,
buildRedirectHandler,
};