magento / magento2

Prior to making any Submission(s), you must sign an Adobe Contributor License Agreement, available here at: https://opensource.adobe.com/cla.html. All Submissions you make to Adobe Inc. and its affiliates, assigns and subsidiaries (collectively “Adobe”) are subject to the terms of the Adobe Contributor License Agreement.
http://www.magento.com
Open Software License 3.0
11.54k stars 9.31k forks source link

Base URL placeholder defaults in multi-website configuration pollute config cache for one another #36707

Open danemacmillan opened 1 year ago

danemacmillan commented 1 year ago

Preconditions and environment

Steps to reproduce

With two Web Sites configured, now set their base URLs using the default placeholders, so that an explicit domain does not need to be configured, which will allow the deployment to exist at any domain, so long as it points to the correct deployment, as noted here:

{{base_url}} which represents a base URL defined by a virtual host setting or by a virtualization environment like Docker. For example, if you set up a virtual host with the hostname magento.example.com, you can install the software with --base-url={{base_url}} and access the Admin with a URL like http://magento.example.com/admin.

This is also noted in the Admin at Stores > Settings > Configuration > General > Web > Base URLs, should they want to set the URL values at each Web Site scope (not default).

To simplify the process, just use the commands to set the URLs.

Web Site code: base
magento config:set web/unsecure/base_url {{base_url}} --scope=website --scope-code=base
magento config:set web/unsecure/base_link_url {{unsecure_base_url}} --scope=website --scope-code=base
magento config:set web/unsecure/base_static_url "" --scope=website --scope-code=base
magento config:set web/unsecure/base_media_url "" --scope=website --scope-code=base

magento config:set web/secure/base_url {{base_url}} --scope=website --scope-code=base
magento config:set web/secure/base_link_url {{unsecure_base_url}} --scope=website --scope-code=base
magento config:set web/secure/base_static_url "" --scope=website --scope-code=base
magento config:set web/secure/base_media_url "" --scope=website --scope-code=base
Web Site code: base2
magento config:set web/unsecure/base_url {{base_url}} --scope=website --scope-code=base2
magento config:set web/unsecure/base_link_url {{unsecure_base_url}} --scope=website --scope-code=base2
magento config:set web/unsecure/base_static_url "" --scope=website --scope-code=base2
magento config:set web/unsecure/base_media_url "" --scope=website --scope-code=base2

magento config:set web/secure/base_url {{base_url}} --scope=website --scope-code=base2
magento config:set web/secure/base_link_url {{unsecure_base_url}} --scope=website --scope-code=base2
magento config:set web/secure/base_static_url "" --scope=website --scope-code=base2
magento config:set web/secure/base_media_url "" --scope=website --scope-code=base2

Ensure at the very least the config cache is enabled: magento cache:enable config. Everything else can be off.

With Nginx (or Apache) configured with the relevant MAGE_RUN_TYPE and MAGE_RUN_CODE per domain virtual host, navigate to the either of the domains first. For example purposes, base will respond to domain https://base.test/en1/ and base2 will respond to domain https://base2.test/en2/.

The first domain loads fine, with all its static and media assets also loading from the same base URL of https://base.test/, being https://base.test/media/ and https://base.test/static/.

Now navigate to the second domain. It loads fine, except that all of its static and media assets are not loading from https://base2.test/, but are loading from the first domain, which obviously causes numerous CSP and CORS errors, while additionally all of the links on the site are pointing to https://base.test/, which means the moment anyone interacts with the second site, they are brought to the first one.

Disabling the config cache eliminates this problem.

Worthwhile debugging notes

Expected result

After navigating to https://base.test/en1/, navigating to https://base2.test/en2/ should load all of its static and media assets from its own base URL of https://base2.test/.

Actual result

Instead, what happens is that navigating to https://base2.test/en2/ will have all of its static and media assets loaded from the Base URL of the first Web Site that was accessed, being https://base.test/.

Additional information

Note that a similar problem was documented in #10693, though there was no mention of whether they also set the static and media URLs. The probably didn't. In all likelihood, the deployments that the user was making were single Web Site configurations, which would not have this problem, as there would be no other Web Site Base URLs polluting the Base URLs of the config cache.

Release note

No response

Triage and priority

Edit 1: Research

This method gets called on all configs within all scopes, regardless of the Store View being loaded: https://github.com/magento/magento2/blob/5f07eba878296a37bd5c3a2baecad48948547594/app/code/Magento/Store/Model/Config/Processor/Placeholder.php#L35

It then eventually calls a method to process all placeholders, which then replaces all the {{base_url}} and similar URL placeholders with the value detected from the request via this method: https://github.com/magento/magento2/blob/5f07eba878296a37bd5c3a2baecad48948547594/app/code/Magento/Store/Model/Config/Placeholder.php#L126

What that means is that every Web Site-scoped config is replaced with the currently discovered HTTP_HOST, which is erroneous. The current Web Site scope would need to be known before attempting to replace placeholders, and the placeholder replacements themselves should only be done on the configs for the current Web Site scope, not all of them, as is being done now. What this means is that when the config cache is enabled, the moment the first Web Site within a multi-website configuration is hit, the domain for that site is used for every other Web Site scope config, and then saved to the cache. This happens because the code does not care about what scope the placeholder replacements should be made; instead it simply replaces all of them, regardless of scope. That means when the next site is loaded from a different domain, all of its Link, Static, and Media URLs have already been generated by the placeholder replacement operation from the first load of the other site.

In summary, what this means is that the URL placeholder replacement logic runs way too early on the configs, and instead needs to be run only once scopes are known, and only run under the currently active scope.

