0
0
mirror of https://github.com/ezyang/htmlpurifier.git synced 2024-11-09 15:28:40 +00:00

[3.1.0] Fix ScriptRequired bug with trusted installs

- Generator now takes $config and $context during instantiation
- Double quotes outside of attributes are not escaped


git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1700 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
Edward Z. Yang 2008-04-28 01:35:07 +00:00
parent be2cfb7918
commit 4b862f64e6
11 changed files with 227 additions and 188 deletions

4
NEWS
View File

@ -43,12 +43,16 @@ NEWS ( CHANGELOG and HISTORY ) HTMLPurifier
- Missing (or null) in configdoc documentation restored - Missing (or null) in configdoc documentation restored
- If DOM throws and exception during parsing with PH5P (occurs in newer versions - If DOM throws and exception during parsing with PH5P (occurs in newer versions
of DOM), HTML Purifier punts to DirectLex of DOM), HTML Purifier punts to DirectLex
- Fatal error with unserialization of ScriptRequired
. Out-of-date documentation revised . Out-of-date documentation revised
. UTF-8 encoding check optimization as suggested by Diego . UTF-8 encoding check optimization as suggested by Diego
. HTMLPurifier_Error removed in favor of exceptions . HTMLPurifier_Error removed in favor of exceptions
. More copy() function removed; should use clone instead . More copy() function removed; should use clone instead
. More extensive unit tests for HTMLDefinition . More extensive unit tests for HTMLDefinition
. assertPurification moved to central harness . assertPurification moved to central harness
. HTMLPurifier_Generator accepts $config and $context parameters during
instantiation, not runtime
. Double-quotes outside of attribute values are now unescaped
3.1.0rc1, released 2008-04-22 3.1.0rc1, released 2008-04-22
# Autoload support added. Internal require_once's removed in favor of an # Autoload support added. Internal require_once's removed in favor of an

2
TODO
View File

@ -13,6 +13,8 @@ afraid to cast your vote for the next feature to be implemented!
- Get PH5P working with the latest versions of DOM, which have much more - Get PH5P working with the latest versions of DOM, which have much more
stringent error checking procedures. Maybe convert straight to tokens. stringent error checking procedures. Maybe convert straight to tokens.
- Figure out what to do with $this->config configuration object calls
in the scanner
FUTURE VERSIONS FUTURE VERSIONS
--------------- ---------------

View File

@ -2,7 +2,7 @@
<usage> <usage>
<directive id="Core.CollectErrors"> <directive id="Core.CollectErrors">
<file name="HTMLPurifier.php"> <file name="HTMLPurifier.php">
<line>132</line> <line>131</line>
</file> </file>
<file name="HTMLPurifier/Lexer.php"> <file name="HTMLPurifier/Lexer.php">
<line>85</line> <line>85</line>
@ -91,17 +91,7 @@
</directive> </directive>
<directive id="Output.CommentScriptContents"> <directive id="Output.CommentScriptContents">
<file name="HTMLPurifier/Generator.php"> <file name="HTMLPurifier/Generator.php">
<line>37</line> <line>41</line>
</file>
</directive>
<directive id="Output.TidyFormat">
<file name="HTMLPurifier/Generator.php">
<line>58</line>
</file>
</directive>
<directive id="Output.Newline">
<file name="HTMLPurifier/Generator.php">
<line>83</line>
</file> </file>
</directive> </directive>
<directive id="HTML.BlockWrapper"> <directive id="HTML.BlockWrapper">

View File

@ -116,6 +116,7 @@ require 'HTMLPurifier/AttrTransform/ImgSpace.php';
require 'HTMLPurifier/AttrTransform/Lang.php'; require 'HTMLPurifier/AttrTransform/Lang.php';
require 'HTMLPurifier/AttrTransform/Length.php'; require 'HTMLPurifier/AttrTransform/Length.php';
require 'HTMLPurifier/AttrTransform/Name.php'; require 'HTMLPurifier/AttrTransform/Name.php';
require 'HTMLPurifier/AttrTransform/ScriptRequired.php';
require 'HTMLPurifier/ChildDef/Chameleon.php'; require 'HTMLPurifier/ChildDef/Chameleon.php';
require 'HTMLPurifier/ChildDef/Custom.php'; require 'HTMLPurifier/ChildDef/Custom.php';
require 'HTMLPurifier/ChildDef/Empty.php'; require 'HTMLPurifier/ChildDef/Empty.php';

View File

@ -90,7 +90,6 @@ class HTMLPurifier
$this->config = HTMLPurifier_Config::create($config); $this->config = HTMLPurifier_Config::create($config);
$this->strategy = new HTMLPurifier_Strategy_Core(); $this->strategy = new HTMLPurifier_Strategy_Core();
$this->generator = new HTMLPurifier_Generator();
} }
@ -124,8 +123,8 @@ class HTMLPurifier
$context = new HTMLPurifier_Context(); $context = new HTMLPurifier_Context();
// our friendly neighborhood generator, all primed with configuration too! // setup HTML generator
$this->generator->generateFromTokens(array(), $config, $context); $this->generator = new HTMLPurifier_Generator($config, $context);
$context->register('Generator', $this->generator); $context->register('Generator', $this->generator);
// set up global context variables // set up global context variables
@ -178,8 +177,7 @@ class HTMLPurifier
$html, $config, $context $html, $config, $context
), ),
$config, $context $config, $context
), )
$config, $context
); );
for ($i = $filter_size - 1; $i >= 0; $i--) { for ($i = $filter_size - 1; $i >= 0; $i--) {

View File

@ -110,6 +110,7 @@ require_once $__dir . '/HTMLPurifier/AttrTransform/ImgSpace.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Lang.php'; require_once $__dir . '/HTMLPurifier/AttrTransform/Lang.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Length.php'; require_once $__dir . '/HTMLPurifier/AttrTransform/Length.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Name.php'; require_once $__dir . '/HTMLPurifier/AttrTransform/Name.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/ScriptRequired.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Chameleon.php'; require_once $__dir . '/HTMLPurifier/ChildDef/Chameleon.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Custom.php'; require_once $__dir . '/HTMLPurifier/ChildDef/Custom.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Empty.php'; require_once $__dir . '/HTMLPurifier/ChildDef/Empty.php';

View File

@ -0,0 +1,14 @@
<?php
/**
* Implements required attribute stipulation for <script>
*/
class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform
{
public function transform($attr, $config, $context) {
if (!isset($attr['type'])) {
$attr['type'] = 'text/javascript';
}
return $attr;
}
}

View File

@ -11,78 +11,79 @@ class HTMLPurifier_Generator
{ {
/** /**
* Bool cache of %HTML.XHTML * Whether or not generator should produce XML output
*/ */
private $_xhtml = true; private $_xhtml = true;
/** /**
* Bool cache of %Output.CommentScriptContents * :HACK: Whether or not generator should comment the insides of <script> tags
*/ */
private $_scriptFix = false; private $_scriptFix = false;
/** /**
* Cache of HTMLDefinition * Cache of HTMLDefinition during HTML output to determine whether or
* not attributes should be minimized.
*/ */
private $_def; private $_def;
/**
* Configuration for the generator
*/
private $_config;
/**
* @param $config Instance of HTMLPurifier_Config
* @param $context Instance of HTMLPurifier_Context
*/
public function __construct($config = null, $context = null) {
if (!$config) $config = HTMLPurifier_Config::createDefault();
$this->_config = $config;
$this->_scriptFix = $config->get('Output', 'CommentScriptContents');
$this->_def = $config->getHTMLDefinition();
$this->_xhtml = $this->_def->doctype->xml;
}
/** /**
* Generates HTML from an array of tokens. * Generates HTML from an array of tokens.
* @param $tokens Array of HTMLPurifier_Token * @param $tokens Array of HTMLPurifier_Token
* @param $config HTMLPurifier_Config object * @param $config HTMLPurifier_Config object
* @return Generated HTML * @return Generated HTML
*/ */
public function generateFromTokens($tokens, $config, $context) { public function generateFromTokens($tokens) {
$html = '';
if (!$config) $config = HTMLPurifier_Config::createDefault();
$this->_scriptFix = $config->get('Output', 'CommentScriptContents');
$this->_def = $config->getHTMLDefinition();
$this->_xhtml = $this->_def->doctype->xml;
if (!$tokens) return ''; if (!$tokens) return '';
// Basic algorithm
$html = '';
for ($i = 0, $size = count($tokens); $i < $size; $i++) { for ($i = 0, $size = count($tokens); $i < $size; $i++) {
if ($this->_scriptFix && $tokens[$i]->name === 'script' if ($this->_scriptFix && $tokens[$i]->name === 'script'
&& $i + 2 < $size && $tokens[$i+2] instanceof HTMLPurifier_Token_End) { && $i + 2 < $size && $tokens[$i+2] instanceof HTMLPurifier_Token_End) {
// script special case // script special case
// the contents of the script block must be ONE token // the contents of the script block must be ONE token
// for this to work // for this to work.
$html .= $this->generateFromToken($tokens[$i++]); $html .= $this->generateFromToken($tokens[$i++]);
$html .= $this->generateScriptFromToken($tokens[$i++]); $html .= $this->generateScriptFromToken($tokens[$i++]);
// We're not going to do this: it wouldn't be valid anyway
//while ($tokens[$i]->name != 'script') {
// $html .= $this->generateScriptFromToken($tokens[$i++]);
//}
} }
$html .= $this->generateFromToken($tokens[$i]); $html .= $this->generateFromToken($tokens[$i]);
} }
if ($config->get('Output', 'TidyFormat') && extension_loaded('tidy')) {
// Tidy cleanup
$tidy_options = array( if (extension_loaded('tidy') && $this->_config->get('Output', 'TidyFormat')) {
$tidy = new Tidy;
$tidy->parseString($html, array(
'indent'=> true, 'indent'=> true,
'output-xhtml' => $this->_xhtml, 'output-xhtml' => $this->_xhtml,
'show-body-only' => true, 'show-body-only' => true,
'indent-spaces' => 2, 'indent-spaces' => 2,
'wrap' => 68, 'wrap' => 68,
); ), 'utf8');
if (version_compare(PHP_VERSION, '5', '<')) { $tidy->cleanRepair();
tidy_set_encoding('utf8'); $html = (string) $tidy; // explicit cast necessary
foreach ($tidy_options as $key => $value) {
tidy_setopt($key, $value);
}
tidy_parse_string($html);
tidy_clean_repair();
$html = tidy_get_output();
} else {
$tidy = new Tidy;
$tidy->parseString($html, $tidy_options, 'utf8');
$tidy->cleanRepair();
$html = (string) $tidy;
}
} }
// normalize newlines to system
$nl = $config->get('Output', 'Newline'); // Normalize newlines to system defined value
$nl = $this->_config->get('Output', 'Newline');
if ($nl === null) $nl = PHP_EOL; if ($nl === null) $nl = PHP_EOL;
$html = str_replace("\n", $nl, $html); if ($nl !== "\n") $html = str_replace("\n", $nl, $html);
return $html; return $html;
} }
@ -92,8 +93,11 @@ class HTMLPurifier_Generator
* @return Generated HTML * @return Generated HTML
*/ */
public function generateFromToken($token) { public function generateFromToken($token) {
if (!$token instanceof HTMLPurifier_Token) return ''; if (!$token instanceof HTMLPurifier_Token) {
if ($token instanceof HTMLPurifier_Token_Start) { trigger_error('Cannot generate HTML from non-HTMLPurifier_Token object', E_USER_WARNING);
return '';
} elseif ($token instanceof HTMLPurifier_Token_Start) {
$attr = $this->generateAttributes($token->attr, $token->name); $attr = $this->generateAttributes($token->attr, $token->name);
return '<' . $token->name . ($attr ? ' ' : '') . $attr . '>'; return '<' . $token->name . ($attr ? ' ' : '') . $attr . '>';
@ -103,11 +107,11 @@ class HTMLPurifier_Generator
} elseif ($token instanceof HTMLPurifier_Token_Empty) { } elseif ($token instanceof HTMLPurifier_Token_Empty) {
$attr = $this->generateAttributes($token->attr, $token->name); $attr = $this->generateAttributes($token->attr, $token->name);
return '<' . $token->name . ($attr ? ' ' : '') . $attr . return '<' . $token->name . ($attr ? ' ' : '') . $attr .
( $this->_xhtml ? ' /': '' ) ( $this->_xhtml ? ' /': '' ) // <br /> v. <br>
. '>'; . '>';
} elseif ($token instanceof HTMLPurifier_Token_Text) { } elseif ($token instanceof HTMLPurifier_Token_Text) {
return $this->escape($token->data); return $this->escape($token->data, ENT_NOQUOTES);
} elseif ($token instanceof HTMLPurifier_Token_Comment) { } elseif ($token instanceof HTMLPurifier_Token_Comment) {
return '<!--' . $token->data . '-->'; return '<!--' . $token->data . '-->';
@ -124,25 +128,27 @@ class HTMLPurifier_Generator
*/ */
public function generateScriptFromToken($token) { public function generateScriptFromToken($token) {
if (!$token instanceof HTMLPurifier_Token_Text) return $this->generateFromToken($token); if (!$token instanceof HTMLPurifier_Token_Text) return $this->generateFromToken($token);
// return '<!--' . "\n" . trim($token->data) . "\n" . '// -->'; // Thanks <http://lachy.id.au/log/2005/05/script-comments>
// more advanced version:
// thanks <http://lachy.id.au/log/2005/05/script-comments>
$data = preg_replace('#//\s*$#', '', $token->data); $data = preg_replace('#//\s*$#', '', $token->data);
return '<!--//--><![CDATA[//><!--' . "\n" . trim($data) . "\n" . '//--><!]]>'; return '<!--//--><![CDATA[//><!--' . "\n" . trim($data) . "\n" . '//--><!]]>';
} }
/** /**
* Generates attribute declarations from attribute array. * Generates attribute declarations from attribute array.
* @note This does not include the leading or trailing space.
* @param $assoc_array_of_attributes Attribute array * @param $assoc_array_of_attributes Attribute array
* @param $element Name of element attributes are for, used to check
* attribute minimization.
* @return Generate HTML fragment for insertion. * @return Generate HTML fragment for insertion.
*/ */
public function generateAttributes($assoc_array_of_attributes, $element) { public function generateAttributes($assoc_array_of_attributes, $element = false) {
$html = ''; $html = '';
foreach ($assoc_array_of_attributes as $key => $value) { foreach ($assoc_array_of_attributes as $key => $value) {
if (!$this->_xhtml) { if (!$this->_xhtml) {
// remove namespaced attributes // Remove namespaced attributes
if (strpos($key, ':') !== false) continue; if (strpos($key, ':') !== false) continue;
if (!empty($this->_def->info[$element]->attr[$key]->minimized)) { // Check if we should minimize the attribute: val="val" -> val
if ($element && !empty($this->_def->info[$element]->attr[$key]->minimized)) {
$html .= $key . ' '; $html .= $key . ' ';
continue; continue;
} }
@ -154,11 +160,16 @@ class HTMLPurifier_Generator
/** /**
* Escapes raw text data. * Escapes raw text data.
* @todo This really ought to be protected, but until we have a facility
* for properly generating HTML here w/o using tokens, it stays
* public.
* @param $string String data to escape for HTML. * @param $string String data to escape for HTML.
* @param $quote Quoting style, like htmlspecialchars. ENT_NOQUOTES is
* permissible for non-attribute output.
* @return String escaped data. * @return String escaped data.
*/ */
public function escape($string) { public function escape($string, $quote = ENT_COMPAT) {
return htmlspecialchars($string, ENT_COMPAT, 'UTF-8'); return htmlspecialchars($string, $quote, 'UTF-8');
} }
} }

View File

@ -7,19 +7,6 @@ INSIDE HTML PURIFIER DOCUMENTS. USE ONLY WITH TRUSTED USER INPUT!!!
*/ */
/**
* Implements required attribute stipulation for <script>
*/
class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform
{
public function transform($attr, $config, $context) {
if (!isset($attr['type'])) {
$attr['type'] = 'text/javascript';
}
return $attr;
}
}
/** /**
* XHTML 1.1 Scripting module, defines elements that are used to contain * XHTML 1.1 Scripting module, defines elements that are used to contain
* information pertaining to executable scripts or the lack of support * information pertaining to executable scripts or the lack of support

View File

@ -35,11 +35,6 @@ class HTMLPurifier_ComplexHarness extends HTMLPurifier_Harness
*/ */
protected $lexer; protected $lexer;
/**
* Instance of HTMLPurifier_Generator
*/
protected $generator;
/** /**
* Default config to fall back on if no config is available * Default config to fall back on if no config is available
*/ */
@ -52,7 +47,6 @@ class HTMLPurifier_ComplexHarness extends HTMLPurifier_Harness
public function __construct() { public function __construct() {
$this->lexer = new HTMLPurifier_Lexer_DirectLex(); $this->lexer = new HTMLPurifier_Lexer_DirectLex();
$this->generator = new HTMLPurifier_Generator();
parent::__construct(); parent::__construct();
} }
@ -110,7 +104,8 @@ class HTMLPurifier_ComplexHarness extends HTMLPurifier_Harness
* Generate textual HTML from tokens * Generate textual HTML from tokens
*/ */
protected function generate($tokens) { protected function generate($tokens) {
return $this->generator->generateFromTokens($tokens, $this->config, $this->context); $generator = new HTMLPurifier_Generator($this->config, $this->context);
return $generator->generateFromTokens($tokens);
} }
} }

View File

@ -1,108 +1,152 @@
<?php <?php
class HTMLPurifier_GeneratorTest extends HTMLPurifier_ComplexHarness class HTMLPurifier_GeneratorTest extends HTMLPurifier_Harness
{ {
protected $gen; /**
protected $_entity_lookup; * Entity lookup table to help for a few tests.
protected $config; */
private $_entity_lookup;
public function __construct() { public function __construct() {
parent::__construct(); parent::__construct();
$this->gen = new HTMLPurifier_Generator();
$this->_entity_lookup = HTMLPurifier_EntityLookup::instance(); $this->_entity_lookup = HTMLPurifier_EntityLookup::instance();
} }
public function setUp() { public function setUp() {
$this->obj = new HTMLPurifier_Generator(); parent::setUp();
$this->func = null; $this->config->set('Output', 'Newline', "\n");
$this->to_tokens = false;
$this->to_html = false;
} }
function test_generateFromToken() { /**
* Creates a generator based on config and context member variables.
$inputs = $expect = array(); */
protected function createGenerator() {
$inputs[0] = new HTMLPurifier_Token_Text('Foobar.<>'); return new HTMLPurifier_Generator($this->config, $this->context);
$expect[0] = 'Foobar.&lt;&gt;';
$inputs[1] = new HTMLPurifier_Token_Start('a',
array('href' => 'dyn?a=foo&b=bar')
);
$expect[1] = '<a href="dyn?a=foo&amp;b=bar">';
$inputs[2] = new HTMLPurifier_Token_End('b');
$expect[2] = '</b>';
$inputs[3] = new HTMLPurifier_Token_Empty('br',
array('style' => 'font-family:"Courier New";')
);
$expect[3] = '<br style="font-family:&quot;Courier New&quot;;" />';
$inputs[4] = new HTMLPurifier_Token_Start('asdf');
$expect[4] = '<asdf>';
$inputs[5] = new HTMLPurifier_Token_Empty('br');
$expect[5] = '<br />';
// test fault tolerance
$inputs[6] = null;
$expect[6] = '';
// don't convert non-special characters
$theta_char = $this->_entity_lookup->table['theta'];
$inputs[7] = new HTMLPurifier_Token_Text($theta_char);
$expect[7] = $theta_char;
foreach ($inputs as $i => $input) {
$result = $this->obj->generateFromToken($input);
$this->assertIdentical($result, $expect[$i]);
}
} }
function test_generateAttributes() { protected function assertGenerateFromToken($token, $html) {
$generator = $this->createGenerator();
$inputs = $expect = array(); $result = $generator->generateFromToken($token);
$this->assertIdentical($result, $html);
$inputs[0] = array();
$expect[0] = '';
$inputs[1] = array('href' => 'dyn?a=foo&b=bar');
$expect[1] = 'href="dyn?a=foo&amp;b=bar"';
$inputs[2] = array('style' => 'font-family:"Courier New";');
$expect[2] = 'style="font-family:&quot;Courier New&quot;;"';
$inputs[3] = array('src' => 'picture.jpg', 'alt' => 'Short & interesting');
$expect[3] = 'src="picture.jpg" alt="Short &amp; interesting"';
// don't escape nonspecial characters
$theta_char = $this->_entity_lookup->table['theta'];
$inputs[4] = array('title' => 'Theta is ' . $theta_char);
$expect[4] = 'title="Theta is ' . $theta_char . '"';
foreach ($inputs as $i => $input) {
$result = $this->obj->generateAttributes($input, 'irrelevant');
$this->assertIdentical($result, $expect[$i]);
}
} }
function test_generateFromToken_text() {
$this->assertGenerateFromToken(
new HTMLPurifier_Token_Text('Foobar.<>'),
'Foobar.&lt;&gt;'
);
}
function test_generateFromToken_startWithAttr() {
$this->assertGenerateFromToken(
new HTMLPurifier_Token_Start('a',
array('href' => 'dyn?a=foo&b=bar')
),
'<a href="dyn?a=foo&amp;b=bar">'
);
}
function test_generateFromToken_end() {
$this->assertGenerateFromToken(
new HTMLPurifier_Token_End('b'),
'</b>'
);
}
function test_generateFromToken_emptyWithAttr() {
$this->assertGenerateFromToken(
new HTMLPurifier_Token_Empty('br',
array('style' => 'font-family:"Courier New";')
),
'<br style="font-family:&quot;Courier New&quot;;" />'
);
}
function test_generateFromToken_startNoAttr() {
$this->assertGenerateFromToken(
new HTMLPurifier_Token_Start('asdf'),
'<asdf>'
);
}
function test_generateFromToken_emptyNoAttr() {
$this->assertGenerateFromToken(
new HTMLPurifier_Token_Empty('br'),
'<br />'
);
}
function test_generateFromToken_error() {
$this->expectError('Cannot generate HTML from non-HTMLPurifier_Token object');
$this->assertGenerateFromToken( null, '' );
}
function test_generateFromToken_() {
$theta_char = $this->_entity_lookup->table['theta'];
$this->assertGenerateFromToken(
new HTMLPurifier_Token_Text($theta_char),
$theta_char
);
}
function assertGenerateAttributes($attr, $expect, $element = false) {
$generator = $this->createGenerator();
$result = $generator->generateAttributes($attr, $element);
$this->assertIdentical($result, $expect);
}
function test_generateAttributes_blank() {
$this->assertGenerateAttributes(array(), '');
}
function test_generateAttributes_basic() {
$this->assertGenerateAttributes(
array('href' => 'dyn?a=foo&b=bar'),
'href="dyn?a=foo&amp;b=bar"'
);
}
function test_generateAttributes_doubleQuote() {
$this->assertGenerateAttributes(
array('style' => 'font-family:"Courier New";'),
'style="font-family:&quot;Courier New&quot;;"'
);
}
function test_generateAttributes_singleQuote() {
$this->assertGenerateAttributes(
array('style' => 'font-family:\'Courier New\';'),
'style="font-family:\'Courier New\';"'
);
}
function test_generateAttributes_multiple() {
$this->assertGenerateAttributes(
array('src' => 'picture.jpg', 'alt' => 'Short & interesting'),
'src="picture.jpg" alt="Short &amp; interesting"'
);
}
function test_generateAttributes_specialChar() {
$theta_char = $this->_entity_lookup->table['theta'];
$this->assertGenerateAttributes(
array('title' => 'Theta is ' . $theta_char),
'title="Theta is ' . $theta_char . '"'
);
}
function test_generateAttributes_minimized() { function test_generateAttributes_minimized() {
$gen = new HTMLPurifier_Generator(); $this->config->set('HTML', 'Doctype', 'HTML 4.01 Transitional');
$context = new HTMLPurifier_Context(); $this->assertGenerateAttributes(
$gen->generateFromTokens(array(), HTMLPurifier_Config::create(array('HTML.Doctype' => 'HTML 4.01 Transitional')), $context); array('compact' => 'compact'), 'compact', 'menu'
$result = $gen->generateAttributes(array('compact' => 'compact'), 'menu'); );
$this->assertIdentical($result, 'compact');
} }
function test_generateFromTokens() { function test_generateFromTokens() {
$this->func = 'generateFromTokens'; $this->assertGeneration(
$this->assertResult(
array( array(
new HTMLPurifier_Token_Start('b'), new HTMLPurifier_Token_Start('b'),
new HTMLPurifier_Token_Text('Foobar!'), new HTMLPurifier_Token_Text('Foobar!'),
@ -111,23 +155,15 @@ class HTMLPurifier_GeneratorTest extends HTMLPurifier_ComplexHarness
'<b>Foobar!</b>' '<b>Foobar!</b>'
); );
$this->assertResult(array(), '');
} }
protected function assertGeneration($tokens, $expect) { protected function assertGeneration($tokens, $expect) {
$context = new HTMLPurifier_Context(); $generator = new HTMLPurifier_Generator($this->config, $this->context);
$result = $this->gen->generateFromTokens( $result = $generator->generateFromTokens($tokens);
$tokens, $this->config, $context);
// normalized newlines, this probably should be put somewhere else
$result = str_replace("\r\n", "\n", $result);
$result = str_replace("\r", "\n", $result);
$this->assertIdentical($expect, $result); $this->assertIdentical($expect, $result);
} }
function test_generateFromTokens_Scripting() { function test_generateFromTokens_Scripting() {
$this->config = HTMLPurifier_Config::createDefault();
$this->assertGeneration( $this->assertGeneration(
array( array(
new HTMLPurifier_Token_Start('script'), new HTMLPurifier_Token_Start('script'),
@ -136,8 +172,9 @@ class HTMLPurifier_GeneratorTest extends HTMLPurifier_ComplexHarness
), ),
"<script><!--//--><![CDATA[//><!--\nalert(3 < 5);\n//--><!]]></script>" "<script><!--//--><![CDATA[//><!--\nalert(3 < 5);\n//--><!]]></script>"
); );
}
// if missing close tag, don't do anything
function test_generateFromTokens_Scripting_missingCloseTag() {
$this->assertGeneration( $this->assertGeneration(
array( array(
new HTMLPurifier_Token_Start('script'), new HTMLPurifier_Token_Start('script'),
@ -145,8 +182,9 @@ class HTMLPurifier_GeneratorTest extends HTMLPurifier_ComplexHarness
), ),
"<script>alert(3 &lt; 5);" "<script>alert(3 &lt; 5);"
); );
}
// if two script blocks, don't do anything
function test_generateFromTokens_Scripting_doubleBlock() {
$this->assertGeneration( $this->assertGeneration(
array( array(
new HTMLPurifier_Token_Start('script'), new HTMLPurifier_Token_Start('script'),
@ -156,12 +194,10 @@ class HTMLPurifier_GeneratorTest extends HTMLPurifier_ComplexHarness
), ),
"<script>alert(3 &lt; 5);foo();</script>" "<script>alert(3 &lt; 5);foo();</script>"
); );
}
function test_generateFromTokens_Scripting_disableWrapper() {
$this->config = HTMLPurifier_Config::createDefault();
$this->config->set('Output', 'CommentScriptContents', false); $this->config->set('Output', 'CommentScriptContents', false);
$this->assertGeneration( $this->assertGeneration(
array( array(
new HTMLPurifier_Token_Start('script'), new HTMLPurifier_Token_Start('script'),