From: Michael Wallner Date: Thu, 31 Mar 2016 13:12:19 +0000 (+0200) Subject: allow setting multiple headers with the same name X-Git-Tag: RELEASE_2_6_0_BETA1~39 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=commitdiff_plain;h=5d8c2bda1c13b12372af844395471cd614c572f1 allow setting multiple headers with the same name Only http\Message::addHeader will transform the headers into a single one where the values will be concatenated by comma. Closes github issue #34 --- diff --git a/src/php_http_header.c b/src/php_http_header.c index 41601df..2f808c3 100644 --- a/src/php_http_header.c +++ b/src/php_http_header.c @@ -38,39 +38,13 @@ ZEND_RESULT_CODE php_http_header_parse(const char *header, size_t length, HashTa void php_http_header_to_callback(HashTable *headers, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg TSRMLS_DC) { - HashPosition pos1, pos2; + HashPosition pos; php_http_array_hashkey_t key = php_http_array_hashkey_init(0); - zval **header, **single_header; + zval **header; - FOREACH_HASH_KEYVAL(pos1, headers, key, header) { + FOREACH_HASH_KEYVAL(pos, headers, key, header) { if (key.type == HASH_KEY_IS_STRING) { - if (key.len == sizeof("Set-Cookie") && !strcasecmp(key.str, "Set-Cookie") && Z_TYPE_PP(header) == IS_ARRAY) { - FOREACH_VAL(pos2, *header, single_header) { - if (Z_TYPE_PP(single_header) == IS_ARRAY) { - php_http_cookie_list_t *cookie = php_http_cookie_list_from_struct(NULL, *single_header TSRMLS_CC); - - if (cookie) { - char *buf; - size_t len; - - php_http_cookie_list_to_string(cookie, &buf, &len); - cb(cb_arg, crlf ? "Set-Cookie: %s" PHP_HTTP_CRLF : "Set-Cookie: %s", buf); - php_http_cookie_list_free(&cookie); - efree(buf); - } - } else { - zval *strval = php_http_header_value_to_string(*single_header TSRMLS_CC); - - cb(cb_arg, crlf ? "Set-Cookie: %s" PHP_HTTP_CRLF : "Set-Cookie: %s", Z_STRVAL_P(strval)); - zval_ptr_dtor(&strval); - } - } - } else { - zval *strval = php_http_header_value_to_string(*header TSRMLS_CC); - - cb(cb_arg, crlf ? "%s: %s" PHP_HTTP_CRLF : "%s: %s", key.str, Z_STRVAL_P(strval)); - zval_ptr_dtor(&strval); - } + php_http_header_to_callback_ex(key.str, *header, crlf, cb, cb_arg TSRMLS_CC); } } } @@ -80,6 +54,35 @@ void php_http_header_to_string(php_http_buffer_t *str, HashTable *headers TSRMLS php_http_header_to_callback(headers, 1, (php_http_pass_format_callback_t) php_http_buffer_appendf, str TSRMLS_CC); } +void php_http_header_to_callback_ex(const char *key, zval *val, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg TSRMLS_DC) +{ + HashPosition pos; + zval **aval, *tmp; + + switch (Z_TYPE_P(val)) { + case IS_ARRAY: + FOREACH_VAL(pos, val, aval) { + php_http_header_to_callback_ex(key, *aval, crlf, cb, cb_arg TSRMLS_CC); + } + break; + + case IS_BOOL: + cb(cb_arg, "%s: %s%s", key, Z_BVAL_P(val) ? "true" : "false", crlf ? PHP_HTTP_CRLF:""); + break; + + default: + tmp = php_http_ztyp(IS_STRING, val); + cb(cb_arg, "%s: %s%s", key, Z_STRVAL_P(tmp), crlf ? PHP_HTTP_CRLF:""); + zval_ptr_dtor(&tmp); + break; + } +} + +void php_http_header_to_string_ex(php_http_buffer_t *str, const char *key, zval *val TSRMLS_DC) +{ + php_http_header_to_callback_ex(key, val, 1, (php_http_pass_format_callback_t) php_http_buffer_appendf, str TSRMLS_CC); +} + zval *php_http_header_value_to_string(zval *header TSRMLS_DC) { zval *ret; diff --git a/src/php_http_header.h b/src/php_http_header.h index a2baecb..9a57d8f 100644 --- a/src/php_http_header.h +++ b/src/php_http_header.h @@ -18,7 +18,9 @@ PHP_HTTP_API ZEND_RESULT_CODE php_http_header_parse(const char *header, size_t length, HashTable *headers, php_http_info_callback_t callback_func, void **callback_data TSRMLS_DC); PHP_HTTP_API void php_http_header_to_callback(HashTable *headers, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg TSRMLS_DC); +PHP_HTTP_API void php_http_header_to_callback_ex(const char *key, zval *val, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg TSRMLS_DC); PHP_HTTP_API void php_http_header_to_string(php_http_buffer_t *str, HashTable *headers TSRMLS_DC); +PHP_HTTP_API void php_http_header_to_string_ex(php_http_buffer_t *str, const char *key, zval *val TSRMLS_DC); PHP_HTTP_API zval *php_http_header_value_to_string(zval *header TSRMLS_DC); diff --git a/src/php_http_message.c b/src/php_http_message.c index 3ea40e1..2b3090a 100644 --- a/src/php_http_message.c +++ b/src/php_http_message.c @@ -1286,17 +1286,27 @@ static PHP_METHOD(HttpMessage, addHeader) if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name_str, &name_len, &zvalue)) { php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1); - zval *header; + zval *header, *cpy = php_http_header_value_to_string(zvalue TSRMLS_CC); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); - Z_ADDREF_P(zvalue); - if ((header = php_http_message_header(obj->message, name, name_len, 0))) { + if ((name_len != lenof("Set-Cookie") && strcmp(name, "Set-Cookie")) + && (header = php_http_message_header(obj->message, name, name_len, 1))) { + zval *tmp; + char *hdr_str; + size_t hdr_len = spprintf(&hdr_str, 0, "%s, %s", Z_STRVAL_P(header), Z_STRVAL_P(cpy)); + + MAKE_STD_ZVAL(tmp); + ZVAL_STRINGL(tmp, hdr_str, hdr_len, 0); + zend_symtable_update(&obj->message->hdrs, name, name_len + 1, &tmp, sizeof(void *), NULL); + zval_ptr_dtor(&header); + zval_ptr_dtor(&cpy); + } else if ((header = php_http_message_header(obj->message, name, name_len, 0))) { convert_to_array(header); - zend_hash_next_index_insert(Z_ARRVAL_P(header), &zvalue, sizeof(void *), NULL); + zend_hash_next_index_insert(Z_ARRVAL_P(header), &cpy, sizeof(void *), NULL); zval_ptr_dtor(&header); } else { - zend_symtable_update(&obj->message->hdrs, name, name_len + 1, &zvalue, sizeof(void *), NULL); + zend_symtable_update(&obj->message->hdrs, name, name_len + 1, &cpy, sizeof(void *), NULL); } efree(name); } diff --git a/tests/message005.phpt b/tests/message005.phpt index 6f7a546..0372091 100644 --- a/tests/message005.phpt +++ b/tests/message005.phpt @@ -28,5 +28,8 @@ String: foobar === UNKNOWN / HTTP/1.1 -Numbers: 1, 2, 3, 4.5 +Numbers: 1 +Numbers: 2 +Numbers: 3 +Numbers: 4.5 DONE diff --git a/tests/message011.phpt b/tests/message011.phpt index 53aa992..1b1a3f2 100644 --- a/tests/message011.phpt +++ b/tests/message011.phpt @@ -23,18 +23,24 @@ class strval { $m = new http\Message; $m->addHeaders(array("foo"=>"bar","bar"=>"foo")); -var_dump(array("Foo"=>"bar", "Bar"=>"foo") === $m->getHeaders()); +if (array("Foo"=>"bar", "Bar"=>"foo") !== $m->getHeaders()) { + var_dump($m->getHeaders()); +} $m->addHeaders(array("key"=>"val","more"=>"Stuff")); -var_dump(array("Foo"=>"bar", "Bar"=>"foo","Key"=>"val","More"=>"Stuff") === $m->getHeaders()); +if (array("Foo"=>"bar", "Bar"=>"foo","Key"=>"val","More"=>"Stuff") !== $m->getHeaders()) { + var_dump($m->getHeaders()); +} $m = new http\Message("GET / HTTP/1.1"); $m->addHeader("Accept", "text/html"); $m->addHeader("Accept", "text/xml;q=0"); $m->addHeader("Accept", "text/plain;q=0.5"); -var_dump( +if ( "GET / HTTP/1.1\r\n". - "Accept: text/html, text/xml;q=0, text/plain;q=0.5\r\n" === - $m->toString() -); + "Accept: text/html, text/xml;q=0, text/plain;q=0.5\r\n" !== + $m->toString()) { + var_dump($m->toString()); +} + $m = new http\Message("HTTP/1.1 200 Ok"); $m->addHeader("Bool", true); $m->addHeader("Int", 123); @@ -42,7 +48,7 @@ $m->addHeader("Float", 1.23); $m->addHeader("Array", array(1,2,3)); $m->addHeader("Object", new strval("test")); $m->addHeader("Set-Cookie", - array( + new http\Cookie( array( "cookies" => array("foo" => "bar"), "expires" => date_create("2012-12-31 22:59:59 GMT")->format( @@ -54,7 +60,7 @@ $m->addHeader("Set-Cookie", ); $m->addHeader("Set-Cookie", "val=0"); -var_dump( +if ( "HTTP/1.1 200 Ok\r\n". "Bool: true\r\n". "Int: 123\r\n". @@ -62,16 +68,13 @@ var_dump( "Array: 1, 2, 3\r\n". "Object: test\r\n". "Set-Cookie: foo=bar; path=/somewhere; expires=Mon, 31 Dec 2012 22:59:59 GMT; \r\n". - "Set-Cookie: val=0\r\n" === - $m->toString() -); + "Set-Cookie: val=0\r\n" !== + $m->toString()) { + var_dump($m->toString()); +} ?> Done --EXPECT-- Test -bool(true) -bool(true) -bool(true) -bool(true) Done diff --git a/tests/propertyproxy001.phpt b/tests/propertyproxy001.phpt index 1001f8e..8c5f23b 100644 --- a/tests/propertyproxy001.phpt +++ b/tests/propertyproxy001.phpt @@ -92,7 +92,9 @@ bykey: 1 by1ref: 2 by2ref: 1 byXref: 2 -bynext: 1, 2, 3 +bynext: 1 +bynext: 2 +bynext: 3 DONE