diff --git a/README.md b/README.md
index de97960..b817051 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ This project creates customized error pages that mimics the well-known Cloudflar
## Online Editor
-Here's an online editor to create customized error pages. Try it out [here](https://virt.moe/cferr/editor/).
+Here's an online editor to create customized error pages and example server apps. Try it out [here](https://virt.moe/cferr/editor/).

diff --git a/editor/web/index.html b/editor/web/index.html
index 93415a1..cf6bde3 100644
--- a/editor/web/index.html
+++ b/editor/web/index.html
@@ -173,7 +173,7 @@
max-height: 1200px !important;
font-family: monospace;
font-size: 0.8em !important;
- overflow: auto;
+ overflow: hidden;
}
.save-as-dialog__buttons {
@@ -475,7 +475,7 @@
@@ -547,7 +547,9 @@
Save
-
+
diff --git a/editor/web/src/codegen/index.ts b/editor/web/src/codegen/index.ts
index b871936..91ca7a8 100644
--- a/editor/web/src/codegen/index.ts
+++ b/editor/web/src/codegen/index.ts
@@ -1,4 +1,5 @@
import ejs from 'ejs';
+import { ErrorPageParams } from 'cloudflare-error-page';
import jsTemplate from './js.ejs?raw';
import jsonTemplate from './json.ejs?raw';
@@ -7,23 +8,97 @@ import pythonTemplate from './python.ejs?raw';
interface CodeGen {
name: string;
language: string;
- generate(params: any): string;
+ generate(params: ErrorPageParams): string;
}
class EjsCodeGen implements CodeGen {
name: string;
language: string;
private template: ejs.TemplateFunction;
- constructor(name: string, language: string, templateContent: any) {
+ constructor(name: string, language: string, templateContent: string) {
this.name = name;
this.language = language;
this.template = ejs.compile(templateContent);
}
- generate(params: any): string {
- return this.template({ params });
+ protected prepareTemplateArgs(params: ErrorPageParams): Record {
+ return {};
+ }
+ generate(params: ErrorPageParams): string {
+ const moreArgs = this.prepareTemplateArgs(params);
+ return this.template({ params, ...moreArgs });
}
}
-export const jsCodeGen = new EjsCodeGen('NodeJS Example', 'javascript', jsTemplate);
+function getErrorCode(error_code?: string | number) {
+ const errorCode = error_code || '';
+ return /\d{3}/.test(errorCode + '') ? errorCode : 500;
+}
+
+class JSCodeGen extends EjsCodeGen {
+ constructor(templateContent: string) {
+ super('JavaScript Example', 'javascript', templateContent);
+ }
+ private formatJSArgs(params: ErrorPageParams): string {
+ params = { ...params };
+ const rayIdKey = Math.random() + '';
+ const clientIpKey = Math.random() + '';
+ params.ray_id = rayIdKey;
+ params.client_ip = clientIpKey;
+ const paramsArg = JSON.stringify(params, null, 2)
+ .replace(`"${rayIdKey}"`, "(req.get('Cf-Ray') ?? '').substring(0, 16)")
+ .replace(`"${clientIpKey}"`, "req.get('X-Forwarded-For') || req.socket.remoteAddress");
+ return paramsArg;
+ }
+ protected prepareTemplateArgs(params: ErrorPageParams): Record {
+ return {
+ errorCode: getErrorCode(params.error_code),
+ // TODO: format to JS-style object (key w/o parens)
+ indentedParams: this.formatJSArgs(params).replaceAll('\n', '\n '),
+ };
+ }
+}
+
+class PythonCodeGen extends EjsCodeGen {
+ constructor(templateContent: string) {
+ super('Python Example', 'python', templateContent);
+ }
+ private formatPythonArgs(params: ErrorPageParams): string {
+ // Covert the parameters to Python format object
+ params = { ...params };
+ const randomKey = Math.random() + '';
+ const rayIdKey = Math.random() + '';
+ const clientIpKey = Math.random() + '';
+ params.ray_id = rayIdKey;
+ params.client_ip = clientIpKey;
+ const paramsArg = JSON.stringify(
+ params,
+ (key, value) => {
+ if (typeof value === 'boolean') {
+ return randomKey + value.toString();
+ } else if (value === null) {
+ return randomKey + 'null';
+ } else {
+ return value;
+ }
+ },
+ 4
+ )
+ .replace(`"${randomKey}true"`, 'True')
+ .replace(`"${randomKey}false"`, 'False')
+ .replace(`"${randomKey}null"`, 'None')
+ .replace(`"${rayIdKey}"`, 'request.headers.get("Cf-Ray", "")[:16]')
+ .replace(`"${clientIpKey}"`, 'request.headers.get("X-Forwarded-For") or request.remote_addr');
+ return paramsArg;
+ }
+ protected prepareTemplateArgs(params: ErrorPageParams): Record {
+ return {
+ errorCode: getErrorCode(params.error_code),
+ // TODO: format to JS-style object (key w/o parens)
+ indentedParams: this.formatPythonArgs(params).replaceAll('\n', '\n '),
+ };
+ }
+}
+
+export const jsCodeGen = new JSCodeGen(jsTemplate);
export const jsonCodeGen = new EjsCodeGen('JSON', 'json', jsonTemplate);
-export const pythonCodeGen = new EjsCodeGen('Python Example', 'python', pythonTemplate);
+export const pythonCodeGen = new PythonCodeGen(pythonTemplate);
diff --git a/editor/web/src/codegen/js.ejs b/editor/web/src/codegen/js.ejs
index 9f4a506..31aa8a6 100644
--- a/editor/web/src/codegen/js.ejs
+++ b/editor/web/src/codegen/js.ejs
@@ -1,3 +1,11 @@
+#!/usr/bin/env node
+/*
+ * JavaScript Example: Render and serve the Cloudflare error page using Express server
+ *
+ * Prerequisits:
+ * npm install cloudflare-error-page
+ */
+
import express from 'express';
import { render as render_cf_error_page } from 'cloudflare-error-page';
@@ -5,10 +13,8 @@ const app = express();
const port = 3000;
// Define a route for GET requests to the root URL
-<%# TODO: format to JS-style object (key w/o parens) _%>
-<% const errorCode = params.error_code || 500 _%>
app.get('/', (req, res) => {
- res.status(<%= /\d{3}/.test(errorCode + '') ? errorCode : 500 %>).send(render_cf_error_page(<%-JSON.stringify(params, null, 2).replaceAll('\n', '\n ')%>));
+ res.status(<%= errorCode %>).send(render_cf_error_page(<%- indentedParams %>));
});
// Start the server and listen on the specified port
diff --git a/editor/web/src/codegen/json.ejs b/editor/web/src/codegen/json.ejs
index ff9d4ad..f506349 100644
--- a/editor/web/src/codegen/json.ejs
+++ b/editor/web/src/codegen/json.ejs
@@ -1 +1 @@
-<%-JSON.stringify(params, null, 4)%>
+<%- JSON.stringify(params, null, 4) %>
diff --git a/editor/web/src/codegen/python.ejs b/editor/web/src/codegen/python.ejs
index 1266634..772b1a6 100644
--- a/editor/web/src/codegen/python.ejs
+++ b/editor/web/src/codegen/python.ejs
@@ -1,31 +1,21 @@
-<%
-// Covert the parameters to Python format object
-const randomKey = Math.random() + ''
-const paramsArg = JSON.stringify(params, (key, value) => {
- if (typeof value === 'boolean') {
- return randomKey + value.toString()
- } else if (value === null) {
- return randomKey + 'null'
- } else {
- return value
- }
-}, 4)
- .replace(`"${randomKey}true"`, 'True')
- .replace(`"${randomKey}false"`, 'False')
- .replace(`"${randomKey}null"`, 'None')
+#!/usr/bin/env python3
+#
+# Python Example: Render and serve the Cloudflare error page using Flask server
+#
+# Prerequisits:
+# pip install cloudflare-error-page
+#
-const errorCode = params.error_code || 500
-_%>
-from flask import Flask
+from flask import Flask, request
from cloudflare_error_page import render as render_cf_error_page
app = Flask(__name__)
# Define a route for GET requests to the root URL
-@app.route('/')
+@app.route("/")
def index():
# Render the error page
- return render_cf_error_page(<%- paramsArg.replaceAll('\n', '\n ') %>), <%= /\d{3}/.test(errorCode + '') ? errorCode : 500 %>
+ return render_cf_error_page(<%- indentedParams %>), <%= errorCode %>
-if __name__ == '__main__':
+if __name__ == "__main__":
app.run(debug=True, port=5000)
diff --git a/editor/web/src/index.js b/editor/web/src/index.js
index 6dff9d4..70830db 100644
--- a/editor/web/src/index.js
+++ b/editor/web/src/index.js
@@ -431,6 +431,7 @@ function updateSaveAsDialog(e) {
}
const params = { ...lastCfg };
delete params.time;
+ delete params.ray_id;
let language;
if (codegen) {
saveAsContent = codegen.generate(params);
@@ -445,6 +446,7 @@ function updateSaveAsDialog(e) {
const html = Prism.highlight(saveAsContent, Prism.languages[language], language);
$('saveAsDialogCode').innerHTML = html;
+ $('saveAsDialogCode').scrollTop = 0;
document.querySelectorAll('#saveAsDialogTypes button').forEach((element) => {
const isCurrent = element.dataset.type == saveAsType;
diff --git a/javascript/src/index.ts b/javascript/src/index.ts
index 8c2d99c..f827ce8 100644
--- a/javascript/src/index.ts
+++ b/javascript/src/index.ts
@@ -52,7 +52,9 @@ export interface ErrorPageParams {
}
// Load EJS template
-export const baseTemplate: ejs.TemplateFunction = ejs.compile(templateString);
+export const baseTemplate: ejs.TemplateFunction = ejs.compile(templateString, {
+ rmWhitespace: true
+});
/**
* Generate random hex string for ray-id