header cleanups; fix IDE warnings
[m6w6/ext-http] / php_http_request_pool.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: http |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2011, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 #include "php_http_api.h"
14
15 PHP_HTTP_API php_http_request_pool_t *php_http_request_pool_init(php_http_request_pool_t *h, php_http_request_pool_ops_t *ops, php_http_resource_factory_t *rf, void *init_arg TSRMLS_DC)
16 {
17 php_http_request_pool_t *free_h = NULL;
18
19 if (!h) {
20 free_h = h = emalloc(sizeof(*h));
21 }
22 memset(h, 0, sizeof(*h));
23
24 h->ops = ops;
25 h->rf = rf ? rf : php_http_resource_factory_init(NULL, h->ops->rsrc, NULL, NULL);
26 zend_llist_init(&h->requests.attached, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0);
27 zend_llist_init(&h->requests.finished, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0);
28 TSRMLS_SET_CTX(h->ts);
29
30 if (h->ops->init) {
31 if (!(h = h->ops->init(h, init_arg))) {
32 php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_POOL, "Could not initialize request pool");
33 if (free_h) {
34 efree(h);
35 }
36 }
37 }
38
39 return h;
40 }
41
42 PHP_HTTP_API php_http_request_pool_t *php_http_request_pool_copy(php_http_request_pool_t *from, php_http_request_pool_t *to)
43 {
44 if (from->ops->copy) {
45 return from->ops->copy(from, to);
46 }
47
48 return NULL;
49 }
50
51 PHP_HTTP_API void php_http_request_pool_dtor(php_http_request_pool_t *h)
52 {
53 if (h->ops->dtor) {
54 h->ops->dtor(h);
55 }
56
57 zend_llist_clean(&h->requests.finished);
58 zend_llist_clean(&h->requests.attached);
59
60 if (h->persistent_handle_id) {
61 zval_ptr_dtor(&h->persistent_handle_id);
62 }
63
64 php_http_resource_factory_free(&h->rf);
65 }
66
67 PHP_HTTP_API void php_http_request_pool_free(php_http_request_pool_t **h) {
68 if (*h) {
69 php_http_request_pool_dtor(*h);
70 efree(*h);
71 *h = NULL;
72 }
73 }
74
75 PHP_HTTP_API STATUS php_http_request_pool_attach(php_http_request_pool_t *h, zval *request)
76 {
77 TSRMLS_FETCH_FROM_CTX(h->ts);
78
79 if (h->ops->attach) {
80 char *url = NULL;
81 php_http_request_method_t m = PHP_HTTP_NO_REQUEST_METHOD;
82 php_http_message_body_t *body = NULL;
83 php_http_request_object_t *obj = zend_object_store_get_object(request TSRMLS_CC);
84
85 if (SUCCESS != php_http_request_object_requesthandler(obj, request, &m, &url, &body TSRMLS_CC)) {
86 return FAILURE;
87 }
88 if (SUCCESS == h->ops->attach(h, obj->request, m, url, body)) {
89 STR_FREE(url);
90 Z_ADDREF_P(request);
91 zend_llist_add_element(&h->requests.attached, &request);
92 return SUCCESS;
93 }
94 STR_FREE(url);
95 }
96
97 return FAILURE;
98 }
99
100 static int php_http_request_pool_compare_handles(void *h1, void *h2)
101 {
102 return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
103 }
104
105
106 PHP_HTTP_API STATUS php_http_request_pool_detach(php_http_request_pool_t *h, zval *request)
107 {
108 TSRMLS_FETCH_FROM_CTX(h->ts);
109
110 if (h->ops->detach) {
111 php_http_request_object_t *obj = zend_object_store_get_object(request TSRMLS_CC);
112
113 if (SUCCESS == h->ops->detach(h, obj->request)) {
114 zend_llist_del_element(&h->requests.finished, request, php_http_request_pool_compare_handles);
115 zend_llist_del_element(&h->requests.attached, request, php_http_request_pool_compare_handles);
116 return SUCCESS;
117 }
118 }
119
120 return FAILURE;
121 }
122
123 PHP_HTTP_API STATUS php_http_request_pool_wait(php_http_request_pool_t *h, struct timeval *custom_timeout)
124 {
125 if (h->ops->wait) {
126 return h->ops->wait(h, custom_timeout);
127 }
128
129 return FAILURE;
130 }
131
132 PHP_HTTP_API int php_http_request_pool_once(php_http_request_pool_t *h)
133 {
134 if (h->ops->once) {
135 return h->ops->once(h);
136 }
137
138 return FAILURE;
139 }
140
141 PHP_HTTP_API STATUS php_http_request_pool_exec(php_http_request_pool_t *h)
142 {
143 if (h->ops->exec) {
144 return h->ops->exec(h);
145 }
146
147 return FAILURE;
148 }
149
150 static void detach(void *r, void *h TSRMLS_DC)
151 {
152 ((php_http_request_pool_t *) h)->ops->detach(h, ((php_http_request_object_t *) zend_object_store_get_object(*((zval **) r) TSRMLS_CC))->request);
153 }
154
155 PHP_HTTP_API void php_http_request_pool_reset(php_http_request_pool_t *h)
156 {
157 if (h->ops->reset) {
158 h->ops->reset(h);
159 } else if (h->ops->detach) {
160 TSRMLS_FETCH_FROM_CTX(h->ts);
161
162 zend_llist_apply_with_argument(&h->requests.attached, detach, h TSRMLS_CC);
163 }
164
165 zend_llist_clean(&h->requests.attached);
166 zend_llist_clean(&h->requests.finished);
167 }
168
169 PHP_HTTP_API STATUS php_http_request_pool_setopt(php_http_request_pool_t *h, php_http_request_pool_setopt_opt_t opt, void *arg)
170 {
171 if (h->ops->setopt) {
172 return h->ops->setopt(h, opt, arg);
173 }
174
175 return FAILURE;
176 }
177
178 PHP_HTTP_API void php_http_request_pool_requests(php_http_request_pool_t *h, zval ***attached, zval ***finished)
179 {
180 zval **handle;
181 int i, count;
182
183 if (attached) {
184 if ((count = zend_llist_count(&h->requests.attached))) {
185 *attached = ecalloc(count + 1 /* terminating NULL */, sizeof(zval *));
186
187 for (i = 0, handle = zend_llist_get_first(&h->requests.attached); handle; handle = zend_llist_get_next(&h->requests.attached)) {
188 Z_ADDREF_PP(handle);
189 (*attached)[i++] = *handle;
190 }
191 } else {
192 *attached = NULL;
193 }
194 }
195
196 if (finished) {
197 if ((count = zend_llist_count(&h->requests.finished))) {
198 *finished = ecalloc(count + 1 /* terminating NULL */, sizeof(zval *));
199
200 for (i = 0, handle = zend_llist_get_first(&h->requests.finished); handle; handle = zend_llist_get_next(&h->requests.finished)) {
201 Z_ADDREF_PP(handle);
202 (*finished)[i++] = *handle;
203 }
204 } else {
205 *finished = NULL;
206 }
207 }
208 }
209
210 /*#*/
211
212 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpRequestPool, method, 0, req_args)
213 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpRequestPool, method, 0)
214 #define PHP_HTTP_REQPOOL_ME(method, visibility) PHP_ME(HttpRequestPool, method, PHP_HTTP_ARGS(HttpRequestPool, method), visibility)
215
216 PHP_HTTP_EMPTY_ARGS(__construct);
217
218 PHP_HTTP_EMPTY_ARGS(__destruct);
219 PHP_HTTP_EMPTY_ARGS(reset);
220
221 PHP_HTTP_BEGIN_ARGS(attach, 1)
222 PHP_HTTP_ARG_OBJ(http\\Request, request, 0)
223 PHP_HTTP_END_ARGS;
224
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(send);
230 PHP_HTTP_EMPTY_ARGS(once);
231 PHP_HTTP_BEGIN_ARGS(wait, 0)
232 PHP_HTTP_ARG_VAL(timeout, 0)
233 PHP_HTTP_END_ARGS;
234
235 PHP_HTTP_EMPTY_ARGS(valid);
236 PHP_HTTP_EMPTY_ARGS(current);
237 PHP_HTTP_EMPTY_ARGS(key);
238 PHP_HTTP_EMPTY_ARGS(next);
239 PHP_HTTP_EMPTY_ARGS(rewind);
240
241 PHP_HTTP_EMPTY_ARGS(count);
242
243 PHP_HTTP_EMPTY_ARGS(getAttachedRequests);
244 PHP_HTTP_EMPTY_ARGS(getFinishedRequests);
245
246 PHP_HTTP_BEGIN_ARGS(enablePipelining, 0)
247 PHP_HTTP_ARG_VAL(enable, 0)
248 PHP_HTTP_END_ARGS;
249
250 PHP_HTTP_BEGIN_ARGS(enableEvents, 0)
251 PHP_HTTP_ARG_VAL(enable, 0)
252 PHP_HTTP_END_ARGS;
253
254 zend_class_entry *php_http_request_pool_class_entry;
255 zend_function_entry php_http_request_pool_method_entry[] = {
256 PHP_HTTP_REQPOOL_ME(__construct, ZEND_ACC_PRIVATE|ZEND_ACC_CTOR)
257 PHP_HTTP_REQPOOL_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
258 PHP_HTTP_REQPOOL_ME(attach, ZEND_ACC_PUBLIC)
259 PHP_HTTP_REQPOOL_ME(detach, ZEND_ACC_PUBLIC)
260 PHP_HTTP_REQPOOL_ME(send, ZEND_ACC_PUBLIC)
261 PHP_HTTP_REQPOOL_ME(reset, ZEND_ACC_PUBLIC)
262
263 PHP_HTTP_REQPOOL_ME(once, ZEND_ACC_PROTECTED)
264 PHP_HTTP_REQPOOL_ME(wait, ZEND_ACC_PROTECTED)
265
266 /* implements Iterator */
267 PHP_HTTP_REQPOOL_ME(valid, ZEND_ACC_PUBLIC)
268 PHP_HTTP_REQPOOL_ME(current, ZEND_ACC_PUBLIC)
269 PHP_HTTP_REQPOOL_ME(key, ZEND_ACC_PUBLIC)
270 PHP_HTTP_REQPOOL_ME(next, ZEND_ACC_PUBLIC)
271 PHP_HTTP_REQPOOL_ME(rewind, ZEND_ACC_PUBLIC)
272
273 /* implmenents Countable */
274 PHP_HTTP_REQPOOL_ME(count, ZEND_ACC_PUBLIC)
275
276 PHP_HTTP_REQPOOL_ME(getAttachedRequests, ZEND_ACC_PUBLIC)
277 PHP_HTTP_REQPOOL_ME(getFinishedRequests, ZEND_ACC_PUBLIC)
278
279 PHP_HTTP_REQPOOL_ME(enablePipelining, ZEND_ACC_PUBLIC)
280 PHP_HTTP_REQPOOL_ME(enableEvents, ZEND_ACC_PUBLIC)
281
282 EMPTY_FUNCTION_ENTRY
283 };
284 static zend_object_handlers php_http_request_pool_object_handlers;
285
286 zend_object_value php_http_request_pool_object_new(zend_class_entry *ce TSRMLS_DC)
287 {
288 return php_http_request_pool_object_new_ex(ce, NULL, NULL TSRMLS_CC);
289 }
290
291 zend_object_value php_http_request_pool_object_new_ex(zend_class_entry *ce, php_http_request_pool_t *p, php_http_request_pool_object_t **ptr TSRMLS_DC)
292 {
293 zend_object_value ov;
294 php_http_request_pool_object_t *o;
295
296 o = ecalloc(1, sizeof(php_http_request_pool_object_t));
297 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
298 object_properties_init((zend_object *) o, ce);
299
300 if (!(o->pool = p)) {
301 o->pool = php_http_request_pool_init(NULL, NULL, NULL, NULL TSRMLS_CC);
302 }
303
304 if (ptr) {
305 *ptr = o;
306 }
307
308 ov.handle = zend_objects_store_put(o, NULL, php_http_request_pool_object_free, NULL TSRMLS_CC);
309 ov.handlers = &php_http_request_pool_object_handlers;
310
311 return ov;
312 }
313
314 void php_http_request_pool_object_free(void *object TSRMLS_DC)
315 {
316 php_http_request_pool_object_t *o = (php_http_request_pool_object_t *) object;
317
318 php_http_request_pool_free(&o->pool);
319 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
320 efree(o);
321 }
322
323 static void php_http_request_pool_object_llist2array(zval **req, zval *array TSRMLS_DC)
324 {
325 Z_ADDREF_P(*req);
326 add_next_index_zval(array, *req);
327 }
328
329
330 PHP_METHOD(HttpRequestPool, __construct)
331 {
332 with_error_handling(EH_THROW, php_http_exception_class_entry) {
333 zend_parse_parameters_none();
334 } end_error_handling();
335 }
336
337 PHP_METHOD(HttpRequestPool, __destruct)
338 {
339 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
340
341 if (SUCCESS != zend_parse_parameters_none()) {
342 ; /* we always want to clean up */
343 }
344
345 php_http_request_pool_reset(obj->pool);
346 }
347
348 PHP_METHOD(HttpRequestPool, reset)
349 {
350 if (SUCCESS == zend_parse_parameters_none()) {
351 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
352
353 obj->iterator.pos = 0;
354 php_http_request_pool_reset(obj->pool);
355 }
356 RETVAL_ZVAL(getThis(), 1, 0);
357 }
358
359 PHP_METHOD(HttpRequestPool, attach)
360 {
361 with_error_handling(EH_THROW, php_http_exception_class_entry) {
362 zval *request;
363
364 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_request_class_entry)) {
365 with_error_handling(EH_THROW, php_http_exception_class_entry) {
366 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
367
368 if (obj->iterator.pos > 0 && obj->iterator.pos < zend_llist_count(&obj->pool->requests.attached)) {
369 php_http_error(HE_THROW, PHP_HTTP_E_REQUEST_POOL, "Cannot attach to the HttpRequestPool while the iterator is active");
370 } else {
371 php_http_request_pool_attach(obj->pool, request);
372 }
373 } end_error_handling();
374 }
375 } end_error_handling();
376
377 RETVAL_ZVAL(getThis(), 1, 0);
378 }
379
380 PHP_METHOD(HttpRequestPool, detach)
381 {
382 RETVAL_FALSE;
383
384 with_error_handling(EH_THROW, php_http_exception_class_entry) {
385 zval *request;
386
387 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_request_class_entry)) {
388 with_error_handling(EH_THROW, php_http_exception_class_entry) {
389 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
390
391 obj->iterator.pos = -1;
392 php_http_request_pool_detach(obj->pool, request);
393 } end_error_handling();
394 }
395 } end_error_handling();
396
397 RETVAL_ZVAL(getThis(), 1, 0);
398 }
399
400 PHP_METHOD(HttpRequestPool, send)
401 {
402 RETVAL_FALSE;
403
404 with_error_handling(EH_THROW, php_http_exception_class_entry) {
405 if (SUCCESS == zend_parse_parameters_none()) {
406 with_error_handling(EH_THROW, php_http_exception_class_entry) {
407 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
408
409 php_http_request_pool_exec(obj->pool);
410 } end_error_handling();
411 }
412 } end_error_handling();
413
414 RETVAL_ZVAL(getThis(), 1, 0);
415 }
416
417 PHP_METHOD(HttpRequestPool, once)
418 {
419 if (SUCCESS == zend_parse_parameters_none()) {
420 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
421
422 if (0 < php_http_request_pool_once(obj->pool)) {
423 RETURN_TRUE;
424 }
425 }
426 RETURN_FALSE;
427 }
428
429 PHP_METHOD(HttpRequestPool, wait)
430 {
431 double timeout = 0;
432
433 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|d", &timeout)) {
434 struct timeval timeout_val;
435 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
436
437 timeout_val.tv_sec = (time_t) timeout;
438 timeout_val.tv_usec = PHP_HTTP_USEC(timeout) % PHP_HTTP_MCROSEC;
439
440 RETURN_SUCCESS(php_http_request_pool_wait(obj->pool, timeout ? &timeout_val : NULL));
441 }
442 RETURN_FALSE;
443 }
444
445 PHP_METHOD(HttpRequestPool, valid)
446 {
447 if (SUCCESS == zend_parse_parameters_none()) {
448 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
449
450 RETURN_BOOL(obj->iterator.pos >= 0 && obj->iterator.pos < zend_llist_count(&obj->pool->requests.attached));
451 }
452 RETURN_FALSE;
453 }
454
455 PHP_METHOD(HttpRequestPool, current)
456 {
457 if (SUCCESS == zend_parse_parameters_none()) {
458 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
459
460 if (obj->iterator.pos < zend_llist_count(&obj->pool->requests.attached)) {
461 long pos = 0;
462 zval **current = NULL;
463 zend_llist_position lpos;
464
465 for ( current = zend_llist_get_first_ex(&obj->pool->requests.attached, &lpos);
466 current && obj->iterator.pos != pos++;
467 current = zend_llist_get_next_ex(&obj->pool->requests.attached, &lpos));
468 if (current) {
469 RETURN_OBJECT(*current, 1);
470 }
471 }
472 }
473 RETURN_FALSE;
474 }
475
476 PHP_METHOD(HttpRequestPool, key)
477 {
478 if (SUCCESS == zend_parse_parameters_none()) {
479 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
480
481 RETURN_LONG(obj->iterator.pos);
482 }
483 RETURN_FALSE;
484 }
485
486 PHP_METHOD(HttpRequestPool, next)
487 {
488 if (SUCCESS == zend_parse_parameters_none()) {
489 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
490
491 ++obj->iterator.pos;
492 }
493 }
494
495 PHP_METHOD(HttpRequestPool, rewind)
496 {
497 if (SUCCESS == zend_parse_parameters_none()) {
498 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
499
500 obj->iterator.pos = 0;
501 }
502 }
503
504 PHP_METHOD(HttpRequestPool, count)
505 {
506 if (SUCCESS == zend_parse_parameters_none()) {
507 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
508
509 RETURN_LONG((long) zend_llist_count(&obj->pool->requests.attached));
510 }
511 }
512
513 PHP_METHOD(HttpRequestPool, getAttachedRequests)
514 {
515 if (SUCCESS == zend_parse_parameters_none()) {
516 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
517
518 array_init(return_value);
519 zend_llist_apply_with_argument(&obj->pool->requests.attached,
520 (llist_apply_with_arg_func_t) php_http_request_pool_object_llist2array,
521 return_value TSRMLS_CC);
522 return;
523 }
524 RETURN_FALSE;
525 }
526
527 PHP_METHOD(HttpRequestPool, getFinishedRequests)
528 {
529 if (SUCCESS == zend_parse_parameters_none()) {
530 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
531
532 array_init(return_value);
533 zend_llist_apply_with_argument(&obj->pool->requests.finished,
534 (llist_apply_with_arg_func_t) php_http_request_pool_object_llist2array,
535 return_value TSRMLS_CC);
536 return;
537 }
538 RETURN_FALSE;
539 }
540
541 PHP_METHOD(HttpRequestPool, enablePipelining)
542 {
543 zend_bool enable = 1;
544
545 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) {
546 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
547
548 php_http_request_pool_setopt(obj->pool, PHP_HTTP_REQUEST_POOL_OPT_ENABLE_PIPELINING, &enable);
549 }
550 RETVAL_ZVAL(getThis(), 1, 0);
551 }
552
553 PHP_METHOD(HttpRequestPool, enableEvents)
554 {
555 zend_bool enable = 1;
556
557 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) {
558 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
559
560 php_http_request_pool_setopt(obj->pool, PHP_HTTP_REQUEST_POOL_OPT_USE_EVENTS, &enable);
561 }
562 RETVAL_ZVAL(getThis(), 1, 0);
563 }
564
565 PHP_MINIT_FUNCTION(http_request_pool)
566 {
567 PHP_HTTP_REGISTER_CLASS(http\\Request, Pool, http_request_pool, php_http_object_class_entry, 0);
568 php_http_request_pool_class_entry->create_object = php_http_request_pool_object_new;
569 memcpy(&php_http_request_pool_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
570 php_http_request_pool_object_handlers.clone_obj = NULL;
571
572 zend_class_implements(php_http_request_pool_class_entry TSRMLS_CC, 2, spl_ce_Countable, zend_ce_iterator);
573
574 return SUCCESS;
575 }
576
577
578 /*
579 * Local variables:
580 * tab-width: 4
581 * c-basic-offset: 4
582 * End:
583 * vim600: noet sw=4 ts=4 fdm=marker
584 * vim<600: noet sw=4 ts=4
585 */
586