diff --git a/README.md b/README.md index 9c5cd4b..3fc91ad 100644 --- a/README.md +++ b/README.md @@ -37,24 +37,42 @@ $ ws --spa index.html By default, typical SPA urls (e.g. `/user/1`, `/login`) would return `404 Not Found` as a file does not exist with that path. By marking `index.html` as the SPA you create this rule: -*If a static file at the requested path exists (e.g. `/css/style.css`) then serve it, if it does not (e.g. `/login`) then serve the SPA for client-side processing.* +*If a static file at the requested path exists (e.g. `/css/style.css`) then serve it, if it does not (e.g. `/login`) then serve the SPA and handle the route client-side.* ### Access Control -Access to all files is allowed, beside those in the forbidden list (e.g. config files): +By default, access to all files is allowed (including dot files). Use `--forbid` to establish a blacklist: ```sh $ ws --forbid .json .yml serving at http://localhost:8000 ``` +[Path syntax](http://expressjs.com/guide/routing.html#route-paths) + ### URL rewriting -When urls don't map to your directory structure, rewrite: +Your application requested `/css/style.css` but it's stored at `/build/css/style.css`. Create a rewrite rule: + +```sh +$ ws --rewrite "/css/style.css -> /build/css/style.css" +``` + +Or, more generally (matching any stylesheet path under `/css`): + ```sh -$ ws --rewrite /css=>/build/css +$ ws --rewrite "/css/:stylesheet -> /build/css/:stylesheet" ``` -Rewrite to remote servers (proxy): +If a deep structure is involved it may be easier to mount the entire contents of `/build/css` to the `/css` path: (matches any stylesheet path under `/css`, `/css/a`, `/css/a/b` etc.) + +```sh +$ ws --rewrite "/css/* -> /build/css/$1" +``` + + +#### Proxied rewrite + +If the `to` address contains a hostname local-web-server will act as a proxy - the remote resource will be fetched and returned ```sh $ ws --rewrite "/api => http://api.example.com/api" \ "/npm => http://registry.npmjs.com" \ diff --git a/bin/cli.js b/bin/cli.js index 22e0c92..711bc7a 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -12,6 +12,9 @@ const usage = cli.getUsage(cliOptions.usageData) const stored = loadConfig('local-web-server') const options = collectOptions() +// TODO --config show the merged options +// TODO summary line on server launch + if (options.misc.help) { console.log(usage) process.exit(0) @@ -40,10 +43,10 @@ localWebServer({ }, compress: options.server.compress, mime: options.server.mime, - forbid: options.server.forbid.map(regexp => RegExp(regexp, 'i')), + forbid: options.server.forbid, spa: options.server.spa, 'no-cache': options.server['no-cache'], - rewrite: parseRewriteRules(options.server.rewrite) + rewrite: options.server.rewrite }).listen(options.server.port, onServerUp) function halt (err) { @@ -74,7 +77,11 @@ function collectOptions () { port: 8000, directory: process.cwd(), forbid: [], - proxyRoutes: [] + rewrite: [] + } + + if (options.server.rewrite) { + options.server.rewrite = parseRewriteRules(options.server.rewrite) } /* override built-in defaults with stored config and then command line args */ @@ -83,7 +90,7 @@ function collectOptions () { } function parseRewriteRules (rules) { - return rules.map(rule => { + return rules && rules.map(rule => { const matches = rule.match(/(\S*)\s*->\s*(\S*)/) return { from: matches[1], diff --git a/example/forbid/.local-web-server.json b/example/forbid/.local-web-server.json new file mode 100644 index 0000000..dd8124a --- /dev/null +++ b/example/forbid/.local-web-server.json @@ -0,0 +1,5 @@ +{ + "forbid": [ + "/admin/*", "*.php" + ] +} diff --git a/example/forbid/admin/blocked.html b/example/forbid/admin/blocked.html new file mode 100644 index 0000000..f51dbee --- /dev/null +++ b/example/forbid/admin/blocked.html @@ -0,0 +1 @@ +

Forbidden page

diff --git a/example/forbid/allowed.html b/example/forbid/allowed.html new file mode 100644 index 0000000..4d0bd56 --- /dev/null +++ b/example/forbid/allowed.html @@ -0,0 +1 @@ +

A permitted page

