From: Michael Wallner Date: Wed, 27 Apr 2016 09:34:04 +0000 (+0200) Subject: Merge branch 'v2.6.x' of github.com:m6w6/ext-http X-Git-Tag: RELEASE_3_1_0_BETA1~22 X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=53a654ed6e112b2766b41c01a1c2bb79373c59e4;p=m6w6%2Fext-http Merge branch 'v2.6.x' of github.com:m6w6/ext-http --- 53a654ed6e112b2766b41c01a1c2bb79373c59e4 diff --cc src/php_http_client_curl.c index e56f8d4,5dd7a54..cc62c15 --- a/src/php_http_client_curl.c +++ b/src/php_http_client_curl.c @@@ -156,14 -161,31 +161,31 @@@ static php_resource_factory_ops_t php_h php_http_curle_dtor }; -static void *php_http_curlm_ctor(void *opaque, void *init_arg TSRMLS_DC) +static void *php_http_curlm_ctor(void *opaque, void *init_arg) { - return curl_multi_init(); + php_http_client_curl_handle_t *curl = calloc(1, sizeof(*curl)); + + if (!(curl->multi = curl_multi_init())) { + free(curl); + return NULL; + } + if (!(curl->share = curl_share_init())) { + curl_multi_cleanup(curl->multi); + free(curl); + return NULL; + } + curl_share_setopt(curl->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); + curl_share_setopt(curl->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); + return curl; } -static void php_http_curlm_dtor(void *opaque, void *handle TSRMLS_DC) +static void php_http_curlm_dtor(void *opaque, void *handle) { - curl_multi_cleanup(handle); + php_http_client_curl_handle_t *curl = handle; + + curl_share_cleanup(curl->share); + curl_multi_cleanup(curl->multi); + free(handle); } static php_resource_factory_ops_t php_http_curlm_resource_factory_ops = { @@@ -665,9 -657,10 +687,9 @@@ static void php_http_curlm_responsehand php_http_curle_storage_t *st, *err = NULL; php_http_client_enqueue_t *enqueue; php_http_client_curl_t *curl = context->ctx; - TSRMLS_FETCH_FROM_CTX(context->ts); do { - CURLMsg *msg = curl_multi_info_read(curl->handle, &remaining); + CURLMsg *msg = curl_multi_info_read(curl->handle->multi, &remaining); if (msg && CURLMSG_DONE == msg->msg) { if (CURLE_OK != msg->data.result) { @@@ -749,10 -743,10 +771,10 @@@ static void php_http_curlm_timeout_call (void) socket; (void) action; - while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle, CURL_SOCKET_TIMEOUT, 0, &curl->unfinished))); + while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle->multi, CURL_SOCKET_TIMEOUT, 0, &curl->unfinished))); if (CURLM_OK != rc) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc)); + php_error_docref(NULL, E_WARNING, "%s", curl_multi_strerror(rc)); } php_http_curlm_responsehandler(context); @@@ -769,11 -763,12 +791,11 @@@ static void php_http_curlm_event_callba #endif if (curl->useevents) { CURLMcode rc = CURLM_OK; - TSRMLS_FETCH_FROM_CTX(context->ts); - while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle, socket, etoca(action), &curl->unfinished))); + while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle->multi, socket, etoca(action), &curl->unfinished))); if (CURLM_OK != rc) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", curl_multi_strerror(rc)); + php_error_docref(NULL, E_WARNING, "%s", curl_multi_strerror(rc)); } php_http_curlm_responsehandler(context); @@@ -1661,9 -1663,10 +1687,9 @@@ static ZEND_RESULT_CODE php_http_curlm_ { php_http_client_t *client = userdata; php_http_client_curl_t *curl = client->ctx; - CURLM *ch = curl->handle; + CURLM *ch = curl->handle->multi; HashTable tmp_ht; char **bl = NULL; - TSRMLS_FETCH_FROM_CTX(client->ts); /* array of char *, ending with a NULL */ if (value && Z_TYPE_P(value) != IS_NULL) { @@@ -1897,10 -1896,12 +1924,11 @@@ static ZEND_RESULT_CODE php_http_client static php_http_client_curl_handler_t *php_http_client_curl_handler_init(php_http_client_t *h, php_resource_factory_t *rf) { void *handle; + php_http_client_curl_t *curl = h->ctx; php_http_client_curl_handler_t *handler; - TSRMLS_FETCH_FROM_CTX(h->ts); - if (!(handle = php_resource_factory_handle_ctor(rf, NULL TSRMLS_CC))) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to initialize curl handle->multi"); + if (!(handle = php_resource_factory_handle_ctor(rf, NULL))) { + php_error_docref(NULL, E_WARNING, "Failed to initialize curl handle"); return NULL; } @@@ -2166,20 -2163,21 +2197,21 @@@ static php_resource_factory_t *create_r char *id_str = NULL; size_t id_len; int port = url->port ? url->port : 80; - zval **zport; + zval *zport; + php_persistent_handle_factory_t *phf = h->rf->data; - if (SUCCESS == zend_hash_find(enqueue->options, ZEND_STRS("port"), (void *) &zport)) { - zval *zcpy = php_http_ztyp(IS_LONG, *zport); + if ((zport = zend_hash_str_find(enqueue->options, ZEND_STRL("port")))) { + zend_long lport = zval_get_long(zport); - if (Z_LVAL_P(zcpy)) { - port = Z_LVAL_P(zcpy); + if (lport > 0) { + port = lport; } - zval_ptr_dtor(&zcpy); } - id_len = spprintf(&id_str, 0, "%s:%d", STR_PTR(url->host), port); - id_len = spprintf(&id_str, 0, "%.*s:%s:%d", (int) phf->ident.len, phf->ident.str, STR_PTR(url->host), port); - pf = php_persistent_handle_concede(NULL, ZEND_STRL("http\\Client\\Curl\\Request"), id_str, id_len, NULL, NULL TSRMLS_CC); - efree(id_str); ++ id_len = spprintf(&id_str, 0, "%.*s:%s:%d", (int) phf->ident->len, phf->ident->val, STR_PTR(url->host), port); + id = php_http_cs2zs(id_str, id_len); + pf = php_persistent_handle_concede(NULL, PHP_HTTP_G->client.curl.driver.request_name, id, NULL, NULL); + zend_string_release(id); } if (pf) { @@@ -2218,21 -2217,22 +2250,22 @@@ static ZEND_RESULT_CODE php_http_client enqueue->opaque = handler; enqueue->dtor = queue_dtor; - if (CURLM_OK == (rs = curl_multi_add_handle(curl->handle, handler->handle))) { - zend_llist_add_element(&h->requests, enqueue); - ++curl->unfinished; - - if (h->callback.progress.func && SUCCESS == php_http_client_getopt(h, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, enqueue->request, &progress)) { - progress->info = "start"; - h->callback.progress.func(h->callback.progress.arg, h, &handler->queue, progress); - progress->started = 1; - } - - return SUCCESS; - } else { + if (CURLM_OK != (rs = curl_multi_add_handle(curl->handle->multi, handler->handle))) { + php_http_client_curl_handler_dtor(handler); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not enqueue request: %s", curl_multi_strerror(rs)); + php_error_docref(NULL, E_WARNING, "Could not enqueue request: %s", curl_multi_strerror(rs)); return FAILURE; } + + zend_llist_add_element(&h->requests, enqueue); + ++curl->unfinished; + + if (h->callback.progress.func && SUCCESS == php_http_client_getopt(h, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, enqueue->request, &progress)) { + progress->info = "start"; + h->callback.progress.func(h->callback.progress.arg, h, &handler->queue, progress); + progress->started = 1; + } + + return SUCCESS; } static ZEND_RESULT_CODE php_http_client_curl_dequeue(php_http_client_t *h, php_http_client_enqueue_t *enqueue) @@@ -2240,9 -2240,10 +2273,9 @@@ CURLMcode rs; php_http_client_curl_t *curl = h->ctx; php_http_client_curl_handler_t *handler = enqueue->opaque; - TSRMLS_FETCH_FROM_CTX(h->ts); php_http_client_curl_handler_clear(handler); - if (CURLM_OK == (rs = curl_multi_remove_handle(curl->handle, handler->handle))) { + if (CURLM_OK == (rs = curl_multi_remove_handle(curl->handle->multi, handler->handle))) { zend_llist_del_element(&h->requests, handler->handle, (int (*)(void *, void *)) compare_queue); return SUCCESS; } else { @@@ -2496,14 -2504,14 +2529,15 @@@ php_http_client_ops_t *php_http_client_ PHP_MINIT_FUNCTION(http_client_curl) { + curl_version_info_data *info; php_http_options_t *options; - php_http_client_driver_t driver = { - ZEND_STRL("curl"), - &php_http_client_curl_ops - }; - if (SUCCESS != php_http_client_driver_add(&driver)) { + PHP_HTTP_G->client.curl.driver.driver_name = zend_string_init(ZEND_STRL("curl"), 1); + PHP_HTTP_G->client.curl.driver.client_name = zend_string_init(ZEND_STRL("http\\Client\\Curl"), 1); + PHP_HTTP_G->client.curl.driver.request_name = zend_string_init(ZEND_STRL("http\\Client\\Curl\\Request"), 1); + PHP_HTTP_G->client.curl.driver.client_ops = &php_http_client_curl_ops; + + if (SUCCESS != php_http_client_driver_add(&PHP_HTTP_G->client.curl.driver)) { return FAILURE; } @@@ -2524,9 -2532,65 +2558,65 @@@ options->getter = php_http_option_get; options->setter = php_http_curlm_set_option; - php_http_curlm_options_init(options TSRMLS_CC); + php_http_curlm_options_init(options); } + if ((info = curl_version_info(CURLVERSION_NOW))) { + /* + * Feature constants + */ + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "FEATURES", info->features, CONST_CS|CONST_PERSISTENT); + + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "IPV6", CURL_VERSION_IPV6, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "KERBEROS4", CURL_VERSION_KERBEROS4, CONST_CS|CONST_PERSISTENT); + #if PHP_HTTP_CURL_VERSION(7,40,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "KERBEROS5", CURL_VERSION_KERBEROS5, CONST_CS|CONST_PERSISTENT); + #endif + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "SSL", CURL_VERSION_SSL, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "LIBZ", CURL_VERSION_LIBZ, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "NTLM", CURL_VERSION_NTLM, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "GSSNEGOTIATE", CURL_VERSION_GSSNEGOTIATE, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "ASYNCHDNS", CURL_VERSION_ASYNCHDNS, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "SPNEGO", CURL_VERSION_SPNEGO, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "LARGEFILE", CURL_VERSION_LARGEFILE, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "IDN", CURL_VERSION_IDN, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "SSPI", CURL_VERSION_SSPI, CONST_CS|CONST_PERSISTENT); + #if PHP_HTTP_CURL_VERSION(7,38,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "GSSAPI", CURL_VERSION_GSSAPI, CONST_CS|CONST_PERSISTENT); + #endif + #if PHP_HTTP_CURL_VERSION(7,21,4) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "TLSAUTH_SRP", CURL_VERSION_TLSAUTH_SRP, CONST_CS|CONST_PERSISTENT); + #endif + #if PHP_HTTP_CURL_VERSION(7,22,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "NTLM_WB", CURL_VERSION_NTLM_WB, CONST_CS|CONST_PERSISTENT); + #endif + #if PHP_HTTP_CURL_VERSION(7,33,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "HTTP2", CURL_VERSION_HTTP2, CONST_CS|CONST_PERSISTENT); + #endif + #if PHP_HTTP_CURL_VERSION(7,40,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "UNIX_SOCKETS", CURL_VERSION_UNIX_SOCKETS, CONST_CS|CONST_PERSISTENT); + #endif + #if PHP_HTTP_CURL_VERSION(7,47,0) + REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl\\Features", "PSL", CURL_VERSION_PSL, CONST_CS|CONST_PERSISTENT); + #endif + + /* + * Version constants + */ + REGISTER_NS_STRING_CONSTANT("http\\Client\\Curl", "VERSIONS", curl_version(), CONST_CS|CONST_PERSISTENT); + #if CURLVERSION_NOW >= 0 + REGISTER_NS_STRING_CONSTANT("http\\Client\\Curl\\Versions", "CURL", (char *) info->version, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_STRING_CONSTANT("http\\Client\\Curl\\Versions", "SSL", (char *) info->ssl_version, CONST_CS|CONST_PERSISTENT); + REGISTER_NS_STRING_CONSTANT("http\\Client\\Curl\\Versions", "LIBZ", (char *) info->libz_version, CONST_CS|CONST_PERSISTENT); + # if CURLVERSION_NOW >= 1 + REGISTER_NS_STRING_CONSTANT("http\\Client\\Curl\\Versions", "ARES", (char *) info->ares, CONST_CS|CONST_PERSISTENT); + # if CURLVERSION_NOW >= 2 + REGISTER_NS_STRING_CONSTANT("http\\Client\\Curl\\Versions", "IDN", (char *) info->libidn, CONST_CS|CONST_PERSISTENT); + # endif + # endif + #endif + } + /* * HTTP Protocol Version Constants */ diff --cc src/php_http_header.c index 8242a7c,2f808c3..91204c1 --- a/src/php_http_header.c +++ b/src/php_http_header.c @@@ -36,90 -36,80 +36,137 @@@ ZEND_RESULT_CODE php_http_header_parse( return rs == PHP_HTTP_HEADER_PARSER_STATE_FAILURE ? FAILURE : SUCCESS; } -void php_http_header_to_callback(HashTable *headers, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg TSRMLS_DC) +void php_http_header_to_callback(HashTable *headers, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg) { - HashPosition pos; - php_http_array_hashkey_t key = php_http_array_hashkey_init(0); - zval **header; ++ php_http_arrkey_t key; ++ zval *header; + - FOREACH_HASH_KEYVAL(pos, headers, key, header) { - if (key.type == HASH_KEY_IS_STRING) { - php_http_header_to_callback_ex(key.str, *header, crlf, cb, cb_arg TSRMLS_CC); ++ ZEND_HASH_FOREACH_KEY_VAL(headers, key.h, key.key, header) ++ { ++ if (key.key) { ++ php_http_header_to_callback_ex(key.key->val, header, crlf, cb, cb_arg); + } + } ++ ZEND_HASH_FOREACH_END(); ++/* ++<<<<<<< HEAD + php_http_arrkey_t key; + zval *header, *single_header; + + ZEND_HASH_FOREACH_KEY_VAL(headers, key.h, key.key, header) + { + if (key.key) { + if (zend_string_equals_literal(key.key, "Set-Cookie") && Z_TYPE_P(header) == IS_ARRAY) { + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(header), single_header) + { + if (Z_TYPE_P(single_header) == IS_ARRAY) { + php_http_cookie_list_t *cookie = php_http_cookie_list_from_struct(NULL, single_header); + + 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 { + zend_string *zs = php_http_header_value_to_string(single_header); + + cb(cb_arg, crlf ? "Set-Cookie: %s" PHP_HTTP_CRLF : "Set-Cookie: %s", zs->val); + zend_string_release(zs); + } + } + ZEND_HASH_FOREACH_END(); + } else { + zend_string *zs = php_http_header_value_to_string(header); + + cb(cb_arg, crlf ? "%s: %s" PHP_HTTP_CRLF : "%s: %s", key.key->val, zs->val); + zend_string_release(zs); + } - } - } - ZEND_HASH_FOREACH_END(); ++======= ++>>>>>>> 343738ad56eb70017704fdac57cf0d74da3d0f2e ++*/ } -void php_http_header_to_string(php_http_buffer_t *str, HashTable *headers TSRMLS_DC) +void php_http_header_to_string(php_http_buffer_t *str, HashTable *headers) { - php_http_header_to_callback(headers, 1, (php_http_pass_format_callback_t) php_http_buffer_appendf, str TSRMLS_CC); + php_http_header_to_callback(headers, 1, (php_http_pass_format_callback_t) php_http_buffer_appendf, str); } -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) ++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) + { - HashPosition pos; - zval **aval, *tmp; ++ zval *aval; ++ zend_string *str; + + 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); ++ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(val), aval) ++ { ++ php_http_header_to_callback_ex(key, aval, crlf, cb, cb_arg); + } ++ ZEND_HASH_FOREACH_END(); ++ break; ++ ++ case IS_TRUE: ++ cb(cb_arg, "%s: true%s", key, crlf ? PHP_HTTP_CRLF:""); + break; + - case IS_BOOL: - cb(cb_arg, "%s: %s%s", key, Z_BVAL_P(val) ? "true" : "false", crlf ? PHP_HTTP_CRLF:""); ++ case IS_FALSE: ++ cb(cb_arg, "%s: false%s", key, 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); ++ str = zval_get_string(val); ++ cb(cb_arg, "%s: %s%s", key, str->val, crlf ? PHP_HTTP_CRLF:""); ++ zend_string_release(str); + break; + } + } + -void php_http_header_to_string_ex(php_http_buffer_t *str, const char *key, zval *val TSRMLS_DC) ++void php_http_header_to_string_ex(php_http_buffer_t *str, const char *key, zval *val) + { - php_http_header_to_callback_ex(key, val, 1, (php_http_pass_format_callback_t) php_http_buffer_appendf, str TSRMLS_CC); ++ php_http_header_to_callback_ex(key, val, 1, (php_http_pass_format_callback_t) php_http_buffer_appendf, str); + } + -zval *php_http_header_value_to_string(zval *header TSRMLS_DC) +zend_string *php_http_header_value_array_to_string(zval *header) { - zval *ret; - - if (Z_TYPE_P(header) == IS_BOOL) { - MAKE_STD_ZVAL(ret); - ZVAL_STRING(ret, Z_BVAL_P(header) ? "true" : "false", 1); - } else if (Z_TYPE_P(header) == IS_ARRAY) { - zval **val; - HashPosition pos; - php_http_buffer_t str; - - php_http_buffer_init(&str); - MAKE_STD_ZVAL(ret); - FOREACH_VAL(pos,header, val) { - zval *strval = php_http_header_value_to_string(*val TSRMLS_CC); - - php_http_buffer_appendf(&str, str.used ? ", %s":"%s", Z_STRVAL_P(strval)); - zval_ptr_dtor(&strval); - } - php_http_buffer_fix(&str); - ZVAL_STRINGL(ret, str.data, str.used, 0); - } else { - ret = php_http_zsep(1, IS_STRING, header); + zval *val; + php_http_buffer_t str; + + php_http_buffer_init(&str); + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(header), val) + { + zend_string *zs = php_http_header_value_to_string(val); + + php_http_buffer_appendf(&str, str.used ? ", %s":"%s", zs->val); + zend_string_release(zs); + } + ZEND_HASH_FOREACH_END(); + php_http_buffer_fix(&str); + + return php_http_cs2zs(str.data, str.used); +} + +zend_string *php_http_header_value_to_string(zval *header) +{ + switch (Z_TYPE_P(header)) { + case IS_TRUE: + return zend_string_init(ZEND_STRL("true"), 0); + case IS_FALSE: + return zend_string_init(ZEND_STRL("false"), 0); + case IS_ARRAY: + return php_http_header_value_array_to_string(header); + default: + return zval_get_string(header); } +} - return ret; +static zend_class_entry *php_http_header_class_entry; +zend_class_entry *php_http_header_get_class_entry(void) +{ + return php_http_header_class_entry; } ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader___construct, 0, 0, 0) diff --cc src/php_http_header.h index 1ba9ef5,9a57d8f..00ef264 --- a/src/php_http_header.h +++ b/src/php_http_header.h @@@ -15,15 -15,16 +15,17 @@@ #include "php_http_info.h" -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 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); -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 void php_http_header_to_callback(HashTable *headers, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg); ++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); +PHP_HTTP_API void php_http_header_to_string(php_http_buffer_t *str, HashTable *headers); ++PHP_HTTP_API void php_http_header_to_string_ex(php_http_buffer_t *str, const char *key, zval *val); -PHP_HTTP_API zval *php_http_header_value_to_string(zval *header TSRMLS_DC); +PHP_HTTP_API zend_string *php_http_header_value_to_string(zval *header); +PHP_HTTP_API zend_string *php_http_header_value_array_to_string(zval *header); -PHP_HTTP_API zend_class_entry *php_http_header_class_entry; +PHP_HTTP_API zend_class_entry *php_http_header_get_class_entry(void); PHP_MINIT_FUNCTION(http_header); #endif diff --cc src/php_http_message.c index 8f49e92,2b3090a..56499bb --- a/src/php_http_message.c +++ b/src/php_http_message.c @@@ -1242,21 -1281,32 +1242,32 @@@ static PHP_METHOD(HttpMessage, addHeade { zval *zvalue; char *name_str; - int name_len; + size_t name_len; - 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); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &name_str, &name_len, &zvalue)) { + php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); 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); ++ zend_string *hstr, *vstr = php_http_header_value_to_string(zvalue); ++ zval tmp, *header; PHP_HTTP_MESSAGE_OBJECT_INIT(obj); - Z_TRY_ADDREF_P(zvalue); - if ((header = php_http_message_header(obj->message, name, name_len))) { + if ((name_len != lenof("Set-Cookie") && strcmp(name, "Set-Cookie")) - && (header = php_http_message_header(obj->message, name, name_len, 1))) { - zval *tmp; ++ && (hstr = php_http_message_header_string(obj->message, name, name_len))) { + 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))) { ++ size_t hdr_len = spprintf(&hdr_str, 0, "%s, %s", hstr->val, vstr->val); ++ ++ ZVAL_STR(&tmp, php_http_cs2zs(hdr_str, hdr_len)); ++ zend_symtable_str_update(&obj->message->hdrs, name, name_len, &tmp); ++ zend_string_release(hstr); ++ zend_string_release(vstr); ++ } else if ((header = php_http_message_header(obj->message, name, name_len))) { convert_to_array(header); - zend_hash_next_index_insert(Z_ARRVAL_P(header), zvalue); - zend_hash_next_index_insert(Z_ARRVAL_P(header), &cpy, sizeof(void *), NULL); - zval_ptr_dtor(&header); ++ ZVAL_STR(&tmp, vstr); ++ zend_hash_next_index_insert(Z_ARRVAL_P(header), &tmp); } else { - zend_symtable_str_update(&obj->message->hdrs, name, name_len, zvalue); - zend_symtable_update(&obj->message->hdrs, name, name_len + 1, &cpy, sizeof(void *), NULL); ++ ZVAL_STR(&tmp, vstr); ++ zend_symtable_str_update(&obj->message->hdrs, name, name_len, &tmp); } efree(name); }