From b3e5e3a60c1b08b618d93aca99608b3a26d778fe Mon Sep 17 00:00:00 2001
From: Mac_Weber <Mac_Weber@789986.no-reply.drupal.org>
Date: Wed, 15 Jun 2016 11:05:43 -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 +++++
 .../LinkExternalProtocolsConstraintValidator.php           | 14 ++++++++++++--
 .../LinkExternalProtocolsConstraintValidatorTest.php       |  2 ++
 3 files changed, 19 insertions(+), 2 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..5c3da90 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..70f4372 100644
--- a/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidator.php
+++ b/core/modules/link/src/Plugin/Validation/Constraint/LinkExternalProtocolsConstraintValidator.php
@@ -39,9 +39,19 @@ public function validate($value, Constraint $constraint) {
       catch (\InvalidArgumentException $e) {
         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()) {
+        $allowed_protocols = UrlHelper::getAllowedProtocols();
+        $parsed_url = parse_url($url->getUri(), PHP_URL_SCHEME);
+        $has_untrusted_protocol = !in_array($parsed_url, $allowed_protocols);
+
+        // Protocol-relative URLs start with '//'.
+        $not_protocol_relative = strpos($url->getUri(), '//') !== 0;
+
+        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

