forbid now uses path-to-regexp paths.. docs.. rewrite examples
This commit is contained in:
28
README.md
28
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:
|
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 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
|
```sh
|
||||||
$ ws --forbid .json .yml
|
$ ws --forbid .json .yml
|
||||||
serving at http://localhost:8000
|
serving at http://localhost:8000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[Path syntax](http://expressjs.com/guide/routing.html#route-paths)
|
||||||
|
|
||||||
### URL rewriting
|
### 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
|
```sh
|
||||||
$ ws --rewrite /css=>/build/css
|
$ ws --rewrite "/css/style.css -> /build/css/style.css"
|
||||||
```
|
```
|
||||||
|
|
||||||
Rewrite to remote servers (proxy):
|
Or, more generally (matching any stylesheet path under `/css`):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ ws --rewrite "/css/:stylesheet -> /build/css/:stylesheet"
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
```sh
|
||||||
$ ws --rewrite "/api => http://api.example.com/api" \
|
$ ws --rewrite "/api => http://api.example.com/api" \
|
||||||
"/npm => http://registry.npmjs.com" \
|
"/npm => http://registry.npmjs.com" \
|
||||||
|
15
bin/cli.js
15
bin/cli.js
@ -12,6 +12,9 @@ const usage = cli.getUsage(cliOptions.usageData)
|
|||||||
const stored = loadConfig('local-web-server')
|
const stored = loadConfig('local-web-server')
|
||||||
const options = collectOptions()
|
const options = collectOptions()
|
||||||
|
|
||||||
|
// TODO --config show the merged options
|
||||||
|
// TODO summary line on server launch
|
||||||
|
|
||||||
if (options.misc.help) {
|
if (options.misc.help) {
|
||||||
console.log(usage)
|
console.log(usage)
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
@ -40,10 +43,10 @@ localWebServer({
|
|||||||
},
|
},
|
||||||
compress: options.server.compress,
|
compress: options.server.compress,
|
||||||
mime: options.server.mime,
|
mime: options.server.mime,
|
||||||
forbid: options.server.forbid.map(regexp => RegExp(regexp, 'i')),
|
forbid: options.server.forbid,
|
||||||
spa: options.server.spa,
|
spa: options.server.spa,
|
||||||
'no-cache': options.server['no-cache'],
|
'no-cache': options.server['no-cache'],
|
||||||
rewrite: parseRewriteRules(options.server.rewrite)
|
rewrite: options.server.rewrite
|
||||||
}).listen(options.server.port, onServerUp)
|
}).listen(options.server.port, onServerUp)
|
||||||
|
|
||||||
function halt (err) {
|
function halt (err) {
|
||||||
@ -74,7 +77,11 @@ function collectOptions () {
|
|||||||
port: 8000,
|
port: 8000,
|
||||||
directory: process.cwd(),
|
directory: process.cwd(),
|
||||||
forbid: [],
|
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 */
|
/* override built-in defaults with stored config and then command line args */
|
||||||
@ -83,7 +90,7 @@ function collectOptions () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function parseRewriteRules (rules) {
|
function parseRewriteRules (rules) {
|
||||||
return rules.map(rule => {
|
return rules && rules.map(rule => {
|
||||||
const matches = rule.match(/(\S*)\s*->\s*(\S*)/)
|
const matches = rule.match(/(\S*)\s*->\s*(\S*)/)
|
||||||
return {
|
return {
|
||||||
from: matches[1],
|
from: matches[1],
|
||||||
|
5
example/forbid/.local-web-server.json
Normal file
5
example/forbid/.local-web-server.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"forbid": [
|
||||||
|
"/admin/*", "*.php"
|
||||||
|
]
|
||||||
|
}
|
1
example/forbid/admin/blocked.html
Normal file
1
example/forbid/admin/blocked.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<h1>Forbidden page</h1>
|
1
example/forbid/allowed.html
Normal file
1
example/forbid/allowed.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<h1>A permitted page</h1>
|
5
example/forbid/index.html
Normal file
5
example/forbid/index.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<h1>Forbidden routes</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Notice you can access <a href="allowed.html">this page</a>, but not <a href="admin/blocked.html">this admin page</a> or <a href="something.php">php file</a>.
|
||||||
|
</p>
|
1
example/forbid/something.php
Normal file
1
example/forbid/something.php
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?php echo "i'm coding PHP templatez!\n" ?>
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"rewrite": [
|
"rewrite": [
|
||||||
{ "from": "/css/*", "to": "/styles/$1" },
|
{ "from": "/css/*", "to": "/build/styles/$1" },
|
||||||
{ "from": "/npm/*", "to": "http://registry.npmjs.org/$1" },
|
{ "from": "/npm/*", "to": "http://registry.npmjs.org/$1" },
|
||||||
{ "from": "/gh/:user/repo/:name", "to": "https://api.github.com/repos/:user/:name" }
|
{ "from": "/gh/:user/repo/:name", "to": "https://api.github.com/repos/:user/:name" }
|
||||||
]
|
]
|
||||||
|
@ -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:
|
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 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
|
```sh
|
||||||
$ ws --forbid .json .yml
|
$ ws --forbid .json .yml
|
||||||
serving at http://localhost:8000
|
serving at http://localhost:8000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[Path syntax](http://expressjs.com/guide/routing.html#route-paths)
|
||||||
|
|
||||||
### URL rewriting
|
### 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
|
```sh
|
||||||
$ ws --rewrite /css=>/build/css
|
$ ws --rewrite "/css/style.css -> /build/css/style.css"
|
||||||
```
|
```
|
||||||
|
|
||||||
Rewrite to remote servers (proxy):
|
Or, more generally (matching any stylesheet path under `/css`):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ ws --rewrite "/css/:stylesheet -> /build/css/:stylesheet"
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
```sh
|
||||||
$ ws --rewrite "/api => http://api.example.com/api" \
|
$ ws --rewrite "/api => http://api.example.com/api" \
|
||||||
"/npm => http://registry.npmjs.com" \
|
"/npm => http://registry.npmjs.com" \
|
||||||
|
@ -129,9 +129,7 @@ function localWebServer (options) {
|
|||||||
|
|
||||||
function logstalgiaDate () {
|
function logstalgiaDate () {
|
||||||
var d = new Date()
|
var d = new Date()
|
||||||
return (`${d.getDate()}/${d.getUTCMonth()}/${d.getFullYear()}:${d.toTimeString()}`)
|
return (`${d.getDate()}/${d.getUTCMonth()}/${d.getFullYear()}:${d.toTimeString()}`).replace('GMT', '').replace(' (BST)', '')
|
||||||
.replace('GMT', '')
|
|
||||||
.replace(' (BST)', '')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function proxyRequest (route) {
|
function proxyRequest (route) {
|
||||||
@ -174,7 +172,7 @@ function proxyRequest (route) {
|
|||||||
|
|
||||||
function blacklist (forbid) {
|
function blacklist (forbid) {
|
||||||
return function blacklist (ctx, next) {
|
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])
|
ctx.throw(403, http.STATUS_CODES[403])
|
||||||
} else {
|
} else {
|
||||||
return next()
|
return next()
|
||||||
|
Reference in New Issue
Block a user