Bug 51517 - mod_proxy_fcgi is not RFC 3875 compliant (SCRIPT_FILENAME, PATH_INFO, ...)
Summary: mod_proxy_fcgi is not RFC 3875 compliant (SCRIPT_FILENAME, PATH_INFO, ...)
Status: RESOLVED FIXED
Alias: None
Product: Apache httpd-2
Classification: Unclassified
Component: mod_proxy_fcgi (show other bugs)
Version: 2.4.4
Hardware: PC Linux
: P5 major with 8 votes (vote)
Target Milestone: ---
Assignee: Apache HTTPD Bugs Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-07-16 23:31 UTC by Jérôme Loyet
Modified: 2018-09-02 15:39 UTC (History)
10 users (show)



Attachments
PATH_INFO fix for mod_proxy_balancer.c (1.36 KB, text/plain)
2014-12-02 22:16 UTC, Stefan Rubner
Details
PATH_INFO fix for mod_proxy_fcgi.c (1.75 KB, text/plain)
2014-12-02 22:16 UTC, Stefan Rubner
Details
Combined Patch for Apache 2.4.10. Contains the other, older patches. (3.39 KB, patch)
2014-12-03 20:54 UTC, Stefan Rubner
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jérôme Loyet 2011-07-16 23:31:52 UTC
Hello,

I'm the maintener and developper behind php-fpm. I've been playing with apache 2.3.12 and FPM and I discover that mod_proxy_fcgi is not RFC 3875 compliant.

According to RFC 3875, with the URL 'http://www.mysite.com/path/to/test.php/toto?foo=bar' the following FASTCGI variables must be send to the fastcgi server:
- SCRIPT_NAME=/path/to/test.php
- QUERY_STRING=foo=bar
- PATH_INFO=/toto
- PATH_TRANSLATED=%{DOCUMENT_ROOT}/toto

I've configured mod_proxy_fcgi this way for my tests:

  DocumentRoot /home/fat/web/docs/php
  SetEnvIf Request_URI . proxy-fcgi-pathinfo=1
  ProxyPassMatch ^/(.+\.php.*)$ fcgi://127.0.0.1:9000/$1

And it sends the following FASTCGI variables:
- SCRIPT_NAME=(empty string)
- QUERY_STRING=foo=bar
- PATH_INFO=/path/to/test.php/toto
- PATH_TRANSLATED=proxy:fcgi://127.0.0.1:9000/path/to/test.php/toto/path/to/test.php/toto
- DOCUMENT_ROOT=/home/fat/web/docs/php
- SCRIPT_FILENAME=proxy:fcgi://127.0.0.1:9000/path/to/test.php/toto
- REQUEST_URI=/path/to/test.php/toto?foo=bar

