From 02d6f4643de8260eafec559322b5289114936a35 Mon Sep 17 00:00:00 2001 From: Bill Wallace Date: Wed, 1 Dec 2021 13:11:35 -0500 Subject: [PATCH 1/3] feat(http-server):Add a configuration file to store frequently used configuration values. --- README.md | 21 +++++++++++++++++++++ bin/http-server | 17 +++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/README.md b/README.md index 0ffbbc1f..7da2faca 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ Using `npx` you can run the script without installing it first: npx http-server [path] [options] +Optionally you can create a JavaScript module file 'http-server-config.js' that exports any of the configuration options you want to include. This can be used to create redirects, apply custom content types etc. + #### Globally via `npm` npm install --global http-server @@ -44,6 +46,7 @@ This will install `http-server` globally so that it may be run from the command | Command | Description | Defaults | | ------------- |-------------|-------------| +| --config | Configuration file to read. Defaults to http-server-config.js | |`-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` | @@ -134,6 +137,24 @@ Available on: Hit CTRL-C to stop the server ``` +# configuration file +You can configure http-server automatically with a file named http-server-config.js, located in the directory +you run the command from, or as specified by the --config option. + +An example configuration: +```js +module.exports = { + gzip: true, + before: [ + (req,res) => { + console.log('Hello req', req); + console.log('Hello res', res); + res.emit('next'); + }, + ], +}; +``` + # Development Checkout this repository locally, then: diff --git a/bin/http-server b/bin/http-server index 3b9e59d2..0c02143b 100755 --- a/bin/http-server +++ b/bin/http-server @@ -10,6 +10,7 @@ var colors = require('colors/safe'), fs = require('fs'), url = require('url'); +const path = require('path'); var argv = require('minimist')(process.argv.slice(2), { alias: { tls: 'ssl' @@ -56,6 +57,7 @@ if (argv.h || argv.help) { ' -C --cert Path to TLS cert file (default: cert.pem)', ' -K --key Path to TLS key file (default: key.pem)', '', + ' --config Read the JavaScript file for initial options (http-server-config.js if it exists)', ' -r --robots Respond to /robots.txt [User-agent: *\\nDisallow: /]', ' --no-dotfiles Do not show dotfiles', ' --mimetypes Path to a .types file for custom mimetype definition', @@ -88,6 +90,7 @@ if (proxyOptions) { }); } + if (!argv.s && !argv.silent) { logger = { info: console.log, @@ -156,6 +159,20 @@ function listen(port) { password: argv.password || process.env.NODE_HTTP_SERVER_PASSWORD }; + const configFile = (typeof argv.config) == 'string' && argv.config || 'http-server-config.js'; + const isRootConfig = configFile.length && (configFile[0] == '/' || configFile[0] == '\\') || + configFile.length > 1 && configFile[1] == ':'; + const configPath = isRootConfig && configFile || path.join(process.cwd(), configFile); + try { + const configLoad = require(configPath); + console.log('Read config', configPath); + Object.assign(options, configLoad); + } catch(e) { + if( argv.config ) { + throw new Error(`Couldn't load ${configPath}`); + } + } + if (argv.cors) { options.cors = true; if (typeof argv.cors === 'string') { From 8cfb05e50b3beff7ef6528e58615d56736bffe3b Mon Sep 17 00:00:00 2001 From: Bill Wallace Date: Wed, 1 Dec 2021 13:38:28 -0500 Subject: [PATCH 2/3] fix(http-server):Load the config earlier to allow setting the port --- bin/http-server | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/bin/http-server b/bin/http-server index 0c02143b..1a666afc 100755 --- a/bin/http-server +++ b/bin/http-server @@ -67,7 +67,23 @@ if (argv.h || argv.help) { process.exit(); } -var port = argv.p || argv.port || parseInt(process.env.PORT, 10), +const configFile = (typeof argv.config) == 'string' && argv.config || 'http-server-config.js'; +const isRootConfig = configFile.length && (configFile[0] == '/' || configFile[0] == '\\') || + configFile.length > 1 && configFile[1] == ':'; +const configPath = isRootConfig && configFile || path.join(process.cwd(), configFile); +let defaultOptions = {}; +try { + defaultOptions = require(configPath); + console.log('Read config', configPath); +} catch(e) { + if( argv.config ) { + console.log(e); + throw new Error(`Couldn't load ${configPath}`); + } +} + + +var port = argv.p || argv.port || parseInt(process.env.PORT, 10) || defaultOptions.port, host = argv.a || '0.0.0.0', tls = argv.S || argv.tls, sslPassphrase = process.env.NODE_HTTP_SERVER_SSL_PASSPHRASE, @@ -141,6 +157,7 @@ else { function listen(port) { var options = { + ...defaultOptions, root: argv._[0], cache: argv.c, timeout: argv.t, @@ -159,20 +176,6 @@ function listen(port) { password: argv.password || process.env.NODE_HTTP_SERVER_PASSWORD }; - const configFile = (typeof argv.config) == 'string' && argv.config || 'http-server-config.js'; - const isRootConfig = configFile.length && (configFile[0] == '/' || configFile[0] == '\\') || - configFile.length > 1 && configFile[1] == ':'; - const configPath = isRootConfig && configFile || path.join(process.cwd(), configFile); - try { - const configLoad = require(configPath); - console.log('Read config', configPath); - Object.assign(options, configLoad); - } catch(e) { - if( argv.config ) { - throw new Error(`Couldn't load ${configPath}`); - } - } - if (argv.cors) { options.cors = true; if (typeof argv.cors === 'string') { From 441792d2aa9ebd50305a15c1b16ce7e984f258c1 Mon Sep 17 00:00:00 2001 From: Bill Wallace Date: Thu, 2 Dec 2021 14:59:14 -0500 Subject: [PATCH 3/3] feat(http-server): Implementation of #770 --- bin/http-server | 16 ++++++++-------- lib/core/index.js | 2 +- lib/http-server.js | 5 ++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/bin/http-server b/bin/http-server index 1a666afc..3acc8ae1 100755 --- a/bin/http-server +++ b/bin/http-server @@ -157,7 +157,6 @@ else { function listen(port) { var options = { - ...defaultOptions, root: argv._[0], cache: argv.c, timeout: argv.t, @@ -173,7 +172,8 @@ function listen(port) { showDotfiles: argv.dotfiles, mimetypes: argv.mimetypes, username: argv.username || process.env.NODE_HTTP_SERVER_USERNAME, - password: argv.password || process.env.NODE_HTTP_SERVER_PASSWORD + password: argv.password || process.env.NODE_HTTP_SERVER_PASSWORD, + ...defaultOptions, }; if (argv.cors) { @@ -229,14 +229,14 @@ function listen(port) { logger.info([ colors.yellow('\nhttp-server settings: '), - ([colors.yellow('CORS: '), argv.cors ? colors.cyan(argv.cors) : colors.red('disabled')].join('')), - ([colors.yellow('Cache: '), argv.c ? (argv.c === '-1' ? colors.red('disabled') : colors.cyan(argv.c + ' seconds')) : colors.cyan('3600 seconds')].join('')), + ([colors.yellow('CORS: '), options.cors ? colors.cyan(options.cors) : colors.red('disabled')].join('')), + ([colors.yellow('Cache: '), options.cache ? (options.cache === '-1' ? colors.red('disabled') : colors.cyan(options.cache + ' seconds')) : colors.cyan('3600 seconds')].join('')), ([colors.yellow('Connection Timeout: '), argv.t === '0' ? colors.red('disabled') : (argv.t ? colors.cyan(argv.t + ' seconds') : colors.cyan('120 seconds'))].join('')), - ([colors.yellow('Directory Listings: '), argv.d ? colors.red('not visible') : colors.cyan('visible')].join('')), + ([colors.yellow('Directory Listings: '), options.showDir ? colors.red('not visible') : colors.cyan('visible')].join('')), ([colors.yellow('AutoIndex: '), argv.i ? colors.red('not visible') : colors.cyan('visible')].join('')), - ([colors.yellow('Serve GZIP Files: '), argv.g || argv.gzip ? colors.cyan('true') : colors.red('false')].join('')), - ([colors.yellow('Serve Brotli Files: '), argv.b || argv.brotli ? colors.cyan('true') : colors.red('false')].join('')), - ([colors.yellow('Default File Extension: '), argv.e ? colors.cyan(argv.e) : (argv.ext ? colors.cyan(argv.ext) : colors.red('none'))].join('')) + ([colors.yellow('Serve GZIP Files: '), options.gzip ? colors.cyan('true') : colors.red('false')].join('')), + ([colors.yellow('Serve Brotli Files: '), options.brotli ? colors.cyan('true') : colors.red('false')].join('')), + ([colors.yellow('Default File Extension: '), options.ext ? colors.cyan(options.ext) : colors.red('none')].join('')) ].join('\n')); logger.info(colors.yellow('\nAvailable on:')); diff --git a/lib/core/index.js b/lib/core/index.js index 920e55b9..68593198 100644 --- a/lib/core/index.js +++ b/lib/core/index.js @@ -320,7 +320,7 @@ module.exports = function createMiddleware(_dir, _options) { res.setHeader('content-type', contentType); // set the response statusCode if we have a request statusCode. - // This only can happen if we have a 404 with some kind of 404.html + // This only can happen if we have a 404 with some kind of 404.html // In all other cases where we have a file we serve the 200 res.statusCode = req.statusCode || 200; diff --git a/lib/http-server.js b/lib/http-server.js index dfe4c474..aa3aa407 100644 --- a/lib/http-server.js +++ b/lib/http-server.js @@ -46,11 +46,10 @@ function HttpServer(options) { this.headers['Accept-Ranges'] = 'bytes'; this.cache = ( - // eslint-disable-next-line no-nested-ternary - options.cache === undefined ? 3600 : + options.cache === undefined && 3600 || // -1 is a special case to turn off caching. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Preventing_caching - options.cache === -1 ? 'no-cache, no-store, must-revalidate' : + options.cache === -1 && 'no-cache, no-store, must-revalidate' || options.cache // in seconds. ); this.showDir = options.showDir !== 'false';