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"
14 #include "php_http_client.h"
15 #include "php_http_client_curl.h"
16 #include "php_http_client_curl_user.h"
18 #include "php_network.h"
19 #include "zend_closures.h"
21 #if PHP_HTTP_HAVE_CURL
23 typedef struct php_http_client_curl_user_context
{
24 php_http_client_t
*client
;
26 zend_function closure
;
27 php_http_object_method_t timer
;
28 php_http_object_method_t socket
;
29 php_http_object_method_t once
;
30 php_http_object_method_t wait
;
31 php_http_object_method_t send
;
32 } php_http_client_curl_user_context_t
;
34 typedef struct php_http_client_curl_user_ev
{
36 php_http_client_curl_user_context_t
*context
;
37 } php_http_client_curl_user_ev_t
;
39 static void php_http_client_curl_user_handler(INTERNAL_FUNCTION_PARAMETERS
)
41 zval
*zstream
= NULL
, *zclient
= NULL
;
42 php_stream
*stream
= NULL
;
44 php_socket_t fd
= CURL_SOCKET_TIMEOUT
;
45 php_http_client_object_t
*client
= NULL
;
47 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O|rl", &zclient
, php_http_client_class_entry
, &zstream
, &action
)) {
51 client
= zend_object_store_get_object(zclient TSRMLS_CC
);
53 php_stream_from_zval(stream
, &zstream
);
55 if (SUCCESS
!= php_stream_cast(stream
, PHP_STREAM_AS_SOCKETD
, (void *) &fd
, 1)) {
59 php_http_client_curl_loop(client
->client
, fd
, action
);
62 static void php_http_client_curl_user_timer(CURLM
*multi
, long timeout_ms
, void *timer_data
)
64 php_http_client_curl_user_context_t
*context
= timer_data
;
67 fprintf(stderr
, "\ntimer <- timeout_ms: %ld\n", timeout_ms
);
70 if (timeout_ms
<= 0) {
71 php_http_client_curl_loop(context
->client
, CURL_SOCKET_TIMEOUT
, 0);
72 } else if (timeout_ms
> 0) {
73 zval
**args
[1], *ztimeout
;
74 TSRMLS_FETCH_FROM_CTX(context
->client
->ts
);
76 MAKE_STD_ZVAL(ztimeout
);
77 ZVAL_LONG(ztimeout
, timeout_ms
);
79 php_http_object_method_call(&context
->timer
, context
->user
, NULL
, 1, args TSRMLS_CC
);
80 zval_ptr_dtor(&ztimeout
);
84 static int php_http_client_curl_user_socket(CURL
*easy
, curl_socket_t sock
, int action
, void *socket_data
, void *assign_data
)
86 php_http_client_curl_user_context_t
*ctx
= socket_data
;
87 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
88 php_http_client_curl_user_ev_t
*ev
= assign_data
;
89 zval
**args
[2], *zaction
, *zsocket
;
90 TSRMLS_FETCH_FROM_CTX(ctx
->client
->ts
);
97 ev
= ecalloc(1, sizeof(*ev
));
99 ev
->socket
= php_stream_sock_open_from_socket(sock
, NULL
);
101 curl_multi_assign(curl
->handle
->multi
, sock
, ev
);
107 case CURL_POLL_INOUT
:
108 case CURL_POLL_REMOVE
:
110 MAKE_STD_ZVAL(zsocket
);
111 php_stream_to_zval(ev
->socket
, zsocket
);
113 MAKE_STD_ZVAL(zaction
);
114 ZVAL_LONG(zaction
, action
);
116 php_http_object_method_call(&ctx
->socket
, ctx
->user
, NULL
, 2, args TSRMLS_CC
);
117 zval_ptr_dtor(&zsocket
);
118 zval_ptr_dtor(&zaction
);
122 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Unknown socket action %d", action
);
126 if (action
== CURL_POLL_REMOVE
&& ev
) {
132 static ZEND_RESULT_CODE
php_http_client_curl_user_once(void *context
)
134 php_http_client_curl_user_context_t
*ctx
= context
;
135 TSRMLS_FETCH_FROM_CTX(ctx
->client
->ts
);
138 fprintf(stderr
, "O");
141 return php_http_object_method_call(&ctx
->once
, ctx
->user
, NULL
, 0, NULL TSRMLS_CC
);
144 static ZEND_RESULT_CODE
php_http_client_curl_user_wait(void *context
, struct timeval
*custom_timeout
)
146 php_http_client_curl_user_context_t
*ctx
= context
;
147 struct timeval timeout
;
148 zval
**args
[1], *ztimeout
;
150 TSRMLS_FETCH_FROM_CTX(ctx
->client
->ts
);
153 fprintf(stderr
, "W");
156 if (!custom_timeout
|| !timerisset(custom_timeout
)) {
157 php_http_client_curl_get_timeout(ctx
->client
->ctx
, 1000, &timeout
);
158 custom_timeout
= &timeout
;
161 MAKE_STD_ZVAL(ztimeout
);
162 ZVAL_LONG(ztimeout
, custom_timeout
->tv_sec
* 1000 + custom_timeout
->tv_usec
/ 1000);
164 rv
= php_http_object_method_call(&ctx
->wait
, ctx
->user
, NULL
, 1, args TSRMLS_CC
);
165 zval_ptr_dtor(&ztimeout
);
170 static ZEND_RESULT_CODE
php_http_client_curl_user_exec(void *context
)
172 php_http_client_curl_user_context_t
*ctx
= context
;
173 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
174 TSRMLS_FETCH_FROM_CTX(ctx
->client
->ts
);
177 fprintf(stderr
, "E");
181 php_http_client_curl_loop(ctx
->client
, CURL_SOCKET_TIMEOUT
, 0);
184 if (SUCCESS
!= php_http_object_method_call(&ctx
->send
, ctx
->user
, NULL
, 0, NULL TSRMLS_CC
)) {
187 } while (curl
->unfinished
&& !EG(exception
));
192 static void *php_http_client_curl_user_init(php_http_client_t
*client
, void *user_data
)
194 php_http_client_curl_t
*curl
= client
->ctx
;
195 php_http_client_curl_user_context_t
*ctx
;
196 php_http_object_method_t init
;
197 zval
*zclosure
, **args
[1];
198 TSRMLS_FETCH_FROM_CTX(client
->ts
);
201 fprintf(stderr
, "I");
204 ctx
= ecalloc(1, sizeof(*ctx
));
205 ctx
->client
= client
;
206 ctx
->user
= user_data
;
207 Z_ADDREF_P(ctx
->user
);
209 memset(&ctx
->closure
, 0, sizeof(ctx
->closure
));
210 ctx
->closure
.common
.type
= ZEND_INTERNAL_FUNCTION
;
211 ctx
->closure
.common
.function_name
= "php_http_client_curl_user_handler";
212 ctx
->closure
.internal_function
.handler
= php_http_client_curl_user_handler
;
214 MAKE_STD_ZVAL(zclosure
);
215 zend_create_closure(zclosure
, &ctx
->closure
, NULL
, NULL TSRMLS_CC
);
218 php_http_object_method_init(&init
, ctx
->user
, ZEND_STRL("init") TSRMLS_CC
);
219 php_http_object_method_call(&init
, ctx
->user
, NULL
, 1, args TSRMLS_CC
);
220 php_http_object_method_dtor(&init
);
221 zval_ptr_dtor(&zclosure
);
223 php_http_object_method_init(&ctx
->timer
, ctx
->user
, ZEND_STRL("timer") TSRMLS_CC
);
224 php_http_object_method_init(&ctx
->socket
, ctx
->user
, ZEND_STRL("socket") TSRMLS_CC
);
225 php_http_object_method_init(&ctx
->once
, ctx
->user
, ZEND_STRL("once") TSRMLS_CC
);
226 php_http_object_method_init(&ctx
->wait
, ctx
->user
, ZEND_STRL("wait") TSRMLS_CC
);
227 php_http_object_method_init(&ctx
->send
, ctx
->user
, ZEND_STRL("send") TSRMLS_CC
);
229 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, ctx
);
230 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, php_http_client_curl_user_socket
);
231 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, ctx
);
232 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, php_http_client_curl_user_timer
);
237 static void php_http_client_curl_user_dtor(void **context
)
239 php_http_client_curl_user_context_t
*ctx
= *context
;
240 php_http_client_curl_t
*curl
;
243 fprintf(stderr
, "D");
246 curl
= ctx
->client
->ctx
;
248 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, NULL
);
249 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, NULL
);
250 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, NULL
);
251 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, NULL
);
253 php_http_object_method_dtor(&ctx
->timer
);
254 php_http_object_method_dtor(&ctx
->socket
);
255 php_http_object_method_dtor(&ctx
->once
);
256 php_http_object_method_dtor(&ctx
->wait
);
257 php_http_object_method_dtor(&ctx
->send
);
259 zval_ptr_dtor(&ctx
->user
);
265 static php_http_client_curl_ops_t php_http_client_curl_user_ops
= {
266 &php_http_client_curl_user_init
,
267 &php_http_client_curl_user_dtor
,
268 &php_http_client_curl_user_once
,
269 &php_http_client_curl_user_wait
,
270 &php_http_client_curl_user_exec
,
273 php_http_client_curl_ops_t
*php_http_client_curl_user_ops_get()
275 return &php_http_client_curl_user_ops
;
278 zend_class_entry
*php_http_client_curl_user_class_entry
;
280 ZEND_BEGIN_ARG_INFO_EX(ai_init
, 0, 0, 1)
281 ZEND_ARG_TYPE_INFO(0, run
, IS_CALLABLE
, 0)
283 ZEND_BEGIN_ARG_INFO_EX(ai_timer
, 0, 0, 1)
284 #if PHP_VERSION_ID >= 70000
285 ZEND_ARG_TYPE_INFO(0, timeout_ms
, IS_LONG
, 0)
287 ZEND_ARG_INFO(0, timeout_ms
)
290 ZEND_BEGIN_ARG_INFO_EX(ai_socket
, 0, 0, 2)
291 #if PHP_VERSION_ID >= 70000
292 ZEND_ARG_TYPE_INFO(0, socket
, IS_RESOURCE
, 0)
293 ZEND_ARG_TYPE_INFO(0, action
, IS_LONG
, 0)
295 ZEND_ARG_INFO(0, socket
)
296 ZEND_ARG_INFO(0, action
)
299 ZEND_BEGIN_ARG_INFO_EX(ai_once
, 0, 0, 0)
301 ZEND_BEGIN_ARG_INFO_EX(ai_wait
, 0, 0, 0)
302 #if PHP_VERSION_ID >= 70000
303 ZEND_ARG_TYPE_INFO(0, timeout_ms
, IS_LONG
, 0)
305 ZEND_ARG_INFO(0, timeout_ms
)
308 ZEND_BEGIN_ARG_INFO_EX(ai_send
, 0, 0, 0)
311 static zend_function_entry php_http_client_curl_user_methods
[] = {
312 PHP_ABSTRACT_ME(HttpClientCurlUser
, init
, ai_init
)
313 PHP_ABSTRACT_ME(HttpClientCurlUser
, timer
, ai_timer
)
314 PHP_ABSTRACT_ME(HttpClientCurlUser
, socket
, ai_socket
)
315 PHP_ABSTRACT_ME(HttpClientCurlUser
, once
, ai_once
)
316 PHP_ABSTRACT_ME(HttpClientCurlUser
, wait
, ai_wait
)
317 PHP_ABSTRACT_ME(HttpClientCulrUser
, send
, ai_send
)
321 PHP_MINIT_FUNCTION(http_client_curl_user
)
323 zend_class_entry ce
= {0};
325 INIT_NS_CLASS_ENTRY(ce
, "http\\Client\\Curl", "User", php_http_client_curl_user_methods
);
326 php_http_client_curl_user_class_entry
= zend_register_internal_interface(&ce TSRMLS_CC
);
328 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_NONE"), CURL_POLL_NONE TSRMLS_CC
);
329 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_IN"), CURL_POLL_IN TSRMLS_CC
);
330 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_OUT"), CURL_POLL_OUT TSRMLS_CC
);
331 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_INOUT"), CURL_POLL_INOUT TSRMLS_CC
);
332 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_REMOVE"), CURL_POLL_REMOVE TSRMLS_CC
);
337 #endif /* PHP_HTTP_HAVE_CURL */
344 * vim600: noet sw=4 ts=4 fdm=marker
345 * vim<600: noet sw=4 ts=4