1 #include "php_http_api.h"
2 #include "php_http_client.h"
4 #include <ext/spl/spl_observer.h>
7 * array of name => php_http_client_driver_t*
9 static HashTable php_http_client_drivers
;
11 PHP_HTTP_API STATUS
php_http_client_driver_add(const char *name_str
, uint name_len
, php_http_client_driver_t
*driver
)
13 return zend_hash_add(&php_http_client_drivers
, name_str
, name_len
+ 1, (void *) driver
, sizeof(php_http_client_driver_t
), NULL
);
16 PHP_HTTP_API STATUS
php_http_client_driver_get(char **name_str
, uint
*name_len
, php_http_client_driver_t
*driver
)
18 php_http_client_driver_t
*tmp
;
20 if (*name_str
&& SUCCESS
== zend_hash_find(&php_http_client_drivers
, *name_str
, (*name_len
) + 1, (void *) &tmp
)) {
23 } else if (SUCCESS
== zend_hash_get_current_data(&php_http_client_drivers
, (void *) &tmp
)) {
24 zend_hash_get_current_key_ex(&php_http_client_drivers
, name_str
, name_len
, NULL
, 0, NULL
);
32 void php_http_client_options_set_subr(zval
*this_ptr
, char *key
, size_t len
, zval
*opts
, int overwrite TSRMLS_DC
)
34 if (overwrite
|| (opts
&& zend_hash_num_elements(Z_ARRVAL_P(opts
)))) {
35 zend_class_entry
*this_ce
= Z_OBJCE_P(getThis());
36 zval
*old_opts
, *new_opts
, **entry
= NULL
;
38 MAKE_STD_ZVAL(new_opts
);
40 old_opts
= zend_read_property(this_ce
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
41 if (Z_TYPE_P(old_opts
) == IS_ARRAY
) {
42 array_copy(Z_ARRVAL_P(old_opts
), Z_ARRVAL_P(new_opts
));
46 if (opts
&& zend_hash_num_elements(Z_ARRVAL_P(opts
))) {
48 zend_symtable_update(Z_ARRVAL_P(new_opts
), key
, len
, (void *) &opts
, sizeof(zval
*), NULL
);
50 zend_symtable_del(Z_ARRVAL_P(new_opts
), key
, len
);
52 } else if (opts
&& zend_hash_num_elements(Z_ARRVAL_P(opts
))) {
53 if (SUCCESS
== zend_symtable_find(Z_ARRVAL_P(new_opts
), key
, len
, (void *) &entry
)) {
54 array_join(Z_ARRVAL_P(opts
), Z_ARRVAL_PP(entry
), 0, 0);
57 zend_symtable_update(Z_ARRVAL_P(new_opts
), key
, len
, (void *) &opts
, sizeof(zval
*), NULL
);
61 zend_update_property(this_ce
, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC
);
62 zval_ptr_dtor(&new_opts
);
66 void php_http_client_options_set(zval
*this_ptr
, zval
*opts TSRMLS_DC
)
68 php_http_array_hashkey_t key
= php_http_array_hashkey_init(0);
71 zend_class_entry
*this_ce
= Z_OBJCE_P(getThis());
72 zend_bool is_client
= instanceof_function(this_ce
, php_http_client_class_entry TSRMLS_CC
);
74 MAKE_STD_ZVAL(new_opts
);
77 if (!opts
|| !zend_hash_num_elements(Z_ARRVAL_P(opts
))) {
78 zend_update_property(this_ce
, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC
);
79 zval_ptr_dtor(&new_opts
);
81 zval
*old_opts
, *add_opts
, **opt
;
83 MAKE_STD_ZVAL(add_opts
);
85 /* some options need extra attention -- thus cannot use array_merge() directly */
86 FOREACH_KEYVAL(pos
, opts
, key
, opt
) {
87 if (key
.type
== HASH_KEY_IS_STRING
) {
88 #define KEYMATCH(k, s) ((sizeof(s)==k.len) && !strcasecmp(k.str, s))
89 if (Z_TYPE_PP(opt
) == IS_ARRAY
&& (KEYMATCH(key
, "ssl") || KEYMATCH(key
, "cookies"))) {
90 php_http_client_options_set_subr(getThis(), key
.str
, key
.len
, *opt
, 0 TSRMLS_CC
);
91 } else if (is_client
&& (KEYMATCH(key
, "recordHistory") || KEYMATCH(key
, "responseMessageClass"))) {
92 zend_update_property(this_ce
, getThis(), key
.str
, key
.len
-1, *opt TSRMLS_CC
);
93 } else if (Z_TYPE_PP(opt
) == IS_NULL
) {
94 old_opts
= zend_read_property(this_ce
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
95 if (Z_TYPE_P(old_opts
) == IS_ARRAY
) {
96 zend_symtable_del(Z_ARRVAL_P(old_opts
), key
.str
, key
.len
);
100 add_assoc_zval_ex(add_opts
, key
.str
, key
.len
, *opt
);
105 old_opts
= zend_read_property(this_ce
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
106 if (Z_TYPE_P(old_opts
) == IS_ARRAY
) {
107 array_copy(Z_ARRVAL_P(old_opts
), Z_ARRVAL_P(new_opts
));
109 array_join(Z_ARRVAL_P(add_opts
), Z_ARRVAL_P(new_opts
), 0, 0);
110 zend_update_property(this_ce
, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC
);
111 zval_ptr_dtor(&new_opts
);
112 zval_ptr_dtor(&add_opts
);
116 void php_http_client_options_get_subr(zval
*this_ptr
, char *key
, size_t len
, zval
*return_value TSRMLS_DC
)
118 zend_class_entry
*this_ce
= Z_OBJCE_P(getThis());
119 zval
**options
, *opts
= zend_read_property(this_ce
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
121 if ((Z_TYPE_P(opts
) == IS_ARRAY
) && (SUCCESS
== zend_symtable_find(Z_ARRVAL_P(opts
), key
, len
, (void *) &options
))) {
122 RETVAL_ZVAL(*options
, 1, 0);
126 static void queue_dtor(void *enqueued
)
128 php_http_client_enqueue_t
*e
= enqueued
;
135 PHP_HTTP_API php_http_client_t
*php_http_client_init(php_http_client_t
*h
, php_http_client_ops_t
*ops
, php_resource_factory_t
*rf
, void *init_arg TSRMLS_DC
)
137 php_http_client_t
*free_h
= NULL
;
140 free_h
= h
= emalloc(sizeof(*h
));
142 memset(h
, 0, sizeof(*h
));
147 } else if (ops
->rsrc
) {
148 h
->rf
= php_resource_factory_init(NULL
, h
->ops
->rsrc
, h
, NULL
);
150 zend_llist_init(&h
->requests
, sizeof(php_http_client_enqueue_t
), queue_dtor
, 0);
151 zend_llist_init(&h
->responses
, sizeof(void *), NULL
, 0);
152 TSRMLS_SET_CTX(h
->ts
);
155 if (!(h
= h
->ops
->init(h
, init_arg
))) {
156 php_http_error(HE_WARNING
, PHP_HTTP_E_CLIENT
, "Could not initialize client");
166 PHP_HTTP_API php_http_client_t
*php_http_client_copy(php_http_client_t
*from
, php_http_client_t
*to
)
168 if (from
->ops
->copy
) {
169 return from
->ops
->copy(from
, to
);
175 PHP_HTTP_API
void php_http_client_dtor(php_http_client_t
*h
)
181 zend_llist_clean(&h
->requests
);
182 zend_llist_clean(&h
->responses
);
184 php_resource_factory_free(&h
->rf
);
187 PHP_HTTP_API
void php_http_client_free(php_http_client_t
**h
) {
189 php_http_client_dtor(*h
);
195 PHP_HTTP_API STATUS
php_http_client_enqueue(php_http_client_t
*h
, php_http_client_enqueue_t
*enqueue
)
197 TSRMLS_FETCH_FROM_CTX(h
->ts
);
199 if (h
->ops
->enqueue
) {
200 if (php_http_client_enqueued(h
, enqueue
->request
, NULL
)) {
201 php_http_error(HE_WARNING
, PHP_HTTP_E_CLIENT
, "Failed to enqueue request; request already in queue");
204 return h
->ops
->enqueue(h
, enqueue
);
210 PHP_HTTP_API STATUS
php_http_client_dequeue(php_http_client_t
*h
, php_http_message_t
*request
)
212 TSRMLS_FETCH_FROM_CTX(h
->ts
);
214 if (h
->ops
->dequeue
) {
215 php_http_client_enqueue_t
*enqueue
= php_http_client_enqueued(h
, request
, NULL
);
218 php_http_error(HE_WARNING
, PHP_HTTP_E_CLIENT
, "Failed to dequeue request; request not in queue");
221 return h
->ops
->dequeue(h
, enqueue
);
226 PHP_HTTP_API php_http_client_enqueue_t
*php_http_client_enqueued(php_http_client_t
*h
, void *compare_arg
, php_http_client_enqueue_cmp_func_t compare_func
)
228 zend_llist_element
*el
= NULL
;
231 for (el
= h
->requests
.head
; el
; el
= el
->next
) {
232 if (compare_func((php_http_client_enqueue_t
*) el
->data
, compare_arg
)) {
237 for (el
= h
->requests
.head
; el
; el
= el
->next
) {
238 if (((php_http_client_enqueue_t
*) el
->data
)->request
== compare_arg
) {
243 return el
? (php_http_client_enqueue_t
*) el
->data
: NULL
;
246 PHP_HTTP_API STATUS
php_http_client_wait(php_http_client_t
*h
, struct timeval
*custom_timeout
)
249 return h
->ops
->wait(h
, custom_timeout
);
255 PHP_HTTP_API
int php_http_client_once(php_http_client_t
*h
)
258 return h
->ops
->once(h
);
264 PHP_HTTP_API STATUS
php_http_client_exec(php_http_client_t
*h
)
267 return h
->ops
->exec(h
);
273 PHP_HTTP_API
void php_http_client_reset(php_http_client_t
*h
)
279 zend_llist_clean(&h
->requests
);
280 zend_llist_clean(&h
->responses
);
283 PHP_HTTP_API STATUS
php_http_client_setopt(php_http_client_t
*h
, php_http_client_setopt_opt_t opt
, void *arg
)
285 if (h
->ops
->setopt
) {
286 return h
->ops
->setopt(h
, opt
, arg
);
292 PHP_HTTP_API STATUS
php_http_client_getopt(php_http_client_t
*h
, php_http_client_getopt_opt_t opt
, void *arg
, void *res_ptr
)
294 if (h
->ops
->getopt
) {
295 return h
->ops
->getopt(h
, opt
, arg
, res_ptr
);
300 zend_class_entry
*php_http_client_class_entry
;
301 static zend_object_handlers php_http_client_object_handlers
;
303 void php_http_client_object_free(void *object TSRMLS_DC
)
305 php_http_client_object_t
*o
= (php_http_client_object_t
*) object
;
307 php_http_client_free(&o
->client
);
308 zend_object_std_dtor((zend_object
*) o TSRMLS_CC
);
312 zend_object_value
php_http_client_object_new_ex(zend_class_entry
*ce
, php_http_client_t
*client
, php_http_client_object_t
**ptr TSRMLS_DC
)
314 php_http_client_object_t
*o
;
316 o
= ecalloc(1, sizeof(php_http_client_object_t
));
317 zend_object_std_init((zend_object
*) o
, ce TSRMLS_CC
);
318 object_properties_init((zend_object
*) o
, ce
);
326 o
->zv
.handle
= zend_objects_store_put(o
, NULL
, php_http_client_object_free
, NULL TSRMLS_CC
);
327 o
->zv
.handlers
= &php_http_client_object_handlers
;
332 zend_object_value
php_http_client_object_new(zend_class_entry
*ce TSRMLS_DC
)
334 return php_http_client_object_new_ex(ce
, NULL
, NULL TSRMLS_CC
);
337 static void handle_history(zval
*zclient
, php_http_message_t
*request
, php_http_message_t
*response TSRMLS_DC
)
339 zval
*new_hist
, *old_hist
= zend_read_property(php_http_client_class_entry
, zclient
, ZEND_STRL("history"), 0 TSRMLS_CC
);
340 php_http_message_t
*zipped
= php_http_message_zip(response
, request
);
341 zend_object_value ov
= php_http_message_object_new_ex(php_http_message_get_class_entry(), zipped
, NULL TSRMLS_CC
);
343 MAKE_STD_ZVAL(new_hist
);
344 ZVAL_OBJVAL(new_hist
, ov
, 0);
346 if (Z_TYPE_P(old_hist
) == IS_OBJECT
) {
347 php_http_message_object_prepend(new_hist
, old_hist
, 1 TSRMLS_CC
);
350 zend_update_property(php_http_client_class_entry
, zclient
, ZEND_STRL("history"), new_hist TSRMLS_CC
);
351 zval_ptr_dtor(&new_hist
);
354 static STATUS
handle_response(void *arg
, php_http_client_t
*client
, php_http_client_enqueue_t
*e
, php_http_message_t
**request
, php_http_message_t
**response
)
357 php_http_message_t
*msg
;
358 php_http_client_progress_state_t
*progress
;
359 TSRMLS_FETCH_FROM_CTX(client
->ts
);
361 INIT_PZVAL(&zclient
);
362 ZVAL_OBJVAL(&zclient
, ((php_http_client_object_t
*) arg
)->zv
, 0);
364 if ((msg
= *response
)) {
365 php_http_message_object_t
*msg_obj
;
366 zval
*info
, *zresponse
, *zrequest
;
368 if (i_zend_is_true(zend_read_property(php_http_client_class_entry
, &zclient
, ZEND_STRL("recordHistory"), 0 TSRMLS_CC
))) {
369 handle_history(&zclient
, *request
, *response TSRMLS_CC
);
372 /* hard detach, redirects etc. are in the history */
373 php_http_message_free(&msg
->parent
);
376 MAKE_STD_ZVAL(zresponse
);
377 ZVAL_OBJVAL(zresponse
, php_http_message_object_new_ex(php_http_client_response_get_class_entry(), msg
, &msg_obj TSRMLS_CC
), 0);
379 MAKE_STD_ZVAL(zrequest
);
380 ZVAL_OBJVAL(zrequest
, ((php_http_message_object_t
*) e
->opaque
)->zv
, 1);
382 php_http_message_object_prepend(zresponse
, zrequest
, 1 TSRMLS_CC
);
386 php_http_client_getopt(client
, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO
, e
->request
, &Z_ARRVAL_P(info
));
387 zend_update_property(php_http_client_response_get_class_entry(), zresponse
, ZEND_STRL("transferInfo"), info TSRMLS_CC
);
388 zval_ptr_dtor(&info
);
390 zend_objects_store_add_ref_by_handle(msg_obj
->zv
.handle TSRMLS_CC
);
391 zend_llist_add_element(&client
->responses
, &msg_obj
);
393 if (e
->closure
.fci
.size
) {
396 zend_fcall_info_argn(&e
->closure
.fci TSRMLS_CC
, 1, &zresponse
);
397 with_error_handling(EH_NORMAL
, NULL
) {
398 zend_fcall_info_call(&e
->closure
.fci
, &e
->closure
.fcc
, &retval
, NULL TSRMLS_CC
);
399 } end_error_handling();
400 zend_fcall_info_argn(&e
->closure
.fci TSRMLS_CC
, 0);
403 if (Z_TYPE_P(retval
) == IS_BOOL
&& Z_BVAL_P(retval
)) {
404 php_http_client_dequeue(client
, e
->request
);
406 zval_ptr_dtor(&retval
);
410 zval_ptr_dtor(&zresponse
);
411 zval_ptr_dtor(&zrequest
);
414 if (SUCCESS
== php_http_client_getopt(client
, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO
, e
->request
, &progress
)) {
415 progress
->info
= "finished";
416 progress
->finished
= 1;
417 client
->callback
.progress
.func(client
->callback
.progress
.arg
, client
, e
, progress
);
423 static void handle_progress(void *arg
, php_http_client_t
*client
, php_http_client_enqueue_t
*e
, php_http_client_progress_state_t
*state
)
425 zval
*zrequest
, *retval
= NULL
, *zclient
;
426 TSRMLS_FETCH_FROM_CTX(client
->ts
);
428 MAKE_STD_ZVAL(zclient
);
429 ZVAL_OBJVAL(zclient
, ((php_http_client_object_t
*) arg
)->zv
, 1);
430 MAKE_STD_ZVAL(zrequest
);
431 ZVAL_OBJVAL(zrequest
, ((php_http_message_object_t
*) e
->opaque
)->zv
, 1);
432 with_error_handling(EH_NORMAL
, NULL
) {
433 zend_call_method_with_1_params(&zclient
, NULL
, NULL
, "notify", &retval
, zrequest
);
434 } end_error_handling();
435 zval_ptr_dtor(&zclient
);
436 zval_ptr_dtor(&zrequest
);
438 zval_ptr_dtor(&retval
);
442 static void response_dtor(void *data
)
444 php_http_message_object_t
*msg_obj
= *(php_http_message_object_t
**) data
;
445 TSRMLS_FETCH_FROM_CTX(msg_obj
->message
->ts
);
447 zend_objects_store_del_ref_by_handle_ex(msg_obj
->zv
.handle
, msg_obj
->zv
.handlers TSRMLS_CC
);
450 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_construct
, 0, 0, 0)
451 ZEND_ARG_INFO(0, driver
)
452 ZEND_ARG_INFO(0, persistent_handle_id
)
454 static PHP_METHOD(HttpClient
, __construct
)
456 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
457 char *driver_str
= NULL
, *persistent_handle_str
= NULL
;
458 int driver_len
= 0, persistent_handle_len
= 0;
460 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|ss", &driver_str
, &driver_len
, &persistent_handle_str
, &persistent_handle_len
)) {
461 php_http_client_driver_t driver
;
463 if (SUCCESS
== php_http_client_driver_get(&driver_str
, (uint
*) &driver_len
, &driver
)) {
464 php_resource_factory_t
*rf
= NULL
;
465 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
469 object_init_ex(os
, spl_ce_SplObjectStorage
);
470 zend_update_property(php_http_client_class_entry
, getThis(), ZEND_STRL("observers"), os TSRMLS_CC
);
473 if (persistent_handle_len
) {
476 php_persistent_handle_factory_t
*pf
;
478 name_len
= spprintf(&name_str
, 0, "http\\Client\\%s", php_http_pretty_key(driver_str
, driver_len
, 1, 1));
480 if ((pf
= php_persistent_handle_concede(NULL
, name_str
, name_len
, persistent_handle_str
, persistent_handle_len
, NULL
, NULL TSRMLS_CC
))) {
481 rf
= php_resource_factory_init(NULL
, php_persistent_handle_get_resource_factory_ops(), pf
, (void (*)(void *)) php_persistent_handle_abandon
);
487 if ((obj
->client
= php_http_client_init(NULL
, driver
.client_ops
, rf
, NULL TSRMLS_CC
))) {
488 obj
->client
->callback
.response
.func
= handle_response
;
489 obj
->client
->callback
.response
.arg
= obj
;
490 obj
->client
->callback
.progress
.func
= handle_progress
;
491 obj
->client
->callback
.progress
.arg
= obj
;
493 obj
->client
->responses
.dtor
= response_dtor
;
496 php_http_error(HE_WARNING
, PHP_HTTP_E_REQUEST_FACTORY
, "Failed to locate \"%s\" client request handler", driver_str
);
499 } end_error_handling();
502 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_reset
, 0, 0, 0)
504 static PHP_METHOD(HttpClient
, reset
)
506 if (SUCCESS
== zend_parse_parameters_none()) {
507 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
510 php_http_client_reset(obj
->client
);
512 RETVAL_ZVAL(getThis(), 1, 0);
515 static HashTable
*combined_options(zval
*client
, zval
*request TSRMLS_DC
)
519 zval
*z_roptions
= NULL
, *z_coptions
= zend_read_property(php_http_client_class_entry
, client
, ZEND_STRL("options"), 0 TSRMLS_CC
);
521 if (Z_TYPE_P(z_coptions
) == IS_ARRAY
) {
522 num_options
= zend_hash_num_elements(Z_ARRVAL_P(z_coptions
));
524 zend_call_method_with_0_params(&request
, NULL
, NULL
, "getOptions", &z_roptions
);
525 if (z_roptions
&& Z_TYPE_P(z_roptions
) == IS_ARRAY
) {
526 int num
= zend_hash_num_elements(Z_ARRVAL_P(z_roptions
));
527 if (num
> num_options
) {
531 ALLOC_HASHTABLE(options
);
532 ZEND_INIT_SYMTABLE_EX(options
, num_options
, 0);
533 if (Z_TYPE_P(z_coptions
) == IS_ARRAY
) {
534 array_copy(Z_ARRVAL_P(z_coptions
), options
);
537 if (Z_TYPE_P(z_roptions
) == IS_ARRAY
) {
538 array_join(Z_ARRVAL_P(z_roptions
), options
, 1, 0);
540 zval_ptr_dtor(&z_roptions
);
545 static void msg_queue_dtor(php_http_client_enqueue_t
*e
)
547 php_http_message_object_t
*msg_obj
= e
->opaque
;
548 TSRMLS_FETCH_FROM_CTX(msg_obj
->message
->ts
);
550 zend_objects_store_del_ref_by_handle_ex(msg_obj
->zv
.handle
, msg_obj
->zv
.handlers TSRMLS_CC
);
551 zend_hash_destroy(e
->options
);
552 FREE_HASHTABLE(e
->options
);
554 if (e
->closure
.fci
.size
) {
555 zval_ptr_dtor(&e
->closure
.fci
.function_name
);
556 if (e
->closure
.fci
.object_ptr
) {
557 zval_ptr_dtor(&e
->closure
.fci
.object_ptr
);
562 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enqueue
, 0, 0, 1)
563 ZEND_ARG_OBJ_INFO(0, request
, http
\\Client
\\Request
, 0)
564 ZEND_ARG_INFO(0, callable
)
566 static PHP_METHOD(HttpClient
, enqueue
)
568 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
570 zend_fcall_info fci
= empty_fcall_info
;
571 zend_fcall_info_cache fcc
= empty_fcall_info_cache
;
573 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O|f", &request
, php_http_client_request_get_class_entry(), &fci
, &fcc
)) {
574 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
575 php_http_message_object_t
*msg_obj
= zend_object_store_get_object(request TSRMLS_CC
);
577 if (php_http_client_enqueued(obj
->client
, msg_obj
->message
, NULL
)) {
578 php_http_error(HE_WARNING
, PHP_HTTP_E_CLIENT
, "Failed to enqueue request; request already in queue");
580 php_http_client_enqueue_t q
= {
582 combined_options(getThis(), request TSRMLS_CC
),
589 Z_ADDREF_P(fci
.function_name
);
590 if (fci
.object_ptr
) {
591 Z_ADDREF_P(fci
.object_ptr
);
595 zend_objects_store_add_ref_by_handle(msg_obj
->zv
.handle TSRMLS_CC
);
596 php_http_client_enqueue(obj
->client
, &q
);
599 } end_error_handling();
601 RETVAL_ZVAL(getThis(), 1, 0);
604 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_dequeue
, 0, 0, 1)
605 ZEND_ARG_OBJ_INFO(0, request
, http
\\Client
\\Request
, 0)
607 static PHP_METHOD(HttpClient
, dequeue
)
609 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
612 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O", &request
, php_http_client_request_get_class_entry())) {
613 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
614 php_http_message_object_t
*msg_obj
= zend_object_store_get_object(request TSRMLS_CC
);
616 php_http_client_dequeue(obj
->client
, msg_obj
->message
);
618 } end_error_handling();
620 RETVAL_ZVAL(getThis(), 1, 0);
623 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_requeue
, 0, 0, 1)
624 ZEND_ARG_OBJ_INFO(0, request
, http
\\Client
\\Request
, 0)
625 ZEND_ARG_INFO(0, callable
)
627 static PHP_METHOD(HttpClient
, requeue
)
629 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
631 zend_fcall_info fci
= empty_fcall_info
;
632 zend_fcall_info_cache fcc
= empty_fcall_info_cache
;
634 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O|f", &request
, php_http_client_request_get_class_entry(), &fci
, &fcc
)) {
635 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
636 php_http_message_object_t
*msg_obj
= zend_object_store_get_object(request TSRMLS_CC
);
637 php_http_client_enqueue_t q
= {
639 combined_options(getThis(), request TSRMLS_CC
),
646 Z_ADDREF_P(fci
.function_name
);
647 if (fci
.object_ptr
) {
648 Z_ADDREF_P(fci
.object_ptr
);
652 zend_objects_store_add_ref_by_handle(msg_obj
->zv
.handle TSRMLS_CC
);
653 if (php_http_client_enqueued(obj
->client
, msg_obj
->message
, NULL
)) {
654 php_http_client_dequeue(obj
->client
, msg_obj
->message
);
656 php_http_client_enqueue(obj
->client
, &q
);
658 } end_error_handling();
660 RETVAL_ZVAL(getThis(), 1, 0);
663 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getResponse
, 0, 0, 0)
665 static PHP_METHOD(HttpClient
, getResponse
)
667 if (SUCCESS
== zend_parse_parameters_none()) {
668 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
670 if (obj
->client
->responses
.tail
) {
671 php_http_message_object_t
*response_obj
= *(php_http_message_object_t
**) obj
->client
->responses
.tail
->data
;
675 RETVAL_OBJVAL(response_obj
->zv
, 1);
676 zend_llist_remove_tail(&obj
->client
->responses
);
682 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getHistory
, 0, 0, 0)
684 static PHP_METHOD(HttpClient
, getHistory
)
686 if (SUCCESS
== zend_parse_parameters_none()) {
687 zval
*zhistory
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("history"), 0 TSRMLS_CC
);
688 RETVAL_ZVAL(zhistory
, 1, 0);
692 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_send
, 0, 0, 0)
694 static PHP_METHOD(HttpClient
, send
)
698 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
699 if (SUCCESS
== zend_parse_parameters_none()) {
700 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
701 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
703 php_http_client_exec(obj
->client
);
704 } end_error_handling();
706 } end_error_handling();
708 RETVAL_ZVAL(getThis(), 1, 0);
711 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_once
, 0, 0, 0)
713 static PHP_METHOD(HttpClient
, once
)
715 if (SUCCESS
== zend_parse_parameters_none()) {
716 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
718 if (0 < php_http_client_once(obj
->client
)) {
725 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_wait
, 0, 0, 0)
726 ZEND_ARG_INFO(0, timeout
)
728 static PHP_METHOD(HttpClient
, wait
)
732 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|d", &timeout
)) {
733 struct timeval timeout_val
;
734 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
736 timeout_val
.tv_sec
= (time_t) timeout
;
737 timeout_val
.tv_usec
= PHP_HTTP_USEC(timeout
) % PHP_HTTP_MCROSEC
;
739 RETURN_SUCCESS(php_http_client_wait(obj
->client
, timeout
> 0 ? &timeout_val
: NULL
));
744 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enablePipelining
, 0, 0, 0)
745 ZEND_ARG_INFO(0, enable
)
747 static PHP_METHOD(HttpClient
, enablePipelining
)
749 zend_bool enable
= 1;
751 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|b", &enable
)) {
752 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
754 php_http_client_setopt(obj
->client
, PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING
, &enable
);
756 RETVAL_ZVAL(getThis(), 1, 0);
759 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enableEvents
, 0, 0, 0)
760 ZEND_ARG_INFO(0, enable
)
762 static PHP_METHOD(HttpClient
, enableEvents
)
764 zend_bool enable
= 1;
766 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|b", &enable
)) {
767 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
769 php_http_client_setopt(obj
->client
, PHP_HTTP_CLIENT_OPT_USE_EVENTS
, &enable
);
771 RETVAL_ZVAL(getThis(), 1, 0);
774 static int notify(zend_object_iterator
*iter
, void *puser TSRMLS_DC
)
776 zval
**observer
= NULL
, **args
= puser
;
778 iter
->funcs
->get_current_data(iter
, &observer TSRMLS_CC
);
782 zend_call_method(observer
, NULL
, NULL
, ZEND_STRL("update"), &retval
, args
[1]?2:1, args
[0], args
[1] TSRMLS_CC
);
784 zval_ptr_dtor(&retval
);
792 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_notify
, 0, 0, 0)
793 ZEND_ARG_OBJ_INFO(0, request
, http
\\Client
\\Request
, 1)
795 static PHP_METHOD(HttpClient
, notify
)
797 zval
*request
= NULL
;
799 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|O!", &request
, php_http_client_request_get_class_entry())) {
800 zval
*args
[2], *observers
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC
);
802 if (Z_TYPE_P(observers
) == IS_OBJECT
) {
803 Z_ADDREF_P(getThis());
809 spl_iterator_apply(observers
, notify
, &args TSRMLS_CC
);
810 zval_ptr_dtor(&getThis());
812 zval_ptr_dtor(&request
);
817 RETVAL_ZVAL(getThis(), 1, 0);
820 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_attach
, 0, 0, 1)
821 ZEND_ARG_OBJ_INFO(0, observer
, SplObserver
, 0)
823 static PHP_METHOD(HttpClient
, attach
)
827 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O", &observer
, spl_ce_SplObserver
)) {
828 zval
*retval
= NULL
, *observers
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC
);
829 zend_call_method_with_1_params(&observers
, NULL
, NULL
, "attach", &retval
, observer
);
831 zval_ptr_dtor(&retval
);
835 RETVAL_ZVAL(getThis(), 1, 0);
838 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_detach
, 0, 0, 1)
839 ZEND_ARG_OBJ_INFO(0, observer
, SplObserver
, 0)
841 static PHP_METHOD(HttpClient
, detach
)
845 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O", &observer
, spl_ce_SplObserver
)) {
846 zval
*retval
, *observers
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC
);
847 zend_call_method_with_1_params(&observers
, NULL
, NULL
, "detach", &retval
, observer
);
848 zval_ptr_dtor(&retval
);
851 RETVAL_ZVAL(getThis(), 1, 0);
854 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getObservers
, 0, 0, 0)
856 static PHP_METHOD(HttpClient
, getObservers
)
858 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
859 if (SUCCESS
== zend_parse_parameters_none()) {
860 zval
*observers
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC
);
861 RETVAL_ZVAL(observers
, 1, 0);
863 } end_error_handling();
866 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getProgressInfo
, 0, 0, 1)
867 ZEND_ARG_OBJ_INFO(0, request
, http
\\Client
\\Request
, 0)
869 static PHP_METHOD(HttpClient
, getProgressInfo
)
873 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
874 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O", &request
, php_http_client_request_get_class_entry())) {
875 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
876 php_http_message_object_t
*req_obj
= zend_object_store_get_object(request TSRMLS_CC
);
877 php_http_client_progress_state_t
*progress
;
879 if (SUCCESS
== php_http_client_getopt(obj
->client
, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO
, req_obj
->message
, &progress
)) {
880 object_init(return_value
);
881 add_property_bool(return_value
, "started", progress
->started
);
882 add_property_bool(return_value
, "finished", progress
->finished
);
883 add_property_string(return_value
, "info", STR_PTR(progress
->info
), 1);
884 add_property_double(return_value
, "dltotal", progress
->dl
.total
);
885 add_property_double(return_value
, "dlnow", progress
->dl
.now
);
886 add_property_double(return_value
, "ultotal", progress
->ul
.total
);
887 add_property_double(return_value
, "ulnow", progress
->ul
.now
);
890 } end_error_handling();
893 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getTransferInfo
, 0, 0, 1)
894 ZEND_ARG_OBJ_INFO(0, request
, http
\\Client
\\Request
, 0)
896 static PHP_METHOD(HttpClient
, getTransferInfo
)
900 with_error_handling(EH_THROW
, php_http_exception_get_class_entry()) {
901 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O", &request
, php_http_client_request_get_class_entry())) {
902 php_http_client_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
903 php_http_message_object_t
*req_obj
= zend_object_store_get_object(request TSRMLS_CC
);
905 array_init(return_value
);
906 php_http_client_getopt(obj
->client
, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO
, req_obj
->message
, &Z_ARRVAL_P(return_value
));
908 } end_error_handling();
911 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setOptions
, 0, 0, 0)
912 ZEND_ARG_ARRAY_INFO(0, options
, 1)
914 static PHP_METHOD(HttpClient
, setOptions
)
918 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|a!/", &opts
)) {
919 php_http_client_options_set(getThis(), opts TSRMLS_CC
);
921 RETVAL_ZVAL(getThis(), 1, 0);
925 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getOptions
, 0, 0, 0)
927 static PHP_METHOD(HttpClient
, getOptions
)
929 if (SUCCESS
== zend_parse_parameters_none()) {
930 zval
*options
= zend_read_property(php_http_client_class_entry
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
931 RETVAL_ZVAL(options
, 1, 0);
935 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setSslOptions
, 0, 0, 0)
936 ZEND_ARG_ARRAY_INFO(0, ssl_option
, 1)
938 static PHP_METHOD(HttpClient
, setSslOptions
)
942 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|a!/", &opts
)) {
943 php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts
, 1 TSRMLS_CC
);
945 RETVAL_ZVAL(getThis(), 1, 0);
949 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addSslOptions
, 0, 0, 0)
950 ZEND_ARG_ARRAY_INFO(0, ssl_options
, 1)
952 static PHP_METHOD(HttpClient
, addSslOptions
)
956 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|a!/", &opts
)) {
957 php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts
, 0 TSRMLS_CC
);
959 RETVAL_ZVAL(getThis(), 1, 0);
963 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getSslOptions
, 0, 0, 0)
965 static PHP_METHOD(HttpClient
, getSslOptions
)
967 if (SUCCESS
== zend_parse_parameters_none()) {
968 php_http_client_options_get_subr(getThis(), ZEND_STRS("ssl"), return_value TSRMLS_CC
);
972 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setCookies
, 0, 0, 0)
973 ZEND_ARG_ARRAY_INFO(0, cookies
, 1)
975 static PHP_METHOD(HttpClient
, setCookies
)
979 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|a!/", &opts
)) {
980 php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts
, 1 TSRMLS_CC
);
982 RETVAL_ZVAL(getThis(), 1, 0);
986 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addCookies
, 0, 0, 0)
987 ZEND_ARG_ARRAY_INFO(0, cookies
, 1)
989 static PHP_METHOD(HttpClient
, addCookies
)
993 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|a!/", &opts
)) {
994 php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts
, 0 TSRMLS_CC
);
996 RETVAL_ZVAL(getThis(), 1, 0);
1000 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getCookies
, 0, 0, 0)
1001 ZEND_END_ARG_INFO();
1002 static PHP_METHOD(HttpClient
, getCookies
)
1004 if (SUCCESS
== zend_parse_parameters_none()) {
1005 php_http_client_options_get_subr(getThis(), ZEND_STRS("cookies"), return_value TSRMLS_CC
);
1009 static zend_function_entry php_http_client_methods
[] = {
1010 PHP_ME(HttpClient
, __construct
, ai_HttpClient_construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
1011 PHP_ME(HttpClient
, reset
, ai_HttpClient_reset
, ZEND_ACC_PUBLIC
)
1012 PHP_ME(HttpClient
, enqueue
, ai_HttpClient_enqueue
, ZEND_ACC_PUBLIC
)
1013 PHP_ME(HttpClient
, dequeue
, ai_HttpClient_dequeue
, ZEND_ACC_PUBLIC
)
1014 PHP_ME(HttpClient
, requeue
, ai_HttpClient_requeue
, ZEND_ACC_PUBLIC
)
1015 PHP_ME(HttpClient
, send
, ai_HttpClient_send
, ZEND_ACC_PUBLIC
)
1016 PHP_ME(HttpClient
, once
, ai_HttpClient_once
, ZEND_ACC_PUBLIC
)
1017 PHP_ME(HttpClient
, wait
, ai_HttpClient_wait
, ZEND_ACC_PUBLIC
)
1018 PHP_ME(HttpClient
, getResponse
, ai_HttpClient_getResponse
, ZEND_ACC_PUBLIC
)
1019 PHP_ME(HttpClient
, getHistory
, ai_HttpClient_getHistory
, ZEND_ACC_PUBLIC
)
1020 PHP_ME(HttpClient
, enablePipelining
, ai_HttpClient_enablePipelining
, ZEND_ACC_PUBLIC
)
1021 PHP_ME(HttpClient
, enableEvents
, ai_HttpClient_enableEvents
, ZEND_ACC_PUBLIC
)
1022 PHP_ME(HttpClient
, notify
, ai_HttpClient_notify
, ZEND_ACC_PUBLIC
)
1023 PHP_ME(HttpClient
, attach
, ai_HttpClient_attach
, ZEND_ACC_PUBLIC
)
1024 PHP_ME(HttpClient
, detach
, ai_HttpClient_detach
, ZEND_ACC_PUBLIC
)
1025 PHP_ME(HttpClient
, getObservers
, ai_HttpClient_getObservers
, ZEND_ACC_PUBLIC
)
1026 PHP_ME(HttpClient
, getProgressInfo
, ai_HttpClient_getProgressInfo
, ZEND_ACC_PUBLIC
)
1027 PHP_ME(HttpClient
, getTransferInfo
, ai_HttpClient_getTransferInfo
, ZEND_ACC_PUBLIC
)
1028 PHP_ME(HttpClient
, setOptions
, ai_HttpClient_setOptions
, ZEND_ACC_PUBLIC
)
1029 PHP_ME(HttpClient
, getOptions
, ai_HttpClient_getOptions
, ZEND_ACC_PUBLIC
)
1030 PHP_ME(HttpClient
, setSslOptions
, ai_HttpClient_setSslOptions
, ZEND_ACC_PUBLIC
)
1031 PHP_ME(HttpClient
, addSslOptions
, ai_HttpClient_addSslOptions
, ZEND_ACC_PUBLIC
)
1032 PHP_ME(HttpClient
, getSslOptions
, ai_HttpClient_getSslOptions
, ZEND_ACC_PUBLIC
)
1033 PHP_ME(HttpClient
, setCookies
, ai_HttpClient_setCookies
, ZEND_ACC_PUBLIC
)
1034 PHP_ME(HttpClient
, addCookies
, ai_HttpClient_addCookies
, ZEND_ACC_PUBLIC
)
1035 PHP_ME(HttpClient
, getCookies
, ai_HttpClient_getCookies
, ZEND_ACC_PUBLIC
)
1036 EMPTY_FUNCTION_ENTRY
1039 PHP_MINIT_FUNCTION(http_client
)
1041 zend_class_entry ce
= {0};
1043 INIT_NS_CLASS_ENTRY(ce
, "http", "Client", php_http_client_methods
);
1044 php_http_client_class_entry
= zend_register_internal_class_ex(&ce
, NULL
, NULL TSRMLS_CC
);
1045 php_http_client_class_entry
->create_object
= php_http_client_object_new
;
1046 zend_class_implements(php_http_client_class_entry TSRMLS_CC
, 1, spl_ce_SplSubject
);
1047 memcpy(&php_http_client_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
1048 php_http_client_object_handlers
.clone_obj
= NULL
;
1049 zend_declare_property_null(php_http_client_class_entry
, ZEND_STRL("observers"), ZEND_ACC_PRIVATE TSRMLS_CC
);
1050 zend_declare_property_null(php_http_client_class_entry
, ZEND_STRL("options"), ZEND_ACC_PROTECTED TSRMLS_CC
);
1051 zend_declare_property_null(php_http_client_class_entry
, ZEND_STRL("history"), ZEND_ACC_PROTECTED TSRMLS_CC
);
1052 zend_declare_property_bool(php_http_client_class_entry
, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
1054 zend_hash_init(&php_http_client_drivers
, 2, NULL
, NULL
, 1);
1059 PHP_MSHUTDOWN_FUNCTION(http_client
)
1061 zend_hash_destroy(&php_http_client_drivers
);