as you see:
- SCRIPT_NAME is not set (it's set to /path/to/test.php/toto if proxy-fcgi-pathinfo is not set)
- QUERY_STRING is set correctly
- PATH_INFO is not correct as it should be set to '/toto'
- PATH_TRANSLATED is not correct as it should be set to /home/fat/web/docs/php/toto

- DOCUMENT_ROOT is set correctly even if this variable is not defined in the RFC
- REQUEST_URI is set correctly even if this variable is not defined in the RFC
- SCRIPT_FILENAME is set not correctly even if this variable is not defined in the RFC. It should be set to '/home/fat/web/docs/php/path/to/test.php'.

I didn't really checked other fastcgi variables.

Then, I've made the test with the URL 'http://www.mysite.com/path/to/test.php/toto?foo=bar' (I removed the /toto after the script name, which is a more common usage I think). mod_proxy_fcgi should send:
- SCRIPT_NAME=/path/to/test.php
- QUERY_STRING=foo=bar
- PATH_INFO=(empty string)
(PATH_TRANSLATED must not be send when PATH_INFO is empty)

and it sends with proxy-fcgi-pathinfo:
- SCRIPT_NAME=(empty string)
- QUERY_STRING=foo=bar
- PATH_INFO=/path/to/test.php
- PATH_TRANSLATED=proxy:fcgi://127.0.0.1:9000/path/to/test.php/path/to/test.php
- SCRIPT_FILENAME=proxy:fcgi://127.0.0.1:9000/path/to/test.php
- DOCUMENT_ROOT=/home/fat/web/docs/php
- REQUEST_URI=/path/to/test.php?foo=bar

or without proxy-fcgi-pathinfo:
- SCRIPT_NAME=/path/to/test.php
- QUERY_STRING=foo=bar
- SCRIPT_FILENAME=proxy:fcgi://127.0.0.1:9000/path/to/test.php
- DOCUMENT_ROOT=/home/fat/web/docs/php
- REQUEST_URI=/path/to/test.php?foo=bar


The problem is still the same:
- proxy-fcgi-pathinfo is buggy (SCRIPT_NAME empty and PATH_INFO/TRANSLATED set to wrong values)
- SCRIPT_FILENAME is not set correctly (proxy:fcgi://127.0.0.1:9000 should be replace by DOCUMENT_ROOT)

I can make more tests if needed.

I really think mod_proxy_fcgi should be RFC 3875.

Hope it helps
++ jerome
Comment 1 Jim Jagielski 2012-11-01 15:25:11 UTC
Can you reconfirm w 2.4.x?
Comment 2 admin 2013-04-22 09:14:26 UTC
I use mod_proxy_fcgi along with FPM:

ProxyPassMatch ^/(.*\.php(/.*)?)$ 
fcgi://172.16.0.11:1007/home/admin/domains/domenaadmina.fulo.inten.pl/public_htm
l/$1 timeout=180

Using scripts like this:
/glowna/index.php/aaa/bbb/ccc

causes _SERVER["SCRIPT_NAME"] to be wrongly evaluated. Instead of 
/glowna/index.php FPM returns 
/glowna/index.php/aaa/bbb/ccc which obviously also destroys _SERVER["PHP_SELF"].

We've checked it with cgi.fix_pathinfo = 0 (no input file specified error) and 
cgi.fix_pathinfo = 1.
proxy-fcgi-pathinfo = 1 doesn't help to.



Expected result:
----------------
_SERVER["REQUEST_URI"]	/glowna/index.php/aaa/bbb/ccc
_SERVER["SCRIPT_NAME"]	/glowna/index.php
_SERVER["PATH_INFO"]	/aaa/bbb/ccc
_SERVER["ORIG_SCRIPT_FILENAME"]	
/home/admin/domains/domenaadmina.fulo.inten.pl/public_html/glowna/index.php/aaa/bb
b/ccc
_SERVER["PATH_TRANSLATED"]	
/home/admin/domains/domenaadmina.fulo.inten.pl/public_html/aaa/bbb/ccc
_SERVER["PHP_SELF"]	/glowna/index.php/aaa/bbb/ccc

Actual result:
--------------
_SERVER["REQUEST_URI"]	/glowna/index.php/aaa/bbb/ccc
_SERVER["SCRIPT_NAME"]	/glowna/index.php/aaa/bbb/ccc
_SERVER["PATH_INFO"]	/aaa/bbb/ccc
_SERVER["ORIG_SCRIPT_FILENAME"]	
/home/admin/domains/domenaadmina.fulo.inten.pl/public_html/glowna/index.php/aaa/bb
b/ccc
_SERVER["PATH_TRANSLATED"]	
/home/admin/domains/domenaadmina.fulo.inten.pl/public_html/aaa/bbb/ccc
_SERVER["PHP_SELF"]	/glowna/index.php/aaa/bbb/ccc/aaa/bbb/ccc
Comment 3 Jérôme Loyet 2013-05-13 20:27:33 UTC
Hi

I've made some more testing using apache 2.4.4.

To ensure the results were not altered by FPM I've made a very simple perl script which act as a fastcgi server using either TCP or unix socket. It returns all the environment variables apache has sent.

Here is the script:
#!/usr/bin/perl
use FCGI;
use Socket;
use FCGI::ProcManager;
use Data::Dumper;

$num_args = $#ARGV + 1;
if ($num_args != 1) {
  print "\nUsage: fcgi.pl <socket>\n";
  exit 1;
}

$proc_manager = FCGI::ProcManager->new( {n_processes => 1} );
$socket = FCGI::OpenSocket( $ARGV[0], 10 )
$request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%req_params, $socket, &FCGI::FAIL_ACCEPT_ON_INTR );
$proc_manager->pm_manage();
if ($request) {
  while ( $request->Accept() >= 0 ) {
    $proc_manager->pm_pre_dispatch();
    print("Content-type: text/plain\r\n\r\n");
    print Dumper(\%req_params);
  }
}
FCGI::CloseSocket($socket);

Here are the results I got with different configurations


*** request /test.php?N=1
*** using ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/$1
*** without proxy-fcgi-pathinfo
          'SCRIPT_NAME' => '/test.php',
          'PATH_INFO' => UNSET,
          'SCRIPT_FILENAME' => 'proxy:fcgi://127.0.0.1:9000/test.php',
          'QUERY_STRING' => 'N=1',
          'SCRIPT_URL' => '/test.php',
          'DOCUMENT_ROOT' => '/usr/local/apache-2.4/htdocs',
          'PATH_TRANSLATED' => UNSET,
          'SCRIPT_URI' => UNSET,
          'REQUEST_URI' => '/test.php?N=1',

*** request /test.php/more?N=1
*** using ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/$1
*** without proxy-fcgi-pathinfo
          'SCRIPT_NAME' => '/test.php/more',
          'PATH_INFO' => UNSET,
          'SCRIPT_FILENAME' => 'proxy:fcgi://127.0.0.1:9000/test.php/more',
          'QUERY_STRING' => 'N=1',
          'SCRIPT_URL' => '/test.php/more',
          'DOCUMENT_ROOT' => '/usr/local/apache-2.4/htdocs',
          'PATH_TRANSLATED' => UNSET,
          'SCRIPT_URI' => UNSET,
          'REQUEST_URI' => '/test.php/more?N=1',

*** request /test.php?N=1
*** using ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/$1
*** with proxy-fcgi-pathinfo
          'SCRIPT_NAME' => '',
          'PATH_INFO' => '/test.php',
          'SCRIPT_FILENAME' => 'proxy:fcgi://127.0.0.1:9000/test.php',
          'QUERY_STRING' => 'N=1',
          'SCRIPT_URL' => UNSET,
          'DOCUMENT_ROOT' => '/usr/local/apache-2.4/htdocs',
          'PATH_TRANSLATED' => 'proxy:fcgi://127.0.0.1:9000/test.php/test.php',
          'SCRIPT_URI' => UNSET,
          'REQUEST_URI' => '/test.php?N=1',

*** request /test.php/more?N=1
*** using ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/$1
*** with proxy-fcgi-pathinfo
          'SCRIPT_NAME' => '',
          'PATH_INFO' => '/test.php/more',
          'SCRIPT_FILENAME' => 'proxy:fcgi://127.0.0.1:9000/test.php/more',
          'QUERY_STRING' => 'N=1',
          'SCRIPT_URL' => UNSET,
          'DOCUMENT_ROOT' => '/usr/local/apache-2.4/htdocs',
          'PATH_TRANSLATED' => 'proxy:fcgi://127.0.0.1:9000/test.php/more/test.php/more',
          'SCRIPT_URI' => UNSET,
          'REQUEST_URI' => '/test.php/more?N=1',

*** request /test.php?N=1
*** using RewriteRule ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/$1 [P]
*** without proxy-fcgi-pathinfo
          'SCRIPT_NAME' => '/test.php',
          'PATH_INFO' => UNSET,
          'SCRIPT_FILENAME' => 'proxy:fcgi://127.0.0.1:9000/test.php',
          'QUERY_STRING' => 'N=1',
          'SCRIPT_URL' => '/test.php',
          'DOCUMENT_ROOT' => '/usr/local/apache-2.4/htdocs',
          'PATH_TRANSLATED' => UNSET,
          'SCRIPT_URI' => 'http://my.test.com/test.php',
          'REQUEST_URI' => '/test.php?N=1',

*** request /test.php/more?N=1
*** using RewriteRule ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/$1 [P]
*** without proxy-fcgi-pathinfo
          'SCRIPT_NAME' => '/test.php/more',
          'PATH_INFO' => UNSET,
          'SCRIPT_FILENAME' => 'proxy:fcgi://127.0.0.1:9000/test.php/more',
          'QUERY_STRING' => 'N=1',
          'SCRIPT_URL' => '/test.php/more',
          'DOCUMENT_ROOT' => '/usr/local/apache-2.4/htdocs',
          'PATH_TRANSLATED' => UNSET,
          'SCRIPT_URI' => 'http://my.test.com/test.php/more',
          'REQUEST_URI' => '/test.php?N=1',

*** request /test.php?N=1
*** using RewriteRule ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/$1 [P]
*** with proxy-fcgi-pathinfo
          'SCRIPT_NAME' => '',
          'PATH_INFO' => '/test.php',
          'SCRIPT_FILENAME' => 'proxy:fcgi://127.0.0.1:9000/test.php',
          'QUERY_STRING' => 'N=1',
          'SCRIPT_URL' => '/test.php',
          'DOCUMENT_ROOT' => '/usr/local/apache-2.4/htdocs',
          'PATH_TRANSLATED' => 'proxy:fcgi://127.0.0.1:9000/test.php/test.php',
          'SCRIPT_URI' => 'http://my.test.com/test.php',
          'REQUEST_URI' => '/test.php?N=1',

*** request /test.php/more?N=1
*** using RewriteRule ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/$1 [P]
*** with proxy-fcgi-pathinfo
          'SCRIPT_NAME' => '',
          'PATH_INFO' => '/test.php/more',
          'SCRIPT_FILENAME' => 'proxy:fcgi://127.0.0.1:9000/test.php/more',
          'QUERY_STRING' => 'N=1',
          'SCRIPT_URL' => '/test.php',
          'DOCUMENT_ROOT' => '/usr/local/apache-2.4/htdocs',
          'PATH_TRANSLATED' => 'proxy:fcgi://127.0.0.1:9000/test.php/more/test.php/more',
          'SCRIPT_URI' => 'http://my.test.com/test.php/more',
          'REQUEST_URI' => '/test.php/more?N=1',



Remarks:
For a reminder, the RFC 3875 is available at http://www.ietf.org/rfc/rfc3875.

*** PATH_INFO ***
    The PATH_INFO variable specifies a path to be interpreted by the CGI
    script.  It identifies the resource or sub-resource to be returned by
    the CGI script, and is derived from the portion of the URI path
    hierarchy following the part that identifies the script itself.

As I understand it, PATH_INFO should be empty or not set for URL like /test.php and
should be set to /more for URL like /test.php/more.
That's not what happened with mod_proxy_fcgi. Sometimes it's not set where it should be
(without proxy-fcgi-pathinfo) and when proxy-fcgi-pathinfo is set, PATH_INFO is always set
to /test.php or /test.php/more. If we assume that this is a normal behaviour without proxy-fcgi-pathinfo
this is a bug when proxy-fcgi-pathinfo is set.

*** PATH_TRANSLATED ***
    The PATH_TRANSLATED variable is derived by taking the PATH_INFO
    value, parsing it as a local URI in its own right, and performing any
    virtual-to-physical translation appropriate to map it onto the
    server's document repository structure.
    This is the file location that would be accessed by a request for
      <scheme> "://" <server-name> ":" <server-port> <extra-path>
    where <scheme> is the scheme for the original client request and
    <extra-path> is a URL-encoded version of PATH_INFO, with ";", "=" and
    "?"  reserved.

As I understand it, PATH_TRANSLATED is forged from PATH_INFO:
map_to_physical(http://<server_name>:<server_port>/PATH_INFO) which should result
in my test case (/test.php/more with DOCUMENT_ROOT set to /usr/local/apache-2.4/htdocs) to
PATH_TRANSLATED=/usr/local/apache-2.4/htdocs/more
But PATH_TRANSLATED is always an url begining with proxy:fcgi:// and the script name (/test.php)
is also included. Moreover, the script_url (/test.php/more) appears twice in PATH_TRANSLATED.

*** QUERY_STRING ***
it is set correctly in all the case.

*** SCRIPT_NAME ***
The SCRIPT_NAME variable MUST be set to a URI path (not URL-encoded)
    which could identify the CGI script (rather than the script's
    output).  The syntax is the same as for PATH_INFO (section 4.1.5)
      SCRIPT_NAME = "" | ( "/" path )
    The leading "/" is not part of the path.  It is optional if the path
    is NULL; however, the variable MUST still be set in that case.
    The SCRIPT_NAME string forms some leading part of the path component
    of the Script-URI derived in some implementation-defined manner.  No
    PATH_INFO segment (see section 4.1.5) is included in the SCRIPT_NAME
    value.

As I understand it, SCRIPT_NAME must always identifies the CGI script. In my
test SCRIPT_NAME should be set to /test.php in all the case. This is not the case.
When proxy-fcgi-pathinfo is set, SCRIPT_NAME is always empty.
When proxy-fcgi-pathinfo is not set, SCRIPT_NAME always include what should be the 
PATH_INFO (/more): /test.php/more instead of /test.php

*** DOCUMENT_ROOT ***
Even if it's not defined in the RFC, the value is consistent in my tests and
the value is correct.

*** REQUEST_URI ***
Even if it's not defined in the RFC, the value is consistent in my tests and
the value is correct.

*** SCRIPT_URI and SCRIPT_URL ***
Those variables are set when using RewriteRule and are not set when using ProxyPass.
Even if they are not defined in the RFC, the values seems correct when RewriteRule is used.

*** SCRIPT_FILENAME ***
Even if it's not defined in the RFC, the value is consistent in my tests. The value is an
URI which does not make sense to me as the variable is named FILENAME. For me, the value should
be set to DOCUMENT_ROOT + SCRIPT_NAME.


For me, mod_fcgi does not respect the corresponding RFC and it makes fastcgi servers complex to match with apache fastcgi client implementation.

PHP-FPM code for fastcgi is a mess and I'm trying to clean all this to make something consistent. But apache implementations (mod_fastcgi or mod_proxy_fcgi) make me do some very complex and dirty hacks to make things right. I would be greatful if apache mod_proxy_fcgi can be RFC compliant, not only for FPM but also for others fastcgi servers.

Hope this comment is not too long or too messy.
Hope it helps make things smoother :-)

++ Jerome
Comment 4 raffaele 2013-06-08 20:18:55 UTC
Hi,

I got the same problem when i configure Apache 2.4.4 with PHP-FPM (both last versions of PHP releases, 5.3.25 and 5.4.15).

Each vhost of Apache has a dedicate pool of PHP-FPM with chroot, own resources and other settings.
On the vhost mod_proxy_fcgi work well on a single php file like info.php or any CMS like wordpress, joomla and vbulletin without URL SEO rewrite enable.

When enable the URL SEO each url like: http://domain.com/index.php/some-articles will break.
Also another type of URL seo break (the vBseo of vBulletin 4 platform for forum): http://domain.com/forum/category/thread/
On headers response there are a 301 code that redirect to /

While my project it's based on a cluster using only PHP-FPM i'm in crisis because i'm unable make working much sites with url rewrite rules that normaly work with old mod_fastcgi and Apache 2.2.22.

My situation is also same as this http://www.msgerror.com/qid450628.html
Can i know if there are a bugfix or any workground work in progress?

Many Thanks
Comment 5 Stefan Rubner 2014-12-02 22:16:05 UTC
Created attachment 32253 [details]
PATH_INFO fix for mod_proxy_balancer.c

Fixes PATH_INFO env var according to RFC 3875 for mod_proxy_balancer.c
Comment 6 Stefan Rubner 2014-12-02 22:16:57 UTC
Created attachment 32254 [details]
PATH_INFO fix for mod_proxy_fcgi.c

Fixes PATH_INFO according to RFC 3875 for mod_proxy_fcgi.c
Comment 7 Stefan Rubner 2014-12-02 22:18:36 UTC
Jérôme,

I don't know whether you're still following this issue but I ran into the same problem recently.

When trying to build a fix I found that by fixing the PATH_INFO issue all other problems you found and described went away, too. The only "problem" that is still left is that my current patch set doesn't produce a clean SCRIPT_NAME but rather leaves the PATH_INFO portion in the string. Personally I think one could live with that but of course I'd like your input on that. If you think that absolute adherence to RFC 3875 is necessary I could try to dive deeper into the code.

Anyway, I'd be happy if you could test the attached patches (ugly code, I know. It's currently more a proof of concept than an actual patch) and let me know what you think.

