diff --git a/README.md b/README.md index 27f2de7b..cdc1e16a 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ This will install `http-server` globally so that it may be run from the command `-a` Address to use (defaults to 0.0.0.0) +`-b` Base path to serve files from (defaults /) + `-d` Show directory listings (defaults to `true`) `-i` Display autoIndex (defaults to `true`) diff --git a/bin/http-server b/bin/http-server index 7d9bac9d..650debe4 100755 --- a/bin/http-server +++ b/bin/http-server @@ -22,6 +22,7 @@ if (argv.h || argv.help) { ' -p Port to use [8080]', ' -a Address to use [0.0.0.0]', ' -d Show directory listings [true]', + ' -b Base directory to serve files from [/]', ' -i Display autoIndex [true]', ' -g --gzip Serve gzip files when possible [false]', ' -e --ext Default file extension if none supplied [none]', @@ -51,6 +52,7 @@ var port = argv.p || parseInt(process.env.PORT, 10), ssl = !!argv.S || !!argv.ssl, proxy = argv.P || argv.proxy, utc = argv.U || argv.utc, + baseDir = argv.b, logger; if (!argv.s && !argv.silent) { @@ -99,6 +101,7 @@ function listen(port) { root: argv._[0], cache: argv.c, showDir: argv.d, + baseDir: baseDir, autoIndex: argv.i, gzip: argv.g || argv.gzip, robots: argv.r || argv.robots, @@ -125,7 +128,8 @@ function listen(port) { var server = httpServer.createServer(options); server.listen(port, host, function () { var canonicalHost = host === '0.0.0.0' ? '127.0.0.1' : host, - protocol = ssl ? 'https://' : 'http://'; + protocol = ssl ? 'https://' : 'http://', + path = baseDir ? '/' + baseDir.replace(/^\//, '') : ''; logger.info([colors.yellow('Starting up http-server, serving '), colors.cyan(server.root), @@ -134,13 +138,13 @@ function listen(port) { ].join('')); if (argv.a && host !== '0.0.0.0') { - logger.info((' ' + protocol + canonicalHost + ':' + colors.green(port.toString()))); + logger.info((' ' + protocol + canonicalHost + ':' + colors.green(port.toString()) + path)); } else { Object.keys(ifaces).forEach(function (dev) { ifaces[dev].forEach(function (details) { if (details.family === 'IPv4') { - logger.info((' ' + protocol + details.address + ':' + colors.green(port.toString()))); + logger.info((' ' + protocol + details.address + ':' + colors.green(port.toString()) + path)); } }); }); @@ -153,7 +157,7 @@ function listen(port) { logger.info('Hit CTRL-C to stop the server'); if (argv.o) { opener( - protocol + canonicalHost + ':' + port, + protocol + canonicalHost + ':' + port + path, { command: argv.o !== true ? argv.o : null } ); } diff --git a/lib/http-server.js b/lib/http-server.js index 8d40fe17..ea448994 100644 --- a/lib/http-server.js +++ b/lib/http-server.js @@ -97,6 +97,7 @@ function HttpServer(options) { before.push(ecstatic({ baseDir: this.baseDir, root: this.root, + baseDir: options.baseDir, cache: this.cache, showDir: this.showDir, showDotfiles: this.showDotfiles, diff --git a/test/http-server-test.js b/test/http-server-test.js index e64f04e1..a8578161 100644 --- a/test/http-server-test.js +++ b/test/http-server-test.js @@ -154,5 +154,45 @@ vows.describe('http-server').addBatch({ assert.ok(res.headers['access-control-allow-headers'].split(/\s*,\s*/g).indexOf('X-Test') >= 0, 204); } } + }, + 'When baseDir is specified': { + topic: function () { + var server = httpServer.createServer({ + root: root, + baseDir: '/test' + }); + server.listen(8083); + this.callback(null, server); + }, + 'it should serve files at the specified baseDir': { + topic: function () { + request('http://127.0.0.1:8083/test/file', this.callback); + }, + 'status code should be 200': function (res) { + assert.equal(res.statusCode, 200); + }, + 'and file content': { + topic: function (res, body) { + var self = this; + fs.readFile(path.join(root, 'file'), 'utf8', function (err, data) { + self.callback(err, data, body); + }); + }, + 'should match content of served file': function (err, file, body) { + assert.equal(body.trim(), file.trim()); + } + } + }, + 'it should not serve files at the root': { + topic: function () { + request('http://127.0.0.1:8083/file', this.callback); + }, + 'status code should be 403': function (res) { + assert.equal(res.statusCode, 403); + }, + 'and file content should be empty': function (res) { + assert.equal(res.body, ''); + } + } } }).export(module);