123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- "use strict";
- var fs = require("fs");
- var path = require("path");
- var join = require("path").join;
- var connect = require("connect");
- var Immutable = require("immutable");
- var http = require("http");
- var https = require("https");
- var Map = require("immutable").Map;
- var fromJS = require("immutable").fromJS;
- var List = require("immutable").List;
- var snippet = require("./../snippet").utils;
- var _ = require("../lodash.custom");
- var serveStatic = require("./serve-static-wrapper").default();
- var serveIndex = require("serve-index");
- var logger = require("../logger");
- var snippetUtils = require("../snippet").utils;
- var lrSnippet = require("resp-modifier");
- var certPath = join(__dirname, "..", "..", "certs");
- function getCa(options) {
- var caOption = options.getIn(["https", "ca"]);
- // if not provided, use Browsersync self-signed
- if (typeof caOption === "undefined") {
- return fs.readFileSync(join(certPath, "server.csr"));
- }
- // if a string was given, read that file from disk
- if (typeof caOption === "string") {
- return fs.readFileSync(caOption);
- }
- // if an array was given, read all
- if (List.isList(caOption)) {
- return caOption.toArray().map(function (x) {
- return fs.readFileSync(x);
- });
- }
- }
- function getKey(options) {
- return fs.readFileSync(options.getIn(["https", "key"]) || join(certPath, "server.key"));
- }
- function getCert(options) {
- return fs.readFileSync(options.getIn(["https", "cert"]) || join(certPath, "server.crt"));
- }
- function getHttpsServerDefaults(options) {
- return fromJS({
- key: getKey(options),
- cert: getCert(options),
- ca: getCa(options),
- passphrase: ""
- });
- }
- function getPFXDefaults(options) {
- return fromJS({
- pfx: fs.readFileSync(options.getIn(["https", "pfx"]))
- });
- }
- var serverUtils = {
- /**
- * @param options
- * @returns {{key, cert}}
- */
- getHttpsOptions: function (options) {
- var userOption = options.get("https");
- if (Map.isMap(userOption)) {
- if (userOption.has("pfx")) {
- return userOption.mergeDeep(getPFXDefaults(options));
- }
- return userOption.mergeDeep(getHttpsServerDefaults(options));
- }
- return getHttpsServerDefaults(options);
- },
- /**
- * Get either http or https server
- * or use the httpModule provided in options if present
- */
- getServer: function (app, options) {
- return {
- server: (function () {
- var httpModule = serverUtils.getHttpModule(options);
- if (options.get("scheme") === "https" ||
- options.get("httpModule") === "http2") {
- var opts = serverUtils.getHttpsOptions(options);
- return httpModule.createServer(opts.toJS(), app);
- }
- return httpModule.createServer(app);
- })(),
- app: app
- };
- },
- getHttpModule: function (options) {
- /**
- * Users may provide a string to be used by nodes
- * require lookup.
- */
- var httpModule = options.get("httpModule");
- if (typeof httpModule === "string") {
- /**
- * Note, this could throw, but let that happen as
- * the error message good enough.
- */
- var maybe = require.resolve(httpModule);
- return require(maybe);
- }
- if (options.get("scheme") === "https") {
- return https;
- }
- return http;
- },
- getMiddlewares: function (bs) {
- var clientJs = bs.pluginManager.hook("client:js", {
- port: bs.options.get("port"),
- options: bs.options
- });
- var scripts = bs.pluginManager.get("client:script")(bs.options.toJS(), clientJs, "middleware");
- var defaultMiddlewares = [
- {
- id: "Browsersync HTTP Protocol",
- route: require("../config").httpProtocol.path,
- handle: require("../http-protocol").middleware(bs)
- },
- {
- id: "Browsersync IE8 Support",
- route: "",
- handle: snippet.isOldIe(bs.options.get("excludedFileTypes").toJS())
- },
- {
- id: "Browsersync Response Modifier",
- route: "",
- handle: serverUtils.getSnippetMiddleware(bs)
- },
- {
- id: "Browsersync Client - versioned",
- route: bs.options.getIn(["scriptPaths", "versioned"]),
- handle: scripts
- },
- {
- id: "Browsersync Client",
- route: bs.options.getIn(["scriptPaths", "path"]),
- handle: scripts
- }
- ];
- /**
- * Add cors middleware to the front of the stack
- * if a user provided a 'cors' flag
- */
- if (bs.options.get("cors")) {
- defaultMiddlewares.unshift({
- id: "Browsersync CORS support",
- route: "",
- handle: serverUtils.getCorsMiddlewware()
- });
- }
- /**
- * Add connect-history-api-fallback if 'single' argument given
- */
- if (bs.options.get("single")) {
- defaultMiddlewares.unshift({
- id: "Browsersync SPA support",
- route: "",
- handle: require("connect-history-api-fallback")()
- });
- }
- /**
- * Add serve static middleware
- */
- if (bs.options.get("serveStatic")) {
- var ssMiddlewares = serverUtils.getServeStaticMiddlewares(bs.options.get("serveStatic"), bs.options.get("serveStaticOptions", Immutable.Map({})).toJS());
- var withErrors = ssMiddlewares.filter(function (x) {
- return x.get("errors").size > 0;
- });
- var withoutErrors = ssMiddlewares.filter(function (x) {
- return x.get("errors").size === 0;
- });
- if (withErrors.size) {
- withErrors.forEach(function (item) {
- logger.logger.error("{red:Warning!} %s", item.getIn(["errors", 0, "data", "message"]));
- });
- }
- if (withoutErrors.size) {
- withoutErrors.forEach(function (item) {
- defaultMiddlewares.push.apply(defaultMiddlewares, item.get("items").toJS());
- });
- }
- }
- /**
- * Add user-provided middlewares
- */
- var userMiddlewares = bs.options
- .get("middleware")
- .map(normaliseMiddleware)
- .toArray();
- var beforeMiddlewares = userMiddlewares.filter(function (x) {
- return x.override;
- });
- var afterMiddlewares = userMiddlewares
- .filter(function (x) {
- return !x.override;
- })
- .concat(bs.options.get("mode") !== "proxy" &&
- userMiddlewares.length === 0 && {
- id: "Browsersync 404/index support",
- route: "",
- handle: serveIndex(bs.options.get("cwd"), {
- icons: true,
- view: "details"
- })
- });
- var mwStack = []
- .concat(beforeMiddlewares, defaultMiddlewares, afterMiddlewares)
- .filter(Boolean);
- return mwStack;
- function normaliseMiddleware(item) {
- /**
- * Object given in options, which
- * ended up being a Map
- */
- if (Map.isMap(item)) {
- return item.toJS();
- }
- /**
- * Single function
- */
- if (typeof item === "function") {
- return {
- route: "",
- handle: item
- };
- }
- /**
- * Plain obj
- */
- if (item.route !== undefined && item.handle) {
- return item;
- }
- }
- },
- getBaseApp: function (bs) {
- var app = connect();
- var middlewares = serverUtils.getMiddlewares(bs);
- /**
- * Add all internal middlewares
- */
- middlewares.forEach(function (item) {
- app.stack.push(item);
- });
- return app;
- },
- getSnippetMiddleware: function (bs) {
- var rules = [];
- var blacklist = List([])
- .concat(bs.options.getIn(["snippetOptions", "ignorePaths"]))
- .concat(bs.options.getIn(["snippetOptions", "blacklist"]))
- .filter(Boolean);
- var whitelist = List([]).concat(bs.options.getIn(["snippetOptions", "whitelist"]));
- // Snippet
- rules.push(snippetUtils.getRegex(bs.options.get("snippet"), bs.options.get("snippetOptions")));
- // User
- bs.options.get("rewriteRules").forEach(function (rule) {
- if (Map.isMap(rule)) {
- rules.push(rule.toJS());
- }
- if (_.isPlainObject(rule)) {
- rules.push(rule);
- }
- });
- // Proxy
- if (bs.options.get("proxy")) {
- var proxyRule = require("./proxy-utils").rewriteLinks(bs.options.getIn(["proxy", "url"]).toJS());
- rules.push(proxyRule);
- }
- var lr = lrSnippet.create({
- rules: rules,
- blacklist: blacklist.toArray(),
- whitelist: whitelist.toArray()
- });
- return lr.middleware;
- },
- getCorsMiddlewware: function () {
- return function (req, res, next) {
- // Website you wish to allow to connect
- res.setHeader("Access-Control-Allow-Origin", "*");
- // Request methods you wish to allow
- res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, PATCH, DELETE");
- // Request headers you wish to allow
- res.setHeader("Access-Control-Allow-Headers", "X-Requested-With,content-type");
- // Set to true if you need the website to include cookies in the requests sent
- // to the API (e.g. in case you use sessions)
- res.setHeader("Access-Control-Allow-Credentials", true);
- next();
- };
- },
- /**
- * @param ssOption
- * @param serveStaticOptions
- * @returns {*}
- */
- getServeStaticMiddlewares: function (ssOption, serveStaticOptions) {
- return ssOption.map(function (dir, i) {
- /**
- * When a user gives a plain string only, eg:
- * serveStatic: ['./temp']
- * ->
- * This means a middleware will be created with
- * route: ''
- * handle: serveStatic('./temp', options)
- */
- if (_.isString(dir)) {
- return getFromString(dir);
- }
- /**
- * If a user gave an object eg:
- * serveStatic: [{route: "", dir: ["test", "./tmp"]}]
- * ->
- * This means we need to create a middle for each route + dir combo
- */
- if (Immutable.Map.isMap(dir)) {
- return getFromMap(dir, i);
- }
- /**
- * At this point, an item in the serveStatic array was not a string
- * or an object so we return an error that can be logged
- */
- return fromJS({
- items: [],
- errors: [
- {
- type: "Invalid Type",
- data: {
- message: "Only strings and Objects (with route+dir) are supported for the ServeStatic option"
- }
- }
- ]
- });
- });
- /**
- * @param {string} x
- * @returns {string}
- */
- function getRoute(x) {
- if (x === "")
- return "";
- return x[0] === "/" ? x : "/" + x;
- }
- /**
- * @param dir
- * @returns {Map}
- */
- function getFromString(dir) {
- return fromJS({
- items: [
- {
- route: "",
- handle: serveStatic(dir, serveStaticOptions)
- }
- ],
- errors: []
- });
- }
- /**
- * @param dir
- * @returns {Map}
- */
- function getFromMap(dir) {
- var ssOptions = (function () {
- if (dir.get("options")) {
- return dir.get("options").toJS();
- }
- return {};
- })();
- var route = Immutable.List([])
- .concat(dir.get("route"))
- .filter(_.isString);
- var _dir = Immutable.List([])
- .concat(dir.get("dir"))
- .filter(_.isString);
- if (_dir.size === 0) {
- return fromJS({
- items: [],
- errors: [
- {
- type: "Invalid Object",
- data: {
- message: "Serve Static requires a 'dir' property when using an Object"
- }
- }
- ]
- });
- }
- var ssItems = (function () {
- /**
- * iterate over every 'route' item
- * @type {Immutable.List<any>|Immutable.List<*>|Immutable.List<any>|*}
- */
- var routeItems = (function () {
- /**
- * If no 'route' was given, assume we want to match all
- * paths
- */
- if (route.size === 0) {
- return _dir.map(function (dirString) {
- return Map({
- route: "",
- dir: dirString
- });
- });
- }
- return route.reduce(function (acc, routeString) {
- /**
- * For each 'route' item, also iterate through 'dirs'
- * @type {Immutable.Iterable<K, M>}
- */
- var perDir = _dir.map(function (dirString) {
- return Map({
- route: getRoute(routeString),
- dir: dirString
- });
- });
- return acc.concat(perDir);
- }, List([]));
- })();
- /**
- * Now create a serverStatic Middleware for each item
- */
- return routeItems.map(function (routeItem) {
- return routeItem.merge({
- handle: serveStatic(routeItem.get("dir"), ssOptions)
- });
- });
- })();
- return fromJS({
- items: ssItems,
- errors: []
- });
- }
- }
- };
- module.exports = serverUtils;
- //# sourceMappingURL=utils.js.map
|