4 static HashTable php_http_request_datashare_options
;
5 static php_http_request_datashare_t php_http_request_datashare_global
;
6 static int php_http_request_datashare_compare_handles(void *h1
, void *h2
);
7 static void php_http_request_datashare_destroy_handles(void *el
);
10 static void *php_http_request_datashare_locks_init(void);
11 static void php_http_request_datashare_locks_dtor(void *l
);
12 static void php_http_request_datashare_lock_func(CURL
*handle
, curl_lock_data data
, curl_lock_access locktype
, void *userptr
);
13 static void php_http_request_datashare_unlock_func(CURL
*handle
, curl_lock_data data
, void *userptr
);
16 php_http_request_datashare_t
*php_http_request_datashare_global_get(void)
18 return &php_http_request_datashare_global
;
21 PHP_HTTP_API php_http_request_datashare_t
*php_http_request_datashare_init(php_http_request_datashare_t
*share
, zend_bool persistent TSRMLS_DC
)
25 if ((free_share
= !share
)) {
26 share
= pemalloc(sizeof(php_http_request_datashare_t
), persistent
);
28 memset(share
, 0, sizeof(php_http_request_datashare_t
));
30 if (SUCCESS
!= php_http_persistent_handle_acquire(ZEND_STRL("http_request_datashare"), &share
->ch TSRMLS_CC
)) {
32 pefree(share
, persistent
);
37 if (!(share
->persistent
= persistent
)) {
38 share
->handle
.list
= emalloc(sizeof(zend_llist
));
39 zend_llist_init(share
->handle
.list
, sizeof(zval
*), ZVAL_PTR_DTOR
, 0);
42 if (SUCCESS
== php_http_persistent_handle_acquire(ZEND_STRL("http_request_datashare_lock"), (void *) &share
->handle
.locks
)) {
43 curl_share_setopt(share
->ch
, CURLSHOPT_LOCKFUNC
, php_http_request_datashare_lock_func
);
44 curl_share_setopt(share
->ch
, CURLSHOPT_UNLOCKFUNC
, php_http_request_datashare_unlock_func
);
45 curl_share_setopt(share
->ch
, CURLSHOPT_USERDATA
, share
->handle
.locks
);
50 TSRMLS_SET_CTX(share
->ts
);
55 PHP_HTTP_API STATUS
php_http_request_datashare_attach(php_http_request_datashare_t
*share
, zval
*request
)
58 TSRMLS_FETCH_FROM_CTX(share
->ts
);
59 php_http_request_object_t
*obj
= zend_object_store_get_object(request TSRMLS_CC
);
62 if (obj
->share
== share
) {
64 } else if (SUCCESS
!= php_http_request_datashare_detach(obj
->share
, request
)) {
69 PHP_HTTP_CHECK_CURL_INIT(obj
->request
->ch
, php_http_curl_init(obj
->request
->ch
, obj
->request TSRMLS_CC
), return FAILURE
);
70 if (CURLE_OK
!= (rc
= curl_easy_setopt(obj
->request
->ch
, CURLOPT_SHARE
, share
->ch
))) {
71 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
));
77 zend_llist_add_element(PHP_HTTP_RSHARE_HANDLES(share
), (void *) &request
);
82 PHP_HTTP_API STATUS
php_http_request_datashare_detach(php_http_request_datashare_t
*share
, zval
*request
)
85 TSRMLS_FETCH_FROM_CTX(share
->ts
);
86 php_http_request_object_t
*obj
= zend_object_store_get_object(request TSRMLS_CC
);
89 php_http_error(HE_WARNING
, PHP_HTTP_E_REQUEST
, "HttpRequest object(#%d) is not attached to any HttpRequestDataShare", Z_OBJ_HANDLE_P(request
));
90 } else if (obj
->share
!= share
) {
91 php_http_error(HE_WARNING
, PHP_HTTP_E_REQUEST
, "HttpRequest object(#%d) is not attached to this HttpRequestDataShare", Z_OBJ_HANDLE_P(request
));
92 } else if (CURLE_OK
!= (rc
= curl_easy_setopt(obj
->request
->ch
, CURLOPT_SHARE
, NULL
))) {
93 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
));
96 zend_llist_del_element(PHP_HTTP_RSHARE_HANDLES(share
), request
, php_http_request_datashare_compare_handles
);
102 PHP_HTTP_API
void php_http_request_datashare_detach_all(php_http_request_datashare_t
*share
)
106 while ((r
= zend_llist_get_first(PHP_HTTP_RSHARE_HANDLES(share
)))) {
107 php_http_request_datashare_detach(share
, *r
);
111 PHP_HTTP_API
void php_http_request_datashare_dtor(php_http_request_datashare_t
*share
)
113 TSRMLS_FETCH_FROM_CTX(share
->ts
);
115 if (!share
->persistent
) {
116 zend_llist_destroy(share
->handle
.list
);
117 efree(share
->handle
.list
);
119 php_http_persistent_handle_release(ZEND_STRL("http_request_datashare"), &share
->ch TSRMLS_CC
);
121 if (share
->persistent
) {
122 php_http_persistent_handle_release(ZEND_STRL("http_request_datashare_lock"), (void *) &share
->handle
.locks TSRMLS_CC
);
127 PHP_HTTP_API
void php_http_request_datashare_free(php_http_request_datashare_t
**share
)
129 php_http_request_datashare_dtor(*share
);
130 pefree(*share
, (*share
)->persistent
);
134 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
)
138 TSRMLS_FETCH_FROM_CTX(share
->ts
);
140 if (SUCCESS
== zend_hash_find(&php_http_request_datashare_options
, (char *) option
, option_len
+ 1, (void *) &opt
)) {
141 if (CURLSHE_OK
== (rc
= curl_share_setopt(share
->ch
, enable
? CURLSHOPT_SHARE
: CURLSHOPT_UNSHARE
, *opt
))) {
144 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
));
149 static int php_http_request_datashare_compare_handles(void *h1
, void *h2
)
151 return (Z_OBJ_HANDLE_PP((zval
**) h1
) == Z_OBJ_HANDLE_P((zval
*) h2
));
154 static void php_http_request_datashare_destroy_handles(void *el
)
156 zval
**r
= (zval
**) el
;
159 { /* gcc 2.95 needs these braces */
160 php_http_request_object_t
*obj
= zend_object_store_get_object(*r TSRMLS_CC
);
162 curl_easy_setopt(obj
->request
->ch
, CURLOPT_SHARE
, NULL
);
168 static void *php_http_request_datashare_locks_init(void)
171 php_http_request_datashare_lock_t
*locks
= pecalloc(CURL_LOCK_DATA_LAST
, sizeof(php_http_request_datashare_lock_t
), 1);
174 for (i
= 0; i
< CURL_LOCK_DATA_LAST
; ++i
) {
175 locks
[i
].mx
= tsrm_mutex_alloc();
182 static void php_http_request_datashare_locks_dtor(void *l
)
185 php_http_request_datashare_lock_t
*locks
= (php_http_request_datashare_lock_t
*) l
;
187 for (i
= 0; i
< CURL_LOCK_DATA_LAST
; ++i
) {
188 tsrm_mutex_free(locks
[i
].mx
);
193 static void php_http_request_datashare_lock_func(CURL
*handle
, curl_lock_data data
, curl_lock_access locktype
, void *userptr
)
195 php_http_request_datashare_lock_t
*locks
= (php_http_request_datashare_lock_t
*) userptr
;
197 /* TSRM can't distinguish shared/exclusive locks */
198 tsrm_mutex_lock(locks
[data
].mx
);
199 locks
[data
].ch
= handle
;
202 static void php_http_request_datashare_unlock_func(CURL
*handle
, curl_lock_data data
, void *userptr
)
204 php_http_request_datashare_lock_t
*locks
= (php_http_request_datashare_lock_t
*) userptr
;
206 if (locks
[data
].ch
== handle
) {
207 tsrm_mutex_unlock(locks
[data
].mx
);
213 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpRequestDataShare, method, 0, req_args)
214 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpRequestDataShare, method, 0)
215 #define PHP_HTTP_RSHARE_ME(method, visibility) PHP_ME(HttpRequestDataShare, method, PHP_HTTP_ARGS(HttpRequestDataShare, method), visibility)
217 PHP_HTTP_EMPTY_ARGS(__destruct
);
218 PHP_HTTP_EMPTY_ARGS(count
);
220 PHP_HTTP_BEGIN_ARGS(attach
, 1)
221 PHP_HTTP_ARG_OBJ(http
\\Request
, request
, 0)
223 PHP_HTTP_BEGIN_ARGS(detach
, 1)
224 PHP_HTTP_ARG_OBJ(http
\\Request
, request
, 0)
227 PHP_HTTP_EMPTY_ARGS(reset
);
229 PHP_HTTP_EMPTY_ARGS(getGlobalInstance
);
232 static zval
*php_http_request_datashare_object_read_prop(zval
*object
, zval
*member
, int type
, const zend_literal
*literal_key TSRMLS_DC
);
233 static void php_http_request_datashare_object_write_prop(zval
*object
, zval
*member
, zval
*value
, const zend_literal
*literal_key TSRMLS_DC
);
235 #define THIS_CE php_http_request_datashare_class_entry
236 zend_class_entry
*php_http_request_datashare_class_entry
;
237 zend_function_entry php_http_request_datashare_method_entry
[] = {
238 PHP_HTTP_RSHARE_ME(__destruct
, ZEND_ACC_PUBLIC
|ZEND_ACC_DTOR
)
239 PHP_HTTP_RSHARE_ME(count
, ZEND_ACC_PUBLIC
)
240 PHP_HTTP_RSHARE_ME(attach
, ZEND_ACC_PUBLIC
)
241 PHP_HTTP_RSHARE_ME(detach
, ZEND_ACC_PUBLIC
)
242 PHP_HTTP_RSHARE_ME(reset
, ZEND_ACC_PUBLIC
)
243 PHP_HTTP_RSHARE_ME(getGlobalInstance
, ZEND_ACC_PUBLIC
|ZEND_ACC_STATIC
)
246 static zend_object_handlers php_http_request_datashare_object_handlers
;
248 zend_object_value
php_http_request_datashare_object_new(zend_class_entry
*ce TSRMLS_DC
)
250 return php_http_request_datashare_object_new_ex(ce
, NULL
, NULL TSRMLS_CC
);
253 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
)
255 zend_object_value ov
;
256 php_http_request_datashare_object_t
*o
;
258 o
= ecalloc(1, sizeof(*o
));
259 zend_object_std_init((zend_object
*) o
, ce TSRMLS_CC
);
260 object_properties_init((zend_object
*) o
, ce
);
265 o
->share
= php_http_request_datashare_init(NULL
, 0 TSRMLS_CC
);
272 ov
.handle
= zend_objects_store_put(o
, NULL
, php_http_request_datashare_object_free
, NULL TSRMLS_CC
);
273 ov
.handlers
= &php_http_request_datashare_object_handlers
;
278 void php_http_request_datashare_object_free(void *object TSRMLS_DC
)
280 php_http_request_datashare_object_t
*o
= (php_http_request_datashare_object_t
*) object
;
282 if (!o
->share
->persistent
) {
283 php_http_request_datashare_free(&o
->share
);
285 zend_object_std_dtor((zend_object
*) o
);
289 static zval
*php_http_request_datashare_object_read_prop(zval
*object
, zval
*member
, int type
, const zend_literal
*literal_key TSRMLS_DC
)
291 if (type
== BP_VAR_W
&& zend_get_property_info(THIS_CE
, member
, 1 TSRMLS_CC
)) {
292 zend_error(E_ERROR
, "Cannot access HttpRequestDataShare default properties by reference or array key/index");
296 return zend_get_std_object_handlers()->read_property(object
, member
, type
, literal_key TSRMLS_CC
);
299 static void php_http_request_datashare_object_write_prop(zval
*object
, zval
*member
, zval
*value
, const zend_literal
*literal_key TSRMLS_DC
)
301 if (zend_get_property_info(THIS_CE
, member
, 1 TSRMLS_CC
)) {
303 php_http_request_datashare_object_t
*obj
= zend_object_store_get_object(object TSRMLS_CC
);
305 status
= php_http_request_datashare_set(obj
->share
, Z_STRVAL_P(member
), Z_STRLEN_P(member
), (zend_bool
) i_zend_is_true(value
));
306 if (SUCCESS
!= status
) {
311 zend_get_std_object_handlers()->write_property(object
, member
, value
, literal_key TSRMLS_CC
);
314 PHP_METHOD(HttpRequestDataShare
, __destruct
)
316 php_http_request_datashare_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
318 if (SUCCESS
== zend_parse_parameters_none()) {
319 ; /* we always want to clean up */
322 php_http_request_datashare_detach_all(obj
->share
);
325 PHP_METHOD(HttpRequestDataShare
, count
)
327 if (SUCCESS
== zend_parse_parameters_none()) {
328 php_http_request_datashare_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
330 RETURN_LONG(zend_llist_count(PHP_HTTP_RSHARE_HANDLES(obj
->share
)));
336 PHP_METHOD(HttpRequestDataShare
, attach
)
340 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O", &request
, php_http_request_class_entry
)) {
341 php_http_request_datashare_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
343 RETURN_SUCCESS(php_http_request_datashare_attach(obj
->share
, request
));
349 PHP_METHOD(HttpRequestDataShare
, detach
)
353 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O", &request
, php_http_request_class_entry
)) {
354 php_http_request_datashare_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
356 RETURN_SUCCESS(php_http_request_datashare_detach(obj
->share
, request
));
361 PHP_METHOD(HttpRequestDataShare
, reset
)
363 if (SUCCESS
== zend_parse_parameters_none()) {
364 php_http_request_datashare_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
366 php_http_request_datashare_detach_all(obj
->share
);
372 PHP_METHOD(HttpRequestDataShare
, getGlobalInstance
)
374 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(runtime
)) {
375 if (SUCCESS
== zend_parse_parameters_none()) {
376 zval
*instance
= *zend_std_get_static_property(THIS_CE
, ZEND_STRL("instance"), 0, NULL TSRMLS_CC
);
378 if (Z_TYPE_P(instance
) != IS_OBJECT
) {
379 MAKE_STD_ZVAL(instance
);
380 ZVAL_OBJVAL(instance
, php_http_request_datashare_object_new_ex(THIS_CE
, php_http_request_datashare_global_get(), NULL TSRMLS_CC
), 1);
381 zend_update_static_property(THIS_CE
, ZEND_STRL("instance"), instance TSRMLS_CC
);
383 if (PHP_HTTP_G
->request_datashare
.cookie
) {
384 zend_update_property_bool(THIS_CE
, instance
, ZEND_STRL("cookie"), PHP_HTTP_G
->request_datashare
.cookie TSRMLS_CC
);
386 if (PHP_HTTP_G
->request_datashare
.dns
) {
387 zend_update_property_bool(THIS_CE
, instance
, ZEND_STRL("dns"), PHP_HTTP_G
->request_datashare
.dns TSRMLS_CC
);
389 if (PHP_HTTP_G
->request_datashare
.ssl
) {
390 zend_update_property_bool(THIS_CE
, instance
, ZEND_STRL("ssl"), PHP_HTTP_G
->request_datashare
.ssl TSRMLS_CC
);
392 if (PHP_HTTP_G
->request_datashare
.connect
) {
393 zend_update_property_bool(THIS_CE
, instance
, ZEND_STRL("connect"), PHP_HTTP_G
->request_datashare
.connect TSRMLS_CC
);
397 RETVAL_ZVAL(instance
, 0, 0);
399 }end_error_handling();
402 PHP_MINIT_FUNCTION(http_request_datashare
)
406 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
)) {
410 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
)) {
415 if (!php_http_request_datashare_init(&php_http_request_datashare_global
, 1 TSRMLS_CC
)) {
419 zend_hash_init(&php_http_request_datashare_options
, 4, NULL
, NULL
, 1);
420 #define ADD_DATASHARE_OPT(name, opt) \
422 zend_hash_add(&php_http_request_datashare_options, name, sizeof(name), &val, sizeof(curl_lock_data), NULL)
423 ADD_DATASHARE_OPT("cookie", CURL_LOCK_DATA_COOKIE
);
424 ADD_DATASHARE_OPT("dns", CURL_LOCK_DATA_DNS
);
425 ADD_DATASHARE_OPT("ssl", CURL_LOCK_DATA_SSL_SESSION
);
426 ADD_DATASHARE_OPT("connect", CURL_LOCK_DATA_CONNECT
);
428 PHP_HTTP_REGISTER_CLASS(http
\\request
, DataShare
, http_request_datashare
, php_http_object_class_entry
, 0);
429 php_http_request_datashare_class_entry
->create_object
= php_http_request_datashare_object_new
;
430 memcpy(&php_http_request_datashare_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
431 php_http_request_datashare_object_handlers
.clone_obj
= NULL
;
432 php_http_request_datashare_object_handlers
.read_property
= php_http_request_datashare_object_read_prop
;
433 php_http_request_datashare_object_handlers
.write_property
= php_http_request_datashare_object_write_prop
;
434 php_http_request_datashare_object_handlers
.get_property_ptr_ptr
= NULL
;
436 zend_class_implements(php_http_request_datashare_class_entry TSRMLS_CC
, 1, spl_ce_Countable
);
438 zend_declare_property_null(THIS_CE
, ZEND_STRL("instance"), (ZEND_ACC_STATIC
|ZEND_ACC_PRIVATE
) TSRMLS_CC
);
439 zend_declare_property_bool(THIS_CE
, ZEND_STRL("cookie"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
440 zend_declare_property_bool(THIS_CE
, ZEND_STRL("dns"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
441 zend_declare_property_bool(THIS_CE
, ZEND_STRL("ssl"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
442 zend_declare_property_bool(THIS_CE
, ZEND_STRL("connect"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
447 PHP_MSHUTDOWN_FUNCTION(http_request_datashare
)
449 php_http_request_datashare_dtor(&php_http_request_datashare_global
);
450 zend_hash_destroy(&php_http_request_datashare_options
);
455 PHP_RINIT_FUNCTION(http_request_datashare
)
457 zend_llist_init(&PHP_HTTP_G
->request_datashare
.handles
, sizeof(zval
*), php_http_request_datashare_destroy_handles
, 0);
462 PHP_RSHUTDOWN_FUNCTION(http_request_datashare
)
464 zend_llist_destroy(&PHP_HTTP_G
->request_datashare
.handles
);