-Stefan
Comment 8 Jérôme Loyet 2014-12-02 22:34:22 UTC
Hi,

I did not review your patch as I'm not confortable with apache code.

But if the only problem is the PATH_INFO which include the SCRIPT_NAME, that is not big deal. Not so many users uses PATH_INFO. It would be acceptable comparing to the current situation which is messy.

It's been a while since this bug has been opened and I don't have time to setup a full environment for testing right now.

But thx for your effort, it's good to see someone trying to take care of this problem.
Comment 9 Stefan Rubner 2014-12-03 10:23:57 UTC
Jérôme,

Right now it's the other way round. PATH_INFO is correct while SCRIPT_NAME isn't 100% correct. An example:

If I call http://127.0.0.1/this/is/my/test.php/more/path/info?var=1234

the (shortened) output of the perl script you used will be:

=== Proxy Balancer ===

$VAR1 = {
          'SCRIPT_NAME' => '/this/is/my/test.php/more/path/info',
          'PATH_INFO' => '/more/path/info?var=1234',
          'SCRIPT_FILENAME' => 'proxy:balancer://php5fpm/var/www/html/this/is/my/test.php/more/path/info?var=1234',
          'SERVER_SOFTWARE' => 'Apache/2.4.10 (Debian)',
          'QUERY_STRING' => 'var=1234',
          'BALANCER_WORKER_NAME' => 'fcgi://127.0.0.1:9000/',
          'DOCUMENT_ROOT' => '/var/www/html',
          'PATH_TRANSLATED' => '/var/www/html/more/path/info?var=1234',
          'REQUEST_URI' => '/this/is/my/test.php/more/path/info?var=1234',
        };


