-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathredirect-handler.js
116 lines (95 loc) · 3.5 KB
/
redirect-handler.js
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
* @license
* Copyright 2020 Brigham Young University
*
* 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
*
* http://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.
*/
"use strict";
const defaultRulesLoader = require('./redirect-rules-loader.js');
const Cache = require('./cache.js');
const applyRules = require('./apply-rules.js');
const DEFAULT_RULES_CACHE_TTL = 60 * 1000;
module.exports = class RedirectHandler {
constructor({
defaultHost = null,
redirectRulesLoader = defaultRulesLoader,
cacheTTL = DEFAULT_RULES_CACHE_TTL,
}) {
this.defaultHost = defaultHost;
this.redirectRulesLoader = redirectRulesLoader;
this.cache = new Cache({ttl: cacheTTL});
}
async handleRequest(request) {
const uri = request.uri;
console.log('incoming request to', uri);
const host = resolveHostForRequest(request, this.defaultHost, true);
const rules = await this.cache.get(() => this.redirectRulesLoader({host}));
const pathParts = uri.split('/').filter(it => it.length > 0);
const redirect = applyRules(rules, pathParts);
if (redirect) {
console.log('Got a redirect from ', redirect.from, 'to', redirect.to);
const file = uri.replace(redirect.from, '');
const destination = uri.replace(redirect.from, redirect.to);
return {
status: String(redirect.status),
headers: getHeadersForRedirect(file, destination, redirect),
}
} else {
console.log('No redirect');
return request;
}
}
};
function getHeadersForRedirect(file, destination, redirect) {
const headers = {
Location: destination,
'Cache-Control': redirect.cache,
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, HEAD',
'Access-Control-Max-Age': '86400',
'Timing-Allow-Origin': '*'
};
if (redirect.preload) {
console.log('Computing preload headers for', file);
const preload = buildPreload(file, redirect.preload);
if (preload) {
console.log('Sending Link header', preload);
headers.Link = preload;
}
}
return toAmzHeaders(headers);
}
function buildPreload(file, preload) {
return preload[file];
}
function toAmzHeaders(headers) {
return Object.entries(headers)
.reduce((agg, [key, value]) => {
agg[key.toLowerCase()] = [{
key, value
}];
return agg;
}, {});
}
const S3_WEBSITE_HOST = 's3-website-us-east-1.amazonaws.com';
const S3_SECURE_HOST = 's3.dualstack.us-east-1.amazonaws.com';
function resolveHostForRequest(request, defaultHost, canUseCloudfront) {
if (canUseCloudfront && defaultHost) {
return defaultHost;
}
const host = request.headers.host[0].value;
if (host.includes(S3_WEBSITE_HOST)) {
return host.replace(S3_WEBSITE_HOST, S3_SECURE_HOST);
}
return host;
}