- add HttpRequestDataShare (interface to curl_share)
authorMichael Wallner <mike@php.net>
Wed, 13 Sep 2006 12:45:27 +0000 (12:45 +0000)
committerMichael Wallner <mike@php.net>
Wed, 13 Sep 2006 12:45:27 +0000 (12:45 +0000)
12 files changed:
config.w32
config9.m4
docs/http.ini
http.c
http_request_datashare_api.c [new file with mode: 0644]
http_requestdatashare_object.c [new file with mode: 0644]
package2.xml
php_http.h
php_http_request_datashare_api.h [new file with mode: 0644]
php_http_request_object.h
php_http_requestdatashare_object.h [new file with mode: 0644]
tests/HttpRequestDataShare_001.phpt [new file with mode: 0644]

index ed909dc..c524037 100644 (file)
@@ -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");
index cb7db94..14db91a 100644 (file)
@@ -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)
        ], [
index f325595..932ee31 100644 (file)
@@ -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 (file)
--- 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 (file)
index 0000000..4983377
--- /dev/null
@@ -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 <mike@php.net>            |
+    +--------------------------------------------------------------------+
+*/
+
+/* $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 (file)
index 0000000..e3872f6
--- /dev/null
@@ -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 <mike@php.net>            |
+    +--------------------------------------------------------------------+
+*/
+
+/* $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
+ */
+
index 43d6afa..a5a2935 100644 (file)
@@ -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)
 ]]></notes>
  <contents>
   <dir name="/">
@@ -81,6 +82,7 @@ support. Parallel requests are available for PHP 5 and greater.
    <file role="src" name="php_http_request_api.h"/>
    <file role="src" name="php_http_request_int.h"/>
    <file role="src" name="php_http_request_body_api.h"/>
+   <file role="src" name="php_http_request_datashare_api.h"(>)
    <file role="src" name="php_http_request_method_api.h"/>
    <file role="src" name="php_http_request_pool_api.h"/>
    <file role="src" name="php_http_send_api.h"/>
@@ -91,6 +93,7 @@ support. Parallel requests are available for PHP 5 and greater.
    <file role="src" name="php_http_message_object.h"/>
    <file role="src" name="php_http_querystring_object.h"/>
    <file role="src" name="php_http_request_object.h"/>
+   <file role="src" name="php_http_requestdatashare_object.h"/>
    <file role="src" name="php_http_requestpool_object.h"/>
    <file role="src" name="php_http_response_object.h"/>
    <file role="src" name="php_http_exception_object.h"/>
@@ -109,6 +112,7 @@ support. Parallel requests are available for PHP 5 and greater.
    <file role="src" name="http_querystring_api.c"/>
    <file role="src" name="http_request_api.c"/>
    <file role="src" name="http_request_body_api.c"/>
+   <file role="src" name="http_request_datashare_api.c"/>
    <file role="src" name="http_request_method_api.c"/>
    <file role="src" name="http_request_pool_api.c"/>
    <file role="src" name="http_send_api.c"/>
@@ -119,6 +123,7 @@ support. Parallel requests are available for PHP 5 and greater.
    <file role="src" name="http_message_object.c"/>
    <file role="src" name="http_querystring_object.c"/>
    <file role="src" name="http_request_object.c"/>
+   <file role="src" name="http_requestdatashare_object.c"/>
    <file role="src" name="http_requestpool_object.c"/>
    <file role="src" name="http_response_object.c"/>
    <file role="src" name="http_exception_object.c"/>
@@ -192,6 +197,7 @@ support. Parallel requests are available for PHP 5 and greater.
     <file role="test" name="HttpRequest_008.phpt"/>
     <file role="test" name="HttpRequest_009.phpt"/>
     <file role="test" name="HttpRequest_010.phpt"/>
+    <file role="test" name="HttpRequestDataShare_001.phpt"/>
     <file role="test" name="HttpRequestPool_001.phpt"/>
     <file role="test" name="HttpRequestPool_002.phpt"/>
     <file role="test" name="HttpRequestPool_003.phpt"/>
index 7b922a7..e614f22 100644 (file)
@@ -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 (file)
index 0000000..179124e
--- /dev/null
@@ -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 <mike@php.net>            |
+    +--------------------------------------------------------------------+
+*/
+
+/* $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
+ */
+
index 9ac4116..884f8b4 100644 (file)
 #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 (file)
index 0000000..b6f43bf
--- /dev/null
@@ -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 <mike@php.net>            |
+    +--------------------------------------------------------------------+
+*/
+
+/* $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 (file)
index 0000000..d1b18e8
--- /dev/null
@@ -0,0 +1,37 @@
+--TEST--
+HttpRequestDataShare
+--SKIPIF--
+<?php
+include "skip.inc";
+checkcls("HttpRequestDataShare");
+?>
+--FILE--
+<?php
+echo "-TEST\n";
+
+$s = new HttpRequestDataShare;
+$s->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