=== Proxy FCGI ===

$VAR1 = {
          'SCRIPT_NAME' => '/this/is/my/test.php/more/path/info',
          'PATH_INFO' => '/more/path/info?var=1234',
          'SCRIPT_FILENAME' => 'proxy:fcgi://127.0.0.1:9000/this/is/my/test.php/more/path/info',
          'SERVER_SOFTWARE' => 'Apache/2.4.10 (Debian)',
          'QUERY_STRING' => 'var=1234',
          'DOCUMENT_ROOT' => '/var/www/html',
          'PATH_TRANSLATED' => '/var/www/html/more/path/info?var=1234',
          'REQUEST_URI' => '/this/is/my/test.php/more/path/info?var=1234',
        };

The main question is whether PHP-FPM could "live" with that state of the SCRIPT_NAME env var and whether the others would be fine. I guess I could fix SCRIPT_NAME as well if need be.

As for the prefixing of SCRIPT_FILENAME with "proxy:(fcgi|balancer):": Looking at the Apache code I think I see why they're doing it and I think they do it wrong for the wrong reasons: It looks like Apache is trying to determine whether an incoming request actually is a proxy request using these prefixes and if it isn't while Apache is in the "mod_proxy_*" execution path, a request will be declined. Personally I disagree with this behavior because imo any request that comes in should be served as long it is a valid HTTP 1.0/1.1 request. But since I think it will be hard to convince the Apache project of that view and since there's already a fix for the the "proxy:fcgi:" route in PHP-FPM I guess it would be easier to also fix the "proxy:balancer:" stuff on PHP's side.

