-
Notifications
You must be signed in to change notification settings - Fork 7.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Partial content on POST request with 'chunked' transfer encoding #9949
Comments
Hmm, I tried variations of the following script, but for me, <?php
$s = fsockopen("localhost", 80);
fwrite($s, "POST /gh9949.php HTTP/1.1\r\n");
fwrite($s, "Host: localhost\r\n");
fwrite($s, "User-Agent: curl/7.83.1\r\n");
fwrite($s, "Accept: */*\r\n");
fwrite($s, "Content-Type: application/x-www-form-urlencoded\r\n");
fwrite($s, "Transfer-Encoding: chunked\r\n");
fwrite($s, "\r\n");
fwrite($s, "f\r\n");
fwrite($s, "foo=bar&baz=qux\r\n");
// fwrite($s, "0\r\n\r\n");
var_dump(fread($s, 4096)); Could you come up with a reproduce script? |
Yes sure I should have done that before, please find attached the (ugly) c code that we used to reproduce it. post-issue.zip (the exit(0/0) is to simulate a violent crash but I don't think it's necessary) To compile: It must call a php script, as simple as for example:
What makes it not hung I guess is the fact that we (abruptly) close the TCP connection, which triggers the end of the while loop. Do not hesitate to ask for more information. |
Ah, indeed. Thank you! |
After having a closer look, I wonder if and how we should handle other
That appears to be reasonable, so I've looked what happened if
Hmm, there is no Content-Length for this chunked request, though. ;) |
Yes it's indeed normal, according to the RFC. Yes HTTP_INTERNAL_SERVER_ERROR would be good I guess, the php script should interrupt and/or be signaled to stop in some way, how could you trigger this internal error ? |
Hello, I may have misunderstood your last comment @cmb69, do you confirm you see the current behavior as a bug ? |
Yes; that's why I added the |
`ap_get_brigade()` may fail for different reasons, and we must not pretend that a partially read POST payload is fine; instead we report a content length of zero what matches all other `read_post()` callbacks of bundled SAPIs.
Thank you for the fix, though when testing it (on php8.2), I still can reproduce the issue: apache returns HTTP 200 and the page gets executed. Are you sure returning 0 is enough ? Do we need to add a check for this length in the php code (and how) ? |
I've checked the other bundled SAPI's, and they all just return |
Ok thank you we'll make do with the size :) |
* PHP-8.1: Fix GH-9949: Partial content on incomplete POST request
* PHP-8.2: Fix GH-9949: Partial content on incomplete POST request
Description
Using sapi_apache2 and performing a POST query with the "transfer-encoding: chunk" header, if the query is interrupted before all chunked/data were sent, PHP still accept the partial content received and execute normally, returning a 200 status.
Per RFC, it should return 400, which apache2 does if the php module is not activated. Also php should either not get executed at all, or warned in some way that the content is partial.
Looking at this closely, it seems the issue comes from the following code:
In function php_apache_sapi_read_post of
sapi_apache2.c
lines 196-205 (on PHP8.2 branch):The return of
ap_get_brigade
exit normally if it receives anything other than APR_SUCCESS and in particular does not check if it returns APR_INCOMPLETE in which case it should return a 400 response code.I checked a quick and dirty fix:
And it returns 400 correctly (but clearly I am not suggesting this as the correct fix, just demonstrating that the ap_get_bricade() return code should be taken care of).
PHP Version
8.0+
Operating System
Ubuntu 18.04+
The text was updated successfully, but these errors were encountered: