cleanups & includes
[m6w6/ext-http] / php_http_request_datashare.c
1
2 #include "php_http.h"
3
4 #include <ext/spl/spl_iterators.h>
5
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);
10
11 #ifdef ZTS
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);
16 #endif
17
18 php_http_request_datashare_t *php_http_request_datashare_global_get(void)
19 {
20 return &php_http_request_datashare_global;
21 }
22
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)
24 {
25 zend_bool free_share;
26
27 if ((free_share = !share)) {
28 share = pemalloc(sizeof(php_http_request_datashare_t), persistent);
29 }
30 memset(share, 0, sizeof(php_http_request_datashare_t));
31
32 if (SUCCESS != php_http_persistent_handle_acquire(ZEND_STRL("http_request_datashare"), &share->ch TSRMLS_CC)) {
33 if (free_share) {
34 pefree(share, persistent);
35 }
36 return NULL;
37 }
38
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);
42 #ifdef ZTS
43 } else {
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);
48 }
49 #endif
50 }
51
52 TSRMLS_SET_CTX(share->ts);
53
54 return share;
55 }
56
57 PHP_HTTP_API STATUS php_http_request_datashare_attach(php_http_request_datashare_t *share, zval *request)
58 {
59 CURLcode rc;
60 TSRMLS_FETCH_FROM_CTX(share->ts);
61 php_http_request_object_t *obj = zend_object_store_get_object(request TSRMLS_CC);
62
63 if (obj->share) {
64 if (obj->share == share) {
65 return SUCCESS;
66 } else if (SUCCESS != php_http_request_datashare_detach(obj->share, request)) {
67 return FAILURE;
68 }
69 }
70
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));
74 return FAILURE;
75 }
76
77 obj->share = share;
78 Z_ADDREF_P(request);
79 zend_llist_add_element(PHP_HTTP_RSHARE_HANDLES(share), (void *) &request);
80
81 return SUCCESS;
82 }
83
84 PHP_HTTP_API STATUS php_http_request_datashare_detach(php_http_request_datashare_t *share, zval *request)
85 {
86 CURLcode rc;
87 TSRMLS_FETCH_FROM_CTX(share->ts);
88 php_http_request_object_t *obj = zend_object_store_get_object(request TSRMLS_CC);
89
90 if (!obj->share) {
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));
96 } else {
97 obj->share = NULL;
98 zend_llist_del_element(PHP_HTTP_RSHARE_HANDLES(share), request, php_http_request_datashare_compare_handles);
99 return SUCCESS;
100 }
101 return FAILURE;
102 }
103
104 PHP_HTTP_API void php_http_request_datashare_detach_all(php_http_request_datashare_t *share)
105 {
106 zval **r;
107
108 while ((r = zend_llist_get_first(PHP_HTTP_RSHARE_HANDLES(share)))) {
109 php_http_request_datashare_detach(share, *r);
110 }
111 }
112
113 PHP_HTTP_API void php_http_request_datashare_dtor(php_http_request_datashare_t *share)
114 {
115 TSRMLS_FETCH_FROM_CTX(share->ts);
116
117 if (!share->persistent) {
118 zend_llist_destroy(share->handle.list);
119 efree(share->handle.list);
120 }
121 php_http_persistent_handle_release(ZEND_STRL("http_request_datashare"), &share->ch TSRMLS_CC);
122 #ifdef ZTS
123 if (share->persistent) {
124 php_http_persistent_handle_release(ZEND_STRL("http_request_datashare_lock"), (void *) &share->handle.locks TSRMLS_CC);
125 }
126 #endif
127 }
128
129 PHP_HTTP_API void php_http_request_datashare_free(php_http_request_datashare_t **share)
130 {
131 php_http_request_datashare_dtor(*share);
132 pefree(*share, (*share)->persistent);
133 *share = NULL;
134 }
135
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)
137 {
138 curl_lock_data *opt;
139 CURLSHcode rc;
140 TSRMLS_FETCH_FROM_CTX(share->ts);
141
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))) {
144 return SUCCESS;
145 }
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));
147 }
148 return FAILURE;
149 }
150
151 static int php_http_request_datashare_compare_handles(void *h1, void *h2)
152 {
153 return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
154 }
155
156 static void php_http_request_datashare_destroy_handles(void *el)
157 {
158 zval **r = (zval **) el;
159 TSRMLS_FETCH();
160
161 { /* gcc 2.95 needs these braces */
162 php_http_request_object_t *obj = zend_object_store_get_object(*r TSRMLS_CC);
163
164 curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL);
165 zval_ptr_dtor(r);
166 }
167 }
168
169 #ifdef ZTS
170 static void *php_http_request_datashare_locks_init(void)
171 {
172 int i;
173 php_http_request_datashare_lock_t *locks = pecalloc(CURL_LOCK_DATA_LAST, sizeof(php_http_request_datashare_lock_t), 1);
174
175 if (locks) {
176 for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
177 locks[i].mx = tsrm_mutex_alloc();
178 }
179 }
180
181 return locks;
182 }
183
184 static void php_http_request_datashare_locks_dtor(void *l)
185 {
186 int i;
187 php_http_request_datashare_lock_t *locks = (php_http_request_datashare_lock_t *) l;
188
189 for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
190 tsrm_mutex_free(locks[i].mx);
191 }
192 pefree(locks, 1);
193 }
194
195 static void php_http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr)
196 {
197 php_http_request_datashare_lock_t *locks = (php_http_request_datashare_lock_t *) userptr;
198
199 /* TSRM can't distinguish shared/exclusive locks */
200 tsrm_mutex_lock(locks[data].mx);
201 locks[data].ch = handle;
202 }
203
204 static void php_http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr)
205 {
206 php_http_request_datashare_lock_t *locks = (php_http_request_datashare_lock_t *) userptr;
207
208 if (locks[data].ch == handle) {
209 tsrm_mutex_unlock(locks[data].mx);
210 }
211 }
212 #endif
213
214
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)
218
219 PHP_HTTP_EMPTY_ARGS(__destruct);
220 PHP_HTTP_EMPTY_ARGS(count);
221
222 PHP_HTTP_BEGIN_ARGS(attach, 1)
223 PHP_HTTP_ARG_OBJ(http\\Request, request, 0)
224 PHP_HTTP_END_ARGS;
225 PHP_HTTP_BEGIN_ARGS(detach, 1)
226 PHP_HTTP_ARG_OBJ(http\\Request, request, 0)
227 PHP_HTTP_END_ARGS;
228
229 PHP_HTTP_EMPTY_ARGS(reset);
230
231 PHP_HTTP_EMPTY_ARGS(getGlobalInstance);
232
233
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);
236
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)
246 EMPTY_FUNCTION_ENTRY
247 };
248 static zend_object_handlers php_http_request_datashare_object_handlers;
249
250 zend_object_value php_http_request_datashare_object_new(zend_class_entry *ce TSRMLS_DC)
251 {
252 return php_http_request_datashare_object_new_ex(ce, NULL, NULL TSRMLS_CC);
253 }
254
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)
256 {
257 zend_object_value ov;
258 php_http_request_datashare_object_t *o;
259
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);
263
264 if (share) {
265 o->share = share;
266 } else {
267 o->share = php_http_request_datashare_init(NULL, 0 TSRMLS_CC);
268 }
269
270 if (ptr) {
271 *ptr = o;
272 }
273
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;
276
277 return ov;
278 }
279
280 void php_http_request_datashare_object_free(void *object TSRMLS_DC)
281 {
282 php_http_request_datashare_object_t *o = (php_http_request_datashare_object_t *) object;
283
284 if (!o->share->persistent) {
285 php_http_request_datashare_free(&o->share);
286 }
287 zend_object_std_dtor((zend_object *) o);
288 efree(o);
289 }
290
291 static zval *php_http_request_datashare_object_read_prop(zval *object, zval *member, int type, const zend_literal *literal_key TSRMLS_DC)
292 {
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");
295 return NULL;
296 }
297
298 return zend_get_std_object_handlers()->read_property(object, member, type, literal_key TSRMLS_CC);
299 }
300
301 static void php_http_request_datashare_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *literal_key TSRMLS_DC)
302 {
303 if (zend_get_property_info(THIS_CE, member, 1 TSRMLS_CC)) {
304 int status;
305 php_http_request_datashare_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
306
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) {
309 return;
310 }
311 }
312
313 zend_get_std_object_handlers()->write_property(object, member, value, literal_key TSRMLS_CC);
314 }
315
316 PHP_METHOD(HttpRequestDataShare, __destruct)
317 {
318 php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
319
320 if (SUCCESS == zend_parse_parameters_none()) {
321 ; /* we always want to clean up */
322 }
323
324 php_http_request_datashare_detach_all(obj->share);
325 }
326
327 PHP_METHOD(HttpRequestDataShare, count)
328 {
329 if (SUCCESS == zend_parse_parameters_none()) {
330 php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
331
332 RETURN_LONG(zend_llist_count(PHP_HTTP_RSHARE_HANDLES(obj->share)));
333 }
334 RETURN_FALSE;
335 }
336
337
338 PHP_METHOD(HttpRequestDataShare, attach)
339 {
340 zval *request;
341
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);
344
345 RETURN_SUCCESS(php_http_request_datashare_attach(obj->share, request));
346 }
347 RETURN_FALSE;
348
349 }
350
351 PHP_METHOD(HttpRequestDataShare, detach)
352 {
353 zval *request;
354
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);
357
358 RETURN_SUCCESS(php_http_request_datashare_detach(obj->share, request));
359 }
360 RETURN_FALSE;
361 }
362
363 PHP_METHOD(HttpRequestDataShare, reset)
364 {
365 if (SUCCESS == zend_parse_parameters_none()) {
366 php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
367
368 php_http_request_datashare_detach_all(obj->share);
369 RETURN_TRUE;
370 }
371 RETURN_FALSE;
372 }
373
374 PHP_METHOD(HttpRequestDataShare, getGlobalInstance)
375 {
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);
379
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);
384
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);
387 }
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);
390 }
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);
393 }
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);
396 }
397 }
398
399 RETVAL_ZVAL(instance, 0, 0);
400 }
401 }end_error_handling();
402 }
403
404 PHP_MINIT_FUNCTION(http_request_datashare)
405 {
406 curl_lock_data val;
407
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)) {
409 return FAILURE;
410 }
411 #ifdef ZTS
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)) {
413 return FAILURE;
414 }
415 #endif
416
417 if (!php_http_request_datashare_init(&php_http_request_datashare_global, 1 TSRMLS_CC)) {
418 return FAILURE;
419 }
420
421 zend_hash_init(&php_http_request_datashare_options, 4, NULL, NULL, 1);
422 #define ADD_DATASHARE_OPT(name, opt) \
423 val = 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);
429
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;
437
438 zend_class_implements(php_http_request_datashare_class_entry TSRMLS_CC, 1, spl_ce_Countable);
439
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);
445
446 return SUCCESS;
447 }
448
449 PHP_MSHUTDOWN_FUNCTION(http_request_datashare)
450 {
451 php_http_request_datashare_dtor(&php_http_request_datashare_global);
452 zend_hash_destroy(&php_http_request_datashare_options);
453
454 return SUCCESS;
455 }
456
457 PHP_RINIT_FUNCTION(http_request_datashare)
458 {
459 zend_llist_init(&PHP_HTTP_G->request_datashare.handles, sizeof(zval *), php_http_request_datashare_destroy_handles, 0);
460
461 return SUCCESS;
462 }
463
464 PHP_RSHUTDOWN_FUNCTION(http_request_datashare)
465 {
466 zend_llist_destroy(&PHP_HTTP_G->request_datashare.handles);
467
468 return SUCCESS;
469 }
470