-
Notifications
You must be signed in to change notification settings - Fork 7
/
resolver.js
121 lines (104 loc) · 3.89 KB
/
resolver.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
const path = require('path');
const fs = require('fs');
const config = require('./config');
const LogUtil = require('./log');
const BrowserUtils = require('./browser_utils');
const BaseService = require('./base_service');
const RESOURCE_ROOT = config.ConfigManager.getInstance().getValue(config.keys.KEY_IMAGE_DIR);
const EXT_MAP = {
"image/avif": ".avif",
"image/heic": '.heic',
"image/heif": '.heic',
"image/webp": ".webp",
};
const AVAILABLE_EXTENSIONS = config.ConfigManager.getInstance().getValue(config.keys.KEY_AVAILABLE_EXT);
/**
* Parse url and send image.
*/
class ImageResolver extends BaseService {
handleRequest(req, res) {
const url = req.url
const pathInfo = path.parse(url);
if (!pathInfo || !pathInfo.name || !pathInfo.ext || !AVAILABLE_EXTENSIONS.includes(pathInfo.ext)) {
LogUtil.error(`URL: ${req.url} is illegal.`);
res.sendStatus(404);
return;
}
const fullNormalFilePath = getImagePath(true, null, pathInfo);
const accepts = req.headers['accept'];
LogUtil.info(`Target File Path: ${fullNormalFilePath}`);
const supportedExts = getSupportedExtensions(accepts);
for (let index = 0; index < supportedExts.length; index++) {
const element = supportedExts[index];
const fullCompressedFilePath = getImagePath(true, element.ext, pathInfo);
if (fs.existsSync(fullCompressedFilePath)) {
LogUtil.info(`URL: ${req.url} Accepts: ${accepts} sends ${element.ext}`);
res.sendFile(fullCompressedFilePath, { headers: { 'Content-Type': element.mime } });
return;
}
}
const userAgent = req.headers['user-agent'];
if (userAgent && BrowserUtils.isSafari(userAgent) && BrowserUtils.isSupportHeic(userAgent)) {
const heicPath = getImagePath(true, ".heic", pathInfo);
if (fs.existsSync(heicPath)) {
LogUtil.info(`URL: ${req.url} Safari sends .heic`);
res.sendFile(heicPath, { headers: { 'Content-Type': "image/heic" } });
return;
}
}
// No accepts maybe not a browser, send normal image
if (fs.existsSync(fullNormalFilePath)) {
LogUtil.info(`URL: ${req.url} Accepts: ${accepts} sends normal`);
res.sendFile(fullNormalFilePath);
return;
} else {
LogUtil.error(`URL: ${req.url} Accepts: ${accepts} file not found, send nothing`);
res.sendStatus(404);
return;
}
}
getServiceName() {
return 'Image Resolver';
}
getServerPort() {
return config.ConfigManager.getInstance().getValue(config.keys.KEY_RESOLVE_SERVER_PORT);
}
}
const MAX_ACCEPT_LENGTH = 1000; // 定义 Accept 头的最大长度
function getSupportedExtensions(acceptHeader) {
const result = [];
if (!acceptHeader || acceptHeader.length === 0 || acceptHeader.length > MAX_ACCEPT_LENGTH) {
return result;
}
let start = 0;
let type = '';
for (let i = 0; i <= acceptHeader.length; i++) {
const char = acceptHeader[i];
if (char === ',' || i === acceptHeader.length) {
type = acceptHeader.slice(start, i).split(';')[0].trim();
if (EXT_MAP[type]) {
result.push({
ext: EXT_MAP[type],
mime: type,
});
}
start = i + 1;
}
}
return result;
}
/**
* Get the full image file path on the server.
*
* @param {boolean} isAbsolutePath
* @param {string} extension
* @param {ParsedPath} pathInfo
*/
function getImagePath(isAbsolutePath, extension, pathInfo) {
return path.join(
isAbsolutePath ? RESOURCE_ROOT : '',
pathInfo.dir,
pathInfo.name + pathInfo.ext + (extension ? extension : '')
);
};
module.exports = ImageResolver;