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-2007, Michael Wallner <mike@php.net> |
10 : +--------------------------------------------------------------------+
11 : */
12 :
13 : /* $Id: http_requestpool_object.c,v 1.49 2007/02/07 11:50:27 mike Exp $ */
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 220 : {
103 220 : HTTP_REGISTER_CLASS_EX(HttpRequestPool, http_requestpool_object, NULL, 0);
104 220 : http_requestpool_object_handlers.clone_obj = NULL;
105 :
106 : #if defined(HAVE_SPL) && !defined(WONKY)
107 220 : 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 220 : return SUCCESS;
113 : }
114 :
115 : zend_object_value _http_requestpool_object_new(zend_class_entry *ce TSRMLS_DC)
116 7 : {
117 : zend_object_value ov;
118 : http_requestpool_object *o;
119 :
120 7 : o = ecalloc(1, sizeof(http_requestpool_object));
121 7 : o->zo.ce = ce;
122 :
123 7 : http_request_pool_init(&o->pool);
124 :
125 7 : ALLOC_HASHTABLE(OBJ_PROP(o));
126 7 : zend_hash_init(OBJ_PROP(o), zend_hash_num_elements(&ce->default_properties), NULL, ZVAL_PTR_DTOR, 0);
127 7 : zend_hash_copy(OBJ_PROP(o), &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
128 :
129 7 : ov.handle = putObject(http_requestpool_object, o);
130 7 : ov.handlers = &http_requestpool_object_handlers;
131 :
132 7 : return ov;
133 : }
134 :
135 : void _http_requestpool_object_free(zend_object *object TSRMLS_DC)
136 7 : {
137 7 : http_requestpool_object *o = (http_requestpool_object *) object;
138 :
139 7 : http_request_pool_dtor(&o->pool);
140 7 : freeObject(o);
141 7 : }
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 52 : {
146 52 : ZVAL_ADDREF(*req);
147 52 : add_next_index_zval(array, *req);
148 52 : }
149 :
150 : /* ### USERLAND ### */
151 :
152 : /* {{{ proto void HttpRequestPool::__construct([HttpRequest request[, ...]])
153 : Creates a new HttpRequestPool object instance. */
154 : PHP_METHOD(HttpRequestPool, __construct)
155 6 : {
156 6 : int argc = ZEND_NUM_ARGS();
157 6 : zval ***argv = safe_emalloc(argc, sizeof(zval *), 0);
158 6 : getObject(http_requestpool_object, obj);
159 :
160 6 : SET_EH_THROW_HTTP();
161 6 : if (SUCCESS == zend_get_parameters_array_ex(argc, argv)) {
162 : int i;
163 :
164 19 : for (i = 0; i < argc; ++i) {
165 13 : if (Z_TYPE_PP(argv[i]) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(argv[i]), http_request_object_ce TSRMLS_CC)) {
166 13 : http_request_pool_attach(&obj->pool, *(argv[i]));
167 : }
168 : }
169 : }
170 6 : efree(argv);
171 6 : SET_EH_NORMAL();
172 6 : http_final(HTTP_EX_CE(request_pool));
173 6 : }
174 : /* }}} */
175 :
176 : /* {{{ proto void HttpRequestPool::__destruct()
177 : Clean up HttpRequestPool object. */
178 : PHP_METHOD(HttpRequestPool, __destruct)
179 7 : {
180 7 : getObject(http_requestpool_object, obj);
181 :
182 7 : NO_ARGS;
183 :
184 7 : http_request_pool_detach_all(&obj->pool);
185 7 : }
186 : /* }}} */
187 :
188 : /* {{{ proto void HttpRequestPool::reset()
189 : Detach all attached HttpRequest objects. */
190 : PHP_METHOD(HttpRequestPool, reset)
191 0 : {
192 0 : getObject(http_requestpool_object, obj);
193 :
194 0 : NO_ARGS;
195 :
196 0 : obj->iterator.pos = 0;
197 0 : http_request_pool_detach_all(&obj->pool);
198 0 : }
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 54 : {
204 : zval *request;
205 54 : STATUS status = FAILURE;
206 54 : getObject(http_requestpool_object, obj);
207 :
208 54 : SET_EH_THROW_HTTP();
209 54 : if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
210 58 : if (obj->iterator.pos > 0 && obj->iterator.pos < zend_llist_count(&obj->pool.handles)) {
211 4 : http_error(HE_THROW, HTTP_E_REQUEST_POOL, "Cannot attach to the HttpRequestPool while the iterator is active");
212 : } else {
213 50 : status = http_request_pool_attach(&obj->pool, request);
214 : }
215 : }
216 54 : SET_EH_NORMAL();
217 54 : 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 61 : {
225 : zval *request;
226 61 : STATUS status = FAILURE;
227 61 : getObject(http_requestpool_object, obj);
228 :
229 61 : SET_EH_THROW_HTTP();
230 61 : if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
231 61 : obj->iterator.pos = -1;
232 61 : status = http_request_pool_detach(&obj->pool, request);
233 : }
234 61 : SET_EH_NORMAL();
235 61 : 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 4 : {
243 : STATUS status;
244 4 : getObject(http_requestpool_object, obj);
245 :
246 4 : NO_ARGS;
247 :
248 4 : SET_EH_THROW_HTTP();
249 4 : status = http_request_pool_send(&obj->pool);
250 4 : SET_EH_NORMAL();
251 :
252 : /* rethrow as HttpRequestPoolException */
253 4 : http_final(HTTP_EX_CE(request_pool));
254 :
255 4 : 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 250 : {
263 250 : getObject(http_requestpool_object, obj);
264 :
265 250 : NO_ARGS;
266 :
267 250 : if (0 < http_request_pool_perform(&obj->pool)) {
268 248 : RETURN_TRUE;
269 : } else {
270 2 : RETURN_FALSE;
271 : }
272 : }
273 : /* }}} */
274 :
275 : /* {{{ proto protected bool HttpRequestPool::socketSelect() */
276 : PHP_METHOD(HttpRequestPool, socketSelect)
277 248 : {
278 248 : getObject(http_requestpool_object, obj);
279 :
280 248 : NO_ARGS;
281 :
282 248 : 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 17 : {
290 17 : NO_ARGS;
291 :
292 17 : if (return_value_used) {
293 17 : getObject(http_requestpool_object, obj);
294 17 : 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 14 : {
303 14 : NO_ARGS;
304 :
305 14 : if (return_value_used) {
306 14 : long pos = 0;
307 14 : zval **current = NULL;
308 : zend_llist_position lpos;
309 14 : getObject(http_requestpool_object, obj);
310 :
311 14 : if (obj->iterator.pos < zend_llist_count(&obj->pool.handles)) {
312 14 : for ( current = zend_llist_get_first_ex(&obj->pool.handles, &lpos);
313 44 : current && obj->iterator.pos != pos++;
314 16 : current = zend_llist_get_next_ex(&obj->pool.handles, &lpos));
315 14 : if (current) {
316 14 : RETURN_OBJECT(*current, 1);
317 : }
318 : }
319 0 : RETURN_NULL();
320 : }
321 : }
322 : /* }}} */
323 :
324 : /* {{{ proto int HttpRequestPool::key()
325 : Implements Iterator::key(). */
326 : PHP_METHOD(HttpRequestPool, key)
327 0 : {
328 0 : NO_ARGS;
329 :
330 0 : if (return_value_used) {
331 0 : getObject(http_requestpool_object, obj);
332 0 : RETURN_LONG(obj->iterator.pos);
333 : }
334 : }
335 : /* }}} */
336 :
337 : /* {{{ proto void HttpRequestPool::next()
338 : Implements Iterator::next(). */
339 : PHP_METHOD(HttpRequestPool, next)
340 14 : {
341 14 : NO_ARGS {
342 14 : getObject(http_requestpool_object, obj);
343 14 : ++(obj->iterator.pos);
344 : }
345 14 : }
346 : /* }}} */
347 :
348 : /* {{{ proto void HttpRequestPool::rewind()
349 : Implements Iterator::rewind(). */
350 : PHP_METHOD(HttpRequestPool, rewind)
351 3 : {
352 3 : NO_ARGS {
353 3 : getObject(http_requestpool_object, obj);
354 3 : obj->iterator.pos = 0;
355 : }
356 3 : }
357 : /* }}} */
358 :
359 : /* {{{ proto int HttpRequestPool::count()
360 : Implements Countable::count(). */
361 : PHP_METHOD(HttpRequestPool, count)
362 0 : {
363 0 : NO_ARGS {
364 0 : getObject(http_requestpool_object, obj);
365 0 : 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 1 : {
374 1 : getObject(http_requestpool_object, obj);
375 :
376 1 : NO_ARGS;
377 :
378 1 : array_init(return_value);
379 1 : 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 1 : }
383 : /* }}} */
384 :
385 : /* {{{ proto array HttpRequestPool::getFinishedRequests()
386 : Get attached HttpRequest objects that already have finished their work. */
387 : PHP_METHOD(HttpRequestPool, getFinishedRequests)
388 250 : {
389 250 : getObject(http_requestpool_object, obj);
390 :
391 250 : NO_ARGS;
392 :
393 250 : array_init(return_value);
394 250 : 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 250 : }
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 0 : {
404 0 : zend_bool enable = 1;
405 0 : getObject(http_requestpool_object, obj);
406 :
407 0 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable)) {
408 0 : 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 0 : 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 :
|