Clean commit: remove all heavy binaries and history
This commit is contained in:
168
server.js
Executable file
168
server.js
Executable file
@@ -0,0 +1,168 @@
|
||||
const http = require('http');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const url = require('url');
|
||||
|
||||
const PORT = 80;
|
||||
const ROOT = '/app';
|
||||
|
||||
function corsHeaders(extra = {}) {
|
||||
return {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, HEAD',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, X-Requested-With',
|
||||
...extra
|
||||
};
|
||||
}
|
||||
|
||||
function sendFile(req, res, filePath, contentType) {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
res.writeHead(404);
|
||||
return res.end('Not Found');
|
||||
}
|
||||
|
||||
const stat = fs.statSync(filePath);
|
||||
|
||||
res.writeHead(200, {
|
||||
...corsHeaders(),
|
||||
'Content-Type': contentType,
|
||||
'Content-Length': stat.size,
|
||||
'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0'
|
||||
});
|
||||
|
||||
if (req.method !== 'HEAD') {
|
||||
fs.createReadStream(filePath).pipe(res);
|
||||
} else {
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
|
||||
function contentType(file) {
|
||||
const ext = path.extname(file).toLowerCase();
|
||||
|
||||
const types = {
|
||||
'.html': 'text/html',
|
||||
'.css': 'text/css',
|
||||
'.js': 'application/javascript',
|
||||
'.json': 'application/json',
|
||||
'.svg': 'image/svg+xml',
|
||||
'.png': 'image/png',
|
||||
'.jpg': 'image/jpeg',
|
||||
'.jpeg': 'image/jpeg',
|
||||
'.gif': 'image/gif',
|
||||
'.ico': 'image/x-icon',
|
||||
'.woff': 'font/woff',
|
||||
'.woff2': 'font/woff2'
|
||||
};
|
||||
|
||||
return types[ext] || 'application/octet-stream';
|
||||
}
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
const parsed = url.parse(req.url);
|
||||
const pathname = parsed.pathname;
|
||||
|
||||
// CORS preflight
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.writeHead(200, corsHeaders());
|
||||
return res.end();
|
||||
}
|
||||
|
||||
// Get client IP
|
||||
if (pathname === '/getIP') {
|
||||
const ip =
|
||||
req.headers['x-forwarded-for']?.split(',')[0].trim() ||
|
||||
req.socket.remoteAddress ||
|
||||
'';
|
||||
|
||||
res.writeHead(200, {
|
||||
...corsHeaders(),
|
||||
'Content-Type': 'text/plain',
|
||||
'Cache-Control': 'no-store'
|
||||
});
|
||||
|
||||
return res.end(ip);
|
||||
}
|
||||
|
||||
// Upload endpoint
|
||||
if (pathname === '/upload') {
|
||||
if (req.method !== 'POST') {
|
||||
res.writeHead(200, corsHeaders());
|
||||
return res.end('OK');
|
||||
}
|
||||
|
||||
let bytes = 0;
|
||||
|
||||
req.on('data', chunk => {
|
||||
bytes += chunk.length;
|
||||
});
|
||||
|
||||
req.on('end', () => {
|
||||
res.writeHead(200, {
|
||||
...corsHeaders(),
|
||||
'Content-Type': 'text/plain',
|
||||
'Cache-Control': 'no-store'
|
||||
});
|
||||
|
||||
res.end('OK');
|
||||
});
|
||||
|
||||
req.on('error', () => {
|
||||
if (!res.headersSent) {
|
||||
res.writeHead(500, corsHeaders());
|
||||
}
|
||||
res.end('ERROR');
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Download endpoint
|
||||
if (pathname === '/downloading') {
|
||||
const file = path.join(ROOT, 'downloading');
|
||||
|
||||
if (!fs.existsSync(file)) {
|
||||
res.writeHead(404);
|
||||
return res.end('Not Found');
|
||||
}
|
||||
|
||||
const stat = fs.statSync(file);
|
||||
|
||||
res.writeHead(200, {
|
||||
...corsHeaders(),
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'Content-Length': stat.size,
|
||||
'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0',
|
||||
'Content-Disposition': 'inline'
|
||||
});
|
||||
|
||||
if (req.method !== 'HEAD') {
|
||||
fs.createReadStream(file).pipe(res);
|
||||
} else {
|
||||
res.end();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Static files
|
||||
let requested = pathname === '/' ? '/index.html' : pathname;
|
||||
const filePath = path.normalize(path.join(ROOT, requested));
|
||||
|
||||
// Prevent path traversal
|
||||
if (!filePath.startsWith(ROOT)) {
|
||||
res.writeHead(403);
|
||||
return res.end('Forbidden');
|
||||
}
|
||||
|
||||
if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
|
||||
res.writeHead(404);
|
||||
return res.end('Not Found');
|
||||
}
|
||||
|
||||
sendFile(req, res, filePath, contentType(filePath));
|
||||
});
|
||||
|
||||
server.listen(PORT, '0.0.0.0', () => {
|
||||
console.log(`Speedtest server listening on port ${PORT}`);
|
||||
});
|
||||
Reference in New Issue
Block a user