From 0eccfc06147e6b5559f871cd1a1332abf6a9b526 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 13 Sep 2006 12:45:27 +0000 Subject: [PATCH] - add HttpRequestDataShare (interface to curl_share) --- config.w32 | 3 +- config9.m4 | 8 +- docs/http.ini | 4 + http.c | 16 +- http_request_datashare_api.c | 216 +++++++++++++++++++ http_requestdatashare_object.c | 307 ++++++++++++++++++++++++++++ package2.xml | 6 + php_http.h | 8 + php_http_request_datashare_api.h | 69 +++++++ php_http_request_object.h | 2 + php_http_requestdatashare_object.h | 56 +++++ tests/HttpRequestDataShare_001.phpt | 37 ++++ 12 files changed, 728 insertions(+), 4 deletions(-) create mode 100644 http_request_datashare_api.c create mode 100644 http_requestdatashare_object.c create mode 100644 php_http_request_datashare_api.h create mode 100644 php_http_requestdatashare_object.h create mode 100644 tests/HttpRequestDataShare_001.phpt diff --git a/config.w32 b/config.w32 index ed909dc..c524037 100644 --- a/config.w32 +++ b/config.w32 @@ -55,7 +55,8 @@ if (PHP_HTTP != "no") { "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_cookie_api.c http_querystring_api.c http_request_datashare_api.c "+ + "http_requestdatashare_object.c", null, "/I\"" + configure_module_dirname + "/phpstr\""); ADD_SOURCES(configure_module_dirname + "/phpstr", "phpstr.c", "http"); diff --git a/config9.m4 b/config9.m4 index cb7db94..14db91a 100644 --- a/config9.m4 +++ b/config9.m4 @@ -216,6 +216,10 @@ dnl ---- PHP_EVAL_LIBLINE($CURL_LIBS, HTTP_SHARED_LIBADD) AC_DEFINE([HTTP_HAVE_CURL], [1], [Have cURL support]) + PHP_CHECK_LIBRARY(curl, curl_share_strerror, + [AC_DEFINE([HAVE_CURL_SHARE_STRERROR], [1], [ ])], [ ], + [$CURL_LIBS -L$CURL_DIR/$PHP_LIBDIR] + ) PHP_CHECK_LIBRARY(curl, curl_multi_strerror, [AC_DEFINE([HAVE_CURL_MULTI_STRERROR], [1], [ ])], [ ], [$CURL_LIBS -L$CURL_DIR/$PHP_LIBDIR] @@ -319,7 +323,7 @@ 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_querystring_api.c http_request_datashare_api.c http_requestdatashare_object.c" PHP_NEW_EXTENSION([http], $PHP_HTTP_SOURCES, $ext_shared) @@ -338,7 +342,7 @@ 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_cookie_api.h php_http_querystring_api.h php_http_request_datashare_api.h php_http_requestdatashare_object.h" ifdef([PHP_INSTALL_HEADERS], [ PHP_INSTALL_HEADERS(ext/http, $PHP_HTTP_HEADERS) ], [ diff --git a/docs/http.ini b/docs/http.ini index f325595..932ee31 100644 --- a/docs/http.ini +++ b/docs/http.ini @@ -49,3 +49,7 @@ http.etag.mode = "MD5" ; automatically inflate sent content ;http.send.inflate.start_auto = 0 ;http.send.inflate.start_flags = + +; global HttpRequestDataShare settings +;http.request.datashare.cookie = 0 +;http.request.datashare.dns = 1 diff --git a/http.c b/http.c index 5ae77b4..51d452a 100644 --- a/http.c +++ b/http.c @@ -31,6 +31,7 @@ #include "php_http_request_method_api.h" #ifdef HTTP_HAVE_CURL # include "php_http_request_api.h" +# include "php_http_request_datashare_api.h" #endif #ifdef HTTP_HAVE_ZLIB # include "php_http_encoding_api.h" @@ -48,6 +49,7 @@ # ifdef HTTP_HAVE_CURL # include "php_http_request_object.h" # include "php_http_requestpool_object.h" +# include "php_http_requestdatashare_object.h" # endif # ifdef HTTP_HAVE_ZLIB # include "php_http_deflatestream_object.h" @@ -236,6 +238,12 @@ PHP_INI_BEGIN() HTTP_PHP_INI_ENTRY("http.log.composite", "", PHP_INI_ALL, OnUpdateString, log.composite) HTTP_PHP_INI_ENTRY("http.request.methods.allowed", "", PHP_INI_ALL, http_update_allowed_methods, request.methods.allowed) HTTP_PHP_INI_ENTRY("http.request.methods.custom", "", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateString, request.methods.custom.ini) +#ifdef ZEND_ENGINE_2 + HTTP_PHP_INI_ENTRY("http.request.datashare.cookie", "0", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.cookie) + HTTP_PHP_INI_ENTRY("http.request.datashare.dns", "0", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.dns) + HTTP_PHP_INI_ENTRY("http.request.datashare.sll", "0", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.ssl) + HTTP_PHP_INI_ENTRY("http.request.datashare.connect", "0", PHP_INI_SYSTEM, OnUpdateBool, request.datashare.connect) +#endif #ifdef HTTP_HAVE_ZLIB HTTP_PHP_INI_ENTRY("http.send.inflate.start_auto", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, send.inflate.start_auto) HTTP_PHP_INI_ENTRY("http.send.inflate.start_flags", "0", PHP_INI_ALL, OnUpdateLong, send.inflate.start_flags) @@ -265,6 +273,7 @@ PHP_MINIT_FUNCTION(http) (SUCCESS != PHP_MINIT_CALL(http_url)) || #ifdef HTTP_HAVE_CURL (SUCCESS != PHP_MINIT_CALL(http_request)) || + (SUCCESS != PHP_MINIT_CALL(http_request_datashare)) || #endif /* HTTP_HAVE_CURL */ #ifdef HTTP_HAVE_ZLIB (SUCCESS != PHP_MINIT_CALL(http_encoding)) || @@ -284,6 +293,7 @@ PHP_MINIT_FUNCTION(http) # ifdef HTTP_HAVE_CURL (SUCCESS != PHP_MINIT_CALL(http_request_object)) || (SUCCESS != PHP_MINIT_CALL(http_requestpool_object))|| + (SUCCESS != PHP_MINIT_CALL(http_requestdatashare_object))|| # endif /* HTTP_HAVE_CURL */ # ifdef HTTP_HAVE_ZLIB (SUCCESS != PHP_MINIT_CALL(http_deflatestream_object)) || @@ -303,7 +313,10 @@ PHP_MSHUTDOWN_FUNCTION(http) { UNREGISTER_INI_ENTRIES(); #ifdef HTTP_HAVE_CURL - return PHP_MSHUTDOWN_CALL(http_request); + if ( (SUCCESS != PHP_MSHUTDOWN_CALL(http_request_datashare)) || + (SUCCESS != PHP_MSHUTDOWN_CALL(http_request))) { + return FAILURE; + } #endif return SUCCESS; } @@ -365,6 +378,7 @@ PHP_MINFO_FUNCTION(http) # ifdef HTTP_HAVE_CURL "HttpRequest, " "HttpRequestPool, " + "HttpRequestDataShare, " # endif # ifdef HTTP_HAVE_ZLIB "HttpDeflateStream, " diff --git a/http_request_datashare_api.c b/http_request_datashare_api.c new file mode 100644 index 0000000..4983377 --- /dev/null +++ b/http_request_datashare_api.c @@ -0,0 +1,216 @@ +/* + +--------------------------------------------------------------------+ + | 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$ */ + +#define HTTP_WANT_CURL +#include "php_http.h" + +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) + +#include "php_http_api.h" +#include "php_http_request_datashare_api.h" +#include "php_http_request_api.h" +#include "php_http_request_object.h" + +#ifndef HAVE_CURL_SHARE_STRERROR +# define curl_share_strerror(dummy) "unknown error" +#endif + +static HashTable http_request_datashare_options; +static http_request_datashare http_request_datashare_global; +static int http_request_datashare_compare_handles(void *h1, void *h2); +static void http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr); +static void http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr); + +PHP_MINIT_FUNCTION(http_request_datashare) +{ + curl_lock_data val; + + zend_hash_init(&http_request_datashare_options, 4, NULL, NULL, 1); +#define ADD_DATASHARE_OPT(name, opt) \ + val = opt; \ + zend_hash_add(&http_request_datashare_options, name, sizeof(name), &val, sizeof(curl_lock_data), NULL) + ADD_DATASHARE_OPT("cookie", CURL_LOCK_DATA_COOKIE); + ADD_DATASHARE_OPT("dns", CURL_LOCK_DATA_DNS); + ADD_DATASHARE_OPT("ssl", CURL_LOCK_DATA_SSL_SESSION); + ADD_DATASHARE_OPT("connect", CURL_LOCK_DATA_CONNECT); + + http_request_datashare_init_ex(&http_request_datashare_global, 1); + + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(http_request_datashare) +{ + http_request_datashare_dtor(&http_request_datashare_global); + zend_hash_destroy(&http_request_datashare_options); + + return SUCCESS; +} + +PHP_HTTP_API http_request_datashare *_http_request_datashare_init_ex(http_request_datashare *share, zend_bool persistent TSRMLS_DC) +{ + int i; + zend_bool free_share; + + if ((free_share = !share)) { + share = pemalloc(sizeof(http_request_datashare), persistent); + } + memset(share, 0, sizeof(http_request_datashare)); + + HTTP_CHECK_CURL_INIT(share->ch, curl_share_init(), ;); + if (!share->ch) { + if (free_share) { + pefree(share, persistent); + } + return NULL; + } + + if ((share->persistent = persistent)) { + share->locks = pecalloc(CURL_LOCK_DATA_LAST, sizeof(http_request_datashare_lock), 1); + for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) { + share->locks[i].mx = tsrm_mutex_alloc(); + } + 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); + } + + zend_llist_init(&share->handles, sizeof(zval *), ZVAL_PTR_DTOR, persistent); + + return share; +} + +PHP_HTTP_API STATUS _http_request_datashare_attach(http_request_datashare *share, zval *request TSRMLS_DC) +{ + CURLcode rc; + getObjectEx(http_request_object, obj, request); + + if (obj->share) { + if (obj->share == share) { + return SUCCESS; + } else if (SUCCESS != http_request_datashare_detach(obj->share, request)) { + return FAILURE; + } + } + + if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, share->ch))) { + http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not attach HttpRequest object(#%d) to the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_share_strerror(rc)); + return FAILURE; + } + + obj->share = share; + ZVAL_ADDREF(request); + zend_llist_add_element(&share->handles, (void *) &request); + + return SUCCESS; +} + +PHP_HTTP_API STATUS _http_request_datashare_detach(http_request_datashare *share, zval *request TSRMLS_DC) +{ + CURLcode rc; + getObjectEx(http_request_object, obj, request); + + if (!obj->share) { + http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to any HttpRequestDataShare", Z_OBJ_HANDLE_P(request)); + } else if (obj->share != share) { + http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to this HttpRequestDataShare", Z_OBJ_HANDLE_P(request)); + } else if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL))) { + http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not detach HttpRequest object(#%d) from the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_share_strerror(rc)); + } else { + obj->share = NULL; + zend_llist_del_element(&share->handles, request, http_request_datashare_compare_handles); + return SUCCESS; + } + return FAILURE; +} + +PHP_HTTP_API void _http_request_datashare_detach_all(http_request_datashare *share TSRMLS_DC) +{ + zval **r; + + while ((r = zend_llist_get_first(&share->handles))) { + http_request_datashare_detach(share, *r); + } +} + +PHP_HTTP_API void _http_request_datashare_dtor(http_request_datashare *share TSRMLS_DC) +{ + int i; + + zend_llist_destroy(&share->handles); + curl_share_cleanup(share->ch); + if (share->persistent) { + for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) { + tsrm_mutex_free(share->locks[i].mx); + } + pefree(share->locks, 1); + } +} + +PHP_HTTP_API void _http_request_datashare_free(http_request_datashare **share TSRMLS_DC) +{ + http_request_datashare_dtor(*share); + pefree(*share, (*share)->persistent); + *share = NULL; +} + +PHP_HTTP_API STATUS _http_request_datashare_set(http_request_datashare *share, const char *option, size_t option_len, zend_bool enable TSRMLS_DC) +{ + curl_lock_data *opt; + CURLSHcode rc; + + if (SUCCESS == zend_hash_find(&http_request_datashare_options, (char *) option, option_len + 1, (void *) &opt)) { + if (CURLSHE_OK == (rc = curl_share_setopt(share->ch, enable ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, *opt))) { + return SUCCESS; + } + http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not %s sharing of %s data: %s", enable ? "enable" : "disable", option, curl_share_strerror(rc)); + } + return FAILURE; +} + +static int http_request_datashare_compare_handles(void *h1, void *h2) +{ + return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2)); +} + +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; + + /* TSRM can't distinguish shared/exclusive locks */ + tsrm_mutex_lock(share->locks[data].mx); + share->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; + + if (share->locks[data].ch == handle) { + tsrm_mutex_unlock(share->locks[data].mx); + } +} + +#endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */ + + +/* + * 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_requestdatashare_object.c b/http_requestdatashare_object.c new file mode 100644 index 0000000..e3872f6 --- /dev/null +++ b/http_requestdatashare_object.c @@ -0,0 +1,307 @@ +/* + +--------------------------------------------------------------------+ + | 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$ */ + +#define HTTP_WANT_CURL +#include "php_http.h" + +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) + +#include "zend_interfaces.h" + +#include "php_http_api.h" +#include "php_http_exception_object.h" +#include "php_http_request_api.h" +#include "php_http_request_object.h" +#include "php_http_request_datashare_api.h" +#include "php_http_requestdatashare_object.h" + +#define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpRequestDataShare, method, 0, req_args) +#define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpRequestDataShare, method, 0) +#define HTTP_RSHARE_ME(method, visibility) PHP_ME(HttpRequestDataShare, method, HTTP_ARGS(HttpRequestDataShare, method), visibility) + +#if defined(HAVE_SPL) && !defined(WONKY) +/* SPL doesn't install its headers */ +extern PHPAPI zend_class_entry *spl_ce_Countable; +#endif + +HTTP_EMPTY_ARGS(__destruct); +HTTP_EMPTY_ARGS(count); + +HTTP_BEGIN_ARGS(attach, 1) + HTTP_ARG_OBJ(HttpRequest, request, 0) +HTTP_END_ARGS; +HTTP_BEGIN_ARGS(detach, 1) + HTTP_ARG_OBJ(HttpRequest, request, 0) +HTTP_END_ARGS; + +HTTP_EMPTY_ARGS(reset); + +#ifndef WONKY +HTTP_BEGIN_ARGS(singleton, 0) + HTTP_ARG_VAL(global, 0) +HTTP_END_ARGS; +#endif + + +#define http_requestdatashare_object_read_prop _http_requestdatashare_object_read_prop +static zval *_http_requestdatashare_object_read_prop(zval *object, zval *member, int type TSRMLS_DC); +#define http_requestdatashare_object_write_prop _http_requestdatashare_object_write_prop +static void _http_requestdatashare_object_write_prop(zval *object, zval *member, zval *value TSRMLS_DC); +#define http_requestdatashare_instantiate(t, g) _http_requestdatashare_instantiate((t), (g) TSRMLS_CC) +static inline zval *_http_requestdatashare_instantiate(zval *this_ptr, zend_bool global TSRMLS_DC); + +#define OBJ_PROP_CE http_requestdatashare_object_ce +zend_class_entry *http_requestdatashare_object_ce; +zend_function_entry http_requestdatashare_object_fe[] = { + HTTP_RSHARE_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR) + HTTP_RSHARE_ME(count, ZEND_ACC_PUBLIC) + HTTP_RSHARE_ME(attach, ZEND_ACC_PUBLIC) + HTTP_RSHARE_ME(detach, ZEND_ACC_PUBLIC) + HTTP_RSHARE_ME(reset, ZEND_ACC_PUBLIC) +#ifndef WONKY + HTTP_RSHARE_ME(singleton, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) +#endif + EMPTY_FUNCTION_ENTRY +}; +static zend_object_handlers http_requestdatashare_object_handlers; + +PHP_MINIT_FUNCTION(http_requestdatashare_object) +{ + HTTP_REGISTER_CLASS_EX(HttpRequestDataShare, http_requestdatashare_object, NULL, 0); + http_requestdatashare_object_handlers.clone_obj = NULL; + http_requestdatashare_object_handlers.read_property = http_requestdatashare_object_read_prop; + http_requestdatashare_object_handlers.write_property = http_requestdatashare_object_write_prop; + +#if defined(HAVE_SPL) && !defined(WONKY) + zend_class_implements(http_requestdatashare_object_ce TSRMLS_CC, 1, spl_ce_Countable); +#endif + + DCL_STATIC_PROP_N(PRIVATE, instance); + DCL_PROP(PUBLIC, bool, cookie, 0); + DCL_PROP(PUBLIC, bool, dns, 0); + DCL_PROP(PUBLIC, bool, ssl, 0); + DCL_PROP(PUBLIC, bool, connect, 0); + + return SUCCESS; +} + +zend_object_value _http_requestdatashare_object_new(zend_class_entry *ce TSRMLS_DC) +{ + return http_requestdatashare_object_new_ex(ce, NULL, NULL); +} + +zend_object_value _http_requestdatashare_object_new_ex(zend_class_entry *ce, http_request_datashare *share, http_requestdatashare_object **ptr TSRMLS_DC) +{ + zend_object_value ov; + http_requestdatashare_object *o; + + o = ecalloc(1, sizeof(http_requestdatashare_object)); + o->zo.ce = ce; + + if (share) { + o->share = share; + } else { + o->share = http_request_datashare_new(); + } + + if (ptr) { + *ptr = o; + } + + ALLOC_HASHTABLE(OBJ_PROP(o)); + zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0); + zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + + ov.handle = putObject(http_requestdatashare_object, o); + ov.handlers = &http_requestdatashare_object_handlers; + + return ov; +} + +void _http_requestdatashare_object_free(zend_object *object TSRMLS_DC) +{ + http_requestdatashare_object *o = (http_requestdatashare_object *) object; + + if (!o->share->persistent) { + http_request_datashare_free(&o->share); + } + freeObject(o); +} + +static zval *_http_requestdatashare_object_read_prop(zval *object, zval *member, int type TSRMLS_DC) +{ + if (type == BP_VAR_W && zend_hash_exists(&OBJ_PROP_CE->default_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1)) { + zend_error(E_ERROR, "Cannot access HttpRequestDataShare default properties by reference or array key/index"); + return NULL; + } + + return zend_get_std_object_handlers()->read_property(object, member, type TSRMLS_CC); +} + +static void _http_requestdatashare_object_write_prop(zval *object, zval *member, zval *value TSRMLS_DC) +{ + if (zend_hash_exists(&OBJ_PROP_CE->default_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1)) { + int status; + zval *orig = value; + getObjectEx(http_requestdatashare_object, obj, object); + + SEPARATE_ZVAL_IF_NOT_REF(&value); + status = http_request_datashare_set(obj->share, Z_STRVAL_P(member), Z_STRLEN_P(member), zval_is_true(value)); + if (orig != value) { + zval_ptr_dtor(&value); + value = orig; + } + if (SUCCESS != status) { + return; + } + } + + zend_get_std_object_handlers()->write_property(object, member, value TSRMLS_CC); +} + +/* {{{ proto void HttpRequestDataShare::__destruct() + * + * Clean up HttpRequestDataShare object. + */ +PHP_METHOD(HttpRequestDataShare, __destruct) +{ + NO_ARGS { + getObject(http_requestdatashare_object, obj); + http_request_datashare_detach_all(obj->share); + } +} +/* }}} */ + +/* {{{ proto int HttpRequestDataShare::count() + * + * Implements Countable::count(). + */ +PHP_METHOD(HttpRequestDataShare, count) +{ + getObject(http_requestdatashare_object, obj); + + NO_ARGS; + + RETURN_LONG(zend_llist_count(&obj->share->handles)); +} +/* }}} */ + +PHP_METHOD(HttpRequestDataShare, attach) +{ + zval *request; + getObject(http_requestdatashare_object, obj); + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) { + RETURN_FALSE; + } + + RETURN_SUCCESS(http_request_datashare_attach(obj->share, request)); +} + +PHP_METHOD(HttpRequestDataShare, detach) +{ + zval *request; + getObject(http_requestdatashare_object, obj); + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) { + RETURN_FALSE; + } + + RETURN_SUCCESS(http_request_datashare_detach(obj->share, request)); +} + +PHP_METHOD(HttpRequestDataShare, reset) +{ + NO_ARGS { + getObject(http_requestdatashare_object, obj); + http_request_datashare_detach_all(obj->share); + } +} + +#ifndef WONKY +/* {{{ proto static HttpRequestDataShare HttpRequestDataShare::singleton([bool global = false]) + * + * Get a single instance (differentiates between the global setting). + */ +PHP_METHOD(HttpRequestDataShare, singleton) +{ + zend_bool global = 0; + zval *instance = GET_STATIC_PROP(instance); + + SET_EH_THROW_HTTP(); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &global)) { + zval **zobj_ptr = NULL, *zobj = NULL; + + if (Z_TYPE_P(instance) == IS_ARRAY) { + if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(instance), global, (void *) &zobj_ptr)) { + RETVAL_ZVAL(*zobj_ptr, 1, 0); + } else { + zobj = http_requestdatashare_instantiate(NULL, global); + add_index_zval(instance, global, zobj); + RETVAL_OBJECT(zobj, 1); + } + } else { + MAKE_STD_ZVAL(instance); + array_init(instance); + + zobj = http_requestdatashare_instantiate(NULL, global); + add_index_zval(instance, global, zobj); + RETVAL_OBJECT(zobj, 1); + + SET_STATIC_PROP(instance, instance); + zval_ptr_dtor(&instance); + } + } + SET_EH_NORMAL(); +} +/* }}} */ + +static inline zval *_http_requestdatashare_instantiate(zval *this_ptr, zend_bool global TSRMLS_DC) +{ + if (!this_ptr) { + MAKE_STD_ZVAL(this_ptr); + Z_TYPE_P(this_ptr) = IS_OBJECT; + this_ptr->value.obj = http_requestdatashare_object_new(http_requestdatashare_object_ce); + } + if (global) { + if (HTTP_G->request.datashare.cookie) { + UPD_PROP(bool, cookie, HTTP_G->request.datashare.cookie); + } + if (HTTP_G->request.datashare.dns) { + UPD_PROP(bool, dns, HTTP_G->request.datashare.dns); + } + if (HTTP_G->request.datashare.ssl) { + UPD_PROP(bool, ssl, HTTP_G->request.datashare.ssl); + } + if (HTTP_G->request.datashare.connect) { + UPD_PROP(bool, connect, HTTP_G->request.datashare.connect); + } + } + return this_ptr; +} +#endif + + + +#endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */ + +/* + * 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/package2.xml b/package2.xml index 43d6afa..a5a2935 100644 --- a/package2.xml +++ b/package2.xml @@ -42,6 +42,7 @@ support. Parallel requests are available for PHP 5 and greater. + Added HttpRequestPool::enablePipielining([bool enable = TRUE]) (libcurl >= 7.16.0) + Added "dns_cache_timeout", "low_speed_limit", "low_speed_time", "max_send_speed", "max_recv_speed", "forbid_reuse" and "fresh_connect" request options ++ Added HttpRequestDataShare (interface to curl_share) ]]> @@ -81,6 +82,7 @@ support. Parallel requests are available for PHP 5 and greater. + ) @@ -91,6 +93,7 @@ support. Parallel requests are available for PHP 5 and greater. + @@ -109,6 +112,7 @@ support. Parallel requests are available for PHP 5 and greater. + @@ -119,6 +123,7 @@ support. Parallel requests are available for PHP 5 and greater. + @@ -192,6 +197,7 @@ support. Parallel requests are available for PHP 5 and greater. + diff --git a/php_http.h b/php_http.h index 7b922a7..e614f22 100644 --- a/php_http.h +++ b/php_http.h @@ -123,6 +123,14 @@ ZEND_BEGIN_MODULE_GLOBALS(http) void *entries; } custom; } methods; +#ifdef ZEND_ENGINE_2 + struct _http_globals_request_datashare { + zend_bool cookie; + zend_bool dns; + zend_bool ssl; + zend_bool connect; + } datashare; +#endif } request; #ifdef ZEND_ENGINE_2 diff --git a/php_http_request_datashare_api.h b/php_http_request_datashare_api.h new file mode 100644 index 0000000..179124e --- /dev/null +++ b/php_http_request_datashare_api.h @@ -0,0 +1,69 @@ +/* + +--------------------------------------------------------------------+ + | 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 PHP_HTTP_REQUEST_DATASHARE_API_H +#define PHP_HTTP_REQUEST_DATASHARE_API_H +#ifdef HTTP_HAVE_CURL + +typedef struct _http_request_datashare_lock_t { + CURL *ch; + MUTEX_T mx; +} http_request_datashare_lock; + +typedef struct _http_request_datashare_t { + CURLSH *ch; + zend_llist handles; + zend_bool persistent; + http_request_datashare_lock *locks; +} http_request_datashare; + +extern PHP_MINIT_FUNCTION(http_request_datashare); +extern PHP_MSHUTDOWN_FUNCTION(http_request_datashare); + +#define http_request_datashare_new() _http_request_datashare_init_ex(NULL, 0 TSRMLS_CC) +#define http_request_datashare_init(s) _http_request_datashare_init_ex((s), 0 TSRMLS_CC) +#define http_request_datashare_init_ex(s, p) _http_request_datashare_init_ex((s), (p) TSRMLS_CC) +PHP_HTTP_API http_request_datashare *_http_request_datashare_init_ex(http_request_datashare *share, zend_bool persistent TSRMLS_DC); + +#define http_request_datashare_attach(s, r) _http_request_datashare_attach((s), (r) TSRMLS_CC) +PHP_HTTP_API STATUS _http_request_datashare_attach(http_request_datashare *share, zval *request TSRMLS_DC); + +#define http_request_datashare_detach(s, r) _http_request_datashare_detach((s), (r) TSRMLS_CC) +PHP_HTTP_API STATUS _http_request_datashare_detach(http_request_datashare *share, zval *request TSRMLS_DC); + +#define http_request_datashare_detach_all(s) _http_request_datashare_detach_all((s) TSRMLS_CC) +PHP_HTTP_API void _http_request_datashare_detach_all(http_request_datashare *share TSRMLS_DC); + +#define http_request_datashare_dtor(s) _http_request_datashare_dtor((s) TSRMLS_CC) +PHP_HTTP_API void _http_request_datashare_dtor(http_request_datashare *share TSRMLS_DC); + +#define http_request_datashare_free(s) _http_request_datashare_free((s) TSRMLS_CC) +PHP_HTTP_API void _http_request_datashaere_free(http_request_datashare **share TSRMLS_DC); + +#define http_request_datashare_set(s, o, l, e) _http_request_datashare_set((s), (o), (l), (e) TSRMLS_CC) +PHP_HTTP_API STATUS _http_request_datashare_set(http_request_datashare *share, const char *option, size_t option_len, zend_bool enable TSRMLS_DC); + + +#endif +#endif + +/* + * 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/php_http_request_object.h b/php_http_request_object.h index 9ac4116..884f8b4 100644 --- a/php_http_request_object.h +++ b/php_http_request_object.h @@ -18,11 +18,13 @@ #ifdef ZEND_ENGINE_2 #include "php_http_request_pool_api.h" +#include "php_http_request_datashare_api.h" typedef struct _http_request_object_t { zend_object zo; http_request *request; http_request_pool *pool; + http_request_datashare *share; } http_request_object; extern zend_class_entry *http_request_object_ce; diff --git a/php_http_requestdatashare_object.h b/php_http_requestdatashare_object.h new file mode 100644 index 0000000..b6f43bf --- /dev/null +++ b/php_http_requestdatashare_object.h @@ -0,0 +1,56 @@ +/* + +--------------------------------------------------------------------+ + | 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 PHP_HTTP_REQUEST_DATASHARE_OBJECT_H +#define PHP_HTTP_REQUEST_DATASHARE_OBJECT_H +#ifdef ZEND_ENGINE_2 + +typedef struct _http_requestdatashare_object_t { + zend_object zo; + http_request_datashare *share; +} http_requestdatashare_object; + +extern zend_class_entry *http_requestdatashare_object_ce; +extern zend_function_entry http_requestdatashare_object_fe[]; + +extern PHP_MINIT_FUNCTION(http_requestdatashare_object); + +#define http_requestdatashare_object_new(ce) _http_requestdatashare_object_new((ce) TSRMLS_CC) +extern zend_object_value _http_requestdatashare_object_new(zend_class_entry *ce TSRMLS_DC); +#define http_requestdatashare_object_new_ex(ce, s, ptr) _http_requestdatashare_object_new_ex((ce), (s), (ptr) TSRMLS_CC) +extern zend_object_value _http_requestdatashare_object_new_ex(zend_class_entry *ce, http_request_datashare *share, http_requestdatashare_object **ptr TSRMLS_DC); +#define http_requestdatashare_object_free(o) _http_requestdatashare_object_free((o) TSRMLS_CC) +extern void _http_requestdatashare_object_free(zend_object *object TSRMLS_DC); + +PHP_METHOD(HttpRequestDataShare, __destruct); +PHP_METHOD(HttpRequestDataShare, count); +PHP_METHOD(HttpRequestDataShare, attach); +PHP_METHOD(HttpRequestDataShare, detach); +PHP_METHOD(HttpRequestDataShare, reset); +#ifndef WONKY +PHP_METHOD(HttpRequestDataShare, singleton); +#endif + +#endif +#endif + +/* + * 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/tests/HttpRequestDataShare_001.phpt b/tests/HttpRequestDataShare_001.phpt new file mode 100644 index 0000000..d1b18e8 --- /dev/null +++ b/tests/HttpRequestDataShare_001.phpt @@ -0,0 +1,37 @@ +--TEST-- +HttpRequestDataShare +--SKIPIF-- + +--FILE-- +dns = true; +$s->cookie = true; + +$r1 = new HttpRequest("http://www.google.com/"); +$r2 = new HttpRequest("http://www.google.com/"); + +$r1->enableCookies(); +$r2->enableCookies(); + +$s->attach($r1); +$s->attach($r2); + +$r1->send(); +$r2->send(); + +$s->reset(); + +var_dump(current($r1->getResponseCookies())->cookies["PREF"] === HttpUtil::parseCookie($r2->getRequestMessage()->getHeader("Cookie"))->cookies["PREF"]); + +echo "Done\n"; +?> +--EXPECTF-- +%sTEST +bool(true) +Done -- 2.30.2