forked from svrjs/svrjs
Remove redundant fs.stat in static file serving function
This commit is contained in:
parent
e584cce286
commit
80943bf695
1 changed files with 179 additions and 208 deletions
387
svr.js
387
svr.js
|
@ -3799,195 +3799,107 @@ if (!cluster.isPrimary) {
|
||||||
if (!acceptEncoding) acceptEncoding = "";
|
if (!acceptEncoding) acceptEncoding = "";
|
||||||
|
|
||||||
// Check if the requested file exists and handle errors
|
// Check if the requested file exists and handle errors
|
||||||
fs.stat(readFrom, function (err, stats) {
|
// Check if the requested resource is a file
|
||||||
if (err) {
|
if (!stats.isFile()) {
|
||||||
if (err.code == "ENOENT") {
|
callServerError(501);
|
||||||
callServerError(404);
|
serverconsole.errmessage("SVR.JS doesn't support block devices, character devices, FIFOs nor sockets.");
|
||||||
serverconsole.errmessage("Resource not found.");
|
return;
|
||||||
} else if (err.code == "ENOTDIR") {
|
}
|
||||||
callServerError(404); // Assume that file doesn't exist.
|
|
||||||
serverconsole.errmessage("Resource not found.");
|
var filelen = stats.size;
|
||||||
} else if (err.code == "EACCES") {
|
|
||||||
callServerError(403);
|
// ETag code
|
||||||
serverconsole.errmessage("Access denied.");
|
var fileETag = undefined;
|
||||||
} else if (err.code == "ENAMETOOLONG") {
|
if (configJSON.enableETag == undefined || configJSON.enableETag) {
|
||||||
callServerError(414);
|
fileETag = generateETag(href, stats);
|
||||||
} else if (err.code == "EMFILE") {
|
// Check if the client's request matches the ETag value (If-None-Match)
|
||||||
callServerError(503);
|
var clientETag = req.headers["if-none-match"];
|
||||||
} else if (err.code == "ELOOP") {
|
if (clientETag === fileETag) {
|
||||||
callServerError(508); // The symbolic link loop is detected during file system operations.
|
var headers = getCustomHeaders();
|
||||||
serverconsole.errmessage("Symbolic link loop detected.");
|
headers.ETag = clientETag;
|
||||||
} else {
|
res.writeHead(304, http.STATUS_CODES[304], headers);
|
||||||
callServerError(500, err);
|
res.end();
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the requested resource is a file
|
// Check if the client's request doesn't match the ETag value (If-Match)
|
||||||
if (stats.isDirectory()) {
|
var ifMatchETag = req.headers["if-match"];
|
||||||
callServerError(501);
|
if (ifMatchETag && ifMatchETag !== "*" && ifMatchETag !== fileETag) {
|
||||||
serverconsole.errmessage("SVR.JS expected file but got directory instead.");
|
var headers = getCustomHeaders();
|
||||||
return;
|
headers.ETag = clientETag;
|
||||||
} else if (!stats.isFile()) {
|
callServerError(412, headers);
|
||||||
callServerError(501);
|
|
||||||
serverconsole.errmessage("SVR.JS doesn't support block devices, character devices, FIFOs nor sockets.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var filelen = stats.size;
|
// Helper function to check if compression is allowed for the file
|
||||||
|
function canCompress(path, list) {
|
||||||
// ETag code
|
var canCompress = true;
|
||||||
var fileETag = undefined;
|
for (var i = 0; i < list.length; i++) {
|
||||||
if (configJSON.enableETag == undefined || configJSON.enableETag) {
|
if (createRegex(list[i], true).test(path)) {
|
||||||
fileETag = generateETag(href, stats);
|
canCompress = false;
|
||||||
// Check if the client's request matches the ETag value (If-None-Match)
|
break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return canCompress;
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to check if compression is allowed for the file
|
var isCompressable = true;
|
||||||
function canCompress(path, list) {
|
try {
|
||||||
var canCompress = true;
|
isCompressable = canCompress(href, dontCompress);
|
||||||
for (var i = 0; i < list.length; i++) {
|
} catch (err) {
|
||||||
if (createRegex(list[i], true).test(path)) {
|
callServerError(500, err);
|
||||||
canCompress = false;
|
return;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return canCompress;
|
|
||||||
}
|
|
||||||
|
|
||||||
var isCompressable = true;
|
// 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 {
|
try {
|
||||||
isCompressable = canCompress(href, dontCompress);
|
var rhd = getCustomHeaders();
|
||||||
} catch (err) {
|
rhd["Accept-Ranges"] = "bytes";
|
||||||
callServerError(500, err);
|
rhd["Content-Range"] = "bytes */" + filelen;
|
||||||
return;
|
var regexmatch = req.headers["range"].match(/bytes=([0-9]*)-([0-9]*)/);
|
||||||
}
|
if (!regexmatch) {
|
||||||
|
callServerError(416, rhd);
|
||||||
// Check for browser quirks and adjust compression accordingly
|
} else {
|
||||||
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"]))) {
|
// Process the partial content request
|
||||||
isCompressable = false; // Netscape 4.x doesn't handle compressed data properly outside of HTML documents.
|
var beginOrig = regexmatch[1];
|
||||||
} 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"]))) {
|
var endOrig = regexmatch[2];
|
||||||
isCompressable = false; // Netscape 4.06-4.08 doesn't handle compressed data properly.
|
var begin = 0;
|
||||||
} else if (ext != "html" && ext != "htm" && ext != "xhtml" && ext != "xht" && ext != "shtml" && /^w3m\/[^ ]*$/.test(req.headers["user-agent"])) {
|
var end = filelen - 1;
|
||||||
isCompressable = false; // w3m doesn't handle compressed data properly outside of HTML documents.
|
if (beginOrig == "" && endOrig == "") {
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
callServerError(416, rhd);
|
||||||
|
return;
|
||||||
|
} else if (beginOrig == "") {
|
||||||
|
begin = end - parseInt(endOrig) + 1;
|
||||||
} else {
|
} else {
|
||||||
// Process the partial content request
|
begin = parseInt(beginOrig);
|
||||||
var beginOrig = regexmatch[1];
|
if (endOrig != "") end = parseInt(endOrig);
|
||||||
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) {
|
if (begin > end || begin < 0 || begin > filelen - 1) {
|
||||||
callServerError(500, err);
|
callServerError(416, rhd);
|
||||||
}
|
return;
|
||||||
} 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";
|
if (end > filelen - 1) end = filelen - 1;
|
||||||
delete hdhds["Content-Type"];
|
rhd["Content-Range"] = "bytes " + begin + "-" + end + "/" + filelen;
|
||||||
if (!(mime.contentType(ext) == false) && ext != "") hdhds["Content-Type"] = mime.contentType(ext);
|
rhd["Content-Length"] = end - begin + 1;
|
||||||
if (fileETag) hdhds["ETag"] = fileETag;
|
if (!(mime.contentType(ext) == false) && ext != "") rhd["Content-Type"] = mime.contentType(ext);
|
||||||
|
if (fileETag) rhd["ETag"] = fileETag;
|
||||||
|
|
||||||
if (req.method != "HEAD") {
|
if (req.method != "HEAD") {
|
||||||
var readStream = fs.createReadStream(readFrom);
|
var readStream = fs.createReadStream(readFrom, {
|
||||||
|
start: begin,
|
||||||
|
end: end
|
||||||
|
});
|
||||||
readStream.on("error", function (err) {
|
readStream.on("error", function (err) {
|
||||||
if (err.code == "ENOENT") {
|
if (err.code == "ENOENT") {
|
||||||
callServerError(404);
|
callServerError(404);
|
||||||
|
@ -4010,52 +3922,111 @@ if (!cluster.isPrimary) {
|
||||||
}
|
}
|
||||||
}).on("open", function () {
|
}).on("open", function () {
|
||||||
try {
|
try {
|
||||||
res.writeHead(200, http.STATUS_CODES[200], hdhds);
|
res.writeHead(206, http.STATUS_CODES[206], rhd);
|
||||||
var resStream = {};
|
readStream.pipe(res);
|
||||||
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.");
|
serverconsole.resmessage("Client successfully received content.");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
callServerError(500, err);
|
callServerError(500, err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.writeHead(200, http.STATUS_CODES[200], hdhds);
|
res.writeHead(206, http.STATUS_CODES[206], rhd);
|
||||||
res.end();
|
res.end();
|
||||||
serverconsole.resmessage("Client successfully received content.");
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
callServerError(500, err);
|
|
||||||
}
|
}
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Reference in a new issue