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 zend_create_closure(zclosure
, &ctx
->closure
, NULL
, NULL TSRMLS_CC
);
222 php_http_object_method_init(&init
, ctx
->user
, ZEND_STRL("init") TSRMLS_CC
);
223 php_http_object_method_call(&init
, ctx
->user
, NULL
, 1, args TSRMLS_CC
);
224 php_http_object_method_dtor(&init
);
225 zval_ptr_dtor(&zclosure
);
227 php_http_object_method_init(&ctx
->timer
, ctx
->user
, ZEND_STRL("timer") TSRMLS_CC
);
228 php_http_object_method_init(&ctx
->socket
, ctx
->user
, ZEND_STRL("socket") TSRMLS_CC
);
229 php_http_object_method_init(&ctx
->once
, ctx
->user
, ZEND_STRL("once") TSRMLS_CC
);
230 php_http_object_method_init(&ctx
->wait
, ctx
->user
, ZEND_STRL("wait") TSRMLS_CC
);
231 php_http_object_method_init(&ctx
->send
, ctx
->user
, ZEND_STRL("send") TSRMLS_CC
);
233 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, ctx
);
234 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, php_http_client_curl_user_socket
);
235 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, ctx
);
236 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, php_http_client_curl_user_timer
);
241 static void php_http_client_curl_user_dtor(void **context
)
243 php_http_client_curl_user_context_t
*ctx
= *context
;
244 php_http_client_curl_t
*curl
;
247 fprintf(stderr
, "D");
250 curl
= ctx
->client
->ctx
;
252 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETDATA
, NULL
);
253 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_SOCKETFUNCTION
, NULL
);
254 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERDATA
, NULL
);
255 curl_multi_setopt(curl
->handle
->multi
, CURLMOPT_TIMERFUNCTION
, NULL
);
257 php_http_object_method_dtor(&ctx
->timer
);
258 php_http_object_method_dtor(&ctx
->socket
);
259 php_http_object_method_dtor(&ctx
->once
);
260 php_http_object_method_dtor(&ctx
->wait
);
261 php_http_object_method_dtor(&ctx
->send
);
263 zval_ptr_dtor(&ctx
->user
);
269 static php_http_client_curl_ops_t php_http_client_curl_user_ops
= {
270 &php_http_client_curl_user_init
,
271 &php_http_client_curl_user_dtor
,
272 &php_http_client_curl_user_once
,
273 &php_http_client_curl_user_wait
,
274 &php_http_client_curl_user_exec
,
277 php_http_client_curl_ops_t
*php_http_client_curl_user_ops_get()
279 return &php_http_client_curl_user_ops
;
282 zend_class_entry
*php_http_client_curl_user_class_entry
;
284 ZEND_BEGIN_ARG_INFO_EX(ai_init
, 0, 0, 1)
285 ZEND_ARG_TYPE_INFO(0, run
, IS_CALLABLE
, 0)
287 ZEND_BEGIN_ARG_INFO_EX(ai_timer
, 0, 0, 1)
288 #if PHP_VERSION_ID >= 70000
289 ZEND_ARG_TYPE_INFO(0, timeout_ms
, IS_LONG
, 0)
291 ZEND_ARG_INFO(0, timeout_ms
)
294 ZEND_BEGIN_ARG_INFO_EX(ai_socket
, 0, 0, 2)
295 #if PHP_VERSION_ID >= 70000
296 ZEND_ARG_TYPE_INFO(0, socket
, IS_RESOURCE
, 0)
297 ZEND_ARG_TYPE_INFO(0, action
, IS_LONG
, 0)
299 ZEND_ARG_INFO(0, socket
)
300 ZEND_ARG_INFO(0, action
)
303 ZEND_BEGIN_ARG_INFO_EX(ai_once
, 0, 0, 0)
305 ZEND_BEGIN_ARG_INFO_EX(ai_wait
, 0, 0, 0)
306 #if PHP_VERSION_ID >= 70000
307 ZEND_ARG_TYPE_INFO(0, timeout_ms
, IS_LONG
, 0)
309 ZEND_ARG_INFO(0, timeout_ms
)
312 ZEND_BEGIN_ARG_INFO_EX(ai_send
, 0, 0, 0)
315 static zend_function_entry php_http_client_curl_user_methods
[] = {
316 PHP_ABSTRACT_ME(HttpClientCurlUser
, init
, ai_init
)
317 PHP_ABSTRACT_ME(HttpClientCurlUser
, timer
, ai_timer
)
318 PHP_ABSTRACT_ME(HttpClientCurlUser
, socket
, ai_socket
)
319 PHP_ABSTRACT_ME(HttpClientCurlUser
, once
, ai_once
)
320 PHP_ABSTRACT_ME(HttpClientCurlUser
, wait
, ai_wait
)
321 PHP_ABSTRACT_ME(HttpClientCulrUser
, send
, ai_send
)
325 PHP_MINIT_FUNCTION(http_client_curl_user
)
327 zend_class_entry ce
= {0};
329 INIT_NS_CLASS_ENTRY(ce
, "http\\Client\\Curl", "User", php_http_client_curl_user_methods
);
330 php_http_client_curl_user_class_entry
= zend_register_internal_interface(&ce TSRMLS_CC
);
332 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_NONE"), CURL_POLL_NONE TSRMLS_CC
);
333 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_IN"), CURL_POLL_IN TSRMLS_CC
);
334 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_OUT"), CURL_POLL_OUT TSRMLS_CC
);
335 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_INOUT"), CURL_POLL_INOUT TSRMLS_CC
);
336 zend_declare_class_constant_long(php_http_client_curl_user_class_entry
, ZEND_STRL("POLL_REMOVE"), CURL_POLL_REMOVE TSRMLS_CC
);
341 #endif /* PHP_HTTP_HAVE_CURL */
348 * vim600: noet sw=4 ts=4 fdm=marker
349 * vim<600: noet sw=4 ts=4