-Stefan
Comment 10 Jérôme Loyet 2014-12-03 10:28:55 UTC
Hi,

apache code is a mess and as a consequence PHP-FPM code concerning fcgi variables is a mess too.

Since nobody from apache wants to take care of this problem I won't add more dirty tricks in PHP-FPM code. If you want to use PHP-FPM, stop using apache as it sucks and use nginx instead. It's simple, faster and has always been working as expected.

I can't say more :-)

good luck with your patch because after developping you'll have to submit it to the apache project. Maybe it'll be done before 2020 :-)

my 2 cents
Comment 11 Eric Covener 2014-12-03 14:14:01 UTC
It seems to me the problem with all of these related variables is that mod_proxy does not map requests to any file, so there is no reasonable split between the script name and path info.

If you configure mod_proxy_fcgi with the "handler" method documented here:

http://httpd.apache.org/docs/current/mod/mod_proxy_fcgi.html#examples

Then the core of apache does map the file and does seem to set reasonable SCRIPT_FILENAME and PATH_INFO (at least by desk checking in comparison to the totally wrong values in this PR).

Can someone with a better eye for this at least confirm so we can get it documented for the time being?
Comment 12 Eric Covener 2014-12-03 14:23:27 UTC
arg, ignore my last comment -- I wasn't using the mock server so result cannot be trusted.
Comment 13 Stefan Rubner 2014-12-03 20:46:40 UTC
> apache code is a mess and as a consequence PHP-FPM code concerning fcgi
> variables is a mess too.

