- finalize persistent handle support (probably)
authorMichael Wallner <mike@php.net>
Fri, 9 Feb 2007 14:19:40 +0000 (14:19 +0000)
committerMichael Wallner <mike@php.net>
Fri, 9 Feb 2007 14:19:40 +0000 (14:19 +0000)
  * make it a system ini option instead of a configure option
    = http.persistent.handles.limit controls the maximum of
      idle handles lingering around for a single provider
  * re-arrange stat() structure
  * display verbose phpinfo()

15 files changed:
config9.m4
docs/http.ini
http.c
http_api.c
http_functions.c
http_persistent_handle_api.c
http_request_api.c
http_request_datashare_api.c
http_request_object.c
http_request_pool_api.c
php_http.h
php_http_persistent_handle_api.h
php_http_request_api.h
php_http_request_pool_api.h
tests/persistent_handles_001.phpt

index 6539daf..3edb363 100644 (file)
@@ -4,9 +4,6 @@ dnl vim: noet ts=1 sw=1
 
 PHP_ARG_ENABLE([http], [whether to enable extended HTTP support],
 [  --enable-http           Enable extended HTTP support])
-PHP_ARG_ENABLE([http-persistent-handles], [whether to enable per-process persistent cURL handles],
-[  --enable-http-persistent-handles
-                           HTTP: enable per-process persistent cURL handles], "no", "no")
 PHP_ARG_WITH([http-shared-deps], [whether to depend on extensions which have been built shared],
 [  --with-http-shared-deps
                            HTTP: disable to not depend on extensions like hash,
@@ -270,14 +267,6 @@ dnl ----
                        [$CURL_LIBS -L$CURL_DIR/$PHP_LIBDIR]
                )
                
-               dnl persistent cURL handles
-               AC_MSG_CHECKING([whether to enable per-process persistent cURL handles])
-               if test "$PHP_HTTP_PERSISTENT_HANDLES" != "no"; then
-                       AC_DEFINE([HTTP_HAVE_PERSISTENT_HANDLES], [1], [Have per-process persistent cURL handles])
-                       AC_MSG_RESULT([yes])
-               else
-                       AC_MSG_RESULT([no])
-               fi
        fi
 
 dnl ----
index a7ab0f6..a32ad46 100644 (file)
@@ -54,5 +54,8 @@
 ;http.request.datashare.cookie = 0
 ;http.request.datashare.dns = 1
 
+; limit of idle persistent handles per provider
+;http.persistent.handles.limit = -1
+
 ; default ident of persistent handles
 ;http.persistent.handles.ident = "GLOBAL"
diff --git a/http.c b/http.c
index 0118e6d..2ad9644 100644 (file)
--- a/http.c
+++ b/http.c
 #include "php_http_cache_api.h"
 #include "php_http_send_api.h"
 #include "php_http_message_api.h"
+#include "php_http_persistent_handle_api.h"
 #include "php_http_request_method_api.h"
 #ifdef HTTP_HAVE_CURL
 #      include "php_http_request_api.h"
 #      include "php_http_request_pool_api.h"
 #      include "php_http_request_datashare_api.h"
-#      ifdef HTTP_HAVE_PERSISTENT_HANDLES
-#              include "php_http_persistent_handle_api.h"
-#      endif
 #endif
 #ifdef HTTP_HAVE_ZLIB
 #      include "php_http_encoding_api.h"
@@ -104,12 +102,10 @@ zend_function_entry http_functions[] = {
        PHP_FE(http_get_request_body, NULL)
        PHP_FE(http_get_request_body_stream, NULL)
        PHP_FE(http_match_request_header, NULL)
-#ifdef HTTP_HAVE_CURL
-#      ifdef HTTP_HAVE_PERSISTENT_HANDLES
        PHP_FE(http_persistent_handles_count, NULL)
        PHP_FE(http_persistent_handles_clean, NULL)
        PHP_FE(http_persistent_handles_ident, NULL)
-#      endif
+#ifdef HTTP_HAVE_CURL
        PHP_FE(http_get, http_arg_pass_ref_3)
        PHP_FE(http_head, http_arg_pass_ref_3)
        PHP_FE(http_post_data, http_arg_pass_ref_4)
@@ -240,13 +236,11 @@ PHP_INI_MH(http_update_allowed_methods)
        http_check_allowed_methods(new_value, new_value_length);
        return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
 }
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
 PHP_INI_MH(http_update_persistent_handle_ident)
 {
        HTTP_G->persistent.handles.ident.h = zend_hash_func(new_value, HTTP_G->persistent.handles.ident.l = new_value_length+1);
        return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
 }
-#endif
 
 #ifndef ZEND_ENGINE_2
 #      define OnUpdateLong OnUpdateInt
@@ -273,9 +267,8 @@ PHP_INI_BEGIN()
        HTTP_PHP_INI_ENTRY("http.send.deflate.start_auto", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, send.deflate.start_auto)
        HTTP_PHP_INI_ENTRY("http.send.deflate.start_flags", "0", PHP_INI_ALL, OnUpdateLong, send.deflate.start_flags)
 #endif
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
+       HTTP_PHP_INI_ENTRY("http.persistent.handles.limit", "-1", PHP_INI_SYSTEM, OnUpdateLong, persistent.handles.limit)
        HTTP_PHP_INI_ENTRY("http.persistent.handles.ident", "GLOBAL", PHP_INI_ALL, http_update_persistent_handle_ident, persistent.handles.ident.s)
-#endif
        HTTP_PHP_INI_ENTRY("http.send.not_found_404", "1", PHP_INI_ALL, OnUpdateBool, send.not_found_404)
 #ifdef ZEND_ENGINE_2
        HTTP_PHP_INI_ENTRY("http.only_exceptions", "0", PHP_INI_ALL, OnUpdateBool, only_exceptions)
@@ -293,19 +286,16 @@ PHP_MINIT_FUNCTION(http)
 
        REGISTER_INI_ENTRIES();
        
-       if (    (SUCCESS != PHP_MINIT_CALL(http_support))       ||
+       if (    (SUCCESS != PHP_MINIT_CALL(http_persistent_handle)) || /* first */
+                       (SUCCESS != PHP_MINIT_CALL(http_support))       ||
                        (SUCCESS != PHP_MINIT_CALL(http_cookie))        ||
                        (SUCCESS != PHP_MINIT_CALL(http_send))          ||
                        (SUCCESS != PHP_MINIT_CALL(http_url))           ||
+                       
 #ifdef HTTP_HAVE_CURL
-#      ifdef HTTP_HAVE_PERSISTENT_HANDLES
-                       (SUCCESS != PHP_MINIT_CALL(http_persistent_handle)) ||
-#              ifdef ZEND_ENGINE_2
-                       (SUCCESS != PHP_MINIT_CALL(http_request_pool)) ||
-#              endif
-#      endif
                        (SUCCESS != PHP_MINIT_CALL(http_request))       ||
 #      ifdef ZEND_ENGINE_2
+                       (SUCCESS != PHP_MINIT_CALL(http_request_pool)) ||
                        (SUCCESS != PHP_MINIT_CALL(http_request_datashare)) ||
 #      endif
 #endif /* HTTP_HAVE_CURL */
@@ -346,19 +336,17 @@ PHP_MINIT_FUNCTION(http)
 PHP_MSHUTDOWN_FUNCTION(http)
 {
        UNREGISTER_INI_ENTRIES();
-#ifdef HTTP_HAVE_CURL
        if (    
+#ifdef HTTP_HAVE_CURL
 #      ifdef ZEND_ENGINE_2
                        (SUCCESS != PHP_MSHUTDOWN_CALL(http_request_datashare)) ||
 #      endif
-                       (SUCCESS != PHP_MSHUTDOWN_CALL(http_request))
-#      ifdef HTTP_HAVE_PERSISTENT_HANDLES
-                       || (SUCCESS != PHP_MSHUTDOWN_CALL(http_persistent_handle))
-#      endif
+                       (SUCCESS != PHP_MSHUTDOWN_CALL(http_request)) ||
+#endif
+                       (SUCCESS != PHP_MSHUTDOWN_CALL(http_persistent_handle)) /* last */
        ) {
                return FAILURE;
        }
-#endif
        return SUCCESS;
 }
 /* }}} */
@@ -445,46 +433,6 @@ PHP_MINFO_FUNCTION(http)
                        "http.chunked_decode, http.chunked_encode, http.deflate, http.inflate"
 #endif
                );
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
-               {
-                       phpstr s;
-                       HashTable *ht;
-                       HashPosition pos1, pos2;
-                       HashKey key1 = initHashKey(0), key2 = initHashKey(0);
-                       zval **val1, **val2;
-                       
-                       if ((ht = http_persistent_handle_statall()) && zend_hash_num_elements(ht)) {
-                               phpstr_init(&s);
-                               
-                               FOREACH_HASH_KEYVAL(pos1, ht, key1, val1) {
-                                       phpstr_append(&s, key1.str, key1.len-1);
-                                       phpstr_appends(&s, " (");
-                                       if (zend_hash_num_elements(Z_ARRVAL_PP(val1))) {
-                                               FOREACH_KEYVAL(pos2, *val1, key2, val2) {
-                                                       phpstr_append(&s, key2.str, key2.len-1);
-                                                       phpstr_appendf(&s, ":%ld, ", Z_LVAL_PP(val2));
-                                               }
-                                               PHPSTR_LEN(&s) -= 2;
-                                       } else {
-                                               phpstr_appends(&s, "0");
-                                       }
-                                       phpstr_appends(&s, "), ");
-                               }
-                               zend_hash_destroy(ht);
-                               FREE_HASHTABLE(ht);
-                               
-                               PHPSTR_LEN(&s) -= 2; /* get rid of last ", " */
-                               phpstr_fix(&s);
-                               
-                               php_info_print_table_row(2, "Persistent Handles", PHPSTR_VAL(&s));
-                               phpstr_dtor(&s);
-                       } else {
-                               php_info_print_table_row(2, "Persistent Handles", "none");
-                       }
-               }
-#else
-               php_info_print_table_row(2, "Persistent Handles", "disabled");
-#endif
        }
        php_info_print_table_end();
        
@@ -510,6 +458,42 @@ PHP_MINFO_FUNCTION(http)
        }
        php_info_print_table_end();
        
