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