Fix #73630: Built-in Weberver - overwrite $_SERVER['request_uri']

The built-in Webserver's `on_path`, `on_query_string` and `on_url`
callbacks may be called multiple times from the parser; we must not
simply replace the old values, but need to concatenate the new values
instead.

This appears to be tricky for `on_path` due to the path normalization,
so we fail if the function is called again.

The built-in Webserver logs errors during request parsing to stderr,
but this is ignored by the php_cli_server framework, and apparently the
Webserver does not send a resonse at all in such cases (instead of an
4xx).  Thus we can only check that a request with an overly long path
fails.

Closes GH-7207.
This commit is contained in:
Christoph M. Becker 2021-06-30 13:46:43 +02:00
parent 98a21d1dfb
commit d7db5701a3
No known key found for this signature in database
GPG key ID: D66C9593118BCCB6
4 changed files with 97 additions and 5 deletions

View file

@ -1629,6 +1629,9 @@ static int php_cli_server_client_read_request_on_path(php_http_parser *parser, c
{
char *vpath;
size_t vpath_len;
if (UNEXPECTED(client->request.vpath != NULL)) {
return 1;
}
normalize_vpath(&vpath, &vpath_len, at, length, 1);
client->request.vpath = vpath;
client->request.vpath_len = vpath_len;
@ -1639,17 +1642,34 @@ static int php_cli_server_client_read_request_on_path(php_http_parser *parser, c
static int php_cli_server_client_read_request_on_query_string(php_http_parser *parser, const char *at, size_t length)
{
php_cli_server_client *client = parser->data;
client->request.query_string = pestrndup(at, length, 1);
client->request.query_string_len = length;
if (EXPECTED(client->request.query_string == NULL)) {
client->request.query_string = pestrndup(at, length, 1);
client->request.query_string_len = length;
} else {
ZEND_ASSERT(length <= PHP_HTTP_MAX_HEADER_SIZE && PHP_HTTP_MAX_HEADER_SIZE - length >= client->request.query_string_len);
client->request.query_string = perealloc(client->request.query_string, client->request.query_string_len + length + 1, 1);
memcpy(client->request.query_string + client->request.query_string_len, at, length);
client->request.query_string_len += length;
client->request.query_string[client->request.query_string_len] = '\0';
}
return 0;
}
static int php_cli_server_client_read_request_on_url(php_http_parser *parser, const char *at, size_t length)
{
php_cli_server_client *client = parser->data;
client->request.request_method = parser->method;
client->request.request_uri = pestrndup(at, length, 1);
client->request.request_uri_len = length;
if (EXPECTED(client->request.request_uri == NULL)) {
client->request.request_method = parser->method;
client->request.request_uri = pestrndup(at, length, 1);
client->request.request_uri_len = length;
} else {
ZEND_ASSERT(client->request.request_method == parser->method);
ZEND_ASSERT(length <= PHP_HTTP_MAX_HEADER_SIZE && PHP_HTTP_MAX_HEADER_SIZE - length >= client->request.query_string_len);
client->request.request_uri = perealloc(client->request.request_uri, client->request.request_uri_len + length + 1, 1);
memcpy(client->request.request_uri + client->request.request_uri_len, at, length);
client->request.request_uri_len += length;
client->request.request_uri[client->request.request_uri_len] = '\0';
}
return 0;
}