4 #include <ext/spl/spl_iterators.h>
6 static HashTable php_http_request_datashare_options
;
7 static php_http_request_datashare_t php_http_request_datashare_global
;
8 static int php_http_request_datashare_compare_handles(void *h1
, void *h2
);
9 static void php_http_request_datashare_destroy_handles(void *el
);
12 static void *php_http_request_datashare_locks_init(void);
13 static void php_http_request_datashare_locks_dtor(void *l
);
14 static void php_http_request_datashare_lock_func(CURL
*handle
, curl_lock_data data
, curl_lock_access locktype
, void *userptr
);
15 static void php_http_request_datashare_unlock_func(CURL
*handle
, curl_lock_data data
, void *userptr
);
18 php_http_request_datashare_t
*php_http_request_datashare_global_get(void)
20 return &php_http_request_datashare_global
;
23 PHP_HTTP_API php_http_request_datashare_t
*php_http_request_datashare_init(php_http_request_datashare_t
*share
, zend_bool persistent TSRMLS_DC
)
27 if ((free_share
= !share
)) {
28 share
= pemalloc(sizeof(php_http_request_datashare_t
), persistent
);
30 memset(share
, 0, sizeof(php_http_request_datashare_t
));
32 if (SUCCESS
!= php_http_persistent_handle_acquire(ZEND_STRL("http_request_datashare"), &share
->ch TSRMLS_CC
)) {
34 pefree(share
, persistent
);
39 if (!(share
->persistent
= persistent
)) {
40 share
->handle
.list
= emalloc(sizeof(zend_llist
));
41 zend_llist_init(share
->handle
.list
, sizeof(zval
*), ZVAL_PTR_DTOR
, 0);
44 if (SUCCESS
== php_http_persistent_handle_acquire(ZEND_STRL("http_request_datashare_lock"), (void *) &share
->handle
.locks
)) {
45 curl_share_setopt(share
->ch
, CURLSHOPT_LOCKFUNC
, php_http_request_datashare_lock_func
);
46 curl_share_setopt(share
->ch
, CURLSHOPT_UNLOCKFUNC
, php_http_request_datashare_unlock_func
);
47 curl_share_setopt(share
->ch
, CURLSHOPT_USERDATA
, share
->handle
.locks
);
52 TSRMLS_SET_CTX(share
->ts
);
57 PHP_HTTP_API STATUS
php_http_request_datashare_attach(php_http_request_datashare_t
*share
, zval
*request
)
60 TSRMLS_FETCH_FROM_CTX(share
->ts
);
61 php_http_request_object_t
*obj
= zend_object_store_get_object(request TSRMLS_CC
);
64 if (obj
->share
== share
) {
66 } else if (SUCCESS
!= php_http_request_datashare_detach(obj
->share
, request
)) {
71 PHP_HTTP_CHECK_CURL_INIT(obj
->request
->ch
, php_http_curl_init(obj
->request
->ch
, obj
->request TSRMLS_CC
), return FAILURE
);
72 if (CURLE_OK
!= (rc
= curl_easy_setopt(obj
->request
->ch
, CURLOPT_SHARE
, share
->ch
))) {
73 php_http_error(HE_WARNING
, PHP_HTTP_E_REQUEST
, "Could not attach HttpRequest object(#%d) to the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request
), curl_easy_strerror(rc
));
79 zend_llist_add_element(PHP_HTTP_RSHARE_HANDLES(share
), (void *) &request
);
84 PHP_HTTP_API STATUS
php_http_request_datashare_detach(php_http_request_datashare_t
*share
, zval
*request
)
87 TSRMLS_FETCH_FROM_CTX(share
->ts
);
88 php_http_request_object_t
*obj
= zend_object_store_get_object(request TSRMLS_CC
);
91 php_http_error(HE_WARNING
, PHP_HTTP_E_REQUEST
, "HttpRequest object(#%d) is not attached to any HttpRequestDataShare", Z_OBJ_HANDLE_P(request
));
92 } else if (obj
->share
!= share
) {
93 php_http_error(HE_WARNING
, PHP_HTTP_E_REQUEST
, "HttpRequest object(#%d) is not attached to this HttpRequestDataShare", Z_OBJ_HANDLE_P(request
));
94 } else if (CURLE_OK
!= (rc
= curl_easy_setopt(obj
->request
->ch
, CURLOPT_SHARE
, NULL
))) {
95 php_http_error(HE_WARNING
, PHP_HTTP_E_REQUEST
, "Could not detach HttpRequest object(#%d) from the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request
), curl_share_strerror(rc
));
98 zend_llist_del_element(PHP_HTTP_RSHARE_HANDLES(share
), request
, php_http_request_datashare_compare_handles
);
104 PHP_HTTP_API
void php_http_request_datashare_detach_all(php_http_request_datashare_t
*share
)
108 while ((r
= zend_llist_get_first(PHP_HTTP_RSHARE_HANDLES(share
)))) {
109 php_http_request_datashare_detach(share
, *r
);
113 PHP_HTTP_API
void php_http_request_datashare_dtor(php_http_request_datashare_t
*share
)
115 TSRMLS_FETCH_FROM_CTX(share
->ts
);
117 if (!share
->persistent
) {
118 zend_llist_destroy(share
->handle
.list
);
119 efree(share
->handle
.list
);
121 php_http_persistent_handle_release(ZEND_STRL("http_request_datashare"), &share
->ch TSRMLS_CC
);
123 if (share
->persistent
) {
124 php_http_persistent_handle_release(ZEND_STRL("http_request_datashare_lock"), (void *) &share
->handle
.locks TSRMLS_CC
);
129 PHP_HTTP_API
void php_http_request_datashare_free(php_http_request_datashare_t
**share
)
131 php_http_request_datashare_dtor(*share
);
132 pefree(*share
, (*share
)->persistent
);
136 PHP_HTTP_API STATUS
php_http_request_datashare_set(php_http_request_datashare_t
*share
, const char *option
, size_t option_len
, zend_bool enable
)
140 TSRMLS_FETCH_FROM_CTX(share
->ts
);
142 if (SUCCESS
== zend_hash_find(&php_http_request_datashare_options
, (char *) option
, option_len
+ 1, (void *) &opt
)) {
143 if (CURLSHE_OK
== (rc
= curl_share_setopt(share
->ch
, enable
? CURLSHOPT_SHARE
: CURLSHOPT_UNSHARE
, *opt
))) {
146 php_http_error(HE_WARNING
, PHP_HTTP_E_REQUEST
, "Could not %s sharing of %s data: %s", enable
? "enable" : "disable", option
, curl_share_strerror(rc
));
151 static int php_http_request_datashare_compare_handles(void *h1
, void *h2
)
153 return (Z_OBJ_HANDLE_PP((zval
**) h1
) == Z_OBJ_HANDLE_P((zval
*) h2
));
156 static void php_http_request_datashare_destroy_handles(void *el
)
158 zval
**r
= (zval
**) el
;
161 { /* gcc 2.95 needs these braces */
162 php_http_request_object_t
*obj
= zend_object_store_get_object(*r TSRMLS_CC
);
164 curl_easy_setopt(obj
->request
->ch
, CURLOPT_SHARE
, NULL
);
170 static void *php_http_request_datashare_locks_init(void)
173 php_http_request_datashare_lock_t
*locks
= pecalloc(CURL_LOCK_DATA_LAST
, sizeof(php_http_request_datashare_lock_t
), 1);
176 for (i
= 0; i
< CURL_LOCK_DATA_LAST
; ++i
) {
177 locks
[i
].mx
= tsrm_mutex_alloc();
184 static void php_http_request_datashare_locks_dtor(void *l
)
187 php_http_request_datashare_lock_t
*locks
= (php_http_request_datashare_lock_t
*) l
;
189 for (i
= 0; i
< CURL_LOCK_DATA_LAST
; ++i
) {
190 tsrm_mutex_free(locks
[i
].mx
);
195 static void php_http_request_datashare_lock_func(CURL
*handle
, curl_lock_data data
, curl_lock_access locktype
, void *userptr
)
197 php_http_request_datashare_lock_t
*locks
= (php_http_request_datashare_lock_t
*) userptr
;
199 /* TSRM can't distinguish shared/exclusive locks */
200 tsrm_mutex_lock(locks
[data
].mx
);
201 locks
[data
].ch
= handle
;
204 static void php_http_request_datashare_unlock_func(CURL
*handle
, curl_lock_data data
, void *userptr
)
206 php_http_request_datashare_lock_t
*locks
= (php_http_request_datashare_lock_t
*) userptr
;
208 if (locks
[data
].ch
== handle
) {
209 tsrm_mutex_unlock(locks
[data
].mx
);
215 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpRequestDataShare, method, 0, req_args)
216 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpRequestDataShare, method, 0)
217 #define PHP_HTTP_RSHARE_ME(method, visibility) PHP_ME(HttpRequestDataShare, method, PHP_HTTP_ARGS(HttpRequestDataShare, method), visibility)
219 PHP_HTTP_EMPTY_ARGS(__destruct
);
220 PHP_HTTP_EMPTY_ARGS(count
);
222 PHP_HTTP_BEGIN_ARGS(attach
, 1)
223 PHP_HTTP_ARG_OBJ(http
\\Request
, request
, 0)
225 PHP_HTTP_BEGIN_ARGS(detach
, 1)
226 PHP_HTTP_ARG_OBJ(http
\\Request
, request
, 0)
229 PHP_HTTP_EMPTY_ARGS(reset
);
231 PHP_HTTP_EMPTY_ARGS(getGlobalInstance
);
234 static zval
*php_http_request_datashare_object_read_prop(zval
*object
, zval
*member
, int type
, const zend_literal
*literal_key TSRMLS_DC
);
235 static void php_http_request_datashare_object_write_prop(zval
*object
, zval
*member
, zval
*value
, const zend_literal
*literal_key TSRMLS_DC
);
237 #define THIS_CE php_http_request_datashare_class_entry
238 zend_class_entry
*php_http_request_datashare_class_entry
;
239 zend_function_entry php_http_request_datashare_method_entry
[] = {
240 PHP_HTTP_RSHARE_ME(__destruct
, ZEND_ACC_PUBLIC
|ZEND_ACC_DTOR
)
241 PHP_HTTP_RSHARE_ME(count
, ZEND_ACC_PUBLIC
)
242 PHP_HTTP_RSHARE_ME(attach
, ZEND_ACC_PUBLIC
)
243 PHP_HTTP_RSHARE_ME(detach
, ZEND_ACC_PUBLIC
)
244 PHP_HTTP_RSHARE_ME(reset
, ZEND_ACC_PUBLIC
)
245 PHP_HTTP_RSHARE_ME(getGlobalInstance
, ZEND_ACC_PUBLIC
|ZEND_ACC_STATIC
)
248 static zend_object_handlers php_http_request_datashare_object_handlers
;
250 zend_object_value
php_http_request_datashare_object_new(zend_class_entry
*ce TSRMLS_DC
)
252 return php_http_request_datashare_object_new_ex(ce
, NULL
, NULL TSRMLS_CC
);
255 zend_object_value
php_http_request_datashare_object_new_ex(zend_class_entry
*ce
, php_http_request_datashare_t
*share
, php_http_request_datashare_object_t
**ptr TSRMLS_DC
)
257 zend_object_value ov
;
258 php_http_request_datashare_object_t
*o
;
260 o
= ecalloc(1, sizeof(*o
));
261 zend_object_std_init((zend_object
*) o
, ce TSRMLS_CC
);
262 object_properties_init((zend_object
*) o
, ce
);
267 o
->share
= php_http_request_datashare_init(NULL
, 0 TSRMLS_CC
);
274 ov
.handle
= zend_objects_store_put(o
, NULL
, php_http_request_datashare_object_free
, NULL TSRMLS_CC
);
275 ov
.handlers
= &php_http_request_datashare_object_handlers
;
280 void php_http_request_datashare_object_free(void *object TSRMLS_DC
)
282 php_http_request_datashare_object_t
*o
= (php_http_request_datashare_object_t
*) object
;
284 if (!o
->share
->persistent
) {
285 php_http_request_datashare_free(&o
->share
);
287 zend_object_std_dtor((zend_object
*) o
);
291 static zval
*php_http_request_datashare_object_read_prop(zval
*object
, zval
*member
, int type
, const zend_literal
*literal_key TSRMLS_DC
)
293 if (type
== BP_VAR_W
&& zend_get_property_info(THIS_CE
, member
, 1 TSRMLS_CC
)) {
294 zend_error(E_ERROR
, "Cannot access HttpRequestDataShare default properties by reference or array key/index");
298 return zend_get_std_object_handlers()->read_property(object
, member
, type
, literal_key TSRMLS_CC
);
301 static void php_http_request_datashare_object_write_prop(zval
*object
, zval
*member
, zval
*value
, const zend_literal
*literal_key TSRMLS_DC
)
303 if (zend_get_property_info(THIS_CE
, member
, 1 TSRMLS_CC
)) {
305 php_http_request_datashare_object_t
*obj
= zend_object_store_get_object(object TSRMLS_CC
);
307 status
= php_http_request_datashare_set(obj
->share
, Z_STRVAL_P(member
), Z_STRLEN_P(member
), (zend_bool
) i_zend_is_true(value
));
308 if (SUCCESS
!= status
) {
313 zend_get_std_object_handlers()->write_property(object
, member
, value
, literal_key TSRMLS_CC
);
316 PHP_METHOD(HttpRequestDataShare
, __destruct
)
318 php_http_request_datashare_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
320 if (SUCCESS
== zend_parse_parameters_none()) {
321 ; /* we always want to clean up */
324 php_http_request_datashare_detach_all(obj
->share
);
327 PHP_METHOD(HttpRequestDataShare
, count
)
329 if (SUCCESS
== zend_parse_parameters_none()) {
330 php_http_request_datashare_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
332 RETURN_LONG(zend_llist_count(PHP_HTTP_RSHARE_HANDLES(obj
->share
)));
338 PHP_METHOD(HttpRequestDataShare
, attach
)
342 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O", &request
, php_http_request_class_entry
)) {
343 php_http_request_datashare_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
345 RETURN_SUCCESS(php_http_request_datashare_attach(obj
->share
, request
));
351 PHP_METHOD(HttpRequestDataShare
, detach
)
355 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O", &request
, php_http_request_class_entry
)) {
356 php_http_request_datashare_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
358 RETURN_SUCCESS(php_http_request_datashare_detach(obj
->share
, request
));
363 PHP_METHOD(HttpRequestDataShare
, reset
)
365 if (SUCCESS
== zend_parse_parameters_none()) {
366 php_http_request_datashare_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
368 php_http_request_datashare_detach_all(obj
->share
);
374 PHP_METHOD(HttpRequestDataShare
, getGlobalInstance
)
376 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(runtime
)) {
377 if (SUCCESS
== zend_parse_parameters_none()) {
378 zval
*instance
= *zend_std_get_static_property(THIS_CE
, ZEND_STRL("instance"), 0, NULL TSRMLS_CC
);
380 if (Z_TYPE_P(instance
) != IS_OBJECT
) {
381 MAKE_STD_ZVAL(instance
);
382 ZVAL_OBJVAL(instance
, php_http_request_datashare_object_new_ex(THIS_CE
, php_http_request_datashare_global_get(), NULL TSRMLS_CC
), 1);
383 zend_update_static_property(THIS_CE
, ZEND_STRL("instance"), instance TSRMLS_CC
);
385 if (PHP_HTTP_G
->request_datashare
.cookie
) {
386 zend_update_property_bool(THIS_CE
, instance
, ZEND_STRL("cookie"), PHP_HTTP_G
->request_datashare
.cookie TSRMLS_CC
);
388 if (PHP_HTTP_G
->request_datashare
.dns
) {
389 zend_update_property_bool(THIS_CE
, instance
, ZEND_STRL("dns"), PHP_HTTP_G
->request_datashare
.dns TSRMLS_CC
);
391 if (PHP_HTTP_G
->request_datashare
.ssl
) {
392 zend_update_property_bool(THIS_CE
, instance
, ZEND_STRL("ssl"), PHP_HTTP_G
->request_datashare
.ssl TSRMLS_CC
);
394 if (PHP_HTTP_G
->request_datashare
.connect
) {
395 zend_update_property_bool(THIS_CE
, instance
, ZEND_STRL("connect"), PHP_HTTP_G
->request_datashare
.connect TSRMLS_CC
);
399 RETVAL_ZVAL(instance
, 0, 0);
401 }end_error_handling();
404 PHP_MINIT_FUNCTION(http_request_datashare
)
408 if (SUCCESS
!= php_http_persistent_handle_provide(ZEND_STRL("http_request_datashare"), curl_share_init
, (php_http_persistent_handle_dtor_t
) curl_share_cleanup
, NULL
)) {
412 if (SUCCESS
!= php_http_persistent_handle_provide(ZEND_STRL("http_request_datashare_lock"), php_http_request_datashare_locks_init
, php_http_request_datashare_locks_dtor
, NULL
)) {
417 if (!php_http_request_datashare_init(&php_http_request_datashare_global
, 1 TSRMLS_CC
)) {
421 zend_hash_init(&php_http_request_datashare_options
, 4, NULL
, NULL
, 1);
422 #define ADD_DATASHARE_OPT(name, opt) \
424 zend_hash_add(&php_http_request_datashare_options, name, sizeof(name), &val, sizeof(curl_lock_data), NULL)
425 ADD_DATASHARE_OPT("cookie", CURL_LOCK_DATA_COOKIE
);
426 ADD_DATASHARE_OPT("dns", CURL_LOCK_DATA_DNS
);
427 ADD_DATASHARE_OPT("ssl", CURL_LOCK_DATA_SSL_SESSION
);
428 ADD_DATASHARE_OPT("connect", CURL_LOCK_DATA_CONNECT
);
430 PHP_HTTP_REGISTER_CLASS(http
\\request
, DataShare
, http_request_datashare
, php_http_object_class_entry
, 0);
431 php_http_request_datashare_class_entry
->create_object
= php_http_request_datashare_object_new
;
432 memcpy(&php_http_request_datashare_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
433 php_http_request_datashare_object_handlers
.clone_obj
= NULL
;
434 php_http_request_datashare_object_handlers
.read_property
= php_http_request_datashare_object_read_prop
;
435 php_http_request_datashare_object_handlers
.write_property
= php_http_request_datashare_object_write_prop
;
436 php_http_request_datashare_object_handlers
.get_property_ptr_ptr
= NULL
;
438 zend_class_implements(php_http_request_datashare_class_entry TSRMLS_CC
, 1, spl_ce_Countable
);
440 zend_declare_property_null(THIS_CE
, ZEND_STRL("instance"), (ZEND_ACC_STATIC
|ZEND_ACC_PRIVATE
) TSRMLS_CC
);
441 zend_declare_property_bool(THIS_CE
, ZEND_STRL("cookie"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
442 zend_declare_property_bool(THIS_CE
, ZEND_STRL("dns"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
443 zend_declare_property_bool(THIS_CE
, ZEND_STRL("ssl"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
444 zend_declare_property_bool(THIS_CE
, ZEND_STRL("connect"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
449 PHP_MSHUTDOWN_FUNCTION(http_request_datashare
)
451 php_http_request_datashare_dtor(&php_http_request_datashare_global
);
452 zend_hash_destroy(&php_http_request_datashare_options
);
457 PHP_RINIT_FUNCTION(http_request_datashare
)
459 zend_llist_init(&PHP_HTTP_G
->request_datashare
.handles
, sizeof(zval
*), php_http_request_datashare_destroy_handles
, 0);
464 PHP_RSHUTDOWN_FUNCTION(http_request_datashare
)
466 zend_llist_destroy(&PHP_HTTP_G
->request_datashare
.handles
);