forked from svrjs/svrjs
Update to SVR.JS 3.14.11
This commit is contained in:
parent
40f100db94
commit
67680fc97f
4 changed files with 256 additions and 274 deletions
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SVR.JS 3.14.10</title>
|
||||
<title>SVR.JS 3.14.11</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta charset="UTF-8" />
|
||||
<style>
|
||||
|
@ -12,7 +12,7 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to SVR.JS 3.14.10</h1>
|
||||
<h1>Welcome to SVR.JS 3.14.11</h1>
|
||||
<br/>
|
||||
<img src="/logo.png" style="width: 256px; max-width: 100%;" />
|
||||
<br/>
|
||||
|
@ -84,7 +84,9 @@
|
|||
</code>
|
||||
<p>Changes:</p>
|
||||
<ul style="display: inline-block; margin: 0;">
|
||||
<li>Disabled trailing slash removal for proxy requests.</li>
|
||||
<li>Added CVE-2024-27982 Node.JS vulnerability warning.</li>
|
||||
<li>Fixed bug with Brotli compression not working, when SVR.JS is running on Bun.</li>
|
||||
<li>Improved the performance of the server.</li>
|
||||
</ul>
|
||||
<p>
|
||||
<a href="/tests.html">Tests</a><br/>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SVR.JS 3.14.10 Licenses</title>
|
||||
<title>SVR.JS 3.14.11 Licenses</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta charset="UTF-8" />
|
||||
<style>
|
||||
|
@ -12,8 +12,8 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>SVR.JS 3.14.10 Licenses</h1>
|
||||
<h2>SVR.JS 3.14.10</h2>
|
||||
<h1>SVR.JS 3.14.11 Licenses</h1>
|
||||
<h2>SVR.JS 3.14.11</h2>
|
||||
<div style="display: inline-block; text-align: left; border-width: 2px; border-style: solid; border-color: gray; padding: 8px;">
|
||||
MIT License<br/>
|
||||
<br/>
|
||||
|
@ -37,7 +37,7 @@
|
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE<br/>
|
||||
SOFTWARE.<br/>
|
||||
</div>
|
||||
<h2>Packages used by SVR.JS 3.14.10</h2>
|
||||
<h2>Packages used by SVR.JS 3.14.11</h2>
|
||||
<div style="width: 100%; max-width: 1280px; margin: auto">
|
||||
<div style="width: 100%; background-color: #ccc; border: 1px solid green; text-align: left; margin: 10px 0;">
|
||||
<div style="float: right;">License: MIT</div>
|
||||
|
|
510
svr.js
510
svr.js
|
@ -69,7 +69,7 @@ function deleteFolderRecursive(path) {
|
|||
}
|
||||
|
||||
var os = require("os");
|
||||
var version = "3.14.10";
|
||||
var version = "3.14.11";
|
||||
var singlethreaded = false;
|
||||
|
||||
if (process.versions) process.versions.svrjs = version; // Inject SVR.JS into process.versions
|
||||
|
@ -3571,7 +3571,246 @@ if (!cluster.isPrimary) {
|
|||
}
|
||||
|
||||
function properDirectoryListingAndStaticFileServe() {
|
||||
if (stats.isDirectory()) {
|
||||
if (stats.isFile()) {
|
||||
var acceptEncoding = req.headers["accept-encoding"];
|
||||
if (!acceptEncoding) acceptEncoding = "";
|
||||
|
||||
var filelen = stats.size;
|
||||
|
||||
// ETag code
|
||||
var fileETag = undefined;
|
||||
if (configJSON.enableETag == undefined || configJSON.enableETag) {
|
||||
fileETag = generateETag(href, stats);
|
||||
// Check if the client's request matches the ETag value (If-None-Match)
|
||||
var clientETag = req.headers["if-none-match"];
|
||||
if (clientETag === fileETag) {
|
||||
var headers = getCustomHeaders();
|
||||
headers.ETag = clientETag;
|
||||
res.writeHead(304, http.STATUS_CODES[304], headers);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the client's request doesn't match the ETag value (If-Match)
|
||||
var ifMatchETag = req.headers["if-match"];
|
||||
if (ifMatchETag && ifMatchETag !== "*" && ifMatchETag !== fileETag) {
|
||||
var headers = getCustomHeaders();
|
||||
headers.ETag = clientETag;
|
||||
callServerError(412, headers);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to check if compression is allowed for the file
|
||||
function canCompress(path, list) {
|
||||
var canCompress = true;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (createRegex(list[i], true).test(path)) {
|
||||
canCompress = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return canCompress;
|
||||
}
|
||||
|
||||
var isCompressable = true;
|
||||
try {
|
||||
// Check for files not to compressed and compression enabling setting. Also check for browser quirks and adjust compression accordingly
|
||||
if(configJSON.enableCompression !== true || !canCompress(href, dontCompress)) {
|
||||
isCompressable = false; // Compression is disabled
|
||||
} else if (ext != "html" && ext != "htm" && ext != "xhtml" && ext != "xht" && ext != "shtml") {
|
||||
if (/^Mozilla\/4\.[0-9]+(( *\[[^)]*\] *| *)\([^)\]]*\))? *$/.test(req.headers["user-agent"]) && !(/https?:\/\/|[bB][oO][tT]|[sS][pP][iI][dD][eE][rR]|[sS][uU][rR][vV][eE][yY]|MSIE/.test(req.headers["user-agent"]))) {
|
||||
isCompressable = false; // Netscape 4.x doesn't handle compressed data properly outside of HTML documents.
|
||||
} else if (/^w3m\/[^ ]*$/.test(req.headers["user-agent"])) {
|
||||
isCompressable = false; // w3m doesn't handle compressed data properly outside of HTML documents.
|
||||
}
|
||||
} else {
|
||||
if (/^Mozilla\/4\.0[6-8](( *\[[^)]*\] *| *)\([^)\]]*\))? *$/.test(req.headers["user-agent"]) && !(/https?:\/\/|[bB][oO][tT]|[sS][pP][iI][dD][eE][rR]|[sS][uU][rR][vV][eE][yY]|MSIE/.test(req.headers["user-agent"]))) {
|
||||
isCompressable = false; // Netscape 4.06-4.08 doesn't handle compressed data properly.
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
callServerError(500, err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle partial content request
|
||||
if (ext != "html" && req.headers["range"]) {
|
||||
try {
|
||||
var rhd = getCustomHeaders();
|
||||
rhd["Accept-Ranges"] = "bytes";
|
||||
rhd["Content-Range"] = "bytes */" + filelen;
|
||||
var regexmatch = req.headers["range"].match(/bytes=([0-9]*)-([0-9]*)/);
|
||||
if (!regexmatch) {
|
||||
callServerError(416, rhd);
|
||||
} else {
|
||||
// Process the partial content request
|
||||
var beginOrig = regexmatch[1];
|
||||
var endOrig = regexmatch[2];
|
||||
var begin = 0;
|
||||
var end = filelen - 1;
|
||||
if (beginOrig == "" && endOrig == "") {
|
||||
callServerError(416, rhd);
|
||||
return;
|
||||
} else if (beginOrig == "") {
|
||||
begin = end - parseInt(endOrig) + 1;
|
||||
} else {
|
||||
begin = parseInt(beginOrig);
|
||||
if (endOrig != "") end = parseInt(endOrig);
|
||||
}
|
||||
if (begin > end || begin < 0 || begin > filelen - 1) {
|
||||
callServerError(416, rhd);
|
||||
return;
|
||||
}
|
||||
if (end > filelen - 1) end = filelen - 1;
|
||||
rhd["Content-Range"] = "bytes " + begin + "-" + end + "/" + filelen;
|
||||
rhd["Content-Length"] = end - begin + 1;
|
||||
if (!(mime.contentType(ext) == false) && ext != "") rhd["Content-Type"] = mime.contentType(ext);
|
||||
if (fileETag) rhd["ETag"] = fileETag;
|
||||
|
||||
if (req.method != "HEAD") {
|
||||
var readStream = fs.createReadStream(readFrom, {
|
||||
start: begin,
|
||||
end: end
|
||||
});
|
||||
readStream.on("error", function (err) {
|
||||
if (err.code == "ENOENT") {
|
||||
callServerError(404);
|
||||
serverconsole.errmessage("Resource not found.");
|
||||
} else if (err.code == "ENOTDIR") {
|
||||
callServerError(404); // Assume that file doesn't exist.
|
||||
serverconsole.errmessage("Resource not found.");
|
||||
} else if (err.code == "EACCES") {
|
||||
callServerError(403);
|
||||
serverconsole.errmessage("Access denied.");
|
||||
} else if (err.code == "ENAMETOOLONG") {
|
||||
callServerError(414);
|
||||
} else if (err.code == "EMFILE") {
|
||||
callServerError(503);
|
||||
} else if (err.code == "ELOOP") {
|
||||
callServerError(508); // The symbolic link loop is detected during file system operations.
|
||||
serverconsole.errmessage("Symbolic link loop detected.");
|
||||
} else {
|
||||
callServerError(500, err);
|
||||
}
|
||||
}).on("open", function () {
|
||||
try {
|
||||
res.writeHead(206, http.STATUS_CODES[206], rhd);
|
||||
readStream.pipe(res);
|
||||
serverconsole.resmessage("Client successfully received content.");
|
||||
} catch (err) {
|
||||
callServerError(500, err);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.writeHead(206, http.STATUS_CODES[206], rhd);
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
callServerError(500, err);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
var hdhds = getCustomHeaders();
|
||||
var brNotImplementedBun = false;
|
||||
// Bun 1.1 has definition for zlib.createBrotliCompress, but throws an error while invoking the function.
|
||||
if (process.isBun && configJSON.enableCompression === true) {
|
||||
try {
|
||||
zlib.createBrotliCompress();
|
||||
} catch (err) {
|
||||
brNotImplementedBun = true;
|
||||
}
|
||||
}
|
||||
if (configJSON.enableCompression === true && ext != "br" && filelen > 256 && isCompressable && !brNotImplementedBun && zlib.createBrotliCompress && acceptEncoding.match(/\bbr\b/)) {
|
||||
hdhds["Content-Encoding"] = "br";
|
||||
} else if (configJSON.enableCompression === true && ext != "zip" && filelen > 256 && isCompressable && acceptEncoding.match(/\bdeflate\b/)) {
|
||||
hdhds["Content-Encoding"] = "deflate";
|
||||
} else if (configJSON.enableCompression === true && ext != "gz" && filelen > 256 && isCompressable && acceptEncoding.match(/\bgzip\b/)) {
|
||||
hdhds["Content-Encoding"] = "gzip";
|
||||
} else {
|
||||
if (ext == "html") {
|
||||
hdhds["Content-Length"] = head.length + filelen + foot.length;
|
||||
} else {
|
||||
hdhds["Content-Length"] = filelen;
|
||||
}
|
||||
}
|
||||
if (ext != "html") hdhds["Accept-Ranges"] = "bytes";
|
||||
delete hdhds["Content-Type"];
|
||||
if (!(mime.contentType(ext) == false) && ext != "") hdhds["Content-Type"] = mime.contentType(ext);
|
||||
if (fileETag) hdhds["ETag"] = fileETag;
|
||||
|
||||
if (req.method != "HEAD") {
|
||||
var readStream = fs.createReadStream(readFrom);
|
||||
readStream.on("error", function (err) {
|
||||
if (err.code == "ENOENT") {
|
||||
callServerError(404);
|
||||
serverconsole.errmessage("Resource not found.");
|
||||
} else if (err.code == "ENOTDIR") {
|
||||
callServerError(404); // Assume that file doesn't exist.
|
||||
serverconsole.errmessage("Resource not found.");
|
||||
} else if (err.code == "EACCES") {
|
||||
callServerError(403);
|
||||
serverconsole.errmessage("Access denied.");
|
||||
} else if (err.code == "ENAMETOOLONG") {
|
||||
callServerError(414);
|
||||
} else if (err.code == "EMFILE") {
|
||||
callServerError(503);
|
||||
} else if (err.code == "ELOOP") {
|
||||
callServerError(508); // The symbolic link loop is detected during file system operations.
|
||||
serverconsole.errmessage("Symbolic link loop detected.");
|
||||
} else {
|
||||
callServerError(500, err);
|
||||
}
|
||||
}).on("open", function () {
|
||||
try {
|
||||
var resStream = {};
|
||||
if (ext != "br" && filelen > 256 && isCompressable && !brNotImplementedBun && zlib.createBrotliCompress && acceptEncoding.match(/\bbr\b/)) {
|
||||
resStream = zlib.createBrotliCompress();
|
||||
resStream.pipe(res);
|
||||
} else if (ext != "zip" && filelen > 256 && isCompressable && acceptEncoding.match(/\bdeflate\b/)) {
|
||||
resStream = zlib.createDeflateRaw();
|
||||
resStream.pipe(res);
|
||||
} else if (ext != "gz" && filelen > 256 && isCompressable && acceptEncoding.match(/\bgzip\b/)) {
|
||||
resStream = zlib.createGzip();
|
||||
resStream.pipe(res);
|
||||
} else {
|
||||
resStream = res;
|
||||
}
|
||||
if (ext == "html") {
|
||||
function afterWriteCallback() {
|
||||
readStream.on("end", function () {
|
||||
resStream.end(foot);
|
||||
});
|
||||
readStream.pipe(resStream, {
|
||||
end: false
|
||||
});
|
||||
}
|
||||
res.writeHead(200, http.STATUS_CODES[200], hdhds);
|
||||
if (!resStream.write(head)) {
|
||||
resStream.on("drain", afterWriteCallback);
|
||||
} else {
|
||||
process.nextTick(afterWriteCallback);
|
||||
}
|
||||
} else {
|
||||
res.writeHead(200, http.STATUS_CODES[200], hdhds);
|
||||
readStream.pipe(resStream);
|
||||
}
|
||||
serverconsole.resmessage("Client successfully received content.");
|
||||
} catch (err) {
|
||||
callServerError(500, err);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.writeHead(200, http.STATUS_CODES[200], hdhds);
|
||||
res.end();
|
||||
serverconsole.resmessage("Client successfully received content.");
|
||||
}
|
||||
} catch (err) {
|
||||
callServerError(500, err);
|
||||
}
|
||||
}
|
||||
} else if (stats.isDirectory()) {
|
||||
// Check if directory listing is enabled in the configuration
|
||||
if (checkForEnabledDirectoryListing(req.headers.host, req.socket ? req.socket.localAddress : undefined)) {
|
||||
var customHeaders = getCustomHeaders();
|
||||
|
@ -3792,270 +4031,10 @@ if (!cluster.isPrimary) {
|
|||
callServerError(403);
|
||||
serverconsole.errmessage("Directory listing is disabled.");
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
var acceptEncoding = req.headers["accept-encoding"];
|
||||
if (!acceptEncoding) acceptEncoding = "";
|
||||
|
||||
// Check if the requested file exists and handle errors
|
||||
fs.stat(readFrom, function (err, stats) {
|
||||
if (err) {
|
||||
if (err.code == "ENOENT") {
|
||||
callServerError(404);
|
||||
serverconsole.errmessage("Resource not found.");
|
||||
} else if (err.code == "ENOTDIR") {
|
||||
callServerError(404); // Assume that file doesn't exist.
|
||||
serverconsole.errmessage("Resource not found.");
|
||||
} else if (err.code == "EACCES") {
|
||||
callServerError(403);
|
||||
serverconsole.errmessage("Access denied.");
|
||||
} else if (err.code == "ENAMETOOLONG") {
|
||||
callServerError(414);
|
||||
} else if (err.code == "EMFILE") {
|
||||
callServerError(503);
|
||||
} else if (err.code == "ELOOP") {
|
||||
callServerError(508); // The symbolic link loop is detected during file system operations.
|
||||
serverconsole.errmessage("Symbolic link loop detected.");
|
||||
} else {
|
||||
callServerError(500, err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the requested resource is a file
|
||||
if (stats.isDirectory()) {
|
||||
callServerError(501);
|
||||
serverconsole.errmessage("SVR.JS expected file but got directory instead.");
|
||||
return;
|
||||
} else if (!stats.isFile()) {
|
||||
callServerError(501);
|
||||
serverconsole.errmessage("SVR.JS doesn't support block devices, character devices, FIFOs nor sockets.");
|
||||
return;
|
||||
}
|
||||
|
||||
var filelen = stats.size;
|
||||
|
||||
// ETag code
|
||||
var fileETag = undefined;
|
||||
if (configJSON.enableETag == undefined || configJSON.enableETag) {
|
||||
fileETag = generateETag(href, stats);
|
||||
// Check if the client's request matches the ETag value (If-None-Match)
|
||||
var clientETag = req.headers["if-none-match"];
|
||||
if (clientETag === fileETag) {
|
||||
var headers = getCustomHeaders();
|
||||
headers.ETag = clientETag;
|
||||
res.writeHead(304, http.STATUS_CODES[304], headers);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the client's request doesn't match the ETag value (If-Match)
|
||||
var ifMatchETag = req.headers["if-match"];
|
||||
if (ifMatchETag && ifMatchETag !== "*" && ifMatchETag !== fileETag) {
|
||||
var headers = getCustomHeaders();
|
||||
headers.ETag = clientETag;
|
||||
callServerError(412, headers);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to check if compression is allowed for the file
|
||||
function canCompress(path, list) {
|
||||
var canCompress = true;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (createRegex(list[i], true).test(path)) {
|
||||
canCompress = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return canCompress;
|
||||
}
|
||||
|
||||
var isCompressable = true;
|
||||
try {
|
||||
isCompressable = canCompress(href, dontCompress);
|
||||
} catch (err) {
|
||||
callServerError(500, err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for browser quirks and adjust compression accordingly
|
||||
if (ext != "html" && ext != "htm" && ext != "xhtml" && ext != "xht" && ext != "shtml" && /^Mozilla\/4\.[0-9]+(( *\[[^)]*\] *| *)\([^)\]]*\))? *$/.test(req.headers["user-agent"]) && !(/https?:\/\/|[bB][oO][tT]|[sS][pP][iI][dD][eE][rR]|[sS][uU][rR][vV][eE][yY]|MSIE/.test(req.headers["user-agent"]))) {
|
||||
isCompressable = false; // Netscape 4.x doesn't handle compressed data properly outside of HTML documents.
|
||||
} else if (/^Mozilla\/4\.0[6-8](( *\[[^)]*\] *| *)\([^)\]]*\))? *$/.test(req.headers["user-agent"]) && !(/https?:\/\/|[bB][oO][tT]|[sS][pP][iI][dD][eE][rR]|[sS][uU][rR][vV][eE][yY]|MSIE/.test(req.headers["user-agent"]))) {
|
||||
isCompressable = false; // Netscape 4.06-4.08 doesn't handle compressed data properly.
|
||||
} else if (ext != "html" && ext != "htm" && ext != "xhtml" && ext != "xht" && ext != "shtml" && /^w3m\/[^ ]*$/.test(req.headers["user-agent"])) {
|
||||
isCompressable = false; // w3m doesn't handle compressed data properly outside of HTML documents.
|
||||
}
|
||||
|
||||
// Handle partial content request
|
||||
if (ext != "html" && req.headers["range"]) {
|
||||
try {
|
||||
var rhd = getCustomHeaders();
|
||||
rhd["Accept-Ranges"] = "bytes";
|
||||
rhd["Content-Range"] = "bytes */" + filelen;
|
||||
var regexmatch = req.headers["range"].match(/bytes=([0-9]*)-([0-9]*)/);
|
||||
if (!regexmatch) {
|
||||
callServerError(416, rhd);
|
||||
} else {
|
||||
// Process the partial content request
|
||||
var beginOrig = regexmatch[1];
|
||||
var endOrig = regexmatch[2];
|
||||
var begin = 0;
|
||||
var end = filelen - 1;
|
||||
if (beginOrig == "" && endOrig == "") {
|
||||
callServerError(416, rhd);
|
||||
return;
|
||||
} else if (beginOrig == "") {
|
||||
begin = end - parseInt(endOrig) + 1;
|
||||
} else {
|
||||
begin = parseInt(beginOrig);
|
||||
if (endOrig != "") end = parseInt(endOrig);
|
||||
}
|
||||
if (begin > end || begin < 0 || begin > filelen - 1) {
|
||||
callServerError(416, rhd);
|
||||
return;
|
||||
}
|
||||
if (end > filelen - 1) end = filelen - 1;
|
||||
rhd["Content-Range"] = "bytes " + begin + "-" + end + "/" + filelen;
|
||||
rhd["Content-Length"] = end - begin + 1;
|
||||
if (!(mime.contentType(ext) == false) && ext != "") rhd["Content-Type"] = mime.contentType(ext);
|
||||
if (fileETag) rhd["ETag"] = fileETag;
|
||||
|
||||
if (req.method != "HEAD") {
|
||||
var readStream = fs.createReadStream(readFrom, {
|
||||
start: begin,
|
||||
end: end
|
||||
});
|
||||
readStream.on("error", function (err) {
|
||||
if (err.code == "ENOENT") {
|
||||
callServerError(404);
|
||||
serverconsole.errmessage("Resource not found.");
|
||||
} else if (err.code == "ENOTDIR") {
|
||||
callServerError(404); // Assume that file doesn't exist.
|
||||
serverconsole.errmessage("Resource not found.");
|
||||
} else if (err.code == "EACCES") {
|
||||
callServerError(403);
|
||||
serverconsole.errmessage("Access denied.");
|
||||
} else if (err.code == "ENAMETOOLONG") {
|
||||
callServerError(414);
|
||||
} else if (err.code == "EMFILE") {
|
||||
callServerError(503);
|
||||
} else if (err.code == "ELOOP") {
|
||||
callServerError(508); // The symbolic link loop is detected during file system operations.
|
||||
serverconsole.errmessage("Symbolic link loop detected.");
|
||||
} else {
|
||||
callServerError(500, err);
|
||||
}
|
||||
}).on("open", function () {
|
||||
try {
|
||||
res.writeHead(206, http.STATUS_CODES[206], rhd);
|
||||
readStream.pipe(res);
|
||||
serverconsole.resmessage("Client successfully received content.");
|
||||
} catch (err) {
|
||||
callServerError(500, err);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.writeHead(206, http.STATUS_CODES[206], rhd);
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
callServerError(500, err);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
var hdhds = getCustomHeaders();
|
||||
if (configJSON.enableCompression === true && ext != "br" && filelen > 256 && isCompressable && zlib.createBrotliCompress && acceptEncoding.match(/\bbr\b/)) {
|
||||
hdhds["Content-Encoding"] = "br";
|
||||
} else if (configJSON.enableCompression === true && ext != "zip" && filelen > 256 && isCompressable && acceptEncoding.match(/\bdeflate\b/)) {
|
||||
hdhds["Content-Encoding"] = "deflate";
|
||||
} else if (configJSON.enableCompression === true && ext != "gz" && filelen > 256 && isCompressable && acceptEncoding.match(/\bgzip\b/)) {
|
||||
hdhds["Content-Encoding"] = "gzip";
|
||||
} else {
|
||||
if (ext == "html") {
|
||||
hdhds["Content-Length"] = head.length + filelen + foot.length;
|
||||
} else {
|
||||
hdhds["Content-Length"] = filelen;
|
||||
}
|
||||
}
|
||||
if (ext != "html") hdhds["Accept-Ranges"] = "bytes";
|
||||
delete hdhds["Content-Type"];
|
||||
if (!(mime.contentType(ext) == false) && ext != "") hdhds["Content-Type"] = mime.contentType(ext);
|
||||
if (fileETag) hdhds["ETag"] = fileETag;
|
||||
|
||||
if (req.method != "HEAD") {
|
||||
var readStream = fs.createReadStream(readFrom);
|
||||
readStream.on("error", function (err) {
|
||||
if (err.code == "ENOENT") {
|
||||
callServerError(404);
|
||||
serverconsole.errmessage("Resource not found.");
|
||||
} else if (err.code == "ENOTDIR") {
|
||||
callServerError(404); // Assume that file doesn't exist.
|
||||
serverconsole.errmessage("Resource not found.");
|
||||
} else if (err.code == "EACCES") {
|
||||
callServerError(403);
|
||||
serverconsole.errmessage("Access denied.");
|
||||
} else if (err.code == "ENAMETOOLONG") {
|
||||
callServerError(414);
|
||||
} else if (err.code == "EMFILE") {
|
||||
callServerError(503);
|
||||
} else if (err.code == "ELOOP") {
|
||||
callServerError(508); // The symbolic link loop is detected during file system operations.
|
||||
serverconsole.errmessage("Symbolic link loop detected.");
|
||||
} else {
|
||||
callServerError(500, err);
|
||||
}
|
||||
}).on("open", function () {
|
||||
try {
|
||||
res.writeHead(200, http.STATUS_CODES[200], hdhds);
|
||||
var resStream = {};
|
||||
if (configJSON.enableCompression === true && ext != "br" && filelen > 256 && isCompressable && zlib.createBrotliCompress && acceptEncoding.match(/\bbr\b/)) {
|
||||
resStream = zlib.createBrotliCompress();
|
||||
resStream.pipe(res);
|
||||
} else if (configJSON.enableCompression === true && ext != "zip" && filelen > 256 && isCompressable && acceptEncoding.match(/\bdeflate\b/)) {
|
||||
resStream = zlib.createDeflateRaw();
|
||||
resStream.pipe(res);
|
||||
} else if (configJSON.enableCompression === true && ext != "gz" && filelen > 256 && isCompressable && acceptEncoding.match(/\bgzip\b/)) {
|
||||
resStream = zlib.createGzip();
|
||||
resStream.pipe(res);
|
||||
} else {
|
||||
resStream = res;
|
||||
}
|
||||
if (ext == "html") {
|
||||
function afterWriteCallback() {
|
||||
readStream.on("end", function () {
|
||||
resStream.end(foot);
|
||||
});
|
||||
readStream.pipe(resStream, {
|
||||
end: false
|
||||
});
|
||||
}
|
||||
if (!resStream.write(head)) {
|
||||
resStream.on("drain", afterWriteCallback);
|
||||
} else {
|
||||
process.nextTick(afterWriteCallback);
|
||||
}
|
||||
} else {
|
||||
readStream.pipe(resStream);
|
||||
}
|
||||
serverconsole.resmessage("Client successfully received content.");
|
||||
} catch (err) {
|
||||
callServerError(500, err);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
res.writeHead(200, http.STATUS_CODES[200], hdhds);
|
||||
res.end();
|
||||
serverconsole.resmessage("Client successfully received content.");
|
||||
}
|
||||
} catch (err) {
|
||||
callServerError(500, err);
|
||||
}
|
||||
}
|
||||
});
|
||||
callServerError(501);
|
||||
serverconsole.errmessage("SVR.JS doesn't support block devices, character devices, FIFOs nor sockets.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -4935,6 +4914,7 @@ function start(init) {
|
|||
if (crypto.__disabled__ !== undefined) serverconsole.locwarnmessage("Your Node.JS version doesn't have crypto support! The 'crypto' module is essential for providing cryptographic functionality in Node.JS. Without crypto support, certain security features may be unavailable, and some functionality may not work as expected. It's recommended to use a Node.JS version that includes crypto support to ensure the security and proper functioning of your server.");
|
||||
if (crypto.__disabled__ === undefined && !crypto.scrypt) serverconsole.locwarnmessage("Your JavaScript runtime doesn't have native scrypt support. HTTP authentication involving scrypt hashes will not work.");
|
||||
if (!process.isBun && /^v(?:[0-9]\.|1[0-7]\.|18\.(?:[0-9]|1[0-8])\.|18\.19\.0|20\.(?:[0-9]|10)\.|20\.11\.0|21\.[0-5]\.|21\.6\.0|21\.6\.1(?![0-9]))/.test(process.version)) serverconsole.locwarnmessage("Your Node.JS version is vulnerable to HTTP server DoS (CVE-2024-22019).");
|
||||
if (!process.isBun && /^v(?:[0-9]\.|1[0-7]\.|18\.(?:1?[0-9])\.|18\.20\.0|20\.(?:[0-9]|1[01])\.|20\.12\.0|21\.[0-6]\.|21\.7\.0|21\.7\.1(?![0-9]))/.test(process.version)) serverconsole.locwarnmessage("Your Node.JS version is vulnerable to HTTP server request smuggling (CVE-2024-27982).");
|
||||
if (process.getuid && process.getuid() == 0) serverconsole.locwarnmessage("You're running SVR.JS as root. It's recommended to run SVR.JS as an non-root user. Running SVR.JS as root may increase the risks of OS command execution vulnerabilities.");
|
||||
if (secure && process.versions && process.versions.openssl && process.versions.openssl.substr(0, 2) == "1.") {
|
||||
if (new Date() > new Date("11 September 2023")) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SVR.JS 3.14.10 Tests</title>
|
||||
<title>SVR.JS 3.14.11 Tests</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta charset="UTF-8" />
|
||||
<style>
|
||||
|
@ -12,7 +12,7 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>SVR.JS 3.14.10 Tests</h1>
|
||||
<h1>SVR.JS 3.14.11 Tests</h1>
|
||||
<h2>Directory (without trailing slash)</h2>
|
||||
<iframe src="/testdir" width="50%" height="300px"></iframe>
|
||||
<h2>Directory (with query)</h2>
|
||||
|
|
Reference in a new issue