Actually, the main problem (as I see it) were two "thinkos" in the relevant code. The first (as Eric mentions in his comment above) is that there's no mapping to an actual handler/file extension when using mod_proxy_*.
And since there's no mapping, mod_proxy_* indeed has no way of determining where the SCRIPT_NAME ends and the PATH_INFO starts.

My code fixes this by "assuming" that anything that contains a dot (".") has to be a file name and thus marks the "handler". Consequently, everything after the dot starting with a slash ("/") or a question mark ("?") is considered to be the "PATH_INFO". While this is ugly and clearly a hack, it most certainly reflects the reality on the vast majority of web sites out there. The cleaner solution would be to go through to the list of defined handlers and check whether on of those is present in the URL. However, I decided to sacrifice thoroughness for speed in this particular case.

The second "thinko" can be found in util_script.c (I have another patch coming up for that). Here the original idea obviously was to compare the request URI against the PATH_INFO and use the result as SCRIPT_NAME. However, the author seemingly overlooked that the URI passed to the function is already stripped of the GET parameters while the PATH_INFO is not. So the comparison would always fail and thus return a wrong SCRIPT_NAME.

> Since nobody from apache wants to take care of this problem I won't add more
> dirty tricks in PHP-FPM code. 

I see your point there, but in this case it would be just one line that would need to be modified a bit if I remember correctly. I hacked support for "proxy:balancer:"  into the PHP-FPM we're using so actually this was a request for the benefit of other users, not for me.

