Skip to content

Commit

Permalink
[fix] replace broken escaping with a working version (#3798)
Browse files Browse the repository at this point in the history
* [fix] replace broken escaping with a working version

* hoist dict
  • Loading branch information
benmccann authored Feb 9, 2022
1 parent 36db7bb commit 0b93d6a
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 31 deletions.
5 changes: 5 additions & 0 deletions .changeset/shy-bats-move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

[fix] replace broken escaping with a working version
4 changes: 2 additions & 2 deletions packages/kit/src/runtime/server/page/load_node.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { normalize } from '../../load.js';
import { respond } from '../index.js';
import { s } from '../../../utils/misc.js';
import { escape_json_string_in_html } from '../../../utils/escape.js';
import { escape_json_value_in_html } from '../../../utils/escape.js';
import { is_root_relative, resolve } from '../../../utils/url.js';
import { create_prerendering_url_proxy } from './utils.js';
import { is_pojo } from '../utils.js';
Expand Down Expand Up @@ -257,7 +257,7 @@ export async function load_node({
fetched.push({
url: requested,
body: /** @type {string} */ (opts.body),
json: `{"status":${response.status},"statusText":${s(response.statusText)},"headers":${s(headers)},"body":"${escape_json_string_in_html(body)}"}`
json: `{"status":${response.status},"statusText":${s(response.statusText)},"headers":${s(headers)},"body":"${escape_json_value_in_html(body)}"}`
});
}

Expand Down
64 changes: 35 additions & 29 deletions packages/kit/src/utils/escape.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
/** @type {Record<string, string>} */
const escape_json_in_html_dict = {
'&': '\\u0026',
'>': '\\u003e',
'<': '\\u003c',
'\u2028': '\\u2028',
'\u2029': '\\u2029'
};

/** @type {Record<string, string>} */
const escape_json_value_in_html_dict = {
'"': '\\"',
'<': '\\u003C',
'>': '\\u003E',
'/': '\\u002F',
Expand All @@ -14,53 +24,30 @@ const escape_json_in_html_dict = {
'\u2029': '\\u2029'
};

/** @type {Record<string, string>} */
const escape_json_string_in_html_dict = {
'"': '\\"',
...escape_json_in_html_dict
};

/**
* Escape a stringified JSON object that's going to be embedded in a `<script>` tag
* @param {string} str
*/
export function escape_json_in_html(str) {
return escape(str, escape_json_in_html_dict, (code) => `\\u${code.toString(16).toUpperCase()}`);
// adapted from https://github.com/vercel/next.js/blob/694407450638b037673c6d714bfe4126aeded740/packages/next/server/htmlescape.ts
// based on https://github.com/zertosh/htmlescape
// License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE
return str.replace(/[&><\u2028\u2029]/g, (match) => escape_json_in_html_dict[match]);
}

/**
* Escape a string JSON value to be embedded into a `<script>` tag
* @param {string} str
*/
export function escape_json_string_in_html(str) {
export function escape_json_value_in_html(str) {
return escape(
str,
escape_json_string_in_html_dict,
escape_json_value_in_html_dict,
(code) => `\\u${code.toString(16).toUpperCase()}`
);
}

/** @type {Record<string, string>} */
const escape_html_attr_dict = {
'<': '&lt;',
'>': '&gt;',
'"': '&quot;'
};

/**
* use for escaping string values to be used html attributes on the page
* e.g.
* <script data-url="here">
*
* @param {string} str
* @returns string escaped string
*/
export function escape_html_attr(str) {
return '"' + escape(str, escape_html_attr_dict, (code) => `&#${code};`) + '"';
}

/**
*
* @param str {string} string to escape
* @param dict {Record<string, string>} dictionary of character replacements
* @param unicode_encoder {function(number): string} encoder to use for high unicode characters
Expand Down Expand Up @@ -92,3 +79,22 @@ function escape(str, dict, unicode_encoder) {

return result;
}

/** @type {Record<string, string>} */
const escape_html_attr_dict = {
'<': '&lt;',
'>': '&gt;',
'"': '&quot;'
};

/**
* use for escaping string values to be used html attributes on the page
* e.g.
* <script data-url="here">
*
* @param {string} str
* @returns string escaped string
*/
export function escape_html_attr(str) {
return '"' + escape(str, escape_html_attr_dict, (code) => `&#${code};`) + '"';
}

0 comments on commit 0b93d6a

Please sign in to comment.