Problem/Motivation

#2417647: Add leading slash to paths within 'user-path:' URIs, to allow 'user-path:' URIs to point to the <none> route altered the URI scheme for user-path to use a leading slash, but the code doesn't actually check for the leading slash. This can cause very wierd behavior, eg

Url::fromUri('user-path:foo/bar')->toString();

will just swallow the 'f' and produce '/oo/bar'

Proposed resolution

Check the the slash, otherwise throw an exception.

Remaining tasks

None.

User interface changes

None.

API changes

None.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

mpdonadio’s picture

Status: Active » Needs review
FileSize
1.84 KB

First pass at a patch w/ a test.

Wim Leers’s picture

I independently cross-rolled this patch yesterday.

Near identical.

May the reviewers choose which they prefer :)

Wim Leers’s picture

Title: Url::fromUrl('user-path:/') doesn't actually check for the leading slash » Url::fromUrl('user-path:/') should throw an exception when a path component without a slash is given

Clarifying title; no leading slash is fine if no path component is specified in the URI. I.e. these are all valid:

  • user-path:#foo
  • user-path:?foo=bar#baz

And none of them have a leading slash.

xjm’s picture

Yep we added the validation for that in #2417567: Rename user-path: scheme to internal:, and I was also thinking it should happen with the scheme generally, rather than at the wrapper level.

xjm’s picture

Status: Needs review » Needs work
xjm’s picture

Assigned: Unassigned » xjm

Adding that coverage.

mpdonadio’s picture

Wim's exception message is better, and will point the developer to how to actually fix the problem.

xjm’s picture

Assigned: xjm » Unassigned
Status: Needs work » Needs review
FileSize
2.37 KB
3.63 KB
2.62 KB

Here's that extended test coverage. Note that I've done this:

    $url = Url::fromUri('user-path:' . $path);

...in the hope of reusing the data providers for tests for fromUserInput() (see #2417567: Rename user-path: scheme to internal:).

xjm’s picture

+++ b/core/tests/Drupal/Tests/Core/UrlTest.php
@@ -637,6 +637,78 @@ public function providerTestToUriStringForUserPath() {
+   * Tests the fromUri() method with an invalid entity: URI.
+   *
+   * @covers ::fromUri
+   * @dataProvider providerFromValidUserPathUri
+   */
+  public function testFromValidUserPathUri($path) {
+    $url = Url::fromUri('user-path:' . $path);
+    $this->assertInstanceOf('Drupal\Core\Url', $url);
+  }

The docblock should say "valid" here rather than "invalid". :P

The last submitted patch, 8: 2423579-7-FAIL.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 8: 2423579-7.patch, failed testing.

mpdonadio’s picture

Assigned: Unassigned » mpdonadio

I should have time to look at this tonight, though it wasn't apparent from a quick look where those exceptions are really coming from.

mpdonadio’s picture

Assigned: mpdonadio » Unassigned
Status: Needs work » Needs review
FileSize
5.09 KB
1.96 KB

Here is a patch. It makes it green. However, I think this is really a bug in LinkWidget.

Read LinkWidget::validateUriElement() after the patch has been applied. I have verified that the `if` on line 155 evaluates to TRUE, but since there isn't a return, it happily continues onward, and then barfs on the `Url::fromUri($uri)` on line 165. However, the exception is coming from the one that we throw in this patch.

If people agree, I will post an issue and fix it.

Wim Leers’s picture

Agreed:

  1. +++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
    @@ -154,13 +154,20 @@ public static function validateUriElement($element, FormStateInterface $form_sta
    +      // Why isn't there a return here?
    

    That's a great, great question. Let's do that.

  2. +++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
    @@ -154,13 +154,20 @@ public static function validateUriElement($element, FormStateInterface $form_sta
    -      $url = Url::fromUri($uri);
    +      try {
    +        $url = Url::fromUri($uri);
    +      }
    +      catch (\InvalidArgumentException $e) {
    +        $form_state->setError($element, t("The path '@link_path' is either invalid or you do not have access to it.", ['@link_path' => static::getUriAsDisplayableString($uri)]));
    +        return;
    +      }
    

    These changes are also being made over at #2419693: Move URI access validation from widget to field constraint — you discovered exactly the same problem here.

mpdonadio’s picture

FileSize
4.44 KB
1.48 KB

OK, if we add the return we don't need the try/catch, and LinkFieldTest passes locally for me b/c ::setError() keeps the first error message. Is this still in scope for this issue?

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community

Awesome! Just one super silly typo :P But marking RTBC, because that can easily be fixed on commit.

+++ b/core/tests/Drupal/Tests/Core/UrlTest.php
@@ -637,6 +637,78 @@ public function providerTestToUriStringForUserPath() {
+   * Tests the fromUri() method with a valid entity: URI.
...
+   * Tests the fromUri() method with an invalid entity: URI.

s/entity:/user-path:/

heilop’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +LatinAmerica2015

I am working and fixing #16

heilop’s picture

Status: Needs work » Needs review
FileSize
4.44 KB
801 bytes

I replaced entity: with user-path: Tests the fromUri() in this two methods documents.

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community

Thanks! :)

webchick’s picture

Status: Reviewed & tested by the community » Fixed
FileSize
35.97 KB

My one worry with this patch was that this developer-oriented exception message would leak its way out into "user space" but that doesn't seem to be the case:

plain-english message that says paths need to start with leading slash

Therefore, looks good! Committed and pushed to 8.0.x. Thanks!

  • webchick committed 47cd92b on 8.0.x
    Issue #2423579 by mpdonadio, xjm, heilop, Wim Leers, webchick: Url::...
mpdonadio’s picture

And congrats to @heilop, as this looks like his first Drupal 8 commit!

Wim Leers’s picture

#20: Indeed it doesn't, that would indeed be unacceptable. Validation callback + constraints are responsible for what you see in the UI. Do we ever really show PHP-level exception to the end user? I can't think of any place where we do that. I sure hope we don't :P

xjm’s picture

Status: Fixed » Closed (fixed)

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