Merge branch 'PHP-7.1' into PHP-7.2

This commit is contained in:
Nikita Popov 2017-09-05 16:24:32 +02:00
commit 9fbd8620fb
4 changed files with 122 additions and 27 deletions

4
NEWS
View File

@ -6,6 +6,10 @@ PHP NEWS
. Fixed Bug #75142 (buildcheck.sh check for autoconf version needs to be updated . Fixed Bug #75142 (buildcheck.sh check for autoconf version needs to be updated
for v2.64). (zizzy at zizzy dot net, Remi) for v2.64). (zizzy at zizzy dot net, Remi)
- CLI server:
. Fixed bug #70470 (Built-in server truncates headers spanning over TCP
packets). (bouk)
- Date: - Date:
. Fixed bug #75149 (redefinition of typedefs ttinfo and t1info). (Remi) . Fixed bug #75149 (redefinition of typedefs ttinfo and t1info). (Remi)

View File

@ -172,6 +172,9 @@ typedef struct php_cli_server_client {
char *current_header_name; char *current_header_name;
size_t current_header_name_len; size_t current_header_name_len;
unsigned int current_header_name_allocated:1; 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; size_t post_read_offset;
php_cli_server_request request; php_cli_server_request request;
unsigned int content_sender_initialized:1; unsigned int content_sender_initialized:1;
@ -1567,50 +1570,100 @@ static int php_cli_server_client_read_request_on_fragment(php_http_parser *parse
return 0; 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) { if (client->current_header_name_allocated) {
pefree(client->current_header_name, 1); pefree(client->current_header_name, 1);
client->current_header_name_allocated = 0; client->current_header_name_allocated = 0;
} }
client->current_header_name = (char *)at; client->current_header_name = NULL;
client->current_header_name_len = length; 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_field(php_http_parser *parser, const char *at, size_t length)
{
php_cli_server_client *client = parser->data;
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;
}
client->last_header_element = HEADER_FIELD;
return 0; return 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_value(php_http_parser *parser, const char *at, size_t length)
{ {
php_cli_server_client *client = parser->data; php_cli_server_client *client = parser->data;
char *value = pestrndup(at, length, 1); switch (client->last_header_element) {
if (!value) { case HEADER_FIELD:
return 1; client->current_header_value = pestrndup(at, length, 1);
} client->current_header_value_len = length;
{ break;
/* strip off the colon */ case HEADER_VALUE:
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); size_t new_length = client->current_header_value_len + length;
zend_hash_str_add_ptr(&client->request.headers, lc_header_name, client->current_header_name_len, value); client->current_header_value = perealloc(client->current_header_value, new_length + 1, 1);
zend_hash_add_ptr(&client->request.headers_original_case, orig_header_name, value); memcpy(client->current_header_value + client->current_header_value_len, at, length);
efree(lc_header_name); client->current_header_value_len = new_length;
zend_string_release(orig_header_name); }
} break;
case HEADER_NONE:
if (client->current_header_name_allocated) { // can't happen
pefree(client->current_header_name, 1); assert(0);
client->current_header_name_allocated = 0; break;
} }
client->last_header_element = HEADER_VALUE;
return 0; return 0;
} }
static int php_cli_server_client_read_request_on_headers_complete(php_http_parser *parser) static int php_cli_server_client_read_request_on_headers_complete(php_http_parser *parser)
{ {
php_cli_server_client *client = parser->data; php_cli_server_client *client = parser->data;
if (client->current_header_name_allocated) { switch (client->last_header_element) {
pefree(client->current_header_name, 1); case HEADER_NONE:
client->current_header_name_allocated = 0; 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; return 0;
} }
@ -1780,9 +1833,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); php_http_parser_init(&client->parser, PHP_HTTP_REQUEST);
client->request_read = 0; client->request_read = 0;
client->last_header_element = HEADER_NONE;
client->current_header_name = NULL; client->current_header_name = NULL;
client->current_header_name_len = 0; client->current_header_name_len = 0;
client->current_header_name_allocated = 0; client->current_header_name_allocated = 0;
client->current_header_value = NULL;
client->current_header_value_len = 0;
client->post_read_offset = 0; client->post_read_offset = 0;
if (FAILURE == php_cli_server_request_ctor(&client->request)) { if (FAILURE == php_cli_server_request_ctor(&client->request)) {
return FAILURE; return FAILURE;

View File

@ -4,8 +4,6 @@ Bug #70470 (Built-in server truncates headers spanning over TCP packets)
<?php <?php
include "skipif.inc"; include "skipif.inc";
?> ?>
--XFAIL--
bug is not fixed yet
--FILE-- --FILE--
<?php <?php
include "php_cli_server.inc"; include "php_cli_server.inc";

View File

@ -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) ""
}