Last active
December 12, 2015 02:58
-
-
Save tleunen/4702769 to your computer and use it in GitHub Desktop.
Simple static files webserver in NodeJS (with SSL in comments)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var http = require('http'), | |
https = require('https'), | |
fs = require('fs'), | |
url = require('url'); | |
/* | |
var options = { | |
key: fs.readFileSync('ssl/server.key'), | |
cert: fs.readFileSync('ssl/server.crt') | |
}; | |
*/ | |
var mimeTypes = { | |
"txt": "text/plain", | |
"html": "text/html", | |
"css": "text/css", | |
"jpeg": "image/jpeg", | |
"jpg": "image/jpeg", | |
"png": "image/png", | |
"js": "application/javascript", | |
"json": "application/json", | |
"xml": "application/xml" | |
}; | |
var dirSpacesBeforeDate = 51; | |
var dirSpacesBeforeSize = 9; | |
var dirMonths = 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','); | |
http.createServer(function(req, res) { | |
serveFiles(req, res); | |
}).listen(80); | |
/* | |
https.createServer(options, function(req, res) { | |
serveFiles(req, res); | |
}).listen(443); | |
*/ | |
function serveFiles(req, res) { | |
var path = url.parse(req.url).pathname; | |
path = ('./' + path).replace('//', '/'); | |
// prevent access to file starting with . | |
var parts = path.split('/'); | |
if(parts[parts.length-1].charAt(0) === '.') | |
return sendForbidden(req, res, path); | |
fs.stat(path, function(err, stats) { | |
if(err) return sendNotFound(req, res, path); | |
if(stats.isDirectory()) { | |
if(path.charAt(path.length-1) !== '/') { | |
return sendRedirect(req, res, path + '/'); | |
} | |
fs.stat(path + 'index.html', function(err2, stats2) { | |
if(err2) return sendDirectory(req, res, path); | |
return sendFile(req, res, path + '/index.html'); | |
}); | |
} | |
else | |
return sendFile(req, res, path); | |
}); | |
} | |
function escapeHtml(value) { | |
return value.toString(). | |
replace('<', '<'). | |
replace('>', '>'). | |
replace('"', '"'); | |
} | |
function zeroFill(value) { | |
return ((value < 10) ? '0' : '') + value; | |
} | |
function convertSize(value) { | |
if(value > 1000000000) return ((value*0.000000001) | 0) + 'G'; | |
if(value > 1000000) return ((value*0.000001) | 0) + 'M'; | |
if(value > 10000) return ((value*0.001) | 0) + 'K'; | |
return '' + value; | |
} | |
function sendFile(req, res, path) { | |
var extension = path.split('.').pop(); | |
var contentType = mimeTypes[extension] || 'text/plain'; | |
res.writeHead(200, {'Content-Type': contentType}); | |
var fileStream = fs.createReadStream(path); | |
fileStream.pipe(res); | |
} | |
function sendRedirect(req, res, path) { | |
res.writeHead(301, { | |
'Content-Type': 'text/html', | |
'Location': path | |
}); | |
res.end(); | |
} | |
function sendServerError(req, res, error) { | |
console.log('500 Internal Server Error: ' + error); | |
res.writeHead(500, {'Content-Type': 'text/html'}); | |
res.writeo('<!DOCTYPE html>\n'); | |
res.write('<html><head>\n'); | |
res.write('<title>500 Internal Server Error</title>\n'); | |
res.write('</head><body>\n'); | |
res.write('<h1>500 Internal Server Error</h1>\n'); | |
res.write('<pre>' + escapeHtml(error) + '</pre>\n'); | |
res.write('</body></html>\n'); | |
res.end(); | |
} | |
function sendForbidden(req, res, path) { | |
console.log('403 Forbidden: ' + path); | |
res.writeHead(403, {'Content-Type': 'text/html'}); | |
res.write('<!DOCTYPE html>\n'); | |
res.write('<html><head>\n'); | |
res.write('<title>403 Forbidden</title>\n'); | |
res.write('</head><body>\n'); | |
res.write('<h1>403 Forbidden</h1>\n'); | |
res.write('<p>You don\'t have permission to access' + escapeHtml(path) + ' on this server.</p>\n'); | |
res.write('</body></html>\n'); | |
res.end(); | |
} | |
function sendNotFound(req, res, path) { | |
console.log('404 Not Found: ' + path); | |
res.writeHead(404, {'Content-Type': 'text/html'}); | |
res.write('<!DOCTYPE html>\n'); | |
res.write('<html><head>\n'); | |
res.write('<title>404 Not Found</title>\n'); | |
res.write('</head><body>\n'); | |
res.write('<h1>404 Not Found</h1>\n'); | |
res.write('<p>The requested URL ' + escapeHtml(path) + ' was not found on this server.\n'); | |
res.write('</body></html>\n'); | |
res.end(); | |
} | |
function sendDirectory(req, res, path) { | |
fs.readdir(path, function(err, files) { | |
if(err) return sendServerError(req, res, err); | |
if(files.length === 0) | |
return sendDirectoryIndex(req, res, path, []); | |
var remaining = files.length; | |
files.forEach(function(filename, idx) { | |
fs.stat(path + '/' + filename, function(err, stats) { | |
if(err) return sendServerError(req, res, err); | |
files[idx] = { | |
name: files[idx], | |
date: stats.mtime, | |
size: '-' | |
}; | |
if(stats.isDirectory()) files[idx].name += '/'; | |
else files[idx].size = stats.size; | |
if(--remaining === 0) | |
return sendDirectoryIndex(req, res, path, files); | |
}); | |
}); | |
}); | |
} | |
function sendDirectoryIndex(req, res, path, files) { | |
res.writeHead(200, {'Content-Type': 'text/html'}); | |
res.write('<!DOCTYPE html>\n'); | |
res.write('<html><head>\n'); | |
res.write('<title>Index of ' + escapeHtml(path) + '</title>\n'); | |
res.write('</head><body>\n'); | |
res.write('<h1>Index of ' + escapeHtml(path) + '</h1>\n'); | |
res.write('<hr><pre>\n'); | |
res.write('<a href="../">../</a>\n'); | |
files.forEach(function(file, idx) { | |
var name = escapeHtml(file.name), | |
displayName = name.substr(0, dirSpacesBeforeDate-1), | |
spBeforeDate = dirSpacesBeforeDate - displayName.length; | |
res.write('<a href="' + name + '">' + displayName + '</a>'); | |
while(--spBeforeDate) res.write(' '); | |
var day = zeroFill(file.date.getDate()), | |
month = dirMonths[file.date.getMonth()], | |
hours = zeroFill(file.date.getHours()), | |
min = zeroFill(file.date.getMinutes()); | |
var date = day + '-' + month + '-' + file.date.getFullYear() + | |
' ' + hours + ':' + min; | |
res.write(date); | |
var size = convertSize(file.size), | |
spBeforeSize = dirSpacesBeforeSize - size.length; | |
while(spBeforeSize--) res.write(' '); | |
res.write(size + '\n'); | |
}); | |
res.write('</pre><hr></body></html>\n'); | |
res.end(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment