Merge pull request #747 from sveltejs/gh-741

Fix escaping/unescaping of text and attributes in SSR
pull/751/head
Rich Harris 8 years ago committed by GitHub
commit 207c59986a

@ -4,7 +4,7 @@ import annotateWithScopes from '../../utils/annotateWithScopes';
import isReference from '../../utils/isReference'; import isReference from '../../utils/isReference';
import { walk } from 'estree-walker'; import { walk } from 'estree-walker';
import deindent from '../../utils/deindent'; import deindent from '../../utils/deindent';
import stringify from '../../utils/stringify'; import { stringify } from '../../utils/stringify';
import CodeBuilder from '../../utils/CodeBuilder'; import CodeBuilder from '../../utils/CodeBuilder';
import visit from './visit'; import visit from './visit';
import shared from './shared'; import shared from './shared';

@ -2,7 +2,7 @@ import { DomGenerator } from '../../index';
import Block from '../../Block'; import Block from '../../Block';
import { Node } from '../../../../interfaces'; import { Node } from '../../../../interfaces';
import { State } from '../../interfaces'; import { State } from '../../interfaces';
import stringify from '../../../../utils/stringify'; import { stringify } from '../../../../utils/stringify';
export default function visitAttribute( export default function visitAttribute(
generator: DomGenerator, generator: DomGenerator,

@ -1,6 +1,6 @@
import attributeLookup from './lookup'; import attributeLookup from './lookup';
import deindent from '../../../../utils/deindent'; import deindent from '../../../../utils/deindent';
import stringify from '../../../../utils/stringify'; import { stringify } from '../../../../utils/stringify';
import getStaticAttributeValue from './getStaticAttributeValue'; import getStaticAttributeValue from './getStaticAttributeValue';
import { DomGenerator } from '../../index'; import { DomGenerator } from '../../index';
import Block from '../../Block'; import Block from '../../Block';

@ -2,7 +2,7 @@ import { DomGenerator } from '../index';
import Block from '../Block'; import Block from '../Block';
import { Node } from '../../../interfaces'; import { Node } from '../../../interfaces';
import { State } from '../interfaces'; import { State } from '../interfaces';
import stringify from '../../../utils/stringify'; import { stringify } from '../../../utils/stringify';
export default function visitText( export default function visitText(
generator: DomGenerator, generator: DomGenerator,

@ -178,7 +178,12 @@ export default function ssr(
function __escape ( html ) { function __escape ( html ) {
return String( html ).replace( /["'&<>]/g, match => escaped[ match ] ); return String( html ).replace( /["'&<>]/g, match => escaped[ match ] );
} }
`.replace(/(\\)?@(\w*)/g, (match: string, escaped: string, name: string) => escaped ? match.slice(1) : generator.alias(name)); `.replace(/(\\)?([@#])(\w*)/g, (match: string, escaped: string, sigil: string, name: string) => {
if (escaped) return match.slice(1);
if (sigil !== '@') return match;
return generator.alias(name);
});
return generator.generate(result, options, { name, format }); return generator.generate(result, options, { name, format });
} }

@ -4,6 +4,7 @@ import visit from '../visit';
import visitWindow from './meta/Window'; import visitWindow from './meta/Window';
import { SsrGenerator } from '../index'; import { SsrGenerator } from '../index';
import Block from '../Block'; import Block from '../Block';
import { escape } from '../../../utils/stringify';
import { Node } from '../../../interfaces'; import { Node } from '../../../interfaces';
const meta = { const meta = {
@ -14,7 +15,7 @@ function stringifyAttributeValue(block: Block, chunks: Node[]) {
return chunks return chunks
.map((chunk: Node) => { .map((chunk: Node) => {
if (chunk.type === 'Text') { if (chunk.type === 'Text') {
return chunk.data; return escape(chunk.data).replace(/"/g, '&quot;');
} }
const { snippet } = block.contextualise(chunk.expression); const { snippet } = block.contextualise(chunk.expression);

@ -1,5 +1,6 @@
import { SsrGenerator } from '../index'; import { SsrGenerator } from '../index';
import Block from '../Block'; import Block from '../Block';
import { escape } from '../../../utils/stringify';
import { Node } from '../../../interfaces'; import { Node } from '../../../interfaces';
export default function visitText( export default function visitText(
@ -7,5 +8,5 @@ export default function visitText(
block: Block, block: Block,
node: Node node: Node
) { ) {
generator.append(node.data.replace(/(\${|`|\\)/g, '\\$1').replace(/([^\\@#])?([@#])/g, '$1\\$2')); generator.append(escape(node.data).replace(/(\${|`|\\)/g, '\\$1'));
} }

@ -1,3 +1,7 @@
export default function stringify(data: string) { export function stringify(data: string) {
return JSON.stringify(data.replace(/([^\\@#])?([@#])/g, '$1\\$2')); return JSON.stringify(escape(data));
}
export function escape(data: string) {
return data.replace(/([^\\@#])?([@#])/g, '$1\\$2');
} }

@ -0,0 +1,3 @@
export default {
html: `<a href='mailto:hello@example.com'>email</a>`
};

@ -0,0 +1 @@
<a href='mailto:hello@example.com'>email</a>

@ -0,0 +1,3 @@
export default {
html: `<span title='"foo"'>foo</span>`
};
Loading…
Cancel
Save