From 9b3160114fab624233e2ae928c63ecd31863f4a5 Mon Sep 17 00:00:00 2001 From: Stefan Stidl Date: Tue, 14 Apr 2026 08:11:03 +0200 Subject: [PATCH 1/3] docker: restore TITLE env handling in entrypoint --- docker/entrypoint.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 3309cd385..11d2a1ac7 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -84,6 +84,14 @@ if [[ "$MODE" == "frontend" || "$MODE" == "dual" || "$MODE" == "standalone" ]]; sed -i "s/var SPEEDTEST_SERVERS = \"server-list.json\";/var SPEEDTEST_SERVERS = \"$SERVER_LIST_URL_ESCAPED\";/" /var/www/html/index-modern.html sed -i "s/var SPEEDTEST_SERVERS = \\[/var SPEEDTEST_SERVERS = \"$SERVER_LIST_URL_ESCAPED\";\\n\\t\\t\\/\\*/" /var/www/html/index-classic.html fi + + # Replace title placeholders if TITLE is set + if [ ! -z "$TITLE" ]; then + TITLE_ESCAPED=$(printf '%s\n' "$TITLE" | sed 's/[&/\\]/\\&/g; s/\$/\\$/g') + sed -i "s/LibreSpeed<\\/title>/<title>$TITLE_ESCAPED<\\/title>/g; s/<h1>LibreSpeed<\\/h1>/<h1>$TITLE_ESCAPED<\\/h1>/g" /var/www/html/index-classic.html + sed -i "s/<title>LibreSpeed<\\/title>/<title>$TITLE_ESCAPED<\\/title>/g" /var/www/html/index.html + sed -i "s/<title>LibreSpeed - Free and Open Source Speedtest<\\/title>/<title>$TITLE_ESCAPED - Free and Open Source Speedtest<\\/title>/g" /var/www/html/index-modern.html + fi # Support legacy EMAIL env var as fallback for GDPR_EMAIL if [ -z "$GDPR_EMAIL" ] && [ ! -z "$EMAIL" ]; then From 771da12c4e07aac5f3cc4a3285bd6e5f53bdefa4 Mon Sep 17 00:00:00 2001 From: Stefan Stidl <sti-github@stidl.com> Date: Tue, 14 Apr 2026 08:33:49 +0200 Subject: [PATCH 2/3] docker: escape TITLE for HTML output --- docker/entrypoint.sh | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 11d2a1ac7..c434c56a7 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -17,6 +17,19 @@ is_alpine() { [ -f /etc/alpine-release ] } +html_escape() { + printf '%s' "$1" | sed \ + -e 's/&/\&/g' \ + -e 's/</\</g' \ + -e 's/>/\>/g' \ + -e 's/"/\"/g' \ + -e "s/'/\'/g" +} + +sed_escape() { + printf '%s\n' "$1" | sed 's/[&/\\]/\\&/g; s/\$/\\$/g' +} + # Cleanup rm -rf /var/www/html/* @@ -87,7 +100,10 @@ if [[ "$MODE" == "frontend" || "$MODE" == "dual" || "$MODE" == "standalone" ]]; # Replace title placeholders if TITLE is set if [ ! -z "$TITLE" ]; then - TITLE_ESCAPED=$(printf '%s\n' "$TITLE" | sed 's/[&/\\]/\\&/g; s/\$/\\$/g') + TITLE_ONE_LINE=${TITLE//$'\r'/} + TITLE_ONE_LINE=${TITLE_ONE_LINE//$'\n'/ } + TITLE_HTML_ESCAPED=$(html_escape "$TITLE_ONE_LINE") + TITLE_ESCAPED=$(sed_escape "$TITLE_HTML_ESCAPED") sed -i "s/<title>LibreSpeed<\\/title>/<title>$TITLE_ESCAPED<\\/title>/g; s/<h1>LibreSpeed<\\/h1>/<h1>$TITLE_ESCAPED<\\/h1>/g" /var/www/html/index-classic.html sed -i "s/<title>LibreSpeed<\\/title>/<title>$TITLE_ESCAPED<\\/title>/g" /var/www/html/index.html sed -i "s/<title>LibreSpeed - Free and Open Source Speedtest<\\/title>/<title>$TITLE_ESCAPED - Free and Open Source Speedtest<\\/title>/g" /var/www/html/index-modern.html From 73f235a8905d67760862711c86eff9d332eafc2c Mon Sep 17 00:00:00 2001 From: Stefan Stidl <sti-github@stidl.com> Date: Tue, 14 Apr 2026 08:50:46 +0200 Subject: [PATCH 3/3] test(e2e): cover TITLE with umlauts and quotes --- tests/docker-compose-playwright.yml | 1 + tests/e2e/title-special-chars.spec.js | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/e2e/title-special-chars.spec.js diff --git a/tests/docker-compose-playwright.yml b/tests/docker-compose-playwright.yml index d84c583ab..2575d26ed 100644 --- a/tests/docker-compose-playwright.yml +++ b/tests/docker-compose-playwright.yml @@ -26,6 +26,7 @@ services: - MODE=standalone - WEBPORT=8080 - USE_NEW_DESIGN=true + - 'TITLE=Grüße "Tempo" ''Österreich''' ports: - "18185:8080" diff --git a/tests/e2e/title-special-chars.spec.js b/tests/e2e/title-special-chars.spec.js new file mode 100644 index 000000000..4fe942555 --- /dev/null +++ b/tests/e2e/title-special-chars.spec.js @@ -0,0 +1,16 @@ +const { test, expect } = require('@playwright/test'); +const { baseUrls } = require('./helpers/env'); + +const specialTitle = 'Grüße "Tempo" \'Österreich\''; + +test.describe('TITLE special characters', () => { + test('modern page title supports umlauts and quotes', async ({ page }) => { + await page.goto(`${baseUrls.standaloneNew}/index-modern.html`); + await expect(page).toHaveTitle(`${specialTitle} - Free and Open Source Speedtest`); + }); + + test('classic heading supports umlauts and quotes', async ({ page }) => { + await page.goto(`${baseUrls.standaloneNew}/index-classic.html`); + await expect(page.locator('h1').first()).toHaveText(specialTitle); + }); +});