From: Michael Wallner Date: Sat, 27 Jan 2007 13:34:47 +0000 (+0000) Subject: - add persistent cURL handle support X-Git-Tag: RELEASE_1_5_0_RC1~22 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=commitdiff_plain;h=fa6e9a361695e1c273266c79d0d27ff19059bb8a - add persistent cURL handle support --- diff --git a/config9.m4 b/config9.m4 index 9a0cda3..6539daf 100644 --- a/config9.m4 +++ b/config9.m4 @@ -4,6 +4,13 @@ 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, + iconv and session (when built shared)], $PHP_HTTP, $PHP_HTTP) PHP_ARG_WITH([http-curl-requests], [whether to enable cURL HTTP request support], [ --with-http-curl-requests[=LIBCURLDIR] HTTP: with cURL request support], $PHP_HTTP, $PHP_HTTP) @@ -13,9 +20,6 @@ PHP_ARG_WITH([http-zlib-compression], [whether to enable zlib encodings support] PHP_ARG_WITH([http-magic-mime], [whether to enable response content type guessing], [ --with-http-magic-mime[=LIBMAGICDIR] HTTP: with magic mime response content type guessing], "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, - iconv and session (when built shared)], $PHP_HTTP, $PHP_HTTP) if test "$PHP_HTTP" != "no"; then @@ -265,6 +269,15 @@ dnl ---- [AC_DEFINE([HAVE_CURL_MULTI_TIMEOUT], [1], [ ])], [ ], [$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 ---- @@ -338,7 +351,8 @@ dnl ---- http_info_api.c http_request_method_api.c http_encoding_api.c \ http_filter_api.c http_request_body_api.c http_querystring_object.c \ http_deflatestream_object.c http_inflatestream_object.c http_cookie_api.c \ - http_querystring_api.c http_request_datashare_api.c http_requestdatashare_object.c" + http_querystring_api.c http_request_datashare_api.c http_requestdatashare_object.c \ + http_persistent_handle_api.c" PHP_NEW_EXTENSION([http], $PHP_HTTP_SOURCES, $ext_shared) @@ -357,7 +371,8 @@ dnl ---- php_http_exception_object.h php_http_message_object.h php_http_request_object.h \ php_http_requestpool_object.h php_http_response_object.h php_http_util_object.h \ php_http_querystring_object.h php_http_deflatestream_object.h php_http_inflatestream_object.h \ - php_http_cookie_api.h php_http_querystring_api.h php_http_request_datashare_api.h php_http_requestdatashare_object.h" + php_http_cookie_api.h php_http_querystring_api.h php_http_request_datashare_api.h php_http_requestdatashare_object.h \ + php_http_persistent_handle_api.h" ifdef([PHP_INSTALL_HEADERS], [ PHP_INSTALL_HEADERS(ext/http, $PHP_HTTP_HEADERS) ], [ diff --git a/http.c b/http.c index 521f2b5..eccffd8 100644 --- a/http.c +++ b/http.c @@ -32,6 +32,9 @@ #ifdef HTTP_HAVE_CURL # include "php_http_request_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" @@ -101,6 +104,10 @@ zend_function_entry http_functions[] = { 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) +# endif 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) @@ -280,6 +287,9 @@ PHP_MINIT_FUNCTION(http) (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)) || +# endif (SUCCESS != PHP_MINIT_CALL(http_request)) || # ifdef ZEND_ENGINE_2 (SUCCESS != PHP_MINIT_CALL(http_request_datashare)) || @@ -327,7 +337,11 @@ PHP_MSHUTDOWN_FUNCTION(http) # ifdef ZEND_ENGINE_2 (SUCCESS != PHP_MSHUTDOWN_CALL(http_request_datashare)) || # endif - (SUCCESS != PHP_MSHUTDOWN_CALL(http_request))) { + (SUCCESS != PHP_MSHUTDOWN_CALL(http_request)) +# ifdef HTTP_HAVE_PERSISTENT_HANDLES + || (SUCCESS != PHP_MSHUTDOWN_CALL(http_persistent_handle)) +# endif + ) { return FAILURE; } #endif diff --git a/http_functions.c b/http_functions.c index c156c8a..c4e358d 100644 --- a/http_functions.c +++ b/http_functions.c @@ -34,6 +34,7 @@ #include "php_http_message_api.h" #include "php_http_request_api.h" #include "php_http_request_method_api.h" +#include "php_http_persistent_handle_api.h" #include "php_http_send_api.h" #include "php_http_url_api.h" @@ -807,6 +808,42 @@ 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) +{ + char **names; + int *counts; + int i, n; + + NO_ARGS; + + if ((n = http_persistent_handle_statall(&names, &counts))) { + object_init(return_value); + for (i = 0; i < n; ++i) { + add_property_long(return_value, names[i], counts[i]); + efree(names[i]); + } + efree(names); + efree(counts); + } +} +/* }}} */ + +/* {{{ proto void http_persistent_handles_clean([string name]) */ +PHP_FUNCTION(http_persistent_handles_clean) +{ + char *name_str = NULL; + int name_len = 0; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name_str, &name_len)) { + http_persistent_handle_cleanup_ex(name_str, name_len); + } +} +/* }}} */ + +#endif /* HTTP_HAVE_PERSISTENT_HANDLES */ #define RETVAL_RESPONSE_OR_BODY(request) \ { \ diff --git a/http_persistent_handle_api.c b/http_persistent_handle_api.c new file mode 100644 index 0000000..8fc1b02 --- /dev/null +++ b/http_persistent_handle_api.c @@ -0,0 +1,193 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2006, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include "php_http.h" + +#ifdef HTTP_HAVE_PERSISTENT_HANDLES + +#include "php_http_persistent_handle_api.h" + +static HashTable http_persistent_handles_hash; +#ifdef ZTS +# define LOCK() tsrm_mutex_lock(http_persistent_handles_lock) +# define UNLOCK() tsrm_mutex_unlock(http_persistent_handles_lock) +static MUTEX_T http_persistent_handles_lock; +#else +# define LOCK() +# define UNLOCK() +#endif + +typedef struct _http_persistent_handles_hash_entry_t { + HashTable list; + http_persistent_handle_ctor ctor; + http_persistent_handle_dtor dtor; +} http_persistent_handles_hash_entry; + +typedef struct _http_persistent_handles_list_entry_t { + void *handle; +} http_persistent_handles_list_entry; + +static inline void http_persistent_handles_hash_dtor_ex(http_persistent_handles_hash_entry *hentry, void (*list_dtor)(HashTable*)) +{ + http_persistent_handles_list_entry *lentry; + + for ( zend_hash_internal_pointer_reset(&hentry->list); + SUCCESS == zend_hash_get_current_data(&hentry->list, (void *) &lentry); + zend_hash_move_forward(&hentry->list)) { + hentry->dtor(lentry->handle); + } + + if (list_dtor) { + list_dtor(&hentry->list); + } +} + +static void http_persistent_handles_hash_dtor(void *h) +{ + http_persistent_handles_hash_dtor_ex(h, zend_hash_destroy); +} + +PHP_MINIT_FUNCTION(http_persistent_handle) +{ + zend_hash_init(&http_persistent_handles_hash, 0, NULL, http_persistent_handles_hash_dtor, 1); +#ifdef ZTS + http_persistent_handles_lock = tsrm_mutex_alloc(); +#endif + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(http_persistent_handle) +{ + zend_hash_destroy(&http_persistent_handles_hash); +#ifdef ZTS + tsrm_mutex_free(http_persistent_handles_lock); +#endif + 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) +{ + STATUS status = SUCCESS; + http_persistent_handles_hash_entry e; + + zend_hash_init(&e.list, 0, NULL, NULL, 1); + e.ctor = ctor; + e.dtor = dtor; + + LOCK(); + if (SUCCESS != zend_hash_add(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &e, sizeof(http_persistent_handles_hash_entry), NULL)) { + zend_hash_destroy(&e.list); + status = FAILURE; + } + UNLOCK(); + + return status; +} + +PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len) +{ + http_persistent_handles_hash_entry *hentry; + + LOCK(); + if (name_str && name_len) { + if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &hentry)) { + http_persistent_handles_hash_dtor_ex(hentry, zend_hash_clean); + } + } else { + for ( zend_hash_internal_pointer_reset(&http_persistent_handles_hash); + SUCCESS == zend_hash_get_current_data(&http_persistent_handles_hash, (void *) &hentry); + zend_hash_move_forward(&http_persistent_handles_hash)) { + http_persistent_handles_hash_dtor_ex(hentry, zend_hash_clean); + } + } + UNLOCK(); +} + +PHP_HTTP_API int _http_persistent_handle_statall_ex(char ***names, int **counts, int persistent) +{ + int i, n; + char *key; + http_persistent_handles_hash_entry *hentry; + + LOCK(); + if ((n = zend_hash_num_elements(&http_persistent_handles_hash))) { + *names = safe_pemalloc(n, sizeof(char **), 0, persistent); + *counts = safe_pemalloc(n, sizeof(int), 0, persistent); + + for ( i = 0, zend_hash_internal_pointer_reset(&http_persistent_handles_hash); + HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(&http_persistent_handles_hash, &key, NULL, 0) && + SUCCESS == zend_hash_get_current_data(&http_persistent_handles_hash, (void *) &hentry); + ++i, zend_hash_move_forward(&http_persistent_handles_hash)) { + (*names)[i] = pestrdup(key, persistent); + (*counts)[i] = zend_hash_num_elements(&hentry->list); + } + } + UNLOCK(); + + return n; +} + +PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle) +{ + STATUS status = FAILURE; + ulong index; + http_persistent_handles_hash_entry *hentry; + http_persistent_handles_list_entry *lentry; + + LOCK(); + if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &hentry)) { + zend_hash_internal_pointer_reset(&hentry->list); + if ( HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(&hentry->list, NULL, &index, 0) && + SUCCESS == zend_hash_get_current_data(&hentry->list, (void *) &lentry)) { + *handle = lentry->handle; + zend_hash_index_del(&hentry->list, index); + status = SUCCESS; + } else if ((*handle = hentry->ctor())) { + status = SUCCESS; + } + } + UNLOCK(); + + return status; +} + +PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle) +{ + STATUS status = FAILURE; + http_persistent_handles_hash_entry *hentry; + http_persistent_handles_list_entry lentry; + + LOCK(); + if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &hentry)) { + lentry.handle = *handle; + if (SUCCESS == zend_hash_next_index_insert(&hentry->list, (void *) &lentry, sizeof(http_persistent_handles_list_entry), NULL)) { + status = SUCCESS; + } + } + UNLOCK(); + + return status; +} + +#endif /* HTTP_HAVE_PERSISTENT_HANDLES */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + diff --git a/http_request_api.c b/http_request_api.c index 6528b97..b9931c8 100644 --- a/http_request_api.c +++ b/http_request_api.c @@ -21,6 +21,9 @@ #include "php_http_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" @@ -109,6 +112,12 @@ 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)) { + return FAILURE; + } +#endif + HTTP_LONG_CONSTANT("HTTP_AUTH_BASIC", CURLAUTH_BASIC); HTTP_LONG_CONSTANT("HTTP_AUTH_DIGEST", CURLAUTH_DIGEST); HTTP_LONG_CONSTANT("HTTP_AUTH_NTLM", CURLAUTH_NTLM); @@ -176,10 +185,18 @@ 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) { - if (ch || (ch = curl_easy_init())) { + if (ch || HTTP_CURL_HANDLE_CTOR(ch)) { #if defined(ZTS) curl_easy_setopt(ch, CURLOPT_NOSIGNAL, 1L); #endif @@ -214,13 +231,12 @@ PHP_HTTP_API CURL * _http_curl_init_ex(CURL *ch, http_request *request) PHP_HTTP_API void _http_curl_free(CURL **ch) { if (*ch) { - /* avoid nasty segfaults with already cleaned up callbacks */ curl_easy_setopt(*ch, CURLOPT_NOPROGRESS, 1L); curl_easy_setopt(*ch, CURLOPT_PROGRESSFUNCTION, NULL); curl_easy_setopt(*ch, CURLOPT_VERBOSE, 0L); curl_easy_setopt(*ch, CURLOPT_DEBUGFUNCTION, NULL); - curl_easy_cleanup(*ch); - *ch = NULL; + + HTTP_CURL_HANDLE_DTOR(ch); } } /* }}} */ diff --git a/package2.xml b/package2.xml index 128ef6f..12bcc97 100644 --- a/package2.xml +++ b/package2.xml @@ -31,7 +31,7 @@ support. Parallel requests are available for PHP 5 and greater. 2007-01-23 1.5.0dev - 1.4.0 + 1.5.0 beta @@ -39,7 +39,8 @@ support. Parallel requests are available for PHP 5 and greater. BSD, revised @@ -75,6 +76,7 @@ support. Parallel requests are available for PHP 5 and greater. + @@ -106,6 +108,7 @@ support. Parallel requests are available for PHP 5 and greater. + @@ -287,6 +290,11 @@ support. Parallel requests are available for PHP 5 and greater. prompt="whether to depend on extensions which have been built shared" default="yes" /> + diff --git a/php_http.h b/php_http.h index caa5c0c..a3d6bd8 100644 --- a/php_http.h +++ b/php_http.h @@ -203,6 +203,10 @@ 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); +# endif PHP_FUNCTION(http_get); PHP_FUNCTION(http_head); PHP_FUNCTION(http_post_data); diff --git a/php_http_persistent_handle_api.h b/php_http_persistent_handle_api.h new file mode 100644 index 0000000..661c8e1 --- /dev/null +++ b/php_http_persistent_handle_api.h @@ -0,0 +1,46 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: http | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2004-2006, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#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); + +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_cleanup(n) _http_persistent_handle_cleanup_ex((n), strlen(n)) +#define http_persistent_handle_cleanup_ex(n, l) _http_persistent_handle_cleanup_ex((n), (l)) +PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len); + +#define http_persistent_handle_statall(n, c) _http_persistent_handle_statall_ex((n), (c), 0) +#define http_persistent_handle_statall_ex(n, c, p) _http_persistent_handle_statall_ex((n), (c), (p)) +PHP_HTTP_API int _http_persistent_handle_statall_ex(char ***names, int **counts, int persistent); + +#define http_persistent_handle_acquire(n, h) _http_persistent_handle_acquire_ex((n), strlen(n), (h)) +#define http_persistent_handle_acquire_ex(n, l, h) _http_persistent_handle_acquire_ex((n), (l), (h)) +PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle); + +#define http_persistent_handle_release(n, h) _http_persistent_handle_release_ex((n), strlen(n), (h)) +#define http_persistent_handle_release_ex(n, l, h) _http_persistent_handle_release_ex((n), (l), (h)) +PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle); + +#endif /* HTTP_HAVE_PERSISTENT_HANDLES */ +#endif /* HTTP_PERSISTENT_HANDLE_H */