diff --git a/example/forbid/index.html b/example/forbid/index.html new file mode 100644 index 0000000..b2b30ff --- /dev/null +++ b/example/forbid/index.html @@ -0,0 +1,5 @@ +

Forbidden routes

+ +

+ Notice you can access this page, but not this admin page or php file. +

diff --git a/example/forbid/something.php b/example/forbid/something.php new file mode 100644 index 0000000..abb2fca --- /dev/null +++ b/example/forbid/something.php @@ -0,0 +1 @@ + diff --git a/example/rewrite/.local-web-server.json b/example/rewrite/.local-web-server.json index d30aa33..b4ad537 100644 --- a/example/rewrite/.local-web-server.json +++ b/example/rewrite/.local-web-server.json @@ -1,6 +1,6 @@ { "rewrite": [ - { "from": "/css/*", "to": "/styles/$1" }, + { "from": "/css/*", "to": "/build/styles/$1" }, { "from": "/npm/*", "to": "http://registry.npmjs.org/$1" }, { "from": "/gh/:user/repo/:name", "to": "https://api.github.com/repos/:user/:name" } ] diff --git a/example/rewrite/styles/style.css b/example/rewrite/build/styles/style.css similarity index 100% rename from example/rewrite/styles/style.css rename to example/rewrite/build/styles/style.css diff --git a/jsdoc2md/README.hbs b/jsdoc2md/README.hbs index a84fa81..a701f08 100644 --- a/jsdoc2md/README.hbs +++ b/jsdoc2md/README.hbs @@ -37,24 +37,42 @@ $ ws --spa index.html By default, typical SPA urls (e.g. `/user/1`, `/login`) would return `404 Not Found` as a file does not exist with that path. By marking `index.html` as the SPA you create this rule: -*If a static file at the requested path exists (e.g. `/css/style.css`) then serve it, if it does not (e.g. `/login`) then serve the SPA for client-side processing.* +*If a static file at the requested path exists (e.g. `/css/style.css`) then serve it, if it does not (e.g. `/login`) then serve the SPA and handle the route client-side.* ### Access Control -Access to all files is allowed, beside those in the forbidden list (e.g. config files): +By default, access to all files is allowed (including dot files). Use `--forbid` to establish a blacklist: ```sh $ ws --forbid .json .yml serving at http://localhost:8000 ``` +[Path syntax](http://expressjs.com/guide/routing.html#route-paths) + ### URL rewriting -When urls don't map to your directory structure, rewrite: +Your application requested `/css/style.css` but it's stored at `/build/css/style.css`. Create a rewrite rule: + +```sh +$ ws --rewrite "/css/style.css -> /build/css/style.css" +``` + +Or, more generally (matching any stylesheet path under `/css`): + ```sh -$ ws --rewrite /css=>/build/css +$ ws --rewrite "/css/:stylesheet -> /build/css/:stylesheet" ``` -Rewrite to remote servers (proxy): +If a deep structure is involved it may be easier to mount the entire contents of `/build/css` to the `/css` path: (matches any stylesheet path under `/css`, `/css/a`, `/css/a/b` etc.) + +```sh +$ ws --rewrite "/css/* -> /build/css/$1" +``` + + +#### Proxied rewrite + +If the `to` address contains a hostname local-web-server will act as a proxy - the remote resource will be fetched and returned ```sh $ ws --rewrite "/api => http://api.example.com/api" \ "/npm => http://registry.npmjs.com" \ diff --git a/lib/local-web-server.js b/lib/local-web-server.js index e419ea1..9ffdf3d 100644 --- a/lib/local-web-server.js +++ b/lib/local-web-server.js @@ -129,9 +129,7 @@ function localWebServer (options) { function logstalgiaDate () { var d = new Date() - return (`${d.getDate()}/${d.getUTCMonth()}/${d.getFullYear()}:${d.toTimeString()}`) - .replace('GMT', '') - .replace(' (BST)', '') + return (`${d.getDate()}/${d.getUTCMonth()}/${d.getFullYear()}:${d.toTimeString()}`).replace('GMT', '').replace(' (BST)', '') } function proxyRequest (route) { @@ -174,7 +172,7 @@ function proxyRequest (route) { function blacklist (forbid) { return function blacklist (ctx, next) { - if (forbid.some(regexp => regexp.test(ctx.path))) { + if (forbid.some(expression => pathToRegexp(expression).test(ctx.path))) { ctx.throw(403, http.STATUS_CODES[403]) } else { return next()