2 +--------------------------------------------------------------------+
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 +--------------------------------------------------------------------+
13 #include "php_http_api.h"
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)
17 php_http_request_pool_t *free_h = NULL;
20 free_h = h = emalloc(sizeof(*h));
22 memset(h, 0, sizeof(*h));
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);
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");
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)
44 if (from->ops->copy) {
45 return from->ops->copy(from, to);
51 PHP_HTTP_API void php_http_request_pool_dtor(php_http_request_pool_t *h)
57 zend_llist_clean(&h->requests.finished);
58 zend_llist_clean(&h->requests.attached);
60 php_http_resource_factory_free(&h->rf);
63 PHP_HTTP_API void php_http_request_pool_free(php_http_request_pool_t **h) {
65 php_http_request_pool_dtor(*h);
71 PHP_HTTP_API STATUS php_http_request_pool_attach(php_http_request_pool_t *h, zval *request)
73 TSRMLS_FETCH_FROM_CTX(h->ts);
78 php_http_message_body_t *body = NULL;
79 php_http_request_object_t *obj = zend_object_store_get_object(request TSRMLS_CC);
81 if (SUCCESS != php_http_request_object_requesthandler(obj, request, &m, &url, &body TSRMLS_CC)) {
84 if (SUCCESS == h->ops->attach(h, obj->request, m, url, body)) {
87 zend_llist_add_element(&h->requests.attached, &request);
96 static int php_http_request_pool_compare_handles(void *h1, void *h2)
98 return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
102 PHP_HTTP_API STATUS php_http_request_pool_detach(php_http_request_pool_t *h, zval *request)
104 TSRMLS_FETCH_FROM_CTX(h->ts);
106 if (h->ops->detach) {
107 php_http_request_object_t *obj = zend_object_store_get_object(request TSRMLS_CC);
109 if (SUCCESS == h->ops->detach(h, obj->request)) {
110 zend_llist_del_element(&h->requests.finished, request, php_http_request_pool_compare_handles);
111 zend_llist_del_element(&h->requests.attached, request, php_http_request_pool_compare_handles);
119 PHP_HTTP_API STATUS php_http_request_pool_wait(php_http_request_pool_t *h, struct timeval *custom_timeout)
122 return h->ops->wait(h, custom_timeout);
128 PHP_HTTP_API int php_http_request_pool_once(php_http_request_pool_t *h)
131 return h->ops->once(h);
137 PHP_HTTP_API STATUS php_http_request_pool_exec(php_http_request_pool_t *h)
140 return h->ops->exec(h);
146 static void detach(void *r, void *h TSRMLS_DC)
148 ((php_http_request_pool_t *) h)->ops->detach(h, ((php_http_request_object_t *) zend_object_store_get_object(*((zval **) r) TSRMLS_CC))->request);
151 PHP_HTTP_API void php_http_request_pool_reset(php_http_request_pool_t *h)
155 } else if (h->ops->detach) {
156 TSRMLS_FETCH_FROM_CTX(h->ts);
158 zend_llist_apply_with_argument(&h->requests.attached, detach, h TSRMLS_CC);
161 zend_llist_clean(&h->requests.attached);
162 zend_llist_clean(&h->requests.finished);
165 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)
167 if (h->ops->setopt) {
168 return h->ops->setopt(h, opt, arg);
174 PHP_HTTP_API void php_http_request_pool_requests(php_http_request_pool_t *h, zval ***attached, zval ***finished)
180 if ((count = zend_llist_count(&h->requests.attached))) {
181 *attached = ecalloc(count + 1 /* terminating NULL */, sizeof(zval *));
183 for (i = 0, handle = zend_llist_get_first(&h->requests.attached); handle; handle = zend_llist_get_next(&h->requests.attached)) {
185 (*attached)[i++] = *handle;
193 if ((count = zend_llist_count(&h->requests.finished))) {
194 *finished = ecalloc(count + 1 /* terminating NULL */, sizeof(zval *));
196 for (i = 0, handle = zend_llist_get_first(&h->requests.finished); handle; handle = zend_llist_get_next(&h->requests.finished)) {
198 (*finished)[i++] = *handle;
208 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpRequestPool, method, 0, req_args)
209 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpRequestPool, method, 0)
210 #define PHP_HTTP_REQPOOL_ME(method, visibility) PHP_ME(HttpRequestPool, method, PHP_HTTP_ARGS(HttpRequestPool, method), visibility)
212 PHP_HTTP_EMPTY_ARGS(__construct);
214 PHP_HTTP_EMPTY_ARGS(__destruct);
215 PHP_HTTP_EMPTY_ARGS(reset);
217 PHP_HTTP_BEGIN_ARGS(attach, 1)
218 PHP_HTTP_ARG_OBJ(http\\Request, request, 0)
221 PHP_HTTP_BEGIN_ARGS(detach, 1)
222 PHP_HTTP_ARG_OBJ(http\\Request, request, 0)
225 PHP_HTTP_EMPTY_ARGS(send);
226 PHP_HTTP_EMPTY_ARGS(once);
227 PHP_HTTP_BEGIN_ARGS(wait, 0)
228 PHP_HTTP_ARG_VAL(timeout, 0)
231 PHP_HTTP_EMPTY_ARGS(valid);
232 PHP_HTTP_EMPTY_ARGS(current);
233 PHP_HTTP_EMPTY_ARGS(key);
234 PHP_HTTP_EMPTY_ARGS(next);
235 PHP_HTTP_EMPTY_ARGS(rewind);
237 PHP_HTTP_EMPTY_ARGS(count);
239 PHP_HTTP_EMPTY_ARGS(getAttachedRequests);
240 PHP_HTTP_EMPTY_ARGS(getFinishedRequests);
242 PHP_HTTP_BEGIN_ARGS(enablePipelining, 0)
243 PHP_HTTP_ARG_VAL(enable, 0)
246 PHP_HTTP_BEGIN_ARGS(enableEvents, 0)
247 PHP_HTTP_ARG_VAL(enable, 0)
250 zend_class_entry *php_http_request_pool_class_entry;
251 zend_function_entry php_http_request_pool_method_entry[] = {
252 PHP_HTTP_REQPOOL_ME(__construct, ZEND_ACC_PRIVATE|ZEND_ACC_CTOR)
253 PHP_HTTP_REQPOOL_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
254 PHP_HTTP_REQPOOL_ME(attach, ZEND_ACC_PUBLIC)
255 PHP_HTTP_REQPOOL_ME(detach, ZEND_ACC_PUBLIC)
256 PHP_HTTP_REQPOOL_ME(send, ZEND_ACC_PUBLIC)
257 PHP_HTTP_REQPOOL_ME(reset, ZEND_ACC_PUBLIC)
259 PHP_HTTP_REQPOOL_ME(once, ZEND_ACC_PROTECTED)
260 PHP_HTTP_REQPOOL_ME(wait, ZEND_ACC_PROTECTED)
262 /* implements Iterator */
263 PHP_HTTP_REQPOOL_ME(valid, ZEND_ACC_PUBLIC)
264 PHP_HTTP_REQPOOL_ME(current, ZEND_ACC_PUBLIC)
265 PHP_HTTP_REQPOOL_ME(key, ZEND_ACC_PUBLIC)
266 PHP_HTTP_REQPOOL_ME(next, ZEND_ACC_PUBLIC)
267 PHP_HTTP_REQPOOL_ME(rewind, ZEND_ACC_PUBLIC)
269 /* implmenents Countable */
270 PHP_HTTP_REQPOOL_ME(count, ZEND_ACC_PUBLIC)
272 PHP_HTTP_REQPOOL_ME(getAttachedRequests, ZEND_ACC_PUBLIC)
273 PHP_HTTP_REQPOOL_ME(getFinishedRequests, ZEND_ACC_PUBLIC)
275 PHP_HTTP_REQPOOL_ME(enablePipelining, ZEND_ACC_PUBLIC)
276 PHP_HTTP_REQPOOL_ME(enableEvents, ZEND_ACC_PUBLIC)
280 static zend_object_handlers php_http_request_pool_object_handlers;
282 zend_object_value php_http_request_pool_object_new(zend_class_entry *ce TSRMLS_DC)
284 return php_http_request_pool_object_new_ex(ce, NULL, NULL TSRMLS_CC);
287 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)
289 zend_object_value ov;
290 php_http_request_pool_object_t *o;
292 o = ecalloc(1, sizeof(php_http_request_pool_object_t));
293 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
294 object_properties_init((zend_object *) o, ce);
296 if (!(o->pool = p)) {
297 o->pool = php_http_request_pool_init(NULL, NULL, NULL, NULL TSRMLS_CC);
304 ov.handle = zend_objects_store_put(o, NULL, php_http_request_pool_object_free, NULL TSRMLS_CC);
305 ov.handlers = &php_http_request_pool_object_handlers;
310 void php_http_request_pool_object_free(void *object TSRMLS_DC)
312 php_http_request_pool_object_t *o = (php_http_request_pool_object_t *) object;
314 php_http_request_pool_free(&o->pool);
315 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
319 static void php_http_request_pool_object_llist2array(zval **req, zval *array TSRMLS_DC)
322 add_next_index_zval(array, *req);
326 PHP_METHOD(HttpRequestPool, __construct)
328 with_error_handling(EH_THROW, php_http_exception_class_entry) {
329 zend_parse_parameters_none();
330 } end_error_handling();
333 PHP_METHOD(HttpRequestPool, __destruct)
335 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
337 if (SUCCESS != zend_parse_parameters_none()) {
338 ; /* we always want to clean up */
341 php_http_request_pool_reset(obj->pool);
344 PHP_METHOD(HttpRequestPool, reset)
346 if (SUCCESS == zend_parse_parameters_none()) {
347 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
349 obj->iterator.pos = 0;
350 php_http_request_pool_reset(obj->pool);
352 RETVAL_ZVAL(getThis(), 1, 0);
355 PHP_METHOD(HttpRequestPool, attach)
357 with_error_handling(EH_THROW, php_http_exception_class_entry) {
360 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_request_class_entry)) {
361 with_error_handling(EH_THROW, php_http_exception_class_entry) {
362 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
364 if (obj->iterator.pos > 0 && obj->iterator.pos < zend_llist_count(&obj->pool->requests.attached)) {
365 php_http_error(HE_THROW, PHP_HTTP_E_REQUEST_POOL, "Cannot attach to the HttpRequestPool while the iterator is active");
367 php_http_request_pool_attach(obj->pool, request);
369 } end_error_handling();
371 } end_error_handling();
373 RETVAL_ZVAL(getThis(), 1, 0);
376 PHP_METHOD(HttpRequestPool, detach)
380 with_error_handling(EH_THROW, php_http_exception_class_entry) {
383 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_request_class_entry)) {
384 with_error_handling(EH_THROW, php_http_exception_class_entry) {
385 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
387 obj->iterator.pos = -1;
388 php_http_request_pool_detach(obj->pool, request);
389 } end_error_handling();
391 } end_error_handling();
393 RETVAL_ZVAL(getThis(), 1, 0);
396 PHP_METHOD(HttpRequestPool, send)
400 with_error_handling(EH_THROW, php_http_exception_class_entry) {
401 if (SUCCESS == zend_parse_parameters_none()) {
402 with_error_handling(EH_THROW, php_http_exception_class_entry) {
403 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
405 php_http_request_pool_exec(obj->pool);
406 } end_error_handling();
408 } end_error_handling();
410 RETVAL_ZVAL(getThis(), 1, 0);
413 PHP_METHOD(HttpRequestPool, once)
415 if (SUCCESS == zend_parse_parameters_none()) {
416 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
418 if (0 < php_http_request_pool_once(obj->pool)) {
425 PHP_METHOD(HttpRequestPool, wait)
429 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|d", &timeout)) {
430 struct timeval timeout_val;
431 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
433 timeout_val.tv_sec = (time_t) timeout;
434 timeout_val.tv_usec = PHP_HTTP_USEC(timeout) % PHP_HTTP_MCROSEC;
436 RETURN_SUCCESS(php_http_request_pool_wait(obj->pool, timeout > 0 ? &timeout_val : NULL));
441 PHP_METHOD(HttpRequestPool, valid)
443 if (SUCCESS == zend_parse_parameters_none()) {
444 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
446 RETURN_BOOL(obj->iterator.pos >= 0 && obj->iterator.pos < zend_llist_count(&obj->pool->requests.attached));
451 PHP_METHOD(HttpRequestPool, current)
453 if (SUCCESS == zend_parse_parameters_none()) {
454 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
456 if (obj->iterator.pos < zend_llist_count(&obj->pool->requests.attached)) {
458 zval **current = NULL;
459 zend_llist_position lpos;
461 for ( current = zend_llist_get_first_ex(&obj->pool->requests.attached, &lpos);
462 current && obj->iterator.pos != pos++;
463 current = zend_llist_get_next_ex(&obj->pool->requests.attached, &lpos));
465 RETURN_OBJECT(*current, 1);
472 PHP_METHOD(HttpRequestPool, key)
474 if (SUCCESS == zend_parse_parameters_none()) {
475 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
477 RETURN_LONG(obj->iterator.pos);
482 PHP_METHOD(HttpRequestPool, next)
484 if (SUCCESS == zend_parse_parameters_none()) {
485 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
491 PHP_METHOD(HttpRequestPool, rewind)
493 if (SUCCESS == zend_parse_parameters_none()) {
494 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
496 obj->iterator.pos = 0;
500 PHP_METHOD(HttpRequestPool, count)
502 if (SUCCESS == zend_parse_parameters_none()) {
503 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
505 RETURN_LONG((long) zend_llist_count(&obj->pool->requests.attached));
509 PHP_METHOD(HttpRequestPool, getAttachedRequests)
511 if (SUCCESS == zend_parse_parameters_none()) {
512 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
514 array_init(return_value);
515 zend_llist_apply_with_argument(&obj->pool->requests.attached,
516 (llist_apply_with_arg_func_t) php_http_request_pool_object_llist2array,
517 return_value TSRMLS_CC);
523 PHP_METHOD(HttpRequestPool, getFinishedRequests)
525 if (SUCCESS == zend_parse_parameters_none()) {
526 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
528 array_init(return_value);
529 zend_llist_apply_with_argument(&obj->pool->requests.finished,
530 (llist_apply_with_arg_func_t) php_http_request_pool_object_llist2array,
531 return_value TSRMLS_CC);
537 PHP_METHOD(HttpRequestPool, enablePipelining)
539 zend_bool enable = 1;
541 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) {
542 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
544 php_http_request_pool_setopt(obj->pool, PHP_HTTP_REQUEST_POOL_OPT_ENABLE_PIPELINING, &enable);
546 RETVAL_ZVAL(getThis(), 1, 0);
549 PHP_METHOD(HttpRequestPool, enableEvents)
551 zend_bool enable = 1;
553 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) {
554 php_http_request_pool_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
556 php_http_request_pool_setopt(obj->pool, PHP_HTTP_REQUEST_POOL_OPT_USE_EVENTS, &enable);
558 RETVAL_ZVAL(getThis(), 1, 0);
561 PHP_MINIT_FUNCTION(http_request_pool)
563 PHP_HTTP_REGISTER_CLASS(http\\Request, Pool, http_request_pool, php_http_object_class_entry, 0);
564 php_http_request_pool_class_entry->create_object = php_http_request_pool_object_new;
565 memcpy(&php_http_request_pool_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
566 php_http_request_pool_object_handlers.clone_obj = NULL;
568 zend_class_implements(php_http_request_pool_class_entry TSRMLS_CC, 2, spl_ce_Countable, zend_ce_iterator);
579 * vim600: noet sw=4 ts=4 fdm=marker
580 * vim<600: noet sw=4 ts=4