Problem/Motivation

HtmlResponseAttachmentsProcessor::processHtmlHeadLink() has some problems producing the HTTP Link headers (see http://tools.ietf.org/html/rfc2068#section-19.6.2.4).

1) It produces invalid HTTP Link header. This because in this method the href attribute is unproperly escaped:

$href = '<' . Html::escape($attributes['href'] . '>');

It should be:

$href = '<' . Html::escape($attributes['href']) . '>';

2) It not take in account the separator (";") between link and link param

3) It allow only one Link header (while an entity may include multiple Link values), because it set the flag for replace the Link header instead of merge

$attached['http_header'][] = ['Link', $href . drupal_http_header_attributes($attributes), TRUE];<-- TRUE MEANS REPLACE

This means that only one link is added to headers. This cause a big difference between links in the html head and headers

Html head:

<link rel="shortcut icon" href="http://localhost/drupal8/core/misc/favicon.ico" type="image/vnd.microsoft.icon" />
<link rel="canonical" href="/drupal8/node/1" />
<link rel="shortlink" href="/drupal8/node/1" />
<link rel="delete-form" href="/drupal8/node/1/delete" />
<link rel="edit-form" href="/drupal8/node/1/edit" />
<link rel="version-history" href="/drupal8/node/1/revisions" />
<link rel="revision" href="/drupal8/node/1" />
<link rel="devel-render" href="/drupal8/node/1/devel/render" />
<link rel="devel-load" href="/drupal8/node/1/edit/devel" />

Headers:
Link:</drupal8/node/1/edit/devel> rel="devel-load"

Proposed resolution

Fix it

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

willzyx created an issue. See original summary.

willzyx’s picture

Status: Active » Needs review
FileSize
970 bytes
dawehner’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

IMHO bug fixes are pointless without tests :)

willzyx’s picture

Status: Needs work » Needs review
FileSize
1.19 KB
2.14 KB

dawehner, you are completely right :)
Added test coverage for nodes, let me know if we need more test coverage

The last submitted patch, 4: 2585899-4-test-only.patch, failed testing.

dawehner’s picture

