Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Added support to websocket & parametrized changeOrigin configuration … #528

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 40 additions & 22 deletions bin/http-server
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@

'use strict';

var colors = require('colors/safe'),
os = require('os'),
httpServer = require('../lib/http-server'),
portfinder = require('portfinder'),
opener = require('opener'),
argv = require('optimist')
.boolean('cors')
.boolean('log-ip')
.argv;
var colors = require('colors/safe'),
os = require('os'),
httpServer = require('../lib/http-server'),
portfinder = require('portfinder'),
opener = require('opener'),
argv = require('optimist')
.boolean('cors')
.boolean('log-ip')
.boolean('websocket')
.boolean('change-origin')
.argv;

var ifaces = os.networkInterfaces();

Expand Down Expand Up @@ -39,6 +41,10 @@ if (argv.h || argv.help) {
'',
' -P --proxy Fallback proxy if the request cannot be resolved. e.g.: http://someurl.com',
'',
' --change-origin Enable changing the origin host in request when proxy is enabled',
'',
' --websocket Enable websocket proxy',
'',
' --username Username for basic authentication [none]',
' Can also be specified with the env variable NODE_HTTP_SERVER_USERNAME',
' --password Password for basic authentication [none]',
Expand All @@ -56,20 +62,22 @@ if (argv.h || argv.help) {
}

var port = argv.p || argv.port || parseInt(process.env.PORT, 10),
host = argv.a || '0.0.0.0',
ssl = !!argv.S || !!argv.ssl,
proxy = argv.P || argv.proxy,
utc = argv.U || argv.utc,
logger;
host = argv.a || '0.0.0.0',
ssl = !!argv.S || !!argv.ssl,
proxy = argv.P || argv.proxy,
websocket = argv.websocket,
changeOrigin = argv['change-origin'],
utc = argv.U || argv.utc,
logger;

if (!argv.s && !argv.silent) {
logger = {
info: console.log,
request: function (req, res, error) {
var date = utc ? new Date().toUTCString() : new Date();
var ip = argv['log-ip']
? req.headers['x-forwarded-for'] || '' + req.connection.remoteAddress
: '';
? req.headers['x-forwarded-for'] || '' + req.connection.remoteAddress
: '';
if (error) {
logger.info(
'[%s] %s "%s %s" Error (%s): "%s"',
Expand All @@ -89,8 +97,8 @@ if (!argv.s && !argv.silent) {
}
else if (colors) {
logger = {
info: function () {},
request: function () {}
info: function () { },
request: function () { }
};
}

Expand All @@ -117,11 +125,21 @@ function listen(port) {
ext: argv.e || argv.ext,
logFn: logger.request,
proxy: proxy,
changeOrigin: changeOrigin,
showDotfiles: argv.dotfiles,
username: argv.username || process.env.NODE_HTTP_SERVER_USERNAME,
password: argv.password || process.env.NODE_HTTP_SERVER_PASSWORD
};

if (websocket) {
if (!proxy) {
logger.warning(colors.yellow('WebSocket proxy will not be enabled because proxy is not enabled'));
}
else {
options.websocket = true;
}
}

if (argv.cors) {
options.cors = true;
if (typeof argv.cors === 'string') {
Expand All @@ -139,12 +157,12 @@ function listen(port) {
var server = httpServer.createServer(options);
server.listen(port, host, function () {
var canonicalHost = host === '0.0.0.0' ? '127.0.0.1' : host,
protocol = ssl ? 'https://' : 'http://';
protocol = ssl ? 'https://' : 'http://';

logger.info([colors.yellow('Starting up http-server, serving '),
colors.cyan(server.root),
ssl ? (colors.yellow(' through') + colors.cyan(' https')) : '',
colors.yellow('\nAvailable on:')
colors.cyan(server.root),
ssl ? (colors.yellow(' through') + colors.cyan(' https')) : '',
colors.yellow('\nAvailable on:')
].join(''));

if (argv.a && host !== '0.0.0.0') {
Expand Down
95 changes: 52 additions & 43 deletions lib/http-server.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use strict';

var fs = require('fs'),
union = require('union'),
ecstatic = require('ecstatic'),
auth = require('basic-auth'),
httpProxy = require('http-proxy'),
corser = require('corser'),
secureCompare = require('secure-compare');
union = require('union'),
ecstatic = require('ecstatic'),
auth = require('basic-auth'),
httpProxy = require('http-proxy'),
corser = require('corser'),
secureCompare = require('secure-compare');

//
// Remark: backwards compatibility for previous
Expand All @@ -28,39 +28,41 @@ exports.createServer = function (options) {
* with other HTTP-related features.
*/
function HttpServer(options) {
var self = this;

options = options || {};

if (options.root) {
this.root = options.root;
self.root = options.root;
}
else {
try {
fs.lstatSync('./public');
this.root = './public';
self.root = './public';
}
catch (err) {
this.root = './';
self.root = './';
}
}

this.headers = options.headers || {};
self.headers = options.headers || {};

this.cache = (
self.cache = (
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 // in seconds.
// -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 // in seconds.
);
this.showDir = options.showDir !== 'false';
this.autoIndex = options.autoIndex !== 'false';
this.showDotfiles = options.showDotfiles;
this.gzip = options.gzip === true;
this.brotli = options.brotli === true;
this.contentType = options.contentType || 'application/octet-stream';
self.showDir = options.showDir !== 'false';
self.autoIndex = options.autoIndex !== 'false';
self.showDotfiles = options.showDotfiles;
self.gzip = options.gzip === true;
self.brotli = options.brotli === true;
self.contentType = options.contentType || 'application/octet-stream';

if (options.ext) {
this.ext = options.ext === true
self.ext = options.ext === true
? 'html'
: options.ext;
}
Expand Down Expand Up @@ -97,14 +99,14 @@ function HttpServer(options) {
}

if (options.cors) {
this.headers['Access-Control-Allow-Origin'] = '*';
this.headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Range';
self.headers['Access-Control-Allow-Origin'] = '*';
self.headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Range';
if (options.corsHeaders) {
options.corsHeaders.split(/\s*,\s*/)
.forEach(function (h) { this.headers['Access-Control-Allow-Headers'] += ', ' + h; }, this);
.forEach(function (h) { self.headers['Access-Control-Allow-Headers'] += ', ' + h; }, self);
}
before.push(corser.create(options.corsHeaders ? {
requestHeaders: this.headers['Access-Control-Allow-Headers'].split(/\s*,\s*/)
requestHeaders: self.headers['Access-Control-Allow-Headers'].split(/\s*,\s*/)
} : null));
}

Expand All @@ -124,29 +126,30 @@ function HttpServer(options) {
}

before.push(ecstatic({
root: this.root,
cache: this.cache,
showDir: this.showDir,
showDotfiles: this.showDotfiles,
autoIndex: this.autoIndex,
defaultExt: this.ext,
gzip: this.gzip,
brotli: this.brotli,
contentType: this.contentType,
root: self.root,
cache: self.cache,
showDir: self.showDir,
showDotfiles: self.showDotfiles,
autoIndex: self.autoIndex,
defaultExt: self.ext,
gzip: self.gzip,
brotli: self.brotli,
contentType: self.contentType,
handleError: typeof options.proxy !== 'string'
}));

if (typeof options.proxy === 'string') {
var proxy = httpProxy.createProxyServer({});
self.proxyServer = httpProxy.createProxyServer({
target: options.proxy,
changeOrigin: options.changeOrigin
});
before.push(function (req, res) {
proxy.web(req, res, {
target: options.proxy,
changeOrigin: true
}, function (err, req, res, target) {
self.proxyServer.web(req, res, {}, function (err, req, res, target) {
if (options.logFn) {
options.logFn(req, res, {
message: err.message,
status: res.statusCode });
status: res.statusCode
});
}
res.emit('next');
});
Expand All @@ -155,7 +158,7 @@ function HttpServer(options) {

var serverOptions = {
before: before,
headers: this.headers,
headers: self.headers,
onError: function (err, req, res) {
if (options.logFn) {
options.logFn(req, res, err);
Expand All @@ -169,7 +172,13 @@ function HttpServer(options) {
serverOptions.https = options.https;
}

this.server = union.createServer(serverOptions);
self.server = union.createServer(serverOptions);

if (self.proxyServer && options.websocket) {
self.server.on('upgrade', function (request, socket, head) {
self.proxyServer.ws(request, socket, head);
});
}
}

HttpServer.prototype.listen = function () {
Expand Down
Loading