You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
5.0 KiB
180 lines
5.0 KiB
"use strict"; |
|
var httpProxy = require("http-proxy"); |
|
var utils = require("./utils"); |
|
var proxyUtils = require("./proxy-utils"); |
|
var Immutable = require("immutable"); |
|
var Map = require("immutable").Map; |
|
var List = require("immutable").List; |
|
/** |
|
* Default options that are passed along to http-proxy |
|
*/ |
|
var defaultHttpProxyOptions = Map({ |
|
/** |
|
* This ensures targets are more likely to |
|
* accept each request |
|
*/ |
|
changeOrigin: true, |
|
/** |
|
* This handles redirects |
|
*/ |
|
autoRewrite: true, |
|
/** |
|
* This allows our self-signed certs to be used for development |
|
*/ |
|
secure: false, |
|
ws: true |
|
}); |
|
var defaultCookieOptions = Map({ |
|
stripDomain: true |
|
}); |
|
var ProxyOption = Immutable.Record({ |
|
route: "", |
|
target: "", |
|
rewriteRules: true, |
|
/** |
|
* Functions to be called on proxy request |
|
* with args [proxyReq, req, res, options] |
|
*/ |
|
proxyReq: List([]), |
|
/** |
|
* Functions to be called on proxy response |
|
* with args [proxyRes, req, res] |
|
*/ |
|
proxyRes: List([]), |
|
/** |
|
* Functions to be called on proxy response |
|
* with args [proxyReq, req, socket, options, head] |
|
*/ |
|
proxyReqWs: List([]), |
|
errHandler: undefined, |
|
url: Map({}), |
|
proxyOptions: Map(defaultHttpProxyOptions), |
|
cookies: Map(defaultCookieOptions), |
|
ws: false, |
|
middleware: List([]), |
|
reqHeaders: undefined |
|
}); |
|
/** |
|
* @param {BrowserSync} bs |
|
* @param {String} scripts |
|
* @returns {*} |
|
*/ |
|
module.exports = function createProxyServer(bs) { |
|
var opt = new ProxyOption().mergeDeep(bs.options.get("proxy")); |
|
var proxy = httpProxy.createProxyServer(opt |
|
.get("proxyOptions") |
|
.set("target", opt.get("target")) |
|
.toJS()); |
|
var target = opt.get("target"); |
|
var proxyReq = getProxyReqFunctions(opt.get("proxyReq"), opt, bs); |
|
var proxyRes = getProxyResFunctions(opt.get("proxyRes"), opt); |
|
var proxyResWs = opt.get("proxyReqWs"); |
|
bs.options = bs.options.update("middleware", function (mw) { |
|
return mw.concat({ |
|
id: "Browsersync Proxy", |
|
route: opt.get("route"), |
|
handle: function (req, res) { |
|
proxy.web(req, res, { |
|
target: target |
|
}); |
|
} |
|
}); |
|
}); |
|
var app = utils.getBaseApp(bs); |
|
/** |
|
* @type {*|{server, app}} |
|
*/ |
|
var browserSyncServer = utils.getServer(app, bs.options); |
|
browserSyncServer.proxy = proxy; |
|
if (opt.get("ws")) { |
|
// debug(`+ ws upgrade for: ${x.get("target")}`); |
|
browserSyncServer.server.on("upgrade", function (req, socket, head) { |
|
proxy.ws(req, socket, head); |
|
}); |
|
} |
|
/** |
|
* Add any user provided functions for proxyReq, proxyReqWs and proxyRes |
|
*/ |
|
applyFns("proxyReq", proxyReq); |
|
applyFns("proxyRes", proxyRes); |
|
applyFns("proxyReqWs", proxyResWs); |
|
/** |
|
* Handle Proxy errors |
|
*/ |
|
proxy.on("error", function (err) { |
|
if (typeof opt.get("errHandler") === "function") { |
|
opt.get("errHandler").call(null, err); |
|
} |
|
}); |
|
/** |
|
* Apply functions to proxy events |
|
* @param {string} name - the name of the http-proxy event |
|
* @param {Array} fns - functions to call on each event |
|
*/ |
|
function applyFns(name, fns) { |
|
if (!List.isList(fns)) |
|
fns = [fns]; |
|
proxy.on(name, function () { |
|
var args = arguments; |
|
fns.forEach(function (fn) { |
|
if (typeof fn === "function") { |
|
fn.apply(null, args); |
|
} |
|
}); |
|
}); |
|
} |
|
return browserSyncServer; |
|
}; |
|
/** |
|
* @param resFns |
|
* @returns {*} |
|
*/ |
|
function getProxyResFunctions(resFns, opt) { |
|
if (opt.getIn(["cookies", "stripDomain"])) { |
|
return resFns.push(proxyUtils.checkCookies); |
|
} |
|
return resFns; |
|
} |
|
/** |
|
* @param reqFns |
|
* @returns {*} |
|
*/ |
|
function getProxyReqFunctions(reqFns, opt, bs) { |
|
var reqHeaders = opt.getIn(["reqHeaders"]); |
|
if (!reqHeaders) { |
|
return reqFns; |
|
} |
|
/** |
|
* Back-compat for old `reqHeaders` option here a |
|
* function was given that returned an object |
|
* where key:value was header-name:header-value |
|
* This didn't really work as it clobbered all other headers, |
|
* but it remains for the unlucky few who used it. |
|
*/ |
|
if (typeof reqHeaders === "function") { |
|
var output = reqHeaders.call(bs, opt.toJS()); |
|
if (Object.keys(output).length) { |
|
return reqFns.concat(function (proxyReq) { |
|
Object.keys(output).forEach(function (key) { |
|
proxyReq.setHeader(key, output[key]); |
|
}); |
|
}); |
|
} |
|
} |
|
/** |
|
* Now, if {key:value} given, set the each header |
|
* |
|
* eg: reqHeaders: { |
|
* 'is-dev': 'true' |
|
* } |
|
*/ |
|
if (Map.isMap(reqHeaders)) { |
|
return reqFns.concat(function (proxyReq) { |
|
reqHeaders.forEach(function (value, key) { |
|
proxyReq.setHeader(key, value); |
|
}); |
|
}); |
|
} |
|
return reqFns; |
|
} |
|
//# sourceMappingURL=proxy-server.js.map
|