diff --git a/library/HTMLPurifier/Strategy/MakeWellFormed.php b/library/HTMLPurifier/Strategy/MakeWellFormed.php index 24a14bff..0698c4e4 100644 --- a/library/HTMLPurifier/Strategy/MakeWellFormed.php +++ b/library/HTMLPurifier/Strategy/MakeWellFormed.php @@ -274,20 +274,23 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy $reprocess = true; continue; } - foreach ($this->injectors as $i => $injector) { - if (isset($token->skip[$i])) continue; - if ($token->rewind !== null && $token->rewind !== $i) continue; - $injector->handleEnd($token); - $this->processToken($token, $i); - $reprocess = true; - break; - } - if ($reprocess) continue; - // first, check for the simplest case: everything closes neatly + // first, check for the simplest case: everything closes neatly. + // Eventually, everything passes through here; if there are problems + // we modify the input stream accordingly and then punt, so that + // the tokens get processed again. $current_parent = array_pop($this->stack); if ($current_parent->name == $token->name) { $token->start = $current_parent; + foreach ($this->injectors as $i => $injector) { + if (isset($token->skip[$i])) continue; + if ($token->rewind !== null && $token->rewind !== $i) continue; + $injector->handleEnd($token); + $this->processToken($token, $i); + $this->stack[] = $current_parent; + $reprocess = true; + break; + } continue; } @@ -343,6 +346,7 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy $this->insertBefore($new_token); } $reprocess = true; + continue; } $context->destroy('CurrentNesting'); diff --git a/tests/HTMLPurifier/Strategy/MakeWellFormed/EndInsertInjector.php b/tests/HTMLPurifier/Strategy/MakeWellFormed/EndInsertInjector.php new file mode 100644 index 00000000..0673aee9 --- /dev/null +++ b/tests/HTMLPurifier/Strategy/MakeWellFormed/EndInsertInjector.php @@ -0,0 +1,16 @@ +name == 'div') return; + $token = array( + new HTMLPurifier_Token_Start('b'), + new HTMLPurifier_Token_Text('Comment'), + new HTMLPurifier_Token_End('b'), + $token + ); + } +} diff --git a/tests/HTMLPurifier/Strategy/MakeWellFormed/EndInsertInjectorTest.php b/tests/HTMLPurifier/Strategy/MakeWellFormed/EndInsertInjectorTest.php new file mode 100644 index 00000000..ea0025a2 --- /dev/null +++ b/tests/HTMLPurifier/Strategy/MakeWellFormed/EndInsertInjectorTest.php @@ -0,0 +1,37 @@ +obj = new HTMLPurifier_Strategy_MakeWellFormed(); + $this->config->set('AutoFormat', 'Custom', array( + new HTMLPurifier_Strategy_MakeWellFormed_EndInsertInjector() + )); + } + function testEmpty() { + $this->assertResult(''); + } + function testNormal() { + $this->assertResult('Foo', 'FooComment'); + } + function testEndOfDocumentProcessing() { + $this->assertResult('Foo', 'FooComment'); + } + function testDoubleEndOfDocumentProcessing() { + $this->assertResult('Foo', 'FooCommentComment'); + } + function testEndOfNodeProcessing() { + $this->assertResult('
Foo
', '
FooComment
'); + } + function testEmptyToStartEndProcessing() { + $this->assertResult('', 'Comment'); + } + function testSpuriousEndTag() { + $this->assertResult('', ''); + } + function testLessButStillSpuriousEndTag() { + $this->assertResult('
', '
'); + } +} + diff --git a/tests/HTMLPurifier/Strategy/MakeWellFormed/EndRewindInjector.php b/tests/HTMLPurifier/Strategy/MakeWellFormed/EndRewindInjector.php new file mode 100644 index 00000000..9352c1e4 --- /dev/null +++ b/tests/HTMLPurifier/Strategy/MakeWellFormed/EndRewindInjector.php @@ -0,0 +1,27 @@ +_InjectorTest_EndRewindInjector_delete)) { + $token = false; + } + } + public function handleText(&$token) { + $token = false; + } + public function handleEnd(&$token) { + $i = null; + if ( + $this->backward($i, $prev) && + $prev instanceof HTMLPurifier_Token_Start && + $prev->name == 'span' + ) { + $token = false; + $prev->_InjectorTest_EndRewindInjector_delete = true; + $this->rewind($i); + } + } +} diff --git a/tests/HTMLPurifier/Strategy/MakeWellFormed/EndRewindInjectorTest.php b/tests/HTMLPurifier/Strategy/MakeWellFormed/EndRewindInjectorTest.php new file mode 100644 index 00000000..ef906e84 --- /dev/null +++ b/tests/HTMLPurifier/Strategy/MakeWellFormed/EndRewindInjectorTest.php @@ -0,0 +1,32 @@ +obj = new HTMLPurifier_Strategy_MakeWellFormed(); + $this->config->set('AutoFormat', 'Custom', array( + new HTMLPurifier_Strategy_MakeWellFormed_EndRewindInjector() + )); + } + function testBasic() { + $this->assertResult(''); + } + function testFunction() { + $this->assertResult('asdf',''); + } + function testFailedFunction() { + $this->assertResult('asdasdfasdf',''); + } + function testPadded() { + $this->assertResult('asdf',''); + } + function testDoubled() { + $this->config->set('AutoFormat', 'Custom', array( + new HTMLPurifier_Strategy_MakeWellFormed_EndRewindInjector(), + new HTMLPurifier_Strategy_MakeWellFormed_EndRewindInjector(), + )); + $this->assertResult('asdf', ''); + } +} + diff --git a/tests/HTMLPurifier/Strategy/MakeWellFormed/SkipInjector.php b/tests/HTMLPurifier/Strategy/MakeWellFormed/SkipInjector.php new file mode 100644 index 00000000..9ee8e826 --- /dev/null +++ b/tests/HTMLPurifier/Strategy/MakeWellFormed/SkipInjector.php @@ -0,0 +1,10 @@ +obj = new HTMLPurifier_Strategy_MakeWellFormed(); + $this->config->set('AutoFormat', 'Custom', array( + new HTMLPurifier_Strategy_MakeWellFormed_SkipInjector() + )); + } + function testEmpty() { + $this->assertResult(''); + } + function testMultiply() { + $this->assertResult('
', '

