Problem/Motivation
Originally, some work was started in #2430335: Browser language detection is not cache aware to resolve a caching issue. A language redirect was introduced, but the implementation was more general than just adding the language prefix. The target redirect URL was constructed from current route. This caused some test fails (especially, in case if this redirect is enabled always even if the language module is not installed, see 2430335#89). And this issue was created.
Current implementation
There is a new route_normalizer_request_subscriber service that perform redirects like the Global Redirect module. On a GET request, it construct a URL from the current route and the current route/query parameters, and redirects to that URL if it does not match the incoming URL. This causes:
- language redirect, for example from "/" to "/en", this resolves #2430335: Browser language detection is not cache aware
- path alias redirect, for example from "node/1" to "content/my-node"
- front page redirect, for example from "/node" to "/"
There can be more cases, but they are unknown at the moment.
Also, the patch contains some fixes for bugs caught during development, and some documentation changes.
Arguments for this feature:
- globalredirect has a lot of installations, people might need this feature in the core
- better SEO
- less cache entries
- it allows to catch bugs at early development stage (check the fixes provided in the patch)
Remaining tasks
- fix remaining test fails
+ write tests
- try to use CacheableRedirectResponse
User interface changes
The default Drupal installation will behave like the one having the Global Redirect module enabled.
API changes
The "disable_route_normalizer" request attribute can be set to disable the route normalization:
$request->attributes->set('disable_route_normalizer', TRUE);
Data model changes
none
Comment | File | Size | Author |
---|---|---|---|
#167 | diff_reroll_2641118_162-167.txt | 6.97 KB | ankithashetty |
#167 | 2641118-167.patch | 20.46 KB | ankithashetty |
#162 | 2641118-161.patch | 21.37 KB | JeroenT |
Comments
Comment #2
Leksat CreditAttribution: Leksat at Amazee Labs commentedA bit improved version of https://www.drupal.org/node/2430335#comment-10582334
Comment #4
Leksat CreditAttribution: Leksat at Amazee Labs commentedMoved back to system module.
Comment #6
Leksat CreditAttribution: Leksat at Amazee Labs commentedJust wanna be sure that Drupal installer tests fail because of the patch.
Comment #7
Leksat CreditAttribution: Leksat at Amazee Labs commentedOnly consider clean URLs.
Comment #9
Leksat CreditAttribution: Leksat at Amazee Labs commentedRestored http_build_query() in WebTestBase.
Comment #11
Leksat CreditAttribution: Leksat at Amazee Labs commentedTry to always use <current> route.
Comment #13
Leksat CreditAttribution: Leksat at Amazee Labs commentedFix SimpleTestBrowserTest.
Comment #15
Leksat CreditAttribution: Leksat at Amazee Labs commentedFix BrowserTest.
Comment #17
Leksat CreditAttribution: Leksat at Amazee Labs commentedUpdated UrlGenerator to fix MenuRouterTest. Let's see if this will make other tests fail.
Comment #19
Leksat CreditAttribution: Leksat at Amazee Labs commentedOkay, UrlGenerator worked absolutely correct. The real issue is that route parameters are double-decoded by the route-match code.
Comment #21
Leksat CreditAttribution: Leksat at Amazee Labs commentedComment #22
Leksat CreditAttribution: Leksat at Amazee Labs commentedComment #23
Leksat CreditAttribution: Leksat at Amazee Labs commented- fixed URL outbound processing in \Drupal\Core\Routing\UrlGenerator::processPath()
- disabled \Drupal\path\Tests\PathAliasTest::testPathCache()
Comment #25
Leksat CreditAttribution: Leksat at Amazee Labs commentedOkay, it seems that the previous approach is wrong. It looks like \Drupal\Core\PathProcessor\OutboundPathProcessorInterface::processOutbound() should process the URL-encoded path, but this is not stated in docs. At least \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationContentEntity::processOutbound() sometimes adds a query string to the path, which is possible only on the already URL-encoded path.
Comment #27
Leksat CreditAttribution: Leksat at Amazee Labs commentedIntroduced
disable_route_normalizer
request parameter andX-Drupal-Route-Normalizer
response header.Comment #29
Leksat CreditAttribution: Leksat at Amazee Labs commentedSome of these changes are nice-to-have but not required for this issue. Would be nice to get rid of them, but I don't remember which ones we need.
Comment #30
Leksat CreditAttribution: Leksat at Amazee Labs commentedHmm, I thought all patches will go for testing...
Comment #31
Leksat CreditAttribution: Leksat at Amazee Labs commentedOkay... Let's try one by one.
Comment #32
Leksat CreditAttribution: Leksat at Amazee Labs commentedWhat if I add another one right now... :)
Comment #33
Leksat CreditAttribution: Leksat at Amazee Labs commentedSeems to work!
Comment #34
Leksat CreditAttribution: Leksat at Amazee Labs commentedAnother one...
Comment #35
Leksat CreditAttribution: Leksat at Amazee Labs commentedAnd the last one.
Comment #41
Leksat CreditAttribution: Leksat at Amazee Labs commentedReverted unnecessary changes.
I promise to not use DrupalCI in the way I did above anymore! :)
Comment #43
Leksat CreditAttribution: Leksat at Amazee Labs commentedMoved the normalizer to the core. Updated docs/comments.
Comment #45
Leksat CreditAttribution: Leksat at Amazee Labs commentedFix book test.
Comment #46
Leksat CreditAttribution: Leksat at Amazee Labs commentedCool cool. Now we need tests.
Comment #47
Leksat CreditAttribution: Leksat at Amazee Labs commentedAlready wrote half of test cases. Assigning to me for now.
Comment #48
Leksat CreditAttribution: Leksat at Amazee Labs commentedWrote tests. During the process I found some additional places in docs where it was not specified that path is URL-encoded.
Comment #50
Leksat CreditAttribution: Leksat at Amazee Labs commentedIt works! Huh :)
Updated priority to major because this issue solves #2430335: Browser language detection is not cache aware
Comment #51
Leksat CreditAttribution: Leksat at Amazee Labs commentedComment #52
almaudoh CreditAttribution: almaudoh commentedshould be in 8.1.x since it's a feature request.
Comment #53
Leksat CreditAttribution: Leksat at Amazee Labs commentedAn attempt to make the issue summary more readable :)
Comment #54
Leksat CreditAttribution: Leksat at Amazee Labs commentedComment #55
Gábor HojtsyLeksat asked me to review on IRC. Just reviewing for API changes for now:
Why are these API changes needed.
Why was this change necessary?
Comment #56
Leksat CreditAttribution: Leksat at Amazee Labs commentedGabor, thanks for the review!
1. These are not API changes. I just updated docs so it's clear that path is URL-encoded. That how these methods were working, I did not touched them.
I stated "URL-encoded path" because in other places "path" mostly means a decoded path.
2. Previous behavior of this piece of code: if $options['query'] is array, it is set to the empty array in the "else" condition, so the query is lost.
Comment #57
Leksat CreditAttribution: Leksat at Amazee Labs commentedSince this is a new feature, it should go to the new major version. I see the upgrade process like this:
- route normalizer can be enabled/disabled from the UI (maybe a new config page under admin/config/search ?)
- route normalizer is enabled by default on >= 8.1.x installations
- route normalizer is disabled by default on sites upgraded from 8.0.x
Any opinions?
Comment #58
BerdirThis is an interesting approach. Wondering if we should also change the code in redirect.module to something like this if that covers all the cases there.
Would make it easier to remove the functionality there in case this gets into core.
One thing is that there are a lot of settings in redirect/globalredirect. Not sure if they're really needed if things work reliably.
There's a bug report open there right now about a special configuration with content language negotation being different that results in a loop. Might make sense to test that here as well.
should probably only do an invalidate of the rendered cache tag?
Comment #59
Leksat CreditAttribution: Leksat at Amazee Labs commented@Berdir, thanks for the review!
1. I'm not sure whether we need such test in the current issue. Currently we have 4 redirect test cases: front page, path alias, language, and path special characters. The language-redirect part is already the biggest one. I would not make it even bigger.
But I tested https://github.com/md-systems/redirect/issues/77 case manually with different interface/content language negotiation configurations. It works well.
2. Fixed, thanks!
Comment #61
Leksat CreditAttribution: Leksat at Amazee Labs commentedThis patch adds the following behavior:
1. On new Drupal installations, the route normalizer is enabled by default.
2. If Drupal installation is upgraded (say from 8.0.x), the route normalizer is disabled (because route_normalizer.enabled config setting is NULL) to not change the existing routing behavior.
3. Route normalizer can be enabled/disabled via the config change (for example, using drush) or config override (for example, via settings.php).
I have a lot of questions about this:
1) Do we need this at all?
2) Is that okay that route_normalizer_request_subscriber service is always registered, and that route_normalizer.enabled config setting is checked in the onKernelRequestRedirect()? For example, language module uses service provider to register its services.
3) Is it required to have UI for route_normalizer.enabled config setting?
Comment #62
Crell CreditAttribution: Crell as a volunteer commentedthat's set, not that set.
If the killswitch is a config object, then IMO a UI to enable/disable it is a must.
If there's no UI, then it should NOT use the config system but simply be a container parameter, set via the site's services.yml.
I can see a good argument for either approach, personally, but it should be one or the other.
IMO, this should be factored out to a protected shouldRedirect() method on this class, for cleanliness.
I believe direct use of the generator is discouraged at this point, as it bypasses caching metadata. Which of course begs the question of whether this should e a cacheable redirect or not. I think I'm leaning yes, as there's no case in which a subsequent request would not want the same redirect. Right?
-1 would be after routing has happened too.
I am overall +1 on the concept, although the implementation has me a bit concerned about performance. This adds another route generation call and event listenener to every request. It's also very aggressive; if anything might possibly have changed the URL, redirect. Should it be opt-in, rather than opt-out?
Also, even if we keep the kill switch on the request attributes it should be _-prefixed.
Berdir: I still think that redirect module would be better served by creating routes that all map to a single redirection controller rather than using a subscriber, so I don't know that the approach here would translate at all.
Comment #63
BerdirWe have lots of options in configuration without a UI and for example let contrib provide a UI for those that need it, so I don't agree with that argument. However, performance might be an argument. Loading a config is quite a bit of overhead, a container parameter is practically free.
However, not sure what to do about the upgrade path. The patch currently disables that option for existing sites, I don't see how we could do that with a container parameter?
About redirect module. Redirect 8.x-1.x merged in all the features from globalredirect, which isn't about specific redirects but about things like redirecting to the canonical path, removing trailing slashes and a few others. Which is exactly what this is doing.
For the manual redirects, using the router table is an interesting idea that's worth trying out, however, there are quite a few things to consider:
* There might be (tens of) thousands of redirects. Every cache clear or redirect change would have to write them all. I'm fairly sure that's a show-stopper.
* Redirects have features like being language-specific, can vary by query arguments, override actual routes. I guess we would have to use route filtering for that.
I tried my best to optimize it as much possible. We're doing a single, simple db query against just a hash + language. The only thing is that we have to run inbound processing too for language stuff. I'd love reviews on improving that and maybe finding a way to not run that multiple times. See https://github.com/md-systems/redirect/blob/8.x-1.x/src/EventSubscriber/.... Note that we have to run before routing, as the routing could e.g. abort with an access denied exception.
Comment #64
Leksat CreditAttribution: Leksat at Amazee Labs commented@Crell, thanks for the review!
I'll go through all your points a bit later. For now, here is performance testing results.
Conditions: used
ab -n500 -c1
at /user/password page, Drupal 80821af (8.x-1.x, 09.02.16) with standard profile, Redirect 34bee9a (8.x-1.x, 12.02.2016), dynamic_page_cache and page_cache are uninstalled.No route normalizer (patch #61 applied, but the route normalizer service is commented out):
Requests per second: 2.32
Connection Times (ms) Total: 431 +/-sd 11.1
Route normalizer, no config (patch #59):
Requests per second: 2.31
Connection Times (ms) Total: 432 +/-sd 6.9
Difference: +0.23%
Route normalizer (patch #61):
Requests per second: 2.31
Connection Times (ms) Total: 432 +/-sd 11.7
Difference: +0.23%
No route normalizer, Redirect module (with default configuration):
Requests per second: 2.27
Connection Times (ms) Total: 441 +/-sd 5.8
Difference: +2.32%
Difference is calculated on Connection Times parameter.
(Would be great if someone can repeat testing because I did it for the first time)
Comment #65
Leksat CreditAttribution: Leksat at Amazee Labs commentedReply to #62.
2.
I also considered using a container parameter. I see the following disadvantages of this:
- In my company we use service yml files only for storing environment related data (I think most developers do). While the global route normalizer killswitch should be something deployable in my opinion.
- We would have to add that parameter to sites/default/default.services.yml. I think it's not so important to go there.
My arguments for not having UI:
- I expect that people won't disable route normalizer usually.
- The global killswitch is only exists as a BC layer to not change behavior of already existing Drupal installations. If we don't need to keep the behavior, then we don't need the killswitch at all.
- I have no idea where to put this setting... All existing config pages seem unrelated. Adding a new page for a single option does not sound like a good idea.
- If we add UI, we'll add some description to the killswitch option. I can't think out a good one :)
- Only advanced users can have a need to disable the route normalizer.
- As it's pointed by @Berdir, a contrib module can provide a UI.
4.
If the language negotiation is set to url+browser (I'd guess most of multilingual installations use that combination), and the incoming URL does not have the language prefix, this is the case.
5.
I checked this. It works even with "1". So I removed the priority and the comment to make the code simpler.
Comment #66
Crell CreditAttribution: Crell as a volunteer commentedThe site-level services.yml file already has a lot non-environmental stuff in it, for better or worse. Drupal has never really had a clear environment switch, as we couldn't agree on what buttons and dials should change when. While that may be a convention in some companies it's not how Drupal is built currently.
If this is something only advanced users will be messing with, then moving it to a container parameter still makes the most sense to me.
Comment #67
Leksat CreditAttribution: Leksat at Amazee Labs commented@Crell, when I considered the route_normalizer.enabled to be a container parameter, I thought that we can set it to FALSE in core/core.services.yml and set to TRUE in sites/default/default.services.yml so that existing installations won't have the route normalizer enabled. But somehow I missed this change: #2547447: Stop creating services.yml by default The sites/default/services.yml is not created by default on Drupal installation anymore. So container parameters cannot be used for upgrade-path purposes.
The only way to make it via files is to add something like
$settings['route_normalizer_enabled'] = TRUE;
to the sites/default/default.settings.php.Did you mean this approach?
I see the following disadvantages:
- that would be a setting anyway
- default.settings.php should not be used for upgrade-path purposes IMO
Comment #68
Crell CreditAttribution: Crell as a volunteer commentedWell, then let me ask this: We're assuming so far that the upgrade behavior MUST be that this service is not enabled. But... is that really necessary? This is an SEO improvement (presumably), and fixes a few bugs, and is low-level enough that most people likely won't know/care, so... What is wrong with having it enabled by default, even on upgrades? People are expecting new functionality in 8.1 (or 8.2, as it looks like this probably won't make the 8.1 cutoff), so this is new functionality.
That also then allows the kill-switch to be a container parameter without issue.
Comment #69
Leksat CreditAttribution: Leksat at Amazee Labs commentedOkay, got it :)
So, we implement the killswitch as a container parameter, enable the route normalizer for existing installations, publish a change record where we describe how do disable it, and that's it!
Will work on that as soon as I have time.
Comment #70
Leksat CreditAttribution: Leksat at Amazee Labs commentedMeh.. I wanted to use \Drupal\Core\CoreServiceProvider to dynamically register route_normalizer_request_subscriber service depending on the container killswitch parameter. But then I found that both core and module service providers have no access to site-specific yaml files: http://cgit.drupalcode.org/drupal/tree/core/lib/Drupal/Core/DrupalKernel...
So, I'll have to leave the service provider registration in the core/core.services.yml file.
This is not related to the current issue, but maybe someone knows if the above is okay or not? In my opinion, service providers should get final container parameters (which include site-specific overrides). Tried to find an appropriate existing issue for this, but got nothing...
Comment #72
Leksat CreditAttribution: Leksat at Amazee Labs commentedI currently work on a D8 project using language-domain negotiation. We need to test how RouteNormalizer behaves in this case because external redirects are forbidden by default.
Comment #73
Crell CreditAttribution: Crell as a volunteer commentedLeksat: #70 sounds like a bug to me, for reasons like... well, this issue. :-) Can you file a bug issue for that? I hope it's an easy fix...
Comment #74
dawehnerJust some super quick feedback.
@Leksat
Please use xhprof for actual benchmarking. Its way easier to see the actual difference with it. AB/apache adds quite some noise to the equation.
Well, at the moment this is kinda by design, because the idea is that site specific yaml files can override at the final stage ... anway not part of the issue
Do we really want to enable it by default?
We don't expose this as UI option at the moment, so I'm wondering whether a container parameter is actually the better option.
This needs a bit of elaboration why this is covering all this cases.
Comment #75
Leksat CreditAttribution: Leksat at Amazee Labs commented- replaced
core.routing route_normalizer.enabled
config parameter with theroute_normalizer_enabled
container parameter- restored
\Drupal\path\Tests\PathAliasTest::testPathCache()
Comment #77
Leksat CreditAttribution: Leksat at Amazee Labs commented@dawehner,
My opinion was "yes, but only for new installations". @Crell's opinion is "yes", see #68
Now I think that @Crell is right:
Comment #78
Leksat CreditAttribution: Leksat at Amazee Labs commentedFixed BigPipeTest.
Comment #79
Crell CreditAttribution: Crell at Palantir.net for Acquia commentedTwo small points, otherwise the code seems fine to me pending benchmarks:
Hm. This is a subtle but rather important change, and maybe a small API break if someone has code that messes with the URI. Why is this needed?
I do not understand this change. Needs a comment, maybe?
BrowserTestBase works now. Why aren't we using it? For new tests, if it works, let's use it. (Or does it not work in this case for some reason?)
Comment #80
Leksat CreditAttribution: Leksat at Amazee Labs commented@Crell
\Drupal\Core\PathProcessor\OutboundPathProcessorInterface::processOutbound()
is called in two places:-
\Drupal\Core\Routing\UrlGenerator::processPath()
there a URL-encoded path was passed-
\Drupal\Core\Utility\UnroutedUrlAssembler::buildLocalUrl()
there a decoded path was passedTo fix test fails I had to make both methods to use the same approach. I chose URL-encoded way because I think it more fits with the Symfony style, where paths are mostly encoded.
If
$options['query']
is a non-empty array, it is emptied in the end.Now, profiling!
I used xhprof this time. The dump is attached in 2641118-78.xhprof.txt
I used the same conditions as in #64.
As we have only one new method, I looked at it only. First result showed 0.5% performance regression:
That was too much and I suspected that this is because generateFromRoute() and isFrontPage() are called for the first time in our onKernelRequestRedirect() and a lot of init stuff happens. So I added additional calls of generateFromRoute() and isFrontPage() to the the RouteNormalizerRequestSubscriber constructor, and here is what I got:
I think this is more real result.
If we assume that we have an additional service, I'd say that performance difference should be 0.1-0.2%, so nearly the same as in #64. The only expensive thing we do - we generate a URL from a route. (Is this really expensive? :) )
Comment #81
Wim LeersWhy did the BigPipe test fail?
Comment #82
Leksat CreditAttribution: Leksat at Amazee Labs commented@Wim Leers
Because it used /user/login path for testing. This path is set as front page in the minimal installation, so route normalizer performed a redirect. BigPipe test checked response headers, that's why it failed.
Comment #83
Wim LeersThanks for the clarification, I had forgotten that that is what this issue is about. Clarified issue title.
Comment #84
dawehnerCould we leverage the
CacheableRedirectResponse
here to apply this redirect much faster?Comment #85
BerdirIt should yes.
I still think, given that this didn't make it into 8.1.0, that it would be useful to refactor the implementation redirect.module to use this approach. a) It will allow us to test this much more easily in the wild. Redirect is just an alpha, so having something break there is acceptable, much more so than core. In fact, there are currently known bugs with multilingual sites that this could help address.
It would also be much easier to just drop the implementation in redirect module once this lands in core.
Comment #86
dasjoAttached is the same patch as in #78 but against 8.1.1
Comment #87
Leksat CreditAttribution: Leksat at Amazee Labs commentedUpdated test to use BrowserTestBase.
Comment #90
Leksat CreditAttribution: Leksat at Amazee Labs commentedComment #91
Bambell CreditAttribution: Bambell at MD Systems GmbH commentedWe are working in contributed Redirect module to integrate
RouteNormalizerRequestSubscriber
(#2704213: "Redirect from non-canonical URLs to the canonical URLs" not working with language code in url). I have re-rolled this patch 2 days ago. Uploading it here to see if it still applies and to see what tests still fail. Will try to work on that. We also noted that the defaultRedirectResponse
's 302 response code is used, although 301 would be more appropriate, so we changed that.Comment #93
Leksat CreditAttribution: Leksat at Amazee Labs commented@Bambell, I would not say that 301 (permanent) is more appropriate as 302 (temporary). For example, the language redirect may depend on user browser settings, so it is not permanent.
Comment #94
Leksat CreditAttribution: Leksat at Amazee Labs commentedAlso, today I caught a circular redirect after upgrading Drupal 8.0 to 8.1. It was caused by route normalizer + page cache. Reported in #2761639: PageCache should not use $request->getUri()
Comment #95
Leksat CreditAttribution: Leksat at Amazee Labs commentedBTW, I just thought that Route Normalizer is not the best name. The service normalizes URLs, routes stay the same.
I would rename it to URL Normalizer.
Comment #97
stella CreditAttribution: stella at Annertech for Glanbia commentedAttached is the patch from comment #91 above, but with a 302 rather than 301 redirect, as I agree, yes it makes more sense given that this isn't a permanent redirect based on the browser's language settings.
I haven't made any other changes here.
Comment #99
SchnWalter CreditAttribution: SchnWalter as a volunteer and commentedA bug has been discovered against the redirect.module route normalizer which also affects this patch. See #2852680: Redirect loop when serving cached pages to anonymous users
The redirect loop is caused by the fact that the URI string returned by "Request::getRequestUri()" can include characters that don't have any effect on the HTTP request but they are present in the original string and this string is compared to an URI generated from a route object.
For example these URIs are different but the HTTP requests are equal:
https://www.example.com/test?
vshttps://www.example.com/test
https://www.example.com/test?&=true
vshttps://www.example.com/test?amp=true
The RouteNormalizerRequestSubscriber uses
\Symfony\Component\HttpFoundation\Request::getRequestUri()
and then\Symfony\Component\HttpFoundation\Request::prepareRequestUri()
which will return different results depending on the server setup.In the patch I've submitted for the redirect.module, I've used
parse_url()
andGuzzleHttp\Psr7\Uri::fromParts()
to process the URLs before comparing them but I'm not sure if that is the best approach.Comment #100
stella CreditAttribution: stella at Annertech for Glanbia commentedPatch reroll against latest 8.2.x in case anyone needs it.
Comment #101
stella CreditAttribution: stella at Annertech for Glanbia commentedBroken patch, rerolling
Comment #102
geerlingguy CreditAttribution: geerlingguy at Acquia commentedComment #103
geerlingguy CreditAttribution: geerlingguy at Acquia commentedGah, that was for 8.2.x, sorry!
Comment #104
andypostComment #105
piyuesh23 CreditAttribution: piyuesh23 at QED42 commentedUpdated & re-rolled the patch to apply on 8.4.x stream.
Comment #107
jofitz CreditAttribution: jofitz at ComputerMinds commentedRe-work the re-roll.
Comment #109
dawehnerDrupal\file\Tests\DownloadTest
is probably also all about the fact that path aliases don't support query parameters. The testContentNegotiationRoutingTest
at least was.Comment #112
Wim LeersOnce this lands, I'll update the changes made to the CDN module in #2924916: Compatibility with contrib Redirect module: disable language redirects for CDN's "farfuture" route, because they'll no longer be necessary for "just a contrib module", but for Drupal core itself.
Comment #113
dawehnerHere is just a reroll, I couldn't figure out though how to fix the failures.
Comment #115
Leksat CreditAttribution: Leksat at Amazee Labs commentedI'm closing this issue because this functionality is fully implemented in the redirect module. See http://cgit.drupalcode.org/redirect/tree/src/EventSubscriber/RouteNormal...
Comment #116
BerdirIt is, but that was always meant to be temporary until added to core. There are unresolved caching issues in core without this, core can't just say it only works correctly with a contrib module :)
Comment #117
Wim LeersRetesting #113, it still applies cleanly. On its original November 29 test run, it had 21 failures. Let's see if that number has changed.
Comment #118
Leksat CreditAttribution: Leksat at Amazee Labs commentedOkay, I see. Thanks!
Then, here is one more issue I faced today with the redirect version of route normalizer.
We use the redirect module on a decoupled project having GraphQL with batched queries. The important thing is that batched queries produce subrequests for each individual query.
The current issue is: Drupal\redirect\EventSubscriber\RouteNormalizerRequestSubscriber::onKernelRequestRedirect() redirects from the frontpage to the node alias in a subrequest.
Reason: the result of Drupal\Core\Path\PathMatcher::isFrontPage() is statically cached (so it contains the result of the primary request to /graphql).
We'll probably work on this issue in the next 3 weeks.
Comment #119
Wim Leers@Leksat:
Oh! Nice catch :) This definitely is an independent bug that we can reproduce and fix. It's easy enough to write test coverage: create a controller that does subrequests to two paths A and B, with A being the frontpage and B being anything else. Allow the parameter to the controller to determine the subrequest order: either A,B or B,A. In case of A,B it should result in B erroneously being considered the frontpage, and in case of B,A it should result in A erroneously NOT being considered the frontpage. That failing test should allow you to remove the static caching of
PathMatcher::isFrontPage()
. Care to open an issue? :)Comment #120
neclimduldrive by review, i see some changes around /user/login in the patch and #81 mentions
BrowserTestBase also uses /user/login to login and the first failure I saw was triggered in BrowserTestBase::drupalLogin() so I'd wager something is up there.
Comment #123
DuneBLPatching #113 on 8.6 produce few hunk with offset
Comment #124
andypostComment #125
neclimdulReRoll I guess... no changes because its just offset warnings.
Comment #127
nick.morahan CreditAttribution: nick.morahan at Annertech for Glanbia commentedrefactored for 8.6.2
Comment #128
daffie CreditAttribution: daffie commentedChanging the status of this issue to "needs review". This will set of the testbot to do it's work.
Comment #130
SpokjePatch #113 reworked for Drupal Core 8.5.8
Comment #131
SpokjeForgot to add the newly created files, retry.
Comment #133
DuneBL#126 needs reroll for 8.7
Comment #134
DuneBL#130 needs also a reroll for 8.7
Comment #135
FeuerwagenComment #136
vacho CreditAttribution: vacho at Skilld commentedPatch rerolled
Comment #137
Rewted CreditAttribution: Rewted commentedI've noticed on the Frontpage View, the Pager links having ../?destination=/&_exception_statuscode=404&page=1 in the URL where as normally they will be ../?page=1
Clearing the cache they revert back to normal. Does this patch address this and if so, any idea when it will be pushed to Core?
Comment #139
mangy.fox CreditAttribution: mangy.fox commentedRerolled for 8.9.x
Comment #140
daffie CreditAttribution: daffie commentedLet's see what the testbot thinks.
Comment #142
Rewted CreditAttribution: Rewted commentedDoes this address the issue the Frontpage View, the Pager links having ../?destination=/&_exception_statuscode=404&page=1 in the URL where as normally they will be ../?page=1
Clearing the cache will revert URLs back to normal. Has anyone noticed this or are the issues unrelated?
Comment #143
SpokjeReroll of #139 against D8.8.5 (
core/core.services.yml
has an offset of 6 lines)Comment #144
SpokjeReroll of #139 against D8.8.5 (core/core.services.yml has an offset of 6 lines)
Previous patch was incomplete.
Comment #147
DuneBL#144 doesn't apply on 9.1.0
Comment #148
SpokjeRerolls
Comment #149
SpokjeFixing custom command failures
Comment #150
SpokjeGoing for one less test failure.
Comment #151
Spokje"Ambitiously" going for 18 test-fails instead of the 20 in #149...
Comment #153
DuneBL#151 patch failed in some test file:
Comment #154
ankithashettyRerolled the patch in #151 and replaced a
$this->assertEqual
function with$this->assertEquals
function incore/tests/Drupal/KernelTests/Core/Routing/ContentNegotiationRoutingTest.php
file.Thank you!
Comment #156
Wim LeersWould still be great to land this! Here's a rebase to fix the conflict since #3139409: Replace usages of AssertLegacyTrait::assertRaw, that is deprecated. It also aims to fix the remaining failures — which are all just due to a deprecation error.
Comment #157
daffie CreditAttribution: daffie commentedTestbot is not happy.
Comment #158
Wim Leers… because I forgot to update the other place in that class 🙈
Comment #160
Wim LeersLooks like remaining failures are genuine failures … but now it's a very manageable number! :)
Comment #161
BerdirReminder: This feature has been integrated into redirect.module and has been adjusted there quite a bit over time and has been tested on 100k+ sites there. I haven't reviewed the patch here in a very long time, but this should most likely be compared against that version. There have been quite a few issues with caching, query argument encoding, duplicated query arguments, query argument order and so on. Extra test coverage should probably also be ported over in whatever way makes sense.
Comment #162
JeroenTIn some cases the redirect_uri was empty which results in a couple of test failures.
I haven't checked the differences between the global redirect functionality in the redirect module and this patch as mentioned in #161.
Comment #165
DuneBLPatch #162 failed on 9.4
Comment #166
andypostComment #167
ankithashettyRerolled the patch in #162, thanks!
Comment #170
catchThis is running route generation for including on requests that won't need a redirect - i.e. where the request path is an alias. I think we need to check whether this causes a regression for those requests (which should be the majority of requests on most sites).
Could we instead do \Drupal::service('path.current')->getCurrentPath() and only then check for redirect if this is the same as the incoming URL? Then if inbound path processing has changed something, it would be a no-op.
Even then, there are sites that don't use path aliases, do they need this feature?
Why a 302 and not a 301 here? For aliased routes I would expect this to be a 301.
Comment #171
catchThe language redirect I think should be handled in #2430335: Browser language detection is not cache aware itself - i.e. we should refactor browser language detection so it always happens after path language detection and does a redirect.
That would leave this issue dealing with the front page and aliases only, which should be possible to detect by checking the front page config (already happens on all HTML page requests due to is_front and similar) and aliases (should be detectable without generating a route). Wondering if it should be implemented as a module.
Comment #174
ressa CreditAttribution: ressa at Ardea commentedGetting Redirect and #229568: Pathauto in Core would be awesome, as well as Token (#514990: Add a UI for browsing tokens?), since these three modules are probably installed in most Drupal sites.
Comment #175
SpokjeComment #176
SpokjeSorry, double wrong click :/