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

Generated by: LCOV version 1.11