2 +--------------------------------------------------------------------+
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-2014, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
13 #include "php_http_api.h"
15 #include "php_network.h"
16 #include "zend_closures.h"
18 #if PHP_HTTP_HAVE_CURL
20 typedef struct php_http_client_curl_user_ev
{
22 php_http_client_curl_user_context_t
*context
;
23 } php_http_client_curl_user_ev_t
;
25 static void php_http_client_curl_user_handler(INTERNAL_FUNCTION_PARAMETERS
)
27 zval
*zstream
= NULL
, *zclient
= NULL
;
28 php_stream
*stream
= NULL
;
30 php_socket_t fd
= CURL_SOCKET_TIMEOUT
;
31 php_http_client_object_t
*client
= NULL
;
33 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS(), "O|rl", &zclient
, php_http_client_get_class_entry(), &zstream
, &action
)) {
37 client
= PHP_HTTP_OBJ(NULL
, zclient
);
39 php_stream_from_zval(stream
, zstream
);
41 if (SUCCESS
!= php_stream_cast(stream
, PHP_STREAM_AS_SOCKETD
, (void *) &fd
, 1)) {
45 php_http_client_curl_loop(client
->client
, fd
, action
);
48 static void php_http_client_curl_user_timer(CURLM
*multi
, long timeout_ms
, void *timer_data
)
50 php_http_client_curl_user_context_t
*context
= timer_data
;
53 fprintf(stderr
, "\ntimer <- timeout_ms: %ld\n", timeout_ms
);
56 if (timeout_ms
<= 0) {
57 php_http_client_curl_loop(context
->client
, CURL_SOCKET_TIMEOUT
, 0);
58 } else if (timeout_ms
> 0) {
59 zval args
[1], *ztimeout
= &args
[0];
61 ZVAL_LONG(ztimeout
, timeout_ms
);
62 php_http_object_method_call(&context
->timer
, &context
->user
, NULL
, 1, args
);
63 zval_ptr_dtor(ztimeout
);
67 static int php_http_client_curl_user_socket(CURL
*easy
, curl_socket_t sock
, int action
, void *socket_data
, void *assign_data
)
69 php_http_client_curl_user_context_t
*ctx
= socket_data
;
70 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
71 php_http_client_curl_user_ev_t
*ev
= assign_data
;
72 zval args
[2], *zaction
= &args
[1], *zsocket
= &args
[0];
79 ev
= ecalloc(1, sizeof(*ev
));
81 ev
->socket
= php_stream_sock_open_from_socket(sock
, NULL
);
83 curl_multi_assign(curl
->handle
->multi
, sock
, ev
);
90 case CURL_POLL_REMOVE
:
92 php_stream_to_zval(ev
->socket
, zsocket
);
93 Z_TRY_ADDREF_P(zsocket
);
94 ZVAL_LONG(zaction
, action
);
95 php_http_object_method_call(&ctx
->socket
, &ctx
->user
, NULL
, 2, args
);
96 zval_ptr_dtor(zsocket
);
97 zval_ptr_dtor(zaction
);
101 php_error_docref(NULL
, E_WARNING
, "Unknown socket action %d", action
);
105 if (action
== CURL_POLL_REMOVE
&& ev
) {
106 php_stream_close(ev
->socket
);
108 curl_multi_assign(curl
->handle
->multi
, sock
, NULL
);
113 static ZEND_RESULT_CODE
php_http_client_curl_user_once(void *context
)
115 php_http_client_curl_user_context_t
*ctx
= context
;
118 fprintf(stderr
, "O");
121 return php_http_object_method_call(&ctx
->once
, &ctx
->user
, NULL
, 0, NULL
);
124 static ZEND_RESULT_CODE
php_http_client_curl_user_wait(void *context
, struct timeval
*custom_timeout
)
126 php_http_client_curl_user_context_t
*ctx
= context
;
127 struct timeval timeout
;
128 zval args
[1], *ztimeout
= &args
[0];
132 fprintf(stderr
, "W");
135 if (!custom_timeout
|| !timerisset(custom_timeout
)) {
136 php_http_client_curl_get_timeout(ctx
->client
->ctx
, 1000, &timeout
);
137 custom_timeout
= &timeout
;
140 ZVAL_LONG(ztimeout
, custom_timeout
->tv_sec
* 1000 + custom_timeout
->tv_usec
/ 1000);
141 rv
= php_http_object_method_call(&ctx
->wait
, &ctx
->user
, NULL
, 1, args
);
142 zval_ptr_dtor(ztimeout
);
147 static ZEND_RESULT_CODE
php_http_client_curl_user_exec(void *context
)
149 php_http_client_curl_user_context_t
*ctx
= context
;
150 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
153 fprintf(stderr
, "E");
157 php_http_client_curl_loop(ctx
->client
, CURL_SOCKET_TIMEOUT
, 0);
160 if (SUCCESS
!= php_http_object_method_call(&ctx
->send
, &ctx
->user
, NULL
, 0, NULL
)) {
163 } while (curl
->unfinished
&& !EG(exception
));
168 static void *php_http_client_curl_user_init(php_http_client_t
*client
, void *user_data
)
170 php_http_client_curl_t
*curl
= client
->ctx
;
171 php_http_client_curl_user_context_t
*ctx
;
172 php_http_object_method_t init
;
173 zval args
[1], *zclosure
= &args
[0];
176 fprintf(stderr
, "I");
179 ctx
= ecalloc(1, sizeof(*ctx
));
180 ctx
->client
= client
;
181 ZVAL_COPY(&ctx
->user
, user_data
);
183 memset(&ctx
->closure
, 0, sizeof(ctx
->closure
));
184 ctx
->closure
.common
.type
= ZEND_INTERNAL_FUNCTION
;
185 ctx
->closure
.common
.function_name
= zend_string_init(ZEND_STRL("php_http_client_curl_user_handler"), 0);
186 ctx
->closure
.internal_function
.handler
= php_http_client_curl_user_handler
;
188 zend_create_closure(zclosure
, &ctx
->closure
, NULL
, NULL
, NULL
);
190 php_http_object_method_init(&init
, &ctx
->user
, ZEND_STRL("init"));
191 php_http_object_method_call(&init
, &ctx
->user
, NULL
, 1, args
);
192 php_http_object_method_dtor(&init
);
193 zval_ptr_dtor(zclosure
);
195 php_http_object_method_init(&ctx
->timer
, &ctx
->user
, ZEND_STRL("timer"));
196 php_http_object_method_init(&ctx
->socket
, &ctx
->user
, ZEND_STRL("socket"));
197 php_http_object_method_init(&ctx
->once
, &ctx
->user
, ZEND_STRL("once"));
198 php_http_object_method_init(&ctx
->wait
, &ctx
->user
, ZEND_STRL("wait"));
199 php_http_object_method_init(&ctx
->send
, &ctx
->user
, ZEND_STRL("send"));
201 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, ctx
);
202 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, php_http_client_curl_user_socket
);
203 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, ctx
);
204 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, php_http_client_curl_user_timer
);
209 static void php_http_client_curl_user_dtor(void **context
)
211 php_http_client_curl_user_context_t
*ctx
= *context
;
212 php_http_client_curl_t
*curl
;
215 fprintf(stderr
, "D");
218 curl
= ctx
->client
->ctx
;
220 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, NULL
);
221 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, NULL
);
222 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, NULL
);
223 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, NULL
);
225 php_http_object_method_dtor(&ctx
->timer
);
226 php_http_object_method_dtor(&ctx
->socket
);
227 php_http_object_method_dtor(&ctx
->once
);
228 php_http_object_method_dtor(&ctx
->wait
);
229 php_http_object_method_dtor(&ctx
->send
);
231 zend_string_release(ctx
->closure
.common
.function_name
);
232 zval_ptr_dtor(&ctx
->user
);
238 static php_http_client_curl_ops_t php_http_client_curl_user_ops
= {
239 &php_http_client_curl_user_init
,
240 &php_http_client_curl_user_dtor
,
241 &php_http_client_curl_user_once
,
242 &php_http_client_curl_user_wait
,
243 &php_http_client_curl_user_exec
,
246 php_http_client_curl_ops_t
*php_http_client_curl_user_ops_get()
248 return &php_http_client_curl_user_ops
;
251 static zend_class_entry
*php_http_client_curl_user_class_entry
;
253 zend_class_entry
*php_http_client_curl_user_get_class_entry()
255 return php_http_client_curl_user_class_entry
;
258 ZEND_BEGIN_ARG_INFO_EX(ai_init
, 0, 0, 1)
259 ZEND_ARG_TYPE_INFO(0, run
, IS_CALLABLE
, 0)
261 ZEND_BEGIN_ARG_INFO_EX(ai_timer
, 0, 0, 1)
262 #if PHP_VERSION_ID >= 70000
263 ZEND_ARG_TYPE_INFO(0, timeout_ms
, IS_LONG
, 0)
265 ZEND_ARG_INFO(0, timeout_ms
)
268 ZEND_BEGIN_ARG_INFO_EX(ai_socket
, 0, 0, 2)
269 ZEND_ARG_INFO(0, socket
)
270 #if PHP_VERSION_ID >= 70000
271 ZEND_ARG_TYPE_INFO(0, action
, IS_LONG
, 0)
273 ZEND_ARG_INFO(0, action
)
276 ZEND_BEGIN_ARG_INFO_EX(ai_once
, 0, 0, 0)
278 ZEND_BEGIN_ARG_INFO_EX(ai_wait
, 0, 0, 0)
279 #if PHP_VERSION_ID >= 70000
280 ZEND_ARG_TYPE_INFO(0, timeout_ms
, IS_LONG
, 0)
282 ZEND_ARG_INFO(0, timeout_ms
)
285 ZEND_BEGIN_ARG_INFO_EX(ai_send
, 0, 0, 0)
288 static zend_function_entry php_http_client_curl_user_methods
[] = {
289 PHP_ABSTRACT_ME(HttpClientCurlUser
, init
, ai_init
)
290 PHP_ABSTRACT_ME(HttpClientCurlUser
, timer
, ai_timer
)
291 PHP_ABSTRACT_ME(HttpClientCurlUser
, socket
, ai_socket
)
292 PHP_ABSTRACT_ME(HttpClientCurlUser
, once
, ai_once
)
293 PHP_ABSTRACT_ME(HttpClientCurlUser
, wait
, ai_wait
)
294 PHP_ABSTRACT_ME(HttpClientCulrUser
, send
, ai_send
)
298 PHP_MINIT_FUNCTION(http_client_curl_user
)
300 zend_class_entry ce
= {0};
302 INIT_NS_CLASS_ENTRY(ce
, "http\\Client\\Curl", "User", php_http_client_curl_user_methods
);
303 php_http_client_curl_user_class_entry
= zend_register_internal_interface(&ce
);
305 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_NONE"), CURL_POLL_NONE
);
306 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_IN"), CURL_POLL_IN
);
307 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_OUT"), CURL_POLL_OUT
);
308 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_INOUT"), CURL_POLL_INOUT
);
309 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_REMOVE"), CURL_POLL_REMOVE
);
314 #endif /* PHP_HTTP_HAVE_CURL */
321 * vim600: noet sw=4 ts=4 fdm=marker
322 * vim<600: noet sw=4 ts=4