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"
16 #include "ext/spl/spl_observer.h"
19 * array of name => php_http_client_driver_t*
21 static HashTable php_http_client_drivers
;
23 static void php_http_client_driver_hash_dtor(zval
*pData
)
25 pefree(Z_PTR_P(pData
), 1);
28 ZEND_RESULT_CODE
php_http_client_driver_add(php_http_client_driver_t
*driver
)
30 return zend_hash_add_mem(&php_http_client_drivers
, driver
->driver_name
, (void *) driver
, sizeof(php_http_client_driver_t
))
34 php_http_client_driver_t
*php_http_client_driver_get(zend_string
*name
)
37 php_http_client_driver_t
*tmp
;
39 if (name
&& (tmp
= zend_hash_find_ptr(&php_http_client_drivers
, name
))) {
42 if ((ztmp
= zend_hash_get_current_data(&php_http_client_drivers
))) {
48 static int apply_driver_list(zval
*p
, void *arg
)
50 php_http_client_driver_t
*d
= Z_PTR_P(p
);
53 ZVAL_STR_COPY(&zname
, d
->driver_name
);
55 zend_hash_next_index_insert(arg
, &zname
);
56 return ZEND_HASH_APPLY_KEEP
;
59 void php_http_client_driver_list(HashTable
*ht
)
61 zend_hash_apply_with_argument(&php_http_client_drivers
, apply_driver_list
, ht
);
64 static zend_class_entry
*php_http_client_class_entry
;
65 zend_class_entry
*php_http_client_get_class_entry(void)
67 return php_http_client_class_entry
;
70 void php_http_client_options_set_subr(zval
*instance
, char *key
, size_t len
, zval
*opts
, int overwrite
)
72 if (overwrite
|| (opts
&& zend_hash_num_elements(Z_ARRVAL_P(opts
)))) {
73 zend_class_entry
*this_ce
= Z_OBJCE_P(instance
);
74 zval old_opts_tmp
, *old_opts
, new_opts
, *entry
= NULL
;
76 array_init(&new_opts
);
77 old_opts
= zend_read_property(this_ce
, Z_OBJ_P(instance
), ZEND_STRL("options"), 0, &old_opts_tmp
);
79 if (Z_TYPE_P(old_opts
) == IS_ARRAY
) {
80 array_copy(Z_ARRVAL_P(old_opts
), Z_ARRVAL(new_opts
));
84 if (opts
&& zend_hash_num_elements(Z_ARRVAL_P(opts
))) {
86 zend_symtable_str_update(Z_ARRVAL(new_opts
), key
, len
, opts
);
88 zend_symtable_str_del(Z_ARRVAL(new_opts
), key
, len
);
90 } else if (opts
&& zend_hash_num_elements(Z_ARRVAL_P(opts
))) {
91 if ((entry
= zend_symtable_str_find(Z_ARRVAL(new_opts
), key
, len
))) {
93 array_join(Z_ARRVAL_P(opts
), Z_ARRVAL_P(entry
), 0, 0);
96 zend_symtable_str_update(Z_ARRVAL(new_opts
), key
, len
, opts
);
100 zend_update_property(this_ce
, Z_OBJ_P(instance
), ZEND_STRL("options"), &new_opts
);
101 zval_ptr_dtor(&new_opts
);
105 void php_http_client_options_set(zval
*instance
, zval
*opts
)
107 php_http_arrkey_t key
;
109 zend_class_entry
*this_ce
= Z_OBJCE_P(instance
);
110 zend_bool is_client
= instanceof_function(this_ce
, php_http_client_class_entry
);
112 array_init(&new_opts
);
114 if (!opts
|| !zend_hash_num_elements(Z_ARRVAL_P(opts
))) {
115 zend_update_property(this_ce
, Z_OBJ_P(instance
), ZEND_STRL("options"), &new_opts
);
116 zval_ptr_dtor(&new_opts
);
118 zval old_opts_tmp
, *old_opts
, add_opts
, *opt
;
120 array_init(&add_opts
);
121 /* some options need extra attention -- thus cannot use array_merge() directly */
122 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(opts
), key
.h
, key
.key
, opt
)
125 if (Z_TYPE_P(opt
) == IS_ARRAY
&& (zend_string_equals_literal(key
.key
, "ssl") || zend_string_equals_literal(key
.key
, "cookies"))) {
126 php_http_client_options_set_subr(instance
, key
.key
->val
, key
.key
->len
, opt
, 0);
127 } else if (is_client
&& (zend_string_equals_literal(key
.key
, "recordHistory") || zend_string_equals_literal(key
.key
, "responseMessageClass"))) {
128 zend_update_property(this_ce
, Z_OBJ_P(instance
), key
.key
->val
, key
.key
->len
, opt
);
129 } else if (Z_TYPE_P(opt
) == IS_NULL
) {
130 old_opts
= zend_read_property(this_ce
, Z_OBJ_P(instance
), ZEND_STRL("options"), 0, &old_opts_tmp
);
131 if (Z_TYPE_P(old_opts
) == IS_ARRAY
) {
132 zend_symtable_del(Z_ARRVAL_P(old_opts
), key
.key
);
136 add_assoc_zval_ex(&add_opts
, key
.key
->val
, key
.key
->len
, opt
);
140 ZEND_HASH_FOREACH_END();
142 old_opts
= zend_read_property(this_ce
, Z_OBJ_P(instance
), ZEND_STRL("options"), 0, &old_opts_tmp
);
143 if (Z_TYPE_P(old_opts
) == IS_ARRAY
) {
144 array_copy(Z_ARRVAL_P(old_opts
), Z_ARRVAL(new_opts
));
146 array_join(Z_ARRVAL(add_opts
), Z_ARRVAL(new_opts
), 0, 0);
147 zend_update_property(this_ce
, Z_OBJ_P(instance
), ZEND_STRL("options"), &new_opts
);
148 zval_ptr_dtor(&new_opts
);
149 zval_ptr_dtor(&add_opts
);
153 void php_http_client_options_get_subr(zval
*instance
, char *key
, size_t len
, zval
*return_value
)
155 zend_class_entry
*this_ce
= Z_OBJCE_P(instance
);
156 zval
*options
, opts_tmp
, *opts
= zend_read_property(this_ce
, Z_OBJ_P(instance
), ZEND_STRL("options"), 0, &opts_tmp
);
158 if ((Z_TYPE_P(opts
) == IS_ARRAY
) && (options
= zend_symtable_str_find(Z_ARRVAL_P(opts
), key
, len
))) {
159 RETVAL_ZVAL(options
, 1, 0);
163 static void queue_dtor(void *enqueued
)
165 php_http_client_enqueue_t
*e
= enqueued
;
172 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
)
174 php_http_client_t
*free_h
= NULL
;
177 free_h
= h
= emalloc(sizeof(*h
));
179 memset(h
, 0, sizeof(*h
));
184 } else if (ops
->rsrc
) {
185 h
->rf
= php_resource_factory_init(NULL
, h
->ops
->rsrc
, h
, NULL
);
187 zend_llist_init(&h
->requests
, sizeof(php_http_client_enqueue_t
), queue_dtor
, 0);
188 zend_llist_init(&h
->responses
, sizeof(void *), NULL
, 0);
191 if (!(h
= h
->ops
->init(h
, init_arg
))) {
192 php_error_docref(NULL
, E_WARNING
, "Could not initialize client");
200 php_http_client_t
*php_http_client_copy(php_http_client_t
*from
, php_http_client_t
*to
)
202 if (from
->ops
->copy
) {
203 return from
->ops
->copy(from
, to
);
209 void php_http_client_dtor(php_http_client_t
*h
)
211 php_http_client_reset(h
);
216 h
->callback
.debug
.func
= NULL
;
217 h
->callback
.debug
.arg
= NULL
;
219 php_resource_factory_free(&h
->rf
);
222 void php_http_client_free(php_http_client_t
**h
) {
224 php_http_client_dtor(*h
);
230 ZEND_RESULT_CODE
php_http_client_enqueue(php_http_client_t
*h
, php_http_client_enqueue_t
*enqueue
)
232 if (h
->ops
->enqueue
) {
233 if (php_http_client_enqueued(h
, enqueue
->request
, NULL
)) {
234 php_error_docref(NULL
, E_WARNING
, "Failed to enqueue request; request already in queue");
237 return h
->ops
->enqueue(h
, enqueue
);
243 ZEND_RESULT_CODE
php_http_client_dequeue(php_http_client_t
*h
, php_http_message_t
*request
)
245 if (h
->ops
->dequeue
) {
246 php_http_client_enqueue_t
*enqueue
= php_http_client_enqueued(h
, request
, NULL
);
249 php_error_docref(NULL
, E_WARNING
, "Failed to dequeue request; request not in queue");
252 return h
->ops
->dequeue(h
, enqueue
);
257 ZEND_RESULT_CODE
php_http_client_requeue(php_http_client_t
*h
, php_http_message_t
*request
)
259 if (h
->ops
->dequeue
) {
260 php_http_client_enqueue_t
*enqueue
= php_http_client_enqueued(h
, request
, NULL
);
263 php_error_docref(NULL
, E_WARNING
, "Failed to requeue request; request not in queue");
266 return h
->ops
->requeue(h
, enqueue
);
271 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
)
273 zend_llist_element
*el
= NULL
;
276 for (el
= h
->requests
.head
; el
; el
= el
->next
) {
277 if (compare_func((php_http_client_enqueue_t
*) el
->data
, compare_arg
)) {
282 for (el
= h
->requests
.head
; el
; el
= el
->next
) {
283 if (((php_http_client_enqueue_t
*) el
->data
)->request
== compare_arg
) {
288 return el
? (php_http_client_enqueue_t
*) el
->data
: NULL
;
291 ZEND_RESULT_CODE
php_http_client_wait(php_http_client_t
*h
, struct timeval
*custom_timeout
)
294 return h
->ops
->wait(h
, custom_timeout
);
300 int php_http_client_once(php_http_client_t
*h
)
303 return h
->ops
->once(h
);
309 ZEND_RESULT_CODE
php_http_client_exec(php_http_client_t
*h
)
312 return h
->ops
->exec(h
);
318 void php_http_client_reset(php_http_client_t
*h
)
324 zend_llist_clean(&h
->requests
);
325 zend_llist_clean(&h
->responses
);
328 ZEND_RESULT_CODE
php_http_client_setopt(php_http_client_t
*h
, php_http_client_setopt_opt_t opt
, void *arg
)
330 if (h
->ops
->setopt
) {
331 return h
->ops
->setopt(h
, opt
, arg
);
337 ZEND_RESULT_CODE
php_http_client_getopt(php_http_client_t
*h
, php_http_client_getopt_opt_t opt
, void *arg
, void *res_ptr
)
339 if (h
->ops
->getopt
) {
340 return h
->ops
->getopt(h
, opt
, arg
, res_ptr
);
345 static zend_object_handlers php_http_client_object_handlers
;
347 void php_http_client_object_free(zend_object
*object
)
349 php_http_client_object_t
*o
= PHP_HTTP_OBJ(object
, NULL
);
353 php_http_client_free(&o
->client
);
354 if (o
->debug
.fci
.size
> 0) {
355 zend_fcall_info_args_clear(&o
->debug
.fci
, 1);
356 zval_ptr_dtor(&o
->debug
.fci
.function_name
);
357 o
->debug
.fci
.size
= 0;
359 php_http_object_method_dtor(&o
->notify
);
360 php_http_object_method_free(&o
->update
);
361 zend_object_std_dtor(object
);
364 php_http_client_object_t
*php_http_client_object_new_ex(zend_class_entry
*ce
, php_http_client_t
*client
)
366 php_http_client_object_t
*o
;
368 o
= ecalloc(1, sizeof(*o
) + zend_object_properties_size(ce
));
369 zend_object_std_init(&o
->zo
, ce
);
370 object_properties_init(&o
->zo
, ce
);
374 o
->zo
.handlers
= &php_http_client_object_handlers
;
379 zend_object
*php_http_client_object_new(zend_class_entry
*ce
)
381 return &php_http_client_object_new_ex(ce
, NULL
)->zo
;
384 static HashTable
*php_http_client_object_get_gc(zend_object
*object
, zval
**table
, int *n
)
386 php_http_client_object_t
*obj
= PHP_HTTP_OBJ(object
, NULL
);
387 zend_llist_element
*el
= NULL
;
388 HashTable
*props
= object
->handlers
->get_properties(object
);
389 uint32_t count
= zend_hash_num_elements(props
) + zend_llist_count(&obj
->client
->responses
) + zend_llist_count(&obj
->client
->requests
) + 2;
393 *table
= obj
->gc
= erealloc(obj
->gc
, sizeof(zval
) * count
);
395 #if PHP_HTTP_HAVE_LIBCURL
396 if (obj
->client
->ops
== php_http_client_curl_get_ops()) {
397 php_http_client_curl_t
*curl
= obj
->client
->ctx
;
399 if (curl
->ev_ops
== php_http_client_curl_user_ops_get()) {
400 php_http_client_curl_user_context_t
*ctx
= curl
->ev_ctx
;
402 ZVAL_COPY_VALUE(&obj
->gc
[(*n
)++], &ctx
->user
);
407 if (obj
->debug
.fci
.size
> 0) {
408 ZVAL_COPY_VALUE(&obj
->gc
[(*n
)++], &obj
->debug
.fci
.function_name
);
411 for (el
= obj
->client
->responses
.head
; el
; el
= el
->next
) {
412 php_http_message_object_t
*response_obj
= *(php_http_message_object_t
**) el
->data
;
413 ZVAL_OBJ(&obj
->gc
[(*n
)++], &response_obj
->zo
);
416 for (el
= obj
->client
->requests
.head
; el
; el
= el
->next
) {
417 php_http_client_enqueue_t
*q
= (php_http_client_enqueue_t
*) el
->data
;
418 if (q
->request_obj
) {
419 ZVAL_OBJ(&obj
->gc
[(*n
)++], &q
->request_obj
->zo
);
423 ZEND_HASH_FOREACH_VAL(props
, val
)
425 ZVAL_COPY_VALUE(&obj
->gc
[(*n
)++], val
);
427 ZEND_HASH_FOREACH_END();
432 static void handle_history(zval
*zclient
, php_http_message_t
*request
, php_http_message_t
*response
)
434 zval new_hist
, old_hist_tmp
, *old_hist
= zend_read_property(php_http_client_class_entry
, Z_OBJ_P(zclient
), ZEND_STRL("history"), 0, &old_hist_tmp
);
435 php_http_message_t
*req_copy
= php_http_message_copy(request
, NULL
);
436 php_http_message_t
*res_copy
= php_http_message_copy(response
, NULL
);
437 php_http_message_t
*zipped
= php_http_message_zip(res_copy
, req_copy
);
438 php_http_message_object_t
*obj
= php_http_message_object_new_ex(php_http_message_get_class_entry(), zipped
);
440 ZVAL_OBJ(&new_hist
, &obj
->zo
);
442 if (Z_TYPE_P(old_hist
) == IS_OBJECT
) {
443 php_http_message_object_prepend(&new_hist
, old_hist
, 1);
446 zend_update_property(php_http_client_class_entry
, Z_OBJ_P(zclient
), ZEND_STRL("history"), &new_hist
);
447 zval_ptr_dtor(&new_hist
);
450 static ZEND_RESULT_CODE
handle_response(void *arg
, php_http_client_t
*client
, php_http_client_enqueue_t
*e
, php_http_message_t
**response
)
452 zend_bool dequeue
= 0;
454 php_http_message_t
*msg
;
455 php_http_client_progress_state_t
*progress
;
457 ZVAL_OBJ(&zclient
, &((php_http_client_object_t
*) arg
)->zo
);
459 if ((msg
= *response
)) {
460 php_http_message_object_t
*msg_obj
;
461 zval info
, zresponse
, zrequest
, rec_hist_tmp
;
464 /* ensure the message is of type response (could be uninitialized in case of early error, like DNS) */
465 php_http_message_set_type(msg
, PHP_HTTP_RESPONSE
);
467 if (zend_is_true(zend_read_property(php_http_client_class_entry
, Z_OBJ(zclient
), ZEND_STRL("recordHistory"), 0, &rec_hist_tmp
))) {
468 handle_history(&zclient
, e
->request
, *response
);
471 /* hard detach, redirects etc. are in the history */
472 php_http_message_free(&msg
->parent
);
475 msg_obj
= php_http_message_object_new_ex(php_http_get_client_response_class_entry(), msg
);
476 ZVAL_OBJECT(&zresponse
, &msg_obj
->zo
, 1);
477 ZVAL_OBJECT(&zrequest
, &((php_http_message_object_t
*) e
->opaque
)->zo
, 1);
479 php_http_message_object_prepend(&zresponse
, &zrequest
, 1);
482 info_ht
= HASH_OF(&info
);
483 php_http_client_getopt(client
, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO
, e
->request
, &info_ht
);
484 zend_update_property(php_http_get_client_response_class_entry(), Z_OBJ(zresponse
), ZEND_STRL("transferInfo"), &info
);
485 zval_ptr_dtor(&info
);
487 zend_llist_add_element(&client
->responses
, &msg_obj
);
489 if (e
->closure
.fci
.size
) {
491 zend_error_handling zeh
;
494 zend_fcall_info_argn(&e
->closure
.fci
, 1, &zresponse
);
495 zend_replace_error_handling(EH_NORMAL
, NULL
, &zeh
);
496 ++client
->callback
.depth
;
497 zend_fcall_info_call(&e
->closure
.fci
, &e
->closure
.fcc
, &retval
, NULL
);
498 --client
->callback
.depth
;
499 zend_restore_error_handling(&zeh
);
500 zend_fcall_info_argn(&e
->closure
.fci
, 0);
502 if (Z_TYPE(retval
) == IS_TRUE
) {
505 zval_ptr_dtor(&retval
);
508 zval_ptr_dtor(&zresponse
);
509 zval_ptr_dtor(&zrequest
);
512 if (SUCCESS
== php_http_client_getopt(client
, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO
, e
->request
, &progress
)) {
513 progress
->info
= "finished";
514 progress
->finished
= 1;
515 client
->callback
.progress
.func(client
->callback
.progress
.arg
, client
, e
, progress
);
519 php_http_client_dequeue(client
, e
->request
);
525 static void handle_progress(void *arg
, php_http_client_t
*client
, php_http_client_enqueue_t
*e
, php_http_client_progress_state_t
*progress
)
527 zval zclient
, args
[2];
528 php_http_client_object_t
*client_obj
= arg
;
529 zend_error_handling zeh
;
531 ZVAL_OBJECT(&zclient
, &client_obj
->zo
, 1);
532 ZVAL_OBJECT(&args
[0], &((php_http_message_object_t
*) e
->opaque
)->zo
, 1);
533 object_init(&args
[1]);
534 add_property_bool(&args
[1], "started", progress
->started
);
535 add_property_bool(&args
[1], "finished", progress
->finished
);
536 add_property_string(&args
[1], "info", STR_PTR(progress
->info
));
537 add_property_double(&args
[1], "dltotal", progress
->dl
.total
);
538 add_property_double(&args
[1], "dlnow", progress
->dl
.now
);
539 add_property_double(&args
[1], "ultotal", progress
->ul
.total
);
540 add_property_double(&args
[1], "ulnow", progress
->ul
.now
);
542 zend_replace_error_handling(EH_NORMAL
, NULL
, &zeh
);
543 ++client
->callback
.depth
;
544 php_http_object_method_call(&client_obj
->notify
, &zclient
, NULL
, 2, args
);
545 --client
->callback
.depth
;
546 zend_restore_error_handling(&zeh
);
548 zval_ptr_dtor(&zclient
);
549 zval_ptr_dtor(&args
[0]);
550 zval_ptr_dtor(&args
[1]);
553 static void handle_debug(void *arg
, php_http_client_t
*client
, php_http_client_enqueue_t
*e
, unsigned type
, const char *data
, size_t size
)
555 zval ztype
, zdata
, zreq
, zclient
;
556 php_http_client_object_t
*client_obj
= arg
;
557 zend_error_handling zeh
;
559 ZVAL_OBJECT(&zclient
, &client_obj
->zo
, 1);
560 ZVAL_OBJECT(&zreq
, &((php_http_message_object_t
*) e
->opaque
)->zo
, 1);
561 ZVAL_LONG(&ztype
, type
);
562 ZVAL_STRINGL(&zdata
, data
, size
);
564 zend_replace_error_handling(EH_NORMAL
, NULL
, &zeh
);
565 zend_fcall_info_argn(&client_obj
->debug
.fci
, 4, &zclient
, &zreq
, &ztype
, &zdata
);
566 ++client
->callback
.depth
;
567 zend_fcall_info_call(&client_obj
->debug
.fci
, &client_obj
->debug
.fcc
, NULL
, NULL
);
568 --client
->callback
.depth
;
569 zend_fcall_info_args_clear(&client_obj
->debug
.fci
, 0);
570 zend_restore_error_handling(&zeh
);
572 zval_ptr_dtor(&zclient
);
573 zval_ptr_dtor(&zreq
);
574 zval_ptr_dtor(&ztype
);
575 zval_ptr_dtor(&zdata
);
578 static void response_dtor(void *data
)
580 php_http_message_object_t
*msg_obj
= *(php_http_message_object_t
**) data
;
582 zend_object_release(&msg_obj
->zo
);
585 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_construct
, 0, 0, 0)
586 ZEND_ARG_INFO(0, driver
)
587 ZEND_ARG_INFO(0, persistent_handle_id
)
589 static PHP_METHOD(HttpClient
, __construct
)
591 zend_string
*driver_name
= NULL
, *persistent_handle_name
= NULL
;
592 php_http_client_driver_t
*driver
;
593 php_resource_factory_t
*rf
= NULL
;
594 php_http_client_object_t
*obj
;
597 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|S!S!", &driver_name
, &persistent_handle_name
), invalid_arg
, return);
599 if (!zend_hash_num_elements(&php_http_client_drivers
)) {
600 php_http_throw(unexpected_val
, "No http\\Client drivers available");
603 if (!(driver
= php_http_client_driver_get(driver_name
))) {
604 php_http_throw(unexpected_val
, "Failed to locate \"%s\" client request handler", driver_name
? driver_name
->val
: "default");
608 object_init_ex(&os
, spl_ce_SplObjectStorage
);
609 zend_update_property(php_http_client_class_entry
, Z_OBJ_P(ZEND_THIS
), ZEND_STRL("observers"), &os
);
612 if (persistent_handle_name
) {
613 php_persistent_handle_factory_t
*pf
;
615 if ((pf
= php_persistent_handle_concede(NULL
, driver
->client_name
, persistent_handle_name
, NULL
, NULL
))) {
616 rf
= php_persistent_handle_resource_factory_init(NULL
, pf
);
620 obj
= PHP_HTTP_OBJ(NULL
, getThis());
622 php_http_expect(obj
->client
= php_http_client_init(NULL
, driver
->client_ops
, rf
, NULL
), runtime
, return);
624 php_http_object_method_init(&obj
->notify
, getThis(), ZEND_STRL("notify"));
626 obj
->client
->callback
.response
.func
= handle_response
;
627 obj
->client
->callback
.response
.arg
= obj
;
628 obj
->client
->callback
.progress
.func
= handle_progress
;
629 obj
->client
->callback
.progress
.arg
= obj
;
631 obj
->client
->responses
.dtor
= response_dtor
;
634 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_reset
, 0, 0, 0)
636 static PHP_METHOD(HttpClient
, reset
)
638 php_http_client_object_t
*obj
;
639 php_http_expect(SUCCESS
== zend_parse_parameters_none(), invalid_arg
, return);
641 obj
= PHP_HTTP_OBJ(NULL
, getThis());
644 php_http_client_reset(obj
->client
);
646 RETVAL_ZVAL(getThis(), 1, 0);
649 static HashTable
*combined_options(HashTable
*options
, zval
*client
, zval
*request
)
651 unsigned num_options
= 0;
652 zval z_roptions
, z_options_tmp
, *z_coptions
= zend_read_property(php_http_client_class_entry
, Z_OBJ_P(client
), ZEND_STRL("options"), 0, &z_options_tmp
);
654 if (Z_TYPE_P(z_coptions
) == IS_ARRAY
) {
655 num_options
= zend_hash_num_elements(Z_ARRVAL_P(z_coptions
));
657 ZVAL_UNDEF(&z_roptions
);
658 zend_call_method_with_0_params(Z_OBJ_P(request
), NULL
, NULL
, "getOptions", &z_roptions
);
659 if (Z_TYPE(z_roptions
) == IS_ARRAY
) {
660 unsigned num
= zend_hash_num_elements(Z_ARRVAL(z_roptions
));
661 if (num
> num_options
) {
666 zend_hash_clean(options
);
668 ALLOC_HASHTABLE(options
);
669 ZEND_INIT_SYMTABLE_EX(options
, num_options
, 0);
671 if (Z_TYPE_P(z_coptions
) == IS_ARRAY
) {
672 array_copy(Z_ARRVAL_P(z_coptions
), options
);
674 if (Z_TYPE(z_roptions
) == IS_ARRAY
) {
675 array_join(Z_ARRVAL(z_roptions
), options
, 0, 0);
677 zval_ptr_dtor(&z_roptions
);
682 static void msg_queue_dtor(php_http_client_enqueue_t
*e
)
684 php_http_message_object_t
*msg_obj
= e
->opaque
;
686 zend_object_release(&msg_obj
->zo
);
687 zend_hash_destroy(e
->options
);
688 FREE_HASHTABLE(e
->options
);
690 if (e
->closure
.fci
.size
) {
691 zval_ptr_dtor(&e
->closure
.fci
.function_name
);
692 if (e
->closure
.fci
.object
) {
693 zend_object_release(e
->closure
.fci
.object
);
698 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enqueue
, 0, 0, 1)
699 ZEND_ARG_OBJ_INFO(0, request
, http
\\Client
\\Request
, 0)
700 ZEND_ARG_INFO(0, callable
)
702 static PHP_METHOD(HttpClient
, enqueue
)
705 zend_fcall_info fci
= empty_fcall_info
;
706 zend_fcall_info_cache fcc
= empty_fcall_info_cache
;
707 php_http_client_object_t
*obj
;
708 php_http_message_object_t
*msg_obj
;
709 php_http_client_enqueue_t q
= {0};
711 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "O|f", &request
, php_http_get_client_request_class_entry(), &fci
, &fcc
), invalid_arg
, return);
713 obj
= PHP_HTTP_OBJ(NULL
, getThis());
714 msg_obj
= PHP_HTTP_OBJ(NULL
, request
);
716 if (php_http_client_enqueued(obj
->client
, msg_obj
->message
, NULL
)) {
717 php_http_throw(bad_method_call
, "Failed to enqueue request; request already in queue");
721 /* set early for progress callback */
724 if (obj
->client
->callback
.progress
.func
) {
725 php_http_client_progress_state_t progress
= {0};
727 progress
.info
= "prepare";
728 obj
->client
->callback
.progress
.func(obj
->client
->callback
.progress
.arg
, obj
->client
, &q
, &progress
);
732 q
.request
= msg_obj
->message
;
733 q
.options
= combined_options(NULL
, getThis(), request
);
734 q
.dtor
= msg_queue_dtor
;
740 Z_TRY_ADDREF(fci
.function_name
);
742 GC_ADDREF(fci
.object
);
746 php_http_expect(SUCCESS
== php_http_client_enqueue(obj
->client
, &q
), runtime
,
751 RETVAL_ZVAL(getThis(), 1, 0);
754 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_dequeue
, 0, 0, 1)
755 ZEND_ARG_OBJ_INFO(0, request
, http
\\Client
\\Request
, 0)
757 static PHP_METHOD(HttpClient
, dequeue
)
760 php_http_client_object_t
*obj
;
761 php_http_message_object_t
*msg_obj
;
763 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request
, php_http_get_client_request_class_entry()), invalid_arg
, return);
765 obj
= PHP_HTTP_OBJ(NULL
, getThis());
766 msg_obj
= PHP_HTTP_OBJ(NULL
, request
);
768 if (!php_http_client_enqueued(obj
->client
, msg_obj
->message
, NULL
)) {
769 php_http_throw(bad_method_call
, "Failed to dequeue request; request not in queue");
773 php_http_expect(SUCCESS
== php_http_client_dequeue(obj
->client
, msg_obj
->message
), runtime
, return);
775 RETVAL_ZVAL(getThis(), 1, 0);
778 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_requeue
, 0, 0, 1)
779 ZEND_ARG_OBJ_INFO(0, request
, http
\\Client
\\Request
, 0)
780 ZEND_ARG_INFO(0, callable
)
782 static PHP_METHOD(HttpClient
, requeue
)
785 zend_fcall_info fci
= empty_fcall_info
;
786 zend_fcall_info_cache fcc
= empty_fcall_info_cache
;
787 php_http_client_object_t
*obj
;
788 php_http_message_object_t
*msg_obj
;
789 php_http_client_enqueue_t q
, *e
;
791 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "O|f", &request
, php_http_get_client_request_class_entry(), &fci
, &fcc
), invalid_arg
, return);
793 obj
= PHP_HTTP_OBJ(NULL
, getThis());
794 msg_obj
= PHP_HTTP_OBJ(NULL
, request
);
796 if ((e
= php_http_client_enqueued(obj
->client
, msg_obj
->message
, NULL
))) {
797 combined_options(e
->options
, getThis(), request
);
798 php_http_expect(SUCCESS
== php_http_client_requeue(obj
->client
, msg_obj
->message
), runtime
, return);
800 if (e
->closure
.fci
.size
) {
801 zval_ptr_dtor(&e
->closure
.fci
.function_name
);
802 if (e
->closure
.fci
.object
) {
803 zend_object_release(e
->closure
.fci
.object
);
806 Z_TRY_ADDREF(fci
.function_name
);
808 GC_ADDREF(fci
.object
);
811 RETURN_ZVAL(getThis(), 1, 0);
814 q
.request
= msg_obj
->message
;
815 q
.options
= combined_options(NULL
, getThis(), request
);
816 q
.dtor
= msg_queue_dtor
;
822 Z_TRY_ADDREF(fci
.function_name
);
824 GC_ADDREF(fci
.object
);
830 php_http_expect(SUCCESS
== php_http_client_enqueue(obj
->client
, &q
), runtime
,
835 RETVAL_ZVAL(getThis(), 1, 0);
838 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpClient_count
, 0, 0, IS_LONG
, 0)
840 static PHP_METHOD(HttpClient
, count
)
842 zend_long count_mode
= -1;
844 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &count_mode
)) {
845 php_http_client_object_t
*obj
= PHP_HTTP_OBJ(NULL
, getThis());
847 RETVAL_LONG(zend_llist_count(&obj
->client
->requests
));
851 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getResponse
, 0, 0, 0)
852 ZEND_ARG_OBJ_INFO(0, request
, http
\\Client
\\Request
, 1)
854 static PHP_METHOD(HttpClient
, getResponse
)
856 zval
*zrequest
= NULL
;
857 php_http_client_object_t
*obj
;
859 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|O", &zrequest
, php_http_get_client_request_class_entry()), invalid_arg
, return);
861 obj
= PHP_HTTP_OBJ(NULL
, getThis());
864 /* lookup the response with the request */
865 zend_llist_element
*el
= NULL
;
866 php_http_message_object_t
*req_obj
= PHP_HTTP_OBJ(NULL
, zrequest
);
868 for (el
= obj
->client
->responses
.head
; el
; el
= el
->next
) {
869 php_http_message_object_t
*response_obj
= *(php_http_message_object_t
**) el
->data
;
871 if (response_obj
->message
->parent
== req_obj
->message
) {
872 RETURN_OBJECT(&response_obj
->zo
, 1);
876 /* not found for the request! */
877 php_http_throw(unexpected_val
, "Could not find response for the request");
881 /* pop off the last response */
882 if (obj
->client
->responses
.tail
) {
883 php_http_message_object_t
*response_obj
= *(php_http_message_object_t
**) obj
->client
->responses
.tail
->data
;
887 RETVAL_OBJECT(&response_obj
->zo
, 1);
888 zend_llist_remove_tail(&obj
->client
->responses
);
893 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getHistory
, 0, 0, 0)
895 static PHP_METHOD(HttpClient
, getHistory
)
897 zval zhistory_tmp
, *zhistory
;
899 php_http_expect(SUCCESS
== zend_parse_parameters_none(), invalid_arg
, return);
901 zhistory
= zend_read_property(php_http_client_class_entry
, Z_OBJ_P(ZEND_THIS
), ZEND_STRL("history"), 0, &zhistory_tmp
);
902 RETVAL_ZVAL(zhistory
, 1, 0);
905 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_send
, 0, 0, 0)
907 static PHP_METHOD(HttpClient
, send
)
909 php_http_client_object_t
*obj
;
911 php_http_expect(SUCCESS
== zend_parse_parameters_none(), invalid_arg
, return);
913 obj
= PHP_HTTP_OBJ(NULL
, getThis());
915 php_http_expect(SUCCESS
== php_http_client_exec(obj
->client
), runtime
, return);
917 RETVAL_ZVAL(getThis(), 1, 0);
920 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_once
, 0, 0, 0)
922 static PHP_METHOD(HttpClient
, once
)
924 if (SUCCESS
== zend_parse_parameters_none()) {
925 php_http_client_object_t
*obj
= PHP_HTTP_OBJ(NULL
, getThis());
927 RETURN_BOOL(0 < php_http_client_once(obj
->client
));
931 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_wait
, 0, 0, 0)
932 ZEND_ARG_INFO(0, timeout
)
934 static PHP_METHOD(HttpClient
, wait
)
938 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|d", &timeout
)) {
939 struct timeval timeout_val
;
940 php_http_client_object_t
*obj
= PHP_HTTP_OBJ(NULL
, getThis());
942 timeout_val
.tv_sec
= (time_t) timeout
;
943 timeout_val
.tv_usec
= PHP_HTTP_USEC(timeout
) % PHP_HTTP_MCROSEC
;
945 RETURN_BOOL(SUCCESS
== php_http_client_wait(obj
->client
, timeout
> 0 ? &timeout_val
: NULL
));
949 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_configure
, 0, 0, 1)
950 ZEND_ARG_ARRAY_INFO(0, settings
, 1)
952 static PHP_METHOD(HttpClient
, configure
)
954 HashTable
*settings
= NULL
;
955 php_http_client_object_t
*obj
;
957 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|H!", &settings
), invalid_arg
, return);
958 obj
= PHP_HTTP_OBJ(NULL
, getThis());
960 php_http_expect(SUCCESS
== php_http_client_setopt(obj
->client
, PHP_HTTP_CLIENT_OPT_CONFIGURATION
, settings
), unexpected_val
, return);
962 RETVAL_ZVAL(getThis(), 1, 0);
965 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enablePipelining
, 0, 0, 0)
966 ZEND_ARG_INFO(0, enable
)
968 static PHP_METHOD(HttpClient
, enablePipelining
)
970 zend_bool enable
= 1;
971 php_http_client_object_t
*obj
;
973 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable
), invalid_arg
, return);
975 obj
= PHP_HTTP_OBJ(NULL
, getThis());
977 php_http_expect(SUCCESS
== php_http_client_setopt(obj
->client
, PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING
, &enable
), unexpected_val
, return);
979 RETVAL_ZVAL(getThis(), 1, 0);
982 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enableEvents
, 0, 0, 0)
983 ZEND_ARG_INFO(0, enable
)
985 static PHP_METHOD(HttpClient
, enableEvents
)
987 zend_bool enable
= 1;
988 php_http_client_object_t
*obj
;
990 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable
), invalid_arg
, return);
992 obj
= PHP_HTTP_OBJ(NULL
, getThis());
994 php_http_expect(SUCCESS
== php_http_client_setopt(obj
->client
, PHP_HTTP_CLIENT_OPT_USE_EVENTS
, &enable
), unexpected_val
, return);
996 RETVAL_ZVAL(getThis(), 1, 0);
1000 php_http_object_method_t
*cb
;
1005 static int notify(zend_object_iterator
*iter
, void *puser
)
1008 struct notify_arg
*arg
= puser
;
1010 if ((observer
= iter
->funcs
->get_current_data(iter
))) {
1011 if (SUCCESS
== php_http_object_method_call(arg
->cb
, observer
, NULL
, arg
->argc
, arg
->args
)) {
1012 return ZEND_HASH_APPLY_KEEP
;
1015 return ZEND_HASH_APPLY_STOP
;
1018 #if PHP_VERSION_ID >= 80100
1019 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpClient_notify
, 0, 0, IS_VOID
, 0)
1021 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_notify
, 0, 0, 0)
1023 ZEND_ARG_OBJ_INFO(0, request
, http
\\Client
\\Request
, 1)
1024 ZEND_ARG_INFO(0, progress
)
1025 ZEND_END_ARG_INFO();
1026 static PHP_METHOD(HttpClient
, notify
)
1028 zval
*request
= NULL
, *zprogress
= NULL
, observers_tmp
, *observers
;
1029 php_http_client_object_t
*client_obj
;
1030 struct notify_arg arg
= {NULL
};
1032 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|O!o!", &request
, php_http_get_client_request_class_entry(), &zprogress
), invalid_arg
, return);
1034 client_obj
= PHP_HTTP_OBJ(NULL
, getThis());
1035 observers
= zend_read_property(php_http_client_class_entry
, &client_obj
->zo
, ZEND_STRL("observers"), 0, &observers_tmp
);
1037 if (Z_TYPE_P(observers
) != IS_OBJECT
) {
1038 php_http_throw(unexpected_val
, "Observer storage is corrupted");
1042 if (client_obj
->update
) {
1043 arg
.cb
= client_obj
->update
;
1044 ZVAL_COPY(&arg
.args
[0], getThis());
1048 ZVAL_COPY(&arg
.args
[1], request
);
1052 ZVAL_COPY(&arg
.args
[2], zprogress
);
1056 spl_iterator_apply(observers
, notify
, &arg
);
1058 zval_ptr_dtor(getThis());
1060 zval_ptr_dtor(request
);
1063 zval_ptr_dtor(zprogress
);
1066 #if PHP_VERSION_ID < 80100
1067 RETVAL_ZVAL(getThis(), 1, 0);
1071 #if PHP_VERSION_ID >= 80100
1072 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpClient_attach
, 0, 1, IS_VOID
, 0)
1074 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_attach
, 0, 0, 1)
1076 ZEND_ARG_OBJ_INFO(0, observer
, SplObserver
, 0)
1077 ZEND_END_ARG_INFO();
1078 static PHP_METHOD(HttpClient
, attach
)
1080 zval observers_tmp
, *observers
, *observer
, retval
;
1081 php_http_client_object_t
*client_obj
;
1083 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "O", &observer
, spl_ce_SplObserver
), invalid_arg
, return);
1085 client_obj
= PHP_HTTP_OBJ(NULL
, getThis());
1086 observers
= zend_read_property(php_http_client_class_entry
, &client_obj
->zo
, ZEND_STRL("observers"), 0, &observers_tmp
);
1088 if (Z_TYPE_P(observers
) != IS_OBJECT
) {
1089 php_http_throw(unexpected_val
, "Observer storage is corrupted");
1093 if (!client_obj
->update
) {
1094 client_obj
->update
= php_http_object_method_init(NULL
, observer
, ZEND_STRL("update"));
1097 ZVAL_UNDEF(&retval
);
1098 zend_call_method_with_1_params(Z_OBJ_P(observers
), NULL
, NULL
, "attach", &retval
, observer
);
1099 zval_ptr_dtor(&retval
);
1100 #if PHP_VERSION_ID < 80100
1101 RETVAL_ZVAL(getThis(), 1, 0);
1105 #if PHP_VERSION_ID >= 80100
1106 ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(ai_HttpClient_detach
, 0, 1, IS_VOID
, 0)
1108 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_detach
, 0, 0, 1)
1110 ZEND_ARG_OBJ_INFO(0, observer
, SplObserver
, 0)
1111 ZEND_END_ARG_INFO();
1112 static PHP_METHOD(HttpClient
, detach
)
1114 zval observers_tmp
, *observers
, *observer
, retval
;
1116 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "O", &observer
, spl_ce_SplObserver
), invalid_arg
, return);
1118 observers
= zend_read_property(php_http_client_class_entry
, Z_OBJ_P(ZEND_THIS
), ZEND_STRL("observers"), 0, &observers_tmp
);
1120 if (Z_TYPE_P(observers
) != IS_OBJECT
) {
1121 php_http_throw(unexpected_val
, "Observer storage is corrupted");
1125 ZVAL_UNDEF(&retval
);
1126 zend_call_method_with_1_params(Z_OBJ_P(observers
), NULL
, NULL
, "detach", &retval
, observer
);
1127 zval_ptr_dtor(&retval
);
1128 #if PHP_VERSION_ID < 80100
1129 RETVAL_ZVAL(getThis(), 1, 0);
1133 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getObservers
, 0, 0, 0)
1134 ZEND_END_ARG_INFO();
1135 static PHP_METHOD(HttpClient
, getObservers
)
1137 zval observers_tmp
, *observers
;
1139 php_http_expect(SUCCESS
== zend_parse_parameters_none(), invalid_arg
, return);
1141 observers
= zend_read_property(php_http_client_class_entry
, Z_OBJ_P(ZEND_THIS
), ZEND_STRL("observers"), 0, &observers_tmp
);
1143 if (Z_TYPE_P(observers
) != IS_OBJECT
) {
1144 php_http_throw(unexpected_val
, "Observer storage is corrupted");
1148 RETVAL_ZVAL(observers
, 1, 0);
1151 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getProgressInfo
, 0, 0, 1)
1152 ZEND_ARG_OBJ_INFO(0, request
, http
\\Client
\\Request
, 0)
1153 ZEND_END_ARG_INFO();
1154 static PHP_METHOD(HttpClient
, getProgressInfo
)
1157 php_http_client_object_t
*obj
;
1158 php_http_message_object_t
*req_obj
;
1159 php_http_client_progress_state_t
*progress
;
1161 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request
, php_http_get_client_request_class_entry()), invalid_arg
, return);
1163 obj
= PHP_HTTP_OBJ(NULL
, getThis());
1164 req_obj
= PHP_HTTP_OBJ(NULL
, request
);
1166 php_http_expect(SUCCESS
== php_http_client_getopt(obj
->client
, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO
, req_obj
->message
, &progress
), unexpected_val
, return);
1168 object_init(return_value
);
1169 add_property_bool(return_value
, "started", progress
->started
);
1170 add_property_bool(return_value
, "finished", progress
->finished
);
1171 add_property_string(return_value
, "info", STR_PTR(progress
->info
));
1172 add_property_double(return_value
, "dltotal", progress
->dl
.total
);
1173 add_property_double(return_value
, "dlnow", progress
->dl
.now
);
1174 add_property_double(return_value
, "ultotal", progress
->ul
.total
);
1175 add_property_double(return_value
, "ulnow", progress
->ul
.now
);
1178 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getTransferInfo
, 0, 0, 1)
1179 ZEND_ARG_OBJ_INFO(0, request
, http
\\Client
\\Request
, 0)
1180 ZEND_END_ARG_INFO();
1181 static PHP_METHOD(HttpClient
, getTransferInfo
)
1185 php_http_client_object_t
*obj
;
1186 php_http_message_object_t
*req_obj
;
1188 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request
, php_http_get_client_request_class_entry()), invalid_arg
, return);
1190 obj
= PHP_HTTP_OBJ(NULL
, getThis());
1191 req_obj
= PHP_HTTP_OBJ(NULL
, request
);
1193 object_init(return_value
);
1194 info
= HASH_OF(return_value
);
1195 php_http_expect(SUCCESS
== php_http_client_getopt(obj
->client
, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO
, req_obj
->message
, &info
), unexpected_val
, return);
1198 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setOptions
, 0, 0, 0)
1199 ZEND_ARG_ARRAY_INFO(0, options
, 1)
1200 ZEND_END_ARG_INFO();
1201 static PHP_METHOD(HttpClient
, setOptions
)
1205 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts
), invalid_arg
, return);
1207 php_http_client_options_set(getThis(), opts
);
1209 RETVAL_ZVAL(getThis(), 1, 0);
1212 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getOptions
, 0, 0, 0)
1213 ZEND_END_ARG_INFO();
1214 static PHP_METHOD(HttpClient
, getOptions
)
1216 if (SUCCESS
== zend_parse_parameters_none()) {
1217 zval options_tmp
, *options
= zend_read_property(php_http_client_class_entry
, Z_OBJ_P(ZEND_THIS
), ZEND_STRL("options"), 0, &options_tmp
);
1218 RETVAL_ZVAL(options
, 1, 0);
1222 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setSslOptions
, 0, 0, 0)
1223 ZEND_ARG_ARRAY_INFO(0, ssl_option
, 1)
1224 ZEND_END_ARG_INFO();
1225 static PHP_METHOD(HttpClient
, setSslOptions
)
1229 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts
), invalid_arg
, return);
1231 php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts
, 1);
1233 RETVAL_ZVAL(getThis(), 1, 0);
1236 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addSslOptions
, 0, 0, 0)
1237 ZEND_ARG_ARRAY_INFO(0, ssl_options
, 1)
1238 ZEND_END_ARG_INFO();
1239 static PHP_METHOD(HttpClient
, addSslOptions
)
1243 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts
), invalid_arg
, return);
1245 php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts
, 0);
1247 RETVAL_ZVAL(getThis(), 1, 0);
1250 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getSslOptions
, 0, 0, 0)
1251 ZEND_END_ARG_INFO();
1252 static PHP_METHOD(HttpClient
, getSslOptions
)
1254 if (SUCCESS
== zend_parse_parameters_none()) {
1255 php_http_client_options_get_subr(getThis(), ZEND_STRL("ssl"), return_value
);
1259 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setCookies
, 0, 0, 0)
1260 ZEND_ARG_ARRAY_INFO(0, cookies
, 1)
1261 ZEND_END_ARG_INFO();
1262 static PHP_METHOD(HttpClient
, setCookies
)
1266 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts
), invalid_arg
, return);
1268 php_http_client_options_set_subr(getThis(), ZEND_STRL("cookies"), opts
, 1);
1270 RETVAL_ZVAL(getThis(), 1, 0);
1273 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addCookies
, 0, 0, 0)
1274 ZEND_ARG_ARRAY_INFO(0, cookies
, 1)
1275 ZEND_END_ARG_INFO();
1276 static PHP_METHOD(HttpClient
, addCookies
)
1280 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts
), invalid_arg
, return);
1282 php_http_client_options_set_subr(getThis(), ZEND_STRL("cookies"), opts
, 0);
1284 RETVAL_ZVAL(getThis(), 1, 0);
1287 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getCookies
, 0, 0, 0)
1288 ZEND_END_ARG_INFO();
1289 static PHP_METHOD(HttpClient
, getCookies
)
1291 if (SUCCESS
== zend_parse_parameters_none()) {
1292 php_http_client_options_get_subr(getThis(), ZEND_STRL("cookies"), return_value
);
1296 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableDrivers
, 0, 0, 0)
1297 ZEND_END_ARG_INFO();
1298 static PHP_METHOD(HttpClient
, getAvailableDrivers
)
1300 if (SUCCESS
== zend_parse_parameters_none()) {
1301 array_init(return_value
);
1302 php_http_client_driver_list(Z_ARRVAL_P(return_value
));
1306 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableOptions
, 0, 0, 0)
1307 ZEND_END_ARG_INFO();
1308 static PHP_METHOD(HttpClient
, getAvailableOptions
)
1310 if (SUCCESS
== zend_parse_parameters_none()) {
1311 php_http_client_object_t
*obj
= PHP_HTTP_OBJ(NULL
, getThis());
1313 array_init(return_value
);
1314 php_http_client_getopt(obj
->client
, PHP_HTTP_CLIENT_OPT_AVAILABLE_OPTIONS
, NULL
, &Z_ARRVAL_P(return_value
));
1318 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableConfiguration
, 0, 0, 0)
1319 ZEND_END_ARG_INFO();
1320 static PHP_METHOD(HttpClient
, getAvailableConfiguration
)
1322 if (SUCCESS
== zend_parse_parameters_none()) {
1323 php_http_client_object_t
*obj
= PHP_HTTP_OBJ(NULL
, getThis());
1325 array_init(return_value
);
1326 php_http_client_getopt(obj
->client
, PHP_HTTP_CLIENT_OPT_AVAILABLE_CONFIGURATION
, NULL
, &Z_ARRVAL_P(return_value
));
1330 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setDebug
, 0, 0, 1)
1331 /* using IS_CALLABLE type hint would create a forwards compatibility break */
1332 ZEND_ARG_INFO(0, callback
)
1333 ZEND_END_ARG_INFO();
1334 static PHP_METHOD(HttpClient
, setDebug
)
1336 zend_fcall_info fci
;
1337 zend_fcall_info_cache fcc
;
1338 php_http_client_object_t
*client_obj
;
1341 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|f", &fci
, &fcc
), invalid_arg
, return);
1343 client_obj
= PHP_HTTP_OBJ(NULL
, getThis());
1345 if (client_obj
->debug
.fci
.size
> 0) {
1346 zval_ptr_dtor(&client_obj
->debug
.fci
.function_name
);
1347 client_obj
->debug
.fci
.size
= 0;
1350 memcpy(&client_obj
->debug
.fci
, &fci
, sizeof(fci
));
1351 memcpy(&client_obj
->debug
.fcc
, &fcc
, sizeof(fcc
));
1352 Z_ADDREF_P(&fci
.function_name
);
1353 client_obj
->client
->callback
.debug
.func
= handle_debug
;
1354 client_obj
->client
->callback
.debug
.arg
= client_obj
;
1356 client_obj
->client
->callback
.debug
.func
= NULL
;
1357 client_obj
->client
->callback
.debug
.arg
= NULL
;
1360 RETVAL_ZVAL(getThis(), 1, 0);
1363 static zend_function_entry php_http_client_methods
[] = {
1364 PHP_ME(HttpClient
, __construct
, ai_HttpClient_construct
, ZEND_ACC_PUBLIC
)
1365 PHP_ME(HttpClient
, reset
, ai_HttpClient_reset
, ZEND_ACC_PUBLIC
)
1366 PHP_ME(HttpClient
, enqueue
, ai_HttpClient_enqueue
, ZEND_ACC_PUBLIC
)
1367 PHP_ME(HttpClient
, dequeue
, ai_HttpClient_dequeue
, ZEND_ACC_PUBLIC
)
1368 PHP_ME(HttpClient
, requeue
, ai_HttpClient_requeue
, ZEND_ACC_PUBLIC
)
1369 PHP_ME(HttpClient
, count
, ai_HttpClient_count
, ZEND_ACC_PUBLIC
)
1370 PHP_ME(HttpClient
, send
, ai_HttpClient_send
, ZEND_ACC_PUBLIC
)
1371 PHP_ME(HttpClient
, once
, ai_HttpClient_once
, ZEND_ACC_PUBLIC
)
1372 PHP_ME(HttpClient
, wait
, ai_HttpClient_wait
, ZEND_ACC_PUBLIC
)
1373 PHP_ME(HttpClient
, getResponse
, ai_HttpClient_getResponse
, ZEND_ACC_PUBLIC
)
1374 PHP_ME(HttpClient
, getHistory
, ai_HttpClient_getHistory
, ZEND_ACC_PUBLIC
)
1375 PHP_ME(HttpClient
, configure
, ai_HttpClient_configure
, ZEND_ACC_PUBLIC
)
1376 PHP_ME(HttpClient
, enablePipelining
, ai_HttpClient_enablePipelining
, ZEND_ACC_PUBLIC
|ZEND_ACC_DEPRECATED
)
1377 PHP_ME(HttpClient
, enableEvents
, ai_HttpClient_enableEvents
, ZEND_ACC_PUBLIC
|ZEND_ACC_DEPRECATED
)
1378 PHP_ME(HttpClient
, notify
, ai_HttpClient_notify
, ZEND_ACC_PUBLIC
)
1379 PHP_ME(HttpClient
, attach
, ai_HttpClient_attach
, ZEND_ACC_PUBLIC
)
1380 PHP_ME(HttpClient
, detach
, ai_HttpClient_detach
, ZEND_ACC_PUBLIC
)
1381 PHP_ME(HttpClient
, getObservers
, ai_HttpClient_getObservers
, ZEND_ACC_PUBLIC
)
1382 PHP_ME(HttpClient
, getProgressInfo
, ai_HttpClient_getProgressInfo
, ZEND_ACC_PUBLIC
)
1383 PHP_ME(HttpClient
, getTransferInfo
, ai_HttpClient_getTransferInfo
, ZEND_ACC_PUBLIC
)
1384 PHP_ME(HttpClient
, setOptions
, ai_HttpClient_setOptions
, ZEND_ACC_PUBLIC
)
1385 PHP_ME(HttpClient
, getOptions
, ai_HttpClient_getOptions
, ZEND_ACC_PUBLIC
)
1386 PHP_ME(HttpClient
, setSslOptions
, ai_HttpClient_setSslOptions
, ZEND_ACC_PUBLIC
)
1387 PHP_ME(HttpClient
, addSslOptions
, ai_HttpClient_addSslOptions
, ZEND_ACC_PUBLIC
)
1388 PHP_ME(HttpClient
, getSslOptions
, ai_HttpClient_getSslOptions
, ZEND_ACC_PUBLIC
)
1389 PHP_ME(HttpClient
, setCookies
, ai_HttpClient_setCookies
, ZEND_ACC_PUBLIC
)
1390 PHP_ME(HttpClient
, addCookies
, ai_HttpClient_addCookies
, ZEND_ACC_PUBLIC
)
1391 PHP_ME(HttpClient
, getCookies
, ai_HttpClient_getCookies
, ZEND_ACC_PUBLIC
)
1392 PHP_ME(HttpClient
, getAvailableDrivers
, ai_HttpClient_getAvailableDrivers
, ZEND_ACC_PUBLIC
|ZEND_ACC_STATIC
)
1393 PHP_ME(HttpClient
, getAvailableOptions
, ai_HttpClient_getAvailableOptions
, ZEND_ACC_PUBLIC
)
1394 PHP_ME(HttpClient
, getAvailableConfiguration
, ai_HttpClient_getAvailableConfiguration
, ZEND_ACC_PUBLIC
)
1395 PHP_ME(HttpClient
, setDebug
, ai_HttpClient_setDebug
, ZEND_ACC_PUBLIC
)
1396 EMPTY_FUNCTION_ENTRY
1399 PHP_MINIT_FUNCTION(http_client
)
1401 zend_class_entry ce
= {0};
1403 INIT_NS_CLASS_ENTRY(ce
, "http", "Client", php_http_client_methods
);
1404 php_http_client_class_entry
= zend_register_internal_class_ex(&ce
, NULL
);
1405 php_http_client_class_entry
->create_object
= php_http_client_object_new
;
1406 zend_class_implements(php_http_client_class_entry
, 2, spl_ce_SplSubject
, zend_ce_countable
);
1407 memcpy(&php_http_client_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
1408 php_http_client_object_handlers
.offset
= XtOffsetOf(php_http_client_object_t
, zo
);
1409 php_http_client_object_handlers
.free_obj
= php_http_client_object_free
;
1410 php_http_client_object_handlers
.clone_obj
= NULL
;
1411 php_http_client_object_handlers
.get_gc
= php_http_client_object_get_gc
;
1412 zend_declare_property_null(php_http_client_class_entry
, ZEND_STRL("observers"), ZEND_ACC_PRIVATE
);
1413 zend_declare_property_null(php_http_client_class_entry
, ZEND_STRL("options"), ZEND_ACC_PROTECTED
);
1414 zend_declare_property_null(php_http_client_class_entry
, ZEND_STRL("history"), ZEND_ACC_PROTECTED
);
1415 zend_declare_property_bool(php_http_client_class_entry
, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC
);
1417 zend_declare_class_constant_long(php_http_client_class_entry
, ZEND_STRL("DEBUG_INFO"), PHP_HTTP_CLIENT_DEBUG_INFO
);
1418 zend_declare_class_constant_long(php_http_client_class_entry
, ZEND_STRL("DEBUG_IN"), PHP_HTTP_CLIENT_DEBUG_IN
);
1419 zend_declare_class_constant_long(php_http_client_class_entry
, ZEND_STRL("DEBUG_OUT"), PHP_HTTP_CLIENT_DEBUG_OUT
);
1420 zend_declare_class_constant_long(php_http_client_class_entry
, ZEND_STRL("DEBUG_HEADER"), PHP_HTTP_CLIENT_DEBUG_HEADER
);
1421 zend_declare_class_constant_long(php_http_client_class_entry
, ZEND_STRL("DEBUG_BODY"), PHP_HTTP_CLIENT_DEBUG_BODY
);
1422 zend_declare_class_constant_long(php_http_client_class_entry
, ZEND_STRL("DEBUG_SSL"), PHP_HTTP_CLIENT_DEBUG_SSL
);
1424 zend_hash_init(&php_http_client_drivers
, 2, NULL
, php_http_client_driver_hash_dtor
, 1);
1429 PHP_MSHUTDOWN_FUNCTION(http_client
)
1431 zend_hash_destroy(&php_http_client_drivers
);
1440 * vim600: noet sw=4 ts=4 fdm=marker
1441 * vim<600: noet sw=4 ts=4