Skip to content

Commit cf063f0

Browse files
committed
feat: add flag --proxy-all
Adds a flag which allows http-server to be used purely as a proxy without serving any files.
1 parent 7be905c commit cf063f0

File tree

9 files changed

+196
-23
lines changed

9 files changed

+196
-23
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ with the provided Dockerfile.
7676
|`-U` or `--utc` |Use UTC time format in log messages.| |
7777
|`--log-ip` |Enable logging of the client's IP address |`false` |
7878
|`-P` or `--proxy` |Proxies all requests which can't be resolved locally to the given url. e.g.: -P http://someurl.com | |
79+
|`--proxy-all` |Forward every request to the proxy target instead of serving local files|`false`|
7980
|`--proxy-options` |Pass proxy [options](https://github.com/http-party/node-http-proxy#options) using nested dotted objects. e.g.: --proxy-options.secure false |
8081
|`--username` |Username for basic authentication | |
8182
|`--password` |Password for basic authentication | |

bin/http-server

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ var argv = require('minimist')(process.argv.slice(2), {
1414
alias: {
1515
tls: 'ssl',
1616
header: 'H'
17-
}
17+
},
18+
boolean: ['proxy-all']
1819
});
20+
1921
var ifaces = os.networkInterfaces();
2022

2123
process.title = 'http-server';
@@ -59,6 +61,7 @@ if (argv.h || argv.help) {
5961
' --log-ip Enable logging of the client\'s IP address',
6062
'',
6163
' -P --proxy Fallback proxy if the request cannot be resolved. e.g.: http://someurl.com',
64+
' --proxy-all Send every request to the proxy target instead of serving local files',
6265
' --proxy-options Pass options to proxy using nested dotted objects. e.g.: --proxy-options.secure false',
6366
' --websocket Enable websocket proxy',
6467
'',
@@ -87,6 +90,7 @@ var port = argv.p || argv.port || parseInt(process.env.PORT, 10),
8790
proxy = argv.P || argv.proxy,
8891
proxyOptions = argv['proxy-options'],
8992
websocket = argv.websocket,
93+
proxyAll = Boolean(argv['proxy-all']),
9094
utc = argv.U || argv.utc,
9195
version = argv.v || argv.version,
9296
baseDir = argv['base-dir'],
@@ -168,6 +172,7 @@ function listen(port) {
168172
logFn: logger.request,
169173
proxy: proxy,
170174
proxyOptions: proxyOptions,
175+
proxyAll: proxyAll,
171176
showDotfiles: argv.dotfiles,
172177
mimetypes: argv.mimetypes,
173178
contentType: argv['content-type'],
@@ -223,6 +228,11 @@ function listen(port) {
223228
}
224229
}
225230

231+
if (proxyAll && !proxy) {
232+
logger.info(chalk.red('Error: --proxy-all requires --proxy to be set'));
233+
process.exit(1);
234+
}
235+
226236
if (tls) {
227237
options.https = {
228238
cert: argv.C || argv.cert || 'cert.pem',

doc/http-server.1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ Enable logging of the client IP address.
9797
.BI \-P ", " \-\-proxy
9898
Fallback proxy if the request cannot be resolved.
9999

100+
.TP
101+
.BI \-\-proxy\-all
102+
Forward every request to the proxy target and disable local file serving.
103+
Requires \-\-proxy.
104+
100105
.TP
101106
.BI \-\-proxy\-options
102107
Pass proxy options using nested dotted objects.

lib/http-server.js

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ exports.createServer = function (options) {
2929
*/
3030
function HttpServer(options) {
3131
options = options || {};
32+
var proxyAll = options.proxyAll === true || options.proxyAll === 'true';
33+
34+
if (proxyAll && typeof options.proxy !== 'string') {
35+
throw new Error('proxyAll option requires "proxy" to be configured');
36+
}
3237

3338
if (options.root) {
3439
this.root = options.root;
@@ -139,21 +144,23 @@ function HttpServer(options) {
139144
});
140145
}
141146

142-
before.push(httpServerCore({
143-
root: this.root,
144-
baseDir: options.baseDir,
145-
cache: this.cache,
146-
showDir: this.showDir,
147-
showDotfiles: this.showDotfiles,
148-
autoIndex: this.autoIndex,
149-
defaultExt: this.ext,
150-
gzip: this.gzip,
151-
brotli: this.brotli,
152-
forceContentEncoding: this.forceContentEncoding,
153-
contentType: this.contentType,
154-
mimetypes: options.mimetypes,
155-
handleError: typeof options.proxy !== 'string'
156-
}));
147+
if (!proxyAll) {
148+
before.push(httpServerCore({
149+
root: this.root,
150+
baseDir: options.baseDir,
151+
cache: this.cache,
152+
showDir: this.showDir,
153+
showDotfiles: this.showDotfiles,
154+
autoIndex: this.autoIndex,
155+
defaultExt: this.ext,
156+
gzip: this.gzip,
157+
brotli: this.brotli,
158+
forceContentEncoding: this.forceContentEncoding,
159+
contentType: this.contentType,
160+
mimetypes: options.mimetypes,
161+
handleError: typeof options.proxy !== 'string'
162+
}));
163+
}
157164

158165
if (typeof options.proxy === 'string') {
159166
var proxyOptions = options.proxyOptions || {};

package-lock.json

Lines changed: 19 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/cli.test.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const request = require('request');
77
const spawn = require('child_process').spawn;
88
const path = require('path');
99
const portfinder = require('portfinder');
10+
const httpServer = require('../lib/http-server');
1011

1112
const node = process.execPath;
1213
const defaultPort = 8080;
@@ -46,6 +47,8 @@ const getPort = () => new Promise((resolve, reject) => {
4647
});
4748
});
4849

50+
const stripAnsi = (str) => str.replace(/\u001b\[[0-9;]*m/g, '');
51+
4952
test('setting port via cli - custom port', (t) => {
5053
t.plan(2);
5154

@@ -115,6 +118,60 @@ test('--proxy requires you to specify a protocol', (t) => {
115118
});
116119
});
117120

121+
test('--proxy-all requires --proxy', (t) => {
122+
t.plan(1);
123+
124+
const options = ['.', '--proxy-all', 'true'];
125+
const server = startServer(options);
126+
127+
tearDown(server, t);
128+
129+
server.on('exit', (code) => {
130+
t.equal(code, 1);
131+
});
132+
});
133+
134+
test('--proxy-all does not consume following positional args', (t) => {
135+
t.plan(4);
136+
137+
const root = path.resolve(__dirname, 'fixtures', 'root');
138+
const targetServer = httpServer.createServer({ root });
139+
140+
targetServer.listen(0, () => {
141+
const targetPort = targetServer.address().port;
142+
getPort().then((port) => {
143+
const options = [
144+
'--proxy', `http://localhost:${targetPort}`,
145+
'--proxy-all',
146+
root,
147+
'--port', port
148+
];
149+
const server = startServer(options);
150+
151+
tearDown(server, t);
152+
t.teardown(() => targetServer.close());
153+
154+
let sawRootLog = false;
155+
156+
server.stdout.on('data', (msg) => {
157+
const text = stripAnsi(msg.toString());
158+
if (text.includes(root)) {
159+
sawRootLog = true;
160+
}
161+
checkServerIsRunning(`http://localhost:${port}`, msg, t, (err, res) => {
162+
if (err) {
163+
t.fail(err.toString());
164+
return;
165+
}
166+
167+
t.ok(sawRootLog, 'root path should remain positional argument');
168+
t.equal(res.statusCode, 200, 'proxied request should succeed');
169+
});
170+
});
171+
});
172+
});
173+
});
174+
118175
function doHeaderOptionTest(t, argv, obj) {
119176
const options = ['.', '--port', defaultPort].concat(argv);
120177
const server = startServer(options);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This file should never be served when proxyAll is enabled.

test/fixtures/proxy-all-local/file

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Local proxy-all fixture file

0 commit comments

Comments
 (0)