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_LIBCURL
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 ZEND_NAMED_FUNCTION(php_http_client_curl_user_handler
)
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
;
32 php_http_client_curl_t
*curl
;
34 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS(), "O|rl", &zclient
, php_http_client_get_class_entry(), &zstream
, &action
)) {
38 client
= PHP_HTTP_OBJ(NULL
, zclient
);
40 php_stream_from_zval(stream
, zstream
);
42 if (SUCCESS
!= php_stream_cast(stream
, PHP_STREAM_AS_SOCKETD
, (void *) &fd
, 1)) {
46 php_http_client_curl_loop(client
->client
, fd
, action
);
48 curl
= client
->client
->ctx
;
49 RETVAL_LONG(curl
->unfinished
);
52 static void php_http_client_curl_user_timer(CURLM
*multi
, long timeout_ms
, void *timer_data
)
54 php_http_client_curl_user_context_t
*context
= timer_data
;
57 fprintf(stderr
, "\ntimer <- timeout_ms: %ld\n", timeout_ms
);
60 if (timeout_ms
>= 0) {
61 zval args
[1], *ztimeout
= &args
[0];
63 ZVAL_LONG(ztimeout
, timeout_ms
);
64 php_http_object_method_call(&context
->timer
, &context
->user
, NULL
, 1, args
);
65 zval_ptr_dtor(ztimeout
);
69 static int php_http_client_curl_user_socket(CURL
*easy
, curl_socket_t sock
, int action
, void *socket_data
, void *assign_data
)
71 php_http_client_curl_user_context_t
*ctx
= socket_data
;
72 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
73 php_http_client_curl_user_ev_t
*ev
= assign_data
;
74 zval args
[2], *zaction
= &args
[1], *zsocket
= &args
[0];
81 ev
= ecalloc(1, sizeof(*ev
));
83 ev
->socket
= php_stream_sock_open_from_socket(sock
, NULL
);
85 curl_multi_assign(curl
->handle
->multi
, sock
, ev
);
92 case CURL_POLL_REMOVE
:
94 php_stream_to_zval(ev
->socket
, zsocket
);
95 Z_TRY_ADDREF_P(zsocket
);
96 ZVAL_LONG(zaction
, action
);
97 php_http_object_method_call(&ctx
->socket
, &ctx
->user
, NULL
, 2, args
);
98 zval_ptr_dtor(zsocket
);
99 zval_ptr_dtor(zaction
);
103 php_error_docref(NULL
, E_WARNING
, "Unknown socket action %d", action
);
107 if (action
== CURL_POLL_REMOVE
) {
108 php_stream_close(ev
->socket
);
110 curl_multi_assign(curl
->handle
->multi
, sock
, NULL
);
115 static ZEND_RESULT_CODE
php_http_client_curl_user_once(void *context
)
117 php_http_client_curl_user_context_t
*ctx
= context
;
120 fprintf(stderr
, "O");
123 return php_http_object_method_call(&ctx
->once
, &ctx
->user
, NULL
, 0, NULL
);
126 static ZEND_RESULT_CODE
php_http_client_curl_user_wait(void *context
, struct timeval
*custom_timeout
)
128 php_http_client_curl_user_context_t
*ctx
= context
;
129 struct timeval timeout
;
130 zval args
[1], *ztimeout
= &args
[0];
134 fprintf(stderr
, "W");
137 if (!custom_timeout
|| !timerisset(custom_timeout
)) {
138 php_http_client_curl_get_timeout(ctx
->client
->ctx
, 1000, &timeout
);
139 custom_timeout
= &timeout
;
142 ZVAL_LONG(ztimeout
, custom_timeout
->tv_sec
* 1000 + custom_timeout
->tv_usec
/ 1000);
143 rv
= php_http_object_method_call(&ctx
->wait
, &ctx
->user
, NULL
, 1, args
);
144 zval_ptr_dtor(ztimeout
);
149 static ZEND_RESULT_CODE
php_http_client_curl_user_exec(void *context
)
151 php_http_client_curl_user_context_t
*ctx
= context
;
152 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
155 fprintf(stderr
, "E");
159 php_http_client_curl_loop(ctx
->client
, CURL_SOCKET_TIMEOUT
, 0);
162 if (SUCCESS
!= php_http_object_method_call(&ctx
->send
, &ctx
->user
, NULL
, 0, NULL
)) {
165 } while (curl
->unfinished
&& !EG(exception
));
170 static void *php_http_client_curl_user_init(php_http_client_t
*client
, void *user_data
)
172 php_http_client_curl_t
*curl
= client
->ctx
;
173 php_http_client_curl_user_context_t
*ctx
;
174 php_http_object_method_t init
;
175 zval args
[1], *zclosure
= &args
[0];
178 fprintf(stderr
, "I");
181 ctx
= ecalloc(1, sizeof(*ctx
));
182 ctx
->client
= client
;
183 ZVAL_COPY(&ctx
->user
, user_data
);
185 memset(&ctx
->closure
, 0, sizeof(ctx
->closure
));
186 ctx
->closure
.common
.type
= ZEND_INTERNAL_FUNCTION
;
187 ctx
->closure
.common
.function_name
= zend_string_init(ZEND_STRL("php_http_client_curl_user_handler"), 0);
188 ctx
->closure
.internal_function
.handler
= php_http_client_curl_user_handler
;
190 zend_create_closure(zclosure
, &ctx
->closure
, NULL
, NULL
, NULL
);
192 php_http_object_method_init(&init
, &ctx
->user
, ZEND_STRL("init"));
193 php_http_object_method_call(&init
, &ctx
->user
, NULL
, 1, args
);
194 php_http_object_method_dtor(&init
);
195 zval_ptr_dtor(zclosure
);
197 php_http_object_method_init(&ctx
->timer
, &ctx
->user
, ZEND_STRL("timer"));
198 php_http_object_method_init(&ctx
->socket
, &ctx
->user
, ZEND_STRL("socket"));
199 php_http_object_method_init(&ctx
->once
, &ctx
->user
, ZEND_STRL("once"));
200 php_http_object_method_init(&ctx
->wait
, &ctx
->user
, ZEND_STRL("wait"));
201 php_http_object_method_init(&ctx
->send
, &ctx
->user
, ZEND_STRL("send"));
203 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, ctx
);
204 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, php_http_client_curl_user_socket
);
205 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, ctx
);
206 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, php_http_client_curl_user_timer
);
211 static void php_http_client_curl_user_dtor(void **context
)
213 php_http_client_curl_user_context_t
*ctx
= *context
;
214 php_http_client_curl_t
*curl
;
217 fprintf(stderr
, "D");
220 curl
= ctx
->client
->ctx
;
222 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, NULL
);
223 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, NULL
);
224 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, NULL
);
225 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, NULL
);
227 php_http_object_method_dtor(&ctx
->timer
);
228 php_http_object_method_dtor(&ctx
->socket
);
229 php_http_object_method_dtor(&ctx
->once
);
230 php_http_object_method_dtor(&ctx
->wait
);
231 php_http_object_method_dtor(&ctx
->send
);
233 zend_string_release(ctx
->closure
.common
.function_name
);
234 zval_ptr_dtor(&ctx
->user
);
240 static php_http_client_curl_ops_t php_http_client_curl_user_ops
= {
241 &php_http_client_curl_user_init
,
242 &php_http_client_curl_user_dtor
,
243 &php_http_client_curl_user_once
,
244 &php_http_client_curl_user_wait
,
245 &php_http_client_curl_user_exec
,
248 php_http_client_curl_ops_t
*php_http_client_curl_user_ops_get()
250 return &php_http_client_curl_user_ops
;
253 static zend_class_entry
*php_http_client_curl_user_class_entry
;
255 zend_class_entry
*php_http_client_curl_user_get_class_entry()
257 return php_http_client_curl_user_class_entry
;
260 ZEND_BEGIN_ARG_INFO_EX(ai_init
, 0, 0, 1)
261 /* using IS_CALLABLE type hint would create a forwards compatibility break */
262 ZEND_ARG_INFO(0, run
)
264 ZEND_BEGIN_ARG_INFO_EX(ai_timer
, 0, 0, 1)
265 #if PHP_VERSION_ID >= 70000
266 ZEND_ARG_TYPE_INFO(0, timeout_ms
, IS_LONG
, 0)
268 ZEND_ARG_INFO(0, timeout_ms
)
271 ZEND_BEGIN_ARG_INFO_EX(ai_socket
, 0, 0, 2)
272 ZEND_ARG_INFO(0, socket
)
273 #if PHP_VERSION_ID >= 70000
274 ZEND_ARG_TYPE_INFO(0, action
, IS_LONG
, 0)
276 ZEND_ARG_INFO(0, action
)
279 ZEND_BEGIN_ARG_INFO_EX(ai_once
, 0, 0, 0)
281 ZEND_BEGIN_ARG_INFO_EX(ai_wait
, 0, 0, 0)
282 #if PHP_VERSION_ID >= 70000
283 ZEND_ARG_TYPE_INFO(0, timeout_ms
, IS_LONG
, 0)
285 ZEND_ARG_INFO(0, timeout_ms
)
288 ZEND_BEGIN_ARG_INFO_EX(ai_send
, 0, 0, 0)
291 static zend_function_entry php_http_client_curl_user_methods
[] = {
292 PHP_ABSTRACT_ME(HttpClientCurlUser
, init
, ai_init
)
293 PHP_ABSTRACT_ME(HttpClientCurlUser
, timer
, ai_timer
)
294 PHP_ABSTRACT_ME(HttpClientCurlUser
, socket
, ai_socket
)
295 PHP_ABSTRACT_ME(HttpClientCurlUser
, once
, ai_once
)
296 PHP_ABSTRACT_ME(HttpClientCurlUser
, wait
, ai_wait
)
297 PHP_ABSTRACT_ME(HttpClientCulrUser
, send
, ai_send
)
301 PHP_MINIT_FUNCTION(http_client_curl_user
)
303 zend_class_entry ce
= {0};
305 INIT_NS_CLASS_ENTRY(ce
, "http\\Client\\Curl", "User", php_http_client_curl_user_methods
);
306 php_http_client_curl_user_class_entry
= zend_register_internal_interface(&ce
);
308 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_NONE"), CURL_POLL_NONE
);
309 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_IN"), CURL_POLL_IN
);
310 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_OUT"), CURL_POLL_OUT
);
311 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_INOUT"), CURL_POLL_INOUT
);
312 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_REMOVE"), CURL_POLL_REMOVE
);
317 #endif /* PHP_HTTP_HAVE_LIBCURL */
324 * vim600: noet sw=4 ts=4 fdm=marker
325 * vim<600: noet sw=4 ts=4