diff --git a/compiler/CodeGenerator.js b/compiler/CodeGenerator.js index 42a20b21e..c2e437cab 100644 --- a/compiler/CodeGenerator.js +++ b/compiler/CodeGenerator.js @@ -185,7 +185,7 @@ class Generator { var beforeAfterEvent; - if (node.listenerCount('beforeGenerateCode') || node.listenerCount('beforeGenerateCode')) { + if (node.listenerCount('beforeGenerateCode') || node.listenerCount('afterGenerateCode')) { beforeAfterEvent = new GeneratorEvent(node, this); } diff --git a/compiler/CompileContext.js b/compiler/CompileContext.js index c80b85993..46398aae2 100644 --- a/compiler/CompileContext.js +++ b/compiler/CompileContext.js @@ -80,7 +80,7 @@ class CompileContext { } setFlag(name) { - this._flags[name] = true; + this.pushFlag(name); } clearFlag(name) { @@ -91,6 +91,24 @@ class CompileContext { return this._flags.hasOwnProperty(name); } + pushFlag(name) { + if (this._flags.hasOwnProperty(name)) { + this._flags[name]++; + } else { + this._flags[name] = 1; + } + } + + popFlag(name) { + if (!this._flags.hasOwnProperty(name)) { + throw new Error('popFlag() called for "' + name + '" when flag was not set'); + } + + if (--this._flags[name] === 0) { + delete this._flags[name]; + } + } + addError(errorInfo) { if (errorInfo instanceof Node) { let node = arguments[0]; diff --git a/compiler/ast/HtmlElement.js b/compiler/ast/HtmlElement.js index 2a413d779..1977a849e 100644 --- a/compiler/ast/HtmlElement.js +++ b/compiler/ast/HtmlElement.js @@ -66,6 +66,18 @@ class EndTag extends Node { } } +function beforeGenerateCode(event) { + if (event.node.tagName === 'script') { + event.context.pushFlag('SCRIPT_BODY'); + } +} + +function afterGenerateCode(event) { + if (event.node.tagName === 'script') { + event.context.popFlag('SCRIPT_BODY'); + } +} + class HtmlElement extends Node { constructor(def) { super('HtmlElement'); @@ -84,6 +96,9 @@ class HtmlElement extends Node { this.selfClosed = def.selfClosed; this.dynamicAttributes = undefined; this.bodyOnlyIf = undefined; + + this.on('beforeGenerateCode', beforeGenerateCode); + this.on('afterGenerateCode', afterGenerateCode); } generateHtmlCode(codegen) { diff --git a/compiler/ast/Text.js b/compiler/ast/Text.js index d719dce84..1e831c125 100644 --- a/compiler/ast/Text.js +++ b/compiler/ast/Text.js @@ -43,10 +43,16 @@ class Text extends Node { let builder = codegen.builder; if (escape) { + let escapeFuncVar = 'escapeXml'; + + if (codegen.context.isFlagSet('SCRIPT_BODY')) { + escapeFuncVar = codegen.addStaticVar('escapeScript', '__helpers.xs'); + } + // TODO Only escape the parts that need to be escaped if it is a compound expression with static // text parts argument = builder.functionCall( - 'escapeXml', + escapeFuncVar, [argument]); } else { argument = builder.functionCall(builder.identifier('str'), [ argument ]); diff --git a/runtime/helpers.js b/runtime/helpers.js index a5ce6fc2a..510a25e54 100644 --- a/runtime/helpers.js +++ b/runtime/helpers.js @@ -22,6 +22,7 @@ var attr = require('raptor-util/attr'); var isArray = Array.isArray; var STYLE_ATTR = 'style'; var CLASS_ATTR = 'class'; +var escapeEndingScriptTagRegExp = /<\//g; function notEmpty(o) { if (o == null) { @@ -197,6 +198,26 @@ module.exports = { * @private */ xa: escapeXmlAttr, + + /** + * Escapes the ' body to avoid the `' + * }; + * + * + * + * Without escaping the ending '' sequence the opening
{"name":"Evil </script>"}
\ No newline at end of file diff --git a/test/autotests/render/escape-script/template.marko b/test/autotests/render/escape-script/template.marko new file mode 100644 index 000000000..f12f01aad --- /dev/null +++ b/test/autotests/render/escape-script/template.marko @@ -0,0 +1,4 @@ + +
${JSON.stringify(data.foo)}
\ No newline at end of file diff --git a/test/autotests/render/escape-script/test.js b/test/autotests/render/escape-script/test.js new file mode 100644 index 000000000..e0035678a --- /dev/null +++ b/test/autotests/render/escape-script/test.js @@ -0,0 +1,5 @@ +exports.templateData = { + foo: { + name: 'Evil ' + } +}; diff --git a/test/autotests/render/script-tag-entities/expected.html b/test/autotests/render/script-tag-entities/expected.html index 91a5cf44b..b0ca3c7a9 100644 --- a/test/autotests/render/script-tag-entities/expected.html +++ b/test/autotests/render/script-tag-entities/expected.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/test/autotests/render/script-tag-entities/test.js b/test/autotests/render/script-tag-entities/test.js index d7f36b92c..4221021f4 100644 --- a/test/autotests/render/script-tag-entities/test.js +++ b/test/autotests/render/script-tag-entities/test.js @@ -1,3 +1,3 @@ exports.templateData = { - "name": "" };