Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Anonymous’s picture

Status: Active » Postponed (maintainer needs more info)

You can add a relative URL (relative to DocumentRoot) or an absolute URL with full scheme. How do you resolve the relative scheme to a full scheme in a menu link? You can't so this seems to work as designed to me.

Hawk777’s picture

The proper way to render this URI:

//drupal.org/

is with this HTML:

<a href="//drupal.org/">link text</a>

This is a scheme-relative (aka protocol-relative, aka network-path-reference) URI. It is not an absolute URI, and it is not a document-root-relative URI. Section 5 of RFC 2396 states that "A relative reference beginning with two slash characters is termed a network-path reference, as defined by in Section 3. Such references are rarely used.". The BNF in that same RFC defines absoluteURI as scheme, colon, (hier_part|opaque_part). Hier_part is defined as (net_path|abs_path)[?query]. Net_path is defined as //authority[abs_path]. Working backwards along the BNF, this means net_path is literally just the URI (excluding query string, since that's part of the relativeURI nonterminal) minus the scheme and colon.

The proper interpretation of a net_path relative URI is that the scheme is taken from the base URI and everything else—both authority (hostname), path, query string, and so on—are taken from the relative URI.

This URI format is supported by all modern browsers and is exceedingly useful to construct links between different hostnames while neither gaining nor losing HTTPS (that is, an HTTPS page will link to an HTTPS target while an HTTP page will link to an HTTP target) and has been recommended by a number of people as a useful way to construct exactly this type of link. It can also be used in JavaScript or CSS cross-domain references, for example to load something like Google Analytics code from Google's HTTP server (for higher performance) when the containing page was loaded over HTTP, but from Google's HTTPS server (to avoid mixed content) when the containing page was loaded over HTTPS.

Alternatively, I could just ask for the menu system to support a format that allows inserting the "s" in an absolute URI at render time, but that seems like an utter waste of effort given that network-path reference relative URIs exist and do the job just fine—if only I were allowed to type one in!

Thanks for the consideration.

rbayliss’s picture

Version: 7.15 » 8.x-dev
FileSize
1.59 KB

Yes, please. A side effect of this is letting l() and url() use scheme-relative links too. This would need to be applied to Drupal 8 first, then backported.

This will need a security review.

rbayliss’s picture

Status: Postponed (maintainer needs more info) » Needs review
attiks’s picture

nice work, can you add tests?

rbayliss’s picture

Sure. In doing so, I realized that support also needs to be added to valid_url(), so I made that change as well.

tim.plunkett’s picture

Here is a reroll and a backport.

Jody Lynn’s picture

This is an issue beyond menu items. I ran into it using a scheme-relative path for a CDN. It's an issue in D6 as well.

Jody Lynn’s picture

Patch for D6 (Since the botched D7 upgrade I can't add a patch?)

diff --git a/includes/common.inc b/includes/common.inc
index 7ef1e51..f4c2d03 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -1471,7 +1471,8 @@ function url($path = NULL, $options = array()) {
     // Only call the slow filter_xss_bad_protocol if $path contains a ':' before
     // any / ? or #.
     $colonpos = strpos($path, ':');
-    $options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path));
+    $slashpos = (strpos($path, '//') === 0);
+    $options['external'] = (($colonpos !== FALSE  || $slashpos !== FALSE) && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path));
   }

   // May need language dependent rewriting if language.inc is present.
tim.plunkett’s picture