+       php_info_print_table_start();
+       php_info_print_table_colspan_header(4, "Persistent Handles");
+       php_info_print_table_header(4, "Provider", "Ident", "used", "free");
+       {
+               HashTable *ht;
+               HashPosition pos1, pos2;
+               HashKey provider = initHashKey(0), ident = initHashKey(0);
+               zval **val, **sub, **zused, **zfree;
+               
+               if ((ht = http_persistent_handle_statall()) && zend_hash_num_elements(ht)) {
+                       FOREACH_HASH_KEYVAL(pos1, ht, provider, val) {
+                               if (zend_hash_num_elements(Z_ARRVAL_PP(val))) {
+                                       FOREACH_KEYVAL(pos2, *val, ident, sub) {
+                                               if (    SUCCESS == zend_hash_find(Z_ARRVAL_PP(sub), ZEND_STRS("used"), (void *) &zused) &&
+                                                               SUCCESS == zend_hash_find(Z_ARRVAL_PP(sub), ZEND_STRS("free"), (void *) &zfree)) {
+                                                       convert_to_string(*zused);
+                                                       convert_to_string(*zfree);
+                                                       php_info_print_table_row(4, provider.str, ident.str, Z_STRVAL_PP(zused), Z_STRVAL_PP(zfree));
+                                               } else {
+                                                       php_info_print_table_row(4, provider.str, ident.str, "0", "0");
+                                               }
+                                       }
+                               } else {
+                                       php_info_print_table_row(4, provider.str, "N/A", "0", "0");
+                               }
+                       }
+               } else {
+                       php_info_print_table_row(4, "N/A", "N/A", "0", "0");
+               }
+               if (ht) {
+                       zend_hash_destroy(ht);
+                       FREE_HASHTABLE(ht);
+               }
+       }
+       php_info_print_table_end();
+       
        php_info_print_table_start();
        php_info_print_table_colspan_header(2, "Request Methods");
        {
index 77f8df5..138b08e 100644 (file)
@@ -32,7 +32,6 @@ PHP_MINIT_FUNCTION(http_support)
        HTTP_LONG_CONSTANT("HTTP_SUPPORT_MAGICMIME", HTTP_SUPPORT_MAGICMIME);
        HTTP_LONG_CONSTANT("HTTP_SUPPORT_ENCODINGS", HTTP_SUPPORT_ENCODINGS);
        HTTP_LONG_CONSTANT("HTTP_SUPPORT_SSLREQUESTS", HTTP_SUPPORT_SSLREQUESTS);
-       HTTP_LONG_CONSTANT("HTTP_SUPPORT_PERSISTENCE", HTTP_SUPPORT_PERSISTENCE);
        
        HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_COMMA", HTTP_PARAMS_ALLOW_COMMA);
        HTTP_LONG_CONSTANT("HTTP_PARAMS_ALLOW_FAILURE", HTTP_PARAMS_ALLOW_FAILURE);
@@ -51,9 +50,6 @@ PHP_HTTP_API long _http_support(long feature)
 #      ifdef HTTP_HAVE_SSL
        support |= HTTP_SUPPORT_SSLREQUESTS;
 #      endif
-#      ifdef HTTP_HAVE_PERSISTENT_HANDLES
-       support |= HTTP_SUPPORT_PERSISTENCE;
-#      endif
 #endif
 #ifdef HTTP_HAVE_MAGIC
        support |= HTTP_SUPPORT_MAGICMIME;
index 4ddbda1..737cce8 100644 (file)
@@ -802,10 +802,6 @@ PHP_FUNCTION(http_match_request_header)
 }
 /* }}} */
 
-/* {{{ HAVE_CURL */
-#ifdef HTTP_HAVE_CURL
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
-
 /* {{{ proto object http_persistent_handles_count() */
 PHP_FUNCTION(http_persistent_handles_count)
 {
@@ -845,7 +841,8 @@ PHP_FUNCTION(http_persistent_handles_ident)
 }
 /* }}} */
 
-#endif /* HTTP_HAVE_PERSISTENT_HANDLES */
+/* {{{ HAVE_CURL */
+#ifdef HTTP_HAVE_CURL
 
 #define RETVAL_RESPONSE_OR_BODY(request) \
        { \
index b07caff..ec345fb 100644 (file)
@@ -15,7 +15,6 @@
 #include "php_http.h"
 #include "php_http_api.h"
 
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
 #include "php_http_persistent_handle_api.h"
 
 #ifndef HTTP_DEBUG_PHANDLES
@@ -36,66 +35,152 @@ typedef struct _http_persistent_handle_t {
        void *ptr;
 } http_persistent_handle;
 
-typedef HashTable *http_persistent_handle_list;
+typedef struct _http_persistent_handle_list_t {
+       HashTable free;
+       ulong used;
+} http_persistent_handle_list;
 
 typedef struct _http_persistent_handle_provider_t {
        http_persistent_handle_list list; /* "ident" => array(handles) entries */
        http_persistent_handle_ctor ctor;
        http_persistent_handle_dtor dtor;
+       http_persistent_handle_copy copy;
 } http_persistent_handle_provider;
 
-
-static inline STATUS http_persistent_handle_list_find(http_persistent_handle_list parent_list, http_persistent_handle_list **ident_list, int create TSRMLS_DC)
+static inline http_persistent_handle_list *http_persistent_handle_list_init(http_persistent_handle_list *list)
 {
-       http_persistent_handle_list new_list;
+       int free_list;
        
-       if (SUCCESS == zend_hash_quick_find(parent_list, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) ident_list)) {
-               return SUCCESS;
+       if ((free_list = !list)) {
+               list = pemalloc(sizeof(http_persistent_handle_list), 1);
        }
        
-       if (create) {
-               if ((new_list = pemalloc(sizeof(HashTable), 1))) {
-                       if (SUCCESS == zend_hash_init(new_list, 0, NULL, NULL, 1)) {
-                               if (SUCCESS == zend_hash_quick_add(parent_list, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) &new_list, sizeof(http_persistent_handle_list), (void *) ident_list)) {
-                                       return SUCCESS;
-                               }
-                               zend_hash_destroy(new_list);
-                       }
-                       pefree(new_list, 1);
+       list->used = 0;
+       
+       if (SUCCESS != zend_hash_init(&list->free, 0, NULL, NULL, 1)) {
+               if (free_list) {
+                       pefree(list, 1);
                }
+               list = NULL;
        }
        
-       return FAILURE;
+       return list;
 }
 
-static inline void http_persistent_handle_list_dtor(http_persistent_handle_list list, http_persistent_handle_dtor dtor)
+static inline void http_persistent_handle_list_dtor(http_persistent_handle_list *list, http_persistent_handle_dtor dtor)
 {
        HashPosition pos;
        http_persistent_handle *handle;
        
-       FOREACH_HASH_VAL(pos, list, handle) {
+       FOREACH_HASH_VAL(pos, &list->free, handle) {
 #if HTTP_DEBUG_PHANDLES
                fprintf(stderr, "DESTROY: %p\n", handle->ptr);
 #endif
                
                dtor(handle->ptr);
        }
-       zend_hash_clean(list);
+       zend_hash_destroy(&list->free);
+}
+
+static inline void http_persistent_handle_list_free(http_persistent_handle_list **list, http_persistent_handle_dtor dtor)
+{
+       http_persistent_handle_list_dtor(*list, dtor);
+       pefree(*list, 1);
+       *list = NULL;
+}
+
+static inline http_persistent_handle_list *http_persistent_handle_list_find(http_persistent_handle_provider *provider TSRMLS_DC)
+{
+       http_persistent_handle_list **list, *new_list;
+       
+       if (SUCCESS == zend_hash_quick_find(&provider->list.free, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) &list)) {
+               return *list;
+       }
+       
+       if ((new_list = http_persistent_handle_list_init(NULL))) {
+               if (SUCCESS == zend_hash_quick_add(&provider->list.free, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) &new_list, sizeof(http_persistent_handle_list *), (void *) &list)) {
+                       return *list;
+               }
+               http_persistent_handle_list_free(&new_list, provider->dtor);
+       }
+       
+       return NULL;
+}
+
+static inline STATUS http_persistent_handle_do_acquire(http_persistent_handle_provider *provider, void **handle_ptr TSRMLS_DC)
+{
+       ulong index;
+       http_persistent_handle *handle;
+       http_persistent_handle_list *list;
+       
+       if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) {
+               zend_hash_internal_pointer_end(&list->free);
+               if (HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(&list->free, NULL, &index, 0) && SUCCESS == zend_hash_get_current_data(&list->free, (void *) &handle)) {
+                       *handle_ptr = handle->ptr;
+                       zend_hash_index_del(&list->free, index);
+               } else {
+                       *handle_ptr = provider->ctor();
+               }
+               
+               if (*handle_ptr) {
+                       ++provider->list.used;
+                       ++list->used;
+                       return SUCCESS;
+               }
+       }
+       
+       return FAILURE;
+}
+
+static inline STATUS http_persistent_handle_do_release(http_persistent_handle_provider *provider, void **handle_ptr TSRMLS_DC)
+{
+       http_persistent_handle_list *list;
+       
+       if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) {
+               if (provider->list.used >= HTTP_G->persistent.handles.limit) {
+                       provider->dtor(*handle_ptr);
+               } else {
+                       http_persistent_handle handle = {*handle_ptr};
+                       
+                       if (SUCCESS != zend_hash_next_index_insert(&list->free, (void *) &handle, sizeof(http_persistent_handle), NULL)) {
+                               return FAILURE;
+                       }
+               }
+               
+               *handle_ptr = NULL;
+               --provider->list.used;
+               --list->used;
+               return SUCCESS;
+       }
+       
+       return FAILURE;
+}
+
+static inline STATUS http_persistent_handle_do_accrete(http_persistent_handle_provider *provider, void *old_handle, void **new_handle TSRMLS_DC)
+{
+       http_persistent_handle_list *list;
+       
+       if (provider->copy && (*new_handle = provider->copy(old_handle))) {
+               if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) {
+                       ++list->used;
+               }
+               ++provider->list.used;
+               return SUCCESS;
+       }
+       return FAILURE;
 }
 
 static void http_persistent_handles_hash_dtor(void *p)
 {
        http_persistent_handle_provider *provider = (http_persistent_handle_provider *) p;
-       http_persistent_handle_list *list;
+       http_persistent_handle_list **list;
        HashPosition pos;
        
-       FOREACH_HASH_VAL(pos, provider->list, list) {
-               http_persistent_handle_list_dtor(*list, provider->dtor);
-               zend_hash_destroy(*list);
-               pefree(*list, 1);
+       FOREACH_HASH_VAL(pos, &provider->list.free, list) {
+               http_persistent_handle_list_free(list, provider->dtor);
        }
-       zend_hash_destroy(provider->list);
-       pefree(provider->list, 1);
+       
+       zend_hash_destroy(&provider->list.free);
 }
 
 PHP_MINIT_FUNCTION(http_persistent_handle)
@@ -116,26 +201,25 @@ PHP_MSHUTDOWN_FUNCTION(http_persistent_handle)
        return SUCCESS;
 }
 
-PHP_HTTP_API STATUS _http_persistent_handle_provide_ex(const char *name_str, size_t name_len, http_persistent_handle_ctor ctor, http_persistent_handle_dtor dtor)
+PHP_HTTP_API STATUS _http_persistent_handle_provide_ex(const char *name_str, size_t name_len, http_persistent_handle_ctor ctor, http_persistent_handle_dtor dtor, http_persistent_handle_copy copy)
 {
        STATUS status = FAILURE;
        http_persistent_handle_provider provider;
        
        LOCK();
-       provider.list = pemalloc(sizeof(HashTable), 1);
-       if (provider.list) {
+       if (http_persistent_handle_list_init(&provider.list)) {
                provider.ctor = ctor;
                provider.dtor = dtor;
-               zend_hash_init(provider.list, 0, NULL, NULL, 1);
+               provider.copy = copy;
                
 #if HTTP_DEBUG_PHANDLES
-               fprintf(stderr, "PROVIDE: %p (%s)\n", provider.list, name_str);
+               fprintf(stderr, "PROVIDE: %s\n", name_str);
 #endif
                
                if (SUCCESS == zend_hash_add(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider, sizeof(http_persistent_handle_provider), NULL)) {
                        status = SUCCESS;
                } else {
-                       pefree(provider.list, 1);
+                       http_persistent_handle_list_dtor(&provider.list, dtor);
                }
        }
        UNLOCK();
@@ -146,24 +230,12 @@ PHP_HTTP_API STATUS _http_persistent_handle_provide_ex(const char *name_str, siz
 PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle_ptr TSRMLS_DC)
 {
        STATUS status = FAILURE;
-       ulong index;
        http_persistent_handle_provider *provider;
-       http_persistent_handle_list *list;
-       http_persistent_handle *handle;
        
        *handle_ptr = NULL;
        LOCK();
        if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) {
-               if (SUCCESS == http_persistent_handle_list_find(provider->list, &list, 0 TSRMLS_CC)) {
-                       zend_hash_internal_pointer_end(*list);
-                       if (HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(*list, NULL, &index, 0) && SUCCESS == zend_hash_get_current_data(*list, (void *) &handle)) {
-                               *handle_ptr = handle->ptr;
-                               zend_hash_index_del(*list, index);
-                       }
-               }
-               if (*handle_ptr || (*handle_ptr = provider->ctor())) {
-                       status = SUCCESS;
-               }
+               status = http_persistent_handle_do_acquire(provider, handle_ptr TSRMLS_CC);
        }
        UNLOCK();
        
@@ -178,15 +250,10 @@ PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, siz
 {
        STATUS status = FAILURE;
        http_persistent_handle_provider *provider;
-       http_persistent_handle_list *list;
-       http_persistent_handle handle = {*handle_ptr};
        
        LOCK();
        if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) {
-               if (    SUCCESS == http_persistent_handle_list_find(provider->list, &list, 1 TSRMLS_CC) &&
-                               SUCCESS == zend_hash_next_index_insert(*list, (void *) &handle, sizeof(http_persistent_handle), NULL)) {
-                       status = SUCCESS;
-               }
+               status = http_persistent_handle_do_release(provider, handle_ptr TSRMLS_CC);
        }
        UNLOCK();
        
@@ -196,35 +263,58 @@ PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, siz
        
        return status;
 }
+
+PHP_HTTP_API STATUS _http_persistent_handle_accrete_ex(const char *name_str, size_t name_len, void *old_handle, void **new_handle TSRMLS_DC)
+{
+       STATUS status = FAILURE;
+       http_persistent_handle_provider *provider;
+       
+       *new_handle = NULL;
+       LOCK();
+       if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) {
+               status = http_persistent_handle_do_accrete(provider, old_handle, new_handle TSRMLS_CC);
+       }
+       UNLOCK();
+       
+#if HTTP_DEBUG_PHANDLES
+       fprintf(stderr, "ACCRETE: %p > %p (%s)\n", old_handle, *new_handle, name_str);
+#endif
        
+       return status;
+}
+
 PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len, int current_ident_only TSRMLS_DC)
 {
        http_persistent_handle_provider *provider;
-       http_persistent_handle_list *list;
+       http_persistent_handle_list *list, **listp;
        HashPosition pos1, pos2;
        
        LOCK();
        if (name_str && name_len) {
                if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) {
                        if (current_ident_only) {
-                               if (SUCCESS == http_persistent_handle_list_find(provider->list, &list, 0 TSRMLS_CC)) {
-                                       http_persistent_handle_list_dtor(*list, provider->dtor);
+                               if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) {
+                                       http_persistent_handle_list_dtor(list, provider->dtor);
+                                       http_persistent_handle_list_init(list);
                                }
                        } else {
-                               FOREACH_HASH_VAL(pos1, provider->list, list) {
-                                       http_persistent_handle_list_dtor(*list, provider->dtor);
+                               FOREACH_HASH_VAL(pos1, &provider->list.free, listp) {
+                                       http_persistent_handle_list_dtor(*listp, provider->dtor);
+                                       http_persistent_handle_list_init(*listp);
                                }
                        }
                }
        } else {
                FOREACH_HASH_VAL(pos1, &http_persistent_handles_hash, provider) {
                        if (current_ident_only) {
-                               if (SUCCESS == http_persistent_handle_list_find(provider->list, &list, 0 TSRMLS_CC)) {
-                                       http_persistent_handle_list_dtor(*list, provider->dtor);
+                               if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) {
+                                       http_persistent_handle_list_dtor(list, provider->dtor);
+                                       http_persistent_handle_list_init(list);
                                }
                        } else {
-                               FOREACH_HASH_VAL(pos2, provider->list, list) {
-                                       http_persistent_handle_list_dtor(*list, provider->dtor);
+                               FOREACH_HASH_VAL(pos2, &provider->list.free, listp) {
+                                       http_persistent_handle_list_dtor(*listp, provider->dtor);
+                                       http_persistent_handle_list_init(*listp);
                                }
                        }
                }
@@ -232,13 +322,13 @@ PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_
        UNLOCK();
 }
 
-PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht)
+PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht TSRMLS_DC)
 {
-       zval *zlist, *zentry;
+       zval *zentry[2];
        HashPosition pos1, pos2;
        HashKey key1 = initHashKey(0), key2 = initHashKey(0);
        http_persistent_handle_provider *provider;
-       http_persistent_handle_list *list;
+       http_persistent_handle_list **list;
        
        LOCK();
        if (zend_hash_num_elements(&http_persistent_handles_hash)) {
@@ -248,14 +338,20 @@ PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht)
                }
                
                FOREACH_HASH_KEYVAL(pos1, &http_persistent_handles_hash, key1, provider) {
-                       MAKE_STD_ZVAL(zlist);
-                       array_init(zlist);
-                       FOREACH_HASH_KEYVAL(pos2, provider->list, key2, list) {
-                               MAKE_STD_ZVAL(zentry);
-                               ZVAL_LONG(zentry, zend_hash_num_elements(*list));
-                               zend_hash_add(Z_ARRVAL_P(zlist), key2.str, key2.len, (void *) &zentry, sizeof(zval *), NULL);
+                       MAKE_STD_ZVAL(zentry[0]);
+                       array_init(zentry[0]);
+                       
+                       FOREACH_HASH_KEYVAL(pos2, &provider->list.free, key2, list) {
+                               MAKE_STD_ZVAL(zentry[1]);
+                               array_init(zentry[1]);
+                               add_assoc_long_ex(zentry[1], ZEND_STRS("used"), (*list)->used);
+                               add_assoc_long_ex(zentry[1], ZEND_STRS("free"), zend_hash_num_elements(&(*list)->free));
+                               
+                               /* use zend_hash_* not add_assoc_* (which is zend_symtable_*) as we want a string even for numbers */
+                               zend_hash_add(Z_ARRVAL_P(zentry[0]), key2.str, key2.len, &zentry[1], sizeof(zval *), NULL);
                        }
-                       zend_hash_add(ht, key1.str, key1.len, (void *) &zlist, sizeof(zval *), NULL);
+                       
+                       zend_hash_add(ht, key1.str, key1.len, &zentry[0], sizeof(zval *), NULL);
                }
        } else if (ht) {
                ht = NULL;
@@ -265,7 +361,6 @@ PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht)
        return ht;
 }
 
-#endif /* HTTP_HAVE_PERSISTENT_HANDLES */
 
 /*
  * Local variables:
index 3396dba..e574eee 100644 (file)
 #ifdef HTTP_HAVE_CURL
 
 #include "php_http_api.h"
+#include "php_http_persistent_handle_api.h"
 #include "php_http_request_api.h"
 #include "php_http_url_api.h"
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
-#      include "php_http_persistent_handle_api.h"
-#endif
 
 #ifdef ZEND_ENGINE_2
 #      include "php_http_request_object.h"
@@ -112,11 +110,9 @@ PHP_MINIT_FUNCTION(http_request)
                return FAILURE;
        }
        
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
-       if (SUCCESS != http_persistent_handle_provide("http_request", curl_easy_init, curl_easy_cleanup)) {
+       if (SUCCESS != http_persistent_handle_provide("http_request", curl_easy_init, curl_easy_cleanup, curl_easy_duphandle)) {
                return FAILURE;
        }
-#endif
        
        HTTP_LONG_CONSTANT("HTTP_AUTH_BASIC", CURLAUTH_BASIC);
        HTTP_LONG_CONSTANT("HTTP_AUTH_DIGEST", CURLAUTH_DIGEST);
@@ -185,18 +181,10 @@ static int http_curl_dummy_callback(char *data, size_t n, size_t l, void *s) { r
 static curlioerr http_curl_ioctl_callback(CURL *, curliocmd, void *);
 /* }}} */
 
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
-#      define HTTP_CURL_HANDLE_CTOR(ch) (SUCCESS == http_persistent_handle_acquire("http_request", &(ch)))
-#      define HTTP_CURL_HANDLE_DTOR(chp) http_persistent_handle_release("http_request", (chp))
-#else
-#      define HTTP_CURL_HANDLE_CTOR(ch) ((ch) = curl_easy_init())
-#      define HTTP_CURL_HANDLE_DTOR(chp) curl_easy_cleanup(*(chp)); *(chp) = NULL
-#endif
-
 /* {{{ CURL *http_curl_init(http_request *) */
 PHP_HTTP_API CURL * _http_curl_init_ex(CURL *ch, http_request *request TSRMLS_DC)
 {
-       if (ch || HTTP_CURL_HANDLE_CTOR(ch)) {
+       if (ch || (SUCCESS == http_persistent_handle_acquire("http_request", &ch))) {
 #if defined(ZTS)
                curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L);
 #endif
@@ -227,6 +215,18 @@ PHP_HTTP_API CURL * _http_curl_init_ex(CURL *ch, http_request *request TSRMLS_DC
 }
 /* }}} */
 
+/* {{{ CURL *http_curl_copy(CURL *) */
+PHP_HTTP_API CURL *_http_curl_copy(CURL *ch TSRMLS_DC)
+{
+       CURL *copy;
+       
+       if (SUCCESS == http_persistent_handle_accrete("http_request", ch, &copy)) {
+               return copy;
+       }
+       return NULL;
+}
+/* }}} */
+
 /* {{{ void http_curl_free(CURL **) */
 PHP_HTTP_API void _http_curl_free(CURL **ch TSRMLS_DC)
 {
@@ -236,7 +236,7 @@ PHP_HTTP_API void _http_curl_free(CURL **ch TSRMLS_DC)
                curl_easy_setopt(*ch, CURLOPT_VERBOSE, 0L);
                curl_easy_setopt(*ch, CURLOPT_DEBUGFUNCTION, NULL);
                
-               HTTP_CURL_HANDLE_DTOR(ch);
+               http_persistent_handle_release("http_request", ch);
        }
 }
 /* }}} */
index 02c40b4..d86ef88 100644 (file)
 #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
 
 #include "php_http_api.h"
+#include "php_http_persistent_handle_api.h"
 #include "php_http_request_datashare_api.h"
 #include "php_http_request_api.h"
 #include "php_http_request_object.h"
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
-#      include "php_http_persistent_handle_api.h"
-#endif
-
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
-#      define HTTP_CURL_SHARE_CTOR(ch) (SUCCESS == http_persistent_handle_acquire("http_request_datashare", &(ch)))
-#      define HTTP_CURL_SHARE_DTOR(chp) http_persistent_handle_release("http_request_datashare", (chp))
-#      define HTTP_CURL_SLOCK_CTOR(l) (SUCCESS == http_persistent_handle_acquire("http_request_datashare_lock", (void *) &(l)))
-#      define HTTP_CURL_SLOCK_DTOR(lp) http_persistent_handle_release("http_request_datashare_lock", (void *) (lp))
-#else
-#      define HTTP_CURL_SHARE_CTOR(ch) ((ch) = curl_share_init())
-#      define HTTP_CURL_SHARE_DTOR(chp) curl_share_cleanup(*(chp)); *(chp) = NULL
-#      define HTTP_CURL_SLOCK_CTOR(l) ((l) = http_request_datashare_locks_init())
-#      define HTTP_CURL_SLOCK_DTOR(lp) http_request_datashare_locks_dtor(*(lp)); *(lp) = NULL
-#endif
 
 static HashTable http_request_datashare_options;
 static http_request_datashare http_request_datashare_global;
@@ -57,15 +43,13 @@ PHP_MINIT_FUNCTION(http_request_datashare)
 {
        curl_lock_data val;
        
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
-       if (SUCCESS != http_persistent_handle_provide("http_request_datashare", curl_share_init, (http_persistent_handle_dtor) curl_share_cleanup)) {
+       if (SUCCESS != http_persistent_handle_provide("http_request_datashare", curl_share_init, (http_persistent_handle_dtor) curl_share_cleanup, NULL)) {
                return FAILURE;
        }
-#      ifdef ZTS
-       if (SUCCESS != http_persistent_handle_provide("http_request_datashare_lock", http_request_datashare_locks_init, http_request_datashare_locks_dtor)) {
+#ifdef ZTS
+       if (SUCCESS != http_persistent_handle_provide("http_request_datashare_lock", http_request_datashare_locks_init, http_request_datashare_locks_dtor, NULL)) {
                return FAILURE;
        }
-#      endif
 #endif
        
        if (!http_request_datashare_init_ex(&http_request_datashare_global, 1)) {
@@ -115,7 +99,7 @@ PHP_HTTP_API http_request_datashare *_http_request_datashare_init_ex(http_reques
        }
        memset(share, 0, sizeof(http_request_datashare));
        
-       if (!HTTP_CURL_SHARE_CTOR(share->ch)) {
+       if (SUCCESS != http_persistent_handle_acquire("http_request_datashare", &share->ch)) {
                if (free_share) {
                        pefree(share, persistent);
                }
@@ -127,10 +111,10 @@ PHP_HTTP_API http_request_datashare *_http_request_datashare_init_ex(http_reques
                zend_llist_init(share->handle.list, sizeof(zval *), ZVAL_PTR_DTOR, 0);
 #ifdef ZTS
        } else {
-               if (HTTP_CURL_SLOCK_CTOR(share->handle.locks)) {
+               if (SUCCESS == http_persistent_handle_acquire("http_request_datashare_lock", (void *) &share->handle.locks)) {
                        curl_share_setopt(share->ch, CURLSHOPT_LOCKFUNC, http_request_datashare_lock_func);
                        curl_share_setopt(share->ch, CURLSHOPT_UNLOCKFUNC, http_request_datashare_unlock_func);
-                       curl_share_setopt(share->ch, CURLSHOPT_USERDATA, share);
+                       curl_share_setopt(share->ch, CURLSHOPT_USERDATA, share->handle.locks);
                }
 #endif
        }
@@ -198,10 +182,10 @@ PHP_HTTP_API void _http_request_datashare_dtor(http_request_datashare *share TSR
                zend_llist_destroy(share->handle.list);
                efree(share->handle.list);
        }
-       HTTP_CURL_SHARE_DTOR(&share->ch);
+       http_persistent_handle_release("http_request_datashare", &share->ch);
 #ifdef ZTS
        if (share->persistent) {
-               HTTP_CURL_SLOCK_DTOR(&share->handle.locks);
+               http_persistent_handle_release("http_request_datashare_lock", (void *) &share->handle.locks);
        }
 #endif
 }
@@ -273,19 +257,19 @@ static void http_request_datashare_locks_dtor(void *l)
 
 static void http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr)
 {
-       http_request_datashare *share = (http_request_datashare *) userptr;
+       http_request_datashare_lock *locks = (http_request_datashare_lock *) userptr;
        
        /* TSRM can't distinguish shared/exclusive locks */
-       tsrm_mutex_lock(share->handle.locks[data].mx);
-       share->handle.locks[data].ch = handle;
+       tsrm_mutex_lock(locks[data].mx);
+       locks[data].ch = handle;
 }
 
 static void http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr)
 {
-       http_request_datashare *share = (http_request_datashare *) userptr;
+       http_request_datashare_lock *locks = (http_request_datashare_lock *) userptr;
        
-       if (share->handle.locks[data].ch == handle) {
-               tsrm_mutex_unlock(share->handle.locks[data].mx);
+       if (locks[data].ch == handle) {
+               tsrm_mutex_unlock(locks[data].mx);
        }
 }
 #endif
index a380125..49e9103 100644 (file)
@@ -484,7 +484,7 @@ zend_object_value _http_request_object_clone_obj(zval *this_ptr TSRMLS_DC)
        
        new_ov = http_request_object_new_ex(old_obj->zo.ce, NULL, &new_obj);
        if (old_obj->request->ch) {
-               http_curl_init_ex(curl_easy_duphandle(old_obj->request->ch), new_obj->request);
+               http_curl_init_ex(http_curl_copy(old_obj->request->ch), new_obj->request);
        }
        
        zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
index 1c263af..27e1f0d 100644 (file)
 
 #include "php_http_api.h"
 #include "php_http_exception_object.h"
+#include "php_http_persistent_handle_api.h"
 #include "php_http_request_api.h"
 #include "php_http_request_object.h"
 #include "php_http_request_pool_api.h"
 #include "php_http_requestpool_object.h"
-#include "php_http_persistent_handle_api.h"
 
 #ifndef HTTP_DEBUG_REQPOOLS
 #      define HTTP_DEBUG_REQPOOLS 0
 #endif
 
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
-#      define HTTP_CURL_MULTI_CTOR(ch) (SUCCESS == http_persistent_handle_acquire("http_request_pool", &(ch)))
-#      define HTTP_CURL_MULTI_DTOR(chp) http_persistent_handle_release("http_request_pool", (chp))
-#else
-#      define HTTP_CURL_MULTI_CTOR(ch) ((ch) = curl_multi_init())
-#      define HTTP_CURL_MULTI_DTOR(chp) curl_multi_cleanup(*(chp)); *(chp) = NULL
-#endif
-
 static int http_request_pool_compare_handles(void *h1, void *h2);
 
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
 PHP_MINIT_FUNCTION(http_request_pool)
 {
-       if (SUCCESS != http_persistent_handle_provide("http_request_pool", curl_multi_init, (http_persistent_handle_dtor) curl_multi_cleanup)) {
+       if (SUCCESS != http_persistent_handle_provide("http_request_pool", curl_multi_init, (http_persistent_handle_dtor) curl_multi_cleanup, NULL)) {
                return FAILURE;
        }
        return SUCCESS;
 }
-#endif
 
 /* {{{ http_request_pool *http_request_pool_init(http_request_pool *) */
 PHP_HTTP_API http_request_pool *_http_request_pool_init(http_request_pool *pool TSRMLS_DC)
@@ -63,7 +53,7 @@ PHP_HTTP_API http_request_pool *_http_request_pool_init(http_request_pool *pool
                pool->ch = NULL;
        }
 
-       if (!HTTP_CURL_MULTI_CTOR(pool->ch)) {
+       if (SUCCESS != http_persistent_handle_acquire("http_request_pool", &pool->ch)) {
                if (free_pool) {
                        efree(pool);
                }
@@ -259,7 +249,7 @@ PHP_HTTP_API void _http_request_pool_dtor(http_request_pool *pool TSRMLS_DC)
        pool->unfinished = 0;
        zend_llist_clean(&pool->finished);
        zend_llist_clean(&pool->handles);
-       HTTP_CURL_MULTI_DTOR(&pool->ch);
+       http_persistent_handle_release("http_request_pool", &pool->ch);
 }
 /* }}} */
 
index 005498b..44ef1f9 100644 (file)
@@ -138,9 +138,9 @@ ZEND_BEGIN_MODULE_GLOBALS(http)
 #endif
        } request;
 
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
        struct _http_globals_persistent {
                struct _http_globals_persistent_handles {
+                       ulong limit;
                        struct _http_globals_persistent_handles_ident {
                                ulong h;
                                char *s;
@@ -148,7 +148,7 @@ ZEND_BEGIN_MODULE_GLOBALS(http)
                        } ident;
                } handles;
        } persistent;
-#endif
+
 #ifdef ZEND_ENGINE_2
        zend_bool only_exceptions;
 #endif
@@ -213,12 +213,10 @@ PHP_FUNCTION(http_get_request_headers);
 PHP_FUNCTION(http_get_request_body);
 PHP_FUNCTION(http_get_request_body_stream);
 PHP_FUNCTION(http_match_request_header);
-#ifdef HTTP_HAVE_CURL
-#      ifdef HTTP_HAVE_PERSISTENT_HANDLES
 PHP_FUNCTION(http_persistent_handles_count);
 PHP_FUNCTION(http_persistent_handles_clean);
 PHP_FUNCTION(http_persistent_handles_ident);
-#      endif
+#ifdef HTTP_HAVE_CURL
 PHP_FUNCTION(http_get);
 PHP_FUNCTION(http_head);
 PHP_FUNCTION(http_post_data);
index fc5507c..8e00a0e 100644 (file)
 #ifndef HTTP_PERSISTENT_HANDLE_H
 #define HTTP_PERSISTENT_HANDLE_H
 
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
 typedef void *(*http_persistent_handle_ctor)(void);
 typedef void (*http_persistent_handle_dtor)(void *handle);
+typedef void *(*http_persistent_handle_copy)(void *handle);
 
 PHP_MINIT_FUNCTION(http_persistent_handle);
 PHP_MSHUTDOWN_FUNCTION(http_persistent_handle);
 
-#define http_persistent_handle_provide(n, c, d) _http_persistent_handle_provide_ex((n), strlen(n), (c), (d))
-#define http_persistent_handle_provide_ex(n, l, c, d) _http_persistent_handle_provide_ex((n), (l), (c), (d))
-PHP_HTTP_API STATUS _http_persistent_handle_provide_ex(const char *name_str, size_t name_len, http_persistent_handle_ctor ctor, http_persistent_handle_dtor dtor);
+#define http_persistent_handle_provide(n, c, d, cc) _http_persistent_handle_provide_ex((n), strlen(n), (c), (d), (cc))
+#define http_persistent_handle_provide_ex(n, l, c, d, cc) _http_persistent_handle_provide_ex((n), (l), (c), (d), (cc))
+PHP_HTTP_API STATUS _http_persistent_handle_provide_ex(const char *name_str, size_t name_len, http_persistent_handle_ctor ctor, http_persistent_handle_dtor dtor, http_persistent_handle_copy copy);
 
 #define http_persistent_handle_cleanup(n, c) _http_persistent_handle_cleanup_ex((n), strlen(n), (c) TSRMLS_CC)
 #define http_persistent_handle_cleanup_ex(n, l,c ) _http_persistent_handle_cleanup_ex((n), (l), (c) TSRMLS_CC)
 PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len, int current_ident_only TSRMLS_DC);
 
-#define http_persistent_handle_statall() _http_persistent_handle_statall_ex(NULL)
-#define http_persistent_handle_statall_ex(ht) _http_persistent_handle_statall_ex((ht))
-PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht);
+#define http_persistent_handle_statall() _http_persistent_handle_statall_ex(NULL TSRMLS_CC)
+#define http_persistent_handle_statall_ex(ht) _http_persistent_handle_statall_ex((ht) TSRMLS_CC)
+PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht TSRMLS_DC);
 
 #define http_persistent_handle_acquire(n, h) _http_persistent_handle_acquire_ex((n), strlen(n), (h) TSRMLS_CC)
 #define http_persistent_handle_acquire_ex(n, l, h) _http_persistent_handle_acquire_ex((n), (l), (h) TSRMLS_CC)
@@ -42,7 +42,10 @@ PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, siz
 #define http_persistent_handle_release_ex(n, l, h) _http_persistent_handle_release_ex((n), (l), (h) TSRMLS_CC)
 PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle TSRMLS_DC);
 
-#endif /* HTTP_HAVE_PERSISTENT_HANDLES */
+#define http_persistent_handle_accrete(n, oh, nh) _http_persistent_handle_accrete_ex((n), strlen(n), (oh), (nh) TSRMLS_CC)
+#define http_persistent_handle_accrete_ex(n, l, oh, nh) _http_persistent_handle_accrete_ex((n), (l), (oh), (nh) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_persistent_handle_accrete_ex(const char *name_str, size_t name_len, void *old_handle, void **new_handle TSRMLS_DC);
+
 #endif /* HTTP_PERSISTENT_HANDLE_H */
 
 /*
index dfc50f6..65d62e1 100644 (file)
@@ -59,6 +59,9 @@ PHP_HTTP_API CURL *_http_curl_init_ex(CURL *ch, http_request *request TSRMLS_DC)
 #define http_curl_free(c) _http_curl_free((c) TSRMLS_CC)
 PHP_HTTP_API void _http_curl_free(CURL **ch TSRMLS_DC);
 
+#define http_curl_copy(c) _http_curl_copy((c) TSRMLS_CC)
+PHP_HTTP_API CURL *_http_curl_copy(CURL *ch TSRMLS_DC);
+
 #define http_request_new() _http_request_init_ex(NULL, NULL, 0, NULL ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
 #define http_request_init(r) _http_request_init_ex((r), NULL, 0, NULL ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
 #define http_request_init_ex(r, c, m, u) _http_request_init_ex((r), (c), (m), (u) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC TSRMLS_CC)
index 4523b49..34294a9 100644 (file)
@@ -26,9 +26,7 @@ typedef struct _http_request_pool_t {
 typedef int (*http_request_pool_apply_func)(http_request_pool *pool, zval *request TSRMLS_DC);
 typedef int (*http_request_pool_apply_with_arg_func)(http_request_pool *pool, zval *request, void *arg TSRMLS_DC);
 
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
 PHP_MINIT_FUNCTION(http_request_pool);
-#endif
 
 #define http_request_pool_responsehandler(p, r, c) _http_request_pool_responsehandler((p), (r), (c) TSRMLS_CC)
 extern int _http_request_pool_responsehandler(http_request_pool *pool, zval *req, void *ch TSRMLS_DC);
index f5a6309..45332d9 100644 (file)
@@ -3,65 +3,88 @@ persistent handles
 --SKIPIF--
 <?php
 include 'skip.inc';
-skipif(!defined("HTTP_SUPPORT_PERSISTENCE") || !http_support(HTTP_SUPPORT_PERSISTENCE), "need persistent handle support");
+skipif(!http_support(HTTP_SUPPORT_REQUESTS), "need request support");
 ?>
 --INI--
+http.persistent.handles.limit=-1
 http.persistent.handles.ident=GLOBAL
 --FILE--
 <?php
 echo "-TEST\n";
 
-echo "No free handles:\n";
-var_dump(http_persistent_handles_count());
+echo "No free handles!\n";
+foreach (http_persistent_handles_count() as $provider => $idents) {
+       foreach ((array)$idents as $ident => $counts) {
+               if (!empty($counts["free"])) {
+                       printf("%s, %s, %s\n", $provider, $ident, $counts["free"]);
+               }
+       }
+}
+
 http_get("http://www.google.com/", null, $info[]);
-echo "One free request handle within GLOBAL:\n";
-var_dump(http_persistent_handles_count()->http_request["GLOBAL"]);
-echo "Reusing request handle:\n";
+
+echo "One free request handle within GLOBAL: ";
+var_dump(http_persistent_handles_count()->http_request["GLOBAL"]["free"]);
+
+echo "Reusing request handle: ";
 http_get("http://www.google.com/", null, $info[]);
-var_dump($info[0]["pretransfer_time"] > 100 * $info[1]["pretransfer_time"], $info[0]["pretransfer_time"], $info[1]["pretransfer_time"]);
+var_dump($info[0]["pretransfer_time"] > 10 * $info[1]["pretransfer_time"], $info[0]["pretransfer_time"], $info[1]["pretransfer_time"]);
+
 echo "Handles' been cleaned up:\n";
-#http_persistent_handles_clean();
-var_dump(http_persistent_handles_count());
+http_persistent_handles_clean();
+print_r(http_persistent_handles_count());
+
 echo "Done\n";
 ?>
 --EXPECTF--
 %sTEST
-No free handles:
-object(stdClass)#%d (%d) {
-  ["http_request_pool"]=>
-  array(0) {
-  }
-  ["http_request"]=>
-  array(0) {
-  }
-  ["http_request_datashare"]=>
-  array(0) {
-  }
-  ["http_request_datashare_lock"]=>
-  array(0) {
-  }
-}
-One free request handle within GLOBAL:
-int(1)
-Reusing request handle:
-bool(true)
+No free handles!
+One free request handle within GLOBAL: int(1)
+Reusing request handle: bool(true)
 float(%f)
 float(%f)
 Handles' been cleaned up:
-object(stdClass)#%d (%d) {
-  ["http_request_pool"]=>
-  array(0) {
-  }
-  ["http_request"]=>
-  array(1) {
-    ["GLOBAL"]=>
-    int(1)
-  }
-  ["http_request_datashare"]=>
-  array(0) {
-  }
-  ["http_request_datashare_lock"]=>
-  array(0) {
-  }
-}
+stdClass Object
+(
+    [http_request] => Array
+        (
+            [GLOBAL] => Array
+                (
+                    [used] => 0
+                    [free] => 0
+                )
+
+        )
+
+    [http_request_pool] => Array
+        (
+            [GLOBAL] => Array
+                (
+                    [used] => 0
+                    [free] => 0
+                )
+
+        )
+
+    [http_request_datashare] => Array
+        (
+            [GLOBAL] => Array
+                (
+                    [used] => 0
+                    [free] => 0
+                )
+
+        )
+
+    [http_request_datashare_lock] => Array
+        (
+            [GLOBAL] => Array
+                (
+                    [used] => 0
+                    [free] => 0
+                )
+
+        )
+
+)
 Done