From 52b0fc768f17f428356b6ec69797a80badab0474 Mon Sep 17 00:00:00 2001 From: Florian MARGAINE Date: Sat, 27 Sep 2014 23:40:11 +0200 Subject: [PATCH] Fixes setcookie to only send one Set-Cookie header per name According to the IETF RFC 6265, only one Set-Cookie header should be sent per cookie name. Fixes #67736 Cherry-picks and adapts 208deda for master --- ext/standard/basic_functions.c | 9 ++++ ext/standard/head.c | 8 ++++ .../network/bug67736-display-errors-off.phpt | 48 +++++++++++++++++++ .../network/bug67736-display-errors-on.phpt | 33 +++++++++++++ ext/standard/tests/network/setcookie.phpt | 44 ++++++++--------- main/SAPI.h | 1 + 6 files changed, 121 insertions(+), 22 deletions(-) create mode 100644 ext/standard/tests/network/bug67736-display-errors-off.phpt create mode 100644 ext/standard/tests/network/bug67736-display-errors-on.phpt diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 36611b812b8a4..a55c5a990b645 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -3740,6 +3740,10 @@ PHP_RINIT_FUNCTION(basic) /* {{{ */ /* Default to global filters only */ FG(stream_filters) = NULL; + /* setcookie */ + ALLOC_HASHTABLE(SG(cookies)); + zend_hash_init(SG(cookies), 0, NULL, NULL, 0); + return SUCCESS; } /* }}} */ @@ -3796,6 +3800,11 @@ PHP_RSHUTDOWN_FUNCTION(basic) /* {{{ */ BG(page_uid) = -1; BG(page_gid) = -1; + + /* setcookie */ + zend_hash_destroy(SG(cookies)); + FREE_HASHTABLE(SG(cookies)); + return SUCCESS; } /* }}} */ diff --git a/ext/standard/head.c b/ext/standard/head.c index 3dd18ee0fd36a..21eadde2d9b16 100644 --- a/ext/standard/head.c +++ b/ext/standard/head.c @@ -81,6 +81,7 @@ PHPAPI int php_setcookie(char *name, int name_len, char *value, int value_len, t sapi_header_line ctr = {0}; int result; zend_string *encoded_value = NULL; + zend_string *z_name = zend_string_init(name, name_len, 0); if (name && strpbrk(name, "=,; \t\r\n\013\014") != NULL) { /* man isspace for \013 and \014 */ zend_error( E_WARNING, "Cookie names cannot contain any of the following '=,; \\t\\r\\n\\013\\014'" ); @@ -92,6 +93,13 @@ PHPAPI int php_setcookie(char *name, int name_len, char *value, int value_len, t return FAILURE; } + if (zend_hash_exists(SG(cookies), z_name) == 1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "should not be used twice with the same name"); + } + + zend_hash_add_empty_element(SG(cookies), z_name); + zend_string_release(z_name); + len += name_len; if (value && url_encode) { encoded_value = php_url_encode(value, value_len); diff --git a/ext/standard/tests/network/bug67736-display-errors-off.phpt b/ext/standard/tests/network/bug67736-display-errors-off.phpt new file mode 100644 index 0000000000000..0529116de3f95 --- /dev/null +++ b/ext/standard/tests/network/bug67736-display-errors-off.phpt @@ -0,0 +1,48 @@ +--TEST-- +setcookie() emits 2 cookies with same name with display_error off +--DESCRIPTION-- +--INI-- +display_errors=0 +--FILE-- + $header) { + if ($header !== $expected[$i]) { + $bad++; + echo "Header mismatch:\n\tExpected: " + . $expected[$i] + . "\n\tReceived: " + . $header + . "\n"; + } +} + +echo ($bad === 0) + ? 'OK' + : 'A total of ' . $bad . ' errors found.'; +--EXPECTHEADERS-- + +--EXPECT-- +OK \ No newline at end of file diff --git a/ext/standard/tests/network/bug67736-display-errors-on.phpt b/ext/standard/tests/network/bug67736-display-errors-on.phpt new file mode 100644 index 0000000000000..094967041d3e1 --- /dev/null +++ b/ext/standard/tests/network/bug67736-display-errors-on.phpt @@ -0,0 +1,33 @@ +--TEST-- +setcookie() emits 1 cookie then adds a warning for 2nd with same name +--DESCRIPTION-- +--INI-- +--FILE-- +