- added http_get_request_body()
[m6w6/ext-http] / http_request_pool_api.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 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
21
22 #include "php.h"
23 #include "php_http.h"
24 #include "php_http_std_defs.h"
25 #include "php_http_api.h"
26 #include "php_http_request_api.h"
27 #include "php_http_request_pool_api.h"
28 #include "php_http_request_object.h"
29 #include "php_http_requestpool_object.h"
30
31 #ifdef ZEND_ENGINE_2
32
33 #ifndef HTTP_DEBUG_REQPOOLS
34 # define HTTP_DEBUG_REQPOOLS 0
35 #endif
36
37 static void http_request_pool_freebody(http_request_body **body);
38 static int http_request_pool_compare_handles(void *h1, void *h2);
39
40 /* {{{ http_request_pool *http_request_pool_init(http_request_pool *) */
41 PHP_HTTP_API http_request_pool *_http_request_pool_init(http_request_pool *pool TSRMLS_DC)
42 {
43 zend_bool free_pool;
44 #if HTTP_DEBUG_REQPOOLS
45 fprintf(stderr, "Initializing request pool\n");
46 #endif
47 if ((free_pool = (!pool))) {
48 pool = emalloc(sizeof(http_request_pool));
49 pool->ch = NULL;
50 }
51
52 if (!pool->ch) {
53 if (!(pool->ch = curl_multi_init())) {
54 http_error(E_WARNING, HTTP_E_CURL, "Could not initialize curl");
55 if (free_pool) {
56 efree(pool);
57 }
58 return NULL;
59 }
60 }
61
62 pool->unfinished = 0;
63 zend_llist_init(&pool->handles, sizeof(zval *), (llist_dtor_func_t) ZVAL_PTR_DTOR, 0);
64 zend_llist_init(&pool->bodies, sizeof(http_request_body *), (llist_dtor_func_t) http_request_pool_freebody, 0);
65 #if HTTP_DEBUG_REQPOOLS
66 fprintf(stderr, "Initialized request pool %p\n", pool);
67 #endif
68 return pool;
69 }
70 /* }}} */
71
72 /* {{{ STATUS http_request_pool_attach(http_request_pool *, zval *) */
73 PHP_HTTP_API STATUS _http_request_pool_attach(http_request_pool *pool, zval *request TSRMLS_DC)
74 {
75 getObjectEx(http_request_object, req, request);
76 #if HTTP_DEBUG_REQPOOLS
77 fprintf(stderr, "Attaching request %p to pool %p\n", req, pool);
78 #endif
79 if (req->pool) {
80 http_error(E_WARNING, HTTP_E_CURL, "HttpRequest object is already member of an HttpRequestPool");
81 } else {
82 CURLMcode code;
83 http_request_body *body = http_request_body_new();
84 zval *info = GET_PROP_EX(req, request, responseInfo);
85
86 if (SUCCESS != http_request_object_requesthandler(req, request, body)) {
87 http_error_ex(E_WARNING, HTTP_E_CURL, "Could not initialize HttpRequest object for attaching to the HttpRequestPool");
88 } else {
89 code = curl_multi_add_handle(pool->ch, req->ch);
90 if ((CURLM_OK != code) && (CURLM_CALL_MULTI_PERFORM != code)) {
91 http_error_ex(E_WARNING, HTTP_E_CURL, "Could not attach HttpRequest object to the HttpRequestPool: %s", curl_multi_strerror(code));
92 } else {
93 req->pool = pool;
94 zend_llist_add_element(&pool->handles, &request);
95 zend_llist_add_element(&pool->bodies, &body);
96 zval_add_ref(&request);
97 return SUCCESS;
98 }
99 }
100 efree(body);
101 }
102 return FAILURE;
103 }
104 /* }}} */
105
106 /* {{{ STATUS http_request_pool_detach(http_request_pool *, zval *) */
107 PHP_HTTP_API STATUS _http_request_pool_detach(http_request_pool *pool, zval *request TSRMLS_DC)
108 {
109 getObjectEx(http_request_object, req, request);
110 #if HTTP_DEBUG_REQPOOLS
111 fprintf(stderr, "Detaching request %p from pool %p\n", req, pool);
112 #endif
113 if (req->pool != pool) {
114 http_error(E_WARNING, HTTP_E_CURL, "HttpRequest object is not attached to this HttpRequestPool");
115 } else {
116 CURLMcode code;
117
118 if (CURLM_OK != (code = curl_multi_remove_handle(pool->ch, req->ch))) {
119 http_error_ex(E_WARNING, HTTP_E_CURL, "Could not detach HttpRequest object from the HttpRequestPool: %s", curl_multi_strerror(code));
120 } else {
121 req->pool = NULL;
122 zend_llist_del_element(&pool->handles, request, http_request_pool_compare_handles);
123 return SUCCESS;
124 }
125 }
126 return FAILURE;
127 }
128 /* }}} */
129
130 /* {{{ void http_request_pool_detach_all(http_request_pool *) */
131 PHP_HTTP_API void _http_request_pool_detach_all(http_request_pool *pool TSRMLS_DC)
132 {
133 int count = zend_llist_count(&pool->handles);
134 #if HTTP_DEBUG_REQPOOLS
135 fprintf(stderr, "Detaching %d requests from pool %p\n", count, pool);
136 #endif
137 /*
138 * we cannot apply a function to the llist which actually detaches
139 * the curl handle *and* removes the llist element --
140 * so let's get our hands dirty
141 */
142 if (count) {
143 int i = 0;
144 zend_llist_position pos;
145 zval **handle, **handles = emalloc(count * sizeof(zval *));
146
147 for (handle = zend_llist_get_first_ex(&pool->handles, &pos); handle; handle = zend_llist_get_next_ex(&pool->handles, &pos)) {
148 handles[i++] = *handle;
149 }
150 for (i = 0; i < count; ++i) {
151 http_request_pool_detach(pool, handles[i]);
152 }
153 efree(handles);
154 }
155 }
156
157
158 /* {{{ STATUS http_request_pool_send(http_request_pool *) */
159 PHP_HTTP_API STATUS _http_request_pool_send(http_request_pool *pool TSRMLS_DC)
160 {
161 #if HTTP_DEBUG_REQPOOLS
162 fprintf(stderr, "Attempt to send %d requests of pool %p\n", zend_llist_count(&pool->handles), pool);
163 #endif
164 while (http_request_pool_perform(pool)) {
165 #if HTTP_DEBUG_REQPOOLS
166 fprintf(stderr, "%d unfinished requests of pool %p remaining\n", pool->unfinished, pool);
167 #endif
168 if (SUCCESS != http_request_pool_select(pool)) {
169 http_error(E_WARNING, HTTP_E_CURL, "Socket error");
170 return FAILURE;
171 }
172 }
173 zend_llist_apply(&pool->handles, (llist_apply_func_t) http_request_pool_responsehandler TSRMLS_CC);
174 return SUCCESS;
175 }
176 /* }}} */
177
178 /* {{{ void http_request_pool_dtor(http_request_pool *) */
179 PHP_HTTP_API void _http_request_pool_dtor(http_request_pool *pool TSRMLS_DC)
180 {
181 #if HTTP_DEBUG_REQPOOLS
182 fprintf(stderr, "Destructing request pool %p\n", pool);
183 #endif
184 pool->unfinished = 0;
185 zend_llist_clean(&pool->handles);
186 zend_llist_clean(&pool->bodies);
187 curl_multi_cleanup(pool->ch);
188 }
189 /* }}} */
190
191 /* {{{ STATUS http_request_pool_select(http_request_pool *) */
192 PHP_HTTP_API STATUS _http_request_pool_select(http_request_pool *pool)
193 {
194 int MAX;
195 fd_set R, W, E;
196 struct timeval timeout = {1, 0};
197
198 FD_ZERO(&R);
199 FD_ZERO(&W);
200 FD_ZERO(&E);
201
202 curl_multi_fdset(pool->ch, &R, &W, &E, &MAX);
203 return (-1 != select(MAX + 1, &R, &W, &E, &timeout)) ? SUCCESS : FAILURE;
204 }
205 /* }}} */
206
207 /* {{{ int http_request_pool_perform(http_request_pool *) */
208 PHP_HTTP_API int _http_request_pool_perform(http_request_pool *pool)
209 {
210 while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(pool->ch, &pool->unfinished));
211 return pool->unfinished;
212 }
213 /* }}} */
214
215 /* {{{ void http_request_pool_responsehandler(zval **) */
216 void _http_request_pool_responsehandler(zval **req TSRMLS_DC)
217 {
218 getObjectEx(http_request_object, obj, *req);
219 #if HTTP_DEBUG_REQPOOLS
220 fprintf(stderr, "Fetching data from request %p of pool %p\n", obj, obj->pool);
221 #endif
222 http_request_object_responsehandler(obj, *req);
223 }
224 /* }}} */
225
226 /*#*/
227
228 /* {{{ static void http_request_pool_freebody(http_request_body **) */
229 static void http_request_pool_freebody(http_request_body **body)
230 {
231 TSRMLS_FETCH();
232 http_request_body_free(*body);
233 }
234 /* }}} */
235
236 /* {{{ static int http_request_pool_compare_handles(void *, void *) */
237 static int http_request_pool_compare_handles(void *h1, void *h2)
238 {
239 return ((*((zval **) h1)) == ((zval *) h2));
240 }
241 /* }}} */
242
243 #endif /* ZEND_ENGINE_2 */
244
245
246 /*
247 * Local variables:
248 * tab-width: 4
249 * c-basic-offset: 4
250 * End:
251 * vim600: noet sw=4 ts=4 fdm=marker
252 * vim<600: noet sw=4 ts=4
253 */
254