- remove arginfo on ctor
[m6w6/ext-http] / http_requestpool_object.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-2006, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #define HTTP_WANT_CURL
16 #include "php_http.h"
17
18 #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
19
20 #include "zend_interfaces.h"
21
22 #include "php_http_api.h"
23 #include "php_http_exception_object.h"
24 #include "php_http_request_api.h"
25 #include "php_http_request_object.h"
26 #include "php_http_request_pool_api.h"
27 #include "php_http_requestpool_object.h"
28
29 #if defined(HAVE_SPL) && !defined(WONKY)
30 /* SPL doesn't install its headers */
31 extern PHPAPI zend_class_entry *spl_ce_Countable;
32 #endif
33
34 #define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpRequestPool, method, 0, req_args)
35 #define HTTP_EMPTY_ARGS(method) HTTP_EMPTY_ARGS_EX(HttpRequestPool, method, 0)
36 #define HTTP_REQPOOL_ME(method, visibility) PHP_ME(HttpRequestPool, method, HTTP_ARGS(HttpRequestPool, method), visibility)
37
38 HTTP_EMPTY_ARGS(__construct);
39
40 HTTP_EMPTY_ARGS(__destruct);
41 HTTP_EMPTY_ARGS(reset);
42
43 HTTP_BEGIN_ARGS(attach, 1)
44 HTTP_ARG_OBJ(HttpRequest, request, 0)
45 HTTP_END_ARGS;
46
47 HTTP_BEGIN_ARGS(detach, 1)
48 HTTP_ARG_OBJ(HttpRequest, request, 0)
49 HTTP_END_ARGS;
50
51 HTTP_EMPTY_ARGS(send);
52 HTTP_EMPTY_ARGS(socketPerform);
53 HTTP_EMPTY_ARGS(socketSelect);
54
55 HTTP_EMPTY_ARGS(valid);
56 HTTP_EMPTY_ARGS(current);
57 HTTP_EMPTY_ARGS(key);
58 HTTP_EMPTY_ARGS(next);
59 HTTP_EMPTY_ARGS(rewind);
60
61 HTTP_EMPTY_ARGS(count);
62
63 HTTP_EMPTY_ARGS(getAttachedRequests);
64 HTTP_EMPTY_ARGS(getFinishedRequests);
65
66 HTTP_BEGIN_ARGS(enablePipelining, 0)
67 HTTP_ARG_VAL(enable, 0)
68 HTTP_END_ARGS;
69
70 zend_class_entry *http_requestpool_object_ce;
71 zend_function_entry http_requestpool_object_fe[] = {
72 HTTP_REQPOOL_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
73 HTTP_REQPOOL_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
74 HTTP_REQPOOL_ME(attach, ZEND_ACC_PUBLIC)
75 HTTP_REQPOOL_ME(detach, ZEND_ACC_PUBLIC)
76 HTTP_REQPOOL_ME(send, ZEND_ACC_PUBLIC)
77 HTTP_REQPOOL_ME(reset, ZEND_ACC_PUBLIC)
78
79 HTTP_REQPOOL_ME(socketPerform, ZEND_ACC_PROTECTED)
80 HTTP_REQPOOL_ME(socketSelect, ZEND_ACC_PROTECTED)
81
82 /* implements Iterator */
83 HTTP_REQPOOL_ME(valid, ZEND_ACC_PUBLIC)
84 HTTP_REQPOOL_ME(current, ZEND_ACC_PUBLIC)
85 HTTP_REQPOOL_ME(key, ZEND_ACC_PUBLIC)
86 HTTP_REQPOOL_ME(next, ZEND_ACC_PUBLIC)
87 HTTP_REQPOOL_ME(rewind, ZEND_ACC_PUBLIC)
88
89 /* implmenents Countable */
90 HTTP_REQPOOL_ME(count, ZEND_ACC_PUBLIC)
91
92 HTTP_REQPOOL_ME(getAttachedRequests, ZEND_ACC_PUBLIC)
93 HTTP_REQPOOL_ME(getFinishedRequests, ZEND_ACC_PUBLIC)
94
95 HTTP_REQPOOL_ME(enablePipelining, ZEND_ACC_PUBLIC)
96
97 EMPTY_FUNCTION_ENTRY
98 };
99 static zend_object_handlers http_requestpool_object_handlers;
100
101 PHP_MINIT_FUNCTION(http_requestpool_object)
102 {
103 HTTP_REGISTER_CLASS_EX(HttpRequestPool, http_requestpool_object, NULL, 0);
104 http_requestpool_object_handlers.clone_obj = NULL;
105
106 #if defined(HAVE_SPL) && !defined(WONKY)
107 zend_class_implements(http_requestpool_object_ce TSRMLS_CC, 2, spl_ce_Countable, zend_ce_iterator);
108 #else
109 zend_class_implements(http_requestpool_object_ce TSRMLS_CC, 1, zend_ce_iterator);
110 #endif
111
112 return SUCCESS;
113 }
114
115 zend_object_value _http_requestpool_object_new(zend_class_entry *ce TSRMLS_DC)
116 {
117 zend_object_value ov;
118 http_requestpool_object *o;
119
120 o = ecalloc(1, sizeof(http_requestpool_object));
121 o->zo.ce = ce;
122
123 http_request_pool_init(&o->pool);
124
125 ALLOC_HASHTABLE(OBJ_PROP(o));
126 zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0);
127 zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
128
129 ov.handle = putObject(http_requestpool_object, o);
130 ov.handlers = &http_requestpool_object_handlers;
131
132 return ov;
133 }
134
135 void _http_requestpool_object_free(zend_object *object TSRMLS_DC)
136 {
137 http_requestpool_object *o = (http_requestpool_object *) object;
138
139 http_request_pool_dtor(&o->pool);
140 freeObject(o);
141 }
142
143 #define http_requestpool_object_llist2array _http_requestpool_object_llist2array
144 static void _http_requestpool_object_llist2array(zval **req, zval *array TSRMLS_DC)
145 {
146 ZVAL_ADDREF(*req);
147 add_next_index_zval(array, *req);
148 }
149
150 /* ### USERLAND ### */
151
152 /* {{{ proto void HttpRequestPool::__construct([HttpRequest request[, ...]])
153 Creates a new HttpRequestPool object instance. */
154 PHP_METHOD(HttpRequestPool, __construct)
155 {
156 int argc = ZEND_NUM_ARGS();
157 zval ***argv = safe_emalloc(argc, sizeof(zval *), 0);
158 getObject(http_requestpool_object, obj);
159
160 SET_EH_THROW_HTTP();
161 if (SUCCESS == zend_get_parameters_array_ex(argc, argv)) {
162 int i;
163
164 for (i = 0; i < argc; ++i) {
165 if (Z_TYPE_PP(argv[i]) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(argv[i]), http_request_object_ce TSRMLS_CC)) {
166 http_request_pool_attach(&obj->pool, *(argv[i]));
167 }
168 }
169 }
170 efree(argv);
171 SET_EH_NORMAL();
172 http_final(HTTP_EX_CE(request_pool));
173 }
174 /* }}} */
175
176 /* {{{ proto void HttpRequestPool::__destruct()
177 Clean up HttpRequestPool object. */
178 PHP_METHOD(HttpRequestPool, __destruct)
179 {
180 getObject(http_requestpool_object, obj);
181
182 NO_ARGS;
183
184 http_request_pool_detach_all(&obj->pool);
185 }
186 /* }}} */
187
188 /* {{{ proto void HttpRequestPool::reset()
189 Detach all attached HttpRequest objects. */
190 PHP_METHOD(HttpRequestPool, reset)
191 {
192 getObject(http_requestpool_object, obj);
193
194 NO_ARGS;
195
196 obj->iterator.pos = 0;
197 http_request_pool_detach_all(&obj->pool);
198 }
199
200 /* {{{ proto bool HttpRequestPool::attach(HttpRequest request)
201 Attach an HttpRequest object to this HttpRequestPool. WARNING: set all options prior attaching! */
202 PHP_METHOD(HttpRequestPool, attach)
203 {
204 zval *request;
205 STATUS status = FAILURE;
206 getObject(http_requestpool_object, obj);
207
208 SET_EH_THROW_HTTP();
209 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
210 if (obj->iterator.pos > 0 && obj->iterator.pos < zend_llist_count(&obj->pool.handles)) {
211 http_error(HE_THROW, HTTP_E_REQUEST_POOL, "Cannot attach to the HttpRequestPool while the iterator is active");
212 } else {
213 status = http_request_pool_attach(&obj->pool, request);
214 }
215 }
216 SET_EH_NORMAL();
217 RETURN_SUCCESS(status);
218 }
219 /* }}} */
220
221 /* {{{ proto bool HttpRequestPool::detach(HttpRequest request)
222 Detach an HttpRequest object from this HttpRequestPool. */
223 PHP_METHOD(HttpRequestPool, detach)
224 {
225 zval *request;
226 STATUS status = FAILURE;
227 getObject(http_requestpool_object, obj);
228
229 SET_EH_THROW_HTTP();
230 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
231 obj->iterator.pos = -1;
232 status = http_request_pool_detach(&obj->pool, request);
233 }
234 SET_EH_NORMAL();
235 RETURN_SUCCESS(status);
236 }
237 /* }}} */
238
239 /* {{{ proto bool HttpRequestPool::send()
240 Send all attached HttpRequest objects in parallel. */
241 PHP_METHOD(HttpRequestPool, send)
242 {
243 STATUS status;
244 getObject(http_requestpool_object, obj);
245
246 NO_ARGS;
247
248 SET_EH_THROW_HTTP();
249 status = http_request_pool_send(&obj->pool);
250 SET_EH_NORMAL();
251
252 /* rethrow as HttpRequestPoolException */
253 http_final(HTTP_EX_CE(request_pool));
254
255 RETURN_SUCCESS(status);
256 }
257 /* }}} */
258
259 /* {{{ proto protected bool HttpRequestPool::socketPerform()
260 Returns TRUE until each request has finished its transaction. */
261 PHP_METHOD(HttpRequestPool, socketPerform)
262 {
263 getObject(http_requestpool_object, obj);
264
265 NO_ARGS;
266
267 if (0 < http_request_pool_perform(&obj->pool)) {
268 RETURN_TRUE;
269 } else {
270 RETURN_FALSE;
271 }
272 }
273 /* }}} */
274
275 /* {{{ proto protected bool HttpRequestPool::socketSelect() */
276 PHP_METHOD(HttpRequestPool, socketSelect)
277 {
278 getObject(http_requestpool_object, obj);
279
280 NO_ARGS;
281
282 RETURN_SUCCESS(http_request_pool_select(&obj->pool));
283 }
284 /* }}} */
285
286 /* {{{ proto bool HttpRequestPool::valid()
287 Implements Iterator::valid(). */
288 PHP_METHOD(HttpRequestPool, valid)
289 {
290 NO_ARGS;
291
292 if (return_value_used) {
293 getObject(http_requestpool_object, obj);
294 RETURN_BOOL(obj->iterator.pos >= 0 && obj->iterator.pos < zend_llist_count(&obj->pool.handles));
295 }
296 }
297 /* }}} */
298
299 /* {{{ proto HttpRequest HttpRequestPool::current()
300 Implements Iterator::current(). */
301 PHP_METHOD(HttpRequestPool, current)
302 {
303 NO_ARGS;
304
305 if (return_value_used) {
306 long pos = 0;
307 zval **current = NULL;
308 zend_llist_position lpos;
309 getObject(http_requestpool_object, obj);
310
311 if (obj->iterator.pos < zend_llist_count(&obj->pool.handles)) {
312 for ( current = zend_llist_get_first_ex(&obj->pool.handles, &lpos);
313 current && obj->iterator.pos != pos++;
314 current = zend_llist_get_next_ex(&obj->pool.handles, &lpos));
315 if (current) {
316 RETURN_OBJECT(*current, 1);
317 }
318 }
319 RETURN_NULL();
320 }
321 }
322 /* }}} */
323
324 /* {{{ proto int HttpRequestPool::key()
325 Implements Iterator::key(). */
326 PHP_METHOD(HttpRequestPool, key)
327 {
328 NO_ARGS;
329
330 if (return_value_used) {
331 getObject(http_requestpool_object, obj);
332 RETURN_LONG(obj->iterator.pos);
333 }
334 }
335 /* }}} */
336
337 /* {{{ proto void HttpRequestPool::next()
338 Implements Iterator::next(). */
339 PHP_METHOD(HttpRequestPool, next)
340 {
341 NO_ARGS {
342 getObject(http_requestpool_object, obj);
343 ++(obj->iterator.pos);
344 }
345 }
346 /* }}} */
347
348 /* {{{ proto void HttpRequestPool::rewind()
349 Implements Iterator::rewind(). */
350 PHP_METHOD(HttpRequestPool, rewind)
351 {
352 NO_ARGS {
353 getObject(http_requestpool_object, obj);
354 obj->iterator.pos = 0;
355 }
356 }
357 /* }}} */
358
359 /* {{{ proto int HttpRequestPool::count()
360 Implements Countable::count(). */
361 PHP_METHOD(HttpRequestPool, count)
362 {
363 NO_ARGS {
364 getObject(http_requestpool_object, obj);
365 RETURN_LONG((long) zend_llist_count(&obj->pool.handles));
366 }
367 }
368 /* }}} */
369
370 /* {{{ proto array HttpRequestPool::getAttachedRequests()
371 Get attached HttpRequest objects. */
372 PHP_METHOD(HttpRequestPool, getAttachedRequests)
373 {
374 getObject(http_requestpool_object, obj);
375
376 NO_ARGS;
377
378 array_init(return_value);
379 zend_llist_apply_with_argument(&obj->pool.handles,
380 (llist_apply_with_arg_func_t) http_requestpool_object_llist2array,
381 return_value TSRMLS_CC);
382 }
383 /* }}} */
384
385 /* {{{ proto array HttpRequestPool::getFinishedRequests()
386 Get attached HttpRequest objects that already have finished their work. */
387 PHP_METHOD(HttpRequestPool, getFinishedRequests)
388 {
389 getObject(http_requestpool_object, obj);
390
391 NO_ARGS;
392
393 array_init(return_value);
394 zend_llist_apply_with_argument(&obj->pool.finished,
395 (llist_apply_with_arg_func_t) http_requestpool_object_llist2array,
396 return_value TSRMLS_CC);
397 }
398 /* }}} */
399
400 /* {{{ proto bool HttpRequest::enablePiplelinig([bool enable = true])
401 Enables pipelining support for all attached requests if support in libcurl is given. */
402 PHP_METHOD(HttpRequestPool, enablePipelining)
403 {
404 zend_bool enable = 1;
405 getObject(http_requestpool_object, obj);
406
407 if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) {
408 RETURN_FALSE;
409 }
410 #if defined(HAVE_CURL_MULTI_SETOPT) && HTTP_CURL_VERSION(7,16,0)
411 if (CURLM_OK == curl_multi_setopt(obj->pool.ch, CURLMOPT_PIPELINING, (long) enable)) {
412 RETURN_TRUE;
413 }
414 #endif
415 RETURN_FALSE;
416 }
417 /* }}} */
418
419 #endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
420
421 /*
422 * Local variables:
423 * tab-width: 4
424 * c-basic-offset: 4
425 * End:
426 * vim600: noet sw=4 ts=4 fdm=marker
427 * vim<600: noet sw=4 ts=4
428 */
429