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 php_http_client_curl_loop(context
->client
, CURL_SOCKET_TIMEOUT
, 0);
63 zval args
[1], *ztimeout
= &args
[0];
65 ZVAL_LONG(ztimeout
, timeout_ms
);
66 php_http_object_method_call(&context
->timer
, &context
->user
, NULL
, 1, args
);
67 zval_ptr_dtor(ztimeout
);
71 static int php_http_client_curl_user_socket(CURL
*easy
, curl_socket_t sock
, int action
, void *socket_data
, void *assign_data
)
73 php_http_client_curl_user_context_t
*ctx
= socket_data
;
74 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
75 php_http_client_curl_user_ev_t
*ev
= assign_data
;
76 zval args
[2], *zaction
= &args
[1], *zsocket
= &args
[0];
83 ev
= ecalloc(1, sizeof(*ev
));
85 ev
->socket
= php_stream_sock_open_from_socket(sock
, NULL
);
87 curl_multi_assign(curl
->handle
->multi
, sock
, ev
);
94 case CURL_POLL_REMOVE
:
96 php_stream_to_zval(ev
->socket
, zsocket
);
97 Z_TRY_ADDREF_P(zsocket
);
98 ZVAL_LONG(zaction
, action
);
99 php_http_object_method_call(&ctx
->socket
, &ctx
->user
, NULL
, 2, args
);
100 zval_ptr_dtor(zsocket
);
101 zval_ptr_dtor(zaction
);
105 php_error_docref(NULL
, E_WARNING
, "Unknown socket action %d", action
);
109 if (action
== CURL_POLL_REMOVE
) {
110 php_stream_close(ev
->socket
);
112 curl_multi_assign(curl
->handle
->multi
, sock
, NULL
);
117 static ZEND_RESULT_CODE
php_http_client_curl_user_once(void *context
)
119 php_http_client_curl_user_context_t
*ctx
= context
;
122 fprintf(stderr
, "O");
125 return php_http_object_method_call(&ctx
->once
, &ctx
->user
, NULL
, 0, NULL
);
128 static ZEND_RESULT_CODE
php_http_client_curl_user_wait(void *context
, struct timeval
*custom_timeout
)
130 php_http_client_curl_user_context_t
*ctx
= context
;
131 struct timeval timeout
;
132 zval args
[1], *ztimeout
= &args
[0];
136 fprintf(stderr
, "W");
139 if (!custom_timeout
|| !timerisset(custom_timeout
)) {
140 php_http_client_curl_get_timeout(ctx
->client
->ctx
, 1000, &timeout
);
141 custom_timeout
= &timeout
;
144 ZVAL_LONG(ztimeout
, custom_timeout
->tv_sec
* 1000 + custom_timeout
->tv_usec
/ 1000);
145 rv
= php_http_object_method_call(&ctx
->wait
, &ctx
->user
, NULL
, 1, args
);
146 zval_ptr_dtor(ztimeout
);
151 static ZEND_RESULT_CODE
php_http_client_curl_user_exec(void *context
)
153 php_http_client_curl_user_context_t
*ctx
= context
;
154 php_http_client_curl_t
*curl
= ctx
->client
->ctx
;
157 fprintf(stderr
, "E");
161 php_http_client_curl_loop(ctx
->client
, CURL_SOCKET_TIMEOUT
, 0);
164 if (SUCCESS
!= php_http_object_method_call(&ctx
->send
, &ctx
->user
, NULL
, 0, NULL
)) {
167 } while (curl
->unfinished
&& !EG(exception
));
172 static void *php_http_client_curl_user_init(php_http_client_t
*client
, void *user_data
)
174 php_http_client_curl_t
*curl
= client
->ctx
;
175 php_http_client_curl_user_context_t
*ctx
;
176 php_http_object_method_t init
;
177 zval args
[1], *zclosure
= &args
[0];
180 fprintf(stderr
, "I");
183 ctx
= ecalloc(1, sizeof(*ctx
));
184 ctx
->client
= client
;
185 ZVAL_COPY(&ctx
->user
, user_data
);
187 memset(&ctx
->closure
, 0, sizeof(ctx
->closure
));
188 ctx
->closure
.common
.type
= ZEND_INTERNAL_FUNCTION
;
189 ctx
->closure
.common
.function_name
= zend_string_init(ZEND_STRL("php_http_client_curl_user_handler"), 0);
190 ctx
->closure
.internal_function
.handler
= php_http_client_curl_user_handler
;
192 zend_create_closure(zclosure
, &ctx
->closure
, NULL
, NULL
, NULL
);
194 php_http_object_method_init(&init
, &ctx
->user
, ZEND_STRL("init"));
195 php_http_object_method_call(&init
, &ctx
->user
, NULL
, 1, args
);
196 php_http_object_method_dtor(&init
);
197 zval_ptr_dtor(zclosure
);
199 php_http_object_method_init(&ctx
->timer
, &ctx
->user
, ZEND_STRL("timer"));
200 php_http_object_method_init(&ctx
->socket
, &ctx
->user
, ZEND_STRL("socket"));
201 php_http_object_method_init(&ctx
->once
, &ctx
->user
, ZEND_STRL("once"));
202 php_http_object_method_init(&ctx
->wait
, &ctx
->user
, ZEND_STRL("wait"));
203 php_http_object_method_init(&ctx
->send
, &ctx
->user
, ZEND_STRL("send"));
205 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, ctx
);
206 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, php_http_client_curl_user_socket
);
207 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, ctx
);
208 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, php_http_client_curl_user_timer
);
213 static void php_http_client_curl_user_dtor(void **context
)
215 php_http_client_curl_user_context_t
*ctx
= *context
;
216 php_http_client_curl_t
*curl
;
219 fprintf(stderr
, "D");
222 curl
= ctx
->client
->ctx
;
224 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, NULL
);
225 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, NULL
);
226 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, NULL
);
227 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, NULL
);
229 php_http_object_method_dtor(&ctx
->timer
);
230 php_http_object_method_dtor(&ctx
->socket
);
231 php_http_object_method_dtor(&ctx
->once
);
232 php_http_object_method_dtor(&ctx
->wait
);
233 php_http_object_method_dtor(&ctx
->send
);
235 zend_string_release(ctx
->closure
.common
.function_name
);
236 zval_ptr_dtor(&ctx
->user
);
242 static php_http_client_curl_ops_t php_http_client_curl_user_ops
= {
243 &php_http_client_curl_user_init
,
244 &php_http_client_curl_user_dtor
,
245 &php_http_client_curl_user_once
,
246 &php_http_client_curl_user_wait
,
247 &php_http_client_curl_user_exec
,
250 php_http_client_curl_ops_t
*php_http_client_curl_user_ops_get()
252 return &php_http_client_curl_user_ops
;
255 static zend_class_entry
*php_http_client_curl_user_class_entry
;
257 zend_class_entry
*php_http_client_curl_user_get_class_entry()
259 return php_http_client_curl_user_class_entry
;
262 ZEND_BEGIN_ARG_INFO_EX(ai_init
, 0, 0, 1)
263 /* using IS_CALLABLE type hint would create a forwards compatibility break */
264 ZEND_ARG_INFO(0, run
)
266 ZEND_BEGIN_ARG_INFO_EX(ai_timer
, 0, 0, 1)
267 #if PHP_VERSION_ID >= 70000
268 ZEND_ARG_TYPE_INFO(0, timeout_ms
, IS_LONG
, 0)
270 ZEND_ARG_INFO(0, timeout_ms
)
273 ZEND_BEGIN_ARG_INFO_EX(ai_socket
, 0, 0, 2)
274 ZEND_ARG_INFO(0, socket
)
275 #if PHP_VERSION_ID >= 70000
276 ZEND_ARG_TYPE_INFO(0, action
, IS_LONG
, 0)
278 ZEND_ARG_INFO(0, action
)
281 ZEND_BEGIN_ARG_INFO_EX(ai_once
, 0, 0, 0)
283 ZEND_BEGIN_ARG_INFO_EX(ai_wait
, 0, 0, 0)
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_send
, 0, 0, 0)
293 static zend_function_entry php_http_client_curl_user_methods
[] = {
294 PHP_ABSTRACT_ME(HttpClientCurlUser
, init
, ai_init
)
295 PHP_ABSTRACT_ME(HttpClientCurlUser
, timer
, ai_timer
)
296 PHP_ABSTRACT_ME(HttpClientCurlUser
, socket
, ai_socket
)
297 PHP_ABSTRACT_ME(HttpClientCurlUser
, once
, ai_once
)
298 PHP_ABSTRACT_ME(HttpClientCurlUser
, wait
, ai_wait
)
299 PHP_ABSTRACT_ME(HttpClientCulrUser
, send
, ai_send
)
303 PHP_MINIT_FUNCTION(http_client_curl_user
)
305 zend_class_entry ce
= {0};
307 INIT_NS_CLASS_ENTRY(ce
, "http\\Client\\Curl", "User", php_http_client_curl_user_methods
);
308 php_http_client_curl_user_class_entry
= zend_register_internal_interface(&ce
);
310 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_NONE"), CURL_POLL_NONE
);
311 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_IN"), CURL_POLL_IN
);
312 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_OUT"), CURL_POLL_OUT
);
313 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_INOUT"), CURL_POLL_INOUT
);
314 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_REMOVE"), CURL_POLL_REMOVE
);
319 #endif /* PHP_HTTP_HAVE_LIBCURL */
326 * vim600: noet sw=4 ts=4 fdm=marker
327 * vim<600: noet sw=4 ts=4