Skip to content

Commit 1ca4359

Browse files
committed
Merge branch 'PHP-7.2'
2 parents 431ea10 + 9fbd862 commit 1ca4359

File tree

3 files changed

+118
-27
lines changed

3 files changed

+118
-27
lines changed

sapi/cli/php_cli_server.c

Lines changed: 83 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ typedef struct php_cli_server_client {
172172
char *current_header_name;
173173
size_t current_header_name_len;
174174
unsigned int current_header_name_allocated:1;
175+
char *current_header_value;
176+
size_t current_header_value_len;
177+
enum { HEADER_NONE=0, HEADER_FIELD, HEADER_VALUE } last_header_element;
175178
size_t post_read_offset;
176179
php_cli_server_request request;
177180
unsigned int content_sender_initialized:1;
@@ -1567,50 +1570,100 @@ static int php_cli_server_client_read_request_on_fragment(php_http_parser *parse
15671570
return 0;
15681571
}
15691572

1570-
static int php_cli_server_client_read_request_on_header_field(php_http_parser *parser, const char *at, size_t length)
1573+
static void php_cli_server_client_save_header(php_cli_server_client *client)
15711574
{
1572-
php_cli_server_client *client = parser->data;
1575+
/* strip off the colon */
1576+
zend_string *orig_header_name = zend_string_init(client->current_header_name, client->current_header_name_len, 1);
1577+
char *lc_header_name = zend_str_tolower_dup(client->current_header_name, client->current_header_name_len);
1578+
zend_hash_str_add_ptr(&client->request.headers, lc_header_name, client->current_header_name_len, client->current_header_value);
1579+
zend_hash_add_ptr(&client->request.headers_original_case, orig_header_name, client->current_header_value);
1580+
efree(lc_header_name);
1581+
zend_string_release(orig_header_name);
1582+
15731583
if (client->current_header_name_allocated) {
15741584
pefree(client->current_header_name, 1);
15751585
client->current_header_name_allocated = 0;
15761586
}
1577-
client->current_header_name = (char *)at;
1578-
client->current_header_name_len = length;
1579-
return 0;
1587+
client->current_header_name = NULL;
1588+
client->current_header_name_len = 0;
1589+
client->current_header_value = NULL;
1590+
client->current_header_value_len = 0;
15801591
}
15811592

1582-
static int php_cli_server_client_read_request_on_header_value(php_http_parser *parser, const char *at, size_t length)
1593+
static int php_cli_server_client_read_request_on_header_field(php_http_parser *parser, const char *at, size_t length)
15831594
{
15841595
php_cli_server_client *client = parser->data;
1585-
char *value = pestrndup(at, length, 1);
1586-
if (!value) {
1587-
return 1;
1588-
}
1589-
{
1590-
/* strip off the colon */
1591-
zend_string *orig_header_name = zend_string_init(client->current_header_name, client->current_header_name_len, 1);
1592-
char *lc_header_name = zend_str_tolower_dup(client->current_header_name, client->current_header_name_len);
1593-
zend_hash_str_add_ptr(&client->request.headers, lc_header_name, client->current_header_name_len, value);
1594-
zend_hash_add_ptr(&client->request.headers_original_case, orig_header_name, value);
1595-
efree(lc_header_name);
1596-
zend_string_release(orig_header_name);
1596+
switch (client->last_header_element) {
1597+
case HEADER_VALUE:
1598+
php_cli_server_client_save_header(client);
1599+
/* break missing intentionally */
1600+
case HEADER_NONE:
1601+
client->current_header_name = (char *)at;
1602+
client->current_header_name_len = length;
1603+
break;
1604+
case HEADER_FIELD:
1605+
if (client->current_header_name_allocated) {
1606+
size_t new_length = client->current_header_name_len + length;
1607+
client->current_header_name = perealloc(client->current_header_name, new_length + 1, 1);
1608+
memcpy(client->current_header_name + client->current_header_name_len, at, length);
1609+
client->current_header_name_len = new_length;
1610+
} else {
1611+
size_t new_length = client->current_header_name_len + length;
1612+
char* field = pemalloc(new_length + 1, 1);
1613+
memcpy(field, client->current_header_name, client->current_header_name_len);
1614+
memcpy(field + client->current_header_name_len, at, length);
1615+
client->current_header_name = field;
1616+
client->current_header_name_len = new_length;
1617+
client->current_header_name_allocated = 1;
1618+
}
1619+
break;
15971620
}
15981621

1599-
if (client->current_header_name_allocated) {
1600-
pefree(client->current_header_name, 1);
1601-
client->current_header_name_allocated = 0;
1622+
client->last_header_element = HEADER_FIELD;
1623+
return 0;
1624+
}
1625+
1626+
static int php_cli_server_client_read_request_on_header_value(php_http_parser *parser, const char *at, size_t length)
1627+
{
1628+
php_cli_server_client *client = parser->data;
1629+
switch (client->last_header_element) {
1630+
case HEADER_FIELD:
1631+
client->current_header_value = pestrndup(at, length, 1);
1632+
client->current_header_value_len = length;
1633+
break;
1634+
case HEADER_VALUE:
1635+
{
1636+
size_t new_length = client->current_header_value_len + length;
1637+
client->current_header_value = perealloc(client->current_header_value, new_length + 1, 1);
1638+
memcpy(client->current_header_value + client->current_header_value_len, at, length);
1639+
client->current_header_value_len = new_length;
1640+
}
1641+
break;
1642+
case HEADER_NONE:
1643+
// can't happen
1644+
assert(0);
1645+
break;
16021646
}
1647+
client->last_header_element = HEADER_VALUE;
16031648
return 0;
16041649
}
16051650

16061651
static int php_cli_server_client_read_request_on_headers_complete(php_http_parser *parser)
16071652
{
16081653
php_cli_server_client *client = parser->data;
1609-
if (client->current_header_name_allocated) {
1610-
pefree(client->current_header_name, 1);
1611-
client->current_header_name_allocated = 0;
1654+
switch (client->last_header_element) {
1655+
case HEADER_NONE:
1656+
break;
1657+
case HEADER_FIELD:
1658+
client->current_header_value = pemalloc(1, 1);
1659+
*client->current_header_value = '\0';
1660+
client->current_header_value_len = 0;
1661+
/* break missing intentionally */
1662+
case HEADER_VALUE:
1663+
php_cli_server_client_save_header(client);
1664+
break;
16121665
}
1613-
client->current_header_name = NULL;
1666+
client->last_header_element = HEADER_NONE;
16141667
return 0;
16151668
}
16161669

@@ -1780,9 +1833,14 @@ static int php_cli_server_client_ctor(php_cli_server_client *client, php_cli_ser
17801833
}
17811834
php_http_parser_init(&client->parser, PHP_HTTP_REQUEST);
17821835
client->request_read = 0;
1836+
1837+
client->last_header_element = HEADER_NONE;
17831838
client->current_header_name = NULL;
17841839
client->current_header_name_len = 0;
17851840
client->current_header_name_allocated = 0;
1841+
client->current_header_value = NULL;
1842+
client->current_header_value_len = 0;
1843+
17861844
client->post_read_offset = 0;
17871845
if (FAILURE == php_cli_server_request_ctor(&client->request)) {
17881846
return FAILURE;

sapi/cli/tests/bug70470.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ Bug #70470 (Built-in server truncates headers spanning over TCP packets)
44
<?php
55
include "skipif.inc";
66
?>
7-
--XFAIL--
8-
bug is not fixed yet
97
--FILE--
108
<?php
119
include "php_cli_server.inc";

sapi/cli/tests/emptyheader.phpt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
Correctly handle split and empty header
3+
--SKIPIF--
4+
<?php
5+
include "skipif.inc";
6+
?>
7+
--FILE--
8+
<?php
9+
include "php_cli_server.inc";
10+
php_cli_server_start("var_dump(getAllheaders());");
11+
12+
$fp = fsockopen(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT, $errno, $errmsg, 0.5);
13+
14+
if (!$fp) {
15+
die("connect failed: " . $errmsg);
16+
}
17+
18+
fwrite($fp, "GET / HTTP/1.1\r\nUser-Agent\r\nAccept: */*\r\nReferer:\r\nHi\r\n\r\n");
19+
fflush($fp);
20+
while (!feof($fp)) {
21+
echo fgets($fp);
22+
}
23+
fclose($fp);
24+
?>
25+
--EXPECTF--
26+
HTTP/1.1 200 OK
27+
%a
28+
array(3) {
29+
["User-AgentAccept"]=>
30+
string(3) "*/*"
31+
["Referer"]=>
32+
string(0) ""
33+
["Hi"]=>
34+
string(0) ""
35+
}

0 commit comments

Comments
 (0)