import http from 'node:http'; import { request as httpRequest } from 'node:http'; const listenHost = process.env.IMGPROXY_COMPAT_HOST || '10.10.0.2'; const listenPort = Number(process.env.IMGPROXY_COMPAT_PORT || 20081); const upstream = new URL(process.env.IMGPROXY_UPSTREAM || 'http://127.0.0.1:20082'); function convertPath(url) { if (url === '/health') return '/health'; const pathname = url.split('?')[0] || '/'; const match = pathname.match(/^(?:\/[^/]+)?\/unsafe\/(\d+)x(\d+)\/(\d+)\/([a-z0-9]+)\/(.+)$/i); if (!match) return pathname; const [, width, height, quality, format, encodedSource] = match; let source; source = encodedSource; for (let i = 0; i < 3; i += 1) { try { const decoded = decodeURIComponent(source); if (decoded === source) break; source = decoded; } catch { break; } } if (source.startsWith('local://') && !source.startsWith('local:///')) { source = `local:///${source.slice('local://'.length)}`; } return `/unsafe/rs:fit:${width}:${height}/q:${quality}/plain/${source}@${format}`; } const server = http.createServer((req, res) => { const upstreamPath = convertPath(req.url || '/'); const options = { hostname: upstream.hostname, port: upstream.port || 80, method: req.method, path: upstreamPath, headers: { ...req.headers, host: upstream.host, }, }; const proxy = httpRequest(options, (upstreamRes) => { res.writeHead(upstreamRes.statusCode || 502, upstreamRes.headers); upstreamRes.pipe(res); }); proxy.on('error', (err) => { res.writeHead(502, { 'content-type': 'text/plain' }); res.end(`imgproxy compat proxy error: ${err.message}`); }); req.pipe(proxy); }); server.listen(listenPort, listenHost, () => { console.log(`imgproxy compat proxy listening on ${listenHost}:${listenPort}, upstream ${upstream.href}`); });