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,44 +1,48 @@
{
"routes": {
".html": {
"path": "./res/html/",
"mime": "text/html"
},
".htm": {
"path": "./res/html/",
"mime": "text/html"
},
".js": {
"path": "./res/scripts/",
"mime": "text/javascript"
},
".css": {
"path": "./res/css/",
"mime": "text/css"
},
".json": {
"path": "./res/data/",
"mime": "text/plain"
},
".ico": {
"path": "./res/img/",
"mime": "image/x-icon"
},
".jpg": {
"path": "./res/img/",
"mime": "image/jpeg"
},
".png": {
"path": "./res/img/",
"mime": "image/png"
},
".ttf": {
"path": "./res/fonts/",
"mime": "font/opentype"
},
".sass" :{
"path": "./res/sass",
"mime": "style/css"
}
}
"errors": {
"403": "./glob/errors/403.html",
"404": "./glob/errors/404.html"
},
"routes": {
".html": {
"path": "./res/html/",
"mime": "text/html"
},
".htm": {
"path": "./res/html/",
"mime": "text/html"
},
".js": {
"path": "./res/scripts/",
"mime": "text/javascript"
},
".css": {
"path": "./res/css/",
"mime": "text/css"
},
".json": {
"path": "./res/data/",
"mime": "text/plain"
},
".ico": {
"path": "./res/img/",
"mime": "image/x-icon"
},
".jpg": {
"path": "./res/img/",
"mime": "image/jpeg"
},
".png": {
"path": "./res/img/",
"mime": "image/png"
},
".ttf": {
"path": "./res/fonts/",
"mime": "font/opentype"
},
".sass": {
"path": "./res/sass",
"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"),
path = require("path"),
config_path = "./config/caching_dump.json",
cache_dump = JSON.parse(fs.readFileSync(config_path)),
cache_dir = "./.cache";
let cache = {};
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
@ -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 () {
logger.verbose("Dumping cache into cache_dump file");
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
deleteFolder(cache_dir); // delte the cache folder and it's contents
};
/**
* 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,34 +28,29 @@ exports.setLogger = function (newLogger) {
* @return {String} The data that should be send
*/
exports.getProcessed = function (filename) {
try {
logger.debug("Processing File %s", filename);
let extension = utils.getExtension(filename); // use the utils function to get the files extension
let data = null;
if (caching.isCached(filename)) return caching.getCached(filename) // return the cached file if it exists
logger.debug("File is not cached. Processing...");
switch (pp_config[extension]) {
case "sass":
logger.debug("Processing sass %s", filename);
data = Buffer.from(pp_sass.renderSync({ // use the sass preprocessor
file: filename
}).css).toString("utf-8");
break;
case "html":
logger.debug("Processing html %s", filename);
data = pp_html.formatHtml(filename); // use the html-preprocessor
break;
default:
logger.debug("No processor found for %s. Returning data.", filename);
return fs.readFileSync(filename); // just read the data from the file
}
caching.cache(filename, data); // cache the file for faster access next time
logger.debug("Cached file %s", filename);
return data; // return the data
} catch (error) {
logger.error(error);
return "Processing Error";
logger.debug("Processing File %s", filename);
let extension = utils.getExtension(filename); // use the utils function to get the files extension
let data = null;
if (caching.isCached(filename)) return caching.getCached(filename) // return the cached file if it exists
logger.debug("File is not cached. Processing...");
switch (pp_config[extension]) {
case "sass":
logger.debug("Processing sass %s", filename);
data = Buffer.from(pp_sass.renderSync({ // use the sass preprocessor
file: filename
}).css).toString("utf-8");
break;
case "html":
logger.debug("Processing html %s", filename);
data = pp_html.formatHtml(filename); // use the html-preprocessor
break;
default:
logger.debug("No processor found for %s. Returning data.", filename);
return fs.readFileSync(filename); // just read the data from the file
}
caching.cache(filename, data); // cache the file for faster access next time
logger.debug("Cached file %s", filename);
return data; // return the data
};
/**

@ -2,6 +2,8 @@
* A Series of utility functions
*/
function noOp() {};
/**
* returns the extension of a file for the given filename.
* @param {String} filename The name of the file.
@ -18,3 +20,35 @@ exports.getExtension = function (filename) {
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",
"node-sass": "^4.9.3",
"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
utils = require("./lib/utils"),
prepro = require("./lib/preprocessor"),
// cleanup
clean = utils.Cleanup(cleanup),
// args
args = require('args-parser')(process.argv), // create an args parser
// config file
@ -91,20 +93,18 @@ function main() {
let uri = url.pathname; // set uri to the urls uriame
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
logger.debug({'response-length': response.length, 'mime-type': mime});
res.writeHead(200, {"Content-Type": mime || "text/plain"}); // write the mime as head
let resArray = getResponse(uri); // get a response for the url path
let response = resArray[0] || "", // the response
mime = resArray[1] || "text/plain", // the mime-type
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
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
}).listen(port); // server listens on port specified in the parameter
} catch (error) {
logger.error(error);
logger.info("Shutting Down...");
prepro.cleanup();
winston.end();
logger.error(error.message);
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.
* @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) {
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});
let gp = prepro.getProcessed;
let gp = prepro.getProcessed; // shorten the function name
try {
// get the file extension
let extension = utils.getExtension(uri);
let extension = utils.getExtension(uri); // get the urls file-extension
// 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")) {
logger.verbose("Using global uri");
@ -131,12 +131,16 @@ function getResponse(uri) {
logger.verbose("Mount for uri is " + mount);
let route = routes[extension]; // get the route from the extension json
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)
} catch (error) {
logger.error(error);
logger.warn(error.message);
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;
}
function cleanup() {
logger.info('Cleanup...');
prepro.cleanup(); // cleanup the preprocessor
logger.end(); // let the logger finish all operations
}
// Executing the main function
if (typeof require !== 'undefined' && require.main === module) {
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
logger.info("Starting up... "); // log the current date so that the logfile is better to read.
if (args.test) {
setTimeout(() => process.exit(0), 30000);
setTimeout(() => process.exit(0), 10000); // if in testing mode, exit after 10 seconds
}
main();
}

Loading…
Cancel
Save