Also, given how early in the process URL placeholders are being replaced, it means, for example, that code like this will never be run, as replacements will have already occurred (keep in mind that this section would not address the other URL placeholders, though, even if they managed to get to this section: https://github.com/magento/magento2/blob/5f07eba878296a37bd5c3a2baecad48948547594/app/code/Magento/Store/Model/Store.php#L669

Edit 2: Research

Based on git logs, much of this functionality was rewritten in a very large commit (https://github.com/magento/magento2/commit/a978a4cb72a2babba91cb78988bc4a41a70a60ab) by Sergii Kovalenko, which may be the source of the problem.

m2-assistant[bot] commented 1 year ago

Hi @danemacmillan. Thank you for your report. To speed up processing of this issue, make sure that you provided the following information:

Make sure that the issue is reproducible on the vanilla Magento instance following Steps to reproduce. To deploy vanilla Magento instance on our environment, Add a comment to the issue:

@magento give me 2.4-develop instance - upcoming 2.4.x release

For more details, review the Magento Contributor Assistant documentation.

Add a comment to assign the issue: @magento I am working on this

To learn more about issue processing workflow, refer to the Code Contributions.


:clock10: You can find the schedule on the Magento Community Calendar page.

:telephone_receiver: The triage of issues happens in the queue order. If you want to speed up the delivery of your contribution, join the Community Contributions Triage session to discuss the appropriate ticket.

:pencil2: Feel free to post questions/proposals/feedback related to the Community Contributions Triage process to the corresponding Slack Channel

m2-assistant[bot] commented 1 year ago

Hi @engcom-November. Thank you for working on this issue. In order to make sure that issue has enough information and ready for development, please read and check the following instruction: :point_down:

engcom-November commented 1 year ago

@magento give me 2.4-develop instance

magento-deployment-service[bot] commented 1 year ago

Hi @engcom-November. Thank you for your request. I'm working on Magento instance for you.

magento-deployment-service[bot] commented 1 year ago

Hi @engcom-November, here is your Magento Instance: https://882b1fcb1582f0688f079b4872326b69.instances.magento-community.engineering Admin access: https://882b1fcb1582f0688f079b4872326b69.instances.magento-community.engineering/admin_d356 Login: 4a348d08 Password: acd23f1b1221

engcom-November commented 1 year ago

Hi @danemacmillan , Thank you for reporting and collaboration. Verified the issue on Magento 2.4-develop instance but unable to reproduce the issue with below steps performed: Steps performed:

  1. Enabled config cache: magento cache:enable config

  2. Stores setup as shown below: image

  3. Apache server with virtual host configured as below: image

  4. Set the urls for both the website scopes as shown below: image Note: static and media urls left blank

Getting 404 not found error for both the website scopes when trying to access : http://mg24.local/static, http://mg24.local/media http://en.mg24.local/static, http://en. mg24.local/media image Kindly recheck the behavior on Magento 2.4-develop instance and elaborate missing steps / configuration details if the issue is still reproducible. Thank you.

danemacmillan commented 1 year ago

Hi,

There are several problems with your attempt to reproduce. Mainly, they are just not following the steps mentioned in the original report.

  1. Good.
  2. Good.
  3. Bad. You need to have 2 virtual hosts, one for each Web Site, each specifying their unique Web Site code, which would mean one virtual host for base and a second virtual host for base2. Additionally, they need to have unique server names (domain names); they cannot be the same. Give them a unique name each. In your case, I would use base.mg24.local for the virtual host that corresponds to the base Web Site scope code, and base2.mg24.local for the virtual host that corresponds with the base2 Web Site scope code.
  4. Bad. Based on screenshots, you're only setting the Base URL for one scope (and probably for the "Default Config" scope, which is erroneous). Secure and unsecure URLs are not scopes. You need to switch to the "Main Website" Web Site scope (code being base) in the scope changer located at the top left of the admin (see image a), then set the Base URL, Base Link URL, Secure Base URL, and Secure Base Link URL; then you need to do the same thing for the "base2" Web Site scope (code being base2). Additionally, and more importantly, the whole point of this ticket is that the placeholders don't work: you're not using placeholders, you're explicitly setting a domain in the admin config. To repeat what was mentioned in the original ticket, you need to set the URLs with the placeholder values that Magento supports. That would look like this for each Web Site scope:

base:

base2:

You literally save the placeholder values (see image b). This was explicitly written in the original issue, with the commands to execute to do this.

Lastly, you don't go visit the static URLs directly, though the problem will likely exist there as well. You visit the site itself, which will in turn build all the link, static, and media URLs and then cache them. You having a 404 has nothing to do with the issue, and only to do with your own misconfigured machine.

References:

a) Note that I recreated what your scope changer menu would look like, based on the Web Sites you displayed in your screenshot.

Screenshot 2023-01-10 at 12 41 27 PM

b)

Screenshot 2023-01-10 at 12 54 21 PM

--

To be clear, I wrote all of this in my original ticket. Yes, it's a complex set of steps, but I've merely repeated myself here, but will happily continue to guide you until you can reproduce.

engcom-November commented 1 year ago

Thank you for the response @danemacmillan Verified the issue again on Magento 2.4-develop instance with updated steps and the issue is reproducible. Hence updating the description and confirming the issue.

github-jira-sync-bot commented 1 year ago

:white_check_mark: Jira issue https://jira.corp.adobe.com/browse/AC-7687 is successfully created for this GitHub issue.

m2-assistant[bot] commented 1 year ago

:white_check_mark: Confirmed by @engcom-November. Thank you for verifying the issue.
Issue Available: @engcom-November, You will be automatically unassigned. Contributors/Maintainers can claim this issue to continue. To reclaim and continue work, reassign the ticket to yourself.

github-jira-sync-bot commented 1 year ago

:x: You don't have permission to export this issue.