Commit 95c57164 authored by Aral Balkan's avatar Aral Balkan

Add native support for the 404 to 302 technique (see 4042302.org)

parent 25d1c34d
......@@ -61,7 +61,24 @@ All command-line arguments are optional. By default, Indie Web Server will serve
If you specify the `--global` flag, globally-trusted Let’s Encrypt TLS certificates are automatically provisioned for you using ACME TLS the first time you hit your hostname. The hostname for the certificates is automatically set from the hostname of your system (and the _www._ subdomain is also automatically provisioned).
### Custom error pages
## Native 404 → 302 support for an evergreen web
What if links never died? What if we never broke the Web? What if it didn’t involve any extra work? It’s possible. And easy. Just make your 404s into 302s.
Indie Web Server has native support for [the 404 to 302 technique](https://4042302.org) to ensure an evergreen web. Just serve the old version of your site (e.g., your WordPress site, etc.) from a different subdomain and tell Indie Web Server to forward any unknown requests to that subdomain so that all your existing links magically work when you start using Indie Web Server to serve your new static site.
To do so, create a simple file called `4042302` in the root directory of your web content and add the URL of the server that is hosting your older content. e.g.,
#### /4042302
{{<highlight shell>}}
https://the-previous-verison-of.my.site
{{</highlight>}}
You can chain the 404 → 302 method any number of times to ensure that none of your links ever break without expending any additional effort to migrate your content.
For more information and examples, see [4042302.org](https://4042302.org).
## Custom error pages
![Screenshot of the custom 404 error page included in the unit tests](images/custom-404.png)
......
......@@ -81,8 +81,22 @@ class WebServer {
console.log(`\n 🎉 Serving ${pathToServe} on https://${location}\n`)
}
// Check if a 4042302 (404 → 302) redirect has been requested.
//
// What if links never died? What if we never broke the Web? What if it didn’t involve any extra work?
// It’s possible. And easy. (And with Indie Web Server, it’s seamless.)
// Just make your 404s into 302s.
//
// Find out more at https://4042302.org/
const _4042302Path = path.join(pathToServe, '4042302')
const has4042302 = fs.existsSync(_4042302Path)
let _4042302 = null
if (has4042302) {
_4042302 = fs.readFileSync(_4042302Path, 'utf-8').replace(/\s/g, '')
}
// Check if a custom 404 page exists at the conventional path. If it does, load it for use later.
const custom404Path = path.join(pathToServe, '/404/index.html')
const custom404Path = path.join(pathToServe, '404', 'index.html')
const hasCustom404 = fs.existsSync(custom404Path)
let custom404 = null
if (hasCustom404) {
......@@ -90,7 +104,7 @@ class WebServer {
}
// Check if a custom 500 page exists at the conventional path. If it does, load it for use later.
const custom500Path = path.join(pathToServe, '/500/index.html')
const custom500Path = path.join(pathToServe, '500', 'index.html')
const hasCustom500 = fs.existsSync(custom500Path)
let custom500 = null
if (hasCustom500) {
......@@ -127,10 +141,15 @@ class WebServer {
// 404 (Not Found) support.
app.use((request, response, next) => {
// If there is a custom 404 path, serve that. The template variable
// THE_PATH, if present on the page, will be replaced with the current
// request path before it is returned.
if (hasCustom404) {
// If a 4042302 (404 → 302) redirect has been requested, honour that.
// (See https://4042302.org/). Otherwise, if there is a custom 404 error page,
// serve that. (The template variable THE_PATH, if present on the page, will be
// replaced with the current request path before it is returned.)
if (has4042302) {
const forwardingURL = `${_4042302}${request.url}`
console.log(`404 → 302: Forwarding to ${forwardingURL}`)
response.redirect(forwardingURL)
} else if (hasCustom404) {
// Enable basic template support for including the missing path.
const custom404WithPath = custom404.replace('THE_PATH', request.path)
......
......@@ -11,16 +11,17 @@ async function secureGet (url) {
return new Promise((resolve, reject) => {
https.get(url, (response) => {
const statusCode = response.statusCode
const location = response.headers.location
// Reject if it’s not one of the status codes we are testing.
if (statusCode !== 200 && statusCode !== 404 && statusCode !== 500) {
if (statusCode !== 200 && statusCode !== 404 && statusCode !== 500 && statusCode !== 302) {
reject({statusCode})
}
let body = ''
response.on('data', _ => body += _)
response.on('end', () => {
resolve({statusCode, body})
resolve({statusCode, location, body})
})
})
})
......@@ -40,6 +41,32 @@ test('createServer method', t => {
})
test('4042302', t => {
// See https://4042302.org/get-started/
t.plan(2)
const _4042302FilePath = path.join(__dirname, 'site', '4042302')
fs.writeFileSync(_4042302FilePath, 'https://my-previous.site', 'utf-8')
const server = webServer.serve({path: 'test/site', callback: async () => {
let response
try {
response = await secureGet('https://localhost/this-page-exists-on-my-previous-site')
} catch (error) {
console.log(error)
process.exit(1)
}
t.equal(response.statusCode, 302, '302 status is returned')
t.equal(response.location, 'https://my-previous.site/this-page-exists-on-my-previous-site')
fs.unlinkSync(_4042302FilePath)
server.close()
t.end()
}})
})
test('serve method default 404 and 500 responses', t => {
//
// Test the default 404 and 500 responses of the serve method.
......
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