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.

Comments

mpdonadio’s picture

Status: Active » Needs review
StatusFileSize
new1.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
StatusFileSize
new2.37 KB
new3.63 KB
new2.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
StatusFileSize
new5.09 KB
new1.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

StatusFileSize
new4.44 KB
new1.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
StatusFileSize
new4.44 KB
new801 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
StatusFileSize
new35.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.