diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 797979b67305..9ebdd38586a8 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -174,6 +174,7 @@ typedef struct php_cli_server_client { zend_string *addr_str; php_http_parser parser; bool request_read; + bool too_large_post; zend_string *current_header_name; zend_string *current_header_value; enum { HEADER_NONE=0, HEADER_FIELD, HEADER_VALUE } last_header_element; @@ -209,6 +210,7 @@ static const php_cli_server_http_response_status_code_pair template_map[] = { { 400, "
Your browser sent a request that this server could not understand.
" }, { 404, "The requested resource %s was not found on this server.
Requested method not allowed.
" }, + { 413, "The request body exceeds the configured post_max_size of " ZEND_LONG_FMT " bytes.
The server is temporarily unavailable.
" }, { 501, "Request method not supported.
" } }; @@ -1779,14 +1781,36 @@ static int php_cli_server_client_read_request_on_headers_complete(php_http_parse break; } client->last_header_element = HEADER_NONE; + + if (parser->content_length > 0 + && SG(post_max_size) > 0 + && (zend_long) parser->content_length > SG(post_max_size)) { + client->request.protocol_version = parser->http_major * 100 + parser->http_minor; + client->too_large_post = true; + client->request_read = true; + return 2; + } + return 0; } static int php_cli_server_client_read_request_on_body(php_http_parser *parser, const char *at, size_t length) { php_cli_server_client *client = parser->data; + + if (SG(post_max_size) > 0 && client->request.content_len + length > (size_t) SG(post_max_size)) { + client->request.protocol_version = parser->http_major * 100 + parser->http_minor; + client->too_large_post = true; + client->request_read = true; + return 1; + } + if (!client->request.content) { - client->request.content = pemalloc(parser->content_length, 1); + size_t reserve = (size_t) parser->content_length; + if (SG(post_max_size) > 0 && reserve > (size_t) SG(post_max_size)) { + reserve = (size_t) SG(post_max_size); + } + client->request.content = pemalloc(reserve, 1); client->request.content_len = 0; } client->request.content = perealloc(client->request.content, client->request.content_len + length, 1); @@ -1866,7 +1890,7 @@ static int php_cli_server_client_read_request(php_cli_server_client *client, cha } client->parser.data = client; nbytes_consumed = php_http_parser_execute(&client->parser, &settings, buf, nbytes_read); - if (nbytes_consumed != (size_t)nbytes_read) { + if (nbytes_consumed != (size_t)nbytes_read && !client->too_large_post) { if (php_cli_server_log_level >= PHP_CLI_SERVER_LOG_ERROR) { if ((buf[0] & 0x80) /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) { *errstr = estrdup("Unsupported SSL request"); @@ -1960,6 +1984,7 @@ static void php_cli_server_client_ctor(php_cli_server_client *client, php_cli_se php_http_parser_init(&client->parser, PHP_HTTP_REQUEST); client->request_read = false; + client->too_large_post = false; client->last_header_element = HEADER_NONE; client->current_header_name = NULL; @@ -1983,10 +2008,16 @@ static void php_cli_server_client_dtor(php_cli_server_client *client) /* {{{ */ pefree(client->addr, 1); zend_string_release_ex(client->addr_str, /* persistent */ true); + if (client->current_header_name) { + zend_string_release_ex(client->current_header_name, /* persistent */ true); + client->current_header_name = NULL; + } + if (client->current_header_value) { + zend_string_release_ex(client->current_header_value, /* persistent */ true); + client->current_header_value = NULL; + } + if (client->content_sender_initialized) { - /* Headers must be set if we reached the content initialisation */ - assert(client->current_header_name == NULL); - assert(client->current_header_value == NULL); php_cli_server_content_sender_dtor(&client->content_sender); } } /* }}} */ @@ -2038,11 +2069,20 @@ static zend_result php_cli_server_send_error_page(php_cli_server *server, php_cl php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } { - php_cli_server_chunk *chunk = php_cli_server_chunk_heap_new_self_contained(strlen(content_template) + ZSTR_LEN(escaped_request_uri) + 3 + strlen(status_string) + 1); - if (!chunk) { - goto fail; + php_cli_server_chunk *chunk; + if (status == 413) { + chunk = php_cli_server_chunk_heap_new_self_contained(strlen(content_template) + strlen(status_string) + MAX_LENGTH_OF_LONG + 1); + if (!chunk) { + goto fail; + } + snprintf(chunk->data.heap.p, chunk->data.heap.len, content_template, status_string, SG(post_max_size)); + } else { + chunk = php_cli_server_chunk_heap_new_self_contained(strlen(content_template) + ZSTR_LEN(escaped_request_uri) + 3 + strlen(status_string) + 1); + if (!chunk) { + goto fail; + } + snprintf(chunk->data.heap.p, chunk->data.heap.len, content_template, status_string, ZSTR_VAL(escaped_request_uri)); } - snprintf(chunk->data.heap.p, chunk->data.heap.len, content_template, status_string, ZSTR_VAL(escaped_request_uri)); chunk->data.heap.len = strlen(chunk->data.heap.p); php_cli_server_buffer_append(&client->content_sender.buffer, chunk); } @@ -2641,6 +2681,9 @@ static zend_result php_cli_server_recv_event_read_request(php_cli_server *server if (client->request.request_method == PHP_HTTP_NOT_IMPLEMENTED) { return php_cli_server_send_error_page(server, client, 501); } + if (client->too_large_post) { + return php_cli_server_send_error_page(server, client, 413); + } php_cli_server_poller_remove(&server->poller, POLLIN, client->sock); return php_cli_server_dispatch(server, client); case 0: diff --git a/sapi/cli/php_http_parser.c b/sapi/cli/php_http_parser.c index c7c2ad0caaea..8a059df986f6 100644 --- a/sapi/cli/php_http_parser.c +++ b/sapi/cli/php_http_parser.c @@ -20,6 +20,7 @@ */ #include