diff --git a/README.md b/README.md index 99b19be2..2af8a70e 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ This will install `http-server` globally so that it may be run from the command |`-p` or `--port` |Port to use. Use `-p 0` to look for an open port, starting at 8080. It will also read from `process.env.PORT`. |8080 | |`-a` |Address to use |0.0.0.0| |`-d` |Show directory listings |`true` | +|`-dir-overrides-404` | Whether `-d` should override magic `404.html` | `false` |`-i` | Display autoIndex | `true` | |`-g` or `--gzip` |When enabled it will serve `./public/some-file.js.gz` in place of `./public/some-file.js` when a gzipped version of the file exists and the request accepts gzip encoding. If brotli is also enabled, it will try to serve brotli first.|`false`| |`-b` or `--brotli`|When enabled it will serve `./public/some-file.js.br` in place of `./public/some-file.js` when a brotli compressed version of the file exists and the request accepts `br` encoding. If gzip is also enabled, it will try to serve brotli first. |`false`| diff --git a/bin/http-server b/bin/http-server index 7c597fa8..0be18262 100755 --- a/bin/http-server +++ b/bin/http-server @@ -27,6 +27,7 @@ if (argv.h || argv.help) { ' -p --port Port to use. If 0, look for open port. [8080]', ' -a Address to use [0.0.0.0]', ' -d Show directory listings [true]', + ' --dir-overrides-404 Whether -d should override magic 404.html [false]', ' -i Display autoIndex [true]', ' -g --gzip Serve gzip files when possible [false]', ' -b --brotli Serve brotli files when possible [false]', @@ -142,6 +143,7 @@ function listen(port) { cache: argv.c, timeout: argv.t, showDir: argv.d, + dirOverrides404: argv['dir-overrides-404'], autoIndex: argv.i, gzip: argv.g || argv.gzip, brotli: argv.b || argv.brotli, diff --git a/doc/http-server.1 b/doc/http-server.1 index 8e2796e6..2e1ae951 100644 --- a/doc/http-server.1 +++ b/doc/http-server.1 @@ -33,6 +33,11 @@ Default is 0.0.0.0. Show directory listings. Default is true. +.TP +.BI \-d +Whether -d should override magic 404.html +Default is false. + .TP .BI \-i Display autoIndex. diff --git a/lib/core/aliases.json b/lib/core/aliases.json index 53a22a56..5867807d 100644 --- a/lib/core/aliases.json +++ b/lib/core/aliases.json @@ -1,6 +1,13 @@ { "autoIndex": [ "autoIndex", "autoindex" ], "showDir": [ "showDir", "showdir" ], + "dirOverrides404": [ + "dirOverrides404", + "diroverrides404", + "dir-overrides-404", + "listingsOverride404", + "listings-override-404" + ], "showDotfiles": ["showDotfiles", "showdotfiles"], "humanReadable": [ "humanReadable", "humanreadable", "human-readable" ], "hidePermissions": ["hidePermissions", "hidepermissions", "hide-permissions"], diff --git a/lib/core/defaults.json b/lib/core/defaults.json index d919f292..f0a285a7 100644 --- a/lib/core/defaults.json +++ b/lib/core/defaults.json @@ -1,6 +1,7 @@ { "autoIndex": true, "showDir": true, + "dirOverrides404": false, "showDotfiles": true, "humanReadable": true, "hidePermissions": false, diff --git a/lib/core/index.js b/lib/core/index.js index 920e55b9..6b08f796 100644 --- a/lib/core/index.js +++ b/lib/core/index.js @@ -359,6 +359,11 @@ module.exports = function createMiddleware(_dir, _options) { url: `${parsed.pathname}.${defaultExt}${(parsed.search) ? parsed.search : ''}`, headers: req.headers, }, res, next); + } else if (opts.showDir && opts.dirOverrides404) { + // If showDir and dirOverrides404 are true, show the directory instead of 404.html + req.url = path.dirname(req.url); + showDir(opts, stat)(req, res); + return; } else { // Try to serve default ./404.html const rawUrl = (handleError ? `/${path.join(baseDir, `404.${defaultExt}`)}` : req.url); @@ -406,7 +411,6 @@ module.exports = function createMiddleware(_dir, _options) { showDir(opts, stat)(req, res); return; } - status[403](res, next); }); return; diff --git a/lib/core/opts.js b/lib/core/opts.js index ec1b2cbc..b7ee25fb 100644 --- a/lib/core/opts.js +++ b/lib/core/opts.js @@ -8,6 +8,7 @@ const aliases = require('./aliases.json'); module.exports = (opts) => { let autoIndex = defaults.autoIndex; let showDir = defaults.showDir; + let dirOverrides404 = defaults.dirOverrides404; let showDotfiles = defaults.showDotfiles; let humanReadable = defaults.humanReadable; let hidePermissions = defaults.hidePermissions; @@ -55,6 +56,14 @@ module.exports = (opts) => { return false; }); + aliases.dirOverrides404.some((k) => { + if (isDeclared(k)) { + dirOverrides404 = opts[k]; + return true; + } + return false; + }); + aliases.showDotfiles.some((k) => { if (isDeclared(k)) { showDotfiles = opts[k]; @@ -184,6 +193,7 @@ module.exports = (opts) => { cache, autoIndex, showDir, + dirOverrides404, showDotfiles, humanReadable, hidePermissions, diff --git a/lib/http-server.js b/lib/http-server.js index dfe4c474..91369fc5 100644 --- a/lib/http-server.js +++ b/lib/http-server.js @@ -54,6 +54,7 @@ function HttpServer(options) { options.cache // in seconds. ); this.showDir = options.showDir !== 'false'; + this.dirOverrides404 = options.dirOverrides404; this.autoIndex = options.autoIndex !== 'false'; this.showDotfiles = options.showDotfiles; this.gzip = options.gzip === true; @@ -129,6 +130,7 @@ function HttpServer(options) { root: this.root, cache: this.cache, showDir: this.showDir, + dirOverrides404: this.dirOverrides404, showDotfiles: this.showDotfiles, autoIndex: this.autoIndex, defaultExt: this.ext, diff --git a/package.json b/package.json index 44f98490..4c23ef9d 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,10 @@ { "name": "Jade Michael Thornton", "email": "jademichael@jmthornton.net" + }, + { + "name": "Jorens Merenjanu", + "email": "jorensmerenjanu@gmail.com" } ], "dependencies": { diff --git a/test/dir-overrides-404.test.js b/test/dir-overrides-404.test.js new file mode 100644 index 00000000..95f023fd --- /dev/null +++ b/test/dir-overrides-404.test.js @@ -0,0 +1,63 @@ +'use strict'; + +const test = require('tap').test; +const http = require('http'); +const ecstatic = require('../lib/core'); +const request = require('request'); +const showDir = require('../lib/core/show-dir'); + +const root = `${__dirname}/public/dir-overrides-404`; + +test('server should display directory if -d and --dir-overrides--404 flags are specified', (t) => { + // require('portfinder').getPort((err, port) => { + try { + const server = http.createServer(ecstatic({root, showDir: true, dirOverrides404: true})); + // t.plan(2); + // t.on('end', () => { server.close(); }); + server.listen(0, () => { + const port = server.address().port; + request.get(`http://localhost:${port}/directory/`, (err, res, body) => { + if(err) { + t.error(err); + } + // console.log(body); + // console.log(res.statusCode); + t.equal(res.statusCode, 200); + console.log(body); + t.equal(body.includes('Index of /directory/'), true); + server.close(() => { t.end(); }); + }); + }) + console.log('d'); + + } catch (e) { + t.fail(e.message); + t.end(); + } + // }); +}); + +test('server should display 404.html if -d flag is specified but not --dir-overrides-404', (t) => { + try { + const server = http.createServer(ecstatic({root, showDir: true, dirOverrides404: false})); + // t.plan(2); + // t.on('end', () => { server.close(); }); + server.listen(0, () => { + const port = server.address().port; + request.get(`http://localhost:${port}/directory/`, (err, res, body) => { + if(err) { + t.error(err); + } + t.equal(res.statusCode, 404); + t.equal(body.includes('404file'), true); + server.close(() => { t.end(); }); + }); + }) + console.log('d'); + + } catch (e) { + t.fail(e.message); + t.end(); + } + +}); \ No newline at end of file diff --git a/test/public/dir-overrides-404/404.html b/test/public/dir-overrides-404/404.html new file mode 100644 index 00000000..8b07b31f --- /dev/null +++ b/test/public/dir-overrides-404/404.html @@ -0,0 +1 @@ +404file \ No newline at end of file diff --git a/test/public/dir-overrides-404/directory/file.txt b/test/public/dir-overrides-404/directory/file.txt new file mode 100644 index 00000000..e69de29b