Title: Scheme-relative URL in menu item rejected » Scheme-relative URL rejected by validation
Issue summary: View changes
+++ b/core/modules/system/lib/Drupal/system/Tests/Common/UrlTest.php
@@ -290,4 +290,37 @@ function testExternalUrls() {
+  public function testSchemeRelativeUrls() {

Yes, this tests it beyond menu specific code.

(For uploading patches, edit the issue node)

Jody Lynn’s picture

Thanks Tim. I am running both the D6 patch and the D7 patch in production. It allows me to use relative schemas with a CDN.

Dave Reid’s picture

Issue tags: +Protocol-relative
tim.plunkett’s picture

It seems that #2195983: Support scheme-relative URLs is a more invasive change for D8 to do the same thing. If that indeed goes in, this can just be marked back to D7.

jhedstrom’s picture

Issue tags: +Needs reroll

Either this or the issue linked in ##1 need a reroll for 8.x.

Status: Needs review » Needs work

The last submitted patch, 7: schema-relative-1783278-7-D8.patch, failed testing.

redndahead’s picture

Re-roll for d7. Part of this patch went into core with the security release. Not sure if tests are needed anymore since some tests went in with that patch. I left them in just in case.

If it wasn't for the tests this would be a one line patch. So it's greatly simplified.

Jody Lynn’s picture

The comment doesn't make sense: "# Look for ftp, http, http, feed or scheme relative schemes"

kerby70’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
FileSize
7.21 KB
12.71 KB

Reroll for D8 attached.

Status: Needs review » Needs work

The last submitted patch, 19: scheme_relative_url-1783278-19-D8.patch, failed testing.

jhedstrom’s picture

Assigned: Unassigned » jhedstrom

Note that after #2455083: Open redirect fixes from SA-CORE-2015-001 need to be ported to Drupal 8 went in, UrlHelper::isExternal() now always treats urls starting with // as external, so this patch needs to take that into account.

I'm going to see if I can get this working.

jhedstrom’s picture

Status: Needs review » Needs work

The last submitted patch, 22: scheme-relative-urls-1783278-22.patch, failed testing.

jhedstrom’s picture

Status: Needs work » Needs review
FileSize
4.5 KB
6.94 KB

This should fix the failing tests.

mgifford’s picture

Status: Needs review » Needs work

Patch no longer applies.

Mac_Weber’s picture

Assigned: jhedstrom » Unassigned
Status: Needs work » Needs review
Related issues: +#2573635: Url::fromUri() should accept protocol-relative URLs
FileSize
617 bytes
7.89 KB

This will also help in other issues, such as: #2573635: Url::fromUri() should accept protocol-relative URLs

Rerolled and also added a test for a schema relative URL at UnroutedUrlTest.php

Mac_Weber’s picture

Component: menu system » routing system

I think this is a better component, as it affects other modules, too.

Mac_Weber’s picture

Maybe we need a bigger rewrite for this validation: #2691099: Improve external URL validation in many ways

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.

Wim Leers’s picture

Priority: Normal » Major
Issue tags: +Contributed project blocker

This will also help in other issues

Indeed. The CDN module for Drupal 8 will only do protocol-relative URLs, to avoid having to render everything twice: once for HTTP and once for HTTPS. And e.g. the image dialog in the text editor uses #type => managed_file, which uses #theme => file_link, which uses Url::fromUri()… and since that does not support protocol-relative URIs, it breaks.


  1. +++ b/core/lib/Drupal/Core/Url.php
    @@ -302,6 +302,10 @@ public static function fromUri($uri, $options = []) {
    +    if (empty($uri_parts['scheme']) &&  strpos($uri, '//') === 0) {
    

    Two spaces after &&.

  2. +++ b/core/lib/Drupal/Core/Url.php
    @@ -302,6 +302,10 @@ public static function fromUri($uri, $options = []) {
    +      $uri_parts['scheme'] = 'relative';
    

    Eh… that doesn't seem quite right.

  3. +++ b/core/modules/system/src/Tests/Common/UrlTest.php
    @@ -321,4 +321,37 @@ function testExternalUrls() {
    +    // Verify scheme-relative URL can contain a fragment.
    ...
    +    $this->assertEqual($url, $result, 'Scheme-relative URL with fragment works without a fragment in $options.');
    

    s/scheme/protocol/

    … because that is the accepted term.

  4. +++ b/core/tests/Drupal/Tests/Core/UnroutedUrlTest.php
    @@ -87,6 +87,8 @@ public function providerFromUri() {
    +      // A protocol relative URL.
    

    Missing dash.

  5. +++ b/core/tests/Drupal/Tests/Core/UnroutedUrlTest.php
    @@ -119,7 +121,6 @@ public function providerFromInvalidUri() {
           // Schemeless paths.
    ...
           // Schemeless path with a query string.
    

    s/Schemeless path/Relative URL/

Mac_Weber’s picture

@Wim Leers, really cool to know we are also helping the CDN module and other contribs here

Wim Leers’s picture

yobottehg’s picture

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

Composer patches just told me the patch does not longer apply on 8.1.2 so tagging and setting to needs work

yobottehg’s picture

Status: Needs work » Needs review
FileSize
7.07 KB

rebased on 8.1.x

Status: Needs review » Needs work

The last submitted patch, 34: system-schema_relative-1783278-34.patch, failed testing.

The last submitted patch, 34: system-schema_relative-1783278-34.patch, failed testing.

Wim Leers’s picture

Assigned: Unassigned » Wim Leers
  1. +++ b/core/lib/Drupal/Component/Utility/UrlHelper.php
    @@ -384,7 +384,7 @@ public static function isValid($url, $absolute = FALSE) {
    -        (?:ftp|https?|feed):\/\/                                # Look for ftp, http, https or feed schemes
    +        (?:ftp:|https?:|feed:)?\/\/                                # Look for ftp, http, https or feed schemes
    

    This is a problem that did not exist in #26.

  2. +++ b/core/tests/Drupal/Tests/Core/UrlTest.php
    @@ -294,6 +294,38 @@ public function testUrlFromRequestInvalid() {
    +    $this->assertEqual($url, $result, 'Scheme-relative URL with query string works without a query string in $options.');
    +    ¶
    

    Nor this.

Plus the patch is smaller now, which probably means some hunks were lost, which probably explains the failing tests.

This looks like a bad reroll. I'll do it over.

Wim Leers’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
FileSize
7.51 KB

Straight reroll of #26, with only one tiny trivial conflict.

Tests pass locally.

Wim Leers’s picture

Assigned: Wim Leers » Unassigned
Mac_Weber’s picture

@Wim Leers I see you did not apply your proposed changes at #30 and I was going to apply them myself, but I realize that at UrlHelperTest in many places it calls methods and variables 'scheme'. Changing everything there would be a big change and no reason for such, then I did not replace all strings 'scheme' by 'protocol as pointed on item 3, only the ones that makes more sense.

1- fixed.
2- I think it is right, why not?
3- not going to fix all entries, as commented above.
4- fixed.
5- These lines are not being patched and these comments are regarding invalid URLs, which makes sense to keep the comment as is.

dawehner’s picture

One thing I'm wondering, should absolute URLs generated in the HTML use a scheme relative URL by default?

+++ b/core/modules/menu_ui/src/Tests/MenuTest.php
index 062e3e4..1717114 100644
--- a/core/modules/system/src/Tests/Common/UrlTest.php

--- a/core/modules/system/src/Tests/Common/UrlTest.php
+++ b/core/modules/system/src/Tests/Common/UrlTest.php

+++ b/core/modules/system/src/Tests/Common/UrlTest.php
+++ b/core/modules/system/src/Tests/Common/UrlTest.php
@@ -317,4 +317,36 @@ function testExternalUrls() {

@@ -317,4 +317,36 @@ function testExternalUrls() {
     $this->assertEqual($url . '&' . http_build_query($query, '', '&'), $result);
   }
 
+  public function testSchemeRelativeUrls() {

Ideally we would adapt the unit test instead of this old web test

Wim Leers’s picture

One thing I'm wondering, should absolute URLs generated in the HTML use a scheme relative URL by default?

That's a very good question. Technically (well, pedantically to be pedantically precise) they're not an absolute URL anymore, but in practice that's how they behave. So I think this makes sense.
(Note that this would only affect local URLs that we render in an absolute manner. This would not affect external URLs. If it would, that'd result in problems, because we cannot know whether external URLs in fact support HTTP or HTTPS.)

Hawk777’s picture

I think absolute URLs generated in HTML specifically can probably all be made scheme-relative, but not necessarily all absolute URLs; specifically, I think scheme-relative URLs (like any other relative URLs) are probably not permitted in HTTP Location headers.

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.

dawehner’s picture

Status: Needs review » Needs work

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

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.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.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.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.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.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.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

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

DamienMcKenna’s picture

Version: 8.6.x-dev » 8.9.x-dev
Issue tags: +Needs reroll

Needs a reroll.

sashi.kiran’s picture

Reroll that applies to commit 2db400d0bc4fefb.

Below are the conflicts addressed:

drupal\core\lib\Drupal\Core\Url.php
<<<<<<< HEAD
// We support protocol-relative URLs.
if (strpos($uri, '//') === 0) {
$uri_parts['scheme'] = '';
}
elseif (empty($uri_parts['scheme'])) {
=======
// Support for scheme-relative URLs.
if (empty($uri_parts['scheme']) && strpos($uri, '//') === 0) {
$uri_parts['scheme'] = 'relative';
}
if (empty($uri_parts['scheme'])) {
>>>>>>> Applying patch from issue 1448e883d1a3 comment 400d0bc4fefb

drupal\core\tests\Drupal\Tests\Component\Utility\UrlHelperTest.php
<<<<<<< HEAD
$url_schemes = ['http', 'https', 'ftp'];
$data = [];
=======
$url_schemes = array('http://', 'https://', 'ftp://', '//');
$data = array();
>>>>>>> Applying patch from issue 1448e883d1a3 comment 400d0bc4fefb

drupal\core\tests\Drupal\Tests\Core\UnroutedUrlTest.php
<<<<<<< HEAD
$this->expectException(\InvalidArgumentException::class);
$url = Url::fromUri($uri);
=======
Url::fromUri($uri);
>>>>>>> Applying patch from issue 1448e883d1a3 comment 400d0bc4fefb

Reroll is done w.r.t 8.9.x

sashi.kiran’s picture

Issue tags: -Needs reroll +Needs review
ravi.shankar’s picture

Status: Needs work » Needs review
Issue tags: -Needs review

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

quietone’s picture

This is a duplicate of #2195983: Support scheme-relative URLs. In a comment-14 over there from Feb 2014 sun stated that that issue was the preferred solution "because it also removes that apparently hard-coded list of schemes in the preg_match() of isValid(), which has absolutely no business in there."

I'll work on combining the patches and post it over in the other issue and move credit etc.

quietone’s picture

Status: Needs review » Closed (duplicate)

Closing this as a duplicate of #219598: Query trying to use invalid field in node_access table despite the fact that this is the older issue. In that being the older issue in #14 sun states that the other solution is the preferred. "because it also removes that apparently hard-coded list of schemes in the preg_match() of isValid(), which has absolutely no business in there. :)"

The work here has been added to that patch over there and credit moved.