diff --git a/core/modules/openid/openid.inc b/core/modules/openid/openid.inc
index a0549ee..bd9d000 100644
--- a/core/modules/openid/openid.inc
+++ b/core/modules/openid/openid.inc
@@ -371,24 +371,36 @@ function _openid_nonce() {
* Pull the href attribute out of an html link element.
*/
function _openid_link_href($rel, $html) {
- $rel = preg_quote($rel);
- preg_match('||iUs', $html, $matches);
- if (isset($matches[3])) {
- preg_match('|href=["\']([^"]+)["\']|iU', $matches[3], $href);
- return trim($href[1]);
+ $html_dom = new DOMDocument();
+ if (@$html_dom->loadHTML($html)) {
+ $html_element = simplexml_import_dom($html_dom);
+ if (isset($html_element->head->link)) {
+ foreach ($html_element->head->link as $link) {
+ // The rel attribute contains a space-separated list of case-insensitive
+ // link types.
+ if (preg_match('@(?:\s|^)' . preg_quote($rel, '@') . '(?:\s|$)@i', $link['rel'])) {
+ return trim($link['href']);
+ }
+ }
+ }
}
return FALSE;
}
/**
- * Pull the http-equiv attribute out of an html meta element
+ * Pull the content attribute out of an X-XRDS-Location meta http-equiv element.
*/
-function _openid_meta_httpequiv($equiv, $html) {
- preg_match('||iUs', $html, $matches);
- if (isset($matches[1])) {
- preg_match('|content=["\']([^"]+)["\']|iUs', $matches[1], $content);
- if (isset($content[1])) {
- return $content[1];
+function _openid_meta_httpequiv($html) {
+ $html_dom = new DOMDocument();
+ if (@$html_dom->loadHTML($html)) {
+ $html_element = simplexml_import_dom($html_dom);
+ if (isset($html_element->head->meta)) {
+ foreach ($html_element->head->meta as $meta) {
+ // The http-equiv attribute is case-insensitive.
+ if (strtolower(trim($meta['http-equiv'])) == 'x-xrds-location') {
+ return trim($meta['content']);
+ }
+ }
}
}
return FALSE;
diff --git a/core/modules/openid/openid.module b/core/modules/openid/openid.module
index ed02891..f2aa766 100644
--- a/core/modules/openid/openid.module
+++ b/core/modules/openid/openid.module
@@ -517,7 +517,7 @@ function _openid_xrds_discovery($claimed_id) {
}
else {
// Look for meta http-equiv link in HTML head
- $xrds_url = _openid_meta_httpequiv('X-XRDS-Location', $result->data);
+ $xrds_url = _openid_meta_httpequiv($result->data);
}
if (!empty($xrds_url)) {
$headers = array('Accept' => 'application/xrds+xml');
diff --git a/core/modules/openid/tests/openid_test.module b/core/modules/openid/tests/openid_test.module
index 629dcd3..3cb2dcc 100644
--- a/core/modules/openid/tests/openid_test.module
+++ b/core/modules/openid/tests/openid_test.module
@@ -181,7 +181,7 @@ function openid_test_yadis_http_equiv() {
$element = array(
'#tag' => 'meta',
'#attributes' => array(
- 'http-equiv' => 'X-XRDS-Location',
+ 'http-equiv' => "X-XRDS-Location\n",
'content' => url('openid-test/yadis/xrds', array('absolute' => TRUE)),
),
);
@@ -202,7 +202,8 @@ function openid_test_html_openid1() {
* Menu callback; regular HTML page with OpenID 2.0 element.
*/
function openid_test_html_openid2() {
- drupal_add_html_head_link(array('rel' => 'openid2.provider', 'href' => url('openid-test/endpoint', array('absolute' => TRUE))));
+ // Use unusual values in order to test proper parsing of HTML attributes.
+ drupal_add_html_head_link(array('rel' => "foo\nopenid2.PROVIDER\tbar", 'href' => "\n" . url('openid-test/endpoint', array('absolute' => TRUE))));
drupal_add_html_head_link(array('rel' => 'openid2.local_id', 'href' => 'http://example.com/html-openid2'));
return t('This page includes a <link rel=...> element containing the URL of an OpenID Provider Endpoint.');
}