-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
116 lines (102 loc) · 4.88 KB
/
index.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
116
'use strict';
const Proxy = require('./lib/proxy');
const Redirect = require('./lib/redirect');
const util = require('./lib/util');
// These are the domains that this application is handling traffic for
const HOSTS = (process.env.CANONICAL_HOSTS || 'www.prx.org,proxy.prx.org,proxy.staging.prx.tech,localhost:3000').split(',');
const PRI_HOSTS = ['pri.org', 'www.pri.org', 'beta.pri.org', 'www-proxy-test.pri.org'];
// Values set using the x-prx-domain header
// This is for cases where the proxy is running behind a CDN and is not getting
// the viewer request domain. It allow for explicit handling of traffic from
// specific CDNs (i.e., different CDNs would handle different domains, like
// one for prx.org and one for pri.org).
const PRI_HEADER_DOMAIN = 'pri.org';
// These are the domains that traffic is redirected to or used to fetch data
// when being proxied. They are NOT domains for traffic being handled by this
// application.
const EXCHANGE_HOST = process.env.EXCHANGE_HOST || 'exchange.prx.org';
const LISTEN_HOST = process.env.LISTEN_HOST || 'beta.prx.org';
const HELP_HOST = process.env.HELP_HOST || 'help.prx.org';
const CORPORATE_HOST = process.env.CORPORATE_HOST || 'corporate.prx.tech';
const THEWORLD_HOST = process.env.THEWORLD_HOST || 'theworld.org';
const THEWORLD_ADMIN_HOST = process.env.THEWORLD_ADMIN_HOST || 'admin.theworld.org';
const THEWORLD_EMBEDS_HOST = process.env.THEWORLD_EMBEDS_HOST || 'embedded.theworld.org';
const THEWORLD_FEEDS_HOST = process.env.THEWORLD_FEEDS_HOST || 'feeds.theworld.org';
const THEWORLD_FILES_HOST = process.env.THEWORLD_FILES_HOST || 'files.theworld.org';
const THEWORLD_SITEMAP_HOST = process.env.THEWORLD_SITEMAP_HOST || 'sitemap.theworld.org';
const PRX_ROUTES = [
[require('./routes/exchange-proxy'), new Proxy(EXCHANGE_HOST)],
[require('./routes/listen-redirect'), new Redirect(LISTEN_HOST, require('./routes/listen-rewrite'))],
[require('./routes/exchange-redirect'), new Redirect(EXCHANGE_HOST)],
[require('./routes/help-redirect'), new Redirect(HELP_HOST, require('./routes/help-rewrite'))],
[[/./], new Proxy(CORPORATE_HOST)],
];
const PRI_ROUTES = [
[require('./routes/pri-admin-redirect'), new Redirect(THEWORLD_ADMIN_HOST, null, true, 301)],
[require('./routes/pri-embed-redirect'), new Redirect(THEWORLD_EMBEDS_HOST, null, true, 301)],
[require('./routes/pri-feeds-redirect'), new Redirect(THEWORLD_FEEDS_HOST, null, true, 301)],
[require('./routes/pri-files-redirect'), new Redirect(THEWORLD_FILES_HOST, null, true, 301)],
[require('./routes/pri-sitemap-redirect'), new Redirect(THEWORLD_SITEMAP_HOST, null, true, 301)],
[[/./], new Redirect(THEWORLD_HOST, null, true, 301)],
];
/**
* Proxy requests here and there
*/
exports.handler = function handler(event, context, callback) {
const apiId = event.requestContext.apiId;
HOSTS.push(`${apiId}.execute-api.${process.env.AWS_REGION}.amazonaws.com`);
const headers = util.keysToLowerCase(event.headers);
let route;
let domain = 'default';
if (PRI_HOSTS.includes(headers.host) || headers['x-prx-domain'] === PRI_HEADER_DOMAIN) {
domain = 'pri';
// Handle pri.org traffic
PRI_ROUTES.find(([matchers, obj]) => {
if (matchers.some(m => m.test(event.path))) {
return route = obj;
}
});
} else if (HOSTS.includes(headers.host)) {
// Handle prx.org traffic
domain = 'prx';
const loggedIn = util.isLoggedIn(headers['cookie']);
const isCrawler = util.isCrawler(headers['user-agent']);
const isMobile = util.isMobile(headers['user-agent']);
const hatesMobile = util.hatesMobileSite(headers['referer'], event.queryStringParameters);
// test paths
PRX_ROUTES.find(([matchers, obj]) => {
if (matchers.some(m => m.test(event.path, loggedIn, isCrawler, isMobile, hatesMobile))) {
return route = obj;
}
});
} else {
const loc = `https://${HOSTS[0]}${event.path}${util.queryToString(event.queryStringParameters)}`;
return callback(null, {
statusCode: 302,
headers: { 'location': loc, 'content-type': 'text/plain' },
body: `Moved to ${loc}`
});
}
// async handle proxying or redirecting
if (route) {
route.request(event).then(resp => {
const name = route.constructor.name;
const path = `${route.host}${event.path}`;
console.info(JSON.stringify({
statusCode: resp.statusCode,
httpMethod: event.httpMethod,
routeType: name,
routeDestination: path,
domain: domain,
}))
callback(null, resp);
}).catch(err => {
console.error(`[ERROR] 500 ${event.httpMethod} ${event.path}`);
console.error(err);
callback(null, {statusCode: 500, body: 'Something went wrong', headers: {'content-type': 'text/plain'}});
});
} else {
console.error(`[ERROR] No handler for ${event.httpMethod} ${event.path}`);
callback(null, {statusCode: 500, body: 'No handler for request', headers: {'content-type': 'text/plain'}});
}
};