From 0e0def98a4ea4463bf8c21c6f161b2b37aa8c49d Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 20 Nov 2006 11:15:06 +0000 Subject: [PATCH 1/1] - improve internal array handling - fix HttpMessage's header handling --- http_api.c | 64 +++++++++++++++++++++++++++++++++++++ http_cookie_api.c | 18 ++++------- http_headers_api.c | 17 ++++------ http_message_api.c | 25 ++++++--------- http_message_object.c | 43 ++++++++++--------------- http_querystring_api.c | 37 ++++++++++----------- http_request_api.c | 71 +++++++++++++++-------------------------- http_request_body_api.c | 12 +++---- http_request_object.c | 67 ++++++++++++++++++-------------------- http_url_api.c | 19 +++++------ php_http_api.h | 36 +++++++++++++++++++++ php_http_request_int.h | 6 ++-- php_http_std_defs.h | 66 -------------------------------------- 13 files changed, 227 insertions(+), 254 deletions(-) diff --git a/http_api.c b/http_api.c index f8f93e1..b77dd19 100644 --- a/http_api.c +++ b/http_api.c @@ -584,6 +584,70 @@ failure: } /* }}} */ +/* {{{ array_join */ +int apply_array_append_func(void *pDest, int num_args, va_list args, zend_hash_key *hash_key) +{ + int flags; + char *key = NULL; + HashTable *dst; + zval **data = NULL, **value = (zval **) pDest; + + dst = va_arg(args, HashTable *); + flags = va_arg(args, int); + + if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) { + if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) { + key = pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1); + zend_hash_find(dst, key, hash_key->nKeyLength, (void *) &data); + } else { + zend_hash_quick_find(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) &data); + } + + ZVAL_ADDREF(*value); + if (data) { + if (Z_TYPE_PP(data) != IS_ARRAY) { + convert_to_array(*data); + } + add_next_index_zval(*data, *value); + } else if (key) { + zend_hash_add(dst, key, hash_key->nKeyLength, value, sizeof(zval *), NULL); + } else { + zend_hash_quick_add(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, value, sizeof(zval *), NULL); + } + + if (key) { + efree(key); + } + } + + return ZEND_HASH_APPLY_KEEP; +} + +int apply_array_merge_func(void *pDest, int num_args, va_list args, zend_hash_key *hash_key) +{ + int flags; + char *key = NULL; + HashTable *dst; + zval **value = (zval **) pDest; + + dst = va_arg(args, HashTable *); + flags = va_arg(args, int); + + if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->nKeyLength) { + ZVAL_ADDREF(*value); + if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->nKeyLength) { + key = pretty_key(estrndup(hash_key->arKey, hash_key->nKeyLength - 1), hash_key->nKeyLength - 1, 1, 1); + zend_hash_update(dst, key, hash_key->nKeyLength, (void *) value, sizeof(zval *), NULL); + efree(key); + } else { + zend_hash_quick_update(dst, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void *) value, sizeof(zval *), NULL); + } + } + + return ZEND_HASH_APPLY_KEEP; +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff --git a/http_cookie_api.c b/http_cookie_api.c index b487e20..360b793 100644 --- a/http_cookie_api.c +++ b/http_cookie_api.c @@ -316,17 +316,14 @@ PHP_HTTP_API void _http_cookie_list_tostring(http_cookie_list *list, char **str, { phpstr buf; zval **val; - ulong idx = 0; - uint keylen = 0; - char *key = NULL; + HashKey key = initHashKey(0); HashPosition pos; phpstr_init(&buf); - FOREACH_HASH_KEYLENVAL(pos, &list->cookies, key, keylen, idx, val) { - if (key && keylen) { - append_encoded(&buf, key, keylen-1, Z_STRVAL_PP(val), Z_STRLEN_PP(val)); - key = NULL; + FOREACH_HASH_KEYVAL(pos, &list->cookies, key, val) { + if (key.type == HASH_KEY_IS_STRING && key.len) { + append_encoded(&buf, key.str, key.len-1, Z_STRVAL_PP(val), Z_STRLEN_PP(val)); } } @@ -342,10 +339,9 @@ PHP_HTTP_API void _http_cookie_list_tostring(http_cookie_list *list, char **str, efree(date); } - FOREACH_HASH_KEYLENVAL(pos, &list->extras, key, keylen, idx, val) { - if (key && keylen) { - append_encoded(&buf, key, keylen-1, Z_STRVAL_PP(val), Z_STRLEN_PP(val)); - key = NULL; + FOREACH_HASH_KEYVAL(pos, &list->extras, key, val) { + if (key.type == HASH_KEY_IS_STRING && key.len) { + append_encoded(&buf, key.str, key.len-1, Z_STRVAL_PP(val), Z_STRLEN_PP(val)); } } diff --git a/http_headers_api.c b/http_headers_api.c index 9fd3b75..ef5099f 100644 --- a/http_headers_api.c +++ b/http_headers_api.c @@ -423,9 +423,7 @@ PHP_HTTP_API STATUS _http_parse_headers_ex(const char *header, HashTable *header /* {{{ void http_get_request_headers(HashTable *) */ PHP_HTTP_API void _http_get_request_headers(HashTable *headers TSRMLS_DC) { - char *key = NULL; - ulong idx = 0; - uint keylen = 0; + HashKey key = initHashKey(0); zval **hsv, **header; HashPosition pos; @@ -438,17 +436,16 @@ PHP_HTTP_API void _http_get_request_headers(HashTable *headers TSRMLS_DC) #endif if (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &hsv) && Z_TYPE_PP(hsv) == IS_ARRAY) { - FOREACH_KEYLEN(pos, *hsv, key, keylen, idx) { - if (key && keylen > 6 && !strncmp(key, "HTTP_", 5)) { - keylen -= 6; - key = pretty_key(estrndup(key + 5, keylen), keylen, 1, 1); + FOREACH_KEY(pos, *hsv, key) { + if (key.type == HASH_KEY_IS_STRING && key.len > 6 && !strncmp(key.str, "HTTP_", 5)) { + key.len -= 5; + key.str = pretty_key(estrndup(key.str + 5, key.len - 1), key.len - 1, 1, 1); zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos); ZVAL_ADDREF(*header); - zend_hash_add(HTTP_G->request.headers, key, keylen + 1, (void *) header, sizeof(zval *), NULL); + zend_hash_add(HTTP_G->request.headers, key.str, key.len, (void *) header, sizeof(zval *), NULL); - STR_SET(key, NULL) - keylen = 0; + efree(key.str); } } } diff --git a/http_message_api.c b/http_message_api.c index 4da4e88..85b2b00 100644 --- a/http_message_api.c +++ b/http_message_api.c @@ -308,9 +308,9 @@ PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, const char PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_t *length) { phpstr str; - char *key, *data; - ulong idx; + HashKey key = initHashKey(0); zval **header; + char *data; HashPosition pos1; phpstr_init_ex(&str, 4096, 0); @@ -336,24 +336,22 @@ PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_ break; } - FOREACH_HASH_KEYVAL(pos1, &msg->hdrs, key, idx, header) { - if (key) { + FOREACH_HASH_KEYVAL(pos1, &msg->hdrs, key, header) { + if (key.type == HASH_KEY_IS_STRING) { HashPosition pos2; zval **single_header; switch (Z_TYPE_PP(header)) { case IS_STRING: - phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key, Z_STRVAL_PP(header)); + phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key.str, Z_STRVAL_PP(header)); break; case IS_ARRAY: FOREACH_VAL(pos2, *header, single_header) { - phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key, Z_STRVAL_PP(single_header)); + phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key.str, Z_STRVAL_PP(single_header)); } break; } - - key = NULL; } } @@ -500,16 +498,13 @@ PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC) switch (message->type) { case HTTP_MSG_RESPONSE: { - char *key; - uint len; - ulong idx; + HashKey key = initHashKey(0); zval **val; HashPosition pos; - FOREACH_HASH_KEYLENVAL(pos, &message->hdrs, key, len, idx, val) { - if (key) { - http_send_header_zval_ex(key, len-1, val, 1); - key = NULL; + FOREACH_HASH_KEYVAL(pos, &message->hdrs, key, val) { + if (key.type == HASH_KEY_IS_STRING) { + http_send_header_zval_ex(key.str, key.len-1, val, 1); } } rs = SUCCESS == http_send_status(message->http.info.response.code) && diff --git a/http_message_object.c b/http_message_object.c index 5624e21..495cd28 100644 --- a/http_message_object.c +++ b/http_message_object.c @@ -827,12 +827,10 @@ PHP_METHOD(HttpMessage, getHeaders) NO_ARGS; if (return_value_used) { - zval headers; getObject(http_message_object, obj); - INIT_ZARR(headers, &obj->message->hdrs); array_init(return_value); - array_copy(&headers, return_value); + array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value)); } } /* }}} */ @@ -846,7 +844,7 @@ PHP_METHOD(HttpMessage, getHeaders) */ PHP_METHOD(HttpMessage, setHeaders) { - zval *new_headers = NULL, old_headers; + zval *new_headers = NULL; getObject(http_message_object, obj); if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/!", &new_headers)) { @@ -855,8 +853,7 @@ PHP_METHOD(HttpMessage, setHeaders) zend_hash_clean(&obj->message->hdrs); if (new_headers) { - INIT_ZARR(old_headers, &obj->message->hdrs); - array_copy(new_headers, &old_headers); + array_copy(Z_ARRVAL_P(new_headers), &obj->message->hdrs); } } /* }}} */ @@ -873,7 +870,7 @@ PHP_METHOD(HttpMessage, setHeaders) */ PHP_METHOD(HttpMessage, addHeaders) { - zval old_headers, *new_headers; + zval *new_headers; zend_bool append = 0; getObject(http_message_object, obj); @@ -881,12 +878,7 @@ PHP_METHOD(HttpMessage, addHeaders) return; } - INIT_ZARR(old_headers, &obj->message->hdrs); - if (append) { - array_append(new_headers, &old_headers); - } else { - array_merge(new_headers, &old_headers); - } + array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, append, ARRAY_JOIN_STRONLY|ARRAY_JOIN_PRETTIFY); } /* }}} */ @@ -1298,7 +1290,7 @@ PHP_METHOD(HttpMessage, toMessageTypeObject) #ifdef HTTP_HAVE_CURL int method; char *url; - zval tmp, body, *array, *headers, *host = http_message_header(obj->message, "Host"); + zval body, *array, *headers, *host = http_message_header(obj->message, "Host"); php_url hurl, *purl = php_url_parse(obj->message->http.info.request.url); MAKE_STD_ZVAL(array); @@ -1322,8 +1314,7 @@ PHP_METHOD(HttpMessage, toMessageTypeObject) MAKE_STD_ZVAL(headers); array_init(headers); - INIT_ZARR(tmp, &obj->message->hdrs); - array_copy(&tmp, headers); + array_copy(&obj->message->hdrs, Z_ARRVAL_P(headers)); add_assoc_zval(array, "headers", headers); object_init_ex(return_value, http_request_object_ce); @@ -1343,9 +1334,7 @@ PHP_METHOD(HttpMessage, toMessageTypeObject) { #ifndef WONKY HashPosition pos1, pos2; - ulong idx; - uint key_len; - char *key = NULL; + HashKey key = initHashKey(0); zval **header, **h, *body; if (obj->message->http.info.response.code) { @@ -1354,30 +1343,30 @@ PHP_METHOD(HttpMessage, toMessageTypeObject) object_init_ex(return_value, http_response_object_ce); - FOREACH_HASH_KEYLENVAL(pos1, &obj->message->hdrs, key, key_len, idx, header) { - if (key) { - zval zkey; + FOREACH_HASH_KEYVAL(pos1, &obj->message->hdrs, key, header) { + if (key.type == HASH_KEY_IS_STRING) { + zval *zkey; - INIT_PZVAL(&zkey); - ZVAL_STRINGL(&zkey, key, key_len, 0); + MAKE_STD_ZVAL(zkey); + ZVAL_STRINGL(zkey, key.str, key.len - 1, 1); switch (Z_TYPE_PP(header)) { case IS_ARRAY: case IS_OBJECT: FOREACH_HASH_VAL(pos2, HASH_OF(*header), h) { ZVAL_ADDREF(*h); - zend_call_method_with_2_params(&return_value, http_response_object_ce, NULL, "setheader", NULL, &zkey, *h); + zend_call_method_with_2_params(&return_value, http_response_object_ce, NULL, "setheader", NULL, zkey, *h); zval_ptr_dtor(h); } break; default: ZVAL_ADDREF(*header); - zend_call_method_with_2_params(&return_value, http_response_object_ce, NULL, "setheader", NULL, &zkey, *header); + zend_call_method_with_2_params(&return_value, http_response_object_ce, NULL, "setheader", NULL, zkey, *header); zval_ptr_dtor(header); break; } - key = NULL; + zval_ptr_dtor(&zkey); } } diff --git a/http_querystring_api.c b/http_querystring_api.c index 4c45664..09a767f 100644 --- a/http_querystring_api.c +++ b/http_querystring_api.c @@ -43,52 +43,50 @@ PHP_HTTP_API int _http_querystring_xlate(zval *array, zval *param, const char *i { HashPosition pos; zval **entry = NULL; - char *xlate_str = NULL, *xkey, *kstr = NULL; + char *xlate_str = NULL, *xkey; size_t xlate_len = 0, xlen; - uint klen = 0; - ulong kidx = 0; + HashKey key = initHashKey(0); - FOREACH_KEYLENVAL(pos, param, kstr, klen, kidx, entry) { - if (kstr) { - if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(kstr, klen-1, &xkey, &xlen, oe, ie)) { - http_error_ex(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to convert '%.*s' from '%s' to '%s'", klen-1, kstr, ie, oe); + FOREACH_KEYVAL(pos, param, key, entry) { + if (key.type == HASH_KEY_IS_STRING) { + if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(key.str, key.len-1, &xkey, &xlen, oe, ie)) { + http_error_ex(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to convert '%.*s' from '%s' to '%s'", key.len-1, key.str, ie, oe); return FAILURE; } } if (Z_TYPE_PP(entry) == IS_STRING) { if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), &xlate_str, &xlate_len, oe, ie)) { - if (kstr) { + if (key.type == HASH_KEY_IS_STRING) { efree(xkey); } http_error_ex(HE_WARNING, HTTP_E_QUERYSTRING, "Failed to convert '%.*s' from '%s' to '%s'", Z_STRLEN_PP(entry), Z_STRVAL_PP(entry), ie, oe); return FAILURE; } - if (kstr) { + if (key.type == HASH_KEY_IS_STRING) { add_assoc_stringl_ex(array, xkey, xlen+1, xlate_str, xlate_len, 0); } else { - add_index_stringl(array, kidx, xlate_str, xlate_len, 0); + add_index_stringl(array, key.num, xlate_str, xlate_len, 0); } } else if (Z_TYPE_PP(entry) == IS_ARRAY) { zval *subarray; MAKE_STD_ZVAL(subarray); array_init(subarray); - if (kstr) { + if (key.type == HASH_KEY_IS_STRING) { add_assoc_zval_ex(array, xkey, xlen+1, subarray); } else { - add_index_zval(array, kidx, subarray); + add_index_zval(array, key.num, subarray); } if (SUCCESS != http_querystring_xlate(subarray, *entry, ie, oe)) { - if (kstr) { + if (key.type == HASH_KEY_IS_STRING) { efree(xkey); } return FAILURE; } } - if (kstr) { - kstr = NULL; + if (key.type == HASH_KEY_IS_STRING) { efree(xkey); } } @@ -147,18 +145,15 @@ PHP_HTTP_API int _http_querystring_modify(zval *qarray, zval *params TSRMLS_DC) static inline int _http_querystring_modify_array(zval *qarray, zval *params TSRMLS_DC) { int rv = 0; - char *key = NULL; - uint keylen = 0; - ulong idx = 0; + HashKey key = initHashKey(0); HashPosition pos; zval **params_entry = NULL; - FOREACH_KEYLENVAL(pos, params, key, keylen, idx, params_entry) { + FOREACH_KEYVAL(pos, params, key, params_entry) { /* only public properties */ - if ((!key || *key) && http_querystring_modify_array_ex(qarray, key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG, key, keylen, idx, *params_entry)) { + if ((key.type != HASH_KEY_IS_STRING || *key.str) && http_querystring_modify_array_ex(qarray, key.type, key.str, key.len, key.num, *params_entry)) { rv = 1; } - key = NULL; } return rv; diff --git a/http_request_api.c b/http_request_api.c index 62b66bd..fa8ea70 100644 --- a/http_request_api.c +++ b/http_request_api.c @@ -309,8 +309,7 @@ PHP_HTTP_API STATUS _http_request_enable_cookies(http_request *request) TSRMLS_FETCH_FROM_CTX(request->tsrm_ls); HTTP_CHECK_CURL_INIT(request->ch, http_curl_init_ex(request->ch, request), initialized = 0); - if (initialized) { - curl_easy_setopt(request->ch, CURLOPT_COOKIEFILE, ""); + if (initialized && CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIEFILE, "")) { return SUCCESS; } http_error(HE_WARNING, HTTP_E_REQUEST, "Could not enable cookies for this session"); @@ -327,16 +326,14 @@ PHP_HTTP_API STATUS _http_request_reset_cookies(http_request *request, int sessi HTTP_CHECK_CURL_INIT(request->ch, http_curl_init_ex(request->ch, request), initialized = 0); if (session_only) { #if HTTP_CURL_VERSION(7,15,4) - if (initialized) { - curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "SESS"); + if (initialized && CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "SESS")) { return SUCCESS; } #endif http_error(HE_WARNING, HTTP_E_REQUEST, "Could not reset session cookies (need libcurl >= v7.15.4)"); } else { #if HTTP_CURL_VERSION(7,14,1) - if (initialized) { - curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "ALL"); + if (initialized && CURLE_OK == curl_easy_setopt(request->ch, CURLOPT_COOKIELIST, "ALL")) { return SUCCESS; } #endif @@ -637,28 +634,22 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti request->_cache.headers = NULL; } if ((zoption = http_request_option(request, options, "headers", IS_ARRAY))) { - char *header_key = NULL; - ulong header_idx; + HashKey header_key = initHashKey(0); + zval **header_val; HashPosition pos; - FOREACH_KEY(pos, zoption, header_key, header_idx) { - if (header_key) { - zval **header_val; - if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_P(zoption), (void *) &header_val, &pos)) { - char header[1024] = {0}; - - ZVAL_ADDREF(*header_val); - convert_to_string_ex(header_val); - if (!strcasecmp(header_key, "range")) { - range_req = 1; - } - snprintf(header, lenof(header), "%s: %s", header_key, Z_STRVAL_PP(header_val)); - request->_cache.headers = curl_slist_append(request->_cache.headers, header); - zval_ptr_dtor(header_val); + FOREACH_KEYVAL(pos, zoption, header_key, header_val) { + if (header_key.type == HASH_KEY_IS_STRING) { + char header[1024] = {0}; + + ZVAL_ADDREF(*header_val); + convert_to_string_ex(header_val); + if (!strcasecmp(header_key.str, "range")) { + range_req = 1; } - - /* reset */ - header_key = NULL; + snprintf(header, lenof(header), "%s: %s", header_key.str, Z_STRVAL_PP(header_val)); + request->_cache.headers = curl_slist_append(request->_cache.headers, header); + zval_ptr_dtor(header_val); } } } @@ -706,20 +697,14 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti } } else { HashPosition pos; - char *cookie_key = NULL; - ulong cookie_idx; + HashKey cookie_key = initHashKey(0); + zval **cookie_val; - FOREACH_KEY(pos, zoption, cookie_key, cookie_idx) { - if (cookie_key) { - zval **cookie_val; - if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_P(zoption), (void *) &cookie_val, &pos)) { - zval *val = zval_copy(IS_STRING, *cookie_val); - phpstr_appendf(&request->_cache.cookies, "%s=%s; ", cookie_key, Z_STRVAL_P(val)); - zval_free(&val); - } - - /* reset */ - cookie_key = NULL; + FOREACH_KEYVAL(pos, zoption, cookie_key, cookie_val) { + if (cookie_key.type == HASH_KEY_IS_STRING) { + zval *val = zval_copy(IS_STRING, *cookie_val); + phpstr_appendf(&request->_cache.cookies, "%s=%s; ", cookie_key.str, Z_STRVAL_P(val)); + zval_free(&val); } } @@ -767,13 +752,12 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti /* ssl */ if ((zoption = http_request_option(request, options, "ssl", IS_ARRAY))) { - ulong idx; - char *key = NULL; + HashKey key = initHashKey(0); zval **param; HashPosition pos; - FOREACH_KEYVAL(pos, zoption, key, idx, param) { - if (key) { + FOREACH_KEYVAL(pos, zoption, key, param) { + if (key.type == HASH_KEY_IS_STRING) { HTTP_CURL_OPT_STRING(CURLOPT_SSLCERT, 0, 1); HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTTYPE, 0, 0); HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTPASSWD, 0, 0); @@ -793,9 +777,6 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti HTTP_CURL_OPT_STRING(CURLOPT_CAPATH, -3, 1); HTTP_CURL_OPT_STRING(CURLOPT_RANDOM_FILE, -3, 1); HTTP_CURL_OPT_STRING(CURLOPT_EGDSOCKET, -3, 1); - - /* reset key */ - key = NULL; } } } diff --git a/http_request_body_api.c b/http_request_body_api.c index a577023..bc1648c 100644 --- a/http_request_body_api.c +++ b/http_request_body_api.c @@ -99,22 +99,21 @@ PHP_HTTP_API http_request_body *_http_request_body_init_ex(http_request_body *bo PHP_HTTP_API http_request_body *_http_request_body_fill(http_request_body *body, HashTable *fields, HashTable *files ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC) { if (files && (zend_hash_num_elements(files) > 0)) { - char *key = NULL; - ulong idx; + HashKey key = initHashKey(0); zval **data; HashPosition pos; struct curl_httppost *http_post_data[2] = {NULL, NULL}; /* normal data */ if (fields) { - FOREACH_HASH_KEYVAL(pos, fields, key, idx, data) { - if (key) { + FOREACH_HASH_KEYVAL(pos, fields, key, data) { + if (key.type == HASH_KEY_IS_STRING) { CURLcode err; zval *orig = *data; convert_to_string_ex(data); err = curl_formadd(&http_post_data[0], &http_post_data[1], - CURLFORM_COPYNAME, key, + CURLFORM_COPYNAME, key.str, CURLFORM_COPYCONTENTS, Z_STRVAL_PP(data), CURLFORM_CONTENTSLENGTH, (long) Z_STRLEN_PP(data), CURLFORM_END @@ -129,9 +128,6 @@ PHP_HTTP_API http_request_body *_http_request_body_fill(http_request_body *body, curl_formfree(http_post_data[0]); return NULL; } - - /* reset */ - key = NULL; } } } diff --git a/http_request_object.c b/http_request_object.c index 3b40bd2..c56562a 100644 --- a/http_request_object.c +++ b/http_request_object.c @@ -748,26 +748,26 @@ static inline void _http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM array_init(new_opts); old_opts = GET_PROP(options); if (Z_TYPE_P(old_opts) == IS_ARRAY) { - array_copy(old_opts, new_opts); + array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts)); } - if (prettify_keys && opts) { - zend_hash_apply_with_arguments(Z_ARRVAL_P(opts), apply_pretty_key, 0); - } if (SUCCESS == zend_hash_find(Z_ARRVAL_P(new_opts), key, len, (void *) &entry)) { if (overwrite) { zend_hash_clean(Z_ARRVAL_PP(entry)); } if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) { if (overwrite) { - array_copy(opts, *entry); + array_copy(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry)); } else { - array_merge(opts, *entry); + array_join(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry), 0, prettify_keys ? ARRAY_JOIN_PRETTIFY : 0); } } } else if (opts) { + if (prettify_keys) { + zend_hash_apply_with_arguments(Z_ARRVAL_P(opts), apply_pretty_key, 0); + } ZVAL_ADDREF(opts); - add_assoc_zval(new_opts, key, opts); + add_assoc_zval_ex(new_opts, key, len, opts); } SET_PROP(options, new_opts); zval_ptr_dtor(&new_opts); @@ -790,7 +790,7 @@ static inline void _http_request_get_options_subr(INTERNAL_FUNCTION_PARAMETERS, if ( (Z_TYPE_P(opts) == IS_ARRAY) && (SUCCESS == zend_hash_find(Z_ARRVAL_P(opts), key, len, (void *) &options))) { convert_to_array(*options); - array_copy(*options, return_value); + array_copy(Z_ARRVAL_PP(options), Z_ARRVAL_P(return_value)); } } } @@ -844,8 +844,7 @@ PHP_METHOD(HttpRequest, __construct) */ PHP_METHOD(HttpRequest, setOptions) { - char *key = NULL; - ulong idx = 0; + HashKey key = initHashKey(0); HashPosition pos; zval *opts = NULL, *old_opts, *new_opts, *add_opts, **opt; @@ -865,42 +864,40 @@ PHP_METHOD(HttpRequest, setOptions) MAKE_STD_ZVAL(add_opts); array_init(add_opts); /* some options need extra attention -- thus cannot use array_merge() directly */ - FOREACH_KEYVAL(pos, opts, key, idx, opt) { - if (key) { - if (!strcmp(key, "headers")) { + FOREACH_KEYVAL(pos, opts, key, opt) { + if (key.type == HASH_KEY_IS_STRING) { + if (!strcmp(key.str, "headers")) { zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addheaders", NULL, *opt); - } else if (!strcmp(key, "cookies")) { + } else if (!strcmp(key.str, "cookies")) { zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addcookies", NULL, *opt); - } else if (!strcmp(key, "ssl")) { + } else if (!strcmp(key.str, "ssl")) { zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "addssloptions", NULL, *opt); - } else if ((!strcasecmp(key, "url")) || (!strcasecmp(key, "uri"))) { + } else if ((!strcasecmp(key.str, "url")) || (!strcasecmp(key.str, "uri"))) { zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "seturl", NULL, *opt); - } else if (!strcmp(key, "method")) { + } else if (!strcmp(key.str, "method")) { zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "setmethod", NULL, *opt); #if HTTP_CURL_VERSION(7,14,1) - } else if (!strcmp(key, "resetcookies")) { + } else if (!strcmp(key.str, "resetcookies")) { getObject(http_request_object, obj); http_request_reset_cookies(obj->request, 0); #endif - } else if (!strcmp(key, "enablecookies")) { + } else if (!strcmp(key.str, "enablecookies")) { getObject(http_request_object, obj); http_request_enable_cookies(obj->request); - } else if (!strcasecmp(key, "recordHistory")) { + } else if (!strcasecmp(key.str, "recordHistory")) { UPD_PROP(bool, recordHistory, 1); } else { ZVAL_ADDREF(*opt); - add_assoc_zval(add_opts, key, *opt); + add_assoc_zval_ex(add_opts, key.str, key.len, *opt); } - /* reset */ - key = NULL; } } old_opts = GET_PROP(options); if (Z_TYPE_P(old_opts) == IS_ARRAY) { - array_copy(old_opts, new_opts); + array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts)); } - array_merge(add_opts, new_opts); + array_join(Z_ARRVAL_P(add_opts), Z_ARRVAL_P(new_opts), 0, 0); SET_PROP(options, new_opts); zval_ptr_dtor(&new_opts); zval_ptr_dtor(&add_opts); @@ -1320,9 +1317,9 @@ PHP_METHOD(HttpRequest, addPostFields) array_init(new_post); old_post = GET_PROP(postFields); if (Z_TYPE_P(old_post) == IS_ARRAY) { - array_copy(old_post, new_post); + array_copy(Z_ARRVAL_P(old_post), Z_ARRVAL_P(new_post)); } - array_merge(post_data, new_post); + array_join(Z_ARRVAL_P(post_data), Z_ARRVAL_P(new_post), 0, 0); SET_PROP(postFields, new_post); zval_ptr_dtor(&new_post); } @@ -1352,7 +1349,7 @@ PHP_METHOD(HttpRequest, setPostFields) MAKE_STD_ZVAL(post); array_init(post); if (post_data && zend_hash_num_elements(Z_ARRVAL_P(post_data))) { - array_copy(post_data, post); + array_copy(Z_ARRVAL_P(post_data), Z_ARRVAL_P(post)); } SET_PROP(postFields, post); zval_ptr_dtor(&post); @@ -1498,7 +1495,7 @@ PHP_METHOD(HttpRequest, addPostFile) array_init(new_post); old_post = GET_PROP(postFiles); if (Z_TYPE_P(old_post) == IS_ARRAY) { - array_copy(old_post, new_post); + array_copy(Z_ARRVAL_P(old_post), Z_ARRVAL_P(new_post)); } add_next_index_zval(new_post, entry); SET_PROP(postFiles, new_post); @@ -1530,7 +1527,7 @@ PHP_METHOD(HttpRequest, setPostFiles) MAKE_STD_ZVAL(post); array_init(post); if (files && (Z_TYPE_P(files) == IS_ARRAY)) { - array_copy(files, post); + array_copy(Z_ARRVAL_P(files), Z_ARRVAL_P(post)); } SET_PROP(postFiles, post); zval_ptr_dtor(&post); @@ -1770,8 +1767,8 @@ PHP_METHOD(HttpRequest, getResponseCookies) if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|la!", &flags, &allowed_extras_array)) { int i = 0; - ulong idx = 0; - char *key = NULL, **allowed_extras = NULL; + HashKey key = initHashKey(0); + char **allowed_extras = NULL; zval **header = NULL, **entry = NULL, *message = GET_PROP(responseMessage); HashPosition pos, pos1, pos2; @@ -1790,8 +1787,8 @@ PHP_METHOD(HttpRequest, getResponseCookies) } } - FOREACH_HASH_KEYVAL(pos1, &msg->message->hdrs, key, idx, header) { - if (key && !strcasecmp(key, "Set-Cookie")) { + FOREACH_HASH_KEYVAL(pos1, &msg->message->hdrs, key, header) { + if (key.type == HASH_KEY_IS_STRING && !strcasecmp(key.str, "Set-Cookie")) { http_cookie_list list; if (Z_TYPE_PP(header) == IS_ARRAY) { @@ -1826,8 +1823,6 @@ PHP_METHOD(HttpRequest, getResponseCookies) zval_ptr_dtor(header); } } - /* reset key */ - key = NULL; } if (allowed_extras) { diff --git a/http_url_api.c b/http_url_api.c index 9068378..fe1d834 100644 --- a/http_url_api.c +++ b/http_url_api.c @@ -374,9 +374,7 @@ PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_ /* {{{ http_urlencode_hash_recursive */ PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, const char *arg_sep, size_t arg_sep_len, const char *prefix, size_t prefix_len TSRMLS_DC) { - char *key = NULL; - uint len = 0; - ulong idx = 0; + HashKey key = initHashKey(0); zval **data = NULL; HashPosition pos; @@ -388,7 +386,7 @@ PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, c return SUCCESS; } - FOREACH_HASH_KEYLENVAL(pos, ht, key, len, idx, data) { + FOREACH_HASH_KEYVAL(pos, ht, key, data) { char *encoded_key; int encoded_len; phpstr new_prefix; @@ -398,18 +396,17 @@ PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, c return FAILURE; } - if (key) { - if (!*key) { + if (key.type == HASH_KEY_IS_STRING) { + if (!*key.str) { /* only public properties */ continue; } - if (len && key[len - 1] == '\0') { - --len; + if (key.len && key.str[key.len - 1] == '\0') { + --key.len; } - encoded_key = php_url_encode(key, len, &encoded_len); - key = NULL; + encoded_key = php_url_encode(key.str, key.len, &encoded_len); } else { - encoded_len = spprintf(&encoded_key, 0, "%ld", idx); + encoded_len = spprintf(&encoded_key, 0, "%ld", key.num); } { diff --git a/php_http_api.h b/php_http_api.h index 2e6efca..f2c5312 100644 --- a/php_http_api.h +++ b/php_http_api.h @@ -305,6 +305,42 @@ static inline void _zval_free(zval **z) *z = NULL; } +typedef struct _HashKey { + int type; + int dup; + char *str; + uint len; + ulong num; +} HashKey; +#define initHashKey(dup) {0, (dup), NULL, 0, 0} + +#define FOREACH_VAL(pos, array, val) FOREACH_HASH_VAL(pos, Z_ARRVAL_P(array), val) +#define FOREACH_HASH_VAL(pos, hash, val) \ + for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ + zend_hash_get_current_data_ex(hash, (void *) &val, &pos) == SUCCESS; \ + zend_hash_move_forward_ex(hash, &pos)) + +#define FOREACH_KEY(pos, array, key) FOREACH_HASH_KEY(pos, Z_ARRVAL_P(array), key) +#define FOREACH_HASH_KEY(pos, hash, _key) \ + for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ + ((_key).type = zend_hash_get_current_key_ex(hash, &(_key).str, &(_key).len, &(_key).num, (_key).dup, &pos)) != HASH_KEY_NON_EXISTANT; \ + zend_hash_move_forward_ex(hash, &pos)) \ + +#define FOREACH_KEYVAL(pos, array, key, val) FOREACH_HASH_KEYVAL(pos, Z_ARRVAL_P(array), key, val) +#define FOREACH_HASH_KEYVAL(pos, hash, _key, val) \ + for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ + ((_key).type = zend_hash_get_current_key_ex(hash, &(_key).str, &(_key).len, &(_key).num, (_key).dup, &pos)) != HASH_KEY_NON_EXISTANT && \ + zend_hash_get_current_data_ex(hash, (void *) &val, &pos) == SUCCESS; \ + zend_hash_move_forward_ex(hash, &pos)) + +#define array_copy(src, dst) zend_hash_copy(dst, src, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)) +#define ARRAY_JOIN_STRONLY 1 +#define ARRAY_JOIN_PRETTIFY 2 +#define array_join(src, dst, append, flags) zend_hash_apply_with_arguments(src, (append)?apply_array_append_func:apply_array_merge_func, 2, dst, (int)flags) + +extern int apply_array_append_func(void *pDest, int num_args, va_list args, zend_hash_key *hash_key); +extern int apply_array_merge_func(void *pDest, int num_args, va_list args, zend_hash_key *hash_key); + #endif /* diff --git a/php_http_request_int.h b/php_http_request_int.h index e744964..7bf5db1 100644 --- a/php_http_request_int.h +++ b/php_http_request_int.h @@ -58,13 +58,12 @@ HTTP_CURL_OPT_STRING_EX(K+lenof("CURLOPT_KEY")+ldiff, OPTION, obdc); \ } #define HTTP_CURL_OPT_STRING_EX(keyname, optname, obdc) \ - if (!strcasecmp(key, keyname)) { \ + if (!strcasecmp(key.str, keyname)) { \ zval *copy = http_request_option_cache_ex(request, keyname, strlen(keyname)+1, 0, zval_copy(IS_STRING, *param)); \ if (obdc) { \ HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_P(copy), return FAILURE); \ } \ HTTP_CURL_OPT(optname, Z_STRVAL_P(copy)); \ - key = NULL; \ continue; \ } #define HTTP_CURL_OPT_LONG(OPTION, ldiff) \ @@ -73,10 +72,9 @@ HTTP_CURL_OPT_LONG_EX(K+lenof("CURLOPT_KEY")+ldiff, OPTION); \ } #define HTTP_CURL_OPT_LONG_EX(keyname, optname) \ - if (!strcasecmp(key, keyname)) { \ + if (!strcasecmp(key.str, keyname)) { \ zval *copy = zval_copy(IS_LONG, *param); \ HTTP_CURL_OPT(optname, Z_LVAL_P(copy)); \ - key = NULL; \ zval_free(©); \ continue; \ } diff --git a/php_http_std_defs.h b/php_http_std_defs.h index fd96018..f851983 100644 --- a/php_http_std_defs.h +++ b/php_http_std_defs.h @@ -141,72 +141,6 @@ typedef int STATUS; #define HTTP_PHP_INI_ENTRY_EX(entry, default, scope, updater, displayer, global) \ STD_PHP_INI_ENTRY_EX(entry, default, scope, updater, global, zend_http_globals, http_globals, displayer) -/* {{{ arrays */ -#define FOREACH_VAL(pos, array, val) FOREACH_HASH_VAL(pos, Z_ARRVAL_P(array), val) -#define FOREACH_HASH_VAL(pos, hash, val) \ - for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ - zend_hash_get_current_data_ex(hash, (void *) &val, &pos) == SUCCESS; \ - zend_hash_move_forward_ex(hash, &pos)) - -#define FOREACH_KEY(pos, array, strkey, numkey) FOREACH_HASH_KEY(pos, Z_ARRVAL_P(array), strkey, numkey) -#define FOREACH_HASH_KEY(pos, hash, strkey, numkey) \ - for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ - zend_hash_get_current_key_ex(hash, &strkey, NULL, &numkey, 0, &pos) != HASH_KEY_NON_EXISTANT; \ - zend_hash_move_forward_ex(hash, &pos)) \ - -#define FOREACH_KEYLEN(pos, array, strkey, keylen, numkey) FOREACH_HASH_KEYLEN(pos, Z_ARRVAL_P(array), strkey, keylen, numkey) -#define FOREACH_HASH_KEYLEN(pos, hash, strkey, keylen, numkey) \ - for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ - zend_hash_get_current_key_ex(hash, &strkey, &keylen, &numkey, 0, &pos) != HASH_KEY_NON_EXISTANT; \ - zend_hash_move_forward_ex(hash, &pos)) \ - -#define FOREACH_KEYVAL(pos, array, strkey, numkey, val) FOREACH_HASH_KEYVAL(pos, Z_ARRVAL_P(array), strkey, numkey, val) -#define FOREACH_HASH_KEYVAL(pos, hash, strkey, numkey, val) \ - for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ - zend_hash_get_current_key_ex(hash, &strkey, NULL, &numkey, 0, &pos) != HASH_KEY_NON_EXISTANT && \ - zend_hash_get_current_data_ex(hash, (void *) &val, &pos) == SUCCESS; \ - zend_hash_move_forward_ex(hash, &pos)) - -#define FOREACH_KEYLENVAL(pos, array, strkey, keylen, numkey, val) FOREACH_HASH_KEYLENVAL(pos, Z_ARRVAL_P(array), strkey, keylen, numkey, val) -#define FOREACH_HASH_KEYLENVAL(pos, hash, strkey, keylen, numkey, val) \ - for ( zend_hash_internal_pointer_reset_ex(hash, &pos); \ - zend_hash_get_current_key_ex(hash, &strkey, &keylen, &numkey, 0, &pos) != HASH_KEY_NON_EXISTANT && \ - zend_hash_get_current_data_ex(hash, (void *) &val, &pos) == SUCCESS; \ - zend_hash_move_forward_ex(hash, &pos)) - -#define array_copy(src, dst) zend_hash_copy(Z_ARRVAL_P(dst), Z_ARRVAL_P(src), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)) -#define array_merge(src, dst) zend_hash_merge(Z_ARRVAL_P(dst), Z_ARRVAL_P(src), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *), 1) -#define array_append(src, dst) \ - { \ - ulong idx; \ - uint klen; \ - char *key = NULL; \ - zval **data; \ - HashPosition pos; \ - \ - for ( zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(src), &pos); \ - zend_hash_get_current_key_ex(Z_ARRVAL_P(src), &key, &klen, &idx, 0, &pos) != HASH_KEY_NON_EXISTANT && \ - zend_hash_get_current_data_ex(Z_ARRVAL_P(src), (void *) &data, &pos) == SUCCESS; \ - zend_hash_move_forward_ex(Z_ARRVAL_P(src), &pos)) \ - { \ - if (key) { \ - zval **tmp; \ - \ - if (SUCCESS == zend_hash_find(Z_ARRVAL_P(dst), key, klen, (void *) &tmp)) { \ - if (Z_TYPE_PP(tmp) != IS_ARRAY) { \ - convert_to_array_ex(tmp); \ - } \ - ZVAL_ADDREF(*data); \ - add_next_index_zval(*tmp, *data); \ - } else { \ - ZVAL_ADDREF(*data); \ - add_assoc_zval(dst, key, *data); \ - } \ - key = NULL; \ - } \ - } \ - } -/* }}} */ #define HTTP_LONG_CONSTANT(name, const) REGISTER_LONG_CONSTANT(name, const, CONST_CS | CONST_PERSISTENT) -- 2.30.2