proxy-server.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. "use strict";
  2. var httpProxy = require("http-proxy");
  3. var utils = require("./utils");
  4. var proxyUtils = require("./proxy-utils");
  5. var Immutable = require("immutable");
  6. var Map = require("immutable").Map;
  7. var List = require("immutable").List;
  8. /**
  9. * Default options that are passed along to http-proxy
  10. */
  11. var defaultHttpProxyOptions = Map({
  12. /**
  13. * This ensures targets are more likely to
  14. * accept each request
  15. */
  16. changeOrigin: true,
  17. /**
  18. * This handles redirects
  19. */
  20. autoRewrite: true,
  21. /**
  22. * This allows our self-signed certs to be used for development
  23. */
  24. secure: false,
  25. ws: true
  26. });
  27. var defaultCookieOptions = Map({
  28. stripDomain: true
  29. });
  30. var ProxyOption = Immutable.Record({
  31. route: "",
  32. target: "",
  33. rewriteRules: true,
  34. /**
  35. * Functions to be called on proxy request
  36. * with args [proxyReq, req, res, options]
  37. */
  38. proxyReq: List([]),
  39. /**
  40. * Functions to be called on proxy response
  41. * with args [proxyRes, req, res]
  42. */
  43. proxyRes: List([]),
  44. /**
  45. * Functions to be called on proxy response
  46. * with args [proxyReq, req, socket, options, head]
  47. */
  48. proxyReqWs: List([]),
  49. errHandler: undefined,
  50. url: Map({}),
  51. proxyOptions: Map(defaultHttpProxyOptions),
  52. cookies: Map(defaultCookieOptions),
  53. ws: false,
  54. middleware: List([]),
  55. reqHeaders: undefined
  56. });
  57. /**
  58. * @param {BrowserSync} bs
  59. * @param {String} scripts
  60. * @returns {*}
  61. */
  62. module.exports = function createProxyServer(bs) {
  63. var opt = new ProxyOption().mergeDeep(bs.options.get("proxy"));
  64. var proxy = httpProxy.createProxyServer(opt
  65. .get("proxyOptions")
  66. .set("target", opt.get("target"))
  67. .toJS());
  68. var target = opt.get("target");
  69. var proxyReq = getProxyReqFunctions(opt.get("proxyReq"), opt, bs);
  70. var proxyRes = getProxyResFunctions(opt.get("proxyRes"), opt);
  71. var proxyResWs = opt.get("proxyReqWs");
  72. bs.options = bs.options.update("middleware", function (mw) {
  73. return mw.concat({
  74. id: "Browsersync Proxy",
  75. route: opt.get("route"),
  76. handle: function (req, res) {
  77. proxy.web(req, res, {
  78. target: target
  79. });
  80. }
  81. });
  82. });
  83. var app = utils.getBaseApp(bs);
  84. /**
  85. * @type {*|{server, app}}
  86. */
  87. var browserSyncServer = utils.getServer(app, bs.options);
  88. browserSyncServer.proxy = proxy;
  89. if (opt.get("ws")) {
  90. // debug(`+ ws upgrade for: ${x.get("target")}`);
  91. browserSyncServer.server.on("upgrade", function (req, socket, head) {
  92. proxy.ws(req, socket, head);
  93. });
  94. }
  95. /**
  96. * Add any user provided functions for proxyReq, proxyReqWs and proxyRes
  97. */
  98. applyFns("proxyReq", proxyReq);
  99. applyFns("proxyRes", proxyRes);
  100. applyFns("proxyReqWs", proxyResWs);
  101. /**
  102. * Handle Proxy errors
  103. */
  104. proxy.on("error", function (err) {
  105. if (typeof opt.get("errHandler") === "function") {
  106. opt.get("errHandler").call(null, err);
  107. }
  108. });
  109. /**
  110. * Apply functions to proxy events
  111. * @param {string} name - the name of the http-proxy event
  112. * @param {Array} fns - functions to call on each event
  113. */
  114. function applyFns(name, fns) {
  115. if (!List.isList(fns))
  116. fns = [fns];
  117. proxy.on(name, function () {
  118. var args = arguments;
  119. fns.forEach(function (fn) {
  120. if (typeof fn === "function") {
  121. fn.apply(null, args);
  122. }
  123. });
  124. });
  125. }
  126. return browserSyncServer;
  127. };
  128. /**
  129. * @param resFns
  130. * @returns {*}
  131. */
  132. function getProxyResFunctions(resFns, opt) {
  133. if (opt.getIn(["cookies", "stripDomain"])) {
  134. return resFns.push(proxyUtils.checkCookies);
  135. }
  136. return resFns;
  137. }
  138. /**
  139. * @param reqFns
  140. * @returns {*}
  141. */
  142. function getProxyReqFunctions(reqFns, opt, bs) {
  143. var reqHeaders = opt.getIn(["reqHeaders"]);
  144. if (!reqHeaders) {
  145. return reqFns;
  146. }
  147. /**
  148. * Back-compat for old `reqHeaders` option here a
  149. * function was given that returned an object
  150. * where key:value was header-name:header-value
  151. * This didn't really work as it clobbered all other headers,
  152. * but it remains for the unlucky few who used it.
  153. */
  154. if (typeof reqHeaders === "function") {
  155. var output = reqHeaders.call(bs, opt.toJS());
  156. if (Object.keys(output).length) {
  157. return reqFns.concat(function (proxyReq) {
  158. Object.keys(output).forEach(function (key) {
  159. proxyReq.setHeader(key, output[key]);
  160. });
  161. });
  162. }
  163. }
  164. /**
  165. * Now, if {key:value} given, set the each header
  166. *
  167. * eg: reqHeaders: {
  168. * 'is-dev': 'true'
  169. * }
  170. */
  171. if (Map.isMap(reqHeaders)) {
  172. return reqFns.concat(function (proxyReq) {
  173. reqHeaders.forEach(function (value, key) {
  174. proxyReq.setHeader(key, value);
  175. });
  176. });
  177. }
  178. return reqFns;
  179. }
  180. //# sourceMappingURL=proxy-server.js.map