Skip to content

Commit

Permalink
fix: escape values included in dev 404 page
Browse files Browse the repository at this point in the history
  • Loading branch information
benmccann committed Nov 21, 2024
1 parent 239fe18 commit b09f36c
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/five-maps-yawn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: escape values included in dev 404 page
11 changes: 9 additions & 2 deletions packages/kit/src/exports/vite/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { loadEnv } from 'vite';
import { posixify } from '../../utils/filesystem.js';
import { negotiate } from '../../utils/http.js';
import { filter_private_env, filter_public_env } from '../../utils/env.js';
import { escape_html, escape_html_attr } from '../../utils/escape.js';

/**
* Transforms kit.alias to a valid vite.resolve.alias array.
Expand Down Expand Up @@ -89,11 +90,17 @@ export function not_found(req, res, base) {
if (type === 'text/html') {
res.setHeader('Content-Type', 'text/html');
res.end(
`The server is configured with a public base URL of ${base} - did you mean to visit <a href="${prefixed}">${prefixed}</a> instead?`
`The server is configured with a public base URL of ${escape_html(
base
)} - did you mean to visit <a href=${escape_html_attr(prefixed)}>${escape_html(
prefixed
)}</a> instead?`
);
} else {
res.end(
`The server is configured with a public base URL of ${base} - did you mean to visit ${prefixed} instead?`
`The server is configured with a public base URL of ${escape_html(
base
)} - did you mean to visit ${escape_html(prefixed)} instead?`
);
}
}
Expand Down
27 changes: 27 additions & 0 deletions packages/kit/src/utils/escape.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,30 @@ export function escape_html_attr(str) {

return `"${escaped_str}"`;
}

const ATTR_REGEX = /[&"<]/g;
const CONTENT_REGEX = /[&<]/g;

/**
* @template V
* @param {V} value
* @param {boolean} [is_attr]
*/
export function escape_html(value, is_attr) {
const str = String(value ?? '');

const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX;
pattern.lastIndex = 0;

let escaped = '';
let last = 0;

while (pattern.test(str)) {
const i = pattern.lastIndex - 1;
const ch = str[i];
escaped += str.substring(last, i) + (ch === '&' ? '&amp;' : ch === '"' ? '&quot;' : '&lt;');
last = i + 1;
}

return escaped + str.substring(last);
}

0 comments on commit b09f36c

Please sign in to comment.