Last active
September 24, 2015 06:28
-
-
Save eventualbuddha/706182 to your computer and use it in GitHub Desktop.
simple node.js file server
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
serve.js: serve.jsnext.js | |
babel serve.jsnext.js -o serve.js |
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
#!/usr/bin/env node | |
// Serve files out of a specific directory and its subdirectories. | |
// | |
// $ cd test-project | |
// $ ls | |
// README | |
// $ cat README | |
// Hello World. | |
// $ serve # start the server | |
// | |
// # elsewhere, hit the server (or in the browser) | |
// $ curl http://localhost:9090/README | |
// Hello World. | |
// | |
'use strict'; | |
var fs = require('fs'); | |
var path = require('path'); | |
var args = process.argv.slice(2); | |
// default arg values | |
var root = '.'; | |
var host = '0.0.0.0'; | |
var port = 9090; | |
var usage = function usage(error) { | |
var $0 = path.basename(process.argv[1]); | |
if (error) { | |
console.error($0 + ': error: ' + error); | |
} | |
console.error('Usage: ' + $0 + ' [-h HOST] [-p PORT] [-C DIR]'); | |
console.error(""); | |
console.error(' -h, --host Run the file server on this host (defaults to ' + host + ')'); | |
console.error(' -p, --port Run the file server on this port (defaults to ' + port + ')'); | |
console.error(' -C, --root Serve files using this directory as the root (defaults to ' + root + ')'); | |
return process.exit(error && 1 || 0); | |
}; | |
for (var i = 0; 0 < args.length ? i < args.length : i > args.length; 0 < args.length ? i++ : i--) { | |
var match; | |
var arg = args[i]; | |
if (match = arg.match(/^(--\w+[\w-])(?:=(.*))?$/)) { | |
// --port=1234, --port, etc | |
var key = match[1]; | |
var value = match[2]; | |
} else { | |
// -p, 1234, etc | |
key = arg; | |
value = undefined; | |
} | |
switch (key) { | |
case '-h':case '--host': | |
var hostArg = value || args[++i]; | |
if (hostArg === undefined) { | |
usage('expected host after ' + key); | |
} | |
host = hostArg; | |
break; | |
case '-p':case '--port': | |
var portArg = value || args[++i]; | |
if (portArg === undefined) { | |
usage('expected port number after ' + key); | |
} | |
port = Number(portArg); | |
break; | |
case '-C':case '--root': | |
var rootArg = value || args[++i]; | |
if (rootArg === undefined) { | |
usage('expected root dir after ' + key); | |
} | |
root = rootArg; | |
break; | |
case '-h':case '--help': | |
usage(); | |
break; | |
default: | |
usage('unrecognized argument ' + arg); | |
} | |
} | |
var http = require('http'); | |
var url = require('url'); | |
fs = require('fs'); | |
var contentTypeMap = { txt: 'text/plain', | |
html: 'text/html', | |
css: 'text/css', | |
xml: 'application/xml', | |
jpg: 'image/jpeg', | |
png: 'image/png', | |
tiff: 'image/tiff', | |
gif: 'image/gif', | |
js: 'application/javascript', | |
svg: 'image/svg+xml' }; | |
var contentTypeForPath = function contentTypeForPath(p) { | |
var ext = path.extname(p).substring(1).toLowerCase(); | |
if (ext in contentTypeMap) { | |
return contentTypeMap[ext]; | |
} else if (ext) { | |
return 'application/x-' + ext; | |
} else { | |
return contentTypeMap.txt; | |
} | |
}; | |
var toISO8601 = function toISO8601(date) { | |
var pad_two = function pad_two(n) { | |
return (n < 10 ? '0' : '') + n; | |
}; | |
var pad_three = function pad_three(n) { | |
return (n < 100 ? '0' : '') + (n < 10 ? '0' : '') + n; | |
}; | |
return [date.getUTCFullYear(), '-', pad_two(date.getUTCMonth() + 1), '-', pad_two(date.getUTCDate()), 'T', pad_two(date.getUTCHours()), ':', pad_two(date.getUTCMinutes()), ':', pad_two(date.getUTCSeconds()), '.', pad_three(date.getUTCMilliseconds()), 'Z'].join(''); | |
}; | |
process.chdir(root); | |
http.createServer(function (request, response) { | |
var write = function write(code, body, headers) { | |
var name; | |
headers || (headers = {}); | |
headers[name = 'Content-Type'] || (headers[name] = contentTypeMap.txt); | |
response.writeHead(code, headers); | |
response.end(body); | |
return console.log(toISO8601(new Date()) + ' ' + request.method + ' ' + request.url + ' ' + code + ' ' + (body || '').length); | |
}; | |
var serve = function serve(pathname) { | |
try { | |
if (pathname.indexOf('..') !== -1) { | |
write(404, "cannot ask for files with .. in the name\n"); | |
return; | |
} | |
// return a default page if they asked for the root | |
if (pathname === '') { | |
pathname = '.'; | |
} | |
return fs.exists(pathname, function (exists) { | |
if (!exists) { | |
write(404, "cannot find that file\n"); | |
return; | |
} | |
return fs.stat(pathname, function (err, stats) { | |
if (err) { | |
write(400, 'unable to read file information: ' + err + '\n'); | |
return; | |
} | |
// look for an index.html if they asked for a directory | |
if (stats.isDirectory()) { | |
if (pathname !== '.' && pathname.substring(pathname.length - 1, pathname.length) !== '/') { | |
write(301, '', { 'Location': pathname + '/' }); | |
} else { | |
serve(path.join(pathname, 'index.html')); | |
} | |
return; | |
} | |
return fs.readFile(pathname, function (err, data) { | |
if (err) { | |
write(400, 'unable to read file: ' + err + '\n'); | |
return; | |
} | |
return write(200, data, { 'Content-Type': contentTypeForPath(pathname) }); | |
}); | |
}); | |
}); | |
} catch (e) { | |
return write(500, e.toString()); | |
} | |
}; | |
return serve(url.parse(request.url).pathname.substring(1)); | |
}).listen(port, host); | |
console.log('** Serving files from ' + path.normalize(process.cwd()) + ' at http://' + host + ':' + port + '/. Ctrl+C to stop.'); |
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
#!/usr/bin/env node | |
// Serve files out of a specific directory and its subdirectories. | |
// | |
// $ cd test-project | |
// $ ls | |
// README | |
// $ cat README | |
// Hello World. | |
// $ serve # start the server | |
// | |
// # elsewhere, hit the server (or in the browser) | |
// $ curl http://localhost:9090/README | |
// Hello World. | |
// | |
var fs = require('fs'); | |
var path = require('path'); | |
var args = process.argv.slice(2); | |
// default arg values | |
var root = '.'; | |
var host = '0.0.0.0'; | |
var port = 9090; | |
var usage = function(error) { | |
var $0 = path.basename(process.argv[1]); | |
if (error) { console.error(`${$0}: error: ${error}`); } | |
console.error(`Usage: ${$0} [-h HOST] [-p PORT] [-C DIR]`); | |
console.error(""); | |
console.error(` -h, --host Run the file server on this host (defaults to ${host})`); | |
console.error(` -p, --port Run the file server on this port (defaults to ${port})`); | |
console.error(` -C, --root Serve files using this directory as the root (defaults to ${root})`); | |
return process.exit(error && 1 || 0); | |
}; | |
for (var i = 0; 0 < args.length ? i < args.length : i > args.length; 0 < args.length ? i++ : i--) { | |
var match; | |
var arg = args[i]; | |
if (match = arg.match(/^(--\w+[\w-])(?:=(.*))?$/)) { | |
// --port=1234, --port, etc | |
var key = match[1]; | |
var value = match[2]; | |
} else { | |
// -p, 1234, etc | |
key = arg; | |
value = undefined; | |
} | |
switch (key) { | |
case '-h': case '--host': | |
var hostArg = value || args[++i]; | |
if (hostArg === undefined) { | |
usage(`expected host after ${key}`); | |
} | |
host = hostArg; | |
break; | |
case '-p': case '--port': | |
var portArg = value || args[++i]; | |
if (portArg === undefined) { | |
usage(`expected port number after ${key}`); | |
} | |
port = Number(portArg); | |
break; | |
case '-C': case '--root': | |
var rootArg = value || args[++i]; | |
if (rootArg === undefined) { | |
usage(`expected root dir after ${key}`); | |
} | |
root = rootArg; | |
break; | |
case '-h': case '--help': | |
usage(); | |
break; | |
default: | |
usage(`unrecognized argument ${arg}`); | |
} | |
} | |
var http = require('http'); | |
var url = require('url'); | |
fs = require('fs'); | |
var contentTypeMap = | |
{txt: 'text/plain', | |
html: 'text/html', | |
css: 'text/css', | |
xml: 'application/xml', | |
jpg: 'image/jpeg', | |
png: 'image/png', | |
tiff: 'image/tiff', | |
gif: 'image/gif', | |
js: 'application/javascript', | |
svg: 'image/svg+xml'}; | |
var contentTypeForPath = function(p) { | |
var ext = path.extname(p).substring(1).toLowerCase(); | |
if (ext in contentTypeMap) { | |
return contentTypeMap[ext]; | |
} else if (ext) { | |
return `application/x-${ext}`; | |
} else { | |
return contentTypeMap.txt; | |
} | |
}; | |
var toISO8601 = function(date) { | |
var pad_two = function(n) { | |
return (n < 10 ? '0' : '') + n; | |
}; | |
var pad_three = function(n) { | |
return (n < 100 ? '0' : '') + (n < 10 ? '0' : '') + n; | |
}; | |
return [ | |
date.getUTCFullYear(), | |
'-', | |
pad_two(date.getUTCMonth() + 1), | |
'-', | |
pad_two(date.getUTCDate()), | |
'T', | |
pad_two(date.getUTCHours()), | |
':', | |
pad_two(date.getUTCMinutes()), | |
':', | |
pad_two(date.getUTCSeconds()), | |
'.', | |
pad_three(date.getUTCMilliseconds()), | |
'Z', | |
].join(''); | |
}; | |
process.chdir(root); | |
http.createServer(function(request, response) { | |
var write = function(code, body, headers) { | |
var name; | |
headers || (headers = {}); | |
headers[name = 'Content-Type'] || (headers[name] = contentTypeMap.txt); | |
response.writeHead(code, headers); | |
response.end(body); | |
return console.log(`${toISO8601(new Date())} ${request.method} ${request.url} ${code} ${(body || '').length}`); | |
}; | |
var serve = function(pathname) { | |
try { | |
if (pathname.indexOf('..') !== -1) { | |
write(404, "cannot ask for files with .. in the name\n"); | |
return; | |
} | |
// return a default page if they asked for the root | |
if (pathname === '') { pathname = '.'; } | |
return fs.exists(pathname, function(exists) { | |
if (!exists) { | |
write(404, "cannot find that file\n"); | |
return; | |
} | |
return fs.stat(pathname, function(err, stats) { | |
if (err) { | |
write(400, `unable to read file information: ${err}\n`); | |
return; | |
} | |
// look for an index.html if they asked for a directory | |
if (stats.isDirectory()) { | |
if (pathname !== '.' && pathname.substring(pathname.length-1, pathname.length) !== '/') { | |
write(301, '', {'Location': pathname+'/'}); | |
} else { | |
serve(path.join(pathname, 'index.html')); | |
} | |
return; | |
} | |
return fs.readFile(pathname, function(err, data) { | |
if (err) { | |
write(400, `unable to read file: ${err}\n`); | |
return; | |
} | |
return write(200, data, {'Content-Type': contentTypeForPath(pathname)}); | |
}); | |
}); | |
}); | |
} catch (e) { | |
return write(500, e.toString()); | |
} | |
}; | |
return serve(url.parse(request.url).pathname.substring(1)); | |
} | |
).listen(port, host); | |
console.log(`** Serving files from ${path.normalize(process.cwd())} at http://${host}:${port}/. Ctrl+C to stop.`); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment