[php-src] Issue #9949: Partial content on POST request with 'chunked' transfer encoding
| From: | withings-sas | Date: | Mon, 14 Nov 2022 14:22:02 +0000 |
| Subject: | [php-src] Issue #9949: Partial content on POST request with 'chunked' transfer encoding | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-242820@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/9949
Author: withings-sas
### 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):
```
while (ap_get_brigade(r->input_filters, brigade, AP_MODE_READBYTES, APR_BLOCK_READ, len) ==
APR_SUCCESS) {
apr_brigade_flatten(brigade, buf, &len);
apr_brigade_cleanup(brigade);
tlen += len;
if (tlen == count_bytes || !len) {
break;
}
buf += len;
len = count_bytes - tlen;
}
return tlen;
```
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:
```
apr_status_t ast;
ast = ap_get_brigade(r->input_filters, brigade, AP_MODE_READBYTES, APR_BLOCK_READ, len);
while (ast == APR_SUCCESS) {
apr_brigade_flatten(brigade, buf, &len);
apr_brigade_cleanup(brigade);
tlen += len;
if (tlen == count_bytes || !len) {
break;
}
buf += len;
len = count_bytes - tlen;
ast = ap_get_brigade(r->input_filters, brigade, AP_MODE_READBYTES, APR_BLOCK_READ, len);
}
if (ast == APR_INCOMPLETE) {
ctx->r->status = 400;
}
return tlen;
```
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+