mirror of
https://github.com/ezyang/htmlpurifier.git
synced 2025-07-12 10:16:18 +02:00
Release 2.1.0, merged in 1313 to HEAD.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/branches/strict@1352 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
2
Doxyfile
2
Doxyfile
@ -4,7 +4,7 @@
|
|||||||
# Project related configuration options
|
# Project related configuration options
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
PROJECT_NAME = HTML Purifier
|
PROJECT_NAME = HTML Purifier
|
||||||
PROJECT_NUMBER = 2.0.1
|
PROJECT_NUMBER = 2.1.0
|
||||||
OUTPUT_DIRECTORY = "C:/Documents and Settings/Edward/My Documents/My Webs/htmlpurifier/docs/doxygen"
|
OUTPUT_DIRECTORY = "C:/Documents and Settings/Edward/My Documents/My Webs/htmlpurifier/docs/doxygen"
|
||||||
CREATE_SUBDIRS = NO
|
CREATE_SUBDIRS = NO
|
||||||
OUTPUT_LANGUAGE = English
|
OUTPUT_LANGUAGE = English
|
||||||
|
20
WHATSNEW
20
WHATSNEW
@ -1,12 +1,8 @@
|
|||||||
The 2.0.1 release introduces a number of stability and usability fixes,
|
In version 2.1, HTML Purifier's URI validation and filtering handling
|
||||||
as well as a number of (disabled by default) experimental features. The
|
system has been revamped with a new, extensible URIFilter system. Also
|
||||||
security-minded should note that a reflected XSS vulnerability was patched
|
notable features include preservation of emoticons in PHP5 with
|
||||||
in smoketests/configForm.php; if you cannot upgrade immediately, please
|
%Core.AggressivelyFixLt, standalone and lite download versions,
|
||||||
delete that file (if that directory is not publically accessible, there
|
transforming relative URIs to absolute URIs, Ruby in XHTML 1.1, a Phorum
|
||||||
is no security risk). The maintenance changes include more helpful file
|
mod, and UTF-8 font names. Notable bug-fixes include refinement of
|
||||||
permissions errors, internal newline normalization, reordered includes
|
the auto-paragraphing algorithm (no longer experimental), better XHTML
|
||||||
to prevent a missing class definition in some setups, and better cache
|
1.1 support and the removal of the contents of <style> elements.
|
||||||
revision and id handling. The two experimental features are auto-formatting
|
|
||||||
(auto-paragraphing and linkification) and error collection, these can
|
|
||||||
be enabled with %AutoFormat.AutoParagraph, %AutoFormat.Linkify and
|
|
||||||
%Core.CollectErrors respectively.
|
|
||||||
|
@ -18,6 +18,8 @@ TODO:
|
|||||||
if (version_compare('5', PHP_VERSION, '>')) exit('Requires PHP 5 or higher.');
|
if (version_compare('5', PHP_VERSION, '>')) exit('Requires PHP 5 or higher.');
|
||||||
error_reporting(E_ALL); // probably not possible to use E_STRICT
|
error_reporting(E_ALL); // probably not possible to use E_STRICT
|
||||||
|
|
||||||
|
define('HTMLPURIFIER_SCHEMA_STRICT', true); // description data needs to be collected
|
||||||
|
|
||||||
// load dual-libraries
|
// load dual-libraries
|
||||||
require_once '../library/HTMLPurifier.auto.php';
|
require_once '../library/HTMLPurifier.auto.php';
|
||||||
require_once 'library/ConfigDoc.auto.php';
|
require_once 'library/ConfigDoc.auto.php';
|
||||||
|
@ -11,8 +11,7 @@ docs/examples/demo.php - ad hoc HTML/PHP soup to the extreme
|
|||||||
|
|
||||||
AttrDef - a lot of duplication, more generic classes need to be created;
|
AttrDef - a lot of duplication, more generic classes need to be created;
|
||||||
a lot of strtolower() calls, no legit casing
|
a lot of strtolower() calls, no legit casing
|
||||||
Class - doesn't support Unicode characters (fringe); uses regular
|
Class - doesn't support Unicode characters (fringe); uses regular expressions
|
||||||
expressions
|
|
||||||
Lang - code duplication; premature optimization
|
Lang - code duplication; premature optimization
|
||||||
Length - easily mistaken for CSSLength
|
Length - easily mistaken for CSSLength
|
||||||
URI - multiple regular expressions; missing validation for parts (?)
|
URI - multiple regular expressions; missing validation for parts (?)
|
||||||
@ -22,9 +21,6 @@ ConfigSchema - redefinition is a mess
|
|||||||
Strategy
|
Strategy
|
||||||
FixNesting - cannot bubble nodes out of structures, duplicated checks
|
FixNesting - cannot bubble nodes out of structures, duplicated checks
|
||||||
for special-case parent node
|
for special-case parent node
|
||||||
MakeWellFormed - insufficient automatic closing definitions (check HTML
|
|
||||||
spec for optional end tags, also, closing based on type (block/inline)
|
|
||||||
might be efficient).
|
|
||||||
RemoveForeignElements - should be run in parallel with MakeWellFormed
|
RemoveForeignElements - should be run in parallel with MakeWellFormed
|
||||||
URIScheme - needs to have callable generic checks
|
URIScheme - needs to have callable generic checks
|
||||||
mailto - doesn't validate emails, doesn't validate querystring
|
mailto - doesn't validate emails, doesn't validate querystring
|
||||||
|
@ -10,9 +10,7 @@ to be effective. Things to remember:
|
|||||||
|
|
||||||
2. IDs: see enduser-id.html for more info
|
2. IDs: see enduser-id.html for more info
|
||||||
|
|
||||||
3. Links: document pending feature completion
|
3. URIs: see enduser-uri-filter.html
|
||||||
Rudimentary blacklisting, we should also allow only relative URIs. We
|
|
||||||
need a doc to explain the stuff.
|
|
||||||
|
|
||||||
4. CSS: document pending
|
4. CSS: document pending
|
||||||
Explain which CSS styles we blocked and why.
|
Explain which CSS styles we blocked and why.
|
||||||
|
201
docs/enduser-uri-filter.html
Normal file
201
docs/enduser-uri-filter.html
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<meta name="description" content="Tutorial for creating custom URI filters." />
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||||
|
|
||||||
|
<title>URI Filters - HTML Purifier</title>
|
||||||
|
|
||||||
|
</head><body>
|
||||||
|
|
||||||
|
<h1>URI Filters</h1>
|
||||||
|
|
||||||
|
<div id="filing">Filed under End-User</div>
|
||||||
|
<div id="index">Return to the <a href="index.html">index</a>.</div>
|
||||||
|
<div id="home"><a href="http://htmlpurifier.org/">HTML Purifier</a> End-User Documentation</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This is a quick and dirty document to get you on your way to writing
|
||||||
|
custom URI filters for your own URL filtering needs. Why would you
|
||||||
|
want to write a URI filter? If you need URIs your users put into
|
||||||
|
HTML to magically change into a different URI, this is
|
||||||
|
exactly what you need!
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Creating the class</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Any URI filter you make will be a subclass of <code>HTMLPurifier_URIFilter</code>.
|
||||||
|
The scaffolding is thus:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>class HTMLPurifier_URIFilter_<strong>NameOfFilter</strong> extends HTMLPurifier_URIFilter
|
||||||
|
{
|
||||||
|
var $name = '<strong>NameOfFilter</strong>';
|
||||||
|
function prepare($config) {}
|
||||||
|
function filter(&$uri, $config, &$context) {}
|
||||||
|
}</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Fill in the variable <code>$name</code> with the name of your filter, and
|
||||||
|
take a look at the two methods. <code>prepare()</code> is an initialization
|
||||||
|
method that is called only once, before any filtering has been done of the
|
||||||
|
HTML. Use it to perform any costly setup work that only needs to be done
|
||||||
|
once. <code>filter()</code> is the guts and innards of our filter:
|
||||||
|
it takes the URI and does whatever needs to be done to it.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you've worked with HTML Purifier, you'll recognize the <code>$config</code>
|
||||||
|
and <code>$context</code> parameters. On the other hand, <code>$uri</code>
|
||||||
|
is something unique to this section of the application: it's a
|
||||||
|
<code>HTMLPurifier_URI</code> object. The interface is thus:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>class HTMLPurifier_URI
|
||||||
|
{
|
||||||
|
var $scheme, $userinfo, $host, $port, $path, $query, $fragment;
|
||||||
|
function HTMLPurifier_URI($scheme, $userinfo, $host, $port, $path, $query, $fragment);
|
||||||
|
function toString();
|
||||||
|
function copy();
|
||||||
|
function getSchemeObj($config, &$context);
|
||||||
|
function validate($config, &$context);
|
||||||
|
}</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The first three methods are fairly self-explanatory: you have a constructor,
|
||||||
|
a serializer, and a cloner. Generally, you won't be using them when
|
||||||
|
you are manipulating the URI objects themselves.
|
||||||
|
<code>getSchemeObj()</code> is a special purpose method that returns
|
||||||
|
a <code>HTMLPurifier_URIScheme</code> object corresponding to the specific
|
||||||
|
URI at hand. <code>validate()</code> performs general-purpose validation
|
||||||
|
on the internal components of a URI. Once again, you don't need to
|
||||||
|
worry about these: they've already been handled for you.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>URI format</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
As a URIFilter, we're interested in the member variables of the URI object.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table class="quick"><tbody>
|
||||||
|
<tr><th>Scheme</th> <td>The protocol for identifying (and possibly locating) a resource (http, ftp, https)</td></tr>
|
||||||
|
<tr><th>Userinfo</th> <td>User information such as a username (bob)</td></tr>
|
||||||
|
<tr><th>Host</th> <td>Domain name or IP address of the server (example.com, 127.0.0.1)</td></tr>
|
||||||
|
<tr><th>Port</th> <td>Network port number for the server (80, 12345)</td></tr>
|
||||||
|
<tr><th>Path</th> <td>Data that identifies the resource, possibly hierarchical (/path/to, ed@example.com)</td></tr>
|
||||||
|
<tr><th>Query</th> <td>String of information to be interpreted by the resource (?q=search-term)</td></tr>
|
||||||
|
<tr><th>Fragment</th> <td>Additional information for the resource after retrieval (#bookmark)</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Because the URI is presented to us in this form, and not
|
||||||
|
<code>http://bob@example.com:8080/foo.php?q=string#hash</code>, it saves us
|
||||||
|
a lot of trouble in having to parse the URI every time we want to filter
|
||||||
|
it. For the record, the above URI has the following components:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table class="quick"><tbody>
|
||||||
|
<tr><th>Scheme</th> <td>http</td></tr>
|
||||||
|
<tr><th>Userinfo</th> <td>bob</td></tr>
|
||||||
|
<tr><th>Host</th> <td>example.com</td></tr>
|
||||||
|
<tr><th>Port</th> <td>8080</td></tr>
|
||||||
|
<tr><th>Path</th> <td>/foo.php</td></tr>
|
||||||
|
<tr><th>Query</th> <td>q=string</td></tr>
|
||||||
|
<tr><th>Fragment</th> <td>hash</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Note that there is no question mark or octothorpe in the query or
|
||||||
|
fragment: these get removed during parsing.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
With this information, you can get straight to implementing your
|
||||||
|
<code>filter()</code> method. But one more thing...
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Return value: Boolean, not URI</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You may have noticed that the URI is being passed in by reference.
|
||||||
|
This means that whatever changes you make to it, those changes will
|
||||||
|
be reflected in the URI object the callee had. <strong>Do not
|
||||||
|
return the URI object: it is unnecessary and will cause bugs.</strong>
|
||||||
|
Instead, return a boolean value, true if the filtering was successful,
|
||||||
|
or false if the URI is beyond repair and needs to be axed.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Let's suppose I wanted to write a filter that de-internationalized domain
|
||||||
|
names by converting them to <a href="http://en.wikipedia.org/wiki/Punycode">Punycode</a>.
|
||||||
|
Assuming that <code>punycode_encode($input)</code> converts <code>$input</code> to
|
||||||
|
Punycode and returns <code>false</code> on failure:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>class HTMLPurifier_URIFilter_ConvertIDNToPunycode extends HTMLPurifier_URIFilter
|
||||||
|
{
|
||||||
|
var $name = 'ConvertIDNToPunycode';
|
||||||
|
function filter(&$uri, $config, &$context) {
|
||||||
|
if (is_null($uri->host)) return true;
|
||||||
|
if ($uri->host == utf8_decode($uri->host)) {
|
||||||
|
// is ASCII, abort
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$host = punycode_encode($uri->host);
|
||||||
|
if ($host === false) return false;
|
||||||
|
$uri->host = $host;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Notice I did not <code>return $uri;</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Activating your filter</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Having a filter is all well and good, but you need to tell HTML Purifier
|
||||||
|
to use it. Fortunately, this part's simple:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>$uri =& $config->getDefinition('URI');
|
||||||
|
$uri->addFilter(new HTMLPurifier_URIFilter_<strong>NameOfFilter</strong>());</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you want to be really fancy, you can define a configuration directive
|
||||||
|
for your filter and have HTML Purifier automatically manage whether or
|
||||||
|
not your filter gets loaded or not (this is how internal filters manage
|
||||||
|
things):
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>HTMLPurifier_ConfigSchema::define(
|
||||||
|
'URI', '<strong>NameOfFilter</strong>', false, 'bool',
|
||||||
|
'<strong>What your filter does.</strong>'
|
||||||
|
);
|
||||||
|
$uri =& $config->getDefinition('URI', true);
|
||||||
|
$uri->registerFilter(new HTMLPurifier_URIFilter_<strong>NameOfFilter</strong>());
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Now, your filter will only be called when %URI.<strong>NameOfFilter</strong>
|
||||||
|
is set to true.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Examples</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Check the
|
||||||
|
<a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/library/HTMLPurifier/URIFilter/">URIFilter</a>
|
||||||
|
directory for more implementation examples, and see <a href="http://htmlpurifier.org/svnroot/htmlpurifier/trunk/docs/proposal-new-directives.txt">the
|
||||||
|
new directives proposal document</a> for ideas on what could be implemented
|
||||||
|
as a filter.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div id="version">$Id$</div>
|
||||||
|
|
||||||
|
</body></html>
|
@ -40,6 +40,9 @@ information for casual developers using HTML Purifier.</p>
|
|||||||
<dt><a href="enduser-customize.html">Customize</a></dt>
|
<dt><a href="enduser-customize.html">Customize</a></dt>
|
||||||
<dd>Tutorial for customizing HTML Purifier's tag and attribute sets.</dd>
|
<dd>Tutorial for customizing HTML Purifier's tag and attribute sets.</dd>
|
||||||
|
|
||||||
|
<dt><a href="enduser-uri-filter.html">URI Filters</a></dt>
|
||||||
|
<dd>Tutorial for creating custom URI filters.</dd>
|
||||||
|
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<h2>Development</h2>
|
<h2>Development</h2>
|
||||||
|
@ -32,7 +32,7 @@ Here are some fuzzy levels you could set:
|
|||||||
|
|
||||||
One final note: when you start axing tags that are more commonly used, you
|
One final note: when you start axing tags that are more commonly used, you
|
||||||
run the risk of accidentally destroying user data, especially if the data
|
run the risk of accidentally destroying user data, especially if the data
|
||||||
is incoming from a WYSIWYG eidtor that hasn't been synced accordingly. This may
|
is incoming from a WYSIWYG editor that hasn't been synced accordingly. This may
|
||||||
make forbidden element to text transformations desirable (for example, images).
|
make forbidden element to text transformations desirable (for example, images).
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
Configuration Ideas
|
Configuration Ideas
|
||||||
|
|
||||||
Here are some theoretical configuration ideas that we could implement some
|
Here are some theoretical configuration ideas that we could implement some
|
||||||
time. Note the naming convention: %Namespace.Directive
|
time. Note the naming convention: %Namespace.Directive. If you want one
|
||||||
|
implemented, give us a ring, and we'll move it up the priority chain.
|
||||||
|
|
||||||
%Attr.RewriteFragments - if there's %Attr.IDPrefix we may want to transparently
|
%Attr.RewriteFragments - if there's %Attr.IDPrefix we may want to transparently
|
||||||
rewrite the URLs we parse too. However, we can only do it when it's a pure
|
rewrite the URLs we parse too. However, we can only do it when it's a pure
|
||||||
@ -22,8 +23,6 @@ time. Note the naming convention: %Namespace.Directive
|
|||||||
%URI.AddRelNofollow - will add rel="nofollow" to all links, preventing the
|
%URI.AddRelNofollow - will add rel="nofollow" to all links, preventing the
|
||||||
spread of ill-gotten pagerank
|
spread of ill-gotten pagerank
|
||||||
|
|
||||||
%URI.RelativeToAbsolute - transforms all relative URIs to absolute form
|
|
||||||
|
|
||||||
%URI.HostBlacklistRegex - regexes that if matching the host are disallowed
|
%URI.HostBlacklistRegex - regexes that if matching the host are disallowed
|
||||||
%URI.HostWhitelist - domain names that are excluded from the host blacklist
|
%URI.HostWhitelist - domain names that are excluded from the host blacklist
|
||||||
%URI.HostPolicy - determines whether or not its reject all and then whitelist
|
%URI.HostPolicy - determines whether or not its reject all and then whitelist
|
||||||
|
@ -33,6 +33,9 @@ blockquote .label {font-weight:bold; font-size:1em; margin:0 0 .1em;
|
|||||||
.table thead th:first-child {-moz-border-radius-topleft:1em;}
|
.table thead th:first-child {-moz-border-radius-topleft:1em;}
|
||||||
.table tbody td {border-bottom:1px solid #CCC; padding-right:0.6em;padding-left:0.6em;}
|
.table tbody td {border-bottom:1px solid #CCC; padding-right:0.6em;padding-left:0.6em;}
|
||||||
|
|
||||||
|
/* A quick table*/
|
||||||
|
table.quick tbody th {text-align:right; padding-right:1em;}
|
||||||
|
|
||||||
/* Category of the file */
|
/* Category of the file */
|
||||||
#filing {font-weight:bold; font-size:smaller; }
|
#filing {font-weight:bold; font-size:smaller; }
|
||||||
|
|
||||||
|
9
maintenance/common.php
Normal file
9
maintenance/common.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
function assertCli() {
|
||||||
|
if (php_sapi_name() != 'cli' && !getenv('PHP_IS_CLI')) {
|
||||||
|
echo 'Script cannot be called from web-browser (if you are calling via cli,
|
||||||
|
set environment variable PHP_IS_CLI to work around this).';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
36
maintenance/flush-definition-cache.php
Executable file
36
maintenance/flush-definition-cache.php
Executable file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'common.php';
|
||||||
|
assertCli();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes the default HTMLDefinition serial cache
|
||||||
|
* @param Accepts one argument, cache type to flush; otherwise flushes all
|
||||||
|
* the caches.
|
||||||
|
*/
|
||||||
|
|
||||||
|
echo "Flushing cache... \n";
|
||||||
|
|
||||||
|
require_once(dirname(__FILE__) . '/../library/HTMLPurifier.auto.php');
|
||||||
|
|
||||||
|
$config = HTMLPurifier_Config::createDefault();
|
||||||
|
|
||||||
|
$names = array('HTML', 'CSS', 'URI', 'Test');
|
||||||
|
if (isset($argv[1])) {
|
||||||
|
if (in_array($argv[1], $names)) {
|
||||||
|
$names = array($argv[1]);
|
||||||
|
} else {
|
||||||
|
echo "Did not recognized cache parameter {$argv[1]} as valid cache, aborting.\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($names as $name) {
|
||||||
|
echo " - Flushing $name\n";
|
||||||
|
$cache = new HTMLPurifier_DefinitionCache_Serializer($name);
|
||||||
|
$cache->flush($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo 'Cache flushed successfully.';
|
||||||
|
|
@ -1,23 +0,0 @@
|
|||||||
#!/usr/bin/php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flushes the default HTMLDefinition serial cache
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (php_sapi_name() != 'cli') {
|
|
||||||
echo 'Script cannot be called from web-browser.';
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo 'Flushing cache... ';
|
|
||||||
|
|
||||||
require_once(dirname(__FILE__) . '/../library/HTMLPurifier.auto.php');
|
|
||||||
|
|
||||||
$config = HTMLPurifier_Config::createDefault();
|
|
||||||
|
|
||||||
$cache = new HTMLPurifier_DefinitionCache_Serializer('HTML');
|
|
||||||
$cache->flush($config);
|
|
||||||
|
|
||||||
echo 'Cache flushed successfully.';
|
|
||||||
|
|
8
maintenance/generate-entity-file.php
Normal file → Executable file
8
maintenance/generate-entity-file.php
Normal file → Executable file
@ -1,16 +1,14 @@
|
|||||||
#!/usr/bin/php
|
#!/usr/bin/php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
require_once 'common.php';
|
||||||
|
assertCli();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses *.ent files into an entity lookup table, and then serializes and
|
* Parses *.ent files into an entity lookup table, and then serializes and
|
||||||
* writes the whole kaboodle to a file. The resulting file should be versioned.
|
* writes the whole kaboodle to a file. The resulting file should be versioned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (php_sapi_name() != 'cli') {
|
|
||||||
echo 'Script cannot be called from web-browser.';
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
chdir( dirname(__FILE__) );
|
chdir( dirname(__FILE__) );
|
||||||
|
|
||||||
// here's where the entity files are located, assuming working directory
|
// here's where the entity files are located, assuming working directory
|
||||||
|
198
maintenance/merge-library.php
Executable file
198
maintenance/merge-library.php
Executable file
@ -0,0 +1,198 @@
|
|||||||
|
#!/usr/bin/php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'common.php';
|
||||||
|
assertCli();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles all of HTML Purifier's library files into one big file
|
||||||
|
* named HTMLPurifier.standalone.php. Operates recursively, and will
|
||||||
|
* barf if there are conditional includes.
|
||||||
|
*
|
||||||
|
* Details: also creates blank "include" files in the test/blank directory
|
||||||
|
* in order to simulate require_once's inside the test files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global array that tracks already loaded includes
|
||||||
|
*/
|
||||||
|
$GLOBALS['loaded'] = array('HTMLPurifier.php' => true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $text Text to replace includes from
|
||||||
|
*/
|
||||||
|
function replace_includes($text) {
|
||||||
|
return preg_replace_callback(
|
||||||
|
"/require_once ['\"]([^'\"]+)['\"];/",
|
||||||
|
'replace_includes_callback',
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes leading PHP tags from included files. Assumes that there is
|
||||||
|
* no trailing tag.
|
||||||
|
*/
|
||||||
|
function remove_php_tags($text) {
|
||||||
|
return substr($text, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an appropriate blank file, recursively generating directories
|
||||||
|
* if necessary
|
||||||
|
*/
|
||||||
|
function create_blank($file) {
|
||||||
|
$dir = dirname($file);
|
||||||
|
$base = realpath('../tests/blanks/') . DIRECTORY_SEPARATOR ;
|
||||||
|
if ($dir != '.') mkdir_deep($base . $dir);
|
||||||
|
file_put_contents($base . $file, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively creates a directory
|
||||||
|
* @note Adapted from the PHP manual comment 76612
|
||||||
|
*/
|
||||||
|
function mkdir_deep($folder) {
|
||||||
|
$folders = preg_split("#[\\\\/]#", $folder);
|
||||||
|
$base = '';
|
||||||
|
for($i = 0, $c = count($folders); $i < $c; $i++) {
|
||||||
|
if(empty($folders[$i])) {
|
||||||
|
if (!$i) {
|
||||||
|
// special case for root level
|
||||||
|
$base .= DIRECTORY_SEPARATOR;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$base .= $folders[$i];
|
||||||
|
if(!is_dir($base)){
|
||||||
|
mkdir($base);
|
||||||
|
}
|
||||||
|
$base .= DIRECTORY_SEPARATOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy a file, or recursively copy a folder and its contents
|
||||||
|
*
|
||||||
|
* @author Aidan Lister <aidan@php.net>
|
||||||
|
* @version 1.0.1
|
||||||
|
* @link http://aidanlister.com/repos/v/function.copyr.php
|
||||||
|
* @param string $source Source path
|
||||||
|
* @param string $dest Destination path
|
||||||
|
* @return bool Returns TRUE on success, FALSE on failure
|
||||||
|
*/
|
||||||
|
function copyr($source, $dest) {
|
||||||
|
// Simple copy for a file
|
||||||
|
if (is_file($source)) {
|
||||||
|
return copy($source, $dest);
|
||||||
|
}
|
||||||
|
// Make destination directory
|
||||||
|
if (!is_dir($dest)) {
|
||||||
|
mkdir($dest);
|
||||||
|
}
|
||||||
|
// Loop through the folder
|
||||||
|
$dir = dir($source);
|
||||||
|
while (false !== $entry = $dir->read()) {
|
||||||
|
// Skip pointers
|
||||||
|
if ($entry == '.' || $entry == '..') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Skip hidden files
|
||||||
|
if ($entry[0] == '.') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Deep copy directories
|
||||||
|
if ($dest !== "$source/$entry") {
|
||||||
|
copyr("$source/$entry", "$dest/$entry");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Clean up
|
||||||
|
$dir->close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a file, or a folder and its contents
|
||||||
|
*
|
||||||
|
* @author Aidan Lister <aidan@php.net>
|
||||||
|
* @version 1.0.3
|
||||||
|
* @link http://aidanlister.com/repos/v/function.rmdirr.php
|
||||||
|
* @param string $dirname Directory to delete
|
||||||
|
* @return bool Returns TRUE on success, FALSE on failure
|
||||||
|
*/
|
||||||
|
function rmdirr($dirname)
|
||||||
|
{
|
||||||
|
// Sanity check
|
||||||
|
if (!file_exists($dirname)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple delete for a file
|
||||||
|
if (is_file($dirname) || is_link($dirname)) {
|
||||||
|
return unlink($dirname);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through the folder
|
||||||
|
$dir = dir($dirname);
|
||||||
|
while (false !== $entry = $dir->read()) {
|
||||||
|
// Skip pointers
|
||||||
|
if ($entry == '.' || $entry == '..') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recurse
|
||||||
|
rmdirr($dirname . DIRECTORY_SEPARATOR . $entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
$dir->close();
|
||||||
|
return rmdir($dirname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the contents of a directory to the standalone directory
|
||||||
|
*/
|
||||||
|
function make_dir_standalone($dir) {
|
||||||
|
return copyr($dir, 'standalone/' . $dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
function make_file_standalone($file) {
|
||||||
|
mkdir_deep('standalone/' . dirname($file));
|
||||||
|
return copy($file, 'standalone/' . $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $matches preg_replace_callback matches array, where index 1
|
||||||
|
* is the filename to include
|
||||||
|
*/
|
||||||
|
function replace_includes_callback($matches) {
|
||||||
|
$file = $matches[1];
|
||||||
|
if (isset($GLOBALS['loaded'][$file])) return '';
|
||||||
|
$GLOBALS['loaded'][$file] = true;
|
||||||
|
create_blank($file);
|
||||||
|
return replace_includes(remove_php_tags(file_get_contents($file)));
|
||||||
|
}
|
||||||
|
|
||||||
|
chdir(dirname(__FILE__) . '/../library/');
|
||||||
|
create_blank('HTMLPurifier.php');
|
||||||
|
|
||||||
|
echo 'Creating full file...';
|
||||||
|
$contents = replace_includes(file_get_contents('HTMLPurifier.php'));
|
||||||
|
$contents = str_replace(
|
||||||
|
"define('HTMLPURIFIER_PREFIX', dirname(__FILE__));",
|
||||||
|
"define('HTMLPURIFIER_PREFIX', dirname(__FILE__) . '/standalone');",
|
||||||
|
$contents
|
||||||
|
);
|
||||||
|
file_put_contents('HTMLPurifier.standalone.php', $contents);
|
||||||
|
echo ' done!' . PHP_EOL;
|
||||||
|
|
||||||
|
echo 'Creating standalone directory...';
|
||||||
|
rmdirr('standalone'); // ensure a clean copy
|
||||||
|
mkdir_deep('standalone/HTMLPurifier/DefinitionCache/Serializer');
|
||||||
|
make_dir_standalone('HTMLPurifier/EntityLookup');
|
||||||
|
make_dir_standalone('HTMLPurifier/Language');
|
||||||
|
make_file_standalone('HTMLPurifier/Printer/ConfigForm.js');
|
||||||
|
make_file_standalone('HTMLPurifier/Printer/ConfigForm.css');
|
||||||
|
make_dir_standalone('HTMLPurifier/URIScheme');
|
||||||
|
echo ' done!' . PHP_EOL;
|
||||||
|
|
@ -9,7 +9,7 @@ class HTMLPurifier_AttrCollectionsTest_NoConstructor extends HTMLPurifier_AttrCo
|
|||||||
function performInclusions(&$a) {}
|
function performInclusions(&$a) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HTMLPurifier_AttrCollectionsTest extends UnitTestCase
|
class HTMLPurifier_AttrCollectionsTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function testConstruction() {
|
function testConstruction() {
|
||||||
|
@ -16,6 +16,10 @@ class HTMLPurifier_AttrDef_CSS_FontFamilyTest extends HTMLPurifier_AttrDefHarnes
|
|||||||
$this->assertDef('01234');
|
$this->assertDef('01234');
|
||||||
$this->assertDef(',', false);
|
$this->assertDef(',', false);
|
||||||
$this->assertDef('Times New Roman, serif', '\'Times New Roman\', serif');
|
$this->assertDef('Times New Roman, serif', '\'Times New Roman\', serif');
|
||||||
|
$this->assertDef($d = "'John\\'s Font'");
|
||||||
|
$this->assertDef("John's Font", $d);
|
||||||
|
$this->assertDef($d = "'\xE5\xAE\x8B\xE4\xBD\x93'");
|
||||||
|
$this->assertDef("\xE5\xAE\x8B\xE4\xBD\x93", $d);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,317 +2,86 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/AttrDefHarness.php';
|
require_once 'HTMLPurifier/AttrDefHarness.php';
|
||||||
require_once 'HTMLPurifier/AttrDef/URI.php';
|
require_once 'HTMLPurifier/AttrDef/URI.php';
|
||||||
|
require_once 'HTMLPurifier/URIParser.php';
|
||||||
|
|
||||||
// WARNING: INCOMPLETE UNIT TESTS!
|
/**
|
||||||
// we also need to test all the configuration directives defined by this class
|
* @todo Aim for complete code coverage with mocks
|
||||||
|
*/
|
||||||
// http: is returned quite often when a URL is invalid. We have to change
|
|
||||||
// this behavior to just a plain old "FALSE"!
|
|
||||||
|
|
||||||
class HTMLPurifier_AttrDef_URITest extends HTMLPurifier_AttrDefHarness
|
class HTMLPurifier_AttrDef_URITest extends HTMLPurifier_AttrDefHarness
|
||||||
{
|
{
|
||||||
|
|
||||||
var $scheme, $components, $return_components;
|
function setUp() {
|
||||||
|
|
||||||
function testGenericURI() {
|
|
||||||
|
|
||||||
generate_mock_once('HTMLPurifier_URIScheme');
|
|
||||||
generate_mock_once('HTMLPurifier_URISchemeRegistry');
|
|
||||||
|
|
||||||
$old_registry = HTMLPurifier_URISchemeRegistry::instance();
|
|
||||||
|
|
||||||
// finally, lets get a copy of the actual class
|
|
||||||
$this->def = new HTMLPurifier_AttrDef_URI();
|
$this->def = new HTMLPurifier_AttrDef_URI();
|
||||||
|
parent::setUp();
|
||||||
// initialize test inputs
|
|
||||||
$uri = // input URI
|
|
||||||
$components = // what components the URI should be parsed to
|
|
||||||
$return_components = // return components
|
|
||||||
$expect_uri = array(); // what reassembled URI to expect
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// test a regular instance, return identical URI
|
|
||||||
$uri[0] = 'http://www.example.com/webhp?q=foo#result2';
|
|
||||||
$components[0] = array(
|
|
||||||
null, // userinfo
|
|
||||||
'www.example.com', // host
|
|
||||||
null, // port
|
|
||||||
'/webhp', // path
|
|
||||||
'q=foo' // query
|
|
||||||
);
|
|
||||||
|
|
||||||
// test an amended URI (the actual logic is irrelevant)
|
|
||||||
// test that user and port get parsed correctly (3.2.1 and 3.2.3)
|
|
||||||
$uri[1] = 'http://user@authority.part:80/now/the/path?query#fragment';
|
|
||||||
$components[1] = array(
|
|
||||||
'user', 'authority.part', 80,
|
|
||||||
'/now/the/path', 'query'
|
|
||||||
);
|
|
||||||
$return_components[1] = array( // removed port (it's standard)
|
|
||||||
'user', 'authority.part', null, '/now/the/path', 'query'
|
|
||||||
);
|
|
||||||
$expect_uri[1] = 'http://user@authority.part/now/the/path?query#fragment';
|
|
||||||
|
|
||||||
// percent encoded characters are not resolved during generic URI
|
|
||||||
// parsing even though RFC 3986 defines this notation
|
|
||||||
// also test what happens when query/fragment are missing
|
|
||||||
$uri[2] = 'http://en.wikipedia.org/wiki/Clich%C3%A9';
|
|
||||||
$components[2] = array(
|
|
||||||
null, 'en.wikipedia.org', null, '/wiki/Clich%C3%A9', null
|
|
||||||
);
|
|
||||||
|
|
||||||
// test distinction between empty query and undefined query (above)
|
|
||||||
$uri[3] = 'http://www.example.com/?#';
|
|
||||||
$components[3] = array(null, 'www.example.com', null, '/', '');
|
|
||||||
|
|
||||||
// path is always defined, even if empty
|
|
||||||
$uri[4] = 'http://www.example.com';
|
|
||||||
$components[4] = array(null, 'www.example.com', null, '', null);
|
|
||||||
|
|
||||||
// test parsing of an opaque URI
|
|
||||||
$uri[5] = 'mailto:bob@example.com';
|
|
||||||
$components[5] = array(null, null, null, 'bob@example.com', null);
|
|
||||||
|
|
||||||
// even though we don't resolve percent entities, we have to fix
|
|
||||||
// improper percent-encodes. Taken one at a time:
|
|
||||||
// %56 - V, which is an unreserved character
|
|
||||||
// %fc - u with an umlaut, normalize to uppercase
|
|
||||||
// %GJ - invalid characters in entity, encode %
|
|
||||||
// %5 - prematurely terminated, encode %
|
|
||||||
// %FC - u with umlaut, correct
|
|
||||||
// note that Apache doesn't do such fixing, rather, it just claims
|
|
||||||
// that the browser sent a "Bad Request". See PercentEncoder.php
|
|
||||||
// for more details
|
|
||||||
$uri[6] = 'http://www.example.com/%56%fc%GJ%5%FC';
|
|
||||||
$components[6] = array(null, 'www.example.com', null, '/V%FC%25GJ%255%FC', null);
|
|
||||||
$expect_uri[6] = 'http://www.example.com/V%FC%25GJ%255%FC';
|
|
||||||
|
|
||||||
// test IPv4 address (behavior may vary with configuration)
|
|
||||||
$uri[7] = 'http://192.0.34.166/';
|
|
||||||
$components[7] = array(null, '192.0.34.166', null, '/', null);
|
|
||||||
|
|
||||||
// while it may look like an IPv4 address, it's really a reg-name.
|
|
||||||
// don't destroy it
|
|
||||||
$uri[8] = 'http://333.123.32.123/';
|
|
||||||
$components[8] = array(null, '333.123.32.123', null, '/', null);
|
|
||||||
|
|
||||||
// test IPv6 address, using amended form of RFC's example
|
|
||||||
$uri[9] = 'http://[2001:db8::7]/c=GB?objectClass?one';
|
|
||||||
$components[9] = array(null, '[2001:db8::7]', null, '/c=GB',
|
|
||||||
'objectClass?one');
|
|
||||||
|
|
||||||
// We will not implement punycode encoding, that's up to the browsers
|
|
||||||
// We also will not implement percent to IDNA encoding transformations:
|
|
||||||
// if you need to use an international domain in a link, make sure that
|
|
||||||
// you've got it in UTF-8 and send it in raw (no encoding).
|
|
||||||
|
|
||||||
// break the RFC a little and allow international characters
|
|
||||||
// WARNING: UTF-8 encoded!
|
|
||||||
$uri[10] = 'http://tūdaliņ.lv';
|
|
||||||
$components[10] = array(null, 'tūdaliņ.lv', null, '', null);
|
|
||||||
|
|
||||||
// test invalid IPv6 address and invalid reg-name
|
|
||||||
$uri[11] = 'http://[2001:0db8:85z3:08d3:1319:8a2e:0370:7334]';
|
|
||||||
$components[11] = array(null, null, null, '', null);
|
|
||||||
$expect_uri[11] = 'http:';
|
|
||||||
|
|
||||||
// test invalid port
|
|
||||||
$uri[12] = 'http://example.com:foobar';
|
|
||||||
$components[12] = array(null, 'example.com', null, '', null);
|
|
||||||
$expect_uri[12] = 'http://example.com';
|
|
||||||
|
|
||||||
// test overlarge port (max is 65535, although this isn't official)
|
|
||||||
$uri[13] = 'http://example.com:65536';
|
|
||||||
$components[13] = array(null, 'example.com', null, '', null);
|
|
||||||
$expect_uri[13] = 'http://example.com';
|
|
||||||
|
|
||||||
// some spec abnf tests
|
|
||||||
|
|
||||||
// "authority . path-abempty" omitted, it is a trivial case
|
|
||||||
|
|
||||||
// "path-absolute", note this is different from path-rootless
|
|
||||||
$uri[14] = 'http:/this/is/path';
|
|
||||||
$components[14] = array(null, null, null, '/this/is/path', null);
|
|
||||||
$expect_uri[14] = 'http:/this/is/path'; // do not munge scheme off
|
|
||||||
|
|
||||||
// scheme munging is not being tested yet, it's an extra feature
|
|
||||||
|
|
||||||
// "path-rootless" - this should not be used but is allowed
|
|
||||||
$uri[15] = 'http:this/is/path';
|
|
||||||
$components[15] = array(null, null, null, 'this/is/path', null);
|
|
||||||
//$expect_uri[15] = 'this/is/path'; // munge scheme off
|
|
||||||
|
|
||||||
// "path-empty" - a rather interesting case, remove the scheme
|
|
||||||
$uri[16] = 'http:';
|
|
||||||
$components[16] = array(null, null, null, '', null);
|
|
||||||
//$expect_uri[16] = ''; // munge scheme off
|
|
||||||
|
|
||||||
// test invalid scheme, components shouldn't be passed
|
|
||||||
$uri[17] = 'javascript:alert("moo");';
|
|
||||||
$expect_uri[17] = false;
|
|
||||||
|
|
||||||
// relative URIs - basic case
|
|
||||||
$uri[18] = '/a/b';
|
|
||||||
$components[18] = array(null, null, null, '/a/b', null);
|
|
||||||
|
|
||||||
// result of malformed tag, gracefully handle error
|
|
||||||
$uri[19] = 'http://www.google.com/\'>"';
|
|
||||||
$components[19] = array(null, 'www.google.com', null, '/', null);
|
|
||||||
$expect_uri[19] = 'http://www.google.com/';
|
|
||||||
|
|
||||||
// test empty
|
|
||||||
$uri[20] = '';
|
|
||||||
$components[20] = array(null, null, null, '', null);
|
|
||||||
$expect_uri[20] = '';
|
|
||||||
|
|
||||||
foreach ($uri as $i => $value) {
|
|
||||||
|
|
||||||
// the read in values
|
|
||||||
$this->config = isset($config[$i]) ? $config[$i] : HTMLPurifier_Config::createDefault();
|
|
||||||
$this->context = isset($context[$i]) ? $context[$i] : new HTMLPurifier_Context();
|
|
||||||
|
|
||||||
// setUpAssertDef
|
|
||||||
if ( isset($components[$i]) ) {
|
|
||||||
$this->components = $components[$i];
|
|
||||||
} else {
|
|
||||||
$this->components = false;
|
|
||||||
}
|
|
||||||
if ( isset($return_components[$i]) ) {
|
|
||||||
$this->return_components = $return_components[$i];
|
|
||||||
} else {
|
|
||||||
$this->return_components = $this->components;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parameters
|
|
||||||
if (!isset($expect_uri[$i])) {
|
|
||||||
$expect_uri[$i] = $value; // untouched
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertDef($value, $expect_uri[$i], true, "Test $i: %s");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset to regular implementation
|
|
||||||
HTMLPurifier_URISchemeRegistry::instance($old_registry);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function setUpAssertDef() {
|
|
||||||
// $fake_registry isn't the real mock, because due to PHP 4 weirdness
|
|
||||||
// I cannot set a default value to function parameters that are passed
|
|
||||||
// by reference. So we use the value instance() returns.
|
|
||||||
$fake_registry = new HTMLPurifier_URISchemeRegistryMock();
|
|
||||||
$registry =& HTMLPurifier_URISchemeRegistry::instance($fake_registry);
|
|
||||||
|
|
||||||
// now, let's add a pseudo-scheme to the registry
|
|
||||||
$this->scheme = new HTMLPurifier_URISchemeMock();
|
|
||||||
|
|
||||||
// here are the schemes we will support with overloaded mocks
|
|
||||||
$registry->setReturnReference('getScheme', $this->scheme, array('http', '*', '*'));
|
|
||||||
$registry->setReturnReference('getScheme', $this->scheme, array('mailto', '*', '*'));
|
|
||||||
|
|
||||||
// default return value is false (meaning no scheme defined: reject)
|
|
||||||
$registry->setReturnValue('getScheme', false, array('*', '*', '*'));
|
|
||||||
|
|
||||||
if ($this->components === false) {
|
|
||||||
$this->scheme->expectNever('validateComponents');
|
|
||||||
} else {
|
|
||||||
$this->components[] = '*'; // append the configuration
|
|
||||||
$this->components[] = '*'; // append context
|
|
||||||
$this->scheme->setReturnValue(
|
|
||||||
'validateComponents', $this->return_components, $this->components);
|
|
||||||
$this->scheme->expectOnce('validateComponents', $this->components);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function tearDownAssertDef() {
|
|
||||||
$this->scheme->tally();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testIntegration() {
|
function testIntegration() {
|
||||||
|
|
||||||
$this->def = new HTMLPurifier_AttrDef_URI();
|
|
||||||
|
|
||||||
$this->assertDef('http://www.google.com/');
|
$this->assertDef('http://www.google.com/');
|
||||||
|
$this->assertDef('http:', '');
|
||||||
|
$this->assertDef('http:/foo', '/foo');
|
||||||
$this->assertDef('javascript:bad_stuff();', false);
|
$this->assertDef('javascript:bad_stuff();', false);
|
||||||
$this->assertDef('ftp://www.example.com/');
|
$this->assertDef('ftp://www.example.com/');
|
||||||
$this->assertDef('news:rec.alt');
|
$this->assertDef('news:rec.alt');
|
||||||
$this->assertDef('nntp://news.example.com/324234');
|
$this->assertDef('nntp://news.example.com/324234');
|
||||||
$this->assertDef('mailto:bob@example.com');
|
$this->assertDef('mailto:bob@example.com');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDisableExternal() {
|
function testIntegrationWithPercentEncoder() {
|
||||||
|
$this->assertDef(
|
||||||
$this->def = new HTMLPurifier_AttrDef_URI();
|
'http://www.example.com/%56%fc%GJ%5%FC',
|
||||||
$this->config->set('URI', 'DisableExternal', true);
|
'http://www.example.com/V%FC%25GJ%255%FC'
|
||||||
$this->config->set('URI', 'Host', 'sub.example.com');
|
);
|
||||||
|
|
||||||
$this->assertDef('/foobar.txt');
|
|
||||||
$this->assertDef('http://google.com/', false);
|
|
||||||
$this->assertDef('http://sub.example.com/alas?foo=asd');
|
|
||||||
$this->assertDef('http://example.com/teehee', false);
|
|
||||||
$this->assertDef('http://www.example.com/#man', false);
|
|
||||||
$this->assertDef('http://go.sub.example.com/perhaps?p=foo');
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testEmbeds() {
|
function testEmbeds() {
|
||||||
|
|
||||||
// embedded URI
|
|
||||||
$this->def = new HTMLPurifier_AttrDef_URI(true);
|
$this->def = new HTMLPurifier_AttrDef_URI(true);
|
||||||
|
|
||||||
$this->assertDef('http://sub.example.com/alas?foo=asd');
|
$this->assertDef('http://sub.example.com/alas?foo=asd');
|
||||||
$this->assertDef('mailto:foo@example.com', false);
|
$this->assertDef('mailto:foo@example.com', false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testDisableExternalResources() {
|
function testConfigMunge() {
|
||||||
|
|
||||||
$this->config->set('URI', 'DisableExternalResources', true);
|
|
||||||
|
|
||||||
$this->def = new HTMLPurifier_AttrDef_URI();
|
|
||||||
$this->assertDef('http://sub.example.com/alas?foo=asd');
|
|
||||||
$this->assertDef('/img.png');
|
|
||||||
|
|
||||||
$this->def = new HTMLPurifier_AttrDef_URI(true);
|
|
||||||
$this->assertDef('http://sub.example.com/alas?foo=asd', false);
|
|
||||||
$this->assertDef('/img.png');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function testMunge() {
|
|
||||||
|
|
||||||
$this->config->set('URI', 'Munge', 'http://www.google.com/url?q=%s');
|
$this->config->set('URI', 'Munge', 'http://www.google.com/url?q=%s');
|
||||||
$this->def = new HTMLPurifier_AttrDef_URI();
|
|
||||||
|
|
||||||
$this->assertDef(
|
$this->assertDef(
|
||||||
'http://www.example.com/',
|
'http://www.example.com/',
|
||||||
'http://www.google.com/url?q=http%3A%2F%2Fwww.example.com%2F'
|
'http://www.google.com/url?q=http%3A%2F%2Fwww.example.com%2F'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertDef('index.html');
|
$this->assertDef('index.html');
|
||||||
$this->assertDef('javascript:foobar();', false);
|
$this->assertDef('javascript:foobar();', false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testBlacklist() {
|
function testDefaultSchemeRemovedInBlank() {
|
||||||
|
$this->assertDef('http:', '');
|
||||||
$this->config->set('URI', 'HostBlacklist', array('example.com', 'moo'));
|
}
|
||||||
|
|
||||||
$this->assertDef('foo.txt');
|
function testDefaultSchemeRemovedInRelativeURI() {
|
||||||
$this->assertDef('http://www.google.com/example.com/moo');
|
$this->assertDef('http:/foo/bar', '/foo/bar');
|
||||||
|
}
|
||||||
$this->assertDef('http://example.com/#23', false);
|
|
||||||
$this->assertDef('https://sub.domain.example.com/foobar', false);
|
function testDefaultSchemeNotRemovedInAbsoluteURI() {
|
||||||
$this->assertDef('http://example.com.example.net/?whoo=foo', false);
|
$this->assertDef('http://example.com/foo/bar');
|
||||||
$this->assertDef('ftp://moo-moo.net/foo/foo/', false);
|
}
|
||||||
|
|
||||||
|
function testAltSchemeNotRemoved() {
|
||||||
|
$this->assertDef('mailto:this-looks-like-a-path@example.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testURIDefinitionValidation() {
|
||||||
|
$parser = new HTMLPurifier_URIParser();
|
||||||
|
$uri = $parser->parse('http://example.com');
|
||||||
|
$this->config->set('URI', 'DefinitionID', 'HTMLPurifier_AttrDef_URITest->testURIDefinitionValidation');
|
||||||
|
$uri_def =& $this->config->getDefinition('URI');
|
||||||
|
// overload with mock
|
||||||
|
generate_mock_once('HTMLPurifier_URIDefinition');
|
||||||
|
$uri_def = new HTMLPurifier_URIDefinitionMock();
|
||||||
|
$uri_def->expectOnce('filter', array($uri, '*', '*'));
|
||||||
|
$uri_def->setReturnValue('filter', true, array($uri, '*', '*'));
|
||||||
|
$uri_def->setup = true;
|
||||||
|
$this->assertDef('http://example.com');
|
||||||
}
|
}
|
||||||
|
|
||||||
function testWhitelist() {
|
|
||||||
/*
|
/*
|
||||||
|
function test_validate_configWhitelist() {
|
||||||
|
|
||||||
$this->config->set('URI', 'HostPolicy', 'DenyAll');
|
$this->config->set('URI', 'HostPolicy', 'DenyAll');
|
||||||
$this->config->set('URI', 'HostWhitelist', array(null, 'google.com'));
|
$this->config->set('URI', 'HostWhitelist', array(null, 'google.com'));
|
||||||
|
|
||||||
@ -320,8 +89,9 @@ class HTMLPurifier_AttrDef_URITest extends HTMLPurifier_AttrDefHarness
|
|||||||
$this->assertDef('server.txt');
|
$this->assertDef('server.txt');
|
||||||
$this->assertDef('ftp://www.google.com/?t=a');
|
$this->assertDef('ftp://www.google.com/?t=a');
|
||||||
$this->assertDef('http://google.com.tricky.spamsite.net', false);
|
$this->assertDef('http://google.com.tricky.spamsite.net', false);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
class HTMLPurifier_AttrDefHarness extends UnitTestCase
|
class HTMLPurifier_AttrDefHarness extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
var $def;
|
var $def;
|
||||||
var $context;
|
var $context, $config;
|
||||||
var $config;
|
|
||||||
|
|
||||||
function setUp() {
|
function setUp() {
|
||||||
$this->config = HTMLPurifier_Config::createDefault();
|
$this->config = HTMLPurifier_Config::createDefault();
|
||||||
@ -13,20 +12,15 @@ class HTMLPurifier_AttrDefHarness extends UnitTestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cannot be used for accumulator
|
// cannot be used for accumulator
|
||||||
function assertDef($string, $expect = true, $ini = false, $message = '%s') {
|
function assertDef($string, $expect = true) {
|
||||||
// $expect can be a string or bool
|
// $expect can be a string or bool
|
||||||
if ($ini) $this->setUpAssertDef();
|
|
||||||
$result = $this->def->validate($string, $this->config, $this->context);
|
$result = $this->def->validate($string, $this->config, $this->context);
|
||||||
if ($expect === true) {
|
if ($expect === true) {
|
||||||
$this->assertIdentical($string, $result, $message);
|
$this->assertIdentical($string, $result);
|
||||||
} else {
|
} else {
|
||||||
$this->assertIdentical($expect, $result, $message);
|
$this->assertIdentical($expect, $result);
|
||||||
}
|
}
|
||||||
if ($ini) $this->tearDownAssertDef();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setUpAssertDef() {}
|
|
||||||
function tearDownAssertDef() {}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/AttrDef.php';
|
require_once 'HTMLPurifier/AttrDef.php';
|
||||||
|
|
||||||
class HTMLPurifier_AttrDefTest extends UnitTestCase
|
class HTMLPurifier_AttrDefTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test_parseCDATA() {
|
function test_parseCDATA() {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once 'HTMLPurifier/Harness.php';
|
require_once 'HTMLPurifier/ComplexHarness.php';
|
||||||
|
|
||||||
class HTMLPurifier_AttrTransformHarness extends HTMLPurifier_Harness
|
class HTMLPurifier_AttrTransformHarness extends HTMLPurifier_ComplexHarness
|
||||||
{
|
{
|
||||||
|
|
||||||
function setUp() {
|
function setUp() {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/AttrTransform.php';
|
require_once 'HTMLPurifier/AttrTransform.php';
|
||||||
|
|
||||||
class HTMLPurifier_AttrTransformTest extends UnitTestCase
|
class HTMLPurifier_AttrTransformTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test_prependCSS() {
|
function test_prependCSS() {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/AttrTypes.php';
|
require_once 'HTMLPurifier/AttrTypes.php';
|
||||||
|
|
||||||
class HTMLPurifier_AttrTypesTest extends UnitTestCase
|
class HTMLPurifier_AttrTypesTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test_get() {
|
function test_get() {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once 'HTMLPurifier/Harness.php';
|
require_once 'HTMLPurifier/ComplexHarness.php';
|
||||||
require_once 'HTMLPurifier/ChildDef.php';
|
require_once 'HTMLPurifier/ChildDef.php';
|
||||||
|
|
||||||
class HTMLPurifier_ChildDefHarness extends HTMLPurifier_Harness
|
class HTMLPurifier_ChildDefHarness extends HTMLPurifier_ComplexHarness
|
||||||
{
|
{
|
||||||
|
|
||||||
function setUp() {
|
function setUp() {
|
||||||
|
129
tests/HTMLPurifier/ComplexHarness.php
Normal file
129
tests/HTMLPurifier/ComplexHarness.php
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'HTMLPurifier/Lexer/DirectLex.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General-purpose test-harness that makes testing functions that require
|
||||||
|
* configuration and context objects easier when those two parameters are
|
||||||
|
* meaningless. See HTMLPurifier_ChildDefTest for a good example of usage.
|
||||||
|
*/
|
||||||
|
class HTMLPurifier_ComplexHarness extends HTMLPurifier_Harness
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance of the object that will execute the method
|
||||||
|
*/
|
||||||
|
var $obj;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the function to be executed
|
||||||
|
*/
|
||||||
|
var $func;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the method deals in tokens. If set to true, assertResult()
|
||||||
|
* will transparently convert HTML to and back from tokens.
|
||||||
|
*/
|
||||||
|
var $to_tokens = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not to convert tokens back into HTML before performing
|
||||||
|
* equality check, has no effect on bools.
|
||||||
|
*/
|
||||||
|
var $to_html = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance of an HTMLPurifier_Lexer implementation.
|
||||||
|
*/
|
||||||
|
var $lexer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance of HTMLPurifier_Generator
|
||||||
|
*/
|
||||||
|
var $generator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default config to fall back on if no config is available
|
||||||
|
*/
|
||||||
|
var $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default context to fall back on if no context is available
|
||||||
|
*/
|
||||||
|
var $context;
|
||||||
|
|
||||||
|
function HTMLPurifier_ComplexHarness() {
|
||||||
|
$this->lexer = new HTMLPurifier_Lexer_DirectLex();
|
||||||
|
$this->generator = new HTMLPurifier_Generator();
|
||||||
|
parent::HTMLPurifier_Harness();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts a specific result from a one parameter + config/context function
|
||||||
|
* @param $input Input parameter
|
||||||
|
* @param $expect Expectation
|
||||||
|
* @param $config Configuration array in form of Ns.Directive => Value.
|
||||||
|
* Has no effect if $this->config is set.
|
||||||
|
* @param $context_array Context array in form of Key => Value or an actual
|
||||||
|
* context object.
|
||||||
|
*/
|
||||||
|
function assertResult($input, $expect = true,
|
||||||
|
$config_array = array(), $context_array = array()
|
||||||
|
) {
|
||||||
|
|
||||||
|
// setup config
|
||||||
|
if ($this->config) {
|
||||||
|
$config = HTMLPurifier_Config::create($this->config);
|
||||||
|
$config->autoFinalize = false;
|
||||||
|
$config->loadArray($config_array);
|
||||||
|
} else {
|
||||||
|
$config = HTMLPurifier_Config::create($config_array);
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup context object. Note that we are operating on a copy of it!
|
||||||
|
// When necessary, extend the test harness to allow post-tests
|
||||||
|
// on the context object
|
||||||
|
if (empty($this->context)) {
|
||||||
|
$context = new HTMLPurifier_Context();
|
||||||
|
$context->loadArray($context_array);
|
||||||
|
} else {
|
||||||
|
$context =& $this->context;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->to_tokens && is_string($input)) {
|
||||||
|
// $func may cause $input to change, so "clone" another copy
|
||||||
|
// to sacrifice
|
||||||
|
$input = $this->lexer->tokenizeHTML($s = $input, $config, $context);
|
||||||
|
$input_c = $this->lexer->tokenizeHTML($s, $config, $context);
|
||||||
|
} else {
|
||||||
|
$input_c = $input;
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the function
|
||||||
|
$func = $this->func;
|
||||||
|
$result = $this->obj->$func($input_c, $config, $context);
|
||||||
|
|
||||||
|
// test a bool result
|
||||||
|
if (is_bool($result)) {
|
||||||
|
$this->assertIdentical($expect, $result);
|
||||||
|
return;
|
||||||
|
} elseif (is_bool($expect)) {
|
||||||
|
$expect = $input;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->to_html) {
|
||||||
|
$result = $this->generator->
|
||||||
|
generateFromTokens($result, $config, $context);
|
||||||
|
if (is_array($expect)) {
|
||||||
|
$expect = $this->generator->
|
||||||
|
generateFromTokens($expect, $config, $context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertIdentical($expect, $result);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -6,7 +6,7 @@ if (!class_exists('CS')) {
|
|||||||
class CS extends HTMLPurifier_ConfigSchema {}
|
class CS extends HTMLPurifier_ConfigSchema {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HTMLPurifier_ConfigSchemaTest extends UnitTestCase
|
class HTMLPurifier_ConfigSchemaTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,7 +6,7 @@ if (!class_exists('CS')) {
|
|||||||
class CS extends HTMLPurifier_ConfigSchema {}
|
class CS extends HTMLPurifier_ConfigSchema {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HTMLPurifier_ConfigTest extends UnitTestCase
|
class HTMLPurifier_ConfigTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
var $our_copy, $old_copy;
|
var $our_copy, $old_copy;
|
||||||
|
@ -5,7 +5,7 @@ require_once 'HTMLPurifier/Context.php';
|
|||||||
// mocks
|
// mocks
|
||||||
require_once 'HTMLPurifier/IDAccumulator.php';
|
require_once 'HTMLPurifier/IDAccumulator.php';
|
||||||
|
|
||||||
class HTMLPurifier_ContextTest extends UnitTestCase
|
class HTMLPurifier_ContextTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
var $context;
|
var $context;
|
||||||
|
@ -17,8 +17,7 @@ class HTMLPurifier_DefinitionCache_SerializerTest extends HTMLPurifier_Definitio
|
|||||||
$config_md5 = '1.0.0-serial-2';
|
$config_md5 = '1.0.0-serial-2';
|
||||||
|
|
||||||
$file = realpath(
|
$file = realpath(
|
||||||
$rel_file = dirname(__FILE__) .
|
$rel_file = HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer/Test/' .
|
||||||
'/../../../library/HTMLPurifier/DefinitionCache/Serializer/Test/' .
|
|
||||||
$config_md5 . '.ser'
|
$config_md5 . '.ser'
|
||||||
);
|
);
|
||||||
if($file && file_exists($file)) unlink($file); // prevent previous failures from causing problems
|
if($file && file_exists($file)) unlink($file); // prevent previous failures from causing problems
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/DefinitionCacheFactory.php';
|
require_once 'HTMLPurifier/DefinitionCacheFactory.php';
|
||||||
|
|
||||||
class HTMLPurifier_DefinitionCacheFactoryTest extends UnitTestCase
|
class HTMLPurifier_DefinitionCacheFactoryTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
var $newFactory;
|
var $newFactory;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
class HTMLPurifier_DefinitionCacheHarness extends UnitTestCase
|
class HTMLPurifier_DefinitionCacheHarness extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/DefinitionCache.php';
|
require_once 'HTMLPurifier/DefinitionCache.php';
|
||||||
|
|
||||||
class HTMLPurifier_DefinitionCacheTest extends UnitTestCase
|
class HTMLPurifier_DefinitionCacheTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test_isOld() {
|
function test_isOld() {
|
||||||
|
@ -7,7 +7,7 @@ Mock::generatePartial(
|
|||||||
'HTMLPurifier_Definition_Testable',
|
'HTMLPurifier_Definition_Testable',
|
||||||
array('doSetup'));
|
array('doSetup'));
|
||||||
|
|
||||||
class HTMLPurifier_DefinitionTest extends UnitTestCase
|
class HTMLPurifier_DefinitionTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
function test_setup() {
|
function test_setup() {
|
||||||
$def = new HTMLPurifier_Definition_Testable();
|
$def = new HTMLPurifier_Definition_Testable();
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/DoctypeRegistry.php';
|
require_once 'HTMLPurifier/DoctypeRegistry.php';
|
||||||
|
|
||||||
class HTMLPurifier_DoctypeRegistryTest extends UnitTestCase
|
class HTMLPurifier_DoctypeRegistryTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test_register() {
|
function test_register() {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/ElementDef.php';
|
require_once 'HTMLPurifier/ElementDef.php';
|
||||||
|
|
||||||
class HTMLPurifier_ElementDefTest extends UnitTestCase
|
class HTMLPurifier_ElementDefTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test_mergeIn() {
|
function test_mergeIn() {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/Encoder.php';
|
require_once 'HTMLPurifier/Encoder.php';
|
||||||
|
|
||||||
class HTMLPurifier_EncoderTest extends UnitTestCase
|
class HTMLPurifier_EncoderTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
var $_entity_lookup;
|
var $_entity_lookup;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/EntityLookup.php';
|
require_once 'HTMLPurifier/EntityLookup.php';
|
||||||
|
|
||||||
class HTMLPurifier_EntityLookupTest extends UnitTestCase
|
class HTMLPurifier_EntityLookupTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/EntityParser.php';
|
require_once 'HTMLPurifier/EntityParser.php';
|
||||||
|
|
||||||
class HTMLPurifier_EntityParserTest extends UnitTestCase
|
class HTMLPurifier_EntityParserTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
var $EntityParser;
|
var $EntityParser;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/ErrorCollector.php';
|
require_once 'HTMLPurifier/ErrorCollector.php';
|
||||||
|
|
||||||
class HTMLPurifier_ErrorCollectorTest extends UnitTestCase
|
class HTMLPurifier_ErrorCollectorTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function setup() {
|
function setup() {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
require_once 'HTMLPurifier/ErrorCollectorEMock.php';
|
require_once 'HTMLPurifier/ErrorCollectorEMock.php';
|
||||||
require_once 'HTMLPurifier/Lexer/DirectLex.php';
|
require_once 'HTMLPurifier/Lexer/DirectLex.php';
|
||||||
|
|
||||||
class HTMLPurifier_ErrorsHarness extends UnitTestCase
|
class HTMLPurifier_ErrorsHarness extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
var $config, $context;
|
var $config, $context;
|
||||||
|
@ -3,16 +3,16 @@
|
|||||||
require_once 'HTMLPurifier/Generator.php';
|
require_once 'HTMLPurifier/Generator.php';
|
||||||
require_once 'HTMLPurifier/EntityLookup.php';
|
require_once 'HTMLPurifier/EntityLookup.php';
|
||||||
|
|
||||||
require_once 'HTMLPurifier/Harness.php';
|
require_once 'HTMLPurifier/ComplexHarness.php';
|
||||||
|
|
||||||
class HTMLPurifier_GeneratorTest extends HTMLPurifier_Harness
|
class HTMLPurifier_GeneratorTest extends HTMLPurifier_ComplexHarness
|
||||||
{
|
{
|
||||||
|
|
||||||
var $gen;
|
var $gen;
|
||||||
var $_entity_lookup;
|
var $_entity_lookup;
|
||||||
|
|
||||||
function HTMLPurifier_GeneratorTest() {
|
function HTMLPurifier_GeneratorTest() {
|
||||||
$this->UnitTestCase();
|
$this->HTMLPurifier_Harness();
|
||||||
$this->gen = new HTMLPurifier_Generator();
|
$this->gen = new HTMLPurifier_Generator();
|
||||||
$this->_entity_lookup = HTMLPurifier_EntityLookup::instance();
|
$this->_entity_lookup = HTMLPurifier_EntityLookup::instance();
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,18 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/HTMLDefinition.php';
|
require_once 'HTMLPurifier/HTMLDefinition.php';
|
||||||
|
|
||||||
class HTMLPurifier_HTMLDefinitionTest extends UnitTestCase
|
class HTMLPurifier_HTMLDefinitionTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test_parseTinyMCEAllowedList() {
|
function test_parseTinyMCEAllowedList() {
|
||||||
|
|
||||||
$def = new HTMLPurifier_HTMLDefinition();
|
$def = new HTMLPurifier_HTMLDefinition();
|
||||||
|
|
||||||
|
$this->assertEqual(
|
||||||
|
$def->parseTinyMCEAllowedList(''),
|
||||||
|
array(array(), array())
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertEqual(
|
$this->assertEqual(
|
||||||
$def->parseTinyMCEAllowedList('a,b,c'),
|
$def->parseTinyMCEAllowedList('a,b,c'),
|
||||||
array(array('a' => true, 'b' => true, 'c' => true), array())
|
array(array('a' => true, 'b' => true, 'c' => true), array())
|
||||||
|
56
tests/HTMLPurifier/HTMLModule/RubyTest.php
Normal file
56
tests/HTMLPurifier/HTMLModule/RubyTest.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'HTMLPurifier/HTMLModuleHarness.php';
|
||||||
|
|
||||||
|
class HTMLPurifier_HTMLModule_RubyTest extends HTMLPurifier_HTMLModuleHarness
|
||||||
|
{
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
$this->config->set('HTML', 'Doctype', 'XHTML 1.1');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testBasicUse() {
|
||||||
|
$this->assertResult(
|
||||||
|
'<ruby><rb>WWW</rb><rt>World Wide Web</rt></ruby>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testRPUse() {
|
||||||
|
$this->assertResult(
|
||||||
|
'<ruby><rb>WWW</rb><rp>(</rp><rt>World Wide Web</rt><rp>)</rp></ruby>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testComplexUse() {
|
||||||
|
$this->assertResult(
|
||||||
|
'<ruby>
|
||||||
|
<rbc>
|
||||||
|
<rb>10</rb>
|
||||||
|
<rb>31</rb>
|
||||||
|
<rb>2002</rb>
|
||||||
|
</rbc>
|
||||||
|
<rtc>
|
||||||
|
<rt>Month</rt>
|
||||||
|
<rt>Day</rt>
|
||||||
|
<rt>Year</rt>
|
||||||
|
</rtc>
|
||||||
|
<rtc>
|
||||||
|
<rt rbspan="3">Expiration Date</rt>
|
||||||
|
</rtc>
|
||||||
|
</ruby>'
|
||||||
|
);
|
||||||
|
|
||||||
|
/* not implemented
|
||||||
|
function testBackwardsCompat() {
|
||||||
|
$this->assertResult(
|
||||||
|
'<ruby>A<rp>(</rp><rt>aaa</rt><rp>)</rp></ruby>',
|
||||||
|
'<ruby><rb>A</rb><rp>(</rp><rt>aaa</rt><rp>)</rp></ruby>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ Mock::generatePartial(
|
|||||||
array('makeFixes', 'makeFixesForLevel', 'populate')
|
array('makeFixes', 'makeFixesForLevel', 'populate')
|
||||||
);
|
);
|
||||||
|
|
||||||
class HTMLPurifier_HTMLModule_TidyTest extends UnitTestCase
|
class HTMLPurifier_HTMLModule_TidyTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test_getFixesForLevel() {
|
function test_getFixesForLevel() {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/HTMLModuleManager.php';
|
require_once 'HTMLPurifier/HTMLModuleManager.php';
|
||||||
|
|
||||||
class HTMLPurifier_HTMLModuleManagerTest extends UnitTestCase
|
class HTMLPurifier_HTMLModuleManagerTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test_addModule() {
|
function test_addModule() {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
require_once 'HTMLPurifier/HTMLModule.php';
|
require_once 'HTMLPurifier/HTMLModule.php';
|
||||||
require_once 'HTMLPurifier/AttrDef.php';
|
require_once 'HTMLPurifier/AttrDef.php';
|
||||||
|
|
||||||
class HTMLPurifier_HTMLModuleTest extends UnitTestCase
|
class HTMLPurifier_HTMLModuleTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test_addElementToContentSet() {
|
function test_addElementToContentSet() {
|
||||||
|
@ -1,128 +1,59 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once 'HTMLPurifier/Lexer/DirectLex.php';
|
require_once 'HTMLPurifier/URIParser.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* General-purpose test-harness that makes testing functions that require
|
* All-use harness, use this rather than SimpleTest's
|
||||||
* configuration and context objects easier when those two parameters are
|
|
||||||
* meaningless. See HTMLPurifier_ChildDefTest for a good example of usage.
|
|
||||||
*/
|
*/
|
||||||
class HTMLPurifier_Harness extends UnitTestCase
|
class HTMLPurifier_Harness extends UnitTestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
|
||||||
* Instance of the object that will execute the method
|
|
||||||
*/
|
|
||||||
var $obj;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of the function to be executed
|
|
||||||
*/
|
|
||||||
var $func;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the method deals in tokens. If set to true, assertResult()
|
|
||||||
* will transparently convert HTML to and back from tokens.
|
|
||||||
*/
|
|
||||||
var $to_tokens = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not to convert tokens back into HTML before performing
|
|
||||||
* equality check, has no effect on bools.
|
|
||||||
*/
|
|
||||||
var $to_html = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instance of an HTMLPurifier_Lexer implementation.
|
|
||||||
*/
|
|
||||||
var $lexer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instance of HTMLPurifier_Generator
|
|
||||||
*/
|
|
||||||
var $generator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default config to fall back on if no config is available
|
|
||||||
*/
|
|
||||||
var $config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default context to fall back on if no context is available
|
|
||||||
*/
|
|
||||||
var $context;
|
|
||||||
|
|
||||||
function HTMLPurifier_Harness() {
|
function HTMLPurifier_Harness() {
|
||||||
$this->lexer = new HTMLPurifier_Lexer_DirectLex();
|
|
||||||
$this->generator = new HTMLPurifier_Generator();
|
|
||||||
parent::UnitTestCase();
|
parent::UnitTestCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var $config, $context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts a specific result from a one parameter + config/context function
|
* Generates easily accessible default config/context
|
||||||
* @param $input Input parameter
|
|
||||||
* @param $expect Expectation
|
|
||||||
* @param $config Configuration array in form of Ns.Directive => Value.
|
|
||||||
* Has no effect if $this->config is set.
|
|
||||||
* @param $context_array Context array in form of Key => Value or an actual
|
|
||||||
* context object.
|
|
||||||
*/
|
*/
|
||||||
function assertResult($input, $expect = true,
|
function setUp() {
|
||||||
$config_array = array(), $context_array = array()
|
list($this->config, $this->context) = $this->createCommon();
|
||||||
) {
|
}
|
||||||
|
|
||||||
// setup config
|
/**
|
||||||
if ($this->config) {
|
* Accepts config and context and prepares them into a valid state
|
||||||
$config = HTMLPurifier_Config::create($this->config);
|
* @param &$config Reference to config variable
|
||||||
$config->loadArray($config_array);
|
* @param &$context Reference to context variable
|
||||||
|
*/
|
||||||
|
function prepareCommon(&$config, &$context) {
|
||||||
|
$config = HTMLPurifier_Config::create($config);
|
||||||
|
if (!$context) $context = new HTMLPurifier_Context();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates default configuration and context objects
|
||||||
|
* @return Defaults in form of array($config, $context)
|
||||||
|
*/
|
||||||
|
function createCommon() {
|
||||||
|
return array(HTMLPurifier_Config::createDefault(), new HTMLPurifier_Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If $expect is false, ignore $result and check if status failed.
|
||||||
|
* Otherwise, check if $status if true and $result === $expect.
|
||||||
|
* @param $status Boolean status
|
||||||
|
* @param $result Mixed result from processing
|
||||||
|
* @param $expect Mixed expectation for result
|
||||||
|
*/
|
||||||
|
function assertEitherFailOrIdentical($status, $result, $expect) {
|
||||||
|
if ($expect === false) {
|
||||||
|
$this->assertFalse($status, 'Expected false result, got true');
|
||||||
} else {
|
} else {
|
||||||
$config = HTMLPurifier_Config::create($config_array);
|
$this->assertTrue($status, 'Expected true result, got false');
|
||||||
|
$this->assertIdentical($result, $expect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup context object. Note that we are operating on a copy of it!
|
|
||||||
// When necessary, extend the test harness to allow post-tests
|
|
||||||
// on the context object
|
|
||||||
if (empty($this->context)) {
|
|
||||||
$context = new HTMLPurifier_Context();
|
|
||||||
$context->loadArray($context_array);
|
|
||||||
} else {
|
|
||||||
$context =& $this->context;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->to_tokens && is_string($input)) {
|
|
||||||
// $func may cause $input to change, so "clone" another copy
|
|
||||||
// to sacrifice
|
|
||||||
$input = $this->lexer->tokenizeHTML($s = $input, $config, $context);
|
|
||||||
$input_c = $this->lexer->tokenizeHTML($s, $config, $context);
|
|
||||||
} else {
|
|
||||||
$input_c = $input;
|
|
||||||
}
|
|
||||||
|
|
||||||
// call the function
|
|
||||||
$func = $this->func;
|
|
||||||
$result = $this->obj->$func($input_c, $config, $context);
|
|
||||||
|
|
||||||
// test a bool result
|
|
||||||
if (is_bool($result)) {
|
|
||||||
$this->assertIdentical($expect, $result);
|
|
||||||
return;
|
|
||||||
} elseif (is_bool($expect)) {
|
|
||||||
$expect = $input;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->to_html) {
|
|
||||||
$result = $this->generator->
|
|
||||||
generateFromTokens($result, $config, $context);
|
|
||||||
if (is_array($expect)) {
|
|
||||||
$expect = $this->generator->
|
|
||||||
generateFromTokens($expect, $config, $context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertIdentical($expect, $result);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/IDAccumulator.php';
|
require_once 'HTMLPurifier/IDAccumulator.php';
|
||||||
|
|
||||||
class HTMLPurifier_IDAccumulatorTest extends UnitTestCase
|
class HTMLPurifier_IDAccumulatorTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/LanguageFactory.php';
|
require_once 'HTMLPurifier/LanguageFactory.php';
|
||||||
|
|
||||||
class HTMLPurifier_LanguageFactoryTest extends UnitTestCase
|
class HTMLPurifier_LanguageFactoryTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/Language.php';
|
require_once 'HTMLPurifier/Language.php';
|
||||||
|
|
||||||
class HTMLPurifier_LanguageTest extends UnitTestCase
|
class HTMLPurifier_LanguageTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
var $lang;
|
var $lang;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/Lexer/DirectLex.php';
|
require_once 'HTMLPurifier/Lexer/DirectLex.php';
|
||||||
|
|
||||||
class HTMLPurifier_Lexer_DirectLexTest extends UnitTestCase
|
class HTMLPurifier_Lexer_DirectLexTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
var $DirectLex;
|
var $DirectLex;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/Lexer/DirectLex.php';
|
require_once 'HTMLPurifier/Lexer/DirectLex.php';
|
||||||
|
|
||||||
class HTMLPurifier_LexerTest extends UnitTestCase
|
class HTMLPurifier_LexerTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
var $Lexer;
|
var $Lexer;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/PercentEncoder.php';
|
require_once 'HTMLPurifier/PercentEncoder.php';
|
||||||
|
|
||||||
class HTMLPurifier_PercentEncoderTest extends UnitTestCase
|
class HTMLPurifier_PercentEncoderTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
var $PercentEncoder;
|
var $PercentEncoder;
|
||||||
|
@ -15,7 +15,7 @@ class HTMLPurifier_Strategy_Composite_Test
|
|||||||
}
|
}
|
||||||
|
|
||||||
// doesn't use Strategy harness
|
// doesn't use Strategy harness
|
||||||
class HTMLPurifier_Strategy_CompositeTest extends UnitTestCase
|
class HTMLPurifier_Strategy_CompositeTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
|
@ -63,12 +63,6 @@ class HTMLPurifier_Strategy_FixNestingTest extends HTMLPurifier_StrategyHarness
|
|||||||
'<span><ins>Not allowed!</ins></span>'
|
'<span><ins>Not allowed!</ins></span>'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertResult( // alt config
|
|
||||||
'<span><ins><div>Not allowed!</div></ins></span>',
|
|
||||||
'<span><ins><div>Not allowed!</div></ins></span>',
|
|
||||||
array('Core.EscapeInvalidChildren' => true)
|
|
||||||
);
|
|
||||||
|
|
||||||
// test block element that has inline content
|
// test block element that has inline content
|
||||||
$this->assertResult(
|
$this->assertResult(
|
||||||
'<h1><ins><div>Not allowed!</div></ins></h1>',
|
'<h1><ins><div>Not allowed!</div></ins></h1>',
|
||||||
@ -84,6 +78,12 @@ class HTMLPurifier_Strategy_FixNestingTest extends HTMLPurifier_StrategyHarness
|
|||||||
'<div><ins><del><div>Allowed!</div></del></ins></div>'
|
'<div><ins><del><div>Allowed!</div></del></ins></div>'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->assertResult( // alt config
|
||||||
|
'<span><ins><div>Not allowed!</div></ins></span>',
|
||||||
|
'<span><ins><div>Not allowed!</div></ins></span>',
|
||||||
|
array('Core.EscapeInvalidChildren' => true)
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function testExclusionsIntegration() {
|
function testExclusionsIntegration() {
|
||||||
|
@ -49,7 +49,7 @@ class HTMLPurifier_Strategy_RemoveForeignElements_ErrorsTest extends HTMLPurifie
|
|||||||
}
|
}
|
||||||
|
|
||||||
function testScriptRemoved() {
|
function testScriptRemoved() {
|
||||||
$this->collector->expectAt(0, 'send', array(E_ERROR, 'Strategy_RemoveForeignElements: Script removed'));
|
$this->collector->expectAt(0, 'send', array(E_ERROR, 'Strategy_RemoveForeignElements: Foreign meta element removed'));
|
||||||
$this->collector->expectContextAt(0, 'CurrentToken', new HTMLPurifier_Token_Start('script', array(), 1));
|
$this->collector->expectContextAt(0, 'CurrentToken', new HTMLPurifier_Token_Start('script', array(), 1));
|
||||||
$this->collector->expectAt(1, 'send', array(E_ERROR, 'Strategy_RemoveForeignElements: Token removed to end', 'script'));
|
$this->collector->expectAt(1, 'send', array(E_ERROR, 'Strategy_RemoveForeignElements: Token removed to end', 'script'));
|
||||||
$this->invoke('<script>asdf');
|
$this->invoke('<script>asdf');
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once 'HTMLPurifier/Harness.php';
|
require_once 'HTMLPurifier/ComplexHarness.php';
|
||||||
|
|
||||||
class HTMLPurifier_StrategyHarness extends HTMLPurifier_Harness
|
class HTMLPurifier_StrategyHarness extends HTMLPurifier_ComplexHarness
|
||||||
{
|
{
|
||||||
|
|
||||||
function setUp() {
|
function setUp() {
|
||||||
|
parent::setUp();
|
||||||
$this->func = 'execute';
|
$this->func = 'execute';
|
||||||
$this->to_tokens = true;
|
$this->to_tokens = true;
|
||||||
$this->to_html = true;
|
$this->to_html = true;
|
||||||
|
@ -6,7 +6,7 @@ require_once 'HTMLPurifier/TagTransform.php';
|
|||||||
require_once 'HTMLPurifier/TagTransform/Font.php';
|
require_once 'HTMLPurifier/TagTransform/Font.php';
|
||||||
require_once 'HTMLPurifier/TagTransform/Simple.php';
|
require_once 'HTMLPurifier/TagTransform/Simple.php';
|
||||||
|
|
||||||
class HTMLPurifier_TagTransformTest extends UnitTestCase
|
class HTMLPurifier_TagTransformTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/TokenFactory.php';
|
require_once 'HTMLPurifier/TokenFactory.php';
|
||||||
|
|
||||||
class HTMLPurifier_TokenFactoryTest extends UnitTestCase
|
class HTMLPurifier_TokenFactoryTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
public function test() {
|
public function test() {
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/Token.php';
|
require_once 'HTMLPurifier/Token.php';
|
||||||
|
|
||||||
class HTMLPurifier_TokenTest extends UnitTestCase
|
class HTMLPurifier_TokenTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function assertTokenConstruction($name, $attr,
|
function assertTokenConstruction($name, $attr,
|
||||||
|
59
tests/HTMLPurifier/URIDefinitionTest.php
Normal file
59
tests/HTMLPurifier/URIDefinitionTest.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'HTMLPurifier/URIHarness.php';
|
||||||
|
require_once 'HTMLPurifier/URIDefinition.php';
|
||||||
|
|
||||||
|
class HTMLPurifier_URIDefinitionTest extends HTMLPurifier_URIHarness
|
||||||
|
{
|
||||||
|
|
||||||
|
function createFilterMock($expect = true, $result = true) {
|
||||||
|
generate_mock_once('HTMLPurifier_URIFilter');
|
||||||
|
$mock = new HTMLPurifier_URIFilterMock();
|
||||||
|
if ($expect) $mock->expectOnce('filter');
|
||||||
|
else $mock->expectNever('filter');
|
||||||
|
$mock->setReturnValue('filter', $result);
|
||||||
|
return $mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_filter() {
|
||||||
|
$def = new HTMLPurifier_URIDefinition();
|
||||||
|
$def->filters[] = $this->createFilterMock();
|
||||||
|
$def->filters[] = $this->createFilterMock();
|
||||||
|
$uri = $this->createURI('test');
|
||||||
|
$this->assertTrue($def->filter($uri, $this->config, $this->context));
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_filter_earlyAbortIfFail() {
|
||||||
|
$def = new HTMLPurifier_URIDefinition();
|
||||||
|
$def->filters[] = $this->createFilterMock(true, false);
|
||||||
|
$def->filters[] = $this->createFilterMock(false); // never called
|
||||||
|
$uri = $this->createURI('test');
|
||||||
|
$this->assertFalse($def->filter($uri, $this->config, $this->context));
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_setupMemberVariables_collisionPrecedenceIsHostBaseScheme() {
|
||||||
|
$this->config->set('URI', 'Host', $host = 'example.com');
|
||||||
|
$this->config->set('URI', 'Base', $base = 'http://sub.example.com/foo/bar.html');
|
||||||
|
$this->config->set('URI', 'DefaultScheme', 'ftp');
|
||||||
|
$def = new HTMLPurifier_URIDefinition();
|
||||||
|
$def->setupMemberVariables($this->config);
|
||||||
|
$this->assertIdentical($def->host, $host);
|
||||||
|
$this->assertIdentical($def->base, $this->createURI($base));
|
||||||
|
$this->assertIdentical($def->defaultScheme, 'http'); // not ftp!
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_setupMemberVariables_onlyScheme() {
|
||||||
|
$this->config->set('URI', 'DefaultScheme', 'ftp');
|
||||||
|
$def = new HTMLPurifier_URIDefinition();
|
||||||
|
$def->setupMemberVariables($this->config);
|
||||||
|
$this->assertIdentical($def->defaultScheme, 'ftp');
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_setupMemberVariables_onlyBase() {
|
||||||
|
$this->config->set('URI', 'Base', 'http://sub.example.com/foo/bar.html');
|
||||||
|
$def = new HTMLPurifier_URIDefinition();
|
||||||
|
$def->setupMemberVariables($this->config);
|
||||||
|
$this->assertIdentical($def->host, 'sub.example.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'HTMLPurifier/URIFilter/DisableExternalTest.php';
|
||||||
|
require_once 'HTMLPurifier/URIFilter/DisableExternalResources.php';
|
||||||
|
|
||||||
|
class HTMLPurifier_URIFilter_DisableExternalResourcesTest extends
|
||||||
|
HTMLPurifier_URIFilter_DisableExternalTest
|
||||||
|
{
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
$this->filter = new HTMLPurifier_URIFilter_DisableExternalResources();
|
||||||
|
$var = true;
|
||||||
|
$this->context->register('EmbeddedURI', $var);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPreserveWhenNotEmbedded() {
|
||||||
|
$this->context->destroy('EmbeddedURI'); // undo setUp
|
||||||
|
$this->assertFiltering(
|
||||||
|
'http://example.com'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
47
tests/HTMLPurifier/URIFilter/DisableExternalTest.php
Normal file
47
tests/HTMLPurifier/URIFilter/DisableExternalTest.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'HTMLPurifier/URIFilter/DisableExternal.php';
|
||||||
|
require_once 'HTMLPurifier/URIFilterHarness.php';
|
||||||
|
|
||||||
|
class HTMLPurifier_URIFilter_DisableExternalTest extends HTMLPurifier_URIFilterHarness
|
||||||
|
{
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
$this->filter = new HTMLPurifier_URIFilter_DisableExternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testRemoveExternal() {
|
||||||
|
$this->assertFiltering(
|
||||||
|
'http://example.com', false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPreserveInternal() {
|
||||||
|
$this->assertFiltering(
|
||||||
|
'/foo/bar'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPreserveOurHost() {
|
||||||
|
$this->config->set('URI', 'Host', 'example.com');
|
||||||
|
$this->assertFiltering(
|
||||||
|
'http://example.com'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPreserveOurSubdomain() {
|
||||||
|
$this->config->set('URI', 'Host', 'example.com');
|
||||||
|
$this->assertFiltering(
|
||||||
|
'http://www.example.com'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testRemoveSuperdomain() {
|
||||||
|
$this->config->set('URI', 'Host', 'www.example.com');
|
||||||
|
$this->assertFiltering(
|
||||||
|
'http://example.com', false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
tests/HTMLPurifier/URIFilter/HostBlacklistTest.php
Normal file
30
tests/HTMLPurifier/URIFilter/HostBlacklistTest.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'HTMLPurifier/URIFilter/HostBlacklist.php';
|
||||||
|
require_once 'HTMLPurifier/URIFilterHarness.php';
|
||||||
|
|
||||||
|
class HTMLPurifier_URIFilter_HostBlacklistTest extends HTMLPurifier_URIFilterHarness
|
||||||
|
{
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
$this->filter = new HTMLPurifier_URIFilter_HostBlacklist();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testRejectBlacklistedHost() {
|
||||||
|
$this->config->set('URI', 'HostBlacklist', 'example.com');
|
||||||
|
$this->assertFiltering('http://example.com', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testRejectBlacklistedHostThoughNotTrue() {
|
||||||
|
// maybe this behavior should change
|
||||||
|
$this->config->set('URI', 'HostBlacklist', 'example.com');
|
||||||
|
$this->assertFiltering('http://example.comcast.com', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPreserveNonBlacklistedHost() {
|
||||||
|
$this->config->set('URI', 'HostBlacklist', 'example.com');
|
||||||
|
$this->assertFiltering('http://google.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
122
tests/HTMLPurifier/URIFilter/MakeAbsoluteTest.php
Normal file
122
tests/HTMLPurifier/URIFilter/MakeAbsoluteTest.php
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'HTMLPurifier/URIFilter/MakeAbsolute.php';
|
||||||
|
require_once 'HTMLPurifier/URIFilterHarness.php';
|
||||||
|
|
||||||
|
class HTMLPurifier_URIFilter_MakeAbsoluteTest extends HTMLPurifier_URIFilterHarness
|
||||||
|
{
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
$this->filter = new HTMLPurifier_URIFilter_MakeAbsolute();
|
||||||
|
$this->setBase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBase($base = 'http://example.com/foo/bar.html?q=s#frag') {
|
||||||
|
$this->config->set('URI', 'Base', $base);
|
||||||
|
}
|
||||||
|
|
||||||
|
// corresponding to RFC 2396
|
||||||
|
|
||||||
|
function testPreserveAbsolute() {
|
||||||
|
$this->assertFiltering('http://example.com/foo.html');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterBlank() {
|
||||||
|
$this->assertFiltering('', 'http://example.com/foo/bar.html?q=s');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterEmptyPath() {
|
||||||
|
$this->assertFiltering('?q=s#frag', 'http://example.com/foo/bar.html?q=s#frag');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPreserveAltScheme() {
|
||||||
|
$this->assertFiltering('mailto:bob@example.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterIgnoreHTTPSpecialCase() {
|
||||||
|
$this->assertFiltering('http:/', 'http://example.com/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterAbsolutePath() {
|
||||||
|
$this->assertFiltering('/foo.txt', 'http://example.com/foo.txt');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterRelativePath() {
|
||||||
|
$this->assertFiltering('baz.txt', 'http://example.com/foo/baz.txt');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterRelativePathWithInternalDot() {
|
||||||
|
$this->assertFiltering('./baz.txt', 'http://example.com/foo/baz.txt');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterRelativePathWithEndingDot() {
|
||||||
|
$this->assertFiltering('baz/.', 'http://example.com/foo/baz/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterRelativePathDot() {
|
||||||
|
$this->assertFiltering('.', 'http://example.com/foo/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterRelativePathWithInternalDotDot() {
|
||||||
|
$this->assertFiltering('../baz.txt', 'http://example.com/baz.txt');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterRelativePathWithEndingDotDot() {
|
||||||
|
$this->assertFiltering('..', 'http://example.com/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterRelativePathTooManyDotDots() {
|
||||||
|
$this->assertFiltering('../../', 'http://example.com/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterAppendingQueryAndFragment() {
|
||||||
|
$this->assertFiltering('/foo.php?q=s#frag', 'http://example.com/foo.php?q=s#frag');
|
||||||
|
}
|
||||||
|
|
||||||
|
// edge cases below
|
||||||
|
|
||||||
|
function testFilterAbsolutePathBase() {
|
||||||
|
$this->setBase('/foo/baz.txt');
|
||||||
|
$this->assertFiltering('test.php', '/foo/test.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterAbsolutePathBaseDirectory() {
|
||||||
|
$this->setBase('/foo/');
|
||||||
|
$this->assertFiltering('test.php', '/foo/test.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterAbsolutePathBaseBelow() {
|
||||||
|
$this->setBase('/foo/baz.txt');
|
||||||
|
$this->assertFiltering('../../test.php', '/test.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterRelativePathBase() {
|
||||||
|
$this->setBase('foo/baz.html');
|
||||||
|
$this->assertFiltering('foo.php', 'foo/foo.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterRelativePathBaseBelow() {
|
||||||
|
$this->setBase('../baz.html');
|
||||||
|
$this->assertFiltering('test/strike.html', '../test/strike.html');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterRelativePathBaseWithAbsoluteURI() {
|
||||||
|
$this->setBase('../baz.html');
|
||||||
|
$this->assertFiltering('/test/strike.html');
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFilterRelativePathBaseWithDot() {
|
||||||
|
$this->setBase('../baz.html');
|
||||||
|
$this->assertFiltering('.', '../');
|
||||||
|
}
|
||||||
|
|
||||||
|
// error case
|
||||||
|
|
||||||
|
function testErrorNoBase() {
|
||||||
|
$this->setBase(null);
|
||||||
|
$this->expectError('URI.MakeAbsolute is being ignored due to lack of value for URI.Base configuration');
|
||||||
|
$this->assertFiltering('foo/bar.txt');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
tests/HTMLPurifier/URIFilterHarness.php
Normal file
15
tests/HTMLPurifier/URIFilterHarness.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'HTMLPurifier/URIHarness.php';
|
||||||
|
|
||||||
|
class HTMLPurifier_URIFilterHarness extends HTMLPurifier_URIHarness
|
||||||
|
{
|
||||||
|
|
||||||
|
function assertFiltering($uri, $expect_uri = true) {
|
||||||
|
$this->prepareURI($uri, $expect_uri);
|
||||||
|
$this->filter->prepare($this->config, $this->context);
|
||||||
|
$result = $this->filter->filter($uri, $this->config, $this->context);
|
||||||
|
$this->assertEitherFailOrIdentical($result, $uri, $expect_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
tests/HTMLPurifier/URIHarness.php
Normal file
31
tests/HTMLPurifier/URIHarness.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'HTMLPurifier/URIParser.php';
|
||||||
|
|
||||||
|
class HTMLPurifier_URIHarness extends HTMLPurifier_Harness
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares two URIs into object form
|
||||||
|
* @param &$uri Reference to string input URI
|
||||||
|
* @param &$expect_uri Reference to string expectation URI
|
||||||
|
* @note If $expect_uri is false, it will stay false
|
||||||
|
*/
|
||||||
|
function prepareURI(&$uri, &$expect_uri) {
|
||||||
|
$parser = new HTMLPurifier_URIParser();
|
||||||
|
if ($expect_uri === true) $expect_uri = $uri;
|
||||||
|
$uri = $parser->parse($uri);
|
||||||
|
if ($expect_uri !== false) {
|
||||||
|
$expect_uri = $parser->parse($expect_uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a URI object from the corresponding string
|
||||||
|
*/
|
||||||
|
function createURI($uri) {
|
||||||
|
$parser = new HTMLPurifier_URIParser();
|
||||||
|
return $parser->parse($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
140
tests/HTMLPurifier/URIParserTest.php
Normal file
140
tests/HTMLPurifier/URIParserTest.php
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'HTMLPurifier/URIParser.php';
|
||||||
|
require_once 'HTMLPurifier/URI.php';
|
||||||
|
|
||||||
|
class HTMLPurifier_URIParserTest extends HTMLPurifier_Harness
|
||||||
|
{
|
||||||
|
|
||||||
|
function assertParsing(
|
||||||
|
$uri, $scheme, $userinfo, $host, $port, $path, $query, $fragment, $config = null, $context = null
|
||||||
|
) {
|
||||||
|
$this->prepareCommon($config, $context);
|
||||||
|
$parser = new HTMLPurifier_URIParser();
|
||||||
|
$result = $parser->parse($uri, $config, $context);
|
||||||
|
$expect = new HTMLPurifier_URI($scheme, $userinfo, $host, $port, $path, $query, $fragment);
|
||||||
|
$this->assertEqual($result, $expect);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testRegular() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'http://www.example.com/webhp?q=foo#result2',
|
||||||
|
'http', null, 'www.example.com', null, '/webhp', 'q=foo', 'result2'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPortAndUsername() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'http://user@authority.part:80/now/the/path?query#fragment',
|
||||||
|
'http', 'user', 'authority.part', 80, '/now/the/path', 'query', 'fragment'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPercentEncoding() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'http://en.wikipedia.org/wiki/Clich%C3%A9',
|
||||||
|
'http', null, 'en.wikipedia.org', null, '/wiki/Clich%C3%A9', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testEmptyQuery() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'http://www.example.com/?#',
|
||||||
|
'http', null, 'www.example.com', null, '/', '', null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testEmptyPath() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'http://www.example.com',
|
||||||
|
'http', null, 'www.example.com', null, '', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testOpaqueURI() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'mailto:bob@example.com',
|
||||||
|
'mailto', null, null, null, 'bob@example.com', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testIPv4Address() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'http://192.0.34.166/',
|
||||||
|
'http', null, '192.0.34.166', null, '/', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFakeIPv4Address() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'http://333.123.32.123/',
|
||||||
|
'http', null, '333.123.32.123', null, '/', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testIPv6Address() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'http://[2001:db8::7]/c=GB?objectClass?one',
|
||||||
|
'http', null, '[2001:db8::7]', null, '/c=GB', 'objectClass?one', null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testInternationalizedDomainName() {
|
||||||
|
$this->assertParsing(
|
||||||
|
"http://t\xC5\xABdali\xC5\x86.lv",
|
||||||
|
'http', null, "t\xC5\xABdali\xC5\x86.lv", null, '', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testInvalidPort() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'http://example.com:foobar',
|
||||||
|
'http', null, 'example.com', null, '', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPathAbsolute() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'http:/this/is/path',
|
||||||
|
'http', null, null, null, '/this/is/path', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPathRootless() {
|
||||||
|
// this should not be used but is allowed
|
||||||
|
$this->assertParsing(
|
||||||
|
'http:this/is/path',
|
||||||
|
'http', null, null, null, 'this/is/path', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPathEmpty() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'http:',
|
||||||
|
'http', null, null, null, '', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testRelativeURI() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'/a/b',
|
||||||
|
null, null, null, null, '/a/b', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMalformedTag() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'http://www.example.com/\'>"',
|
||||||
|
'http', null, 'www.example.com', null, '/', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testEmpty() {
|
||||||
|
$this->assertParsing(
|
||||||
|
'',
|
||||||
|
null, null, null, null, '', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once 'HTMLPurifier/URISchemeRegistry.php';
|
require_once 'HTMLPurifier/URISchemeRegistry.php';
|
||||||
|
|
||||||
class HTMLPurifier_URISchemeRegistryTest extends UnitTestCase
|
class HTMLPurifier_URISchemeRegistryTest extends HTMLPurifier_Harness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
require_once 'HTMLPurifier/URI.php';
|
||||||
|
|
||||||
require_once 'HTMLPurifier/URIScheme.php';
|
require_once 'HTMLPurifier/URIScheme.php';
|
||||||
|
require_once 'HTMLPurifier/URISchemeRegistry.php';
|
||||||
|
|
||||||
require_once 'HTMLPurifier/URIScheme/http.php';
|
require_once 'HTMLPurifier/URIScheme/http.php';
|
||||||
require_once 'HTMLPurifier/URIScheme/ftp.php';
|
require_once 'HTMLPurifier/URIScheme/ftp.php';
|
||||||
@ -12,145 +15,133 @@ require_once 'HTMLPurifier/URIScheme/nntp.php';
|
|||||||
// WARNING: All the URI schemes are far to relaxed, we need to tighten
|
// WARNING: All the URI schemes are far to relaxed, we need to tighten
|
||||||
// the checks.
|
// the checks.
|
||||||
|
|
||||||
class HTMLPurifier_URISchemeTest extends UnitTestCase
|
class HTMLPurifier_URISchemeTest extends HTMLPurifier_URIHarness
|
||||||
{
|
{
|
||||||
|
|
||||||
function test_http() {
|
function assertValidation($uri, $expect_uri = true) {
|
||||||
$scheme = new HTMLPurifier_URIScheme_http();
|
$this->prepareURI($uri, $expect_uri);
|
||||||
$config = HTMLPurifier_Config::createDefault();
|
// convenience hack: the scheme should be explicitly specified
|
||||||
$context = new HTMLPurifier_Context();
|
$scheme = $uri->getSchemeObj($this->config, $this->context);
|
||||||
|
$result = $scheme->validate($uri, $this->config, $this->context);
|
||||||
$this->assertIdentical(
|
$this->assertEitherFailOrIdentical($result, $uri, $expect_uri);
|
||||||
$scheme->validateComponents(
|
|
||||||
null, 'www.example.com', null, '/', 's=foobar', $config, $context),
|
|
||||||
array(null, 'www.example.com', null, '/', 's=foobar')
|
|
||||||
);
|
|
||||||
|
|
||||||
// absorb default port and userinfo
|
|
||||||
$this->assertIdentical(
|
|
||||||
$scheme->validateComponents(
|
|
||||||
'user', 'www.example.com', 80, '/', 's=foobar', $config, $context),
|
|
||||||
array(null, 'www.example.com', null, '/', 's=foobar')
|
|
||||||
);
|
|
||||||
|
|
||||||
// do not absorb non-default port
|
|
||||||
$this->assertIdentical(
|
|
||||||
$scheme->validateComponents(
|
|
||||||
null, 'www.example.com', 8080, '/', 's=foobar', $config, $context),
|
|
||||||
array(null, 'www.example.com', 8080, '/', 's=foobar')
|
|
||||||
);
|
|
||||||
|
|
||||||
// https is basically the same
|
|
||||||
|
|
||||||
$scheme = new HTMLPurifier_URIScheme_https();
|
|
||||||
$this->assertIdentical(
|
|
||||||
$scheme->validateComponents(
|
|
||||||
'user', 'www.example.com', 443, '/', 's=foobar', $config, $context),
|
|
||||||
array(null, 'www.example.com', null, '/', 's=foobar')
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_ftp() {
|
function test_http_regular() {
|
||||||
|
$this->assertValidation(
|
||||||
$scheme = new HTMLPurifier_URIScheme_ftp();
|
'http://example.com/?s=q#fragment'
|
||||||
$config = HTMLPurifier_Config::createDefault();
|
|
||||||
$context = new HTMLPurifier_Context();
|
|
||||||
|
|
||||||
$this->assertIdentical(
|
|
||||||
$scheme->validateComponents(
|
|
||||||
'user', 'www.example.com', 21, '/', 's=foobar', $config, $context),
|
|
||||||
array('user', 'www.example.com', null, '/', null)
|
|
||||||
);
|
|
||||||
|
|
||||||
// valid typecode
|
|
||||||
$this->assertIdentical(
|
|
||||||
$scheme->validateComponents(
|
|
||||||
null, 'www.example.com', null, '/file.txt;type=a', null, $config, $context),
|
|
||||||
array(null, 'www.example.com', null, '/file.txt;type=a', null)
|
|
||||||
);
|
|
||||||
|
|
||||||
// remove invalid typecode
|
|
||||||
$this->assertIdentical(
|
|
||||||
$scheme->validateComponents(
|
|
||||||
null, 'www.example.com', null, '/file.txt;type=z', null, $config, $context),
|
|
||||||
array(null, 'www.example.com', null, '/file.txt', null)
|
|
||||||
);
|
|
||||||
|
|
||||||
// encode errant semicolons
|
|
||||||
$this->assertIdentical(
|
|
||||||
$scheme->validateComponents(
|
|
||||||
null, 'www.example.com', null, '/too;many;semicolons=1', null, $config, $context),
|
|
||||||
array(null, 'www.example.com', null, '/too%3Bmany%3Bsemicolons=1', null)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_news() {
|
|
||||||
|
|
||||||
$scheme = new HTMLPurifier_URIScheme_news();
|
|
||||||
$config = HTMLPurifier_Config::createDefault();
|
|
||||||
$context = new HTMLPurifier_Context();
|
|
||||||
|
|
||||||
$this->assertIdentical(
|
|
||||||
$scheme->validateComponents(
|
|
||||||
null, null, null, 'gmane.science.linguistics', null, $config, $context),
|
|
||||||
array(null, null, null, 'gmane.science.linguistics', null)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertIdentical(
|
|
||||||
$scheme->validateComponents(
|
|
||||||
null, null, null, '642@eagle.ATT.COM', null, $config, $context),
|
|
||||||
array(null, null, null, '642@eagle.ATT.COM', null)
|
|
||||||
);
|
|
||||||
|
|
||||||
// test invalid field removal
|
|
||||||
$this->assertIdentical(
|
|
||||||
$scheme->validateComponents(
|
|
||||||
'user', 'www.google.com', 80, 'rec.music', 'path=foo', $config, $context),
|
|
||||||
array(null, null, null, 'rec.music', null)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_nntp() {
|
|
||||||
|
|
||||||
$scheme = new HTMLPurifier_URIScheme_nntp();
|
|
||||||
$config = HTMLPurifier_Config::createDefault();
|
|
||||||
$context = new HTMLPurifier_Context();
|
|
||||||
|
|
||||||
$this->assertIdentical(
|
|
||||||
$scheme->validateComponents(
|
|
||||||
null, 'news.example.com', null, '/alt.misc/12345', null, $config, $context),
|
|
||||||
array(null, 'news.example.com', null, '/alt.misc/12345', null)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
$this->assertIdentical(
|
|
||||||
$scheme->validateComponents(
|
|
||||||
'user', 'news.example.com', 119, '/alt.misc/12345', 'foo=asdf', $config, $context),
|
|
||||||
array(null, 'news.example.com', null, '/alt.misc/12345', null)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_mailto() {
|
function test_http_removeDefaultPort() {
|
||||||
|
$this->assertValidation(
|
||||||
$scheme = new HTMLPurifier_URIScheme_mailto();
|
'http://example.com:80',
|
||||||
$config = HTMLPurifier_Config::createDefault();
|
'http://example.com'
|
||||||
$context = new HTMLPurifier_Context();
|
|
||||||
|
|
||||||
$this->assertIdentical(
|
|
||||||
$scheme->validateComponents(
|
|
||||||
null, null, null, 'bob@example.com', null, $config, $context),
|
|
||||||
array(null, null, null, 'bob@example.com', null)
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$this->assertIdentical(
|
function test_http_removeUserInfo() {
|
||||||
$scheme->validateComponents(
|
$this->assertValidation(
|
||||||
'user', 'example.com', 80, 'bob@example.com', 'subject=Foo!', $config, $context),
|
'http://bob@example.com',
|
||||||
array(null, null, null, 'bob@example.com', 'subject=Foo!')
|
'http://example.com'
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_http_preserveNonDefaultPort() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'http://example.com:8080'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_https_regular() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'https://user@example.com:443/?s=q#frag',
|
||||||
|
'https://example.com/?s=q#frag'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_ftp_regular() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'ftp://user@example.com/path'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_ftp_removeDefaultPort() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'ftp://example.com:21',
|
||||||
|
'ftp://example.com'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_ftp_removeQueryString() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'ftp://example.com?s=q',
|
||||||
|
'ftp://example.com'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_ftp_preserveValidTypecode() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'ftp://example.com/file.txt;type=a'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_ftp_removeInvalidTypecode() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'ftp://example.com/file.txt;type=z',
|
||||||
|
'ftp://example.com/file.txt'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_ftp_encodeExtraSemicolons() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'ftp://example.com/too;many;semicolons=1',
|
||||||
|
'ftp://example.com/too%3Bmany%3Bsemicolons=1'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_news_regular() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'news:gmane.science.linguistics'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_news_explicit() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'news:642@eagle.ATT.COM'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_news_removeNonPathComponents() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'news://user@example.com:80/rec.music?path=foo#frag',
|
||||||
|
'news:/rec.music#frag'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_nntp_regular() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'nntp://news.example.com/alt.misc/42#frag'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_nntp_removalOfRedundantOrUselessComponents() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'nntp://user@news.example.com:119/alt.misc/42?s=q#frag',
|
||||||
|
'nntp://news.example.com/alt.misc/42#frag'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_mailto_regular() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'mailto:bob@example.com'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_mailto_removalOfRedundantOrUselessComponents() {
|
||||||
|
$this->assertValidation(
|
||||||
|
'mailto://user@example.com:80/bob@example.com?subject=Foo#frag',
|
||||||
|
'mailto:/bob@example.com?subject=Foo#frag'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
166
tests/HTMLPurifier/URITest.php
Normal file
166
tests/HTMLPurifier/URITest.php
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once 'HTMLPurifier/URI.php';
|
||||||
|
require_once 'HTMLPurifier/URIParser.php';
|
||||||
|
|
||||||
|
class HTMLPurifier_URITest extends HTMLPurifier_URIHarness
|
||||||
|
{
|
||||||
|
|
||||||
|
function createURI($uri) {
|
||||||
|
$parser = new HTMLPurifier_URIParser();
|
||||||
|
return $parser->parse($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_construct() {
|
||||||
|
$uri1 = new HTMLPurifier_URI('HTTP', 'bob', 'example.com', '23', '/foo', 'bar=2', 'slash');
|
||||||
|
$uri2 = new HTMLPurifier_URI('http', 'bob', 'example.com', 23, '/foo', 'bar=2', 'slash');
|
||||||
|
$this->assertIdentical($uri1, $uri2);
|
||||||
|
}
|
||||||
|
|
||||||
|
var $oldRegistry;
|
||||||
|
|
||||||
|
function &setUpSchemeRegistryMock() {
|
||||||
|
$this->oldRegistry = HTMLPurifier_URISchemeRegistry::instance();
|
||||||
|
generate_mock_once('HTMLPurifier_URIScheme');
|
||||||
|
generate_mock_once('HTMLPurifier_URISchemeRegistry');
|
||||||
|
$registry =& HTMLPurifier_URISchemeRegistry::instance(
|
||||||
|
new HTMLPurifier_URISchemeRegistryMock()
|
||||||
|
);
|
||||||
|
return $registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
function &setUpSchemeMock($name) {
|
||||||
|
$registry =& $this->setUpSchemeRegistryMock();
|
||||||
|
$scheme_mock = new HTMLPurifier_URISchemeMock();
|
||||||
|
$registry->setReturnValue('getScheme', $scheme_mock, array($name, '*', '*'));
|
||||||
|
return $scheme_mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUpNoValidSchemes() {
|
||||||
|
$registry =& $this->setUpSchemeRegistryMock();
|
||||||
|
$registry->setReturnValue('getScheme', false, array('*', '*', '*'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function tearDownSchemeRegistryMock() {
|
||||||
|
HTMLPurifier_URISchemeRegistry::instance($this->oldRegistry);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_getSchemeObj() {
|
||||||
|
$scheme_mock =& $this->setUpSchemeMock('http');
|
||||||
|
|
||||||
|
$uri = $this->createURI('http:');
|
||||||
|
$scheme_obj = $uri->getSchemeObj($this->config, $this->context);
|
||||||
|
$this->assertIdentical($scheme_obj, $scheme_mock);
|
||||||
|
|
||||||
|
$this->tearDownSchemeRegistryMock();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_getSchemeObj_invalidScheme() {
|
||||||
|
$this->setUpNoValidSchemes();
|
||||||
|
|
||||||
|
$uri = $this->createURI('http:');
|
||||||
|
$result = $uri->getSchemeObj($this->config, $this->context);
|
||||||
|
$this->assertIdentical($result, false);
|
||||||
|
|
||||||
|
$this->tearDownSchemeRegistryMock();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_getSchemaObj_defaultScheme() {
|
||||||
|
$scheme = 'foobar';
|
||||||
|
|
||||||
|
$scheme_mock =& $this->setUpSchemeMock($scheme);
|
||||||
|
$this->config->set('URI', 'DefaultScheme', $scheme);
|
||||||
|
|
||||||
|
$uri = $this->createURI('hmm');
|
||||||
|
$scheme_obj = $uri->getSchemeObj($this->config, $this->context);
|
||||||
|
$this->assertIdentical($scheme_obj, $scheme_mock);
|
||||||
|
|
||||||
|
$this->tearDownSchemeRegistryMock();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_getSchemaObj_invalidDefaultScheme() {
|
||||||
|
$this->setUpNoValidSchemes();
|
||||||
|
$this->config->set('URI', 'DefaultScheme', 'foobar');
|
||||||
|
|
||||||
|
$uri = $this->createURI('hmm');
|
||||||
|
|
||||||
|
$this->expectError('Default scheme object "foobar" was not readable');
|
||||||
|
$result = $uri->getSchemeObj($this->config, $this->context);
|
||||||
|
$this->assertIdentical($result, false);
|
||||||
|
|
||||||
|
$this->tearDownSchemeRegistryMock();
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertToString($expect_uri, $scheme, $userinfo, $host, $port, $path, $query, $fragment) {
|
||||||
|
$uri = new HTMLPurifier_URI($scheme, $userinfo, $host, $port, $path, $query, $fragment);
|
||||||
|
$string = $uri->toString();
|
||||||
|
$this->assertIdentical($string, $expect_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_toString_full() {
|
||||||
|
$this->assertToString(
|
||||||
|
'http://bob@example.com:300/foo?bar=baz#fragment',
|
||||||
|
'http', 'bob', 'example.com', 300, '/foo', 'bar=baz', 'fragment'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_toString_scheme() {
|
||||||
|
$this->assertToString(
|
||||||
|
'http:',
|
||||||
|
'http', null, null, null, '', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_toString_authority() {
|
||||||
|
$this->assertToString(
|
||||||
|
'//bob@example.com:8080',
|
||||||
|
null, 'bob', 'example.com', 8080, '', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_toString_path() {
|
||||||
|
$this->assertToString(
|
||||||
|
'/path/to',
|
||||||
|
null, null, null, null, '/path/to', null, null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_toString_query() {
|
||||||
|
$this->assertToString(
|
||||||
|
'?q=string',
|
||||||
|
null, null, null, null, '', 'q=string', null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_toString_fragment() {
|
||||||
|
$this->assertToString(
|
||||||
|
'#fragment',
|
||||||
|
null, null, null, null, '', null, 'fragment'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertValidation($uri, $expect_uri = true) {
|
||||||
|
if ($expect_uri === true) $expect_uri = $uri;
|
||||||
|
$uri = $this->createURI($uri);
|
||||||
|
$result = $uri->validate($this->config, $this->context);
|
||||||
|
if ($expect_uri === false) {
|
||||||
|
$this->assertFalse($result);
|
||||||
|
} else {
|
||||||
|
$this->assertTrue($result);
|
||||||
|
$this->assertIdentical($uri->toString(), $expect_uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_validate_overlongPort() {
|
||||||
|
$this->assertValidation('http://example.com:65536', 'http://example.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_validate_zeroPort() {
|
||||||
|
$this->assertValidation('http://example.com:00', 'http://example.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_validate_invalidHostThatLooksLikeIPv6() {
|
||||||
|
$this->assertValidation('http://[2001:0db8:85z3:08d3:1319:8a2e:0370:7334]', 'http:');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -79,6 +79,7 @@ $test_files[] = 'HTMLPurifier/GeneratorTest.php';
|
|||||||
$test_files[] = 'HTMLPurifier/HTMLDefinitionTest.php';
|
$test_files[] = 'HTMLPurifier/HTMLDefinitionTest.php';
|
||||||
$test_files[] = 'HTMLPurifier/HTMLModuleManagerTest.php';
|
$test_files[] = 'HTMLPurifier/HTMLModuleManagerTest.php';
|
||||||
$test_files[] = 'HTMLPurifier/HTMLModuleTest.php';
|
$test_files[] = 'HTMLPurifier/HTMLModuleTest.php';
|
||||||
|
$test_files[] = 'HTMLPurifier/HTMLModule/RubyTest.php';
|
||||||
$test_files[] = 'HTMLPurifier/HTMLModule/ScriptingTest.php';
|
$test_files[] = 'HTMLPurifier/HTMLModule/ScriptingTest.php';
|
||||||
$test_files[] = 'HTMLPurifier/HTMLModule/TidyTest.php';
|
$test_files[] = 'HTMLPurifier/HTMLModule/TidyTest.php';
|
||||||
$test_files[] = 'HTMLPurifier/IDAccumulatorTest.php';
|
$test_files[] = 'HTMLPurifier/IDAccumulatorTest.php';
|
||||||
@ -102,8 +103,15 @@ $test_files[] = 'HTMLPurifier/Strategy/RemoveForeignElements_ErrorsTest.php';
|
|||||||
$test_files[] = 'HTMLPurifier/Strategy/ValidateAttributesTest.php';
|
$test_files[] = 'HTMLPurifier/Strategy/ValidateAttributesTest.php';
|
||||||
$test_files[] = 'HTMLPurifier/TagTransformTest.php';
|
$test_files[] = 'HTMLPurifier/TagTransformTest.php';
|
||||||
$test_files[] = 'HTMLPurifier/TokenTest.php';
|
$test_files[] = 'HTMLPurifier/TokenTest.php';
|
||||||
|
$test_files[] = 'HTMLPurifier/URIDefinitionTest.php';
|
||||||
|
$test_files[] = 'HTMLPurifier/URIFilter/DisableExternalTest.php';
|
||||||
|
$test_files[] = 'HTMLPurifier/URIFilter/DisableExternalResourcesTest.php';
|
||||||
|
$test_files[] = 'HTMLPurifier/URIFilter/HostBlacklistTest.php';
|
||||||
|
$test_files[] = 'HTMLPurifier/URIFilter/MakeAbsoluteTest.php';
|
||||||
|
$test_files[] = 'HTMLPurifier/URIParserTest.php';
|
||||||
$test_files[] = 'HTMLPurifier/URISchemeRegistryTest.php';
|
$test_files[] = 'HTMLPurifier/URISchemeRegistryTest.php';
|
||||||
$test_files[] = 'HTMLPurifier/URISchemeTest.php';
|
$test_files[] = 'HTMLPurifier/URISchemeTest.php';
|
||||||
|
$test_files[] = 'HTMLPurifier/URITest.php';
|
||||||
$test_files[] = 'HTMLPurifierTest.php';
|
$test_files[] = 'HTMLPurifierTest.php';
|
||||||
|
|
||||||
if (version_compare(PHP_VERSION, '5', '>=')) {
|
if (version_compare(PHP_VERSION, '5', '>=')) {
|
||||||
|
Reference in New Issue
Block a user