From a53ac01590c1dad58f3b16b7f30dc11b4b4c4dbe Mon Sep 17 00:00:00 2001
From: Mac_Weber <Mac_Weber@789986.no-reply.drupal.org>
Date: Tue, 14 Jun 2016 23:18:10 -0300
Subject: [PATCH] Issue #2744729 by Wim Leers, Mac_Weber, dawehner, lluvigne:
 Link field should accept protocol-relative URLs.

---
 .../link/src/Plugin/Field/FieldFormatter/LinkFormatter.php     |  5 +++++
 .../Constraint/LinkExternalProtocolsConstraintValidator.php    | 10 +++++++---
 .../LinkExternalProtocolsConstraintValidatorTest.php           |  2 ++
 3 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php
index 7d2d0ee..e0e7f4e 100644
--- a/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php
+++ b/core/modules/link/src/Plugin/Field/FieldFormatter/LinkFormatter.php
@@ -179,6 +179,11 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
       $url = $this->buildUrl($item);
       $link_title = $url->toString();
 
+      // If the external URL starts with '//', trim it.
+      if ($url->isExternal() && (strpos($url->getUri(), '//') == 0)) {
+        $link_title = ltrim($link_title, '//');
+      }
+
       // If the title field value is available, use it for the link text.
       if (empty($settings['url_only']) && !empty($item->title)) {
         // Unsanitized token replacement here because the entire link title
diff --git a/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidator.php b/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidator.php
index e85de58..8ffe7db 100644
--- a/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidator.php
+++ b/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidator.php
@@ -40,9 +40,13 @@ public function validate($value, Constraint $constraint) {
         return;
       }
       // Disallow external URLs using untrusted protocols.
-      if ($url->isExternal() && !in_array(parse_url($url->getUri(), PHP_URL_SCHEME), UrlHelper::getAllowedProtocols())) {
-        $this->context->addViolation($constraint->message, array('@uri' => $value->uri));
-      }
+     if ($url->isExternal()) {
+       $not_protocol_relative = strpos($url->getUri(), '//') != 0;
+       $has_untrusted_protocol = !in_array(parse_url($url->getUri(), PHP_URL_SCHEME), UrlHelper::getAllowedProtocols());
+       if ($not_protocol_relative && $has_untrusted_protocol) {
+         $this->context->addViolation($constraint->message, array('@uri' => $value->uri));
+       }
+     }
     }
   }
 
diff --git a/core/modules/link/tests/src/Unit/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidatorTest.php b/core/modules/link/tests/src/Unit/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidatorTest.php
index 771b307..c802bd7 100644
--- a/core/modules/link/tests/src/Unit/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidatorTest.php
+++ b/core/modules/link/tests/src/Unit/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidatorTest.php
@@ -50,6 +50,8 @@ public function providerValidate() {
     $data[] = ['http://www.drupal.org', TRUE];
     $data[] = ['https://www.drupal.org', TRUE];
     $data[] = ['magnet:?xt=urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C', TRUE];
+    // Protocol-relative URL.
+    $data[] = ['//www.drupal.org', TRUE];
 
     // Invalid protocols.
     $data[] = ['ftp://ftp.funet.fi/pub/standards/RFC/rfc959.txt', FALSE];
-- 
2.8.1