> If you want to use PHP-FPM, stop using apache
> as it sucks and use nginx instead. It's simple, faster and has always been
> working as expected.

Actually I am using Nginx (which btw doesn't conform to RFC 3875 either) on most of our servers. However, there are some edge cases where I need to use Apache and for those cases it would be nice to be able to use mod_proxy_balancer instead of libphp5. That's why I worked on this issue. I posted my solution to your issue so others can profit from it even in the more than likely case that the Apache project will reject the patches ;)

> good luck with your patch because after developping you'll have to submit it
> to the apache project. Maybe it'll be done before 2020 :-)

As said above I don't really care whether my patches are included into a project or not. I just want to make them available so others can use them if they want to.

-Stefan
Comment 14 Stefan Rubner 2014-12-03 20:54:29 UTC
Created attachment 32257 [details]
Combined Patch for Apache 2.4.10. Contains the other, older patches.

Combined Patch for
- modules/proxy/mod_proxy_balancer.c
- modules/proxy/mod_proxy_fcgi.c
- server/util_script.c

to make Apache's mod_proxy_balancer and mod_proxy_fcgi RFC 3875 compliant.
Comment 15 Stefan Rubner 2014-12-03 22:42:55 UTC
(In reply to Eric Covener from comment #11)
> If you configure mod_proxy_fcgi with the "handler" method documented here:
> http://httpd.apache.org/docs/current/mod/mod_proxy_fcgi.html#examples
> Then the core of apache does map the file and does seem to set reasonable
> SCRIPT_FILENAME and PATH_INFO (at least by desk checking in comparison to
> the totally wrong values in this PR).

Your last comment not withstanding I checked your suggestion with Apache 2.4.10 with and without my patches applied. While your statement seems to be true when used against the Perl script, I found that either version at least for the moment segfaults for me when used on a live site. Both versions seem to work fine when used with simple scripts like, say, phpinfo() and friends.

-Stefan
Comment 16 Philip Cass 2014-12-04 11:59:18 UTC
While people are active, can I also point out bug 57087 where apache won't send a cgi-required content length header if it wasn't a required header for http and the client didn't send it (in other words, when transfer-encoding:chunked is used) as this is also an RFC compliance issue
Comment 17 Nick Kew 2014-12-08 15:54:56 UTC
(In reply to Stefan Rubner from comment #14)
> Created attachment 32257 [details]
> Combined Patch for Apache 2.4.10. Contains the other, older patches.

Stefan, thanks for the patch and the analysis.  This is closely related to some work I'm doing, so I'll certainly test-drive it this week.

I've been running it configured with AddHandler for PHP-FPM.  I guess from comments here a solution configured this way may behave differently when configured using ProxyPass or (shudder) RewriteRule?
Comment 18 Yann Ylavic 2014-12-08 16:06:10 UTC
(In reply to Nick Kew from comment #17)
> This is closely related to
> some work I'm doing, so I'll certainly test-drive it this week.

Eric has something (more generic) about this too, see http://mail-archives.apache.org/mod_mbox/httpd-dev/201412.mbox/%3CCALK%3DYjPK539aZvskfAP0OhY0d14TeP0KacKbL0FkiYznpmjYQg%40mail.gmail.com%3E
Comment 19 Stefan Rubner 2014-12-08 17:28:26 UTC
(In reply to Nick Kew from comment #17)
> I've been running it configured with AddHandler for PHP-FPM.  I guess from
> comments here a solution configured this way may behave differently when
> configured using ProxyPass or (shudder) RewriteRule?

I would think that using the SetHandler approach together with FilesMatch as documented here:

http://httpd.apache.org/docs/current/mod/mod_proxy_fcgi.html#examples

currently is the best approach. 

However, this method is only available from Apache 2.4.10 onward. Also I think that there's another "thinko" in the example. Imho it should read <FilesMatch \.php> (note the missing $) so the handler would also trigger for URIs like /path/to/my.php/with/some/added/stuff?and=vars ;)

The AddHandler method was the one we were using before, but didn't find a good way to use it together with more than one PHP-FPM instance. That's why I explored the proxy_balancer way combined with fcgi:// BalancerMembers. The good news is that this will alos work with the SetHandler method according to my tests. That said I still have some issues but didn't find the time to do some further testing. Maybe I'll find more time in the next few days.

-Stefan
Comment 20 Eric Covener 2014-12-08 17:39:07 UTC
> However, this method is only available from Apache 2.4.10 onward. Also I
> think that there's another "thinko" in the example. Imho it should read
> <FilesMatch \.php> (note the missing $) so the handler would also trigger
> for URIs like /path/to/my.php/with/some/added/stuff?and=vars ;)

This works as-is (\.php$) because <FilesMatch> is relative to the mapped file not just the text in the URL. In other words, it knows the file is $docroot/ /path/to/my.php w/ PATH_INFO of /with/some/added/stuff an query string and=vars.

I hope to add some balancer examples, and fixes for SCRIPT_FILENAME and PATH_INFO in combination with balancer soon.
Comment 21 Nick Kew 2014-12-17 16:07:03 UTC
(In reply to Stefan Rubner from comment #19)

> I would think that using the SetHandler approach together with FilesMatch as
> documented here:
> 
> http://httpd.apache.org/docs/current/mod/mod_proxy_fcgi.html#examples
> 
> currently is the best approach. 

That appears to be fully fixed in trunk and 2.4.10, unless I'm missing something.
Other configs remain TBD, though trunk/2.4.10 fix most of what the OP here reports.  Other configs, including a RewriteMap use case I'm testing, still need fixing.

However, we have another confounding factor with PHP-FPM here: the vars reported by PHP's phpinfo() are themselves 'corrected' from what the server sent.  Though phpinfo's SCRIPT_NAME erroneously contains PATH_INFO.

Jérôme Loyet, are you still here?  Is PHP ready to switch off this autocorrection without troubling the end-users as and when this is fully fixed?
Comment 22 Leho Kraav @lkraav 2017-06-20 14:47:04 UTC
Hmm, I wonder if this bug is now relevant again with 2.4.26 breaking `$_SERVER['PHP_SELF']`

Some var_dump()-ing:

/var/www/wordpress.git/wp-includes/vars.php:31:

'REQUEST_URI' => string '/wp-admin/network/plugins.php' (length=29)

2.4.25 ['PHP_SELF']=> string(29) '/wp-admin/network/plugins.php'

2.4.26 ['PHP_SELF'] => string '/plugins.php' (length=12)
2.4.26 ['SCRIPT_NAME'] => string '/plugins.php' (length=12)

Reverting to 2.4.25 obviously fixes things immediately, but what's the right configuration change now for 2.4.26?
Comment 23 Leho Kraav @lkraav 2017-06-20 15:05:47 UTC
(In reply to Leho Kraav @lkraav from comment #22)

> Reverting to 2.4.25 obviously fixes things immediately, but what's the right
> configuration change now for 2.4.26?

Solution, as unintuitive as it may be, is specifying `ProxyFCGIBackendType GENERIC`.

I guess the follow-up question is, if I'd want to have `ProxyFCGIBackendType` kept as the default `FPM`, what other configuration directives do I then have to adjust?