Problem/Motivation
In Drupal 7 the output of url() is always urlencoded (except for external URLs like url('http://examplecom')
) and a system path (input to url() and used for path alias sources) is never urlencoded
In Drupal 8 there are two bugs
The output of the url generator is *not* urlencoded when there is a path alias
The output of \Drupal\Core\Routing\UrlGenerator::getPathFromRoute()
*is* urlencoded (though usually this doesn't have any effect). The expected behavior is not documented or tested but I believe it should not be urlencoded.
To compare the output of a node path alias:
om+"<script>alert(99)</script>g.com
In D7:
<a href="/om%2B%22%3Cscript%3Ealert%2899%29%3C/script%3Eg.com">
in D8:
<a href="/om+"<script>alert(99)</script>g.com" rel="bookmark">
Proposed resolution
Discussed priority with alexpott and thus setting to major
Discussed possible resolution with Crell and dawehner
Change the internal code to
\Drupal\Core\Routing\UrlGenerator::doGenerate()/code> so that it does not urlencode or append the query string
Return value of UrlGenerator::getPathFromRoute() should not be urlencoded
Urlencode and append the query string in <code>\Drupal\Core\Routing\UrlGenerator::generateFromRoute()
after the path processors have acted
This fix can also fix #2507005: UrlGenerator:processPath() doesn't use altered query parameters
We can simplify the logic in \Drupal\Core\Routing\UrlGenerator::processPath()
since it won't have an appended query string
Remaining tasks
none
User interface changes
none
API changes
Since the expected return value of some methods is not clearly specified or tested, this may be a minor behavior change, but is not an API change.
The $options['query']
param for \Drupal\Core\Routing\UrlGenerator::generateFromRoute()
is documented as being an array and for url() in Drupal 7 could also only be passed as an array. However, the incorrect use of http_build_query() for the extremely rare case of a route with the option _no_path
param (in core only the '' and '' routes) means a string $options['query']
would have worked when generating a URL with no path prior to this fix, but not after.
Data model changes
none
Comment | File | Size | Author |
---|---|---|---|
#40 | increment-2809789-40.txt | 2.39 KB | pwolanin |
#40 | 2809789-40.patch | 24.07 KB | pwolanin |
#34 | 2809789--test-only-34.patch | 5.01 KB | pwolanin |
#31 | increment-2809789-31.txt | 865 bytes | pwolanin |
#31 | 2809789-31.patch | 23.86 KB | pwolanin |
Comments
Comment #2
pwolanin CreditAttribution: pwolanin as a volunteer commentedComment #3
pwolanin CreditAttribution: pwolanin as a volunteer commentedWe can also simplify the logic in \Drupal\Core\Routing\UrlGenerator::processPath() by never giving it a path with a query string
Comment #4
dawehnerThis is some of the tests from
Comment #5
pwolanin CreditAttribution: pwolanin as a volunteer commentedHere's a quick first pass at a patch - let's see if it breaks tests (might break unit tests)
Comment #6
pwolanin CreditAttribution: pwolanin as a volunteer commentedNR for bot
Comment #9
pwolanin CreditAttribution: pwolanin as a volunteer commentedCI error for test patch is
11:48:45 exception 'Drupal\simpletest\Exception\MissingGroupException' with message 'Missing @group annotation in Drupal\KernelTests\Core\Path\UrlAlterTest' in /var/www/html/core/modules/simpletest/src/TestDiscovery.php:351
Comment #10
pwolanin CreditAttribution: pwolanin as a volunteer commentedFixed kernel test - should run but fail on bot
Comment #11
dawehnerJust a small interdiff for peter
Comment #12
pwolanin CreditAttribution: pwolanin as a volunteer commentedThis patch combines the new test code from #10 plus my changes from #5 plus some of dawehner's test fixes from #2507005: UrlGenerator:processPath() doesn't use altered query parameters
Comment #14
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedFix to use UrlHelper::buildQuery() instead of http_build_query() and small fix from dawehner.
Also make query params modified by reference in every methods they need to be
Comment #17
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedSo silly - need to fix NullGenerator
Comment #18
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedNot sure why that worked before - the query option needs to be any array
Comment #20
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedThis is wrong - need to use the Drupal implementation from UrlHelper. Also we are passing too many params to it.
Comment #21
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedNeed to add some tests for urlaliases for paths that would get incorrectly encoded before
Comment #22
dawehnerMade a couple of changes:
Comment #23
dawehnerComment #25
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedI disagree - the query option was never supported as a string in 8.x. It documented on the method as only being an array and we made a very deliberate choice not to support strings. The bug where a string worked was also limited to only the case of a _no_path option, so not a common use.
Also, this looks like an unintended change?
Comment #26
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedComment #27
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedOk, here's a quick start on a test to show part of the bug - creating a path alias to a route path that has characters that are urlencoded will fail to match on outbound path processing and the alias lookup will fail.
Possibly could be writeen better with a data provider, or maybe as a kernel test, though I think there's some value to demonstrating the actual web request works.
The test-only patch is the same as the interdiff and will fail in the 2nd method at least.
Comment #30
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedAh, probably didn't account for the tests being run in a subdirectory - need to account for the fact the alias is the last part of the path, not necessarily the full path
Comment #31
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedI think this will fix the test fails with the patch (should still fail as test only)
Comment #34
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedoops - forgot to include the test module in the test-only patch
Comment #36
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedok, that shows one of the expected fails. Probably should convert to a kernel test and a data provider to better test a range of outbound path processing matching to find aliases
Comment #37
dawehnerFor me this looks really great. Luckily I'm not a subsystem maintainer of routing to decide about it :)
I guess we could get rid of this part of the code as well
nitpick: missing empty line / missing new line
Comment #38
catchJust nits, overall looks good.
Should use short array syntax.
Also when would $options['query'] not be an array? I'd expect we could add this to the += above.
What's a contexts base url?
Comment #39
dawehnerPersonally I think we should have a BC layer just to be sure, but well, @pwolanin has a different opinion here.
This is from code just moved around.
Comment #40
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commented@catch - the rest of the method is not using short array syntax, so using the long syntax is, I think, the correct code style until we do a mass conversion.
There was a bug fixed in the patch with a caller generating a link without a path passed in a string query option, despite the fact that even Drupal 7 only supports passing it as an array. I am sad and perplexed that the various could slipped in treat is as string again. I strongly oppose supporting a string query param which was not valid in even in Drupal 7.
Patch fixes minor problems noted above.
Comment #41
dawehnerWhat about supporting a string and throwing
@trigger_error('', E_USER_DEPRECATED)
in this case? This makes it really explicit without breaking potential code.Comment #42
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedComment #43
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedComment #44
dawehnerThank you for documenting the BC break. A agree, the
_no_path
"API break" is really just a bugfixComment #45
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedComment #47
catchCommitted 3a8b4ee and pushed to 8.3.x. Thanks!
I don't really like this for 8.2.x without the bc layer for string query arguments - yes it's not officially supported, but if a module is relying on it, we don't want a patch release update to start spitting errors. I'm fine if we just leave this in 8.3.x though so leaving fixed there. Re-open if you want to discuss for 8.2.x of course.
Comment #48
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedI think it's important to have this fix in 8.2.x also since the incorrectly encoded aliases can cause a number of problems.
Moving back to 8.2.x per discussion with catch in IRC
Comment #49
catch#41 needs answering a bit more conclusively for me - i.e. can we put it in the issue summary/a change record at least?
Comment #50
tuutti CreditAttribution: tuutti as a volunteer and commentedThis might have caused some issues with Block UI: #2822082: Form redirect broken when saving a new block instanceComment #51
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commented@catch - ok, I thought it was already in the issue summary? I can certainly make a change record
Comment #52
catch@tuutti looks like that's a duplicate of #2794559: [regression] After placing a block and saving, you are directed to the block library (example: admin/structure/block/library/bartik) rather than to the block layout which predates this issue.
Comment #53
xjmI'm also very hesitant to commit this to 8.2.x. I'd prefer not to if we can avoid it.
Edit: We should still add a CR either way. Thanks!
Comment #54
dawehnerGiven #2794559-15: [regression] After placing a block and saving, you are directed to the block library (example: admin/structure/block/library/bartik) rather than to the block layout I'm actually quite sure we should revert stuff.
Comment #55
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commented@Dawhener - I don't think this change is related, since it seems to be a preexisitng bug in 8.2
@xjm - I will add a change record, but we do need this for 8.2.
@catch - what else is needed in the issue summary?
Comment #56
xjmI need clarification here; does this issue need revert because of the regression or did reverting #2745911: Block add links should respect destination address the issue? Hopefully the latter?
Comment #60
pwolanin CreditAttribution: pwolanin as a volunteer and at SciShield commentedAdding draft change record, setting to NR for change record.
Comment #61
mlncn CreditAttribution: mlncn at Agaric for Drutopia commentedChange record approved!