diff options
author | Bouke van der Bijl <boukevanderbijl@gmail.com> | 2017-09-04 16:28:29 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2017-09-05 16:23:32 +0200 |
commit | cd9d90f4d41c87494dee8ee72c7a48951213296b (patch) | |
tree | ac701b2137072f6c09afe46dede09999dfc94e9f /sapi/cli | |
parent | 24da62d342d271b3d785741a48b7103fece6ed82 (diff) | |
download | php-git-cd9d90f4d41c87494dee8ee72c7a48951213296b.tar.gz |
Fixed bug #70470
Diffstat (limited to 'sapi/cli')
-rw-r--r-- | sapi/cli/php_cli_server.c | 110 | ||||
-rw-r--r-- | sapi/cli/tests/bug70470.phpt | 2 | ||||
-rw-r--r-- | sapi/cli/tests/emptyheader.phpt | 35 |
3 files changed, 119 insertions, 28 deletions
diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 5d820743b6..4d5324f36c 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -171,6 +171,9 @@ typedef struct php_cli_server_client { char *current_header_name; size_t current_header_name_len; unsigned int current_header_name_allocated:1; + char *current_header_value; + size_t current_header_value_len; + enum { HEADER_NONE=0, HEADER_FIELD, HEADER_VALUE } last_header_element; size_t post_read_offset; php_cli_server_request request; unsigned int content_sender_initialized:1; @@ -1469,7 +1472,7 @@ static void normalize_vpath(char **retval, size_t *retval_len, const char *vpath #ifdef PHP_WIN32 { char *p = decoded_vpath; - + do { if (*p == '\\') { *p = '/'; @@ -1572,50 +1575,100 @@ static int php_cli_server_client_read_request_on_fragment(php_http_parser *parse return 0; } -static int php_cli_server_client_read_request_on_header_field(php_http_parser *parser, const char *at, size_t length) +static void php_cli_server_client_save_header(php_cli_server_client *client) { - php_cli_server_client *client = parser->data; + /* strip off the colon */ + zend_string *orig_header_name = zend_string_init(client->current_header_name, client->current_header_name_len, 1); + char *lc_header_name = zend_str_tolower_dup(client->current_header_name, client->current_header_name_len); + zend_hash_str_add_ptr(&client->request.headers, lc_header_name, client->current_header_name_len, client->current_header_value); + zend_hash_add_ptr(&client->request.headers_original_case, orig_header_name, client->current_header_value); + efree(lc_header_name); + zend_string_release(orig_header_name); + if (client->current_header_name_allocated) { pefree(client->current_header_name, 1); client->current_header_name_allocated = 0; } - client->current_header_name = (char *)at; - client->current_header_name_len = length; - return 0; + client->current_header_name = NULL; + client->current_header_name_len = 0; + client->current_header_value = NULL; + client->current_header_value_len = 0; } -static int php_cli_server_client_read_request_on_header_value(php_http_parser *parser, const char *at, size_t length) +static int php_cli_server_client_read_request_on_header_field(php_http_parser *parser, const char *at, size_t length) { php_cli_server_client *client = parser->data; - char *value = pestrndup(at, length, 1); - if (!value) { - return 1; - } - { - /* strip off the colon */ - zend_string *orig_header_name = zend_string_init(client->current_header_name, client->current_header_name_len, 1); - char *lc_header_name = zend_str_tolower_dup(client->current_header_name, client->current_header_name_len); - zend_hash_str_add_ptr(&client->request.headers, lc_header_name, client->current_header_name_len, value); - zend_hash_add_ptr(&client->request.headers_original_case, orig_header_name, value); - efree(lc_header_name); - zend_string_release(orig_header_name); + switch (client->last_header_element) { + case HEADER_VALUE: + php_cli_server_client_save_header(client); + /* break missing intentionally */ + case HEADER_NONE: + client->current_header_name = (char *)at; + client->current_header_name_len = length; + break; + case HEADER_FIELD: + if (client->current_header_name_allocated) { + size_t new_length = client->current_header_name_len + length; + client->current_header_name = perealloc(client->current_header_name, new_length + 1, 1); + memcpy(client->current_header_name + client->current_header_name_len, at, length); + client->current_header_name_len = new_length; + } else { + size_t new_length = client->current_header_name_len + length; + char* field = pemalloc(new_length + 1, 1); + memcpy(field, client->current_header_name, client->current_header_name_len); + memcpy(field + client->current_header_name_len, at, length); + client->current_header_name = field; + client->current_header_name_len = new_length; + client->current_header_name_allocated = 1; + } + break; } - if (client->current_header_name_allocated) { - pefree(client->current_header_name, 1); - client->current_header_name_allocated = 0; + client->last_header_element = HEADER_FIELD; + return 0; +} + +static int php_cli_server_client_read_request_on_header_value(php_http_parser *parser, const char *at, size_t length) +{ + php_cli_server_client *client = parser->data; + switch (client->last_header_element) { + case HEADER_FIELD: + client->current_header_value = pestrndup(at, length, 1); + client->current_header_value_len = length; + break; + case HEADER_VALUE: + { + size_t new_length = client->current_header_value_len + length; + client->current_header_value = perealloc(client->current_header_value, new_length + 1, 1); + memcpy(client->current_header_value + client->current_header_value_len, at, length); + client->current_header_value_len = new_length; + } + break; + case HEADER_NONE: + // can't happen + assert(0); + break; } + client->last_header_element = HEADER_VALUE; return 0; } static int php_cli_server_client_read_request_on_headers_complete(php_http_parser *parser) { php_cli_server_client *client = parser->data; - if (client->current_header_name_allocated) { - pefree(client->current_header_name, 1); - client->current_header_name_allocated = 0; + switch (client->last_header_element) { + case HEADER_NONE: + break; + case HEADER_FIELD: + client->current_header_value = pemalloc(1, 1); + *client->current_header_value = '\0'; + client->current_header_value_len = 0; + /* break missing intentionally */ + case HEADER_VALUE: + php_cli_server_client_save_header(client); + break; } - client->current_header_name = NULL; + client->last_header_element = HEADER_NONE; return 0; } @@ -1791,9 +1844,14 @@ static int php_cli_server_client_ctor(php_cli_server_client *client, php_cli_ser } php_http_parser_init(&client->parser, PHP_HTTP_REQUEST); client->request_read = 0; + + client->last_header_element = HEADER_NONE; client->current_header_name = NULL; client->current_header_name_len = 0; client->current_header_name_allocated = 0; + client->current_header_value = NULL; + client->current_header_value_len = 0; + client->post_read_offset = 0; if (FAILURE == php_cli_server_request_ctor(&client->request)) { return FAILURE; diff --git a/sapi/cli/tests/bug70470.phpt b/sapi/cli/tests/bug70470.phpt index acd8c98f05..1e05f184b4 100644 --- a/sapi/cli/tests/bug70470.phpt +++ b/sapi/cli/tests/bug70470.phpt @@ -4,8 +4,6 @@ Bug #70470 (Built-in server truncates headers spanning over TCP packets) <?php include "skipif.inc"; ?> ---XFAIL-- -bug is not fixed yet --FILE-- <?php include "php_cli_server.inc"; diff --git a/sapi/cli/tests/emptyheader.phpt b/sapi/cli/tests/emptyheader.phpt new file mode 100644 index 0000000000..9529730e8b --- /dev/null +++ b/sapi/cli/tests/emptyheader.phpt @@ -0,0 +1,35 @@ +--TEST-- +Correctly handle split and empty header +--SKIPIF-- +<?php +include "skipif.inc"; +?> +--FILE-- +<?php +include "php_cli_server.inc"; +php_cli_server_start("var_dump(getAllheaders());"); + +$fp = fsockopen(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT, $errno, $errmsg, 0.5); + +if (!$fp) { + die("connect failed: " . $errmsg); +} + +fwrite($fp, "GET / HTTP/1.1\r\nUser-Agent\r\nAccept: */*\r\nReferer:\r\nHi\r\n\r\n"); +fflush($fp); +while (!feof($fp)) { + echo fgets($fp); +} +fclose($fp); +?> +--EXPECTF-- +HTTP/1.1 200 OK +%a +array(3) { + ["User-AgentAccept"]=> + string(3) "*/*" + ["Referer"]=> + string(0) "" + ["Hi"]=> + string(0) "" +} |