In #2289683: Select in-editor theme and get all stylesheets, the code to find the theme CSS was changed to require making an HTTP request to the Drupal site itself from PHP.
However, in certain environments (namely Docker-based ones) it might not be possible for the Drupal to make a request to the site itself from PHP.
This happens when you have a container that is the app server running PHP-FPM, which has another container that is the http server (Apache or nginx) in front of it, and the hostname of your site resolves to something other than the IP of the http server or the http server isn't accessible (from the perspective of the app server, of course). This happens in my development environment, where the hostname of the site resolves to 127.0.0.1 -- the app server is trying to request port 80 on 127.0.0.1 but the app server doesn't run http, that's on a different IP inside the network that the app server container is on.
However, this isn't totally specific to Docker-based development environments. I could imagine a non-Docker environment, where there are app servers that connect to the http server over an internal network using internal hostnames, and can't access the http server via it's public IP using it's external hostname.
You could, of course, say that this is a bug in those environments, but I'm really not aware of any other Drupal module that's making requests to the site itself from PHP. I wouldn't be surprised to see several people finding that "Use theme CSS" stops working in their environment, and not really realizing that something is "wrong" with their environment, because everything else (including older versions of the 'wysiwyg' module) work just fine!
It'd be really nice, if you're using the "Active theme" option (like we are), if it could just get the CSS without doing the extra HTTP request, which should be totally possible, because the current request would have already loaded the CSS with the active theme. The extra HTTP request is really only necessary for the new options to pull in the CSS from a specific theme. This would make the implementation basically the same as older versions of the 'wysiwyg' module if you don't need any of the fancy new options.
All that said, now that I know why this is breaking, I'm going to fix my development environment. :-) So, even if the maintainers don't want to do a code fix, there should at least be some documentation somewhere on the fact that this type of environment issue can break the "Use theme CSS" feature!
| Comment | File | Size | Author |
|---|---|---|---|
| #9 | wysiwyg.theme-css.2884450.9.patch | 4.03 KB | twod |
Comments
Comment #2
twodThank you for the detailed report. I am aware of this environment problem as it was discussed in a couple of other issues but I have not found out exactly what has been the cause of the server not being able to call itself in those discussions.
I am also using Docker for my some of my dev servers but as I usually have both the http and php servers inside the same container I have not noticed this problem before.
The reason it makes a separate request is that it was the only way I found to reliably find all the stylesheets added by a theme, including the active one. (Conditionally added stylesheets not included of course.) Deciphering all the ways in which some themes or modules added stylesheets was really difficult, some use custom keys in the .info file (or even hardcodes markup into
<head>!). I also found that sometimes the stylesheets are added so late in the request that you can't get them until after the page callback has returned, hence the custom page delivery callback.Apparently, more environments than I expected were configured without this ability and I've been thinking about other ways to trigger these requests. Ideally it'll happen from the client so the normal way of figuring out routing is used. We may not know the caches are empty until the page we need to attach editors to is requested and by then we have a sort of race condition.
A simple way would be to make a variant of these paths which returns a tiny image and have an admin page somewhere which shows one image per active theme, thus triggering the requests. That would work if we could get whoever flushes the caches, saves a theme, updates an editor profile, etc, to (directly or indirectly) see that page (or at least get the image tags injected into whichever page they see next). Then the internal requests would never be triggered as the caches are already filled (perhaps even give an option to disable them completely to accept the small downside of someone getting an editor without the stylesheets included for a request or two).
Anyway, as soon as I have some spare time I'll test out some of my ideas and see which ones are most viable. Suggestions are welcome.
Btw, would using the value of
$_REQUEST['HTTP_HOST']be helpful inside in your environment, for making an "external" request to localhost rather than over 127.0.0.1? Perhaps it could at least help decrease the number of environments in which this is a problem in the short term.Comment #3
dsnopek$_REQUEST['HTTP_HOST']won't help in my case -- that's just the 'Host' header which comes from the client's browser, so it's still the external name. There might be some 'X-Proxy-Something' header that we get from the webserver, but I haven't looked into that.An image that that makes the request from the client would certainly work! But, yeah, synchronizing that with loading the WYSIWYG editor and knowing when to clear the cache would be a challenge.
Comment #4
twodAh, got it. I understood it as the PHP server didn't know the external name and would default to localhost/127.0.0.1. But if "example.com" also resolves to that ip as far as PHP knows it would of course make no difference.
Looking for empty caches in
hook_init/boot()and injecting those images into the current response would probably cover if someone clears caches using the GUI, as those get triggered after a cache clear. Not so when done via drush, but still... could be a last way out.Comment #5
cilefen commentedI actually don't understand what is going on in wysiwyg_get_css() because
$responseis never used:It responds with "OK", which is good, but nothing is done with that fact.
Comment #6
cilefen commentedOh, I should have read the other issue (and the code) more carefully. From #2289683: Select in-editor theme and get all stylesheets:
Comment #7
badrange commentedThis one bit me. Hard. Auts.
Comment #8
developerchris commentedThis issue is a showstopper for us.
In an enterprise environment there are two issues to deal with. Firstly most enterprise firewalls prevent outgoing requests - Period!
However this can be resolved simply by adding the FQDN to the hosts file (if you have access) on the server. therefore drupal calls itself never trying to leave the server. If you are using a reverse proxy like the docker FPM example above you would add the reverse proxy's IP to the host file.
This is where the second bug bites - Hard.
If the firewall proxy performs SSL interception (as it should) and the server tries to call itself using SSL it fails because the localhost normally doesn't handle SSL. That is left up to the firewall/reverse proxy stack. Of course if you are also running on a different port that is also a problem to be countered
So even if you add the FQDN to the hosts file (if you have that level of access) it still fails.
The only solution I can see is to add a config setting that disables external callbacks.
Comment #9
twodHow about this patch? Would it work in your case @DeveloperChris?
Comment #10
developerchris commented@TwoD
Looks promising. We have disabled editor theming to prevent the callouts as a workaround.
The proposed solution of making the client do the callout will resolve all the firewall and network issues from our point of view.
Comment #15
twodCommitted this with a few additional typo fixes. Thank you very much to everyone involved here and the related issues! This should hopefully make the process of grabbing a theme's CSS much more transparent.
Comment #17
danielvezaThis hit us pretty hard recently. Maybe time for a new release?