diff --git a/config/caching_dump.json b/config/caching_dump.json
deleted file mode 100644
index 0db3279..0000000
--- a/config/caching_dump.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-
-}
diff --git a/config/server.json b/config/server.json
index e423323..5fcc35d 100644
--- a/config/server.json
+++ b/config/server.json
@@ -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"
+ }
+ }
}
diff --git a/glob/errors/403.html b/glob/errors/403.html
new file mode 100644
index 0000000..cf557e1
--- /dev/null
+++ b/glob/errors/403.html
@@ -0,0 +1,12 @@
+
+
+ 403 - Forbidden
+
+
+
+
+ 403 - Forbidden
+ You are not allowed to access the requested ressource.
+ 403
+
+
diff --git a/glob/errors/404.html b/glob/errors/404.html
new file mode 100644
index 0000000..b6eb135
--- /dev/null
+++ b/glob/errors/404.html
@@ -0,0 +1,12 @@
+
+
+ 404 - Not Found
+
+
+
+
+ 404 - Not Found
+ The requested ressouce could not be found.
+ 404
+
+
diff --git a/glob/home.html b/glob/home.html
deleted file mode 100644
index 4c5a8ad..0000000
--- a/glob/home.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
- Home
-
-
- Welcome to the server
-
-
diff --git a/lib/caching.js b/lib/caching.js
index b500c0d..a120d49 100644
--- a/lib/caching.js
+++ b/lib/caching.js
@@ -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
+ }
};
diff --git a/lib/preprocessor.js b/lib/preprocessor.js
index e6d0b03..a3a948f 100644
--- a/lib/preprocessor.js
+++ b/lib/preprocessor.js
@@ -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
};
/**
@@ -63,4 +58,4 @@ exports.getProcessed = function (filename) {
*/
exports.cleanup = function() {
caching.cleanup();
-};
\ No newline at end of file
+};
diff --git a/lib/utils.js b/lib/utils.js
index d478594..f03b338 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -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);
+ });
+};
diff --git a/package.json b/package.json
index b7950c7..d481c76 100644
--- a/package.json
+++ b/package.json
@@ -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"
}
}
diff --git a/server.js b/server.js
index c2fa3dc..ee4f9b6 100644
--- a/server.js
+++ b/server.js
@@ -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();
}