diff --git a/NEWS b/NEWS index 9b087022..b4abb857 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,11 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier 4.7.0, unknown release date # opacity is now considered a "tricky" CSS property rather than a proprietary one. +! %AutoFormat.RemoveEmpty.Predicate for specifying exactly when + an element should be considered "empty" (maybe preserve if it + has attributes), and modify iframe support so that the iframe + is removed if it is missing a src attribute. Thanks meeva for + reporting. - Don't truncate upon encountering when using DOMLex. Thanks Myrto Christina for finally convincing me to fix this. - Update YouTube filter for new code. diff --git a/configdoc/usage.xml b/configdoc/usage.xml index f3f7a36a..97bc34cb 100644 --- a/configdoc/usage.xml +++ b/configdoc/usage.xml @@ -481,6 +481,11 @@ 47 + + + 48 + + 54 diff --git a/library/HTMLPurifier/ConfigSchema/schema.ser b/library/HTMLPurifier/ConfigSchema/schema.ser index 22ea3218..1e6ccd22 100644 Binary files a/library/HTMLPurifier/ConfigSchema/schema.ser and b/library/HTMLPurifier/ConfigSchema/schema.ser differ diff --git a/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt b/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt new file mode 100644 index 00000000..6367fe23 --- /dev/null +++ b/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt @@ -0,0 +1,14 @@ +AutoFormat.RemoveEmpty.Predicate +TYPE: hash +VERSION: 4.7.0 +DEFAULT: array('colgroup' => array(), 'th' => array(), 'td' => array(), 'iframe' => array('src')) +--DESCRIPTION-- +

+ Given that an element has no contents, it will be removed by default, unless + this predicate dictates otherwise. The predicate can either be an associative + map from tag name to list of attributes that must be present for the element + to be considered preserved: thus, the default always preserves colgroup, + th and td, and also iframe if it + has a src. +

+--# vim: et sw=4 sts=4 diff --git a/library/HTMLPurifier/Injector/RemoveEmpty.php b/library/HTMLPurifier/Injector/RemoveEmpty.php index cd885722..01353ff1 100644 --- a/library/HTMLPurifier/Injector/RemoveEmpty.php +++ b/library/HTMLPurifier/Injector/RemoveEmpty.php @@ -28,10 +28,10 @@ class HTMLPurifier_Injector_RemoveEmpty extends HTMLPurifier_Injector private $removeNbspExceptions; /** + * Cached contents of %AutoFormat.RemoveEmpty.Predicate * @type array - * TODO: make me configurable */ - private $_exclude = array('colgroup' => 1, 'th' => 1, 'td' => 1, 'iframe' => 1); + private $exclude; /** * @param HTMLPurifier_Config $config @@ -45,6 +45,7 @@ class HTMLPurifier_Injector_RemoveEmpty extends HTMLPurifier_Injector $this->context = $context; $this->removeNbsp = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp'); $this->removeNbspExceptions = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions'); + $this->exclude = $config->get('AutoFormat.RemoveEmpty.Predicate'); $this->attrValidator = new HTMLPurifier_AttrValidator(); } @@ -75,11 +76,15 @@ class HTMLPurifier_Injector_RemoveEmpty extends HTMLPurifier_Injector break; } if (!$next || ($next instanceof HTMLPurifier_Token_End && $next->name == $token->name)) { - if (isset($this->_exclude[$token->name])) { - return; - } $this->attrValidator->validateToken($token, $this->config, $this->context); $token->armor['ValidateAttributes'] = true; + if (isset($this->exclude[$token->name])) { + $r = true; + foreach ($this->exclude[$token->name] as $elem) { + if (!isset($token->attr[$elem])) $r = false; + } + if ($r) return; + } if (isset($token->attr['id']) || isset($token->attr['name'])) { return; } diff --git a/tests/HTMLPurifier/Injector/RemoveEmptyTest.php b/tests/HTMLPurifier/Injector/RemoveEmptyTest.php index d25b218f..d719ba8a 100644 --- a/tests/HTMLPurifier/Injector/RemoveEmptyTest.php +++ b/tests/HTMLPurifier/Injector/RemoveEmptyTest.php @@ -91,6 +91,25 @@ class HTMLPurifier_Injector_RemoveEmptyTest extends HTMLPurifier_InjectorHarness $this->assertResult(' ', "\xC2\xA0"); } + public function testRemoveIframe() + { + $this->config->set('HTML.SafeIframe', true); + $this->assertResult('', ''); + } + + public function testNoRemoveIframe() + { + $this->config->set('HTML.SafeIframe', true); + $this->assertResult('', ''); + } + + public function testRemoveDisallowedIframe() + { + $this->config->set('HTML.SafeIframe', true); + $this->config->set('URI.SafeIframeRegexp', '%^http://www.youtube.com/embed/%'); + $this->assertResult('', ''); + } + } // vim: et sw=4 sts=4