-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.js
127 lines (99 loc) · 3.43 KB
/
server.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
117
118
119
120
121
122
123
124
125
126
127
'use strict';
// Framework dependencies
const express = require('express');
const fs = require('fs');
const httpContext = require('express-http-context');
const newrelic = process.env.NEW_RELIC_LICENSE_KEY ? require('newrelic') : null;
// Modules
const errorHandling = require('./error-handling');
const optimize = require('./optimize');
const TempTracker = require('./temptracker').TempTracker;
const api = require('./api');
const proxy = require('./proxy');
const OriginWhitelist = require('./origin-whitelist').OriginWhitelist;
const frame = require('./frame');
const log = require('./logger');
const Timer = require('./timer').Timer;
// Constants
const PORT = 80;
const HOST = '0.0.0.0';
const TEMP_DIR = process.env.IMGSRV_TEMP || (__dirname + '/tmp');
// App
const app = express();
// Middleware to keep request-scoped state for JSON logging
app.use(httpContext.middleware);
// Create a whitelist of allowed domains/paths for source images
// If none is supplied, all domains are allowed
const originWhitelist = new OriginWhitelist(process.env.IMGSRV_ORIGIN_WHITELIST);
// Main image optimization proxy route
app.get('/', async (req, res, next) => {
if (newrelic) {
newrelic.setTransactionName('GET/');
}
// Keep track of temp files so we can clean them up after each request
let tempTracker = new TempTracker(TEMP_DIR);
// Initialize the log with a request ID and URL
log.init(tempTracker.id, req.url);
// Instrument performance
let timer = new Timer();
try {
let params = api.parseParams(req);
// Validate the source URL is in the whitelist of allowed domains
// Reduces surface area for DOS attack
originWhitelist.validate(params.uri);
log.write('perf', timer.messages);
// Get the source file and save to disk
timer.start('get');
let tempFile = await proxy.getFile(params.uri, tempTracker);
timer.stop('get');
// Generate the best optimized version of the file
timer.start('optimize');
let optimizedFile = await optimize.optimize(tempFile, params.width, params.allowWebp, params.allowJp2, params.allowJxr, tempTracker);
timer.stop('optimize');
log.write({
resultFile: optimizedFile.path,
resultSize: optimizedFile.fileSize
});
// Write the optimized file to the browser
timer.start('send');
await proxy.sendFile(res, optimizedFile.path, optimizedFile.mimeType);
timer.stop('send');
log.flush();
} catch (ex) {
timer.cleanup();
next(ex);
} finally {
// Clean up temp files
if (tempTracker) {
await tempTracker.cleanup();
}
}
});
// Renders a page which contains an image with the same params
// Useful for testing browser-sniffing and URL generation
app.get('/frame', async (req, res, next) => {
try {
let params = api.parseParams(req);
await frame.write(req, res, next);
} catch (ex) {
next(ex);
}
});
// Error handling goes last
app.use(errorHandling.middleware);
app.listen(PORT, HOST);
// Ensure there's a temp dir
if (!fs.existsSync(TEMP_DIR)) {
fs.mkdirSync(TEMP_DIR);
}
log.writeNoRequest({
source: log.sourceName,
startup: `http://${HOST}:${PORT}`,
env: process.env.NODE_ENV || 'development',
tmp: TEMP_DIR,
verbose: log.verbose,
maxSize: proxy.maxSize,
maxWidth: api.maxWidth,
originTimeout: proxy.originTimeout,
whitelist: originWhitelist.getStatus()
});