|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2003-12-01 17:58 UTC] hexer at studentcenter dot org
Description:
------------
Problem: On Apache 1.3.x, the compiled-in mod_php4 will cause stuck httpd processes while trying to send output from php to a dead client connection.
The Cause: mod_php4.c does not set the Apache Timeout timer in the send functions.
Solution: Apache recommends any modules that write to the client to use the timeout functions provided by the Apache API.
The following modification to mod_php4.c will fix the problem and make mod_php4 comply with Apache 1.3.x Timeout setting.
static int sapi_apache_ub_write(const char *str, uint str_length TSRMLS_DC)
{
int ret=0;
if (SG(server_context)) {
+ ap_hard_timeout("php send body", (request_rec *) SG(server_context));
ret = rwrite(str, str_length, (request_rec *) SG(server_context));
+ ap_kill_timeout((request_rec *) SG(server_context));
}
if (ret != str_length) {
php_handle_aborted_connection();
}
return ret;
}
Reproduce code:
---------------
This problem is easilly reproduced by simply breaking the connection with the server while trying to load any php-generated page.
Expected result:
----------------
Apache process must abort processing the request if a single write operation exceeds the amount of seconds set in the Timeout setting in httpd.conf.
Actual result:
--------------
#0 0x420d368d in writev () from /lib/i686/libc.so.6
#1 0x0815fb08 in writev_it_all ()
#2 0x0815fe77 in large_write ()
#3 0x0815ff3b in ap_bwrite ()
#4 0x08172c10 in ap_rwrite ()
#5 0x080884da in sapi_apache_ub_write ()
#6 0x0809ab6f in php_ub_body_write_no_header (
str=0x86484ec "XXXXXX"..., str_length=4144) at /usr/local/src/php-4.3.4/main/output.c:689
#7 0x0809a117 in php_end_ob_buffer (send_buffer=1 '\001', just_flush=1 '\001')
at /usr/local/src/php-4.3.4/main/output.c:299
#8 0x0809ab39 in php_b_body_write (
str=0x8666834 "XXXXXX",
str_length=51) at /usr/local/src/php-4.3.4/main/output.c:616
#9 0x08099dd2 in php_body_write (
str=0x8666834 "XXXXXX",
str_length=51) at /usr/local/src/php-4.3.4/main/output.c:121
#10 0x080abe89 in zend_print_zval_ex (
write_func=0x808ef40 <php_body_write_wrapper>, expr=0x85992ac, indent=0)
at /usr/local/src/php-4.3.4/Zend/zend.c:211
#11 0x080abe2f in zend_print_zval (expr=0x85992ac, indent=0)
at /usr/local/src/php-4.3.4/Zend/zend.c:192
---Type <return> to continue, or q <return> to quit---
#12 0x080abb70 in zend_print_variable (var=0x85992ac)
at /usr/local/src/php-4.3.4/Zend/zend_variables.c:147
#13 0x080b64b5 in execute (op_array=0x8642fac)
at /usr/local/src/php-4.3.4/Zend/zend_execute.c:1244
#14 0x080b8635 in execute (op_array=0x862bf24)
at /usr/local/src/php-4.3.4/Zend/zend_execute.c:2181
#15 0x080acc03 in zend_execute_scripts (type=8, retval=0x0, file_count=3)
at /usr/local/src/php-4.3.4/Zend/zend.c:884
#16 0x0808ffb3 in php_execute_script (primary_file=0xbffff650)
at /usr/local/src/php-4.3.4/main/main.c:1729
#17 0x080ba6e2 in apache_php_module_main (r=0x8256564, display_source_mode=0)
at /usr/local/src/php-4.3.4/sapi/apache/sapi_apache.c:54
#18 0x08089038 in send_php ()
#19 0x080890a3 in send_parsed_php ()
#20 0x0816109c in ap_invoke_handler ()
#21 0x08175b1f in process_request_internal ()
#22 0x08175b7e in ap_process_request ()
#23 0x0816cd55 in child_main ()
#24 0x0816cfb6 in make_child ()
#25 0x0816d2f5 in perform_idle_server_maintenance ()
#26 0x0816d914 in standalone_main ()
#27 0x0816df1a in main ()
#28 0x420158d4 in __libc_start_main () from /lib/i686/libc.so.6
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Fri Oct 24 00:00:02 2025 UTC |
Ok here is a more detailed step-by-step on how to reproduce: Use php 4.3.10 compiled-in with Apache 1.3.33 1. Compile Apache 1.3 with php-4.3.10 compiled-in: In source tree: ./configure --prefix=/usr/local/apache In PHP source tree: ./configure --with-mysql \ --with-xml \ --with-apache=../apache_1.3.33 \ --enable-track-vars \ --with-gd \ --enable-discard-path \ --enable-bcmath \ --enable-gd-native-tt \ --with-freetype-dir=/usr/local \ --with-png-dir=/usr/local \ --with-jpeg-dir=/usr/local \ --with-zlib=/usr/local make make install In Apache source tree: ./configure \ --activate-module=src/modules/php4/libphp4.a \ --enable-module=php4 \ --enable-module=rewrite \ --enable-module=so \ --prefix=/usr/local/apache make make install 2. Edit httpd.conf and make sure you have the following enabled in httpd.conf: TimeOut 60 AddModule mod_status.c ExtendedStatus On <Location /server-status> SetHandler server-status Order deny,allow Allow from all </Location> 3. Create the test output script (test.php): <?php for($i = 0; $i < 1000000; $i++) { echo "XXXXXXXXXXXXXXXXXXXXXXXX<br>\n"; } ?> 4. On a different computer, open the browser and point it to test.php, as soon as test.php starts loading unplug the computer from the network, before it finishes loading. This one's important. You have to make a true dead connection without the server knowing about it. Make sure your network does not notify the server immediately that the connection was closed or there is a broken pipe etc. (by default the Linux recv has a very long timeout) 5. Check the server-status page. You will see something like this: 0-1 4990 0/177/15106 W 0.45 9 0 0.0 0.19 43.85 x.x.x.x your.server.com GET /test.php Note the 'W' under status in that particular process. 6. You will see the SS value start going way beyond the timeout setting. This _must_ happen unless the system has somehow managed to find out that the connection is broken. If the process is not in W status and 60 seconds have not passed that means the system somehow found out that the connection is broken so the dead-connection condition hasn't been simulated. Also another good experiment would be to see if the TimeOut overrides max_execution_time. If in your scenario TimeOut does in fact work, it probably overrides the max_execution_time and causes the script to abort if it runs longer than TimeOut seconds.