-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathproxy.js
122 lines (98 loc) · 3.25 KB
/
proxy.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
'use strict';
const request = require('request');
const util = require('util');
const fs = require('fs');
const log = require('./logger');
const MAX_SIZE = process.env.IMGSRV_MAX_SIZE || 3145728; // 3MB
const ORIGIN_TIMEOUT = process.env.IMGSRV_ORIGIN_TIMEOUT || 10000;
const validateResponse = function(response) {
if (response.statusCode != 200) {
throw new Error(`Requested image failed with status code: ${response.statusCode}`);
}
let contentTypeHeader = response.headers['content-type'];
if (!contentTypeHeader) {
throw new Error('Requested image failed: no content type specified');
}
let splitContentType = contentTypeHeader.split('/');
let contentTypeCategory = splitContentType[0];
let ext = splitContentType[1];
if (contentTypeCategory != 'image') {
throw new Error(`Requested image failed: content type ${contentTypeCategory}`);
}
let contentLength = parseInt(response.headers['content-length']);
if (contentLength > MAX_SIZE) {
throw new Error(`Request image larger than max size: ${MAX_SIZE} (was ${contentLength})`);
}
log.write('origin', {
statusCode: response.statusCode,
contentType: contentTypeHeader,
contentLength: contentLength
});
return {
ext: ext
};
};
const getFile = function (uri, tempTracker, callback) {
let tempFile;
let fileStream;
// NOTE: Can't use async/await/promises with request module
// when streaming files to disk. The tradeoff is worth it because
// this uses less memory than storing the whole file in a buffer.
// Use callbacks and wrap with a promise.
let r = request.get({
uri: uri,
headers: {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36' //'imgsrv proxy (https://github.com/labaneilers/imgsrv)'
},
insecure: process.env.NODE_TLS_REJECT_UNAUTHORIZED == '0',
timeout: ORIGIN_TIMEOUT || 10000
});
r.on('error', ex => {
callback(ex);
})
.on('response', response => {
try {
let validation = validateResponse(response);
tempFile = tempTracker.create(validation.ext);
fileStream = fs.createWriteStream(tempFile, { encoding: 'binary' });
} catch (ex) {
callback(ex);
return;
}
fileStream.on('finish', () => {
callback(null, tempFile);
});
fileStream.on('err', ex => {
callback(ex);
});
let size = 0;
try {
r.on('data', (data) => {
size += data.length;
if (size > MAX_SIZE) {
res.abort(); // Abort the response (close and cleanup the stream)
throw new Error(`Request image larger than max size: ${MAX_SIZE} (was ${contentLength})`);
}
}).pipe(fileStream);
} catch (ex) {
callback(ex);
}
});
};
const sendFile = async function(response, filePath, mimeType) {
let sendFile = util.promisify(response.sendFile.bind(response));
await sendFile(
filePath,
{
maxAge: '1y',
headers: {
'content-type': mimeType,
'X-RequestID': log.requestId()
}
}
);
};
exports.getFile = util.promisify(getFile);
exports.sendFile = sendFile;
exports.maxSize = MAX_SIZE;
exports.originTimeout = ORIGIN_TIMEOUT;