+++ b/core/modules/node/src/Tests/NodeViewTest.php
@@ -34,6 +35,27 @@ public function testHtmlHeadLinks() {
+    $expected = [];
+    foreach ($node->uriRelationships() as $rel) {
+      $expected[] = '<' . Html::escape($node->url($rel)) . '>; rel="' . $rel . '"';
+      if ($rel == 'canonical') {
+        // Set the non-aliased canonical path as a default shortlink.
+        $expected[] = '<' . Html::escape($node->url($rel, ['alias' => TRUE])) . '>; rel="shortlink"';
+      }

For sure, this tests the functionality but it also feels like just a reimplementation of the actual code

willzyx’s picture

So are you suggesting to initialize the array with the expected value? something like this

    $expected = [
      '<' . Html::escape($node->url('canonical')) . '>; rel="canonical"',
      '<' . Html::escape($node->url('canonical'), ['alias' => TRUE]) . '>; rel="shortlink"',
      ....
    ];
dawehner’s picture

yeah that feels better, if you ask me.

willzyx’s picture

The last submitted patch, 9: 2585899-9-test-only.patch, failed testing.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

esod’s picture

Rerolled the patch since 2585899-9.patch won't apply to Drupal 8.2.x

esod’s picture

Status: Needs review » Needs work

The last submitted patch, 14: 2585899-13.patch, failed testing.

mr.baileys’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
802 bytes
2.03 KB

Some of the header links in the current patch's tests have been removed since the patch was created. See #2406533: edit-form, delete-form etc. <link> tags added on /node/{node} are invalid according to W3C Validator.

Rerolled without those links, tests should now pass. Removed the "Needs tests"-tag.

mr.baileys’s picture

dawehner’s picture

+++ b/core/modules/node/src/Tests/NodeViewTest.php
@@ -64,6 +66,24 @@ public function testHtmlHeadLinks() {
   /**
+   * Tests the Link header.
+   */
+  public function testLinkHeader() {
+    $node = $this->drupalCreateNode();

In an ideal world we would have a test which is more direct, aka. not be part of node module, as well, node module is just one of the users of the system

mr.baileys’s picture

Thanks @dawehner, added additional test coverage to the already existing HtmlResponseAttachmentsTest. No interdiff since the patch contains additional test coverage, no other changes were made to the previous patch.

The last submitted patch, 19: 2585899-19-test-only.patch, failed testing.

SchnWalter’s picture

I've tested the patch from #19 against 8.2.1 and it works properly.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Thank you for addressing that test location problem!

NickDickinsonWilde’s picture

Looks good to my browser/me

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/Render/HtmlResponseAttachmentsProcessor.php
@@ -419,9 +419,13 @@ protected function processHtmlHeadLink(array $html_head_link) {
+          $href .= ';' . $param;

I think for consistency this should be $href .= '; ' . $param;

Because of

function drupal_http_header_attributes(array $attributes = array()) {
  foreach ($attributes as $attribute => &$data) {
    if (is_array($data)) {
      $data = implode(' ', $data);
    }
    $data = $attribute . '="' . $data . '"';
  }
  return $attributes ? ' ' . implode('; ', $attributes) : '';
}

Everything else looks great.

mr.baileys’s picture

Status: Needs work » Needs review

@alexpott: drupal_http_header_attributes() already prefixes its return value with a space, so adding an additional one would result in 2 spaces between the link and the first param:

Link:</node/1>;  rel="shortlink"
Wim Leers’s picture

Very glad to see this being fixed!

esod’s picture

Patch #19 applies cleanly to our system. HtmlResponseAttachmentsTest passes on my local which runs on Apache. On our dev, which runs on nginx, HtmlResponseAttachmentsTest has 8 fails. At HTTP response header X-Drupal-Cache with value MISS (or HIT) found, actual value: neither MISS nor HIT is printing. Where do I look for MISS or HIT in the Response Headers?

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC per #25.

#27: that sounds like a local environment issue.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Thanks for responding to my concern @mr.baileys - and showing me it was unfounded.

Committed and pushed e24749a to 8.3.x and 5863276 to 8.2.x. Thanks!

Minor code style fix on commit:

diff --git a/core/modules/system/tests/modules/render_attached_test/src/Controller/RenderAttachedTestController.php b/core/modules/system/tests/modules/render_attached_test/src/Controller/RenderAttachedTestController.php
index 0e764f7..013f100 100644
--- a/core/modules/system/tests/modules/render_attached_test/src/Controller/RenderAttachedTestController.php
+++ b/core/modules/system/tests/modules/render_attached_test/src/Controller/RenderAttachedTestController.php
@@ -82,4 +82,5 @@ public function htmlHeaderLink() {
     $render['#attached']['html_head_link'][] = [['href' => '/foo/bar', 'hreflang' => 'nl', 'rel' => 'alternate'], TRUE];
     return $render;
   }
+
 }

  • alexpott committed ef5cb44 on 8.3.x
    Issue #2585899 by willzyx, mr.baileys, esod, dawehner:...
Wim Leers’s picture

Status: Fixed » Reviewed & tested by the community

Since this is a bug, I think it should also be cherry-picked to 8.2.x?

alexpott’s picture

Status: Reviewed & tested by the community » Fixed
Wim Leers’s picture

Oh weird, it's not showing up in this issue, only the 8.3.x commit is showing up, in #30 :(

Sorry!

esod’s picture

I'm seeing the commit in the 8.2.x branch, but not in drupal-8.2.2.tar.gz

alexpott’s picture

@esod it'll be in the next patch release of 8.2.x - that's 8.2.3 - 8.2.2 was released before this change was committed.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.