From fb9472c7fbf9979f48ef49aff76903ac130d0959 Mon Sep 17 00:00:00 2001 From: Leonardo Braga Date: Wed, 7 Oct 2015 00:51:23 -0400 Subject: [PATCH] Manipulation: Bring tagname regexes up to spec Fixes gh-2005 Closes gh-2634 --- src/core/var/rsingleTag.js | 2 +- src/manipulation.js | 2 +- src/manipulation/var/rtagName.js | 2 +- test/unit/manipulation.js | 67 ++++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/core/var/rsingleTag.js b/src/core/var/rsingleTag.js index 1a55ee39d..1ddf95ed4 100644 --- a/src/core/var/rsingleTag.js +++ b/src/core/var/rsingleTag.js @@ -1,5 +1,5 @@ define( function() { // Match a standalone tag - return ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ ); + return ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); } ); diff --git a/src/manipulation.js b/src/manipulation.js index cc4fd16cd..6c4b3ede8 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -27,7 +27,7 @@ define( [ dataPriv, dataUser, acceptData, DOMEval ) { var - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, // Support: IE 10-11, Edge 10240+ // In IE/Edge using regex groups here causes severe slowdowns. diff --git a/src/manipulation/var/rtagName.js b/src/manipulation/var/rtagName.js index 9e542694a..1f8751ed8 100644 --- a/src/manipulation/var/rtagName.js +++ b/src/manipulation/var/rtagName.js @@ -1,3 +1,3 @@ define( function() { - return ( /<([\w:-]+)/ ); + return ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); } ); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index 4d8eed7d9..f72000fc4 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -500,6 +500,73 @@ QUnit.test( "html(String) tag-hyphenated elements (Bug #1987)", function( assert assert.equal( j.children().text(), "text", "Tags with multiple hypens behave normally" ); } ); +QUnit.test( "Tag name processing respects the HTML Standard (gh-2005)", function( assert ) { + + assert.expect( 240 ); + + var wrapper = jQuery( "
" ), + nameTerminatingChars = "\x20\t\r\n\f".split( "" ), + specialChars = "[ ] { } _ - = + \\ ( ) * & ^ % $ # @ ! ~ ` ' ; ? ¥ « µ λ ⊕ ≈ ξ ℜ ♣ €" + .split( " " ); + + specialChars.push( specialChars.join( "" ) ); + + jQuery.each( specialChars, function( i, characters ) { + assertSpecialCharsSupport( "html", characters ); + assertSpecialCharsSupport( "append", characters ); + } ); + + jQuery.each( nameTerminatingChars, function( i, character ) { + assertNameTerminatingCharsHandling( "html", character ); + assertNameTerminatingCharsHandling( "append", character ); + } ); + + function buildChild( method, html ) { + wrapper[ method ]( html ); + return wrapper.children()[ 0 ]; + } + + function assertSpecialCharsSupport( method, characters ) { + var child, + codepoint = characters.charCodeAt( 0 ).toString( 16 ).toUpperCase(), + description = characters.length === 1 ? + "U+" + ( "000" + codepoint ).slice( -4 ) + " " + characters : + "all special characters", + nodeName = "valid" + characters + "tagname"; + + child = buildChild( method, "<" + nodeName + ">" ); + assert.equal( child.nodeName.toUpperCase(), nodeName.toUpperCase(), + method + "(): Paired tag name includes " + description ); + + child = buildChild( method, "<" + nodeName + ">" ); + assert.equal( child.nodeName.toUpperCase(), nodeName.toUpperCase(), + method + "(): Unpaired tag name includes " + description ); + + child = buildChild( method, "<" + nodeName + "/>" ); + assert.equal( child.nodeName.toUpperCase(), nodeName.toUpperCase(), + method + "(): Self-closing tag name includes " + description ); + } + + function assertNameTerminatingCharsHandling( method, character ) { + var child, + codepoint = character.charCodeAt( 0 ).toString( 16 ).toUpperCase(), + description = "U+" + ( "000" + codepoint ).slice( -4 ) + " " + character, + nodeName = "div" + character + "this-will-be-discarded"; + + child = buildChild( method, "<" + nodeName + ">" ); + assert.equal( child.nodeName.toUpperCase(), "DIV", + method + "(): Paired tag name terminated by " + description ); + + child = buildChild( method, "<" + nodeName + ">" ); + assert.equal( child.nodeName.toUpperCase(), "DIV", + method + "(): Unpaired open tag name terminated by " + description ); + + child = buildChild( method, "<" + nodeName + "/>" ); + assert.equal( child.nodeName.toUpperCase(), "DIV", + method + "(): Self-closing tag name terminated by " + description ); + } +} ); + QUnit.test( "IE8 serialization bug", function( assert ) { assert.expect( 2 );