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.'); }