f44d5b053f5232cc2095bd7765a076458c13a02f
[m6w6/ext-http] / php_http_request_datashare.c
1
2 #include "php_http.h"
3
4 #include <ext/standard/php_string.h>
5 #include <ext/spl/spl_iterators.h>
6
7 static int php_http_request_datashare_compare_handles(void *h1, void *h2);
8
9 #ifdef ZTS
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);
14 static MUTEX_T php_http_request_datashare_global_shares_lock;
15 #endif
16 static HashTable php_http_request_datashare_global_shares;
17 php_http_request_datashare_t *php_http_request_datashare_global_get(const char *driver_str, size_t driver_len TSRMLS_DC)
18 {
19 php_http_request_datashare_t *s = NULL, **s_ptr;
20 char *lower_str = php_strtolower(estrndup(driver_str, driver_len), driver_len);
21
22 #ifdef ZTS
23 tsrm_mutex_lock(php_http_request_datashare_global_shares_lock);
24 #endif
25 if (zend_hash_find(&php_http_request_datashare_global_shares, lower_str, driver_len + 1, (void *) &s_ptr)) {
26 s = *s_ptr;
27 } else {
28 php_http_request_factory_driver_t driver;
29
30 if ((SUCCESS == php_http_request_factory_get_driver(driver_str, driver_len, &driver)) && driver.request_datashare_ops) {
31 s = php_http_request_datashare_init(NULL, driver.request_datashare_ops, NULL, NULL, 1 TSRMLS_CC);
32 zend_hash_add(&php_http_request_datashare_global_shares, lower_str, driver_len + 1, &s, sizeof(php_http_request_datashare_t *), NULL);
33 }
34 }
35 #ifdef ZTS
36 tsrm_mutex_unlock(php_http_request_datashare_global_shares_lock);
37 #endif
38
39 efree(lower_str);
40 return s;
41 }
42
43 PHP_HTTP_API php_http_request_datashare_t *php_http_request_datashare_init(php_http_request_datashare_t *h, php_http_request_datashare_ops_t *ops, php_http_resource_factory_t *rf, void *init_arg, zend_bool persistent TSRMLS_DC)
44 {
45 php_http_request_datashare_t *free_h = NULL;
46
47 if (!h) {
48 free_h = h = pemalloc(sizeof(*h), persistent);
49 }
50 memset(h, sizeof(*h), 0);
51
52 if (!(h->persistent = persistent)) {
53 h->requests = emalloc(sizeof(*h->requests));
54 zend_llist_init(h->requests, sizeof(zval *), ZVAL_PTR_DTOR, 0);
55 TSRMLS_SET_CTX(h->ts);
56 }
57 h->ops = ops;
58 h->rf = rf ? rf : php_http_resource_factory_init(NULL, h->ops->rsrc, NULL, NULL TSRMLS_CC);
59
60 if (h->ops->init) {
61 if (!(h = h->ops->init(h, init_arg))) {
62 if (free_h) {
63 pefree(free_h, persistent);
64 }
65 }
66 }
67
68 return h;
69 }
70
71 PHP_HTTP_API php_http_request_datashare_t *php_http_request_datashare_copy(php_http_request_datashare_t *from, php_http_request_datashare_t *to)
72 {
73 if (from->ops->copy) {
74 return from->ops->copy(from, to);
75 }
76
77 return NULL;
78 }
79
80 PHP_HTTP_API void php_http_request_datashare_dtor(php_http_request_datashare_t *h)
81 {
82 if (h->ops->dtor) {
83 h->ops->dtor(h);
84 }
85 if (h->requests) {
86 zend_llist_destroy(h->requests);
87 pefree(h->requests, h->persistent);
88 h->requests = NULL;
89 }
90
91 if (h->persistent_handle_id) {
92 zval_ptr_dtor(&h->persistent_handle_id);
93 }
94 }
95
96 PHP_HTTP_API void php_http_request_datashare_free(php_http_request_datashare_t **h)
97 {
98 php_http_request_datashare_dtor(*h);
99 pefree(*h, (*h)->persistent);
100 *h = NULL;
101 }
102
103 PHP_HTTP_API STATUS php_http_request_datashare_attach(php_http_request_datashare_t *h, zval *request)
104 {
105 TSRMLS_FETCH_FROM_CTX(h->ts);
106
107 if (h->ops->attach) {
108 php_http_request_object_t *obj = zend_object_store_get_object(request TSRMLS_CC);
109
110 if (SUCCESS == h->ops->attach(h, obj->request)) {
111 Z_ADDREF_P(request);
112 zend_llist_add_element(PHP_HTTP_REQUEST_DATASHARE_REQUESTS(h), &request);
113 return SUCCESS;
114 }
115 }
116
117 return FAILURE;
118 }
119
120 static int php_http_request_datashare_compare_handles(void *h1, void *h2)
121 {
122 return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
123 }
124
125 PHP_HTTP_API STATUS php_http_request_datashare_detach(php_http_request_datashare_t *h, zval *request)
126 {
127 TSRMLS_FETCH_FROM_CTX(h->ts);
128
129 if (h->ops->detach) {
130 php_http_request_object_t *obj = zend_object_store_get_object(request TSRMLS_CC);
131
132 if (SUCCESS == h->ops->detach(h, obj->request)) {
133 zend_llist_del_element(PHP_HTTP_REQUEST_DATASHARE_REQUESTS(h), request, php_http_request_datashare_compare_handles);
134 return SUCCESS;
135 }
136 }
137 return FAILURE;
138 }
139
140 PHP_HTTP_API STATUS php_http_request_datashare_setopt(php_http_request_datashare_t *h, php_http_request_datashare_setopt_opt_t opt, void *arg)
141 {
142 if (h->ops->setopt) {
143 return h->ops->setopt(h, opt, arg);
144 }
145 return FAILURE;
146 }
147
148 static void detach(void *r, void *h TSRMLS_DC)
149 {
150 ((php_http_request_datashare_t *) h)->ops->detach(h, ((php_http_request_object_t *) zend_object_store_get_object(*((zval **) r) TSRMLS_CC))->request);
151 }
152
153 PHP_HTTP_API void php_http_request_datashare_reset(php_http_request_datashare_t *h)
154 {
155 if (h->ops->reset) {
156 h->ops->reset(h);
157 } else if (h->ops->detach) {
158 TSRMLS_FETCH_FROM_CTX(h->ts);
159
160 zend_llist_apply_with_argument(PHP_HTTP_REQUEST_DATASHARE_REQUESTS(h), detach, h TSRMLS_CC);
161 }
162
163 zend_llist_clean(PHP_HTTP_REQUEST_DATASHARE_REQUESTS(h));
164 }
165
166 static void php_http_request_datashare_global_requests_dtor(void *el)
167 {
168 //php_http_request_datashare_detach(php_http_request_datashare_global_get(), *((zval **) el));
169 zval_ptr_dtor(el);
170 }
171
172 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpRequestDataShare, method, 0, req_args)
173 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpRequestDataShare, method, 0)
174 #define PHP_HTTP_RSHARE_ME(method, visibility) PHP_ME(HttpRequestDataShare, method, PHP_HTTP_ARGS(HttpRequestDataShare, method), visibility)
175
176 PHP_HTTP_EMPTY_ARGS(__construct);
177 PHP_HTTP_EMPTY_ARGS(__destruct);
178 PHP_HTTP_EMPTY_ARGS(reset);
179 PHP_HTTP_EMPTY_ARGS(count);
180
181 PHP_HTTP_BEGIN_ARGS(attach, 1)
182 PHP_HTTP_ARG_OBJ(http\\Request, request, 0)
183 PHP_HTTP_END_ARGS;
184 PHP_HTTP_BEGIN_ARGS(detach, 1)
185 PHP_HTTP_ARG_OBJ(http\\Request, request, 0)
186 PHP_HTTP_END_ARGS;
187
188 static void php_http_request_datashare_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *literal_key TSRMLS_DC);
189
190 #define php_http_request_datashare_class_entry php_http_request_datashare_class_entry
191 zend_class_entry *php_http_request_datashare_class_entry;
192 zend_function_entry php_http_request_datashare_method_entry[] = {
193 PHP_HTTP_RSHARE_ME(__construct, ZEND_ACC_PRIVATE|ZEND_ACC_CTOR)
194 PHP_HTTP_RSHARE_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
195 PHP_HTTP_RSHARE_ME(count, ZEND_ACC_PUBLIC)
196 PHP_HTTP_RSHARE_ME(attach, ZEND_ACC_PUBLIC)
197 PHP_HTTP_RSHARE_ME(detach, ZEND_ACC_PUBLIC)
198 PHP_HTTP_RSHARE_ME(reset, ZEND_ACC_PUBLIC)
199 EMPTY_FUNCTION_ENTRY
200 };
201 static zend_object_handlers php_http_request_datashare_object_handlers;
202
203 zend_object_value php_http_request_datashare_object_new(zend_class_entry *ce TSRMLS_DC)
204 {
205 return php_http_request_datashare_object_new_ex(ce, NULL, NULL TSRMLS_CC);
206 }
207
208 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)
209 {
210 zend_object_value ov;
211 php_http_request_datashare_object_t *o;
212
213 o = ecalloc(1, sizeof(*o));
214 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
215 object_properties_init((zend_object *) o, ce);
216
217 if (share) {
218 o->share = share;
219 } else {
220 o->share = php_http_request_datashare_init(NULL, NULL, NULL, NULL, 0 TSRMLS_CC);
221 }
222
223 if (ptr) {
224 *ptr = o;
225 }
226
227 ov.handle = zend_objects_store_put(o, NULL, php_http_request_datashare_object_free, NULL TSRMLS_CC);
228 ov.handlers = &php_http_request_datashare_object_handlers;
229
230 return ov;
231 }
232
233 void php_http_request_datashare_object_free(void *object TSRMLS_DC)
234 {
235 php_http_request_datashare_object_t *o = (php_http_request_datashare_object_t *) object;
236
237 if (!o->share->persistent) {
238 php_http_request_datashare_free(&o->share);
239 }
240 zend_object_std_dtor((zend_object *) o);
241 efree(o);
242 }
243
244 static void php_http_request_datashare_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *literal_key TSRMLS_DC)
245 {
246 zend_property_info *pi;
247
248 if ((pi = zend_get_property_info(php_http_request_datashare_class_entry, member, 1 TSRMLS_CC))) {
249 zend_bool enable = i_zend_is_true(value);
250 php_http_request_datashare_setopt_opt_t opt;
251 php_http_request_datashare_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
252
253 if (!strcmp(pi->name, "cookie")) {
254 opt = PHP_HTTP_REQUEST_DATASHARE_OPT_COOKIES;
255 } else if (!strcmp(pi->name, "dns")) {
256 opt = PHP_HTTP_REQUEST_DATASHARE_OPT_RESOLVER;
257 } else {
258 return;
259 }
260
261 if (SUCCESS != php_http_request_datashare_setopt(obj->share, opt, &enable)) {
262 return;
263 }
264 }
265
266 zend_get_std_object_handlers()->write_property(object, member, value, literal_key TSRMLS_CC);
267 }
268
269 static zval **php_http_request_datashare_object_get_prop_ptr(zval *object, zval *member, const zend_literal *literal_key TSRMLS_DC)
270 {
271 zend_property_info *pi;
272
273 if ((pi = zend_get_property_info(php_http_request_datashare_class_entry, member, 1 TSRMLS_CC))) {
274 return &php_http_property_proxy_init(NULL, object, member TSRMLS_CC)->myself;
275 }
276
277 return zend_get_std_object_handlers()->get_property_ptr_ptr(object, member, literal_key TSRMLS_CC);
278 }
279
280
281 PHP_METHOD(HttpRequestDataShare, __construct)
282 {
283 with_error_handling(EH_THROW, php_http_exception_class_entry) {
284 zend_parse_parameters_none();
285 } end_error_handling();
286 }
287
288 PHP_METHOD(HttpRequestDataShare, __destruct)
289 {
290 php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
291
292 if (SUCCESS == zend_parse_parameters_none()) {
293 ; /* we always want to clean up */
294 }
295
296 php_http_request_datashare_reset(obj->share);
297 }
298
299 PHP_METHOD(HttpRequestDataShare, count)
300 {
301 if (SUCCESS == zend_parse_parameters_none()) {
302 php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
303
304 RETURN_LONG(zend_llist_count(PHP_HTTP_REQUEST_DATASHARE_REQUESTS(obj->share)));
305 }
306 RETURN_FALSE;
307 }
308
309
310 PHP_METHOD(HttpRequestDataShare, attach)
311 {
312 zval *request;
313
314 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_request_class_entry)) {
315 php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
316
317 RETURN_SUCCESS(php_http_request_datashare_attach(obj->share, request));
318 }
319 RETURN_FALSE;
320
321 }
322
323 PHP_METHOD(HttpRequestDataShare, detach)
324 {
325 zval *request;
326
327 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_request_class_entry)) {
328 php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
329
330 RETURN_SUCCESS(php_http_request_datashare_detach(obj->share, request));
331 }
332 RETURN_FALSE;
333 }
334
335 PHP_METHOD(HttpRequestDataShare, reset)
336 {
337 if (SUCCESS == zend_parse_parameters_none()) {
338 php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
339
340 php_http_request_datashare_reset(obj->share);
341 RETURN_TRUE;
342 }
343 RETURN_FALSE;
344 }
345
346 PHP_MINIT_FUNCTION(http_request_datashare)
347 {
348 PHP_HTTP_REGISTER_CLASS(http\\request, DataShare, http_request_datashare, php_http_object_class_entry, 0);
349 php_http_request_datashare_class_entry->create_object = php_http_request_datashare_object_new;
350 memcpy(&php_http_request_datashare_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
351 php_http_request_datashare_object_handlers.clone_obj = NULL;
352 php_http_request_datashare_object_handlers.write_property = php_http_request_datashare_object_write_prop;
353 php_http_request_datashare_object_handlers.get_property_ptr_ptr = php_http_request_datashare_object_get_prop_ptr;
354
355 zend_class_implements(php_http_request_datashare_class_entry TSRMLS_CC, 1, spl_ce_Countable);
356
357 zend_declare_property_null(php_http_request_datashare_class_entry, ZEND_STRL("instance"), (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
358 zend_declare_property_bool(php_http_request_datashare_class_entry, ZEND_STRL("cookie"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
359 zend_declare_property_bool(php_http_request_datashare_class_entry, ZEND_STRL("dns"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
360
361 #ifdef ZTS
362 php_http_request_datashare_global_shares_lock = tsrm_mutex_alloc();
363 #endif
364 zend_hash_init(&php_http_request_datashare_global_shares, 0, NULL, (dtor_func_t) php_http_request_datashare_free, 1);
365
366 return SUCCESS;
367 }
368
369 PHP_MSHUTDOWN_FUNCTION(http_request_datashare)
370 {
371 zend_hash_destroy(&php_http_request_datashare_global_shares);
372 #ifdef ZTS
373 tsrm_mutex_free(php_http_request_datashare_global_shares_lock);
374 #endif
375
376 return SUCCESS;
377 }
378
379 PHP_RINIT_FUNCTION(http_request_datashare)
380 {
381 zend_llist_init(&PHP_HTTP_G->request_datashare.requests, sizeof(zval *), php_http_request_datashare_global_requests_dtor, 0);
382
383 return SUCCESS;
384 }
385
386 PHP_RSHUTDOWN_FUNCTION(http_request_datashare)
387 {
388 zend_llist_destroy(&PHP_HTTP_G->request_datashare.requests);
389
390 return SUCCESS;
391 }
392