Skip to content

Commit

Permalink
Merge branch 'http-party:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Hermholtz authored Jan 1, 2025
2 parents 1a4d78e + fe91590 commit 24f6a9c
Show file tree
Hide file tree
Showing 30 changed files with 11,129 additions and 8,672 deletions.
8 changes: 8 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
node_modules
yarn-error.log
npm-debug.log
Dockerfile
.dockerignore
.git
.gitignore
testdir/privatefile
6 changes: 3 additions & 3 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [12.x, 14.x, 16.x, 17.x, 18.x]
node-version: [16.x, 18.x, 20.x, 21.x, 22.x]
os: [ubuntu-latest, macOS-latest, windows-latest]

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4.2.2
- name: Use Node.js ${{ matrix.node-version }} on ${{ matrix.os }}
uses: actions/setup-node@v2
uses: actions/setup-node@v4.1.0
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
Expand Down
8 changes: 8 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM node:16-alpine
VOLUME /public
WORKDIR /srv/http-server
COPY package.json package-lock.json ./
RUN npm install --production
COPY . .
EXPOSE 8080
ENTRYPOINT ["node", "./bin/http-server"]
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![GitHub Workflow Status (master)](https://img.shields.io/github/workflow/status/http-party/http-server/Node.js%20CI/master?style=flat-square)](https://github.com/http-party/http-server/actions)
[![GitHub Workflow Status (master)](https://img.shields.io/github/actions/workflow/status/http-party/http-server/node.js.yml?style=flat-square&branch=master)](https://github.com/http-party/http-server/actions)
[![npm](https://img.shields.io/npm/v/http-server.svg?style=flat-square)](https://www.npmjs.com/package/http-server) [![homebrew](https://img.shields.io/homebrew/v/http-server?style=flat-square)](https://formulae.brew.sh/formula/http-server) [![npm downloads](https://img.shields.io/npm/dm/http-server?color=blue&label=npm%20downloads&style=flat-square)](https://www.npmjs.com/package/http-server)
[![license](https://img.shields.io/github/license/http-party/http-server.svg?style=flat-square)](https://github.com/http-party/http-server)
[![license](https://img.shields.io/github/license/http-party/http-server.svg?style=flat-square)](https://github.com/http-party/http-server/blob/master/LICENSE)

# http-server: a simple static HTTP server

Expand Down Expand Up @@ -30,6 +30,22 @@ This will install `http-server` globally so that it may be run from the command

npm install http-server

#### Using Docker

Note: a public image is not provided currently, but you can build one yourself
with the provided Dockerfile.

1. Create an image
```
docker build -t my-image .
```
2. Run a container
```
docker run -p 8080:8080 -v "${pwd}:/public" my-image
```
In the example above we're serving the directory `./` (working directory).
If you wanted to serve `./test` you'd replace `${pwd}` with `${pwd}/test`.

## Usage:

http-server [path] [options]
Expand All @@ -46,13 +62,15 @@ 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|
|`--base-dir` | Base path to serve files from | `/` |
|`-d` |Show directory listings |`true` |
|`-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`|
|`-e` or `--ext` |Default file extension if none supplied |`html` |
|`-s` or `--silent` |Suppress log messages from output | |
|`--cors` |Enable CORS via the `Access-Control-Allow-Origin` header | |
|`-H` or `--header` |Add an extra response header (can be used several times) | |
|`-o [path]` |Open browser window after starting the server. Optionally provide a URL path to open. e.g.: -o /other/dir/ | |
|`-c` |Set cache time (in seconds) for cache-control max-age header, e.g. `-c10` for 10 seconds. To disable caching, use `-c-1`.|`3600` |
|`-U` or `--utc` |Use UTC time format in log messages.| |
Expand Down
61 changes: 52 additions & 9 deletions bin/http-server
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ var chalk = require('chalk'),
url = require('url');
var argv = require('minimist')(process.argv.slice(2), {
alias: {
tls: 'ssl'
tls: 'ssl',
header: 'H'
}
});
var ifaces = os.networkInterfaces();
Expand All @@ -25,8 +26,9 @@ if (argv.h || argv.help) {
'',
'options:',
' -p --port Port to use. If 0, look for open port. [8080]',
' -a Address to use [0.0.0.0]',
' -a Address to use [0.0.0.0] or [::]',
' -d Show directory listings [true]',
' --base-dir Base directory to serve files from [/]',
' -i Display autoIndex [true]',
' -g --gzip Serve gzip files when possible [false]',
' -b --brotli Serve brotli files when possible [false]',
Expand All @@ -35,6 +37,9 @@ if (argv.h || argv.help) {
' -s --silent Suppress log messages from output',
' --cors[=headers] Enable CORS via the "Access-Control-Allow-Origin" header',
' Optionally provide CORS headers list separated by commas',
' -H',
' --header',
' Add an extra response header (can be used several times)',
' -o [path] Open browser window after starting the server.',
' Optionally provide a URL path to open the browser window to.',
' -c Cache time (max-age) in seconds [3600], e.g. -c10 for 10 seconds.',
Expand Down Expand Up @@ -66,13 +71,14 @@ if (argv.h || argv.help) {
}

var port = argv.p || argv.port || parseInt(process.env.PORT, 10),
host = argv.a || '0.0.0.0',
host = argv.a || '::',
tls = argv.S || argv.tls,
sslPassphrase = process.env.NODE_HTTP_SERVER_SSL_PASSPHRASE,
proxy = argv.P || argv.proxy,
proxyOptions = argv['proxy-options'],
utc = argv.U || argv.utc,
version = argv.v || argv.version,
baseDir = argv['base-dir'],
logger;

var proxyOptionsBooleanProps = [
Expand Down Expand Up @@ -142,6 +148,7 @@ function listen(port) {
cache: argv.c,
timeout: argv.t,
showDir: argv.d,
baseDir: baseDir,
autoIndex: argv.i,
gzip: argv.g || argv.gzip,
brotli: argv.b || argv.brotli,
Expand All @@ -153,16 +160,35 @@ 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,
headers: {}
};

function setHeader(str) {
const m = /^(.+?)\s*(:\s*(.*))$/.exec(str);
if (!m || m.length < 4) {
options.headers[str] = '';
} else {
options.headers[m[1]] = m[3];
}
}

if (argv.cors) {
options.cors = true;
if (typeof argv.cors === 'string') {
options.corsHeaders = argv.cors;
}
}

if (argv.header) {
if (Array.isArray(argv.header)) {
argv.header.forEach(h => setHeader(h));
}
else {
setHeader(argv.header);
}
}

if (proxy) {
try {
new url.URL(proxy)
Expand Down Expand Up @@ -197,7 +223,8 @@ function listen(port) {

var server = httpServer.createServer(options);
server.listen(port, host, function () {
var protocol = tls ? 'https://' : 'http://';
var protocol = tls ? 'https://' : 'http://',
path = baseDir ? '/' + baseDir.replace(/^\//, '') : '';

logger.info([
chalk.yellow('Starting up http-server, serving '),
Expand All @@ -216,17 +243,30 @@ function listen(port) {
([chalk.yellow('AutoIndex: '), argv.i ? chalk.red('not visible') : chalk.cyan('visible')].join('')),
([chalk.yellow('Serve GZIP Files: '), argv.g || argv.gzip ? chalk.cyan('true') : chalk.red('false')].join('')),
([chalk.yellow('Serve Brotli Files: '), argv.b || argv.brotli ? chalk.cyan('true') : chalk.red('false')].join('')),
([chalk.yellow('Default File Extension: '), argv.e ? chalk.cyan(argv.e) : (argv.ext ? chalk.cyan(argv.ext) : chalk.red('none'))].join(''))
([chalk.yellow('Default File Extension: '), argv.e ? chalk.cyan(argv.e) : (argv.ext ? chalk.cyan(argv.ext) : chalk.red('none'))].join('')),
([chalk.yellow('Base directory: '), baseDir ? chalk.cyan(baseDir) : chalk.cyan('/')].join(''))
].join('\n'));

if (options.headers) {
logger.info(chalk.yellow('Additional Headers:'));
for (let k in options.headers) {
let v = options.headers[k];
logger.info(chalk.yellow(`\t${k}:`) + chalk.cyan(` ${v}`));
}
}

logger.info(chalk.yellow('\nAvailable on:'));

if (argv.a && host !== '0.0.0.0') {
logger.info(` ${protocol}${host}:${chalk.green(port.toString())}`);

if (argv.a && (host !== '::' || host !== '0.0.0.0')) {
logger.info(` ${protocol}${host}:${chalk.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 + ':' + chalk.green(port.toString()) + path));
}
if (details.family === 'IPv6' && !details.address.startsWith("fe80") ) { // Ignoring Ipv6-Link Local addresses
logger.info((' ' + protocol + details.address + ':' + chalk.green(port.toString())));
}
});
Expand All @@ -244,7 +284,10 @@ function listen(port) {

logger.info('Hit CTRL-C to stop the server');
if (argv.o) {
const openHost = host === '0.0.0.0' ? '127.0.0.1' : host;
let openHost = host
if ('::' === host || '0.0.0.0'===host){
openHost = '127.0.0.1'
}
let openUrl = `${protocol}${openHost}:${port}`;
if (typeof argv.o === 'string') {
openUrl += argv.o[0] === '/' ? argv.o : '/' + argv.o;
Expand Down
4 changes: 4 additions & 0 deletions doc/http-server.1
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ Suppress log messages from output.
Enable CORS via the "Access-Control-Allow-Origin" header.
Optionally provide CORS headers list separated by commas.

.TP
.BI \-H ", " \-\-header " " \fIHEADER\fR
Add an extra response header (can be used several times)

.TP
.BI \-o " " [\fIPATH\fR]
Open default browser window after starting the server.
Expand Down
1 change: 1 addition & 0 deletions lib/http-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ function HttpServer(options) {

before.push(httpServerCore({
root: this.root,
baseDir: options.baseDir,
cache: this.cache,
showDir: this.showDir,
showDotfiles: this.showDotfiles,
Expand Down
Loading

0 comments on commit 24f6a9c

Please sign in to comment.