web-servo
Version:
Node HTTP web server that can execute node JS scripts
1,188 lines (991 loc) • 31.5 kB
JavaScript
/**
* The main class
*/
var webservo = function() {
this.initModules();
this.isInitiated = false;
this.isRunning = false;
this.isSilent = false;
this.hasError = false;
this.cache = {};
this.configData = {};
this.setDir(process.cwd());
this.aliasRecursion = 100;
this.protocol = 'http';
};
/**
* Initialize the modules
*/
webservo.prototype.initModules = function() {
// init the modules
this.modules = {};
this.modules.fs = require('fs');
this.modules.os = require('os');
this.modules.sd = require('node-screwdriver');
this.modules.url = require('url');
this.modules.http = require('http');
this.modules.mime = require('mime');
this.modules.path = require('path');
this.modules.https = require('https');
this.modules.busboy = require('busboy');
this.modules.colors = require('colors');
this.modules.child_process = require('child_process');
};
/**
* Set the server directory. Chainable
* @param {string} dir The directory, relative or absolute
*/
webservo.prototype.setDir = function(dir) {
// server is not running
if (this.isRunning === true) {
this.warning('Cannot set the server directory while the server is running');
return this;
}
// init the dir object
this.dir = {};
this.dir.base = this.modules.path.resolve(dir+'/');
// check if the config is loaded
if (this.configData && this.configData.server && this.configData.server.dir) {
// set the www directory
this.dir.www = this.modules.path.resolve(this.dir.base+'/'+this.configData.server.dir+'/');
}
this.isInitiated = false;
return this;
};
/**
* Set silent mode on and off. Chainable
*/
webservo.prototype.silent = function (b) {
if (typeof b === "undefined") {
b = true;
}
this.isSilent = b;
return this;
};
/**
* Exit the process on error
*/
webservo.prototype.exitOnError = function(callback) {
if (this.hasError) {
process.exit();
}
return this;
};
/**
* Stop the server. Chainable
* @param {Function} callback Called when done
*/
webservo.prototype.stop = function(callback) {
// server is not running
if (this.isRunning === false) {
this.warning('Stop: the server is not running');
return this;
}
var ws = this;
// stop the server
this.server.close(function(){
ws.log('Server stopped');
// call the callback
if (callback) {
callback(ws);
}
});
return this;
};
/**
* Start the server. Chainable
* @param {Function} callback Called when done
*/
webservo.prototype.start = function(callback) {
if (this.isRunning === true) {
this.warning('Start: the server is already running');
return this;
}
// init the server
if (this.isInitiated === false) {
this.config();
}
// the server could not init
if (this.isInitiated === false) {
// exit with failure code
this.isRunning = false;
this.error('Failed to load the server');
return this;
}
var ws = this;
function handleRequest(request, response) {
if (ws.configData.methods.allowed) {
if (ws.configData.methods.allowed.indexOf(request.method) == -1) {
return ws.status405(request, response, 'Method not allowed: '+request.method);
}
}
// handle the OPTIONS method
if (request.method == 'OPTIONS') {
if (ws.configData.methods.allowed) {
response.setHeader("Allow", ws.configData.methods.allowed.join(','));
}
return ws.status200(request, response, '');
}
try {
var requestedFile = ws.getUrlFile(request.url);
var parameters = ws.modules.url.parse(request.url, true);
parameters = parameters.query;
if (request.method == 'POST') {
var busboy = new ws.modules.busboy({ headers: request.headers });
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
if (filename != '') {
// save file
var saveTo = ws.modules.path.join(ws.modules.os.tmpDir(), ws.modules.path.basename(fieldname)+'_'+Math.floor(Math.random() * 10000000000)+'_'+filename);
var item = {
fieldname: fieldname,
filename: filename,
encoding: encoding,
mimetype: mimetype,
tmpFile: saveTo,
fileObject: file
};
file.pipe(ws.modules.fs.createWriteStream(saveTo));
parameters[fieldname] = item;
return true;
} else {
// discard file with no name
file.resume();
return false;
}
});
busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated) {
if (typeof parameters[fieldname] !== 'object') {
parameters[fieldname] = val;
}
});
busboy.on('finish', function() {
ws.process(request, response, requestedFile, parameters);
});
return request.pipe(busboy);
}
return ws.process(request, response, requestedFile, parameters);
} catch (e) {
return ws.status500(request, response, ''+e);
}
};
if (this.configData.server.ssl.enabled) {
try {
var file_cert = this.modules.path.resolve(this.dir.base+'/'+this.configData.server.ssl.cert);
var file_key = this.modules.path.resolve(this.dir.base+'/'+this.configData.server.ssl.key);
var options = {
key: this.modules.fs.readFileSync(file_key),
cert: this.modules.fs.readFileSync(file_cert)
};
this.server = this.modules.https.createServer(options, handleRequest);
this.protocol = 'https';
} catch (e) {
this.error('Problem while starting the server');
this.error(''+e);
return this;
}
} else {
try {
this.server = this.modules.http.createServer(handleRequest);
this.protocol = 'http';
} catch (e) {
this.error('Problem while starting the server');
this.error(''+e);
return this;
}
}
this.server.listen(this.configData.server.port, function() {
ws.log("Server listening on: "+ws.protocol+"://localhost:"+ws.configData.server.port);
if (callback) {
callback(ws);
}
});
this.isRunning = true;
return this;
};
/**
* Set the config file or the config object of the server. Chainable
* @param {mixed} file Path of the config file or object
* @return {bool} True on success
*/
webservo.prototype.config = function(file) {
if (this.isRunning) {
this.warning('Cannot change config while server is running');
return this;
}
this.isInitiated = false;
this.configData = {};
var config = false;
var fromFile = true;
if (file && typeof file === 'object') {
// file is the configuration object
fromFile = false;
config = file;
} else {
// try to load config from file
// default config file
if (!file) {
file = this.modules.path.resolve(this.dir.base+'/config.json');
} else {
file = this.modules.path.resolve(this.dir.base+'/'+file);
}
// check if the file exists
try {
this.modules.fs.lstatSync(file);
} catch (e) {
this.log(('Using config file "'+file+'"').cyan);
this.error(''+e);
return this;
}
// try to load the JSON file
try {
config = require(file);
} catch (e) {
this.log(('Using config file "'+file+'"').cyan);
this.error(''+e);
return this;
}
}
// set the default params in config object
if (!config) config = {};
if (!config.server) config.server = {};
if (!config.server.port) config.server.port = '80';
if (!config.server.dir) config.server.dir = 'www/';
if (!config.server.ssl) config.server.ssl = { enabled: false };
if (!config.page) config.page = {};
if (!config.page.error) config.page.error = {};
if (!config.page.script) config.page.script = 'node.js';
if (!config.page.default) config.page.default = 'index.html';
if (!config.log) config.log = {};
if (!config.log.error) config.log.error = { "enabled": true, "path": "", "console": true };
if (!config.log.access) config.log.access = { "enabled": false, "path": "", "console": false };
if (!config.log.warning) config.log.warning = { "enabled": true };
if (!config.methods) config.methods = {};
if (!config.methods.allowed) config.methods.allowed = ["OPTIONS", "GET", "POST", "HEAD", "PUT", "PATCH", "DELETE", "COPY", "LINK", "UNLINK", "TRACE", "CONNECT"];
if (fromFile) {
this.log(('Using config file "'+file+'"').cyan);
}
return this.checkConfig(config);
};
webservo.prototype.checkConfig = function (config) {
var changedDir = false;
var previousDir = this.dir.www;
// set configData at the beginning, so the log functions can access their parameters
this.configData = config;
// check every error page in config
var pages = ['401', '403', '404', '405', '500'];
for (var t=0; t<pages.length; t++) {
try {
if (config.page.error && config.page.error[pages[t]]) {
var file = this.modules.path.resolve(this.dir.base+'/'+config.page.error[pages[t]]);
var error = this.modules.fs.appendFileSync(file, '');
} else {
config.page.error[pages[t]] = false;
}
} catch (e) {
this.warning('Cannot find error file "'+file+'"');
config.page.error[pages[t]] = false;
}
}
// check if www root directory exists
if (!this.dir.www) {
changedDir = true;
}
this.dir.www = this.modules.path.resolve(this.dir.base+'/'+this.configData.server.dir+'/');
if (previousDir != this.dir.www) {
changedDir = true;
}
try {
var stats = this.modules.fs.lstatSync(this.dir.www);
if (!stats.isDirectory()) {
this.configData = false;
this.error('WWW root must be a directory "'+this.dir.www+'"');
return this;
}
} catch (e) {
this.configData = false;
this.error(e+'');
return this;
}
// check error log file
if (!config.log.error.path) {
config.log.error.path = '';
}
if (config.log.error.enabled && config.log.error.path != '') {
try {
var file = this.modules.path.resolve(this.dir.base+'/'+config.log.error.path);
var error = this.modules.fs.appendFileSync(file, '');
} catch (e) {
this.warning('Cannot write in error log file "'+file+'"');
config.log.error.path = '';
}
}
// check access log file
if (!config.log.error.path) {
config.log.error.path = '';
}
if (config.log.access.enabled && config.log.access.path != '') {
try {
var file = this.modules.path.resolve(this.dir.base+'/'+config.log.access.path);
var access = this.modules.fs.appendFileSync(file, '');
} catch (e) {
this.warning('Cannot write in access log file "'+file+'"');
config.log.access.path = '';
}
}
// check SSL files
if (config.server.ssl.enabled) {
if (!config.server.ssl.key || config.server.ssl.key == '') {
this.error('SSL key file is not configured');
this.warning('Server will run with HTTP protocol');
config.server.ssl.enabled = false;
} else {
try {
var file = this.modules.path.resolve(this.dir.base+'/'+config.server.ssl.key);
var read = this.modules.fs.readFileSync(file);
} catch (e) {
this.error('Cannot read SSL file "'+file+'"');
this.warning('Server will run with HTTP protocol');
config.server.ssl.enabled = false;
}
}
}
if (config.server.ssl.enabled) {
if (!config.server.ssl.cert || config.server.ssl.cert == '') {
this.error('SSL certificate file is not configured');
this.warning('Server will run with HTTP protocol');
config.server.ssl.enabled = false;
} else {
try {
var file = this.modules.path.resolve(this.dir.base+'/'+config.server.ssl.cert);
var read = this.modules.fs.readFileSync(file);
} catch (e) {
this.error('Cannot read SSL file "'+file+'"');
this.warning('Server will run with HTTP protocol');
config.server.ssl.enabled = false;
}
}
}
this.configData = config;
this.isInitiated = true;
if (changedDir) {
this.log(('Using WWW directory "'+this.dir.www+'"').cyan);
}
return this;
};
/**
* Set a variable in the config and rebuild and check the
* @param {[type]} name [description]
* @param {[type]} value [description]
*/
webservo.prototype.setConfigVar = function (name, value) {
if (this.isRunning) {
this.warning('Cannot change config variable while server is running');
return this;
}
if (!this.isInitiated) {
this.warning('setConfigVar: server is not initiated ['+name+' = '+value+']');
this.config();
}
var list = name.split('.');
if (list.length == 0) {
this.warning('setConfigVar: empty name ['+name+' = '+value+']');
return this;
}
var config = this.configData;
var name = list[0];
for (var i = 0; i < list.length-1; i++) {
if (!config[list[i]]) {
this.warning('setConfigVar: variable does not exist ['+name+' = '+value+']');
return this;
}
config = config[list[i]];
}
config[list[i]] = value;
this.checkConfig(this.configData);
return this;
};
/**
* Trim
*/
webservo.prototype.trim = function (str) {
return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
};
/**
* Get the date and time for log
*/
webservo.prototype.getDateTime = function() {
var date = new Date();
var hour = date.getHours();
hour = (hour < 10 ? "0" : "") + hour;
var min = date.getMinutes();
min = (min < 10 ? "0" : "") + min;
var sec = date.getSeconds();
sec = (sec < 10 ? "0" : "") + sec;
var year = date.getFullYear();
var month = date.getMonth() + 1;
month = (month < 10 ? "0" : "") + month;
var day = date.getDate();
day = (day < 10 ? "0" : "") + day;
return year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec;
};
/**
* A error occured
* @param {string} message Error description
*/
webservo.prototype.error = function(message) {
// set the server in an error state
if (!this.isRunning) {
this.hasError = true;
}
// if config not loaded yet, just print message in console
if (!this.configData || !this.configData.log) {
this.log(message.red);
} else if (this.configData.log.error.enabled) {
if (this.configData.log.error.path && this.configData.log.error.path != '') {
// write error in file
this.writeError(message);
}
// print in console if needed
if (this.configData.log.error.console) {
this.log(message.red);
}
}
if (this.configData.server.exitOnError) {
process.exit();
}
};
/**
* Write the error in the error log file
* @param {string} message
*/
webservo.prototype.writeError = function(message) {
return this.modules.fs.appendFile(this.modules.path.resolve(this.dir.base+'/'+this.configData.log.error.path), this.getDateTime()+' '+message+String.fromCharCode(13));
};
/**
* Show message in console
* @param {string} message
*/
webservo.prototype.log = function(message) {
if (!this.isSilent) {
console.log(message);
}
};
/**
* Show warning in console
* @param {string} message
*/
webservo.prototype.warning = function(message) {
this.log(message.yellow);
};
/**
* Show debug for a JS file in console
* @param {string} file Path to node file
*/
webservo.prototype.debug = function(file) {
var ws = this;
// callback to show the result
function puts(error, stdout, stderr) {
// split the lines
var lines = (stderr+'').split(String.fromCharCode(13));
// show each line
for (var t=0; t<lines.length; t++) {
// hide if line empty
if (ws.trim(lines[t]) != '') {
ws.log(('Debug: '+lines[t]).replace(String.fromCharCode(13), '').replace(String.fromCharCode(10), '').green);
}
}
}
// execute "node -c file" to get the error details
this.modules.child_process.exec("node -c "+file, puts);
};
/**
* Log an access
* @param {object} request
* @param {object} response
* @param {int} statusCode The returned status code (200, 404 ...)
*/
webservo.prototype.access = function(request, response, statusCode) {
// if access log is enabled
if (this.configData.log.access.enabled) {
// get the url
var url = request.url;
// get the IP @TODO convert to ipv4 if possible
var ip = request.connection.remoteAddress;
// write in log
if (this.configData.log.access.path && this.configData.log.access.path != '') {
this.writeAccess(statusCode, ip, url);
}
// write in console if needed
if (this.configData.log.access.console) {
this.log(('Access: '+ip+' '+statusCode+' '+url).magenta);
}
}
}
/**
* Write an access in the access log file
* @param {int} statusCode The returned status code
* @param {string} ip Remote IP
* @param {string} url URL
*/
webservo.prototype.writeAccess = function(statusCode, ip, url) {
return this.modules.fs.appendFile(this.modules.path.resolve(this.dir.base+'/'+this.configData.log.access.path), this.getDateTime()+' '+statusCode+' '+ip+' '+url+String.fromCharCode(13));
};
/**
* Return a page with status code 500
* @param {object} request
* @param {object} response
* @param {string} message
*/
webservo.prototype.status500 = function(request, response, message) {
// log the access
this.access(request, response, 500);
// show in console if needed
if (message) {
this.error(message);
}
var ws = this;
// output to client
response.writeHead(500, {"Content-Type": "text/html"});
if (this.cache.error500) {
response.write(this.cache.error500);
response.end();
return true;
}
if (this.configData.page && this.configData.page.error && this.configData.page.error['500']) {
this.modules.fs.readFile(this.dir.base+'/'+this.configData.page.error['500'], 'utf8', function (err, data) {
if (err) {
ws.configData.page.error['500'] = false;
response.write("500 Server error");
response.end();
} else {
ws.cache.error500 = data;
response.write(data);
response.end();
}
});
} else {
response.write("500 Server error");
response.end();
}
return true;
};
/**
* Return a page with status code 403
* @param {object} request
* @param {object} response
* @param {string} message
*/
webservo.prototype.status403 = function(request, response, message) {
// log the access
this.access(request, response, 403);
// show in console if needed
if (message) {
this.error(message);
}
var ws = this;
// output to client
response.writeHead(403, {"Content-Type": "text/html"});
if (this.cache.error403) {
response.write(this.cache.error403);
response.end();
return true;
}
if (this.configData.page && this.configData.page.error && this.configData.page.error['403']) {
this.modules.fs.readFile(this.dir.base+'/'+this.configData.page.error['403'], 'utf8', function (err, data) {
if (err) {
ws.configData.page.error['403'] = false;
response.write("403 Forbidden");
response.end();
} else {
ws.cache.error403 = data;
response.write(data);
response.end();
}
});
} else {
response.write("403 Forbidden");
response.end();
}
return true;
};
/**
* Return a page with status code 404
* @param {object} request
* @param {object} response
* @param {string} message
*/
webservo.prototype.status404 = function(request, response, message) {
// log the access
this.access(request, response, 404);
// show in console if needed
if (message) {
this.error(message);
}
var ws = this;
// output to client
response.writeHead(404, {"Content-Type": "text/html"});
if (this.cache.error404) {
response.write(this.cache.error404);
response.end();
return true;
}
if (this.configData.page && this.configData.page.error && this.configData.page.error['404']) {
this.modules.fs.readFile(this.dir.base+'/'+this.configData.page.error['404'], 'utf8', function (err, data) {
if (err) {
ws.configData.page.error['404'] = false;
response.write("404 Not found");
response.end();
} else {
ws.cache.error404 = data;
response.write(data);
response.end();
}
});
} else {
response.write("404 Not found");
response.end();
}
return true;
};
/**
* Return a page with status code 404
* @param {object} request
* @param {object} response
* @param {string} message
*/
webservo.prototype.status405 = function(request, response, message) {
// log the access
this.access(request, response, 405);
// show in console if needed
if (message) {
this.error(message);
}
var ws = this;
// output to client
response.writeHead(405, {"Content-Type": "text/html"});
if (this.cache.error404) {
response.write(this.cache.error405);
response.end();
return true;
}
if (this.configData.page && this.configData.page.error && this.configData.page.error['405']) {
this.modules.fs.readFile(this.dir.base+'/'+this.configData.page.error['405'], 'utf8', function (err, data) {
if (err) {
ws.configData.page.error['405'] = false;
response.write("405 Method Not Allowed");
response.end();
} else {
ws.cache.error405 = data;
response.write(data);
response.end();
}
});
} else {
response.write("405 Method Not Allowed");
response.end();
}
return true;
};
/**
* Return a page with status code 401
* @param {object} request
* @param {object} response
* @param {string} message
*/
webservo.prototype.status401 = function(request, response, message) {
// log the access
this.access(request, response, 401);
// show in console if needed
if (message) {
this.error(message);
}
var ws = this;
// output to client
if (response._header && response._header.indexOf('Content-Type:') < 0) {
response.writeHead(401, {"Content-Type": "text/html"});
}
if (this.cache.error401) {
response.write(this.cache.error401);
response.end();
return true;
}
if (this.configData.page && this.configData.page.error && this.configData.page.error['401']) {
this.modules.fs.readFile(this.dir.base+'/'+this.configData.page.error['401'], 'utf8', function (err, data) {
if (err) {
ws.configData.page.error['401'] = false;
response.write("401 Not found");
response.end();
} else {
ws.cache.error401 = data;
response.write(data);
response.end();
}
});
} else {
response.write("401 Not found");
response.end();
}
return true;
};
/**
* Return a page with status code 200
* @param {object} request
* @param {object} response
* @param {string} message
*/
webservo.prototype.status200 = function(request, response, body) {
// output to client
if (response._headers && !response._headers['content-type']) {
response.setHeader('Content-Type', 'text/html');
}
// log the access
this.access(request, response, response.statusCode);
response.write(body);
response.end();
return true;
};
/**
* Check if the file is a server script
* @param {string} file Path to the file
*/
webservo.prototype.isScript = function(file) {
return this.modules.sd.endsWith(file, this.configData.page.script);
};
/**
* Transform a file path to an URL. Return false if impossible or server not initiated
* @param {string} file Path of the file
* @return {string} The URL
*/
webservo.prototype.fileToUrl = function(file) {
if (!this.dir || !this.dir.www || file.indexOf(this.dir.www) != 0) {
return false;
}
return file.replace(this.dir.www, '').replace(/\\/g, '/');
};
webservo.prototype.stringToRegex = function(string) {
var regString = '^' + string.replace(/\./g, '\\.').replace(/\*/g, '(.*)') + '$';
return new RegExp(regString, "");
};
/**
* Get the alias from a file
* @param {string} file Path to the file
* @return {string} Path to the alias
*/
webservo.prototype.getAlias = function(file) {
var count = 0;
var originalUrl = this.fileToUrl(file);
var previousFile, url;
while (previousFile != file) {
previousFile = file;
url = this.fileToUrl(file);
if (this.configData.url && this.configData.url[url] && this.configData.url[url].alias) {
if (count > this.aliasRecursion) {
this.error('Max alias recursion reach for \"'+originalUrl+'\"');
break;
}
file = this.getUrlFile(this.configData.url[url].alias);
count++;
} else {
for (var term in this.configData.url) {
if (term.indexOf('*') >= 0) {
if (!this.configData.url[term].regex) {
this.configData.url[term].regex = this.stringToRegex(term);
}
var match = this.configData.url[term].regex.exec(url);
if (match) {
if (this.configData.url[term].alias) {
file = this.getUrlFile(this.configData.url[term].alias);
if (match.length > 1) {
for (var t=1; t<match.length; t++) {
file = file.replace('*', match[t]);
}
}
}
}
}
}
break;
}
}
return file;
};
webservo.prototype.verifyAuthentication = function(request, authentication) {
if (authentication && authentication.login) {
// no authentication
if (authentication.login === 'none') {
return false;
}
if (request.headers && request.headers.authorization) {
var list = request.headers.authorization.split(' ');
// invalid authorization
if (list.length != 2) {
return false;
}
if (list[0] == 'Basic') {
var string = (new Buffer(list[1], 'base64'))+'';
var values = string.split(':', 2);
// wrong login
if (authentication.login != values[0]) {
return false;
}
// wrong password
if (authentication.password != values[1]) {
return false;
}
// everything is awesome
return true;
} else {
// authorization other than Basic is not implemented
return false;
}
return false;
}
// URL need authentication and no authorization in header
return false;
}
return true;
};
/**
* Returns true if authentication is correct
* @param {object} request
* @param {object} response
* @param {object} file
* @param {object} parameters
* @return {bool} True if can access the page, False ask for login / password
*/
webservo.prototype.getAuthentication = function(request, response, file, parameters) {
var url = this.fileToUrl(file);
if (this.configData.url && this.configData.url[url] && this.configData.url[url].authentication) {
if (!this.verifyAuthentication(request, this.configData.url[url].authentication)) {
return false;
}
}
for (var term in this.configData.url) {
if (term.indexOf('*') >= 0) {
if (!this.configData.url[term].regex) {
this.configData.url[term].regex = this.stringToRegex(term);
}
var match = this.configData.url[term].regex.exec(url);
if (match) {
if (this.configData.url[term] && this.configData.url[term].authentication) {
if (!this.verifyAuthentication(request, this.configData.url[term].authentication)) {
return false;
}
}
}
}
}
return true;
};
/**
* Process a file
*/
webservo.prototype.process = function(request, response, file, parameters) {
if (this.onBeforeRequest) {
this.onBeforeRequest(request, response, file, parameters);
}
var pathAbsolute = this.modules.path.resolve(file);
file = this.getAlias(pathAbsolute);
if (!this.getAuthentication(request, response, file, parameters)) {
response.writeHead(401, {"WWW-Authenticate": "Basic realm=\"Password Protected Area\"", "Content-Type": "text/html"});
return this.status401(request, response, 'Error: 401 unathorised access to "'+file+'"');
}
// check if file exists
try {
this.modules.fs.lstatSync(file);
} catch (e) {
// return the 404 page
return this.status404(request, response, 'Error: 404 file not found "'+file+'"');
}
// check if file is a script
if (this.isScript(file)) {
// process as a JS script, execute on the server
this.processScript(request, response, file, parameters);
} else {
// process as a simple file, send the data to client
this.processFile(request, response, file, parameters);
}
return true;
};
/**
* Execute script and return result
*/
webservo.prototype.processScript = function(request, response, file, parameters) {
// execute the JS file and catch error
try {
// absolute path of the file
var pathAbsolute = this.modules.path.resolve(file);
// get the function to call / execute the JS
var fct = require(pathAbsolute);
var getType = {};
var result = false;
// if result if a function, execute it here and get result
if (fct && getType.toString.call(fct) == '[object Function]') {
result = fct(request, response, parameters, this);
}
// delete cache so the file is also executed next time
require.cache[pathAbsolute] = null;
} catch(e) {
// absolute path of the file
var pathAbsolute = this.modules.path.resolve(file);
// delete cache so the file is also executed next time
require.cache[pathAbsolute] = null;
// try to show the debug of the error
if (this.configData.log.error.debug) {
this.debug(file);
}
// return the error 500 page
return this.status500(request, response, ''+e+' in "'+file+'"');
}
// display a warning if the script returned nothing
if (result === false || result === '') {
this.warning('Script returned nothing: "'+file+'"');
}
if (this.onAfterRequest) {
this.onAfterRequest(request, response, file, parameters, result);
}
// return the page with status code 200
return this.status200(request, response, result || '');
};
/**
* Get file and return it to client
*/
webservo.prototype.processFile = function(request, response, file, parameters) {
// process the file
try {
var content = this.modules.fs.readFileSync(file);
if (this.onAfterRequest) {
this.onAfterRequest(request, response, file, parameters, content);
}
response.writeHead(200, {"Content-Type": this.modules.mime.lookup(file)});
response.write(content);
response.end();
// log the access
this.access(request, response, 200);
} catch (e) {
// if any errors happened, file is probably not here
// return the 404 page
return this.status404(request, response, 'Error: 404 file not found "'+file+'"');
}
};
webservo.prototype.getUrlFile = function(url) {
// build the path of the file
var file = [this.dir.www, this.modules.url.parse(url).pathname].join('/').replace('//', '/');
var filename = this.modules.path.basename(file);
// set default file if needed
if (file.slice(-1) == '/' || filename == '') {
file += '/'+this.configData.page.default;
}
return this.modules.path.resolve(file);
};
/**
* Executed before the request is processed
*/
webservo.prototype.onBeforeRequest = function(request, response, file, parameters) {
};
/**
* Executed before the request is processed
*/
webservo.prototype.onAfterRequest = function(request, response, file, parameters, body) {
};
module.exports = new webservo();