Skip to content

Commit cd32c59

Browse files
authored
Fix regression with header removal removing whole prefixes (#21020)
* Fix regression with header removing removing whole prefixes The header removal code looked for the colon for key-value at the wrong place, so it would overzealously remove headers. Tweak that condition, and make the alternative condition only active if it's set (with the remove prefix op case). Fixes GH-21018. * avoid reading past the actual length * Rename variable to be more clear
1 parent 00466a0 commit cd32c59

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
GH-21018 (header() removes headers with the same prefix)
3+
--INI--
4+
expose_php=On
5+
--CGI--
6+
--FILE--
7+
<?php
8+
header('a: 1');
9+
header('a-test: 1');
10+
header('a: 1');
11+
var_dump(headers_list());
12+
?>
13+
--EXPECTF--
14+
array(3) {
15+
[0]=>
16+
string(%d) "X-Powered-By: PHP/%s"
17+
[1]=>
18+
string(9) "a-test: 1"
19+
[2]=>
20+
string(4) "a: 1"
21+
}

main/SAPI.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ static void sapi_update_response_code(int ncode)
601601
* since zend_llist_del_element only removes one matched item once,
602602
* we should remove them manually
603603
*/
604-
static void sapi_remove_header(zend_llist *l, char *name, size_t len, size_t header_len)
604+
static void sapi_remove_header(zend_llist *l, char *name, size_t len, size_t prefix_len)
605605
{
606606
sapi_header_struct *header;
607607
zend_llist_element *next;
@@ -610,8 +610,13 @@ static void sapi_remove_header(zend_llist *l, char *name, size_t len, size_t hea
610610
while (current) {
611611
header = (sapi_header_struct *)(current->data);
612612
next = current->next;
613-
if (header->header_len > header_len
614-
&& (header->header[header_len] == ':' || len > header_len)
613+
/*
614+
* prefix_len is set for DELETE_PREFIX (used for deleting i.e.
615+
* "Set-Cookie: PHPSESSID=", where we need more than just key)
616+
* look for the : otherwise
617+
*/
618+
if (header->header_len > len
619+
&& (header->header[len] == ':' || (prefix_len && len > prefix_len))
615620
&& !strncasecmp(header->header, name, len)) {
616621
if (current->prev) {
617622
current->prev->next = next;

0 commit comments

Comments
 (0)