Commit d4883495 authored by Sebastiaan Deckers's avatar Sebastiaan Deckers 馃悜

feat: directories.resolve to normalise URL path

parent e941b740
......@@ -89,6 +89,14 @@ module.exports = {
Behaviour of directory paths in *clean URLs*.
### `hosts[].directories.resolve`
Default: `true`
If `true`, URL paths are normalised by resolving their `//`, `..`, and `.` segments. A `308` permanent redirect response is generated to the resolved path.
If `false`, no server-side normalisation is performed, which may be useful for client-side routing.
### `hosts[].directories.trailingSlash`
Default: `'always'`
......
......@@ -66,14 +66,16 @@ module.exports.resolveRequest = () => {
}
}
const normalised = normalize(pathname)
if (normalised !== pathname) {
url.protocol = 'https'
url.host = getHost(request)
url.pathname = normalised
response.writeHead(PERMANENT_REDIRECT, { location: format(url) })
response.end()
return
if (request.options.directories.resolve === true) {
const normalised = normalize(pathname)
if (normalised !== pathname) {
url.protocol = 'https'
url.host = getHost(request)
url.pathname = normalised
response.writeHead(PERMANENT_REDIRECT, { location: format(url) })
response.end()
return
}
}
return next(new NotFound())
......
......@@ -3,23 +3,64 @@ const { Master } = require('..')
const { join } = require('path')
const { h1 } = require('./helpers/receive')
let master
test('start server', async (t) => {
const cwd = join(__dirname, 'fixtures')
const options = {}
master = new Master({ cwd, options })
await master.listen()
})
const fixtures = [
{
resolve: true,
given: 'https://localhost:8443/foo/../../bar//logo.svg',
expected: {
status: 308,
statusText: 'Permanent Redirect',
location: 'https://localhost:8443/bar/logo.svg'
}
},
{
resolve: false,
given: 'https://localhost:8443/foo/../../bar//logo.svg',
expected: {
status: 404,
statusText: 'Not Found',
location: null
}
},
{
resolve: undefined,
given: 'https://localhost:8443/foo/../../bar//logo.svg',
expected: {
status: 308,
statusText: 'Permanent Redirect',
location: 'https://localhost:8443/bar/logo.svg'
}
},
{
resolve: false,
given: 'https://localhost:8443/gopher://1/foo/bar%09lol%20abc',
expected: {
status: 404,
statusText: 'Not Found',
location: null
}
}
]
test('Resolve special URL paths safely', async (t) => {
const url = 'https://localhost:8443/foo/../../bar//logo.svg'
const response = await h1(url)
t.is(response.status, 308)
t.is(response.statusText, 'Permanent Redirect')
t.is(
response.headers.get('location'),
'https://localhost:8443/bar/logo.svg'
)
})
for (const { resolve, given, expected } of fixtures) {
let master
test('start server', async (t) => {
const cwd = join(__dirname, 'fixtures')
const options = { hosts: [{ directories: { resolve } }] }
master = new Master({ cwd, options })
await master.listen()
})
test('stop server', async (t) => master.close())
test('Resolve special URL paths safely', async (t) => {
const url = given
const response = await h1(url)
t.is(response.status, expected.status)
t.is(response.statusText, expected.statusText)
t.is(
response.headers.get('location'),
expected.location
)
})
test('stop server', async (t) => master.close())
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment