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,
[$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 ----
;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"
#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"
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)
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
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)
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 */
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;
}
/* }}} */
"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();
}
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");
{
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);
# 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;
}
/* }}} */
-/* {{{ HAVE_CURL */
-#ifdef HTTP_HAVE_CURL
-#ifdef HTTP_HAVE_PERSISTENT_HANDLES
-
/* {{{ proto object http_persistent_handles_count() */
PHP_FUNCTION(http_persistent_handles_count)
{
}
/* }}} */
-#endif /* HTTP_HAVE_PERSISTENT_HANDLES */
+/* {{{ HAVE_CURL */
+#ifdef HTTP_HAVE_CURL
#define RETVAL_RESPONSE_OR_BODY(request) \
{ \
#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
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)
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();
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();
{
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();
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);
}
}
}
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)) {
}
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;
return ht;
}
-#endif /* HTTP_HAVE_PERSISTENT_HANDLES */
/*
* Local variables:
#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"
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);
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
}
/* }}} */
+/* {{{ 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, ©)) {
+ return copy;
+ }
+ return NULL;
+}
+/* }}} */
+
/* {{{ void http_curl_free(CURL **) */
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);
}
}
/* }}} */
#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;
{
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)) {
}
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);
}
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
}
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
}
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
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);
#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)
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);
}
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);
}
/* }}} */
#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;
} ident;
} handles;
} persistent;
-#endif
+
#ifdef ZEND_ENGINE_2
zend_bool only_exceptions;
#endif
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);
#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)
#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 */
/*
#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)
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);
--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