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
;
46 php_http_client_curl_t
*curl
;
48 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O|rl", &zclient
, php_http_client_class_entry
, &zstream
, &action
)) {
52 client
= zend_object_store_get_object(zclient TSRMLS_CC
);
54 php_stream_from_zval(stream
, &zstream
);
56 if (SUCCESS
!= php_stream_cast(stream
, PHP_STREAM_AS_SOCKETD
, (void *) &fd
, 1)) {
60 php_http_client_curl_loop(client
->client
, fd
, action
);
62 curl
= client
->client
->ctx
;
63 RETVAL_LONG(curl
->unfinished
);
66 static void php_http_client_curl_user_timer(CURLM
*multi
, long timeout_ms
, void *timer_data
)
68 php_http_client_curl_user_context_t
*context
= timer_data
;
71 fprintf(stderr
, "\ntimer <- timeout_ms: %ld\n", timeout_ms
);
74 if (timeout_ms
<= 0) {
75 php_http_client_curl_loop(context
->client
, CURL_SOCKET_TIMEOUT
, 0);
76 } else if (timeout_ms
> 0) {
77 zval
**args
[1], *ztimeout
;
78 TSRMLS_FETCH_FROM_CTX(context
->client
->ts
);
80 MAKE_STD_ZVAL(ztimeout
);
81 ZVAL_LONG(ztimeout
, timeout_ms
);
83 php_http_object_method_call(&context
->timer
, context
->user
, NULL
, 1, args TSRMLS_CC
);
84 zval_ptr_dtor(&ztimeout
);
88 static int php_http_client_curl_user_socket(CURL
*easy
, curl_socket_t sock
, int action
, void *socket_data
, void *assign_data
)
90 php_http_client_curl_user_context_t
*ctx
= socket_data
;
91 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
92 php_http_client_curl_user_ev_t
*ev
= assign_data
;
93 zval
**args
[2], *zaction
, *zsocket
;
94 TSRMLS_FETCH_FROM_CTX(ctx
->client
->ts
);
101 ev
= ecalloc(1, sizeof(*ev
));
103 ev
->socket
= php_stream_sock_open_from_socket(sock
, NULL
);
105 curl_multi_assign(curl
->handle
->multi
, sock
, ev
);
111 case CURL_POLL_INOUT
:
112 case CURL_POLL_REMOVE
:
114 MAKE_STD_ZVAL(zsocket
);
115 php_stream_to_zval(ev
->socket
, zsocket
);
117 MAKE_STD_ZVAL(zaction
);
118 ZVAL_LONG(zaction
, action
);
120 php_http_object_method_call(&ctx
->socket
, ctx
->user
, NULL
, 2, args TSRMLS_CC
);
121 zval_ptr_dtor(&zsocket
);
122 zval_ptr_dtor(&zaction
);
126 php_error_docref(NULL TSRMLS_CC
, E_WARNING
, "Unknown socket action %d", action
);
130 if (action
== CURL_POLL_REMOVE
&& ev
) {
136 static ZEND_RESULT_CODE
php_http_client_curl_user_once(void *context
)
138 php_http_client_curl_user_context_t
*ctx
= context
;
139 TSRMLS_FETCH_FROM_CTX(ctx
->client
->ts
);
142 fprintf(stderr
, "O");
145 return php_http_object_method_call(&ctx
->once
, ctx
->user
, NULL
, 0, NULL TSRMLS_CC
);
148 static ZEND_RESULT_CODE
php_http_client_curl_user_wait(void *context
, struct timeval
*custom_timeout
)
150 php_http_client_curl_user_context_t
*ctx
= context
;
151 struct timeval timeout
;
152 zval
**args
[1], *ztimeout
;
154 TSRMLS_FETCH_FROM_CTX(ctx
->client
->ts
);
157 fprintf(stderr
, "W");
160 if (!custom_timeout
|| !timerisset(custom_timeout
)) {
161 php_http_client_curl_get_timeout(ctx
->client
->ctx
, 1000, &timeout
);
162 custom_timeout
= &timeout
;
165 MAKE_STD_ZVAL(ztimeout
);
166 ZVAL_LONG(ztimeout
, custom_timeout
->tv_sec
* 1000 + custom_timeout
->tv_usec
/ 1000);
168 rv
= php_http_object_method_call(&ctx
->wait
, ctx
->user
, NULL
, 1, args TSRMLS_CC
);
169 zval_ptr_dtor(&ztimeout
);
174 static ZEND_RESULT_CODE
php_http_client_curl_user_exec(void *context
)
176 php_http_client_curl_user_context_t
*ctx
= context
;
177 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
178 TSRMLS_FETCH_FROM_CTX(ctx
->client
->ts
);
181 fprintf(stderr
, "E");
185 php_http_client_curl_loop(ctx
->client
, CURL_SOCKET_TIMEOUT
, 0);
188 if (SUCCESS
!= php_http_object_method_call(&ctx
->send
, ctx
->user
, NULL
, 0, NULL TSRMLS_CC
)) {
191 } while (curl
->unfinished
&& !EG(exception
));
196 static void *php_http_client_curl_user_init(php_http_client_t
*client
, void *user_data
)
198 php_http_client_curl_t
*curl
= client
->ctx
;
199 php_http_client_curl_user_context_t
*ctx
;
200 php_http_object_method_t init
;
201 zval
*zclosure
, **args
[1];
202 TSRMLS_FETCH_FROM_CTX(client
->ts
);
205 fprintf(stderr
, "I");
208 ctx
= ecalloc(1, sizeof(*ctx
));
209 ctx
->client
= client
;
210 ctx
->user
= user_data
;
211 Z_ADDREF_P(ctx
->user
);
213 memset(&ctx
->closure
, 0, sizeof(ctx
->closure
));
214 ctx
->closure
.common
.type
= ZEND_INTERNAL_FUNCTION
;
215 ctx
->closure
.common
.function_name
= "php_http_client_curl_user_handler";
216 ctx
->closure
.internal_function
.handler
= php_http_client_curl_user_handler
;
218 MAKE_STD_ZVAL(zclosure
);
219 #if PHP_VERSION_ID >= 50400
220 zend_create_closure(zclosure
, &ctx
->closure
, NULL
, NULL TSRMLS_CC
);
222 zend_create_closure(zclosure
, &ctx
->closure TSRMLS_CC
);
226 php_http_object_method_init(&init
, ctx
->user
, ZEND_STRL("init") TSRMLS_CC
);
227 php_http_object_method_call(&init
, ctx
->user
, NULL
, 1, args TSRMLS_CC
);
228 php_http_object_method_dtor(&init
);
229 zval_ptr_dtor(&zclosure
);
231 php_http_object_method_init(&ctx
->timer
, ctx
->user
, ZEND_STRL("timer") TSRMLS_CC
);
232 php_http_object_method_init(&ctx
->socket
, ctx
->user
, ZEND_STRL("socket") TSRMLS_CC
);
233 php_http_object_method_init(&ctx
->once
, ctx
->user
, ZEND_STRL("once") TSRMLS_CC
);
234 php_http_object_method_init(&ctx
->wait
, ctx
->user
, ZEND_STRL("wait") TSRMLS_CC
);
235 php_http_object_method_init(&ctx
->send
, ctx
->user
, ZEND_STRL("send") TSRMLS_CC
);
237 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, ctx
);
238 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, php_http_client_curl_user_socket
);
239 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, ctx
);
240 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, php_http_client_curl_user_timer
);
245 static void php_http_client_curl_user_dtor(void **context
)
247 php_http_client_curl_user_context_t
*ctx
= *context
;
248 php_http_client_curl_t
*curl
;
251 fprintf(stderr
, "D");
254 curl
= ctx
->client
->ctx
;
256 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, NULL
);
257 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, NULL
);
258 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, NULL
);
259 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, NULL
);
261 php_http_object_method_dtor(&ctx
->timer
);
262 php_http_object_method_dtor(&ctx
->socket
);
263 php_http_object_method_dtor(&ctx
->once
);
264 php_http_object_method_dtor(&ctx
->wait
);
265 php_http_object_method_dtor(&ctx
->send
);
267 zval_ptr_dtor(&ctx
->user
);
273 static php_http_client_curl_ops_t php_http_client_curl_user_ops
= {
274 &php_http_client_curl_user_init
,
275 &php_http_client_curl_user_dtor
,
276 &php_http_client_curl_user_once
,
277 &php_http_client_curl_user_wait
,
278 &php_http_client_curl_user_exec
,
281 php_http_client_curl_ops_t
*php_http_client_curl_user_ops_get()
283 return &php_http_client_curl_user_ops
;
286 zend_class_entry
*php_http_client_curl_user_class_entry
;
288 ZEND_BEGIN_ARG_INFO_EX(ai_init
, 0, 0, 1)
289 /* using IS_CALLABLE type hint would create a forwards compatibility break */
290 ZEND_ARG_INFO(0, run
)
292 ZEND_BEGIN_ARG_INFO_EX(ai_timer
, 0, 0, 1)
293 #if PHP_VERSION_ID >= 70000
294 ZEND_ARG_TYPE_INFO(0, timeout_ms
, IS_LONG
, 0)
296 ZEND_ARG_INFO(0, timeout_ms
)
299 ZEND_BEGIN_ARG_INFO_EX(ai_socket
, 0, 0, 2)
300 #if PHP_VERSION_ID >= 70000
301 ZEND_ARG_TYPE_INFO(0, socket
, IS_RESOURCE
, 0)
302 ZEND_ARG_TYPE_INFO(0, action
, IS_LONG
, 0)
304 ZEND_ARG_INFO(0, socket
)
305 ZEND_ARG_INFO(0, action
)
308 ZEND_BEGIN_ARG_INFO_EX(ai_once
, 0, 0, 0)
310 ZEND_BEGIN_ARG_INFO_EX(ai_wait
, 0, 0, 0)
311 #if PHP_VERSION_ID >= 70000
312 ZEND_ARG_TYPE_INFO(0, timeout_ms
, IS_LONG
, 0)
314 ZEND_ARG_INFO(0, timeout_ms
)
317 ZEND_BEGIN_ARG_INFO_EX(ai_send
, 0, 0, 0)
320 static zend_function_entry php_http_client_curl_user_methods
[] = {
321 PHP_ABSTRACT_ME(HttpClientCurlUser
, init
, ai_init
)
322 PHP_ABSTRACT_ME(HttpClientCurlUser
, timer
, ai_timer
)
323 PHP_ABSTRACT_ME(HttpClientCurlUser
, socket
, ai_socket
)
324 PHP_ABSTRACT_ME(HttpClientCurlUser
, once
, ai_once
)
325 PHP_ABSTRACT_ME(HttpClientCurlUser
, wait
, ai_wait
)
326 PHP_ABSTRACT_ME(HttpClientCulrUser
, send
, ai_send
)
330 PHP_MINIT_FUNCTION(http_client_curl_user
)
332 zend_class_entry ce
= {0};
334 INIT_NS_CLASS_ENTRY(ce
, "http\\Client\\Curl", "User", php_http_client_curl_user_methods
);
335 php_http_client_curl_user_class_entry
= zend_register_internal_interface(&ce TSRMLS_CC
);
337 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_NONE"), CURL_POLL_NONE TSRMLS_CC
);
338 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_IN"), CURL_POLL_IN TSRMLS_CC
);
339 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_OUT"), CURL_POLL_OUT TSRMLS_CC
);
340 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_INOUT"), CURL_POLL_INOUT TSRMLS_CC
);
341 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_REMOVE"), CURL_POLL_REMOVE TSRMLS_CC
);
346 #endif /* PHP_HTTP_HAVE_CURL */
353 * vim600: noet sw=4 ts=4 fdm=marker
354 * vim<600: noet sw=4 ts=4