diff --git a/README.md b/README.md
index 0ffbbc1f..0f17dfd8 100644
--- a/README.md
+++ b/README.md
@@ -53,6 +53,7 @@ This will install `http-server` globally so that it may be run from the command
|`-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 | |
+|`--private-network-access` |Enable Private Network Access via the `Access-Control-Allow-Private-Network` header | |
|`-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.| |
diff --git a/bin/http-server b/bin/http-server
index 7c597fa8..5d247686 100755
--- a/bin/http-server
+++ b/bin/http-server
@@ -35,6 +35,8 @@ 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',
+ ' --private-network-access Enable Private Network Access via the',
+ ' "Access-Control-Allow-Private-Network" header',
' -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.',
@@ -163,6 +165,10 @@ function listen(port) {
}
}
+ if (argv['private-network-access']) {
+ options.privateNetworkAccess = true;
+ }
+
if (proxy) {
try {
new url.URL(proxy)
@@ -210,6 +216,7 @@ function listen(port) {
logger.info([
chalk.yellow('\nhttp-server settings: '),
([chalk.yellow('CORS: '), argv.cors ? chalk.cyan(argv.cors) : chalk.red('disabled')].join('')),
+ ([chalk.yellow('Private Network Access: '), argv['private-network-access'] ? chalk.cyan(argv['private-network-access']) : chalk.red('disabled')].join('')),
([chalk.yellow('Cache: '), argv.c ? (argv.c === '-1' ? chalk.red('disabled') : chalk.cyan(argv.c + ' seconds')) : chalk.cyan('3600 seconds')].join('')),
([chalk.yellow('Connection Timeout: '), argv.t === '0' ? chalk.red('disabled') : (argv.t ? chalk.cyan(argv.t + ' seconds') : chalk.cyan('120 seconds'))].join('')),
([chalk.yellow('Directory Listings: '), argv.d ? chalk.red('not visible') : chalk.cyan('visible')].join('')),
diff --git a/doc/http-server.1 b/doc/http-server.1
index bbd87e82..f84e27d9 100644
--- a/doc/http-server.1
+++ b/doc/http-server.1
@@ -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 \-\-private-network-access
+Enable Private Network Access via the "Access-Control-Allow-Private-Network" header.
+
.TP
.BI \-o " " [\fIPATH\fR]
Open default browser window after starting the server.
diff --git a/lib/core/aliases.json b/lib/core/aliases.json
index 53a22a56..88b50c99 100644
--- a/lib/core/aliases.json
+++ b/lib/core/aliases.json
@@ -7,6 +7,7 @@
"si": [ "si", "index" ],
"handleError": [ "handleError", "handleerror" ],
"cors": [ "cors", "CORS" ],
+ "privateNetworkAccess": [ "privateNetworkAccess", "privatenetworkaccess", "private-network-access" ],
"headers": [ "H", "header", "headers" ],
"contentType": [ "contentType", "contenttype", "content-type" ],
"mimeType": [
diff --git a/lib/core/defaults.json b/lib/core/defaults.json
index d919f292..c2a71524 100644
--- a/lib/core/defaults.json
+++ b/lib/core/defaults.json
@@ -7,6 +7,7 @@
"si": false,
"cache": "max-age=3600",
"cors": false,
+ "privateNetworkAccess": false,
"gzip": true,
"brotli": false,
"defaultExt": ".html",
diff --git a/lib/core/opts.js b/lib/core/opts.js
index ec1b2cbc..4b45f791 100644
--- a/lib/core/opts.js
+++ b/lib/core/opts.js
@@ -125,6 +125,12 @@ module.exports = (opts) => {
}
});
+ aliases.privateNetworkAccess.forEach((k) => {
+ if (isDeclared(k) && opts[k]) {
+ headers['Access-Control-Allow-Private-Network'] = 'true';
+ }
+ });
+
aliases.headers.forEach((k) => {
if (isDeclared(k)) {
if (Array.isArray(opts[k])) {
diff --git a/lib/http-server.js b/lib/http-server.js
index dfe4c474..19bd9392 100644
--- a/lib/http-server.js
+++ b/lib/http-server.js
@@ -110,6 +110,10 @@ function HttpServer(options) {
} : null));
}
+ if (options.privateNetworkAccess) {
+ this.headers['Access-Control-Allow-Private-Network'] = true;
+ }
+
if (options.robots) {
before.push(function (req, res) {
if (req.url === '/robots.txt') {
diff --git a/test/private-network-access.test.js b/test/private-network-access.test.js
new file mode 100644
index 00000000..16c331b2
--- /dev/null
+++ b/test/private-network-access.test.js
@@ -0,0 +1,88 @@
+'use strict';
+
+const test = require('tap').test;
+const server = require('../lib/core');
+const http = require('http');
+const path = require('path');
+const request = require('request');
+
+const root = path.join(__dirname, 'public');
+
+test('private-network-access defaults to false', (t) => {
+ t.plan(3);
+
+ const httpServer = http.createServer(
+ server({
+ root,
+ autoIndex: true,
+ defaultExt: 'html',
+ })
+ );
+
+ httpServer.listen(() => {
+ const port = httpServer.address().port;
+ const uri = `http://localhost:${port}/subdir/index.html`;
+
+ request.get({ uri }, (err, res) => {
+ t.ifError(err);
+ t.equal(res.statusCode, 200);
+ t.type(res.headers['access-control-allow-private-network'], 'undefined');
+ });
+ });
+ t.once('end', () => {
+ httpServer.close();
+ });
+});
+
+test('privateNetworkAccess set to false', (t) => {
+ t.plan(3);
+
+ const httpServer = http.createServer(
+ server({
+ root,
+ privateNetworkAccess: false,
+ autoIndex: true,
+ defaultExt: 'html',
+ })
+ );
+
+ httpServer.listen(() => {
+ const port = httpServer.address().port;
+ const uri = `http://localhost:${port}/subdir/index.html`;
+
+ request.get({ uri }, (err, res) => {
+ t.ifError(err);
+ t.equal(res.statusCode, 200);
+ t.type(res.headers['access-control-allow-private-network'], 'undefined');
+ });
+ });
+ t.once('end', () => {
+ httpServer.close();
+ });
+});
+
+test('privateNetworkAccess set to true', (t) => {
+ t.plan(3);
+
+ const httpServer = http.createServer(
+ server({
+ root,
+ privateNetworkAccess: true,
+ autoIndex: true,
+ defaultExt: 'html',
+ })
+ );
+
+ httpServer.listen(() => {
+ const port = httpServer.address().port;
+ const uri = `http://localhost:${port}/subdir/index.html`;
+ request.get({ uri }, (err, res) => {
+ t.ifError(err);
+ t.equal(res.statusCode, 200);
+ t.equal(res.headers['access-control-allow-private-network'], 'true');
+ });
+ });
+ t.once('end', () => {
+ httpServer.close();
+ });
+});