uwsgi + mod_apache_uwsgi + php plugin: issue with absolute PATH_INFO?
Hello,
- Debian 12
- libapache-mod-proxy-uwsgi 2.4.62-1~deb12u1
- uwsgi-core 2.0.21-5.1
- uwsgi-plugin-php 2.0.21+4+0.0.15
I am having an issue with Apache using AddHandler to forward .php files to uwsgi through mod-proxy-uwsgi. All packages are the ones provided by Debian 12 bookworm.
/etc/apache/sites-enabled/test.conf:
<VirtualHost *:8000>
ServerName localhost:8000
DocumentRoot /home/test/www
DirectoryIndex index.php
AddHandler proxy:unix:/run/sockets/uwsgi.sock|uwsgi://localhost .php
</VirtualHost>
/etc/uwsgi/test.ini:
[uwsgi]
chdir = /home/test/www
plugins = php
remap-modifier = 14:0
php-index = index.php
socket = /run/sockets/uwsgi.sock
fastcgi-socket = /run/sockets/uwsgi-fcgi.sock
log-format = %(ftime) %(method) %(uri) %(status) %(var.SCRIPT_FILENAME) %(var.SCRIPT_NAME) %(var.PATH_INFO) %(var.PATH_TRANSLATED) %(var.CONTEXT_DOCUMENT_ROOT)
/home/test/www/index.php contains a test file. However, a request for http://localhost:8000/index.php fails with 404 Not Found (from uwsgi).
The request log, with the above format, returns this:
Sep 06 14:01:52 test uwsgi[50038]: 06/Sep/2024:14:01:52 +0200 GET /index.php 404 proxy:uwsgi://localhost/home/test/www/index.php /index.php /home/test/www/index.php - /home/test/www
In other words:
SCRIPT_FILENAME = proxy:uwsgi://localhost/home/test/www/index.php
SCRIPT_NAME = /index.php
PATH_INFO = /home/test/www/index.php
PATH_TRANSLATED = -
CONTEXT_DOCUMENT_ROOT = /home/test/www
However, everything works fine if I switch Apache to use FastCGI through the fastcgi-socket provided by uwsgi, and overriding PATH_INFO, with the following changes to the Apache config above:
ProxyFCGISetEnvIf "true" PATH_INFO "%{reqenv:SCRIPT_NAME}"
AddHandler proxy:unix:/run/sockets/uwsgi-fcgi.sock|fcgi://localhost .php
Log line produced:
Sep 06 14:01:54 test uwsgi[50038]: 06/Sep/2024:14:01:54 +0200 GET /index.php 200 proxy:fcgi://localhost/home/test/www/index.php /index.php /index.php - /home/test/www
SCRIPT_FILENAME = proxy:fcgi://localhost/home/test/www/index.php
SCRIPT_NAME = /index.php
PATH_INFO = /index.php
PATH_TRANSLATED = -
CONTEXT_DOCUMENT_ROOT = /home/test/www
The only difference I can see in the passed variables is that when using mod-proxy-uwsgi, PATH_INFO is passed as an absolute path and not a path relative to the document root, as is done for FCGI due to my PATH_INFO override above.
Apparently, uwsgi expects PATH_INFO to be relative to CONTEXT_DOCUMENT_ROOT. An strace shows this:
newfstatat(AT_FDCWD, "/home/test/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
newfstatat(AT_FDCWD, "/home/test/www/home", 0x7ffc9ae360a0, 0) = -1 ENOENT (No such file or directory)
writev(8, [{iov_base="HTTP/1.1 404 Not Found\r\nConnecti"..., iov_len=71}, {iov_base="Not Found", iov_len=9}], 2) = 80
(It stops when it encounters the non-existant directory /home/test/www/home)
My question is, is there a way to either make uwsgi properly handle the absolute path in PATH_INFO, or alternatively have Apache send the relative PATH_INFO when using the mod_proxy_uwsgi module?
I've tried doing SetEnv / SetEnvIf to set PATH_INFO(similar to the ProxyFCGISetEnvIf above), but this appears to be ignored. I've also tried setting manage-script-name = true in uwsgi.ini, with no effect.
uwsgi does work fine when using ProxyPass, but this is not an adequate solution for us. We only want proxying to uwsgi for files, not locations, and to happen after Apache rewrites.
I've been working around this for years with:
$ cat /etc/uwsgi/apps-available/reader.ini
[uwsgi]
[...]
# workaround uwsgi-plugin-php cannot set SCRIPT_NAME
php-set = auto_prepend_file=/etc/uwsgi/apps-available/reader.prepend.php
$ cat /etc/uwsgi/apps-available/reader.prepend.php
<?php
$_SERVER['SCRIPT_NAME'] = '/r/index.php';
?>
Maybe related to #1616 and #1278. Never got into fixing it.
@niol I don't think we're talking about the same issue. auto_prepend_file would never come into play in my case as uwsgi never gets to the point of invoking the PHP subsystem.
From what I can tell, for my specific case, the uwsgi PHP plugin fails because of this concatenation of document_root and path_info:
https://github.com/unbit/uwsgi/blob/0d1c793465ac331bdb43c6d56fb7c348ea94f463/plugins/php/php_plugin.c#L852
In my case, this produces filename = /home/test/www/home/test/www/index.php, because
wsgi_req->document_root = /home/test/www
wsgi_req->path_info = /home/test/www/index.php
which in turn causes uwsgi_php_walk() to fail when traversing the path, when it eventually encounters the non-existant path /home/test/www/home.
https://github.com/unbit/uwsgi/blob/0d1c793465ac331bdb43c6d56fb7c348ea94f463/plugins/php/php_plugin.c#L855
I'm unfortunately not versed enough in the realm of CGI/WSGI/uwsgi to determine which part of the chain is "at fault" here, be it the Apache module or the PHP plugin, or maybe Apache itself.