Skip to content

Instantly share code, notes, and snippets.

@eventualbuddha
Last active September 24, 2015 06:28
Show Gist options
  • Save eventualbuddha/706182 to your computer and use it in GitHub Desktop.
Save eventualbuddha/706182 to your computer and use it in GitHub Desktop.
simple node.js file server
serve.js: serve.jsnext.js
babel serve.jsnext.js -o serve.js
#!/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.');
#!/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