php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79991 Connection handling mod_php and mod_fcgid
Submitted: 2020-08-18 15:05 UTC Modified: 2020-08-30 04:22 UTC
From: hoover at gmx dot at Assigned:
Status: No Feedback Package: *General Issues
PHP Version: 7.2.33 OS: Windows Server 2012
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: hoover at gmx dot at
New email:
PHP Version: OS:

 

 [2020-08-18 15:05 UTC] hoover at gmx dot at
Description:
------------
This thing is nearly version independent. The behavior can
be found with 5.4, 7.0 and 7.2.

There are many bug reports for this case but none of them has
a reproducible solution. The bug reports are starting 2005 so
this thing is long lasting.

We have a php-rest-api (no framework) that simplifies a heavy
(java) soap-api.

We have to do a lot of work after the rest/soap-processing. So,
the client of the rest-api gets a response, php should finish
the request and then php should procced with the internal work.

At the point where the client gets the response php should be
aware if client is still alive. So in short:

1) Client - requests
2) PHP - processes
3) PHP - requests soap-server
4) PHP - processes
5) PHP - repsonses to client
6) PHP - should check if client still alive
7) PHP - should close connection to client
8) PHP - processes
9) PHP finished.


So it looks like:

* ignore_user_abort = true
* No use of gzip or ...
* zlib.output_compression = 0
* output_buffering = '0'
* implicit_flush = 1;
* ob_implicit_flush(1);
* Content-Encoding: identity

Functions for connHandling:
connection_aborted()
AND
connection_status()


A) mod_php

A1) If we do a simple echo of the payload and a flush()
the client waits until 9) (until the php-script has total
finished). A client abort, with above functions, is never
detected.

A2) After thousand days of trail and error we noticed that at
least a content-length header has to be set by the php-script
to "release the client". So 7) close connection to client
does work. But again no chance to detect a client abort.

A3) After thousand days of trail and error we noticed that 
after a content-length and an echo payload and a flush()
and at least a echo {SPACE} after the flush => detects
a client abort. Analysed with wireshark the {SPACE} fortunately
gets lost in TCP and not sent to the client.

Perfect!

BUT,

B) mod_fcgid

B1) The same thing with mod_fcgid would not work.



It was really hard to find out how connection handling has actually to
be done in this scenario. The php docs are not very helpful here.
Other bug reports are also not very helpful.


So my bug report is at least a question to the php developers:

What is the right and reliable way for connection handling (in
this scenario) wiht mod_php and mod_fcgid?


Regards,
AH


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-08-18 15:31 UTC] requinix@php.net
-Status: Open +Status: Feedback
 [2020-08-18 15:31 UTC] requinix@php.net
Client aborts are essentially client-closed connections, so they aren't detected until you try to write to that connection and TCP reports failure.
https://www.php.net/manual/en/features.connection-handling.php

> A1) If we do a simple echo of the payload and a flush()
> the client waits until 9) (until the php-script has total
> finished). A client abort, with above functions, is never
> detected.
You have to send output, then check connection_aborted().

> A2) After thousand days of trail and error we noticed that at
> least a content-length header has to be set by the php-script
> to "release the client". So 7) close connection to client
> does work. But again no chance to detect a client abort.
Correct: without a Content-Length the client has no idea how long the response is going to be. It will hang on until the connection is closed, or
with a chunked Transfer-Encoding (IIRC what PHP does by default) until it receives a 0-length chunk indicating the end of the response.

If you were using php-fpm (which Apache itself recommends) then you'd have access to fastcgi_finish_request().
https://cwiki.apache.org/confluence/display/HTTPD/Php-fcgid
https://www.php.net/manual/en/function.fastcgi-finish-request.php

> A3) After thousand days of trail and error we noticed that 
> after a content-length and an echo payload and a flush()
> and at least a echo {SPACE} after the flush => detects
> a client abort.
...which satisfies the "have to send output" requirement.

> Analysed with wireshark the {SPACE} fortunately
> gets lost in TCP and not sent to the client.
PHP should not be dropping the space, so presumably your web server is.

> B1) The same thing with mod_fcgid would not work.
I'm not familiar with mod_fcgid but I suspect you're running into FcgidOutputBufferSize.
https://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html#fcgidoutputbuffersize

If mod_fcgid is buffering output then PHP won't know about problems until the buffer gets flushed. Even then, I don't know how CGI/mod_fcgid handles client aborts.
 [2020-08-19 10:57 UTC] hoover at gmx dot at
Thank you for your quick response.


>> A1) If we do a simple echo of the payload and a flush()
>> the client waits until 9) (until the php-script has total
>> finished). A client abort, with above functions, is never
>> detected.
> You have to send output, then check connection_aborted().

I know but that is not working as expected, considering
(with configuration as mentioned above):

1) Client requests
2) Client is disconnected (closed):

3) PHP:
header('Content-length: ' . strlen(payload));
echo {payload};
flush();
connection_aborted(); => false
connection_status(); => CONNECTION_NORMAL

I did send something to the client but the
abort is not detected by PHP, if I do:

1) Client requests
2) Client is disconnected (closed):

3) PHP:
header('Content-length: ' . strlen(payload));
echo {payload};
flush();
echo " "; <= !!!
connection_aborted(); => true
connection_status(); => !CONNECTION_NORMAL


That is weird for me.


> I'm not familiar with mod_fcgid but I suspect you're running into FcgidOutputBufferSize.
> https://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html#fcgidoutputbuffersize

Thank you for that one. I am new to work with mod_fcgid
(mod_fcgid got necessary because of an unstable
combination of Apache - SSL - mod_php). So I will test
that.


It is a pitty that connection handling is no straigth
forward work and not consistent across different
servers and mechanisms.


Regards,
AH
 [2020-08-30 04:22 UTC] php-bugs at lists dot php dot net
No feedback was provided. The bug is being suspended because
we assume that you are no longer experiencing the problem.
If this is not the case and you are able to provide the
information that was requested earlier, please do so and
change the status of the bug back to "Re-Opened". Thank you.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 25 05:01:33 2024 UTC