Added tailwind look option.
This commit is contained in:
@@ -19,18 +19,17 @@ To run the server from the command line:
|
|||||||
```bash
|
```bash
|
||||||
python3 ok-server.py
|
python3 ok-server.py
|
||||||
python3 ok-server.py --look basic
|
python3 ok-server.py --look basic
|
||||||
python3 ok-server.py --bind 127.0.0.1 --port 8080 --look bootstrap
|
python3 ok-server.py --bind 127.0.0.1 --port 8080 --look tailwind
|
||||||
```
|
```
|
||||||
|
|
||||||
`--look` accepts `basic`, `nice`, or `bootstrap`.
|
`--look` accepts `basic`, `nice`, `bootstrap`, or `tailwind`.
|
||||||
You can override the look per request with the `look` query parameter, for example:
|
You can override the look per request with the `look` query parameter, for example:
|
||||||
|
`http://localhost:8080/?look=tailwind`
|
||||||
or
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
node ok-server.mjs
|
node ok-server.mjs
|
||||||
node ok-server.mjs --look basic
|
node ok-server.mjs --look basic
|
||||||
node ok-server.mjs --bind 127.0.0.1 --port 8080 --look bootstrap
|
node ok-server.mjs --bind 127.0.0.1 --port 8080 --look tailwind
|
||||||
```
|
```
|
||||||
|
|
||||||
Connect to the server using a web browser or a tool like `curl`:
|
Connect to the server using a web browser or a tool like `curl`:
|
||||||
|
|||||||
+40
-5
@@ -12,14 +12,15 @@
|
|||||||
* * basic - plain HTML with no external references
|
* * basic - plain HTML with no external references
|
||||||
* * nice - includes Google Font "Noto Sans" (default)
|
* * nice - includes Google Font "Noto Sans" (default)
|
||||||
* * bootstrap - Bootstrap 5 layout
|
* * bootstrap - Bootstrap 5 layout
|
||||||
|
* * tailwind - Tailwind CSS via @tailwindcss/browser@latest
|
||||||
* - The URL query parameter "look" (e.g. /?look=nice) overrides --look for
|
* - The URL query parameter "look" (e.g. /?look=nice) overrides --look for
|
||||||
* that request only. Values are case-insensitive and must be basic,nice,bootstrap.
|
* that request only. Values are case-insensitive and must be basic,nice,bootstrap,tailwind.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import http from "node:http";
|
import http from "node:http";
|
||||||
import { URL } from "node:url";
|
import { URL } from "node:url";
|
||||||
|
|
||||||
const VALID_LOOKS = new Set(["basic", "nice", "bootstrap"]);
|
const VALID_LOOKS = new Set(["basic", "nice", "bootstrap", "tailwind"]);
|
||||||
|
|
||||||
const PLAIN_TEMPLATE =
|
const PLAIN_TEMPLATE =
|
||||||
"Hello, This is a test HTTP server.\n\n" +
|
"Hello, This is a test HTTP server.\n\n" +
|
||||||
@@ -108,6 +109,34 @@ const HTML_BOOTSTRAP = `<!doctype html>
|
|||||||
</html>
|
</html>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const HTML_TAILWIND = `<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Test HTTP server</title>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@latest"></script>
|
||||||
|
</head>
|
||||||
|
<body class="min-h-screen bg-slate-100 text-slate-900">
|
||||||
|
<div class="mx-auto max-w-3xl px-4 py-10 sm:py-16">
|
||||||
|
<div class="overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-lg">
|
||||||
|
<div class="bg-slate-900 px-6 py-4 text-slate-100">
|
||||||
|
<h1 class="text-xl font-semibold">Test HTTP server</h1>
|
||||||
|
<p class="mt-1 text-sm text-slate-300">Simple status page for firewall/testing</p>
|
||||||
|
</div>
|
||||||
|
<main class="space-y-4 px-6 py-6">
|
||||||
|
<p class="text-2xl font-bold">Hello,</p>
|
||||||
|
<p>This is a test HTTP server.</p>
|
||||||
|
<p>Your request came from <strong>{ip}</strong>.</p>
|
||||||
|
{proxy_headers_html}
|
||||||
|
<p class="pt-2">Have a nice day!</p>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
|
||||||
function escapeHtml(value) {
|
function escapeHtml(value) {
|
||||||
return String(value)
|
return String(value)
|
||||||
.replace(/&/g, "&")
|
.replace(/&/g, "&")
|
||||||
@@ -174,7 +203,13 @@ function proxyMarkup(xHeaders) {
|
|||||||
|
|
||||||
function htmlForLook(look, ip, proxyHeadersHtml) {
|
function htmlForLook(look, ip, proxyHeadersHtml) {
|
||||||
const template =
|
const template =
|
||||||
look === "basic" ? HTML_BASIC : look === "nice" ? HTML_NICE : HTML_BOOTSTRAP;
|
look === "basic"
|
||||||
|
? HTML_BASIC
|
||||||
|
: look === "nice"
|
||||||
|
? HTML_NICE
|
||||||
|
: look === "bootstrap"
|
||||||
|
? HTML_BOOTSTRAP
|
||||||
|
: HTML_TAILWIND;
|
||||||
|
|
||||||
return template
|
return template
|
||||||
.replaceAll("{ip}", ip)
|
.replaceAll("{ip}", ip)
|
||||||
@@ -240,7 +275,7 @@ function parseArgs(argv) {
|
|||||||
}
|
}
|
||||||
const value = String(argv[i]).trim().toLowerCase();
|
const value = String(argv[i]).trim().toLowerCase();
|
||||||
if (!VALID_LOOKS.has(value)) {
|
if (!VALID_LOOKS.has(value)) {
|
||||||
throw new Error(`Invalid look: ${argv[i]} (expected one of: basic, nice, bootstrap)`);
|
throw new Error(`Invalid look: ${argv[i]} (expected one of: basic, nice, bootstrap, tailwind)`);
|
||||||
}
|
}
|
||||||
look = value;
|
look = value;
|
||||||
continue;
|
continue;
|
||||||
@@ -249,7 +284,7 @@ function parseArgs(argv) {
|
|||||||
if (arg === "-h" || arg === "--help") {
|
if (arg === "-h" || arg === "--help") {
|
||||||
const help = [
|
const help = [
|
||||||
"Usage:",
|
"Usage:",
|
||||||
" node ok-server.mjs [-b|--bind ADDRESS] [-p|--port PORT] [--look basic|nice|bootstrap]",
|
" node ok-server.mjs [-b|--bind ADDRESS] [-p|--port PORT] [--look basic|nice|bootstrap|tailwind]",
|
||||||
"",
|
"",
|
||||||
"Defaults:",
|
"Defaults:",
|
||||||
" --bind 0.0.0.0",
|
" --bind 0.0.0.0",
|
||||||
|
|||||||
+40
-5
@@ -11,13 +11,14 @@ Behavior:
|
|||||||
* basic - plain HTML with no external references
|
* basic - plain HTML with no external references
|
||||||
* nice - includes Google Font "Noto Sans" (default)
|
* nice - includes Google Font "Noto Sans" (default)
|
||||||
* bootstrap - Bootstrap 5 layout
|
* bootstrap - Bootstrap 5 layout
|
||||||
|
* tailwind - Tailwind CSS via @tailwindcss/browser@latest
|
||||||
- The URL query parameter "look" (e.g. /?look=nice) overrides the command-line --look
|
- The URL query parameter "look" (e.g. /?look=nice) overrides the command-line --look
|
||||||
for that request only. Values are case-insensitive and must be one of basic,nice,bootstrap.
|
for that request only. Values are case-insensitive and must be one of basic,nice,bootstrap,tailwind.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
python3 ok_server.py # binds 0.0.0.0:8080, nice look
|
python3 ok_server.py # binds 0.0.0.0:8080, nice look
|
||||||
python3 ok_server.py --look basic
|
python3 ok_server.py --look basic
|
||||||
python3 ok_server.py -b 127.0.0.1 -p 8080 --look bootstrap
|
python3 ok_server.py -b 127.0.0.1 -p 8080 --look tailwind
|
||||||
|
|
||||||
Test:
|
Test:
|
||||||
curl -i http://localhost:8080/ # text/plain for curl
|
curl -i http://localhost:8080/ # text/plain for curl
|
||||||
@@ -127,7 +128,36 @@ HTML_BOOTSTRAP = """<!doctype html>
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
VALID_LOOKS = ("basic", "nice", "bootstrap")
|
HTML_TAILWIND = """<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Test HTTP server</title>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@latest"></script>
|
||||||
|
</head>
|
||||||
|
<body class="min-h-screen bg-slate-100 text-slate-900">
|
||||||
|
<div class="mx-auto max-w-3xl px-4 py-10 sm:py-16">
|
||||||
|
<div class="overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-lg">
|
||||||
|
<div class="bg-slate-900 px-6 py-4 text-slate-100">
|
||||||
|
<h1 class="text-xl font-semibold">Test HTTP server</h1>
|
||||||
|
<p class="mt-1 text-sm text-slate-300">Simple status page for firewall/testing</p>
|
||||||
|
</div>
|
||||||
|
<main class="space-y-4 px-6 py-6">
|
||||||
|
<p class="text-2xl font-bold">Hello,</p>
|
||||||
|
<p>This is a test HTTP server.</p>
|
||||||
|
<p>Your request came from <strong>{ip}</strong>.</p>
|
||||||
|
{proxy_headers_html}
|
||||||
|
<p class="pt-2">Have a nice day!</p>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
VALID_LOOKS = ("basic", "nice", "bootstrap", "tailwind")
|
||||||
|
|
||||||
|
|
||||||
class OkHandler(BaseHTTPRequestHandler):
|
class OkHandler(BaseHTTPRequestHandler):
|
||||||
@@ -190,11 +220,16 @@ class OkHandler(BaseHTTPRequestHandler):
|
|||||||
ip=ip,
|
ip=ip,
|
||||||
proxy_headers_html=proxy_headers_html,
|
proxy_headers_html=proxy_headers_html,
|
||||||
)
|
)
|
||||||
# fallback to bootstrap
|
if look == "bootstrap":
|
||||||
return HTML_BOOTSTRAP.format(
|
return HTML_BOOTSTRAP.format(
|
||||||
ip=ip,
|
ip=ip,
|
||||||
proxy_headers_html=proxy_headers_html,
|
proxy_headers_html=proxy_headers_html,
|
||||||
)
|
)
|
||||||
|
# fallback to tailwind
|
||||||
|
return HTML_TAILWIND.format(
|
||||||
|
ip=ip,
|
||||||
|
proxy_headers_html=proxy_headers_html,
|
||||||
|
)
|
||||||
|
|
||||||
def _make_body_and_type(self, client_ip: str, user_agent: str) -> Tuple[bytes, str]:
|
def _make_body_and_type(self, client_ip: str, user_agent: str) -> Tuple[bytes, str]:
|
||||||
x_headers = self._collect_x_headers()
|
x_headers = self._collect_x_headers()
|
||||||
@@ -280,6 +315,6 @@ if __name__ == "__main__":
|
|||||||
parser.add_argument("-p", "--port", type=int, default=8080,
|
parser.add_argument("-p", "--port", type=int, default=8080,
|
||||||
help="Port to listen on (default: 8080)")
|
help="Port to listen on (default: 8080)")
|
||||||
parser.add_argument("--look", choices=VALID_LOOKS, default=VALID_LOOKS[1],
|
parser.add_argument("--look", choices=VALID_LOOKS, default=VALID_LOOKS[1],
|
||||||
help="Default HTML look for non-cli agents (basic, nice, bootstrap). Default: nice")
|
help="Default HTML look for non-cli agents (basic, nice, bootstrap, tailwind). Default: nice")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
run(args.bind, args.port, args.look)
|
run(args.bind, args.port, args.look)
|
||||||
|
|||||||
Reference in New Issue
Block a user