- proper fallthrough in zend_update_static_property()
[m6w6/ext-http] / http_requestpool_object.c
1 /*
2 +----------------------------------------------------------------------+
3 | PECL :: http |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.0 of the PHP license, that |
6 | is bundled with this package in the file LICENSE, and is available |
7 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
8 | If you did not receive a copy of the PHP license and are unable to |
9 | obtain it through the world-wide-web, please send a note to |
10 | license@php.net so we can mail you a copy immediately. |
11 +----------------------------------------------------------------------+
12 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
13 +----------------------------------------------------------------------+
14 */
15
16 /* $Id$ */
17
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22 #include "php.h"
23
24 #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
25
26 #include "php_http_std_defs.h"
27 #include "php_http_requestpool_object.h"
28 #include "php_http_request_pool_api.h"
29 #include "php_http_request_object.h"
30 #include "php_http_exception_object.h"
31
32 #include "zend_interfaces.h"
33
34 #ifdef PHP_WIN32
35 # include <winsock2.h>
36 #endif
37 #include <curl/curl.h>
38
39 #define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpRequestPool, method, 0, req_args)
40 #define HTTP_EMPTY_ARGS(method, ret_ref) HTTP_EMPTY_ARGS_EX(HttpRequestPool, method, ret_ref)
41 #define HTTP_REQPOOL_ME(method, visibility) PHP_ME(HttpRequestPool, method, HTTP_ARGS(HttpRequestPool, method), visibility)
42
43 HTTP_BEGIN_ARGS_AR(HttpRequestPool, __construct, 0, 0)
44 HTTP_ARG_OBJ(HttpRequest, request0, 0)
45 HTTP_ARG_OBJ(HttpRequest, request1, 0)
46 HTTP_ARG_OBJ(HttpRequest, requestN, 0)
47 HTTP_END_ARGS;
48
49 HTTP_EMPTY_ARGS(__destruct, 0);
50 HTTP_EMPTY_ARGS(reset, 0);
51
52 HTTP_BEGIN_ARGS(attach, 1)
53 HTTP_ARG_OBJ(HttpRequest, request, 0)
54 HTTP_END_ARGS;
55
56 HTTP_BEGIN_ARGS(detach, 1)
57 HTTP_ARG_OBJ(HttpRequest, request, 0)
58 HTTP_END_ARGS;
59
60 HTTP_EMPTY_ARGS(send, 0);
61 HTTP_EMPTY_ARGS(socketSend, 0);
62 HTTP_EMPTY_ARGS(socketSelect, 0);
63 HTTP_EMPTY_ARGS(socketRead, 0);
64
65 HTTP_EMPTY_ARGS(valid, 0);
66 HTTP_EMPTY_ARGS(current, 1);
67 HTTP_EMPTY_ARGS(key, 0);
68 HTTP_EMPTY_ARGS(next, 0);
69 HTTP_EMPTY_ARGS(rewind, 0);
70
71 #define http_requestpool_object_declare_default_properties() _http_requestpool_object_declare_default_properties(TSRMLS_C)
72 static inline void _http_requestpool_object_declare_default_properties(TSRMLS_D);
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(socketSend, ZEND_ACC_PROTECTED)
84 HTTP_REQPOOL_ME(socketSelect, ZEND_ACC_PROTECTED)
85 HTTP_REQPOOL_ME(socketRead, ZEND_ACC_PROTECTED)
86
87 /* implements Interator */
88 HTTP_REQPOOL_ME(valid, ZEND_ACC_PUBLIC)
89 HTTP_REQPOOL_ME(current, ZEND_ACC_PUBLIC)
90 HTTP_REQPOOL_ME(key, ZEND_ACC_PUBLIC)
91 HTTP_REQPOOL_ME(next, ZEND_ACC_PUBLIC)
92 HTTP_REQPOOL_ME(rewind, ZEND_ACC_PUBLIC)
93
94 {NULL, NULL, NULL}
95 };
96 static zend_object_handlers http_requestpool_object_handlers;
97
98 void _http_requestpool_object_init(INIT_FUNC_ARGS)
99 {
100 HTTP_REGISTER_CLASS_EX(HttpRequestPool, http_requestpool_object, NULL, 0);
101 zend_class_implements(http_requestpool_object_ce TSRMLS_CC, 1, zend_ce_iterator);
102 }
103
104 zend_object_value _http_requestpool_object_new(zend_class_entry *ce TSRMLS_DC)
105 {
106 zend_object_value ov;
107 http_requestpool_object *o;
108
109 o = ecalloc(1, sizeof(http_requestpool_object));
110 o->zo.ce = ce;
111
112 http_request_pool_init(&o->pool);
113 o->iterator.pos = 0;
114
115 ALLOC_HASHTABLE(OBJ_PROP(o));
116 zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
117 zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
118
119 ov.handle = putObject(http_requestpool_object, o);
120 ov.handlers = &http_requestpool_object_handlers;
121
122 return ov;
123 }
124
125 static inline void _http_requestpool_object_declare_default_properties(TSRMLS_D)
126 {
127 zend_class_entry *ce = http_requestpool_object_ce;
128
129 DCL_PROP_N(PROTECTED, pool);
130 }
131
132 void _http_requestpool_object_free(zend_object *object TSRMLS_DC)
133 {
134 http_requestpool_object *o = (http_requestpool_object *) object;
135
136 if (OBJ_PROP(o)) {
137 zend_hash_destroy(OBJ_PROP(o));
138 FREE_HASHTABLE(OBJ_PROP(o));
139 }
140 http_request_pool_dtor(&o->pool);
141 efree(o);
142 }
143
144 /* ### USERLAND ### */
145
146 /* {{{ proto void HttpRequestPool::__construct([HttpRequest request[, ...]])
147 *
148 * Instantiate a new HttpRequestPool object. An HttpRequestPool is
149 * able to send several HttpRequests in parallel.
150 *
151 * Example:
152 * <pre>
153 * <?php
154 * try {
155 * $pool = new HttpRequestPool(
156 * new HttpRequest('http://www.google.com/', HTTP_HEAD),
157 * new HttpRequest('http://www.php.net/', HTTP_HEAD)
158 * );
159 * $pool->send();
160 * foreach($pool as $request) {
161 * printf("%s is %s (%d)\n",
162 * $request->getUrl(),
163 * $request->getResponseCode() ? 'alive' : 'not alive',
164 * $request->getResponseCode()
165 * );
166 * }
167 * } catch (HttpException $e) {
168 * echo $e;
169 * }
170 * ?>
171 * </pre>
172 */
173 PHP_METHOD(HttpRequestPool, __construct)
174 {
175 int argc = ZEND_NUM_ARGS();
176 zval ***argv = safe_emalloc(argc, sizeof(zval *), 0);
177 getObject(http_requestpool_object, obj);
178
179 if (SUCCESS == zend_get_parameters_array_ex(argc, argv)) {
180 int i;
181
182 for (i = 0; i < argc; ++i) {
183 if (Z_TYPE_PP(argv[i]) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(argv[i]), http_request_object_ce TSRMLS_CC)) {
184 http_request_pool_attach(&obj->pool, *(argv[i]));
185 }
186 }
187 }
188 efree(argv);
189 }
190 /* }}} */
191
192 /* {{{ proto void HttpRequestPool::__destruct()
193 *
194 * Clean up HttpRequestPool object.
195 */
196 PHP_METHOD(HttpRequestPool, __destruct)
197 {
198 getObject(http_requestpool_object, obj);
199
200 NO_ARGS;
201
202 http_request_pool_detach_all(&obj->pool);
203 }
204 /* }}} */
205
206 /* {{{ proto void HttpRequestPool::reset()
207 *
208 * Detach all attached HttpRequest objects.
209 */
210 PHP_METHOD(HttpRequestPool, reset)
211 {
212 getObject(http_requestpool_object, obj);
213
214 NO_ARGS;
215
216 http_request_pool_detach_all(&obj->pool);
217 }
218
219 /* {{{ proto bool HttpRequestPool::attach(HttpRequest request)
220 *
221 * Attach an HttpRequest object to this HttpRequestPool.
222 * NOTE: set all options prior attaching!
223 */
224 PHP_METHOD(HttpRequestPool, attach)
225 {
226 zval *request;
227 STATUS status = FAILURE;
228 getObject(http_requestpool_object, obj);
229
230 SET_EH_THROW_HTTP();
231 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
232 status = http_request_pool_attach(&obj->pool, request);
233 }
234 SET_EH_NORMAL();
235 RETURN_SUCCESS(status);
236 }
237 /* }}} */
238
239 /* {{{ proto bool HttpRequestPool::detach(HttpRequest request)
240 *
241 * Detach an HttpRequest object from this HttpRequestPool.
242 */
243 PHP_METHOD(HttpRequestPool, detach)
244 {
245 zval *request;
246 STATUS status = FAILURE;
247 getObject(http_requestpool_object, obj);
248
249 SET_EH_THROW_HTTP();
250 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
251 status = http_request_pool_detach(&obj->pool, request);
252 }
253 SET_EH_NORMAL();
254 RETURN_SUCCESS(status);
255 }
256 /* }}} */
257
258 /* {{{ proto bool HttpRequestPool::send()
259 *
260 * Send all attached HttpRequest objects in parallel.
261 */
262 PHP_METHOD(HttpRequestPool, send)
263 {
264 STATUS status;
265 getObject(http_requestpool_object, obj);
266
267 NO_ARGS;
268
269 SET_EH_THROW_HTTP();
270 status = http_request_pool_send(&obj->pool);
271 SET_EH_NORMAL();
272
273 RETURN_SUCCESS(status);
274 }
275 /* }}} */
276
277 /* {{{ proto protected bool HttpRequestPool::socketSend()
278 *
279 * Usage:
280 * <pre>
281 * <?php
282 * while ($pool->socketSend()) {
283 * do_something_else();
284 * if (!$pool->socketSelect()) {
285 * die('Socket error');
286 * }
287 * }
288 * $pool->socketRead();
289 * ?>
290 * </pre>
291 */
292 PHP_METHOD(HttpRequestPool, socketSend)
293 {
294 getObject(http_requestpool_object, obj);
295
296 NO_ARGS;
297
298 RETURN_BOOL(0 < http_request_pool_perform(&obj->pool));
299 }
300 /* }}} */
301
302 /* {{{ proto protected bool HttpRequestPool::socketSelect()
303 *
304 * See HttpRequestPool::socketSend().
305 */
306 PHP_METHOD(HttpRequestPool, socketSelect)
307 {
308 getObject(http_requestpool_object, obj);
309
310 NO_ARGS;
311
312 RETURN_SUCCESS(http_request_pool_select(&obj->pool));
313 }
314 /* }}} */
315
316 /* {{{ proto protected void HttpRequestPool::socketRead()
317 *
318 * See HttpRequestPool::socketSend().
319 */
320 PHP_METHOD(HttpRequestPool, socketRead)
321 {
322 getObject(http_requestpool_object, obj);
323
324 NO_ARGS;
325
326 zend_llist_apply(&obj->pool.handles, (llist_apply_func_t) http_request_pool_responsehandler TSRMLS_CC);
327 }
328 /* }}} */
329
330 /* implements Iterator */
331
332 /* {{{ proto bool HttpRequestPool::valid()
333 *
334 * Implements Iterator::valid().
335 */
336 PHP_METHOD(HttpRequestPool, valid)
337 {
338 NO_ARGS;
339
340 IF_RETVAL_USED {
341 getObject(http_requestpool_object, obj);
342 RETURN_BOOL(obj->iterator.pos < zend_llist_count(&obj->pool.handles));
343 }
344 }
345 /* }}} */
346
347 /* {{{ proto HttpRequest HttpRequestPool::current()
348 *
349 * Implements Iterator::current().
350 */
351 PHP_METHOD(HttpRequestPool, current)
352 {
353 NO_ARGS;
354
355 IF_RETVAL_USED {
356 long pos = 0;
357 zval **current = NULL;
358 zend_llist_position lpos;
359 getObject(http_requestpool_object, obj);
360
361 if (obj->iterator.pos < zend_llist_count(&obj->pool.handles)) {
362 for ( current = zend_llist_get_first_ex(&obj->pool.handles, &lpos);
363 current && obj->iterator.pos != pos++;
364 current = zend_llist_get_next_ex(&obj->pool.handles, &lpos));
365 if (current) {
366 RETURN_OBJECT(*current);
367 }
368 }
369 RETURN_NULL();
370 }
371 }
372 /* }}} */
373
374 /* {{{ proto long HttpRequestPool::key()
375 *
376 * Implements Iterator::key().
377 */
378 PHP_METHOD(HttpRequestPool, key)
379 {
380 NO_ARGS;
381
382 IF_RETVAL_USED {
383 getObject(http_requestpool_object, obj);
384 RETURN_LONG(obj->iterator.pos);
385 }
386 }
387 /* }}} */
388
389 /* {{{ proto void HttpRequestPool::next()
390 *
391 * Implements Iterator::next().
392 */
393 PHP_METHOD(HttpRequestPool, next)
394 {
395 NO_ARGS {
396 getObject(http_requestpool_object, obj);
397 ++(obj->iterator.pos);
398 }
399 }
400 /* }}} */
401
402 /* {{{ proto void HttpRequestPool::rewind()
403 *
404 * Implements Iterator::rewind().
405 */
406 PHP_METHOD(HttpRequestPool, rewind)
407 {
408 NO_ARGS {
409 getObject(http_requestpool_object, obj);
410 obj->iterator.pos = 0;
411 }
412 }
413 /* }}} */
414
415 #endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
416
417 /*
418 * Local variables:
419 * tab-width: 4
420 * c-basic-offset: 4
421 * End:
422 * vim600: noet sw=4 ts=4 fdm=marker
423 * vim<600: noet sw=4 ts=4
424 */
425