'); + } + function testMultiplyMultiply() { + $this->config->set('AutoFormat', 'Custom', array( + new HTMLPurifier_Strategy_MakeWellFormed_SkipInjector(), + new HTMLPurifier_Strategy_MakeWellFormed_SkipInjector() + )); + $this->assertResult('
', '



'); + } +} + diff --git a/tests/HTMLPurifier/Strategy/MakeWellFormed_InjectorTest.php b/tests/HTMLPurifier/Strategy/MakeWellFormed_InjectorTest.php index 80685727..212b2d4c 100644 --- a/tests/HTMLPurifier/Strategy/MakeWellFormed_InjectorTest.php +++ b/tests/HTMLPurifier/Strategy/MakeWellFormed_InjectorTest.php @@ -16,9 +16,13 @@ class HTMLPurifier_Strategy_MakeWellFormed_InjectorTest extends HTMLPurifier_Str $mock = new HTMLPurifier_InjectorMock(); $b = new HTMLPurifier_Token_End('b'); $b->skip = array(0 => true); + $b->start = new HTMLPurifier_Token_Start('b'); + $b->start->skip = array(0 => true, 1 => true); $mock->expectAt(0, 'handleEnd', array($b)); $i = new HTMLPurifier_Token_End('i'); + $i->start = new HTMLPurifier_Token_Start('i'); $i->skip = array(0 => true); + $i->start->skip = array(0 => true, 1 => true); $mock->expectAt(1, 'handleEnd', array($i)); $mock->expectCallCount('handleEnd', 2); $mock->setReturnValue('getRewind', false);