LCOV - code coverage report
Current view: top level - http - php_http_client.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 515 571 90.2 %
Date: 2014-11-03 12:21:11 Functions: 58 61 95.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :     +--------------------------------------------------------------------+
       3             :     | PECL :: http                                                       |
       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             :     +--------------------------------------------------------------------+
      11             : */
      12             : 
      13             : #include "php_http_api.h"
      14             : #include "php_http_client.h"
      15             : 
      16             : #include <ext/spl/spl_observer.h>
      17             : 
      18             : /*
      19             :  * array of name => php_http_client_driver_t*
      20             :  */
      21             : static HashTable php_http_client_drivers;
      22             : 
      23         408 : STATUS php_http_client_driver_add(php_http_client_driver_t *driver)
      24             : {
      25         408 :         return zend_hash_add(&php_http_client_drivers, driver->name_str, driver->name_len + 1, (void *) driver, sizeof(php_http_client_driver_t), NULL);
      26             : }
      27             : 
      28          29 : STATUS php_http_client_driver_get(const char *name_str, size_t name_len, php_http_client_driver_t *driver)
      29             : {
      30             :         php_http_client_driver_t *tmp;
      31             : 
      32          29 :         if ((name_str && SUCCESS == zend_hash_find(&php_http_client_drivers, name_str, name_len + 1, (void *) &tmp))
      33          10 :         ||      (SUCCESS == zend_hash_get_current_data(&php_http_client_drivers, (void *) &tmp))) {
      34          29 :                 *driver = *tmp;
      35          29 :                 return SUCCESS;
      36             :         }
      37           0 :         return FAILURE;
      38             : }
      39             : 
      40          14 : static int apply_driver_list(void *p, void *arg TSRMLS_DC)
      41             : {
      42          14 :         php_http_client_driver_t *d = p;
      43             :         zval *zname;
      44             : 
      45          14 :         MAKE_STD_ZVAL(zname);
      46          14 :         ZVAL_STRINGL(zname, d->name_str, d->name_len, 1);
      47             : 
      48          14 :         zend_hash_next_index_insert(arg, &zname, sizeof(zval *), NULL);
      49          14 :         return ZEND_HASH_APPLY_KEEP;
      50             : }
      51             : 
      52          14 : void php_http_client_driver_list(HashTable *ht TSRMLS_DC)
      53             : {
      54          14 :         zend_hash_apply_with_argument(&php_http_client_drivers, apply_driver_list, ht TSRMLS_CC);
      55          14 : }
      56             : 
      57           6 : void php_http_client_options_set_subr(zval *this_ptr, char *key, size_t len, zval *opts, int overwrite TSRMLS_DC)
      58             : {
      59           6 :         if (overwrite || (opts && zend_hash_num_elements(Z_ARRVAL_P(opts)))) {
      60           6 :                 zend_class_entry *this_ce = Z_OBJCE_P(getThis());
      61           6 :                 zval *old_opts, *new_opts, **entry = NULL;
      62             : 
      63           6 :                 MAKE_STD_ZVAL(new_opts);
      64           6 :                 array_init(new_opts);
      65           6 :                 old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
      66           6 :                 if (Z_TYPE_P(old_opts) == IS_ARRAY) {
      67           3 :                         array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts));
      68             :                 }
      69             : 
      70           6 :                 if (overwrite) {
      71           3 :                         if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) {
      72           3 :                                 Z_ADDREF_P(opts);
      73           3 :                                 zend_symtable_update(Z_ARRVAL_P(new_opts), key, len, (void *) &opts, sizeof(zval *), NULL);
      74             :                         } else {
      75           0 :                                 zend_symtable_del(Z_ARRVAL_P(new_opts), key, len);
      76             :                         }
      77           3 :                 } else if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) {
      78           3 :                         if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(new_opts), key, len, (void *) &entry)) {
      79           2 :                                 array_join(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry), 0, 0);
      80             :                         } else {
      81           1 :                                 Z_ADDREF_P(opts);
      82           1 :                                 zend_symtable_update(Z_ARRVAL_P(new_opts), key, len, (void *) &opts, sizeof(zval *), NULL);
      83             :                         }
      84             :                 }
      85             : 
      86           6 :                 zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC);
      87           6 :                 zval_ptr_dtor(&new_opts);
      88             :         }
      89           6 : }
      90             : 
      91           3 : void php_http_client_options_set(zval *this_ptr, zval *opts TSRMLS_DC)
      92             : {
      93           3 :         php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
      94             :         HashPosition pos;
      95             :         zval *new_opts;
      96           3 :         zend_class_entry *this_ce = Z_OBJCE_P(getThis());
      97           3 :         zend_bool is_client = instanceof_function(this_ce, php_http_client_class_entry TSRMLS_CC);
      98             : 
      99           3 :         MAKE_STD_ZVAL(new_opts);
     100           3 :         array_init(new_opts);
     101             : 
     102           3 :         if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) {
     103           0 :                 zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC);
     104           0 :                 zval_ptr_dtor(&new_opts);
     105             :         } else {
     106             :                 zval *old_opts, *add_opts, **opt;
     107             : 
     108           3 :                 MAKE_STD_ZVAL(add_opts);
     109           3 :                 array_init(add_opts);
     110             :                 /* some options need extra attention -- thus cannot use array_merge() directly */
     111           7 :                 FOREACH_KEYVAL(pos, opts, key, opt) {
     112           4 :                         if (key.type == HASH_KEY_IS_STRING) {
     113             : #define KEYMATCH(k, s) ((sizeof(s)==k.len) && !strcasecmp(k.str, s))
     114           4 :                                 if (Z_TYPE_PP(opt) == IS_ARRAY && (KEYMATCH(key, "ssl") || KEYMATCH(key, "cookies"))) {
     115           1 :                                         php_http_client_options_set_subr(getThis(), key.str, key.len, *opt, 0 TSRMLS_CC);
     116           3 :                                 } else if (is_client && (KEYMATCH(key, "recordHistory") || KEYMATCH(key, "responseMessageClass"))) {
     117           0 :                                         zend_update_property(this_ce, getThis(), key.str, key.len-1, *opt TSRMLS_CC);
     118           3 :                                 } else if (Z_TYPE_PP(opt) == IS_NULL) {
     119           0 :                                         old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
     120           0 :                                         if (Z_TYPE_P(old_opts) == IS_ARRAY) {
     121           0 :                                                 zend_symtable_del(Z_ARRVAL_P(old_opts), key.str, key.len);
     122             :                                         }
     123             :                                 } else {
     124           3 :                                         Z_ADDREF_P(*opt);
     125           3 :                                         add_assoc_zval_ex(add_opts, key.str, key.len, *opt);
     126             :                                 }
     127             :                         }
     128             :                 }
     129             : 
     130           3 :                 old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
     131           3 :                 if (Z_TYPE_P(old_opts) == IS_ARRAY) {
     132           2 :                         array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts));
     133             :                 }
     134           3 :                 array_join(Z_ARRVAL_P(add_opts), Z_ARRVAL_P(new_opts), 0, 0);
     135           3 :                 zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC);
     136           3 :                 zval_ptr_dtor(&new_opts);
     137           3 :                 zval_ptr_dtor(&add_opts);
     138             :         }
     139           3 : }
     140             : 
     141           3 : void php_http_client_options_get_subr(zval *this_ptr, char *key, size_t len, zval *return_value TSRMLS_DC)
     142             : {
     143           3 :         zend_class_entry *this_ce = Z_OBJCE_P(getThis());
     144           3 :         zval **options, *opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
     145             : 
     146           3 :         if ((Z_TYPE_P(opts) == IS_ARRAY) && (SUCCESS == zend_symtable_find(Z_ARRVAL_P(opts), key, len, (void *) &options))) {
     147           3 :                 RETVAL_ZVAL(*options, 1, 0);
     148             :         }
     149           3 : }
     150             : 
     151          43 : static void queue_dtor(void *enqueued)
     152             : {
     153          43 :         php_http_client_enqueue_t *e = enqueued;
     154             : 
     155          43 :         if (e->dtor) {
     156          43 :                 e->dtor(e);
     157             :         }
     158          43 : }
     159             : 
     160          29 : 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)
     161             : {
     162          29 :         php_http_client_t *free_h = NULL;
     163             : 
     164          29 :         if (!h) {
     165          29 :                 free_h = h = emalloc(sizeof(*h));
     166             :         }
     167          29 :         memset(h, 0, sizeof(*h));
     168             : 
     169          29 :         h->ops = ops;
     170          29 :         if (rf) {
     171           5 :                 h->rf = rf;
     172          24 :         } else if (ops->rsrc) {
     173          24 :                 h->rf = php_resource_factory_init(NULL, h->ops->rsrc, h, NULL);
     174             :         }
     175          29 :         zend_llist_init(&h->requests, sizeof(php_http_client_enqueue_t), queue_dtor, 0);
     176          29 :         zend_llist_init(&h->responses, sizeof(void *), NULL, 0);
     177             :         TSRMLS_SET_CTX(h->ts);
     178             : 
     179          29 :         if (h->ops->init) {
     180          29 :                 if (!(h = h->ops->init(h, init_arg))) {
     181           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initialize client");
     182           0 :                         if (free_h) {
     183           0 :                                 efree(free_h);
     184             :                         }
     185             :                 }
     186             :         }
     187             : 
     188          29 :         return h;
     189             : }
     190             : 
     191           0 : php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to)
     192             : {
     193           0 :         if (from->ops->copy) {
     194           0 :                 return from->ops->copy(from, to);
     195             :         }
     196             : 
     197           0 :         return NULL;
     198             : }
     199             : 
     200          29 : void php_http_client_dtor(php_http_client_t *h)
     201             : {
     202          29 :         php_http_client_reset(h);
     203             : 
     204          29 :         if (h->ops->dtor) {
     205          29 :                 h->ops->dtor(h);
     206             :         }
     207             : 
     208          29 :         php_resource_factory_free(&h->rf);
     209          29 : }
     210             : 
     211          30 : void php_http_client_free(php_http_client_t **h) {
     212          30 :         if (*h) {
     213          29 :                 php_http_client_dtor(*h);
     214          29 :                 efree(*h);
     215          29 :                 *h = NULL;
     216             :         }
     217          30 : }
     218             : 
     219          43 : STATUS php_http_client_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue)
     220             : {
     221             :         TSRMLS_FETCH_FROM_CTX(h->ts);
     222             : 
     223          43 :         if (h->ops->enqueue) {
     224          43 :                 if (php_http_client_enqueued(h, enqueue->request, NULL)) {
     225           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to enqueue request; request already in queue");
     226           0 :                         return FAILURE;
     227             :                 }
     228          43 :                 return h->ops->enqueue(h, enqueue);
     229             :         }
     230             : 
     231           0 :         return FAILURE;
     232             : }
     233             : 
     234           6 : STATUS php_http_client_dequeue(php_http_client_t *h, php_http_message_t *request)
     235             : {
     236             :         TSRMLS_FETCH_FROM_CTX(h->ts);
     237             : 
     238           6 :         if (h->ops->dequeue) {
     239           6 :                 php_http_client_enqueue_t *enqueue = php_http_client_enqueued(h, request, NULL);
     240             : 
     241           6 :                 if (!enqueue) {
     242           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to dequeue request; request not in queue");
     243           0 :                         return FAILURE;
     244             :                 }
     245           6 :                 return h->ops->dequeue(h, enqueue);
     246             :         }
     247           0 :         return FAILURE;
     248             : }
     249             : 
     250         243 : 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)
     251             : {
     252         243 :         zend_llist_element *el = NULL;
     253             : 
     254         243 :         if (compare_func) {
     255          27 :                 for (el = h->requests.head; el; el = el->next) {
     256          27 :                         if (compare_func((php_http_client_enqueue_t *) el->data, compare_arg)) {
     257          24 :                                 break;
     258             :                         }
     259             :                 }
     260             :         } else {
     261         279 :                 for (el = h->requests.head; el; el = el->next) {
     262         195 :                         if (((php_http_client_enqueue_t *) el->data)->request == compare_arg) {
     263         135 :                                 break;
     264             :                         }
     265             :                 }
     266             :         }
     267         243 :         return el ? (php_http_client_enqueue_t *) el->data : NULL;
     268             : }
     269             : 
     270          37 : STATUS php_http_client_wait(php_http_client_t *h, struct timeval *custom_timeout)
     271             : {
     272          37 :         if (h->ops->wait) {
     273          37 :                 return h->ops->wait(h, custom_timeout);
     274             :         }
     275             : 
     276           0 :         return FAILURE;
     277             : }
     278             : 
     279          39 : int php_http_client_once(php_http_client_t *h)
     280             : {
     281          39 :         if (h->ops->once) {
     282          39 :                 return h->ops->once(h);
     283             :         }
     284             : 
     285           0 :         return FAILURE;
     286             : }
     287             : 
     288          20 : STATUS php_http_client_exec(php_http_client_t *h)
     289             : {
     290          20 :         if (h->ops->exec) {
     291          20 :                 return h->ops->exec(h);
     292             :         }
     293             : 
     294           0 :         return FAILURE;
     295             : }
     296             : 
     297          30 : void php_http_client_reset(php_http_client_t *h)
     298             : {
     299          30 :         if (h->ops->reset) {
     300          30 :                 h->ops->reset(h);
     301             :         }
     302             : 
     303          30 :         zend_llist_clean(&h->requests);
     304          30 :         zend_llist_clean(&h->responses);
     305          30 : }
     306             : 
     307           7 : STATUS php_http_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg)
     308             : {
     309           7 :         if (h->ops->setopt) {
     310           7 :                 return h->ops->setopt(h, opt, arg);
     311             :         }
     312             : 
     313           0 :         return FAILURE;
     314             : }
     315             : 
     316         124 : STATUS php_http_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void *res_ptr)
     317             : {
     318         124 :         if (h->ops->getopt) {
     319         124 :                 return h->ops->getopt(h, opt, arg, res_ptr);
     320             :         }
     321           0 :         return FAILURE;
     322             : }
     323             : 
     324             : zend_class_entry *php_http_client_class_entry;
     325             : static zend_object_handlers php_http_client_object_handlers;
     326             : 
     327          30 : void php_http_client_object_free(void *object TSRMLS_DC)
     328             : {
     329          30 :         php_http_client_object_t *o = (php_http_client_object_t *) object;
     330             : 
     331          30 :         php_http_client_free(&o->client);
     332          30 :         zend_object_std_dtor((zend_object *) o TSRMLS_CC);
     333          30 :         efree(o);
     334          30 : }
     335             : 
     336          30 : 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)
     337             : {
     338             :         php_http_client_object_t *o;
     339             : 
     340          30 :         o = ecalloc(1, sizeof(php_http_client_object_t));
     341          30 :         zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
     342          30 :         object_properties_init((zend_object *) o, ce);
     343             : 
     344          30 :         o->client = client;
     345             : 
     346          30 :         if (ptr) {
     347           0 :                 *ptr = o;
     348             :         }
     349             : 
     350          30 :         o->zv.handle = zend_objects_store_put(o, NULL, php_http_client_object_free, NULL TSRMLS_CC);
     351          30 :         o->zv.handlers = &php_http_client_object_handlers;
     352             : 
     353          30 :         return o->zv;
     354             : }
     355             : 
     356          30 : zend_object_value php_http_client_object_new(zend_class_entry *ce TSRMLS_DC)
     357             : {
     358          30 :         return php_http_client_object_new_ex(ce, NULL, NULL TSRMLS_CC);
     359             : }
     360             : 
     361           2 : static void handle_history(zval *zclient, php_http_message_t *request, php_http_message_t *response TSRMLS_DC)
     362             : {
     363           2 :         zval *new_hist, *old_hist = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), 0 TSRMLS_CC);
     364           2 :         php_http_message_t *zipped = php_http_message_zip(response, request);
     365           2 :         zend_object_value ov = php_http_message_object_new_ex(php_http_message_class_entry, zipped, NULL TSRMLS_CC);
     366             : 
     367           2 :         MAKE_STD_ZVAL(new_hist);
     368           2 :         ZVAL_OBJVAL(new_hist, ov, 0);
     369             : 
     370           2 :         if (Z_TYPE_P(old_hist) == IS_OBJECT) {
     371           1 :                 php_http_message_object_prepend(new_hist, old_hist, 1 TSRMLS_CC);
     372             :         }
     373             : 
     374           2 :         zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), new_hist TSRMLS_CC);
     375           2 :         zval_ptr_dtor(&new_hist);
     376           2 : }
     377             : 
     378          24 : 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)
     379             : {
     380          24 :         zend_bool dequeue = 0;
     381             :         zval zclient;
     382             :         php_http_message_t *msg;
     383             :         php_http_client_progress_state_t *progress;
     384             :         TSRMLS_FETCH_FROM_CTX(client->ts);
     385             : 
     386          24 :         INIT_PZVAL(&zclient);
     387          24 :         ZVAL_OBJVAL(&zclient, ((php_http_client_object_t*) arg)->zv, 0);
     388             : 
     389          24 :         if ((msg = *response)) {
     390             :                 php_http_message_object_t *msg_obj;
     391             :                 zval *info, *zresponse, *zrequest;
     392             :                 HashTable *info_ht;
     393             : 
     394             :                 /* ensure the message is of type response (could be uninitialized in case of early error, like DNS) */
     395          24 :                 php_http_message_set_type(msg, PHP_HTTP_RESPONSE);
     396             : 
     397          24 :                 if (z_is_true(zend_read_property(php_http_client_class_entry, &zclient, ZEND_STRL("recordHistory"), 0 TSRMLS_CC))) {
     398           2 :                         handle_history(&zclient, *request, *response TSRMLS_CC);
     399             :                 }
     400             : 
     401             :                 /* hard detach, redirects etc. are in the history */
     402          24 :                 php_http_message_free(&msg->parent);
     403          24 :                 *response = NULL;
     404             : 
     405          24 :                 MAKE_STD_ZVAL(zresponse);
     406          24 :                 ZVAL_OBJVAL(zresponse, php_http_message_object_new_ex(php_http_client_response_class_entry, msg, &msg_obj TSRMLS_CC), 0);
     407             : 
     408          24 :                 MAKE_STD_ZVAL(zrequest);
     409          24 :                 ZVAL_OBJVAL(zrequest, ((php_http_message_object_t *) e->opaque)->zv, 1);
     410             : 
     411          24 :                 php_http_message_object_prepend(zresponse, zrequest, 1 TSRMLS_CC);
     412             : 
     413          24 :                 MAKE_STD_ZVAL(info);
     414          24 :                 object_init(info);
     415          24 :                 info_ht = HASH_OF(info);
     416          24 :                 php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, e->request, &info_ht);
     417          24 :                 zend_update_property(php_http_client_response_class_entry, zresponse, ZEND_STRL("transferInfo"), info TSRMLS_CC);
     418          24 :                 zval_ptr_dtor(&info);
     419             : 
     420          24 :                 zend_objects_store_add_ref_by_handle(msg_obj->zv.handle TSRMLS_CC);
     421          24 :                 zend_llist_add_element(&client->responses, &msg_obj);
     422             : 
     423          24 :                 if (e->closure.fci.size) {
     424           5 :                         zval *retval = NULL;
     425             :                         zend_error_handling zeh;
     426             : 
     427           5 :                         zend_fcall_info_argn(&e->closure.fci TSRMLS_CC, 1, &zresponse);
     428           5 :                         zend_replace_error_handling(EH_NORMAL, NULL, &zeh TSRMLS_CC);
     429           5 :                         zend_fcall_info_call(&e->closure.fci, &e->closure.fcc, &retval, NULL TSRMLS_CC);
     430           5 :                         zend_restore_error_handling(&zeh TSRMLS_CC);
     431           5 :                         zend_fcall_info_argn(&e->closure.fci TSRMLS_CC, 0);
     432             : 
     433           5 :                         if (retval) {
     434           5 :                                 if (Z_TYPE_P(retval) == IS_BOOL) {
     435           2 :                                         dequeue = Z_BVAL_P(retval);
     436             :                                 }
     437           5 :                                 zval_ptr_dtor(&retval);
     438             :                         }
     439             :                 }
     440             : 
     441          24 :                 zval_ptr_dtor(&zresponse);
     442          24 :                 zval_ptr_dtor(&zrequest);
     443             :         }
     444             : 
     445          24 :         if (SUCCESS == php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, e->request, &progress)) {
     446          24 :                 progress->info = "finished";
     447          24 :                 progress->finished = 1;
     448          24 :                 client->callback.progress.func(client->callback.progress.arg, client, e, progress);
     449             :         }
     450             : 
     451          24 :         if (dequeue) {
     452           2 :                 php_http_client_dequeue(client, e->request);
     453             :         }
     454             : 
     455          24 :         return SUCCESS;
     456             : }
     457             : 
     458         309 : static void handle_progress(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *progress)
     459             : {
     460         309 :         zval *zrequest, *zprogress, *retval = NULL, *zclient;
     461             :         zend_error_handling zeh;
     462             :         TSRMLS_FETCH_FROM_CTX(client->ts);
     463             : 
     464         309 :         MAKE_STD_ZVAL(zclient);
     465         309 :         ZVAL_OBJVAL(zclient, ((php_http_client_object_t *) arg)->zv, 1);
     466         309 :         MAKE_STD_ZVAL(zrequest);
     467         309 :         ZVAL_OBJVAL(zrequest, ((php_http_message_object_t *) e->opaque)->zv, 1);
     468         309 :         MAKE_STD_ZVAL(zprogress);
     469         309 :         object_init(zprogress);
     470         309 :         add_property_bool(zprogress, "started", progress->started);
     471         309 :         add_property_bool(zprogress, "finished", progress->finished);
     472         309 :         add_property_string(zprogress, "info", STR_PTR(progress->info), 1);
     473         309 :         add_property_double(zprogress, "dltotal", progress->dl.total);
     474         309 :         add_property_double(zprogress, "dlnow", progress->dl.now);
     475         309 :         add_property_double(zprogress, "ultotal", progress->ul.total);
     476         309 :         add_property_double(zprogress, "ulnow", progress->ul.now);
     477         309 :         zend_replace_error_handling(EH_NORMAL, NULL, &zeh TSRMLS_CC);
     478         309 :         zend_call_method_with_2_params(&zclient, NULL, NULL, "notify", &retval, zrequest, zprogress);
     479         309 :         zend_restore_error_handling(&zeh TSRMLS_CC);
     480         309 :         zval_ptr_dtor(&zclient);
     481         309 :         zval_ptr_dtor(&zrequest);
     482         309 :         zval_ptr_dtor(&zprogress);
     483         309 :         if (retval) {
     484         309 :                 zval_ptr_dtor(&retval);
     485             :         }
     486         309 : }
     487             : 
     488          24 : static void response_dtor(void *data)
     489             : {
     490          24 :         php_http_message_object_t *msg_obj = *(php_http_message_object_t **) data;
     491             :         TSRMLS_FETCH_FROM_CTX(msg_obj->message->ts);
     492             : 
     493          24 :         zend_objects_store_del_ref_by_handle_ex(msg_obj->zv.handle, msg_obj->zv.handlers TSRMLS_CC);
     494          24 : }
     495             : 
     496             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_construct, 0, 0, 0)
     497             :         ZEND_ARG_INFO(0, driver)
     498             :         ZEND_ARG_INFO(0, persistent_handle_id)
     499             : ZEND_END_ARG_INFO();
     500          29 : static PHP_METHOD(HttpClient, __construct)
     501             : {
     502          29 :                 char *driver_str = NULL, *persistent_handle_str = NULL;
     503          29 :                 int driver_len = 0, persistent_handle_len = 0;
     504             :                 php_http_client_driver_t driver;
     505          29 :                 php_resource_factory_t *rf = NULL;
     506             :                 php_http_client_object_t *obj;
     507             :                 zval *os;
     508             : 
     509          29 :                 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &driver_str, &driver_len, &persistent_handle_str, &persistent_handle_len), invalid_arg, return);
     510             : 
     511          29 :                 if (SUCCESS != php_http_client_driver_get(driver_str, driver_len, &driver)) {
     512           0 :                         php_http_throw(unexpected_val, "Failed to locate \"%s\" client request handler", driver_str);
     513           0 :                         return;
     514             :                 }
     515             : 
     516          29 :                 MAKE_STD_ZVAL(os);
     517          29 :                 object_init_ex(os, spl_ce_SplObjectStorage);
     518          29 :                 zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), os TSRMLS_CC);
     519          29 :                 zval_ptr_dtor(&os);
     520             : 
     521          29 :                 if (persistent_handle_len) {
     522             :                         char *name_str;
     523             :                         size_t name_len;
     524             :                         php_persistent_handle_factory_t *pf;
     525             : 
     526           5 :                         name_len = spprintf(&name_str, 0, "http\\Client\\%s", driver.name_str);
     527           5 :                         php_http_pretty_key(name_str + sizeof("http\\Client"), driver.name_len, 1, 1);
     528             : 
     529           5 :                         if ((pf = php_persistent_handle_concede(NULL , name_str, name_len, persistent_handle_str, persistent_handle_len, NULL, NULL TSRMLS_CC))) {
     530           5 :                                 rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void *)) php_persistent_handle_abandon);
     531             :                         }
     532             : 
     533           5 :                         efree(name_str);
     534             :                 }
     535             : 
     536          29 :                 obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     537             : 
     538          29 :                 php_http_expect(obj->client = php_http_client_init(NULL, driver.client_ops, rf, NULL TSRMLS_CC), runtime, return);
     539             : 
     540          29 :                 obj->client->callback.response.func = handle_response;
     541          29 :                 obj->client->callback.response.arg = obj;
     542          29 :                 obj->client->callback.progress.func = handle_progress;
     543          29 :                 obj->client->callback.progress.arg = obj;
     544             : 
     545          29 :                 obj->client->responses.dtor = response_dtor;
     546             : }
     547             : 
     548             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_reset, 0, 0, 0)
     549             : ZEND_END_ARG_INFO();
     550           1 : static PHP_METHOD(HttpClient, reset)
     551             : {
     552             :         php_http_client_object_t *obj;
     553           2 :         php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
     554             : 
     555           1 :         obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     556             : 
     557           1 :         obj->iterator = 0;
     558           1 :         php_http_client_reset(obj->client);
     559             : 
     560           1 :         RETVAL_ZVAL(getThis(), 1, 0);
     561             : }
     562             : 
     563          43 : static HashTable *combined_options(zval *client, zval *request TSRMLS_DC)
     564             : {
     565             :         HashTable *options;
     566          43 :         int num_options = 0;
     567          43 :         zval *z_roptions = NULL, *z_coptions = zend_read_property(php_http_client_class_entry, client, ZEND_STRL("options"), 0 TSRMLS_CC);
     568             : 
     569          43 :         if (Z_TYPE_P(z_coptions) == IS_ARRAY) {
     570           3 :                 num_options = zend_hash_num_elements(Z_ARRVAL_P(z_coptions));
     571             :         }
     572          43 :         zend_call_method_with_0_params(&request, NULL, NULL, "getOptions", &z_roptions);
     573          43 :         if (z_roptions && Z_TYPE_P(z_roptions) == IS_ARRAY) {
     574           1 :                 int num = zend_hash_num_elements(Z_ARRVAL_P(z_roptions));
     575           1 :                 if (num > num_options) {
     576           0 :                         num_options = num;
     577             :                 }
     578             :         }
     579          43 :         ALLOC_HASHTABLE(options);
     580          43 :         ZEND_INIT_SYMTABLE_EX(options, num_options, 0);
     581          43 :         if (Z_TYPE_P(z_coptions) == IS_ARRAY) {
     582           3 :                 array_copy(Z_ARRVAL_P(z_coptions), options);
     583             :         }
     584          43 :         if (z_roptions) {
     585          43 :                 if (Z_TYPE_P(z_roptions) == IS_ARRAY) {
     586           1 :                         array_join(Z_ARRVAL_P(z_roptions), options, 0, 0);
     587             :                 }
     588          43 :                 zval_ptr_dtor(&z_roptions);
     589             :         }
     590          43 :         return options;
     591             : }
     592             : 
     593          43 : static void msg_queue_dtor(php_http_client_enqueue_t *e)
     594             : {
     595          43 :         php_http_message_object_t *msg_obj = e->opaque;
     596             :         TSRMLS_FETCH_FROM_CTX(msg_obj->message->ts);
     597             : 
     598          43 :         zend_objects_store_del_ref_by_handle_ex(msg_obj->zv.handle, msg_obj->zv.handlers TSRMLS_CC);
     599          43 :         zend_hash_destroy(e->options);
     600          43 :         FREE_HASHTABLE(e->options);
     601             : 
     602          43 :         if (e->closure.fci.size) {
     603           5 :                 zval_ptr_dtor(&e->closure.fci.function_name);
     604           5 :                 if (e->closure.fci.object_ptr) {
     605           0 :                         zval_ptr_dtor(&e->closure.fci.object_ptr);
     606             :                 }
     607             :         }
     608          43 : }
     609             : 
     610             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enqueue, 0, 0, 1)
     611             :         ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
     612             :         ZEND_ARG_INFO(0, callable)
     613             : ZEND_END_ARG_INFO();
     614          39 : static PHP_METHOD(HttpClient, enqueue)
     615             : {
     616             :         zval *request;
     617          39 :         zend_fcall_info fci = empty_fcall_info;
     618          39 :         zend_fcall_info_cache fcc = empty_fcall_info_cache;
     619             :         php_http_client_object_t *obj;
     620             :         php_http_message_object_t *msg_obj;
     621             :         php_http_client_enqueue_t q;
     622             : 
     623          39 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|f", &request, php_http_client_request_class_entry, &fci, &fcc), invalid_arg, return);
     624             : 
     625          39 :         obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     626          39 :         msg_obj = zend_object_store_get_object(request TSRMLS_CC);
     627             : 
     628          39 :         if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
     629           1 :                 php_http_throw(bad_method_call, "Failed to enqueue request; request already in queue", NULL);
     630           1 :                 return;
     631             :         }
     632             : 
     633          38 :         q.request = msg_obj->message;
     634          38 :         q.options = combined_options(getThis(), request TSRMLS_CC);
     635          38 :         q.dtor = msg_queue_dtor;
     636          38 :         q.opaque = msg_obj;
     637          38 :         q.closure.fci = fci;
     638          38 :         q.closure.fcc = fcc;
     639             : 
     640          38 :         if (fci.size) {
     641           3 :                 Z_ADDREF_P(fci.function_name);
     642           3 :                 if (fci.object_ptr) {
     643           0 :                         Z_ADDREF_P(fci.object_ptr);
     644             :                 }
     645             :         }
     646             : 
     647          38 :         zend_objects_store_add_ref_by_handle(msg_obj->zv.handle TSRMLS_CC);
     648             : 
     649          38 :         php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime,
     650             :                         msg_queue_dtor(&q);
     651             :                         return;
     652             :         );
     653             : 
     654          38 :         RETVAL_ZVAL(getThis(), 1, 0);
     655             : }
     656             : 
     657             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_dequeue, 0, 0, 1)
     658             :         ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
     659             : ZEND_END_ARG_INFO();
     660           2 : static PHP_METHOD(HttpClient, dequeue)
     661             : {
     662             :         zval *request;
     663             :         php_http_client_object_t *obj;
     664             :         php_http_message_object_t *msg_obj;
     665             : 
     666           2 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_request_class_entry), invalid_arg, return);
     667             : 
     668           2 :         obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     669           2 :         msg_obj = zend_object_store_get_object(request TSRMLS_CC);
     670             : 
     671           2 :         if (!php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
     672           2 :                 php_http_throw(bad_method_call, "Failed to dequeue request; request not in queue", NULL);
     673           2 :                 return;
     674             :         }
     675             : 
     676           0 :         php_http_expect(SUCCESS == php_http_client_dequeue(obj->client, msg_obj->message), runtime, return);
     677             : 
     678           0 :         RETVAL_ZVAL(getThis(), 1, 0);
     679             : }
     680             : 
     681             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_requeue, 0, 0, 1)
     682             :         ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
     683             :         ZEND_ARG_INFO(0, callable)
     684             : ZEND_END_ARG_INFO();
     685           5 : static PHP_METHOD(HttpClient, requeue)
     686             : {
     687             :         zval *request;
     688           5 :         zend_fcall_info fci = empty_fcall_info;
     689           5 :         zend_fcall_info_cache fcc = empty_fcall_info_cache;
     690             :         php_http_client_object_t *obj;
     691             :         php_http_message_object_t *msg_obj;
     692             :         php_http_client_enqueue_t q;
     693             : 
     694           5 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|f", &request, php_http_client_request_class_entry, &fci, &fcc), invalid_arg, return);
     695             : 
     696           5 :         obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     697           5 :         msg_obj = zend_object_store_get_object(request TSRMLS_CC);
     698             : 
     699           5 :         if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
     700           4 :                 php_http_expect(SUCCESS == php_http_client_dequeue(obj->client, msg_obj->message), runtime, return);
     701             :         }
     702             : 
     703           5 :         q.request = msg_obj->message;
     704           5 :         q.options = combined_options(getThis(), request TSRMLS_CC);
     705           5 :         q.dtor = msg_queue_dtor;
     706           5 :         q.opaque = msg_obj;
     707           5 :         q.closure.fci = fci;
     708           5 :         q.closure.fcc = fcc;
     709             : 
     710           5 :         if (fci.size) {
     711           2 :                 Z_ADDREF_P(fci.function_name);
     712           2 :                 if (fci.object_ptr) {
     713           0 :                         Z_ADDREF_P(fci.object_ptr);
     714             :                 }
     715             :         }
     716             : 
     717           5 :         zend_objects_store_add_ref_by_handle(msg_obj->zv.handle TSRMLS_CC);
     718             : 
     719           5 :         php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime,
     720             :                         msg_queue_dtor(&q);
     721             :                         return;
     722             :         );
     723             : 
     724           5 :         RETVAL_ZVAL(getThis(), 1, 0);
     725             : }
     726             : 
     727             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_count, 0, 0, 0)
     728             : ZEND_END_ARG_INFO();
     729          12 : static PHP_METHOD(HttpClient, count)
     730             : {
     731          12 :         long count_mode = -1;
     732             : 
     733          12 :         if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &count_mode)) {
     734          12 :                 php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     735             : 
     736          12 :                 RETVAL_LONG(zend_llist_count(&obj->client->requests));
     737             :         }
     738          12 : }
     739             : 
     740             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getResponse, 0, 0, 0)
     741             :         ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 1)
     742             : ZEND_END_ARG_INFO();
     743          17 : static PHP_METHOD(HttpClient, getResponse)
     744             : {
     745          17 :         zval *zrequest = NULL;
     746             :         php_http_client_object_t *obj;
     747             : 
     748          17 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O", &zrequest, php_http_client_request_class_entry), invalid_arg, return);
     749             : 
     750          17 :         obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     751             : 
     752          17 :         if (zrequest) {
     753             :                 /* lookup the response with the request */
     754           1 :                 zend_llist_element *el = NULL;
     755           1 :                 php_http_message_object_t *req_obj = zend_object_store_get_object(zrequest TSRMLS_CC);
     756             : 
     757           1 :                 for (el = obj->client->responses.head; el; el = el->next) {
     758           1 :                         php_http_message_object_t *response_obj = *(php_http_message_object_t **) el->data;
     759             : 
     760           1 :                         if (response_obj->message->parent == req_obj->message) {
     761           1 :                                 RETURN_OBJVAL(response_obj->zv, 1);
     762             :                         }
     763             :                 }
     764             : 
     765             :                 /* not found for the request! */
     766           0 :                 php_http_throw(unexpected_val, "Could not find response for the request", NULL);
     767           0 :                 return;
     768             :         }
     769             : 
     770             :         /* pop off the last response */
     771          16 :         if (obj->client->responses.tail) {
     772          13 :                 php_http_message_object_t *response_obj = *(php_http_message_object_t **) obj->client->responses.tail->data;
     773             : 
     774             :                 /* pop off and go */
     775          13 :                 if (response_obj) {
     776          13 :                         RETVAL_OBJVAL(response_obj->zv, 1);
     777          13 :                         zend_llist_remove_tail(&obj->client->responses);
     778             :                 }
     779             :         }
     780             : }
     781             : 
     782             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getHistory, 0, 0, 0)
     783             : ZEND_END_ARG_INFO();
     784           2 : static PHP_METHOD(HttpClient, getHistory)
     785             : {
     786             :         zval *zhistory;
     787             : 
     788           4 :         php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
     789             : 
     790           2 :         zhistory = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("history"), 0 TSRMLS_CC);
     791           2 :         RETVAL_ZVAL(zhistory, 1, 0);
     792             : }
     793             : 
     794             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_send, 0, 0, 0)
     795             : ZEND_END_ARG_INFO();
     796          20 : static PHP_METHOD(HttpClient, send)
     797             : {
     798             :         php_http_client_object_t *obj;
     799             : 
     800          20 :         php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
     801             : 
     802          20 :         obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     803             : 
     804          20 :         php_http_expect(SUCCESS == php_http_client_exec(obj->client), runtime, return);
     805             : 
     806          20 :         RETVAL_ZVAL(getThis(), 1, 0);
     807             : }
     808             : 
     809             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_once, 0, 0, 0)
     810             : ZEND_END_ARG_INFO();
     811          39 : static PHP_METHOD(HttpClient, once)
     812             : {
     813          39 :         if (SUCCESS == zend_parse_parameters_none()) {
     814          39 :                 php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     815             : 
     816          39 :                 RETURN_BOOL(0 < php_http_client_once(obj->client));
     817             :         }
     818             : }
     819             : 
     820             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_wait, 0, 0, 0)
     821             :         ZEND_ARG_INFO(0, timeout)
     822             : ZEND_END_ARG_INFO();
     823          37 : static PHP_METHOD(HttpClient, wait)
     824             : {
     825          37 :         double timeout = 0;
     826             : 
     827          37 :         if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|d", &timeout)) {
     828             :                 struct timeval timeout_val;
     829          37 :                 php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     830             : 
     831          37 :                 timeout_val.tv_sec = (time_t) timeout;
     832          37 :                 timeout_val.tv_usec = PHP_HTTP_USEC(timeout) % PHP_HTTP_MCROSEC;
     833             : 
     834          37 :                 RETURN_BOOL(SUCCESS == php_http_client_wait(obj->client, timeout > 0 ? &timeout_val : NULL));
     835             :         }
     836             : }
     837             : 
     838             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enablePipelining, 0, 0, 0)
     839             :         ZEND_ARG_INFO(0, enable)
     840             : ZEND_END_ARG_INFO();
     841           1 : static PHP_METHOD(HttpClient, enablePipelining)
     842             : {
     843           1 :         zend_bool enable = 1;
     844             :         php_http_client_object_t *obj;
     845             : 
     846           1 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable), invalid_arg, return);
     847             : 
     848           1 :         obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     849             : 
     850           1 :         php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING, &enable), unexpected_val, return);
     851             : 
     852           1 :         RETVAL_ZVAL(getThis(), 1, 0);
     853             : }
     854             : 
     855             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enableEvents, 0, 0, 0)
     856             :         ZEND_ARG_INFO(0, enable)
     857             : ZEND_END_ARG_INFO();
     858           6 : static PHP_METHOD(HttpClient, enableEvents)
     859             : {
     860           6 :         zend_bool enable = 1;
     861             :         php_http_client_object_t *obj;
     862             : 
     863           6 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable), invalid_arg, return);
     864             : 
     865           6 :         obj = zend_object_store_get_object(getThis() TSRMLS_CC);
     866             : 
     867           6 :         php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_USE_EVENTS, &enable), unexpected_val, return);
     868             : 
     869           6 :         RETVAL_ZVAL(getThis(), 1, 0);
     870             : }
     871             : 
     872          32 : static int notify(zend_object_iterator *iter, void *puser TSRMLS_DC)
     873             : {
     874          32 :         zval **observer = NULL, ***args = puser;
     875             : 
     876          32 :         iter->funcs->get_current_data(iter, &observer TSRMLS_CC);
     877          32 :         if (observer) {
     878          32 :                 return php_http_method_call(*observer, ZEND_STRL("update"), args[2]?3:args[1]?2:args[0]?1:0, args, NULL TSRMLS_CC);
     879             :         }
     880           0 :         return FAILURE;
     881             : }
     882             : 
     883             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_notify, 0, 0, 0)
     884             :         ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 1)
     885             : ZEND_END_ARG_INFO();
     886         309 : static PHP_METHOD(HttpClient, notify)
     887             : {
     888         309 :         zval *request = NULL, *zprogress = NULL, *observers, **args[3];
     889             : 
     890         309 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O!o!", &request, php_http_client_request_class_entry, &zprogress), invalid_arg, return);
     891             : 
     892         309 :         observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC);
     893             : 
     894         309 :         if (Z_TYPE_P(observers) != IS_OBJECT) {
     895           0 :                 php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
     896           0 :                 return;
     897             :         }
     898             : 
     899         309 :         Z_ADDREF_P(getThis());
     900         309 :         args[0] = &getThis();
     901         309 :         if (request) {
     902         309 :                 Z_ADDREF_P(request);
     903             :         }
     904         309 :         args[1] = &request;
     905         309 :         if (zprogress) {
     906         309 :                 Z_ADDREF_P(zprogress);
     907             :         }
     908         309 :         args[2] = &zprogress;
     909         309 :         spl_iterator_apply(observers, notify, args TSRMLS_CC);
     910         309 :         zval_ptr_dtor(&getThis());
     911         309 :         if (request) {
     912         309 :                 zval_ptr_dtor(&request);
     913             :         }
     914         309 :         if (zprogress) {
     915         309 :                 zval_ptr_dtor(&zprogress);
     916             :         }
     917             : 
     918         309 :         RETVAL_ZVAL(getThis(), 1, 0);
     919             : }
     920             : 
     921             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_attach, 0, 0, 1)
     922             :         ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0)
     923             : ZEND_END_ARG_INFO();
     924           4 : static PHP_METHOD(HttpClient, attach)
     925             : {
     926           4 :         zval *observers, *observer, *retval = NULL;
     927             : 
     928           4 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver), invalid_arg, return);
     929             : 
     930           4 :         observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC);
     931             : 
     932           4 :         if (Z_TYPE_P(observers) != IS_OBJECT) {
     933           0 :                 php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
     934           0 :                 return;
     935             :         }
     936             : 
     937           4 :         zend_call_method_with_1_params(&observers, NULL, NULL, "attach", &retval, observer);
     938           4 :         if (retval) {
     939           4 :                 zval_ptr_dtor(&retval);
     940             :         }
     941             : 
     942           4 :         RETVAL_ZVAL(getThis(), 1, 0);
     943             : }
     944             : 
     945             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_detach, 0, 0, 1)
     946             :         ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0)
     947             : ZEND_END_ARG_INFO();
     948           3 : static PHP_METHOD(HttpClient, detach)
     949             : {
     950           3 :         zval *observers, *observer, *retval = NULL;
     951             : 
     952           3 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver), invalid_arg, return);
     953             : 
     954           3 :         observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC);
     955             : 
     956           3 :         if (Z_TYPE_P(observers) != IS_OBJECT) {
     957           0 :                 php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
     958           0 :                 return;
     959             :         }
     960             : 
     961           3 :         zend_call_method_with_1_params(&observers, NULL, NULL, "detach", &retval, observer);
     962           3 :         if (retval) {
     963           3 :                 zval_ptr_dtor(&retval);
     964             :         }
     965             : 
     966           3 :         RETVAL_ZVAL(getThis(), 1, 0);
     967             : }
     968             : 
     969             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getObservers, 0, 0, 0)
     970             : ZEND_END_ARG_INFO();
     971           4 : static PHP_METHOD(HttpClient, getObservers)
     972             : {
     973             :         zval *observers;
     974             : 
     975           4 :         php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
     976             : 
     977           4 :         observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC);
     978             : 
     979           4 :         if (Z_TYPE_P(observers) != IS_OBJECT) {
     980           0 :                 php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
     981           0 :                 return;
     982             :         }
     983             : 
     984           4 :         RETVAL_ZVAL(observers, 1, 0);
     985             : }
     986             : 
     987             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getProgressInfo, 0, 0, 1)
     988             :         ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
     989             : ZEND_END_ARG_INFO();
     990          32 : static PHP_METHOD(HttpClient, getProgressInfo)
     991             : {
     992             :         zval *request;
     993             :         php_http_client_object_t *obj;
     994             :         php_http_message_object_t *req_obj;
     995             :         php_http_client_progress_state_t *progress;
     996             : 
     997          32 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_request_class_entry), invalid_arg, return);
     998             : 
     999          32 :         obj = zend_object_store_get_object(getThis() TSRMLS_CC);
    1000          32 :         req_obj = zend_object_store_get_object(request TSRMLS_CC);
    1001             : 
    1002          32 :         php_http_expect(SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, req_obj->message, &progress), unexpected_val, return);
    1003             : 
    1004          32 :         object_init(return_value);
    1005          32 :         add_property_bool(return_value, "started", progress->started);
    1006          32 :         add_property_bool(return_value, "finished", progress->finished);
    1007          32 :         add_property_string(return_value, "info", STR_PTR(progress->info), 1);
    1008          32 :         add_property_double(return_value, "dltotal", progress->dl.total);
    1009          32 :         add_property_double(return_value, "dlnow", progress->dl.now);
    1010          32 :         add_property_double(return_value, "ultotal", progress->ul.total);
    1011          32 :         add_property_double(return_value, "ulnow", progress->ul.now);
    1012             : }
    1013             : 
    1014             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getTransferInfo, 0, 0, 1)
    1015             :         ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
    1016             : ZEND_END_ARG_INFO();
    1017           1 : static PHP_METHOD(HttpClient, getTransferInfo)
    1018             : {
    1019             :         zval *request;
    1020             :         HashTable *info;
    1021             :         php_http_client_object_t *obj;
    1022             :         php_http_message_object_t *req_obj;
    1023             : 
    1024           1 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_request_class_entry), invalid_arg, return);
    1025             : 
    1026           1 :         obj = zend_object_store_get_object(getThis() TSRMLS_CC);
    1027           1 :         req_obj = zend_object_store_get_object(request TSRMLS_CC);
    1028             : 
    1029           1 :         object_init(return_value);
    1030           1 :         info = HASH_OF(return_value);
    1031           1 :         php_http_expect(SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, req_obj->message, &info), unexpected_val, return);
    1032             : }
    1033             : 
    1034             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setOptions, 0, 0, 0)
    1035             :         ZEND_ARG_ARRAY_INFO(0, options, 1)
    1036             : ZEND_END_ARG_INFO();
    1037           0 : static PHP_METHOD(HttpClient, setOptions)
    1038             : {
    1039           0 :         zval *opts = NULL;
    1040             : 
    1041           0 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return);
    1042             : 
    1043           0 :         php_http_client_options_set(getThis(), opts TSRMLS_CC);
    1044             : 
    1045           0 :         RETVAL_ZVAL(getThis(), 1, 0);
    1046             : }
    1047             : 
    1048             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getOptions, 0, 0, 0)
    1049             : ZEND_END_ARG_INFO();
    1050           0 : static PHP_METHOD(HttpClient, getOptions)
    1051             : {
    1052           0 :         if (SUCCESS == zend_parse_parameters_none()) {
    1053           0 :                 zval *options = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
    1054           0 :                 RETVAL_ZVAL(options, 1, 0);
    1055             :         }
    1056           0 : }
    1057             : 
    1058             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setSslOptions, 0, 0, 0)
    1059             :         ZEND_ARG_ARRAY_INFO(0, ssl_option, 1)
    1060             : ZEND_END_ARG_INFO();
    1061           1 : static PHP_METHOD(HttpClient, setSslOptions)
    1062             : {
    1063           1 :         zval *opts = NULL;
    1064             : 
    1065           2 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return);
    1066             : 
    1067           1 :         php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 1 TSRMLS_CC);
    1068             : 
    1069           1 :         RETVAL_ZVAL(getThis(), 1, 0);
    1070             : }
    1071             : 
    1072             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addSslOptions, 0, 0, 0)
    1073             :         ZEND_ARG_ARRAY_INFO(0, ssl_options, 1)
    1074             : ZEND_END_ARG_INFO();
    1075           1 : static PHP_METHOD(HttpClient, addSslOptions)
    1076             : {
    1077           1 :         zval *opts = NULL;
    1078             : 
    1079           2 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return);
    1080             : 
    1081           1 :         php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 0 TSRMLS_CC);
    1082             : 
    1083           1 :         RETVAL_ZVAL(getThis(), 1, 0);
    1084             : }
    1085             : 
    1086             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getSslOptions, 0, 0, 0)
    1087             : ZEND_END_ARG_INFO();
    1088           1 : static PHP_METHOD(HttpClient, getSslOptions)
    1089             : {
    1090           1 :         if (SUCCESS == zend_parse_parameters_none()) {
    1091           1 :                 php_http_client_options_get_subr(getThis(), ZEND_STRS("ssl"), return_value TSRMLS_CC);
    1092             :         }
    1093           1 : }
    1094             : 
    1095             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setCookies, 0, 0, 0)
    1096             :         ZEND_ARG_ARRAY_INFO(0, cookies, 1)
    1097             : ZEND_END_ARG_INFO();
    1098           1 : static PHP_METHOD(HttpClient, setCookies)
    1099             : {
    1100           1 :         zval *opts = NULL;
    1101             : 
    1102           2 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return);
    1103             : 
    1104           1 :         php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts, 1 TSRMLS_CC);
    1105             : 
    1106           1 :         RETVAL_ZVAL(getThis(), 1, 0);
    1107             : }
    1108             : 
    1109             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addCookies, 0, 0, 0)
    1110             :         ZEND_ARG_ARRAY_INFO(0, cookies, 1)
    1111             : ZEND_END_ARG_INFO();
    1112           1 : static PHP_METHOD(HttpClient, addCookies)
    1113             : {
    1114           1 :         zval *opts = NULL;
    1115             : 
    1116           2 :         php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return);
    1117             : 
    1118           1 :         php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts, 0 TSRMLS_CC);
    1119             : 
    1120           1 :         RETVAL_ZVAL(getThis(), 1, 0);
    1121             : }
    1122             : 
    1123             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getCookies, 0, 0, 0)
    1124             : ZEND_END_ARG_INFO();
    1125           1 : static PHP_METHOD(HttpClient, getCookies)
    1126             : {
    1127           1 :         if (SUCCESS == zend_parse_parameters_none()) {
    1128           1 :                 php_http_client_options_get_subr(getThis(), ZEND_STRS("cookies"), return_value TSRMLS_CC);
    1129             :         }
    1130           1 : }
    1131             : 
    1132             : ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableDrivers, 0, 0, 0)
    1133             : ZEND_END_ARG_INFO();
    1134          14 : static PHP_METHOD(HttpClient, getAvailableDrivers) {
    1135          14 :         if (SUCCESS == zend_parse_parameters_none()) {
    1136          14 :                 array_init(return_value);
    1137          14 :                 php_http_client_driver_list(Z_ARRVAL_P(return_value) TSRMLS_CC);
    1138             :         }
    1139          14 : }
    1140             : 
    1141             : static zend_function_entry php_http_client_methods[] = {
    1142             :         PHP_ME(HttpClient, __construct,          ai_HttpClient_construct,            ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
    1143             :         PHP_ME(HttpClient, reset,                ai_HttpClient_reset,                ZEND_ACC_PUBLIC)
    1144             :         PHP_ME(HttpClient, enqueue,              ai_HttpClient_enqueue,              ZEND_ACC_PUBLIC)
    1145             :         PHP_ME(HttpClient, dequeue,              ai_HttpClient_dequeue,              ZEND_ACC_PUBLIC)
    1146             :         PHP_ME(HttpClient, requeue,              ai_HttpClient_requeue,              ZEND_ACC_PUBLIC)
    1147             :         PHP_ME(HttpClient, count,                ai_HttpClient_count,                ZEND_ACC_PUBLIC)
    1148             :         PHP_ME(HttpClient, send,                 ai_HttpClient_send,                 ZEND_ACC_PUBLIC)
    1149             :         PHP_ME(HttpClient, once,                 ai_HttpClient_once,                 ZEND_ACC_PUBLIC)
    1150             :         PHP_ME(HttpClient, wait,                 ai_HttpClient_wait,                 ZEND_ACC_PUBLIC)
    1151             :         PHP_ME(HttpClient, getResponse,          ai_HttpClient_getResponse,          ZEND_ACC_PUBLIC)
    1152             :         PHP_ME(HttpClient, getHistory,           ai_HttpClient_getHistory,           ZEND_ACC_PUBLIC)
    1153             :         PHP_ME(HttpClient, enablePipelining,     ai_HttpClient_enablePipelining,     ZEND_ACC_PUBLIC)
    1154             :         PHP_ME(HttpClient, enableEvents,         ai_HttpClient_enableEvents,         ZEND_ACC_PUBLIC)
    1155             :         PHP_ME(HttpClient, notify,               ai_HttpClient_notify,               ZEND_ACC_PUBLIC)
    1156             :         PHP_ME(HttpClient, attach,               ai_HttpClient_attach,               ZEND_ACC_PUBLIC)
    1157             :         PHP_ME(HttpClient, detach,               ai_HttpClient_detach,               ZEND_ACC_PUBLIC)
    1158             :         PHP_ME(HttpClient, getObservers,         ai_HttpClient_getObservers,         ZEND_ACC_PUBLIC)
    1159             :         PHP_ME(HttpClient, getProgressInfo,      ai_HttpClient_getProgressInfo,      ZEND_ACC_PUBLIC)
    1160             :         PHP_ME(HttpClient, getTransferInfo,      ai_HttpClient_getTransferInfo,      ZEND_ACC_PUBLIC)
    1161             :         PHP_ME(HttpClient, setOptions,           ai_HttpClient_setOptions,           ZEND_ACC_PUBLIC)
    1162             :         PHP_ME(HttpClient, getOptions,           ai_HttpClient_getOptions,           ZEND_ACC_PUBLIC)
    1163             :         PHP_ME(HttpClient, setSslOptions,        ai_HttpClient_setSslOptions,        ZEND_ACC_PUBLIC)
    1164             :         PHP_ME(HttpClient, addSslOptions,        ai_HttpClient_addSslOptions,        ZEND_ACC_PUBLIC)
    1165             :         PHP_ME(HttpClient, getSslOptions,        ai_HttpClient_getSslOptions,        ZEND_ACC_PUBLIC)
    1166             :         PHP_ME(HttpClient, setCookies,           ai_HttpClient_setCookies,           ZEND_ACC_PUBLIC)
    1167             :         PHP_ME(HttpClient, addCookies,           ai_HttpClient_addCookies,           ZEND_ACC_PUBLIC)
    1168             :         PHP_ME(HttpClient, getCookies,           ai_HttpClient_getCookies,           ZEND_ACC_PUBLIC)
    1169             :         PHP_ME(HttpClient, getAvailableDrivers,  ai_HttpClient_getAvailableDrivers,  ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
    1170             :         EMPTY_FUNCTION_ENTRY
    1171             : };
    1172             : 
    1173         408 : PHP_MINIT_FUNCTION(http_client)
    1174             : {
    1175         408 :         zend_class_entry ce = {0};
    1176             : 
    1177         408 :         INIT_NS_CLASS_ENTRY(ce, "http", "Client", php_http_client_methods);
    1178         408 :         php_http_client_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
    1179         408 :         php_http_client_class_entry->create_object = php_http_client_object_new;
    1180         408 :         zend_class_implements(php_http_client_class_entry TSRMLS_CC, 2, spl_ce_SplSubject, spl_ce_Countable);
    1181         408 :         memcpy(&php_http_client_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    1182         408 :         php_http_client_object_handlers.clone_obj = NULL;
    1183         408 :         zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("observers"), ZEND_ACC_PRIVATE TSRMLS_CC);
    1184         408 :         zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("options"), ZEND_ACC_PROTECTED TSRMLS_CC);
    1185         408 :         zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("history"), ZEND_ACC_PROTECTED TSRMLS_CC);
    1186         408 :         zend_declare_property_bool(php_http_client_class_entry, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
    1187             : 
    1188         408 :         zend_hash_init(&php_http_client_drivers, 2, NULL, NULL, 1);
    1189             : 
    1190         408 :         return SUCCESS;
    1191             : }
    1192             : 
    1193         408 : PHP_MSHUTDOWN_FUNCTION(http_client)
    1194             : {
    1195         408 :         zend_hash_destroy(&php_http_client_drivers);
    1196         408 :         return SUCCESS;
    1197             : }
    1198             : 
    1199             : /*
    1200             :  * Local variables:
    1201             :  * tab-width: 4
    1202             :  * c-basic-offset: 4
    1203             :  * End:
    1204             :  * vim600: noet sw=4 ts=4 fdm=marker
    1205             :  * vim<600: noet sw=4 ts=4
    1206             :  */

Generated by: LCOV version 1.11