summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Net/OpenID/Consumer/Parse.php18
-rw-r--r--Tests/Net/OpenID/Parse.php168
-rw-r--r--Tests/Net/OpenID/linkparse.txt583
-rw-r--r--Tests/TestDriver.php1
4 files changed, 762 insertions, 8 deletions
diff --git a/Net/OpenID/Consumer/Parse.php b/Net/OpenID/Consumer/Parse.php
index b49d462..dbb05eb 100644
--- a/Net/OpenID/Consumer/Parse.php
+++ b/Net/OpenID/Consumer/Parse.php
@@ -61,13 +61,13 @@ function Net_OpenID_html_find()
function Net_OpenID_head_find()
{
- return Net_OpenID_tagMatcher('head');
+ return Net_OpenID_tagMatcher('head', array('body'));
}
-$_Net_OpenID_link_find = sprintf("/<link\b(?!:)[^\>]*>/%s",
- $_Net_OpenID_re_flags);
+$_Net_OpenID_attr_find = '\b(\w+)=("[^"]*"|\'[^\']*\'|[^\'"\s\/<>]+)';
-$_Net_OpenID_attr_find = '(\w+)=("[^"]*"|\'[^\']*\'|[^\s>]*)';
+$_Net_OpenID_link_find = sprintf("/<link\b(?!:)([^>]*)(?!<)>/%s",
+ $_Net_OpenID_re_flags);
$_Net_OpenID_entity_replacements = array(
'amp' => '&',
@@ -150,10 +150,12 @@ function Net_OpenID_parseLinkAttrs($html)
preg_match_all($_Net_OpenID_attr_find, $link, $attr_matches);
$link_attrs = array();
foreach ($attr_matches[0] as $index => $full_match) {
- $link_attrs[$attr_matches[1][$index]] =
- Net_OpenID_replace_entities(
- Net_OpenID_remove_quotes(
- $attr_matches[2][$index]));
+ $name = $attr_matches[1][$index];
+ $value = Net_OpenID_replace_entities(
+ Net_OpenID_remove_quotes(
+ $attr_matches[2][$index]));
+
+ $link_attrs[$name] = $value;
}
$link_data[] = $link_attrs;
}
diff --git a/Tests/Net/OpenID/Parse.php b/Tests/Net/OpenID/Parse.php
new file mode 100644
index 0000000..5d6c0a4
--- /dev/null
+++ b/Tests/Net/OpenID/Parse.php
@@ -0,0 +1,168 @@
+<?php
+
+/**
+ * Tests for the Consumer parsing functions.
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: See the COPYING file included in this distribution.
+ *
+ * @package OpenID
+ * @author JanRain, Inc. <openid@janrain.com>
+ * @copyright 2005 Janrain, Inc.
+ * @license http://www.gnu.org/copyleft/lesser.html LGPL
+ */
+
+require_once('Net/OpenID/Consumer/Parse.php');
+
+class Tests_Net_OpenID_Link extends PHPUnit_TestCase {
+ function Tests_Net_OpenID_Link($case)
+ {
+ list($desc, $markup, $links, $case_text) = $case;
+ $this->desc = $desc;
+ $this->markup = $markup;
+ $this->expected_links = $links;
+ $this->case_text = $case_text;
+ }
+
+ function getName()
+ {
+ return $this->desc;
+ }
+
+ function runTest()
+ {
+ $parsed = Net_OpenID_parseLinkAttrs($this->markup);
+ $i = 0;
+
+ foreach ($this->expected_links as $expected) {
+ list($is_optional_link, $expected_link) = $expected;
+ if ($is_optional_link &&
+ ($i >= count($parsed))) {
+ continue;
+ }
+
+ $act_link = $parsed[$i];
+
+ $increment = true;
+ foreach ($expected_link as $attr => $data) {
+ list($is_optional_attr, $value) = $data;
+
+ if ($is_optional_attr) {
+ $actual_value = null;
+ if (array_key_exists($attr, $act_link)) {
+ $actual_value = $act_link[$attr];
+ } else {
+ continue;
+ }
+ } else {
+ $actual_value = $act_link[$attr];
+ }
+
+ if ($is_optional_link &&
+ ($value != $actual_value)) {
+ $increment = false;
+ break;
+ }
+
+ $this->assertEquals($value, $actual_value);
+ }
+
+ if ($increment) {
+ $i++;
+ }
+ }
+
+ $this->assertEquals($i, count($parsed));
+ }
+}
+
+class NumTestCases extends PHPUnit_TestCase {
+ function NumTestCases($test_cases, $num_tests)
+ {
+ $this->test_cases = $test_cases;
+ $this->num_tests = $num_tests;
+ }
+
+ function runTest()
+ {
+ $this->assertEquals(count($this->test_cases),
+ $this->num_tests);
+ }
+}
+
+class Tests_Net_OpenID_Parse extends PHPUnit_TestSuite {
+
+ function parseLink($line)
+ {
+ $parts = explode(" ", $line);
+ $optional = intval($parts[0] == 'Link*:');
+ assert($optional || ($parts[0] == 'Link:'));
+
+ $attrs = array();
+ foreach (array_slice($parts, 1) as $attr) {
+ list($k, $v) = explode("=", $attr, 2);
+ if ($k[strlen($k) - 1] == '*') {
+ $attr_optional = 1;
+ $k = substr($k, 0, strlen($k) - 1);
+ } else {
+ $attr_optional = 0;
+ }
+
+ $attrs[$k] = array($attr_optional, $v);
+ }
+
+ return array($optional, $attrs);
+ }
+
+ function parseCase($s)
+ {
+ list($header, $markup) = explode("\n\n", $s, 2);
+ $lines = explode("\n", $header);
+ $name = array_shift($lines);
+ assert(strpos($name, 'Name: ') == 0);
+ $desc = substr($name, 6);
+ $parsed = array();
+ foreach ($lines as $line) {
+ $parsed[] = $this->parseLink($line);
+ }
+
+ return array($desc, $markup, $parsed);
+ }
+
+ function parseTests($s)
+ {
+ $tests = array();
+
+ $cases = explode("\n\n\n", $s);
+ $header = array_shift($cases);
+ list($tests_line, $unused) = explode("\n", $header, 2);
+ list($k, $v) = explode(": ", $tests_line);
+ assert($k == 'Num Tests');
+ $num_tests = intval($v);
+
+ foreach (array_slice($cases, 0, count($cases) - 1) as $case) {
+ list($desc, $markup, $links) = $this->parseCase($case);
+ $tests[] = array($desc, $markup, $links, $case);
+ }
+
+ return array($num_tests, $tests);
+ }
+
+ function Tests_Net_OpenID_Parse()
+ {
+ $here = realpath(dirname(__FILE__));
+ $test_data_file_name = $here . DIRECTORY_SEPARATOR . 'linkparse.txt';
+ $test_data = file_get_contents($test_data_file_name);
+
+ list($num_tests, $test_cases) = $this->parseTests($test_data);
+
+ $this->addTest(new NumTestCases($test_cases, $num_tests));
+
+ foreach ($test_cases as $case) {
+ $this->addTest(new Tests_Net_OpenID_Link($case));
+ }
+ }
+}
+
+?> \ No newline at end of file
diff --git a/Tests/Net/OpenID/linkparse.txt b/Tests/Net/OpenID/linkparse.txt
new file mode 100644
index 0000000..2206395
--- /dev/null
+++ b/Tests/Net/OpenID/linkparse.txt
@@ -0,0 +1,583 @@
+Num Tests: 72
+
+OpenID link parsing test cases
+Copyright (C) 2005-2006, JanRain, Inc.
+See COPYING for license information.
+
+File format
+-----------
+
+All text before the first triple-newline (this chunk) should be ignored.
+
+This file may be interpreted as Latin-1 or UTF-8.
+
+Test cases separated by three line separators (`\n\n\n'). The test
+cases consist of a headers section followed by a data block. These are
+separated by a double newline. The headers consist of the header name,
+followed by a colon, a space, the value, and a newline. There must be
+one, and only one, `Name' header for a test case. There may be zero or
+more link headers. The `Link' header consists of whitespace-separated
+attribute pairs. A link header with an empty string as a value
+indicates an empty but present link tag. The attribute pairs are `='
+separated and not quoted.
+
+Optional Links and attributes have a trailing `*'. A compilant
+implementation may produce this as output or may not. A compliant
+implementation will not produce any output that is absent from this
+file.
+
+
+Name: No link tag at all
+
+<html>
+<head>
+</head>
+</html>
+
+
+Name: Link element first
+
+<link>
+
+
+Name: Link inside HTML, not head
+
+<html>
+<link>
+
+
+Name: Link inside head, not html
+
+<head>
+<link>
+
+
+Name: Link inside html, after head
+
+<html>
+<head>
+</head>
+<link>
+
+
+Name: Link inside html, before head
+
+<html>
+<link>
+<head>
+
+
+Name: Link before html and head
+
+<link>
+<html>
+<head>
+
+
+Name: Link after html document with head
+
+<html>
+<head>
+</head>
+</html>
+<link>
+
+
+Name: Link inside html inside head, inside another html
+
+<html>
+<head>
+<html>
+<link>
+
+
+Name: Link inside html inside head
+
+<head>
+<html>
+<link>
+
+
+Name: link inside body inside head inside html
+
+<html>
+<head>
+<body>
+<link>
+
+
+Name: Link inside head inside head inside html
+
+<html>
+<head>
+<head>
+<link>
+
+
+Name: Link inside script inside head inside html
+
+<html>
+<head>
+<script>
+<link>
+</script>
+
+
+Name: Link inside comment inside head inside html
+
+<html>
+<head/>
+<link>
+
+
+Name: Link inside of head after short head
+
+<html>
+<head/>
+<head>
+<link>
+
+
+Name: Plain vanilla
+Link:
+
+<html>
+<head>
+<link>
+
+
+Name: Ignore tags in the <script:... > namespace
+Link*:
+
+<html>
+<head>
+<script:paddypan>
+<link>
+</script:paddypan>
+
+
+Name: Short link tag
+Link:
+
+<html>
+<head>
+<link/>
+
+
+Name: Spaces in the HTML tag
+Link:
+
+<html >
+<head>
+<link>
+
+
+Name: Spaces in the head tag
+Link:
+
+<html>
+<head >
+<link>
+
+
+Name: Spaces in the link tag
+Link:
+
+<html>
+<head>
+<link >
+
+
+Name: No whitespace
+Link:
+
+<html><head><link>
+
+
+Name: Closed head tag
+Link:
+
+<html>
+<head>
+<link>
+</head>
+
+
+Name: One good, one bad (after close head)
+Link:
+
+<html>
+<head>
+<link>
+</head>
+<link>
+
+
+Name: One good, one bad (after open body)
+Link:
+
+<html>
+<head>
+<link>
+<body>
+<link>
+
+
+Name: ill formed (missing close head)
+Link:
+
+<html>
+<head>
+<link>
+</html>
+
+
+Name: Ill formed (no close head, link after </html>)
+Link:
+
+<html>
+<head>
+<link>
+</html>
+<link>
+
+
+Name: Ignore random tags inside of html
+Link:
+
+<html>
+<delicata>
+<head>
+<title>
+<link>
+
+
+Name: case-folding
+Link*:
+
+<HtMl>
+<hEaD>
+<LiNk>
+
+
+Name: unexpected tags
+Link:
+
+<butternut>
+<html>
+<summer>
+<head>
+<turban>
+<link>
+
+
+Name: un-closed script tags
+Link*:
+
+<html>
+<head>
+<script>
+<link>
+
+
+Name: un-closed script tags (no whitespace)
+Link*:
+
+<html><head><script><link>
+
+
+Name: un-closed comment
+Link*:
+
+<html>
+<head>
+<!--
+<link>
+
+
+Name: un-closed CDATA
+Link*:
+
+<html>
+<head>
+<![CDATA[
+<link>
+
+
+Name: cdata-like
+Link*:
+
+<html>
+<head>
+<![ACORN[
+<link>
+]]>
+
+
+Name: comment close only
+Link:
+
+<html>
+<head>
+<link>
+-->
+
+
+Name: Vanilla, two links
+Link:
+Link:
+
+<html>
+<head>
+<link>
+<link>
+
+
+Name: extra tag, two links
+Link:
+Link:
+
+<html>
+<gold nugget>
+<head>
+<link>
+<link>
+
+
+Name: case-fold, body ends, two links
+Link:
+Link*:
+
+<html>
+<head>
+<link>
+<LiNk>
+<body>
+<link>
+
+
+Name: simple, non-quoted rel
+Link: rel=openid.server
+
+<html><head><link rel=openid.server>
+
+
+Name: short tag has rel
+Link: rel=openid.server
+
+<html><head><link rel=openid.server/>
+
+
+Name: short tag w/space has rel
+Link: rel=openid.server
+
+<html><head><link rel=openid.server />
+
+
+Name: extra non-attribute, has rel
+Link: rel=openid.server
+
+<html><head><link hubbard rel=openid.server>
+
+
+Name: non-attr, has rel, short
+Link: rel=openid.server
+
+<html><head><link hubbard rel=openid.server/>
+
+
+Name: non-attr, has rel, short, space
+Link: rel=openid.server
+
+<html><head><link hubbard rel=openid.server />
+
+
+Name: misplaced slash has rel
+Link: rel=openid.server
+
+<html><head><link / rel=openid.server>
+
+
+Name: quoted rel
+Link: rel=openid.server
+
+<html><head><link rel="openid.server">
+
+
+Name: single-quoted rel
+Link: rel=openid.server
+
+<html><head><link rel='openid.server'>
+
+
+Name: two links w/ rel
+Link: x=y
+Link: a=b
+
+<html><head><link x=y><link a=b>
+
+
+Name: non-entity
+Link: x=&y
+
+<html><head><link x=&y>
+
+
+Name: quoted non-entity
+Link: x=&y
+
+<html><head><link x="&y">
+
+
+Name: quoted entity
+Link: x=&
+
+<html><head><link x="&amp;">
+
+
+Name: entity not processed
+Link: x=&#26;
+
+<html><head><link x="&#26;">
+
+
+Name: &lt;
+Link: x=<
+
+<html><head><link x="&lt;">
+
+
+Name: &gt;
+Link: x=>
+
+<html><head><link x="&gt;">
+
+
+Name: &quot;
+Link: x="
+
+<html><head><link x="&quot;">
+
+
+Name: &amp;&quot;
+Link: x=&"
+
+<html><head><link x="&amp;&quot;">
+
+
+Name: mixed entity and non-entity
+Link: x=&"&hellip;>
+
+<html><head><link x="&amp;&quot;&hellip;&gt;">
+
+
+Name: mixed entity and non-entity (w/normal chars)
+Link: x=x&"&hellip;>x
+
+<html><head><link x="x&amp;&quot;&hellip;&gt;x">
+
+
+Name: broken tags
+Link*: x=y
+
+<html><head><link x=y<>
+
+
+Name: missing close pointy
+Link: z=y
+
+<html><head><link x=y<link z=y />
+
+
+Name: missing attribute value
+Link: x=y y*=
+Link: x=y
+
+<html><head><link x=y y=><link x=y />
+
+
+Name: Missing close pointy (no following)
+Link*: x=y
+
+<html><head><link x=y
+
+
+Name: Should be quoted
+Link: x*=<
+
+<html><head><link x="<">
+
+
+Name: Should be quoted (2)
+Link: x*=>
+
+<html><head><link x=">">
+
+
+Name: Repeated attribute
+Link: x=y
+
+<html><head><link x=z x=y>
+
+
+Name: Repeated attribute (2)
+Link: x=y
+
+<html><head><link x=y x=y>
+
+
+Name: Two attributes
+Link: x=y y=z
+
+<html><head><link x=y y=z>
+
+
+Name: Well-formed link rel="openid.server"
+Link: rel=openid.server href=http://www.myopenid.com/server
+
+<html>
+ <head>
+ <link rel="openid.server"
+ href="http://www.myopenid.com/server" />
+ </head>
+</html>
+
+
+Name: Well-formed link rel="openid.server" and "openid.delegate"
+Link: rel=openid.server href=http://www.myopenid.com/server
+Link: rel=openid.delegate href=http://example.myopenid.com/
+
+<html><head><link rel="openid.server"
+ href="http://www.myopenid.com/server" />
+ <link rel="openid.delegate" href="http://example.myopenid.com/" />
+</head></html>
+
+
+Name: from brian's livejournal page
+Link: rel=stylesheet href=http://www.livejournal.com/~serotta/res/319998/stylesheet?1130478711 type=text/css
+Link: rel=openid.server href=http://www.livejournal.com/openid/server.bml
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <link rel="stylesheet"
+ href="http://www.livejournal.com/~serotta/res/319998/stylesheet?1130478711"
+ type="text/css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta name="foaf:maker"
+ content="foaf:mbox_sha1sum '12f8abdacb5b1a806711e23249da592c0d316260'" />
+ <meta name="robots" content="noindex, nofollow, noarchive" />
+ <meta name="googlebot" content="nosnippet" />
+ <link rel="openid.server"
+ href="http://www.livejournal.com/openid/server.bml" />
+ <title>Brian</title>
+ </head>
+
+
+Name: non-ascii (Latin-1 or UTF8)
+Link: x=®
+
+<html><head><link x="®">
+
+
diff --git a/Tests/TestDriver.php b/Tests/TestDriver.php
index 6986f02..ea9ee95 100644
--- a/Tests/TestDriver.php
+++ b/Tests/TestDriver.php
@@ -136,6 +136,7 @@ $_test_names = array(
'HMACSHA1',
'Association',
'StoreTest',
+ 'Parse'
);
function selectTests($names)