Resource tree disappeared suddenly

I have multiple sites on the same server with CPanel hosting and MODX 3+ all running PHP 8.1 or 8.2, which were working fine a couple of days ago. When I log into the manager areas now, there is no resource tree. Everything else works fine, including the front end of the websites. This is without upgrading to 3.2.3, but on one site I have upgraded to 3.2.3 and the resource tree is still not visible.

I can create a new resource, but after saving it does not show in the invisible tree.

Tried clearing the core/cache.

PHP extensions appear not to have changed.

Tried removing the packages (only getResources and TinyMCE).

Nothing shows in the MODX error log.

Nothing seems to have changed with the SuperUser role and the administrator access policy that is assigned to me.

There are no resource groups.

The browser console says only:

InstallTrigger is deprecated and will be removed in the future. manager:111:17
Unreachable code after return statement

How does the resource tree just disappear from the manager from one day to the next?

Is your CPanel hosting using Litespeed for the web server, by chance? If so, see HTTP 1 / 2 / 3 and MODX for more.

Thank you for that suggestion. I see no reference to LiteSpeed in my CPanel admin area, but I will open a support ticket with the hosting company to see if this could be the reason.

The only other thing I can think of is some stubborn javascript cache…

I see that they do use LiteSpeed. A support article mentions the option of disabling connection timeouts in the htaccess file, which I have done, but it does not get the resource tree back. So I am now waiting for a response for the support ticket. Thanks again.

Good to know you’re using cPanel. My host was wondering whether there would any difference between Litespeed on cPanel versus a different control panel software. The first site I noticed this on is running on DirectAdmin.

cPanel here too - same issue

During several recent updates I had the same issue. PHP 7.4 was fine but 8.1 or 8.2 were not. PHP8.3 made it work. Just be sure to clear browser cache or use a different browser.

PHP 8.3 does not solve the issue for me, with MODX 3.2.0, unless it is the PHP extensions that make the difference. I will try to add a screenshot of my extensions below.

The hosting company confirmed that the disappearance of the resource tree did coincide with a LiteSpeed upgrade. They said no rollback is possible. I am still waiting to hear if they can suggest a workaround.

My host rolled back my site to use HTTP/1. That doesn’t involved rolling back LiteSpeed itself to a previous version. Ask if they can do that for you.

Do you have MultiUploadDialog or Articles installed?

The only extras I use are getResources and TinyMCE.

Thank you. Will ask.

I use the UK company Krystal for hosting. Their support team gives this lengthy reply:

[Quote]

I have confirmed that an update to Litespeed to the latest version recently is what has caused this issue.

After extensive testing I have found that the way that Litespeed handles backslashes in query strings is the culprit. In a recent update forward slashes were looked at by Litespeed for security hardening and mentioned in their changelog however backslashes aren’t mentioned anywhere but a more general security hardening is. Despite this I have been able to show that URL encoding the backslashes causes the command to succeed.

I will bring this up with Litespeed however it is likely a deliberate change for security reasons. They may provide a workaround as they did with forward slashes however this may not be possible.

That being the case, the best course of action is patching the application to use URL encoded backslashes instead of explicit ones in the query string. This would likely mean contacting the developers of MODX (which I strongly recommend) as well as filing a bug report at their github (I would classify this a bug given it has been working thus far due to more lax querystring parsing by webservers). Alternatively I haven’t dived deep but it could be the resource builder snippet on your website that is causing this and the core MODx files are fine - your developers would have to verify this prior to a bug report.

In the meantime it may be possible to catch the query string being written and doing a search and replace manually before MODX fix this. This can be shown by injecting the following in a developer console for the page:

(function() {
    function fixUrl(url) {
        if (typeof url === 'string' && url.indexOf('\\') !== -1) {
            return url.replace(/\\/g, '%5C');
        }
        return url;
    }
    var origOpen = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function(method, url) {
        arguments[1] = fixUrl(url);
        return origOpen.apply(this, arguments);
    };
})();

This just replaces \ with the URL encoding of it (%5C) whenever a HTTP request is generated by the page. If added in the console then the refresh icon on the resources is clicked then the pages load in the list.

I have confirmed the above can be added as a plugin bound to the OnManagerPageBeforeRender system event which injects the script immediately into the page. However you will want to review this before activating (it will require a page load after activating).

I hope this helps, please let us know if the plugin I have added “FixBackslashURLEncoding” fixes the issue for you satisfactorily.

[Unquote]

Can anyone suggest how I would add that code as a plugin so that the resource tree becomes visible again? It is way, way beyond my snippet skillset.

It would be great to get some core-contributors’ input on this issue.

It does sound like a bug introduced by LiteSpeed - but there’s no guarantee they will acknowledge it as such or fix it.

Which would leave us patching individual sites.

Seems crazy to me that this is needed, but one solution to get back the resource tree after the LiteSpeed upgrade (with its backslashophobia) is the following plugin (to encode all backslashes in the query string), bound to the OnManagerPageBeforeRender system event:

if ($modx->context->key !== 'mgr') {
    return;
}

/** @var \MODX\Revolution\Controllers\modManagerController $controller */
$controller = $scriptProperties['controller'];
if (!$controller) {
    return;
}

$js = <<<'EOD'
<script>
(function() {
    function fixUrl(url) {
        if (typeof url === 'string' && url.indexOf('\\') !== -1) {
            return url.replace(/\\/g, '%5C');
        }
        return url;
    }

    var origOpen = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function(method, url) {
        arguments[1] = fixUrl(url);
        return origOpen.apply(this, arguments);
    };

    if (window.fetch) {
        var origFetch = window.fetch;
        window.fetch = function(input, init) {
            if (typeof input === 'string') input = fixUrl(input);
            return origFetch.call(this, input, init);
        };
    }
})();
</script>
EOD;

$controller->addHtml($js);

But is there no solution that avoids having to add a plugin to each individual site?

Glad you mentioned Krystal as I have a few sites with them. I’m now getting the same issue but wasn’t getting this just a few days ago.

The plugin the nice chap at Krystal wrote works well, I believe, as long as you bind it to the right system event and give it a priority of 0.

Okay, Krystal broke it, but then they fixed it. Can one complain?

@rthrash @smashingred @opengeek - even if it’s just to confirm that this is a LiteSpeed-only problem - would be good to hear your thoughts.