v0.45
parent
2afb640c24
commit
548caaee5c
@ -1,459 +1,518 @@
|
||||
var myVersion = "0.42", myProductName = "pagePark";
|
||||
|
||||
//The MIT License (MIT)
|
||||
|
||||
//Copyright (c) 2014 Dave Winer
|
||||
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
|
||||
//The above copyright notice and this permission notice shall be included in all
|
||||
//copies or substantial portions of the Software.
|
||||
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
//SOFTWARE.
|
||||
|
||||
var fs = require ("fs");
|
||||
var request = require ("request");
|
||||
var urlpack = require ("url");
|
||||
var http = require ("http");
|
||||
var marked = require ("marked");
|
||||
|
||||
var pageParkPrefs = {
|
||||
myPort: 80,
|
||||
indexFilename: "index"
|
||||
};
|
||||
var fnamePrefs = "prefs/prefs.json";
|
||||
|
||||
var pageParkStats = {
|
||||
ctStarts: 0,
|
||||
whenLastStart: new Date (0)
|
||||
};
|
||||
var fnameStats = "prefs/stats.json";
|
||||
|
||||
var domainsPath = "domains/";
|
||||
|
||||
var mdTemplatePath = "prefs/mdTemplate.txt";
|
||||
var urlDefaultTemplate = "http://fargo.io/code/noderunner/defaultmarkdowntemplate.txt";
|
||||
|
||||
//routines from utils.js, fs.js
|
||||
function getBoolean (val) {
|
||||
switch (typeof (val)) {
|
||||
case "string":
|
||||
if (val.toLowerCase () == "true") {
|
||||
return (true);
|
||||
}
|
||||
break;
|
||||
case "boolean":
|
||||
return (val);
|
||||
break;
|
||||
case "number":
|
||||
if (val != 0) {
|
||||
return (true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
function isAlpha (ch) {
|
||||
return (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')));
|
||||
}
|
||||
function isNumeric (ch) {
|
||||
return ((ch >= '0') && (ch <= '9'));
|
||||
}
|
||||
function jsonStringify (jstruct) {
|
||||
return (JSON.stringify (jstruct, undefined, 4));
|
||||
}
|
||||
function secondsSince (when) {
|
||||
var now = new Date ();
|
||||
when = new Date (when);
|
||||
return ((now - when) / 1000);
|
||||
}
|
||||
function endsWith (s, possibleEnding, flUnicase) {
|
||||
if ((s == undefined) || (s.length == 0)) {
|
||||
return (false);
|
||||
}
|
||||
var ixstring = s.length - 1;
|
||||
if (flUnicase == undefined) {
|
||||
flUnicase = true;
|
||||
}
|
||||
if (flUnicase) {
|
||||
for (var i = possibleEnding.length - 1; i >= 0; i--) {
|
||||
if (s [ixstring--].toLowerCase () != possibleEnding [i].toLowerCase ()) {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var i = possibleEnding.length - 1; i >= 0; i--) {
|
||||
if (s [ixstring--] != possibleEnding [i]) {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
function stringContains (s, whatItMightContain, flUnicase) {
|
||||
if (flUnicase == undefined) {
|
||||
flUnicase = true;
|
||||
}
|
||||
if (flUnicase) {
|
||||
s = s.toLowerCase ();
|
||||
whatItMightContain = whatItMightContain.toLowerCase ();
|
||||
}
|
||||
return (s.indexOf (whatItMightContain) != -1);
|
||||
}
|
||||
function stringCountFields (s, chdelim) {
|
||||
var ct = 1;
|
||||
if (s.length == 0) {
|
||||
return (0);
|
||||
}
|
||||
for (var i = 0; i < s.length; i++) {
|
||||
if (s [i] == chdelim) {
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
return (ct)
|
||||
}
|
||||
function stringNthField (s, chdelim, n) {
|
||||
var splits = s.split (chdelim);
|
||||
if (splits.length >= n) {
|
||||
return splits [n-1];
|
||||
}
|
||||
return ("");
|
||||
}
|
||||
function stringLastField (s, chdelim) {
|
||||
var ct = stringCountFields (s, chdelim);
|
||||
if (ct == 0) { //8/31/14 by DW
|
||||
return (s);
|
||||
}
|
||||
return (stringNthField (s, chdelim, ct));
|
||||
}
|
||||
function multipleReplaceAll (s, adrTable, flCaseSensitive, startCharacters, endCharacters) {
|
||||
if(flCaseSensitive===undefined){
|
||||
flCaseSensitive = false;
|
||||
}
|
||||
if(startCharacters===undefined){
|
||||
startCharacters="";
|
||||
}
|
||||
if(endCharacters===undefined){
|
||||
endCharacters="";
|
||||
}
|
||||
for( var item in adrTable){
|
||||
var replacementValue = adrTable[item];
|
||||
var regularExpressionModifier = "g";
|
||||
if(!flCaseSensitive){
|
||||
regularExpressionModifier = "gi";
|
||||
}
|
||||
var regularExpressionString = (startCharacters+item+endCharacters).replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
|
||||
var regularExpression = new RegExp(regularExpressionString, regularExpressionModifier);
|
||||
s = s.replace(regularExpression, replacementValue);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
function httpExt2MIME (ext) { //12/24/14 by DW
|
||||
var lowerext = ext.toLowerCase ();
|
||||
var map = {
|
||||
"au": "audio/basic",
|
||||
"avi": "application/x-msvideo",
|
||||
"bin": "application/x-macbinary",
|
||||
"css": "text/css",
|
||||
"dcr": "application/x-director",
|
||||
"dir": "application/x-director",
|
||||
"dll": "application/octet-stream",
|
||||
"doc": "application/msword",
|
||||
"dtd": "text/dtd",
|
||||
"dxr": "application/x-director",
|
||||
"exe": "application/octet-stream",
|
||||
"fatp": "text/html",
|
||||
"ftsc": "text/html",
|
||||
"fttb": "text/html",
|
||||
"gif": "image/gif",
|
||||
"gz": "application/x-gzip",
|
||||
"hqx": "application/mac-binhex40",
|
||||
"htm": "text/html",
|
||||
"html": "text/html",
|
||||
"jpeg": "image/jpeg",
|
||||
"jpg": "image/jpeg",
|
||||
"js": "application/javascript",
|
||||
"mid": "audio/x-midi",
|
||||
"midi": "audio/x-midi",
|
||||
"mov": "video/quicktime",
|
||||
"mp3": "audio/mpeg",
|
||||
"pdf": "application/pdf",
|
||||
"png": "image/png",
|
||||
"ppt": "application/mspowerpoint",
|
||||
"ps": "application/postscript",
|
||||
"ra": "audio/x-pn-realaudio",
|
||||
"ram": "audio/x-pn-realaudio",
|
||||
"sit": "application/x-stuffit",
|
||||
"sys": "application/octet-stream",
|
||||
"tar": "application/x-tar",
|
||||
"text": "text/plain",
|
||||
"txt": "text/plain",
|
||||
"wav": "audio/x-wav",
|
||||
"wrl": "x-world/x-vrml",
|
||||
"xml": "text/xml",
|
||||
"zip": "application/zip"
|
||||
};
|
||||
for (x in map) {
|
||||
if (x.toLowerCase () == lowerext) {
|
||||
return (map [x]);
|
||||
}
|
||||
}
|
||||
return ("text/plain");
|
||||
}
|
||||
function httpReadUrl (url, callback) {
|
||||
request (url, function (error, response, body) {
|
||||
if (!error && (response.statusCode == 200)) {
|
||||
callback (body)
|
||||
}
|
||||
});
|
||||
}
|
||||
function fsSureFilePath (path, callback) {
|
||||
var splits = path.split ("/"), path = "";
|
||||
if (splits.length > 0) {
|
||||
function doLevel (levelnum) {
|
||||
if (levelnum < (splits.length - 1)) {
|
||||
path += splits [levelnum] + "/";
|
||||
fs.exists (path, function (flExists) {
|
||||
if (flExists) {
|
||||
doLevel (levelnum + 1);
|
||||
}
|
||||
else {
|
||||
fs.mkdir (path, undefined, function () {
|
||||
doLevel (levelnum + 1);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (callback != undefined) {
|
||||
callback ();
|
||||
}
|
||||
}
|
||||
}
|
||||
doLevel (0);
|
||||
}
|
||||
else {
|
||||
if (callback != undefined) {
|
||||
callback ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeStats (fname, stats) {
|
||||
fsSureFilePath (fname, function () {
|
||||
fs.writeFile (fname, jsonStringify (stats), function (err) {
|
||||
if (err) {
|
||||
console.log ("writeStats: error == " + err.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function readStats (f, stats, callback) {
|
||||
fs.exists (f, function (flExists) {
|
||||
if (flExists) {
|
||||
fs.readFile (f, function (err, data) {
|
||||
if (err) {
|
||||
console.log ("readStats: error reading file " + f + " == " + err.message)
|
||||
}
|
||||
else {
|
||||
var storedStats = JSON.parse (data.toString ());
|
||||
for (var x in storedStats) {
|
||||
stats [x] = storedStats [x];
|
||||
}
|
||||
writeStats (f, stats);
|
||||
}
|
||||
if (callback != undefined) {
|
||||
callback ();
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
writeStats (f, stats);
|
||||
if (callback != undefined) {
|
||||
callback ();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function getMarkdownTemplate (callback) {
|
||||
fs.readFile (mdTemplatePath, function (err, data) {
|
||||
if (err) {
|
||||
httpReadUrl (urlDefaultTemplate, function (s) {
|
||||
fs.writeFile (mdTemplatePath, s, function (err) {
|
||||
if (callback != undefined) {
|
||||
callback (s);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (callback != undefined) {
|
||||
callback (data.toString ());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function checkPathForIllegalChars (path) {
|
||||
function isIllegal (ch) {
|
||||
if (isAlpha (ch) || isNumeric (ch)) {
|
||||
return (false);
|
||||
}
|
||||
switch (ch) {
|
||||
case "/": case "_": case "-": case ".": case " ":
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
for (var i = 0; i < path.length; i++) {
|
||||
if (isIllegal (path [i])) {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
if (stringContains (path, "./")) {
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
function handleHttpRequest (httpRequest, httpResponse) {
|
||||
function return404 () {
|
||||
httpResponse.writeHead (404, {"Content-Type": "text/plain"});
|
||||
httpResponse.end ("The file was not found.");
|
||||
}
|
||||
|
||||
function findIndexFile (folder, callback) {
|
||||
fs.readdir (folder, function (err, list) {
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var fname = list [i];
|
||||
if (stringCountFields (fname, ".") == 2) { //something like xxx.yyy
|
||||
if (stringNthField (fname, ".", 1).toLowerCase () == pageParkPrefs.indexFilename) { //something like index.wtf
|
||||
callback (folder + fname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return404 ();
|
||||
});
|
||||
}
|
||||
function serveFile (f) {
|
||||
fs.readFile (f, function (err, data) {
|
||||
if (err) {
|
||||
return404 ();
|
||||
}
|
||||
else {
|
||||
var ext = stringLastField (f, ".").toLowerCase (), type = httpExt2MIME (ext);
|
||||
switch (ext) {
|
||||
case "js":
|
||||
try {
|
||||
var val = eval (data.toString ());
|
||||
httpResponse.writeHead (200, {"Content-Type": "text/html"});
|
||||
httpResponse.end (val.toString ());
|
||||
}
|
||||
catch (err) {
|
||||
httpResponse.writeHead (500, {"Content-Type": "text/plain"});
|
||||
httpResponse.end ("Error running " + parsedUrl.pathname + ": \"" + err.message + "\"");
|
||||
}
|
||||
break;
|
||||
case "md":
|
||||
getMarkdownTemplate (function (theTemplate) {
|
||||
var mdtext = data.toString (), pagetable = new Object ();
|
||||
pagetable.bodytext = marked (mdtext);
|
||||
pagetable.title = stringLastField (f, "/");
|
||||
var s = multipleReplaceAll (theTemplate, pagetable, false, "[%", "%]");
|
||||
httpResponse.writeHead (200, {"Content-Type": "text/html"});
|
||||
httpResponse.end (s);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
httpResponse.writeHead (200, {"Content-Type": type});
|
||||
httpResponse.end (data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
var parsedUrl = urlpack.parse (httpRequest.url, true), host, port;
|
||||
var lowerpath = parsedUrl.pathname.toLowerCase (), now = new Date ();
|
||||
//set host, port
|
||||
host = httpRequest.headers.host;
|
||||
if (stringContains (host, ":")) {
|
||||
port = stringNthField (host, ":", 2);
|
||||
host = stringNthField (host, ":", 1);
|
||||
}
|
||||
else {
|
||||
port = 80;
|
||||
}
|
||||
console.log (now.toLocaleTimeString () + " " + httpRequest.method + " " + host + ":" + port + " " + lowerpath);
|
||||
switch (lowerpath) {
|
||||
case "/version":
|
||||
httpResponse.writeHead (200, {"Content-Type": "text/plain"});
|
||||
httpResponse.end (myVersion);
|
||||
break;
|
||||
case "/now":
|
||||
httpResponse.writeHead (200, {"Content-Type": "text/plain"});
|
||||
httpResponse.end (now.toString ());
|
||||
break;
|
||||
default: //see if it's a path in the domains folder, if not 404
|
||||
var f = domainsPath + host + parsedUrl.pathname;
|
||||
if (checkPathForIllegalChars (f)) {
|
||||
fsSureFilePath (f, function () { //make sure domains folder exists
|
||||
fs.stat (f, function (err, stats) {
|
||||
if (err) {
|
||||
return404 ();
|
||||
}
|
||||
else {
|
||||
if (stats.isDirectory ()) {
|
||||
if (!endsWith (f, "/")) {
|
||||
f += "/";
|
||||
}
|
||||
findIndexFile (f, function (findex) {
|
||||
serveFile (findex);
|
||||
});
|
||||
}
|
||||
else {
|
||||
serveFile (f);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
httpResponse.writeHead (500, {"Content-Type": "text/plain"});
|
||||
httpResponse.end ("The file name contains illegal characters.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (tryError) {
|
||||
httpResponse.writeHead (500, {"Content-Type": "text/plain"});
|
||||
httpResponse.end (tryError.message);
|
||||
}
|
||||
}
|
||||
|
||||
function startup () {
|
||||
readStats (fnamePrefs, pageParkPrefs, function () {
|
||||
readStats (fnameStats, pageParkStats, function () {
|
||||
var now = new Date ();
|
||||
console.log (myProductName + " v" + myVersion + ".");
|
||||
pageParkStats.ctStarts++;
|
||||
pageParkStats.whenLastStart = now;
|
||||
writeStats (fnameStats, pageParkStats);
|
||||
http.createServer (handleHttpRequest).listen (pageParkPrefs.myPort);
|
||||
});
|
||||
});
|
||||
}
|
||||
startup ();
|
||||
var myVersion = "0.45", myProductName = "pagePark";
|
||||
|
||||
//The MIT License (MIT)
|
||||
|
||||
//Copyright (c) 2014 Dave Winer
|
||||
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
|
||||
//The above copyright notice and this permission notice shall be included in all
|
||||
//copies or substantial portions of the Software.
|
||||
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
//SOFTWARE.
|
||||
|
||||
var fs = require ("fs");
|
||||
var request = require ("request");
|
||||
var urlpack = require ("url");
|
||||
var http = require ("http");
|
||||
var marked = require ("marked");
|
||||
var dns = require ("dns");
|
||||
|
||||
var pageParkPrefs = {
|
||||
myPort: 80,
|
||||
indexFilename: "index"
|
||||
};
|
||||
var fnamePrefs = "prefs/prefs.json";
|
||||
|
||||
var pageParkStats = {
|
||||
ctStarts: 0,
|
||||
whenLastStart: new Date (0),
|
||||
ctHits: 0, ctHitsToday: 0,
|
||||
whenLastHit: new Date (0),
|
||||
hitsByDomain: {}
|
||||
};
|
||||
var fnameStats = "prefs/stats.json", flStatsDirty = false;
|
||||
|
||||
var domainsPath = "domains/";
|
||||
|
||||
var mdTemplatePath = "prefs/mdTemplate.txt";
|
||||
var urlDefaultTemplate = "http://fargo.io/code/pagepark/defaultmarkdowntemplate.txt";
|
||||
|
||||
//routines from utils.js, fs.js
|
||||
function getBoolean (val) {
|
||||
switch (typeof (val)) {
|
||||
case "string":
|
||||
if (val.toLowerCase () == "true") {
|
||||
return (true);
|
||||
}
|
||||
break;
|
||||
case "boolean":
|
||||
return (val);
|
||||
break;
|
||||
case "number":
|
||||
if (val != 0) {
|
||||
return (true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
function isAlpha (ch) {
|
||||
return (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')));
|
||||
}
|
||||
function isNumeric (ch) {
|
||||
return ((ch >= '0') && (ch <= '9'));
|
||||
}
|
||||
function jsonStringify (jstruct) {
|
||||
return (JSON.stringify (jstruct, undefined, 4));
|
||||
}
|
||||
function secondsSince (when) {
|
||||
var now = new Date ();
|
||||
when = new Date (when);
|
||||
return ((now - when) / 1000);
|
||||
}
|
||||
function sameDay (d1, d2) { //returns true if the two dates are on the same day
|
||||
d1 = new Date (d1);
|
||||
d2 = new Date (d2);
|
||||
return ((d1.getFullYear () == d2.getFullYear ()) && (d1.getMonth () == d2.getMonth ()) && (d1.getDate () == d2.getDate ()));
|
||||
}
|
||||
function endsWith (s, possibleEnding, flUnicase) {
|
||||
if ((s == undefined) || (s.length == 0)) {
|
||||
return (false);
|
||||
}
|
||||
var ixstring = s.length - 1;
|
||||
if (flUnicase == undefined) {
|
||||
flUnicase = true;
|
||||
}
|
||||
if (flUnicase) {
|
||||
for (var i = possibleEnding.length - 1; i >= 0; i--) {
|
||||
if (s [ixstring--].toLowerCase () != possibleEnding [i].toLowerCase ()) {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var i = possibleEnding.length - 1; i >= 0; i--) {
|
||||
if (s [ixstring--] != possibleEnding [i]) {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
function stringContains (s, whatItMightContain, flUnicase) {
|
||||
if (flUnicase == undefined) {
|
||||
flUnicase = true;
|
||||
}
|
||||
if (flUnicase) {
|
||||
s = s.toLowerCase ();
|
||||
whatItMightContain = whatItMightContain.toLowerCase ();
|
||||
}
|
||||
return (s.indexOf (whatItMightContain) != -1);
|
||||
}
|
||||
function stringCountFields (s, chdelim) {
|
||||
var ct = 1;
|
||||
if (s.length == 0) {
|
||||
return (0);
|
||||
}
|
||||
for (var i = 0; i < s.length; i++) {
|
||||
if (s [i] == chdelim) {
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
return (ct)
|
||||
}
|
||||
function stringNthField (s, chdelim, n) {
|
||||
var splits = s.split (chdelim);
|
||||
if (splits.length >= n) {
|
||||
return splits [n-1];
|
||||
}
|
||||
return ("");
|
||||
}
|
||||
function stringLastField (s, chdelim) {
|
||||
var ct = stringCountFields (s, chdelim);
|
||||
if (ct == 0) { //8/31/14 by DW
|
||||
return (s);
|
||||
}
|
||||
return (stringNthField (s, chdelim, ct));
|
||||
}
|
||||
function multipleReplaceAll (s, adrTable, flCaseSensitive, startCharacters, endCharacters) {
|
||||
if(flCaseSensitive===undefined){
|
||||
flCaseSensitive = false;
|
||||
}
|
||||
if(startCharacters===undefined){
|
||||
startCharacters="";
|
||||
}
|
||||
if(endCharacters===undefined){
|
||||
endCharacters="";
|
||||
}
|
||||
for( var item in adrTable){
|
||||
var replacementValue = adrTable[item];
|
||||
var regularExpressionModifier = "g";
|
||||
if(!flCaseSensitive){
|
||||
regularExpressionModifier = "gi";
|
||||
}
|
||||
var regularExpressionString = (startCharacters+item+endCharacters).replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
|
||||
var regularExpression = new RegExp(regularExpressionString, regularExpressionModifier);
|
||||
s = s.replace(regularExpression, replacementValue);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
function httpExt2MIME (ext) { //12/24/14 by DW
|
||||
var lowerext = ext.toLowerCase ();
|
||||
var map = {
|
||||
"au": "audio/basic",
|
||||
"avi": "application/x-msvideo",
|
||||
"bin": "application/x-macbinary",
|
||||
"css": "text/css",
|
||||
"dcr": "application/x-director",
|
||||
"dir": "application/x-director",
|
||||
"dll": "application/octet-stream",
|
||||
"doc": "application/msword",
|
||||
"dtd": "text/dtd",
|
||||
"dxr": "application/x-director",
|
||||
"exe": "application/octet-stream",
|
||||
"fatp": "text/html",
|
||||
"ftsc": "text/html",
|
||||
"fttb": "text/html",
|
||||
"gif": "image/gif",
|
||||
"gz": "application/x-gzip",
|
||||
"hqx": "application/mac-binhex40",
|
||||
"htm": "text/html",
|
||||
"html": "text/html",
|
||||
"jpeg": "image/jpeg",
|
||||
"jpg": "image/jpeg",
|
||||
"js": "application/javascript",
|
||||
"mid": "audio/x-midi",
|
||||
"midi": "audio/x-midi",
|
||||
"mov": "video/quicktime",
|
||||
"mp3": "audio/mpeg",
|
||||
"pdf": "application/pdf",
|
||||
"png": "image/png",
|
||||
"ppt": "application/mspowerpoint",
|
||||
"ps": "application/postscript",
|
||||
"ra": "audio/x-pn-realaudio",
|
||||
"ram": "audio/x-pn-realaudio",
|
||||
"sit": "application/x-stuffit",
|
||||
"sys": "application/octet-stream",
|
||||
"tar": "application/x-tar",
|
||||
"text": "text/plain",
|
||||
"txt": "text/plain",
|
||||
"wav": "audio/x-wav",
|
||||
"wrl": "x-world/x-vrml",
|
||||
"xml": "text/xml",
|
||||
"zip": "application/zip"
|
||||
};
|
||||
for (x in map) {
|
||||
if (x.toLowerCase () == lowerext) {
|
||||
return (map [x]);
|
||||
}
|
||||
}
|
||||
return ("text/plain");
|
||||
}
|
||||
function httpReadUrl (url, callback) {
|
||||
request (url, function (error, response, body) {
|
||||
if (!error && (response.statusCode == 200)) {
|
||||
callback (body)
|
||||
}
|
||||
});
|
||||
}
|
||||
function fsSureFilePath (path, callback) {
|
||||
var splits = path.split ("/"), path = "";
|
||||
if (splits.length > 0) {
|
||||
function doLevel (levelnum) {
|
||||
if (levelnum < (splits.length - 1)) {
|
||||
path += splits [levelnum] + "/";
|
||||
fs.exists (path, function (flExists) {
|
||||
if (flExists) {
|
||||
doLevel (levelnum + 1);
|
||||
}
|
||||
else {
|
||||
fs.mkdir (path, undefined, function () {
|
||||
doLevel (levelnum + 1);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (callback != undefined) {
|
||||
callback ();
|
||||
}
|
||||
}
|
||||
}
|
||||
doLevel (0);
|
||||
}
|
||||
else {
|
||||
if (callback != undefined) {
|
||||
callback ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeStats (fname, stats) {
|
||||
fsSureFilePath (fname, function () {
|
||||
fs.writeFile (fname, jsonStringify (stats), function (err) {
|
||||
if (err) {
|
||||
console.log ("writeStats: error == " + err.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function readStats (f, stats, callback) {
|
||||
fs.exists (f, function (flExists) {
|
||||
if (flExists) {
|
||||
fs.readFile (f, function (err, data) {
|
||||
if (err) {
|
||||
console.log ("readStats: error reading file " + f + " == " + err.message)
|
||||
}
|
||||
else {
|
||||
var storedStats = JSON.parse (data.toString ());
|
||||
for (var x in storedStats) {
|
||||
stats [x] = storedStats [x];
|
||||
}
|
||||
writeStats (f, stats);
|
||||
}
|
||||
if (callback != undefined) {
|
||||
callback ();
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
writeStats (f, stats);
|
||||
if (callback != undefined) {
|
||||
callback ();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function getMarkdownTemplate (callback) {
|
||||
fs.readFile (mdTemplatePath, function (err, data) {
|
||||
if (err) {
|
||||
httpReadUrl (urlDefaultTemplate, function (s) {
|
||||
fs.writeFile (mdTemplatePath, s, function (err) {
|
||||
if (callback != undefined) {
|
||||
callback (s);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (callback != undefined) {
|
||||
callback (data.toString ());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function checkPathForIllegalChars (path) {
|
||||
function isIllegal (ch) {
|
||||
if (isAlpha (ch) || isNumeric (ch)) {
|
||||
return (false);
|
||||
}
|
||||
switch (ch) {
|
||||
case "/": case "_": case "-": case ".": case " ":
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
for (var i = 0; i < path.length; i++) {
|
||||
if (isIllegal (path [i])) {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
if (stringContains (path, "./")) {
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
function everySecond () {
|
||||
if (flStatsDirty) {
|
||||
writeStats (fnameStats, pageParkStats);
|
||||
flStatsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleHttpRequest (httpRequest, httpResponse) {
|
||||
function return404 () {
|
||||
httpResponse.writeHead (404, {"Content-Type": "text/plain"});
|
||||
httpResponse.end ("The file was not found.");
|
||||
}
|
||||
|
||||
function findIndexFile (folder, callback) {
|
||||
fs.readdir (folder, function (err, list) {
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var fname = list [i];
|
||||
if (stringCountFields (fname, ".") == 2) { //something like xxx.yyy
|
||||
if (stringNthField (fname, ".", 1).toLowerCase () == pageParkPrefs.indexFilename) { //something like index.wtf
|
||||
callback (folder + fname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return404 ();
|
||||
});
|
||||
}
|
||||
function serveFile (f) {
|
||||
fs.readFile (f, function (err, data) {
|
||||
if (err) {
|
||||
return404 ();
|
||||
}
|
||||
else {
|
||||
var ext = stringLastField (f, ".").toLowerCase (), type = httpExt2MIME (ext);
|
||||
switch (ext) {
|
||||
case "js":
|
||||
try {
|
||||
var val = eval (data.toString ());
|
||||
httpResponse.writeHead (200, {"Content-Type": "text/html"});
|
||||
httpResponse.end (val.toString ());
|
||||
}
|
||||
catch (err) {
|
||||
httpResponse.writeHead (500, {"Content-Type": "text/plain"});
|
||||
httpResponse.end ("Error running " + parsedUrl.pathname + ": \"" + err.message + "\"");
|
||||
}
|
||||
break;
|
||||
case "md":
|
||||
getMarkdownTemplate (function (theTemplate) {
|
||||
var mdtext = data.toString (), pagetable = new Object ();
|
||||
pagetable.bodytext = marked (mdtext);
|
||||
pagetable.title = stringLastField (f, "/");
|
||||
var s = multipleReplaceAll (theTemplate, pagetable, false, "[%", "%]");
|
||||
httpResponse.writeHead (200, {"Content-Type": "text/html"});
|
||||
httpResponse.end (s);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
httpResponse.writeHead (200, {"Content-Type": type});
|
||||
httpResponse.end (data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
var parsedUrl = urlpack.parse (httpRequest.url, true), host, lowerhost, port, referrer;
|
||||
var lowerpath = parsedUrl.pathname.toLowerCase (), now = new Date ();
|
||||
//set host, port
|
||||
host = httpRequest.headers.host;
|
||||
if (stringContains (host, ":")) {
|
||||
port = stringNthField (host, ":", 2);
|
||||
host = stringNthField (host, ":", 1);
|
||||
}
|
||||
else {
|
||||
port = 80;
|
||||
}
|
||||
lowerhost = host.toLowerCase ();
|
||||
//set referrer
|
||||
referrer = httpRequest.headers.referer;
|
||||
if (referrer == undefined) {
|
||||
referrer = "";
|
||||
}
|
||||
|
||||
//stats
|
||||
//hits by domain
|
||||
if (pageParkStats.hitsByDomain [lowerhost] == undefined) {
|
||||
pageParkStats.hitsByDomain [lowerhost] = 1;
|
||||
}
|
||||
else {
|
||||
pageParkStats.hitsByDomain [lowerhost]++;
|
||||
}
|
||||
//hits today
|
||||
if (!sameDay (now, pageParkStats.whenLastHit)) { //day rollover
|
||||
pageParkStats.ctHitsToday = 0;
|
||||
}
|
||||
pageParkStats.ctHits++;
|
||||
pageParkStats.ctHitsToday++;
|
||||
pageParkStats.whenLastHit = now;
|
||||
flStatsDirty = true;
|
||||
|
||||
//log the request
|
||||
dns.reverse (httpRequest.connection.remoteAddress, function (err, domains) {
|
||||
var client = httpRequest.connection.remoteAddress;
|
||||
if (!err) {
|
||||
if (domains.length > 0) {
|
||||
client = domains [0];
|
||||
}
|
||||
}
|
||||
console.log (now.toLocaleTimeString () + " " + httpRequest.method + " " + host + ":" + port + " " + lowerpath + " " + referrer + " " + client);
|
||||
});
|
||||
|
||||
switch (lowerpath) {
|
||||
case "/version":
|
||||
httpResponse.writeHead (200, {"Content-Type": "text/plain"});
|
||||
httpResponse.end (myVersion);
|
||||
break;
|
||||
case "/now":
|
||||
httpResponse.writeHead (200, {"Content-Type": "text/plain"});
|
||||
httpResponse.end (now.toString ());
|
||||
break;
|
||||
case "/status":
|
||||
var status = {
|
||||
prefs: pageParkPrefs,
|
||||
status: pageParkStats
|
||||
}
|
||||
httpResponse.writeHead (200, {"Content-Type": "text/plain"});
|
||||
httpResponse.end (jsonStringify (status));
|
||||
break;
|
||||
default: //see if it's a path in the domains folder, if not 404
|
||||
var f = domainsPath + host + parsedUrl.pathname;
|
||||
if (checkPathForIllegalChars (f)) {
|
||||
fsSureFilePath (domainsPath, function () { //make sure domains folder exists
|
||||
fs.stat (f, function (err, stats) {
|
||||
if (err) {
|
||||
return404 ();
|
||||
}
|
||||
else {
|
||||
if (stats.isDirectory ()) {
|
||||
if (!endsWith (f, "/")) {
|
||||
f += "/";
|
||||
}
|
||||
findIndexFile (f, function (findex) {
|
||||
serveFile (findex);
|
||||
});
|
||||
}
|
||||
else {
|
||||
serveFile (f);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
httpResponse.writeHead (500, {"Content-Type": "text/plain"});
|
||||
httpResponse.end ("The file name contains illegal characters.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (tryError) {
|
||||
httpResponse.writeHead (500, {"Content-Type": "text/plain"});
|
||||
httpResponse.end (tryError.message);
|
||||
}
|
||||
}
|
||||
|
||||
function startup () {
|
||||
readStats (fnamePrefs, pageParkPrefs, function () {
|
||||
readStats (fnameStats, pageParkStats, function () {
|
||||
var now = new Date ();
|
||||
console.log (myProductName + " v" + myVersion + ".");
|
||||
pageParkStats.ctStarts++;
|
||||
pageParkStats.whenLastStart = now;
|
||||
flStatsDirty = true;
|
||||
http.createServer (handleHttpRequest).listen (pageParkPrefs.myPort);
|
||||
setInterval (everySecond, 1000);
|
||||
});
|
||||
});
|
||||
}
|
||||
startup ();
|
||||
|
Loading…
Reference in New Issue