Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 94207f8

Browse files
IgorMinarpetebacondarwin
authored andcommitted
fix($sanitize): support void elements, fixups, remove dead code, typos
Closes #12524
1 parent 35a2153 commit 94207f8

File tree

3 files changed

+25
-58
lines changed

3 files changed

+25
-58
lines changed

docs/content/error/$sanitize/ddns.ngdoc docs/content/error/$sanitize/noinert.ngdoc

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
@ngdoc error
2-
@name $sanitize:ddns
3-
@fullName DOMDocument not supported
2+
@name $sanitize:noinert
3+
@fullName Can't create an inert html document
44
@description
55

6-
This error occurs when `$sanitize` sanitizer determines that `DOMDocument` api is not supported by the current browser.
6+
This error occurs when `$sanitize` sanitizer determines that `document.implementation.createHTMLDocument ` api is not supported by the current browser.
77

88
This api is necessary for safe parsing of HTML strings into DOM trees and without it the sanitizer can't sanitize the input.
99

src/ngSanitize/sanitize.js

+14-35
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ function sanitizeText(chars) {
149149
// Regular Expressions for parsing tags and attributes
150150
var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
151151
// Match everything outside of normal chars and " (quote character)
152-
NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;
152+
NON_ALPHANUMERIC_REGEXP = /([^\#-~ |!])/g;
153153

154154

155155
// Good source of info about elements and attributes
@@ -236,28 +236,24 @@ function toMap(str, lowercaseKeys) {
236236
return obj;
237237
}
238238

239-
var baseNode;
239+
var inertBodyElement;
240240
(function(window) {
241241
var doc;
242-
if (window.DOMDocument) {
243-
doc = new window.DOMDocument();
244-
} else if (window.document && window.document.implementation) {
242+
if (window.document && window.document.implementation) {
245243
doc = window.document.implementation.createHTMLDocument("inert");
246-
} else if (window.ActiveXObject) {
247-
doc = new window.ActiveXObject("Msxml.DOMDocument");
248244
} else {
249-
throw $sanitizeMinErr('ddns', "DOMDocument not supported");
245+
throw $sanitizeMinErr('noinert', "Can't create an inert html document");
250246
}
251247
var docElement = doc.documentElement || doc.getDocumentElement();
252248
var bodyElements = docElement.getElementsByTagName('body');
253249

254250
// usually there should be only one body element in the document, but IE doesn't have any, so we need to create one
255251
if (bodyElements.length === 1) {
256-
baseNode = bodyElements[0];
252+
inertBodyElement = bodyElements[0];
257253
} else {
258254
var html = doc.createElement('html');
259-
baseNode = doc.createElement('body');
260-
html.appendChild(baseNode);
255+
inertBodyElement = doc.createElement('body');
256+
html.appendChild(inertBodyElement);
261257
doc.appendChild(html);
262258
}
263259
})(window);
@@ -280,8 +276,8 @@ function htmlParser(html, handler) {
280276
} else if (typeof html !== 'string') {
281277
html = '' + html;
282278
}
283-
baseNode.innerHTML = html;
284-
var node = baseNode.firstChild;
279+
inertBodyElement.innerHTML = html;
280+
var node = inertBodyElement.firstChild;
285281
while (node) {
286282
switch (node.nodeType) {
287283
case 1: // ELEMENT_NODE
@@ -290,9 +286,6 @@ function htmlParser(html, handler) {
290286
case 3: // TEXT NODE
291287
handler.chars(node.textContent);
292288
break;
293-
case 8: // COMMENT NODE
294-
handler.comment(node.textContent);
295-
break;
296289
}
297290

298291
var nextNode;
@@ -304,7 +297,7 @@ function htmlParser(html, handler) {
304297
if (!nextNode) {
305298
while (nextNode == null) {
306299
node = node.parentNode;
307-
if (node === baseNode) break;
300+
if (node === inertBodyElement) break;
308301
nextNode = node.nextSibling;
309302
if (node.nodeType == 1) {
310303
handler.end(node.nodeName.toLowerCase());
@@ -315,8 +308,8 @@ function htmlParser(html, handler) {
315308
node = nextNode;
316309
}
317310

318-
while (node = baseNode.firstChild) {
319-
baseNode.removeChild(node);
311+
while (node = inertBodyElement.firstChild) {
312+
inertBodyElement.removeChild(node);
320313
}
321314
}
322315

@@ -329,20 +322,6 @@ function attrToMap(attrs) {
329322
return map;
330323
}
331324

332-
var hiddenPre=document.createElement("pre");
333-
/**
334-
* decodes all entities into regular string
335-
* @param value
336-
* @returns {string} A string with decoded entities.
337-
*/
338-
function decodeEntities(value) {
339-
if (!value) { return ''; }
340-
341-
hiddenPre.innerHTML = value.replace(/</g,"&lt;");
342-
// innerText depends on styling as it doesn't display hidden elements.
343-
// Therefore, it's better to use textContent not to cause unnecessary reflows.
344-
return hiddenPre.textContent;
345-
}
346325

347326
/**
348327
* Escapes all potentially dangerous characters, so that the
@@ -368,7 +347,7 @@ function encodeEntities(value) {
368347

369348
/**
370349
* create an HTML/XML writer which writes to buffer
371-
* @param {Array} buf use buf.jain('') to get out sanitized html string
350+
* @param {Array} buf use buf.join('') to get out sanitized html string
372351
* @returns {object} in the form of {
373352
* start: function(tag, attrs) {},
374353
* end: function(tag) {},
@@ -405,7 +384,7 @@ function htmlSanitizeWriter(buf, uriValidator) {
405384
},
406385
end: function(tag) {
407386
tag = angular.lowercase(tag);
408-
if (!ignore && validElements[tag] === true) {
387+
if (!ignore && validElements[tag] === true && voidElements[tag] !== true) {
409388
out('</');
410389
out(tag);
411390
out('>');

test/ngSanitize/sanitizeSpec.js

+8-20
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ describe('HTML', function() {
5050
};
5151
});
5252

53-
it('should parse comments', function() {
53+
it('should not parse comments', function() {
5454
htmlParser('<!--FOOBAR-->', handler);
55-
expect(comment).toEqual('FOOBAR');
55+
expect(comment).not.toBeDefined();
5656
});
5757

5858
it('should parse basic format', function() {
@@ -66,18 +66,6 @@ describe('HTML', function() {
6666
toBe('&lt;- text1 text2 &lt;1 text1 text2 &lt;{');
6767
});
6868

69-
it('should throw badparse if text content contains "<" followed by "/" without matching ">"', function() {
70-
htmlParser('foo </ bar', handler);
71-
expect(start).toEqual(undefined);
72-
expect(text).toEqual('foo ');
73-
});
74-
75-
it('should throw badparse if text content contains "<" followed by an ASCII letter without matching ">"', function() {
76-
htmlParser('foo <a bar', handler);
77-
expect(start).toEqual(undefined);
78-
expect(text).toEqual('foo ');
79-
});
80-
8169
it('should accept tag delimiters such as "<" inside real tags', function() {
8270
// Assert that the < is part of the text node content, and not part of a tag name.
8371
htmlParser('<p> 10 < 100 </p>', handler);
@@ -103,8 +91,8 @@ describe('HTML', function() {
10391
});
10492

10593
it('should parse empty value attribute of node', function() {
106-
htmlParser('<OPTION selected value="">abc</OPTION>', handler);
107-
expect(start).toEqual({tag:'option', attrs:{selected:'', value:''}});
94+
htmlParser('<test-foo selected value="">abc</test-foo>', handler);
95+
expect(start).toEqual({tag:'test-foo', attrs:{selected:'', value:''}});
10896
expect(text).toEqual('abc');
10997
});
11098
});
@@ -165,7 +153,7 @@ describe('HTML', function() {
165153
});
166154

167155
it('should handle self closed elements', function() {
168-
expectHTML('a<hr/>c').toEqual('a<hr></hr>c');
156+
expectHTML('a<hr/>c').toEqual('a<hr>c');
169157
});
170158

171159
it('should handle namespace', function() {
@@ -192,7 +180,7 @@ describe('HTML', function() {
192180

193181
it('should ignore back slash as escape', function() {
194182
expectHTML('<img alt="xxx\\" title="><script>....">').
195-
toEqual('<img alt="xxx\\" title="&gt;&lt;script&gt;...."></img>');
183+
toEqual('<img alt="xxx\\" title="&gt;&lt;script&gt;....">');
196184
});
197185

198186
it('should ignore object attributes', function() {
@@ -415,11 +403,11 @@ describe('HTML', function() {
415403
inject(function() {
416404
$$sanitizeUri.andReturn('someUri');
417405

418-
expectHTML('<img src="someUri"/>').toEqual('<img src="someUri"></img>');
406+
expectHTML('<img src="someUri"/>').toEqual('<img src="someUri">');
419407
expect($$sanitizeUri).toHaveBeenCalledWith('someUri', true);
420408

421409
$$sanitizeUri.andReturn('unsafe:someUri');
422-
expectHTML('<img src="someUri"/>').toEqual('<img></img>');
410+
expectHTML('<img src="someUri"/>').toEqual('<img>');
423411
});
424412
});
425413

0 commit comments

Comments
 (0)