Statuscodes and Cleanups

- Removed caching_dump.json
- Added cleanup function that is called on
  process exit.
- .cache directory will be deleted on cleanup
- The server can now respond with error 403 or 404 depending on the 
request
- Changed exit in testing mode to 10 seconds
pull/7/head
Julius Riegel 6 years ago
parent 977782a67b
commit 0f4c0de2d8

@ -1,4 +1,8 @@
{ {
"errors": {
"403": "./glob/errors/403.html",
"404": "./glob/errors/404.html"
},
"routes": { "routes": {
".html": { ".html": {
"path": "./res/html/", "path": "./res/html/",
@ -36,7 +40,7 @@
"path": "./res/fonts/", "path": "./res/fonts/",
"mime": "font/opentype" "mime": "font/opentype"
}, },
".sass" :{ ".sass": {
"path": "./res/sass", "path": "./res/sass",
"mime": "style/css" "mime": "style/css"
} }

@ -0,0 +1,12 @@
<html>
<head>
<title> 403 - Forbidden </title>
</head>
<body>
<div class="spacer">
</div>
<h1> 403 - Forbidden </h1>
<p> You are not allowed to access the requested ressource. </p>
<code> 403 </code>
</body>
</html>

@ -0,0 +1,12 @@
<html>
<head>
<title> 404 - Not Found </title>
</head>
<body>
<div class="spacer">
</div>
<h1> 404 - Not Found </h1>
<p> The requested ressouce could not be found. </p>
<code> 404 </code>
</body>
</html>

@ -1,8 +0,0 @@
<html>
<head>
<title> Home </title>
</head>
<body>
<h1> Welcome to the server </h1>
</body>
</html>

@ -1,11 +1,8 @@
const fs = require("fs"), const fs = require("fs"),
path = require("path"), path = require("path"),
config_path = "./config/caching_dump.json",
cache_dump = JSON.parse(fs.readFileSync(config_path)),
cache_dir = "./.cache"; cache_dir = "./.cache";
let cache = {}; let cache = {};
let logger = require("winston"); let logger = require("winston");
if (cache_dump != null && cache_dump["last"] != null) cache = cache_dump["last"]; // read the data from the file dump
/** /**
* Sets the logger for logging * Sets the logger for logging
@ -89,10 +86,26 @@ exports.isCached = function (filename) {
} }
/** /**
* A function that dumps the config into the config file after appending the cache to it. * A function that clears the ./.cache directory
*/ */
exports.cleanup = function () { exports.cleanup = function () {
logger.verbose("Dumping cache into cache_dump file"); deleteFolder(cache_dir); // delte the cache folder and it's contents
cache_dump["last"] = cache; // append the cache to the dump object };
fs.writeFileSync(config_path, JSON.stringify(cache_dump)); // write the dump data to the file
/**
* Deletes a folder with it's contents recursive
* @param {string} p the path to the folder
*/
var deleteFolder = function(p) {
if( fs.existsSync(p) ) {
fs.readdirSync(p).forEach(function(file,index){ // get the contents of the directory
var curPath = path.join(p, file); // create path by joining
if(fs.lstatSync(curPath).isDirectory()) { // recurse
deleteFolder(curPath); // call recursive
} else { // delete file
fs.unlinkSync(curPath); // delete file
}
});
fs.rmdirSync(p); // delete directory
}
}; };

@ -28,7 +28,6 @@ exports.setLogger = function (newLogger) {
* @return {String} The data that should be send * @return {String} The data that should be send
*/ */
exports.getProcessed = function (filename) { exports.getProcessed = function (filename) {
try {
logger.debug("Processing File %s", filename); logger.debug("Processing File %s", filename);
let extension = utils.getExtension(filename); // use the utils function to get the files extension let extension = utils.getExtension(filename); // use the utils function to get the files extension
let data = null; let data = null;
@ -52,10 +51,6 @@ exports.getProcessed = function (filename) {
caching.cache(filename, data); // cache the file for faster access next time caching.cache(filename, data); // cache the file for faster access next time
logger.debug("Cached file %s", filename); logger.debug("Cached file %s", filename);
return data; // return the data return data; // return the data
} catch (error) {
logger.error(error);
return "Processing Error";
}
}; };
/** /**

@ -2,6 +2,8 @@
* A Series of utility functions * A Series of utility functions
*/ */
function noOp() {};
/** /**
* returns the extension of a file for the given filename. * returns the extension of a file for the given filename.
* @param {String} filename The name of the file. * @param {String} filename The name of the file.
@ -18,3 +20,35 @@ exports.getExtension = function (filename) {
return null; return null;
} }
} }
/**
* lets you define a cleanup for your program exit
* @param {Function} callback the cleanup function
* @constructor
* @author CanyonCasa & Pier-Luc Gendreau on StackOverflow
*/
exports.Cleanup = function Cleanup(callback) {
// attach user callback to the process event emitter
// if no callback, it will still exit gracefully on Ctrl-C
callback = callback || noOp;
process.on('cleanup',callback);
// do app specific cleaning before exiting
process.on('exit', function () {
process.emit('cleanup');
});
// catch ctrl+c event and exit normally
process.on('SIGINT', function () {
console.log('Ctrl-C...');
process.exit(2);
});
//catch uncaught exceptions, trace, then exit normally
process.on('uncaughtException', function(e) {
console.log('Uncaught Exception...');
console.log(e.stack);
process.exit(99);
});
};

@ -6,7 +6,7 @@
"jsdom": "^12.2.0", "jsdom": "^12.2.0",
"node-sass": "^4.9.3", "node-sass": "^4.9.3",
"perfy": "^1.1.5", "perfy": "^1.1.5",
"winston-daily-rotate-file": "^3.3.3", "winston": "^3.1.0",
"winston": "^3.1.0" "winston-daily-rotate-file": "^3.3.3"
} }
} }

@ -9,6 +9,8 @@ const fs = require('fs'),
// own modules // own modules
utils = require("./lib/utils"), utils = require("./lib/utils"),
prepro = require("./lib/preprocessor"), prepro = require("./lib/preprocessor"),
// cleanup
clean = utils.Cleanup(cleanup),
// args // args
args = require('args-parser')(process.argv), // create an args parser args = require('args-parser')(process.argv), // create an args parser
// config file // config file
@ -91,20 +93,18 @@ function main() {
let uri = url.pathname; // set uri to the urls uriame let uri = url.pathname; // set uri to the urls uriame
logger.debug({"msg": 'Got URL by using url package', 'url': url, 'path': uri}); logger.debug({"msg": 'Got URL by using url package', 'url': url, 'path': uri});
let [response, mime] = getResponse(uri); // get a response for the url path let resArray = getResponse(uri); // get a response for the url path
logger.debug({'response-length': response.length, 'mime-type': mime}); let response = resArray[0] || "", // the response
mime = resArray[1] || "text/plain", // the mime-type
res.writeHead(200, {"Content-Type": mime || "text/plain"}); // write the mime as head statuscode = resArray[2] || 200; // the status code. 200 if not explicitly set
logger.debug({'response-length': response.length, 'mime-type': mime, 'code': statuscode});
res.writeHead(statuscode, {"Content-Type": mime}); // write the mime as head
res.end(response); // write the response res.end(response); // write the response
let execTime = perfy.end('response-calculation').fullMilliseconds; // get the execution time let execTime = perfy.end('response-calculation').fullMilliseconds; // get the execution time
logger.debug("Response-Time: " + execTime + " ms for " + req.url, "debug"); // log the execution time logger.debug("Response-Time: " + execTime + " ms for " + req.url, "debug"); // log the execution time
}).listen(port); // server listens on port specified in the parameter }).listen(port); // server listens on port specified in the parameter
} catch (error) { } catch (error) {
logger.error(error); logger.error(error.message);
logger.info("Shutting Down...");
prepro.cleanup();
winston.end();
process.exit(1); process.exit(1);
} }
} }
@ -112,15 +112,15 @@ function main() {
/** /**
* Returns a string that depends on the uri It gets the data from the routes variable. * Returns a string that depends on the uri It gets the data from the routes variable.
* @param uri * @param uri
* @return {string[]} An Array containing (Either the files content or an error message) and the mime-type. * @return {string[]} An Array containing the files content, the mime type and sometimes the statuscode (if it is not 200)
*/ */
function getResponse(uri) { function getResponse(uri) {
if (!uri || uri === "/") uri = "/index.html"; // uri redirects to the index.html if it is not set or if it is root let matches = uri.match(/(\/$|\/\w+$)/g); // matches when the url has no file extension or ends in a slash (/)
if (matches) uri += '/index.html'; // append index.html if there are matches
logger.verbose({'msg': 'calculating response', 'path': uri}); logger.verbose({'msg': 'calculating response', 'path': uri});
let gp = prepro.getProcessed; let gp = prepro.getProcessed; // shorten the function name
try { try {
// get the file extension let extension = utils.getExtension(uri); // get the urls file-extension
let extension = utils.getExtension(uri);
// returns the global script or css if the extension is css or js and the root-uriis glob. // returns the global script or css if the extension is css or js and the root-uriis glob.
if (uri.includes("/glob") && (extension === ".sass" || extension === ".js")) { if (uri.includes("/glob") && (extension === ".sass" || extension === ".js")) {
logger.verbose("Using global uri"); logger.verbose("Using global uri");
@ -131,12 +131,16 @@ function getResponse(uri) {
logger.verbose("Mount for uri is " + mount); logger.verbose("Mount for uri is " + mount);
let route = routes[extension]; // get the route from the extension json let route = routes[extension]; // get the route from the extension json
logger.verbose("Found route: " + JSON.stringify(route)); logger.verbose("Found route: " + JSON.stringify(route));
if (!route) return ["Not Allowed", "text/plain"]; // return not allowed if no route was found
if (!route) {
logger.warn(`No route found for ${uri}`);
return [gp(config.errors['403']), "text/html", 403]; // return not allowed if no route was found
}
return [gp(mount || path.join(route["path"], uri)), route["mime"]]; // get processed output (done by preprocessor) return [gp(mount || path.join(route["path"], uri)), route["mime"]]; // get processed output (done by preprocessor)
} catch (error) { } catch (error) {
logger.error(error); logger.warn(error.message);
if (args.test) process.exit(1); if (args.test) process.exit(1);
return ["Error", "text/plain"]; return [gp(config.errors['404']), "text/html", 404];
} }
} }
@ -159,6 +163,12 @@ function getMount(uri) {
return false; return false;
} }
function cleanup() {
logger.info('Cleanup...');
prepro.cleanup(); // cleanup the preprocessor
logger.end(); // let the logger finish all operations
}
// Executing the main function // Executing the main function
if (typeof require !== 'undefined' && require.main === module) { if (typeof require !== 'undefined' && require.main === module) {
logger.exceptions.handle( logger.exceptions.handle(
@ -174,7 +184,7 @@ if (typeof require !== 'undefined' && require.main === module) {
} else protocoll = require('http'); // if no certs could be found start the server as http-server } else protocoll = require('http'); // if no certs could be found start the server as http-server
logger.info("Starting up... "); // log the current date so that the logfile is better to read. logger.info("Starting up... "); // log the current date so that the logfile is better to read.
if (args.test) { if (args.test) {
setTimeout(() => process.exit(0), 30000); setTimeout(() => process.exit(0), 10000); // if in testing mode, exit after 10 seconds
} }
main(); main();
} }

Loading…
Cancel
Save