[php-src] PR #25038: Fix bug #61471: Incomplete POST does not timeout but is passed to PHP

From: Date: Thu, 29 Oct 2026 19:09:58 +0000
Subject: [php-src] PR #25038: Fix bug #61471: Incomplete POST does not timeout but is passed to PHP
Groups: php.git-pulls 
Request: Send a blank email to git-pulls+get-40065@lists.php.net to get a copy of this message
Pull Request: https://github.com/php/php-src/pull/25038 Author: bukka Fixes https://bugs.php.net/bug.php?id=61471 php_apache_sapi_read_post() ignores the status of ap_get_brigade() and returns 0 on error which PHP takes as the end of the body. So when the client sends less than the declared Content-Length (disconnects or stalls until mod_reqtimeout or the socket timeout aborts the read), the script runs with a partial or empty $_POST and httpd logs 200. Other handlers report the error and httpd responds with 400 or 408. This was already fixed twice and both fixes got reverted. #2180 compared content_length with read_post_bytes before running the script but PHP reads the body at startup only for POST, so every PATCH or PUT with a body was rejected. #2323 tracked the error properly but returned from the handler before php_request_shutdown() so the temporary files of partial uploads leaked (bug #74318). The error status is now kept in php_struct so it is per request and works with threaded MPMs. It is set in read_post which also keeps the data that HTTP_IN leaves in the brigade on APR_INCOMPLETE and does not try to read again after a failure. The handler checks it right after php_apache_request_ctor() (so after the POST data reading), skips the script execution and returns the status from ap_map_http_request_error() to httpd which generates the 408 or 400 response, or AP_FILTER_ERROR if the input filter already responded. The request shutdown is always done so the uploaded files are cleaned up. Reads during the script execution (php://input, enable_post_data_reading=0) are not changed because the script might have already sent a response. It means that a truncated POST now results in 400/408 instead of running the script, so for example a cancelled upload can no longer be seen through UPLOAD_ERR_PARTIAL. FPM behind nginx or mod_proxy_fcgi never got that reliably either. I tested it with wst using instances labelled bug61471 in https://github.com/wstool/wst-php-apache2handler . The request-body-incomplete-* instances cover the actual bug (stall and disconnect, chunked and Content-Length), request-body-multipart-incomplete the temp files from bug #74318, request-body-unread-methods the PATCH regression of #2180 and request-body-unread-no-post-reading and upload-chunked-over-limit check that an unread body is not reported as incomplete. All pass with prefork and event MPM.

« previous php.git-pulls (#40065) next »