Merge branch 'v2.6.x'
authorMichael Wallner <mike@php.net>
Wed, 7 Sep 2016 06:01:09 +0000 (08:01 +0200)
committerMichael Wallner <mike@php.net>
Wed, 7 Sep 2016 06:02:46 +0000 (08:02 +0200)
1  2 
package.xml
scripts/gen_travis_yml.php
src/php_http_client.c
src/php_http_client_curl_user.c
tests/client028.phpt
tests/client029.phpt
tests/gh-issue47.phpt
tests/gh-issue50.phpt

diff --combined package.xml
index e104c7ebfc599fbd073a995a959a13849331cc85,0e2206660d33b672e59773cc1f375b5293d7956d..f8d65e0aaf08718262b9baf0bcdd4aea31027c5a
@@@ -31,10 -31,10 +31,10 @@@ https://mdref.m6w6.name/htt
    <email>mike@php.net</email>
    <active>yes</active>
   </lead>
-  <date>2016-08-22</date>
+  <date>2016-09-07</date>
   <version>
 -  <release>2.6.0beta2</release>
 -  <api>2.6.0</api>
 +  <release>3.1.0beta2</release>
 +  <api>3.1.0</api>
   </version>
   <stability>
    <release>beta</release>
  * Fix gh-issue #36: Unexpected cookies sent if persistent_handle_id is used (Mike, @rcanavan, @afflerbach)
  * Fix gh-issue #34: allow setting multiple headers with the same name (Mike, @rcanavan)
  * Fix gh-issue #33: allow setting prodyhost request option to NULL (Mike, @rcanavan)
 -* Fix gh-issue #31: add/improve configure checks for default CA bundle/path (Mike, @rcanavan) 
 +* Fix gh-issue #31: add/improve configure checks for default CA bundle/path (Mike, @rcanavan)
+ Changes from beta1:
 -* Fixed PHP-5.3 compatibility
+ * Fixed recursive calls to the event loop dispatcher
  ]]></notes>
   <contents>
    <dir name="/">
       <file role="test" name="filterchunked.phpt"/>
       <file role="test" name="filterzlib.phpt"/>
       <file role="test" name="gh-issue6.phpt"/>
+      <file role="test" name="gh-issue7.phpt"/>
       <file role="test" name="gh-issue12.phpt"/>
       <file role="test" name="gh-issue42.phpt"/>
       <file role="test" name="gh-issue47.phpt"/>
   <dependencies>
    <required>
     <php>
 -    <min>5.3.0</min>
 -    <max>7.0.0</max>
 -    <exclude>7.0.0</exclude>
 +    <min>7.0.0</min>
     </php>
     <pearinstaller>
      <min>1.4.1</min>
     <package>
      <name>raphf</name>
      <channel>pecl.php.net</channel>
 -    <min>1.1.0</min>
 -    <max>2.0.0dev</max>
 -    <exclude>2.0.0dev</exclude>
 +    <min>2.0.0dev</min>
      <providesextension>raphf</providesextension>
     </package>
     <package>
      <name>propro</name>
      <channel>pecl.php.net</channel>
 -    <min>1.0.0</min>
 -    <max>2.0.0dev</max>
 -    <exclude>2.0.0dev</exclude>
 +    <min>2.0.0dev</min>
      <providesextension>propro</providesextension>
     </package>
    </required>
index f83d0b4c3f9e62e36135e46fecd54dcaef761562,0bbda368adc8244a47742d3c123cf63f0da33175..311a4cd000afa5edccef34ab7e1bdcf7349e6bdb
@@@ -17,14 -17,12 +17,12 @@@ env
  
  $gen = include "./travis/pecl/gen-matrix.php";
  $env = $gen([
 -      "PHP" => ["5.3", "5.4", "5.5", "5.6"],
 +      "PHP" => ["7.0", "master"],
        "enable_debug",
        "enable_maintainer_zts",
        "enable_json",
        "enable_hash" => ["yes"],
 -      "enable_iconv" => ["yes"]
 +      "enable_iconv" => ["yes"],
-       "enable_phar" => ["yes"],
-       "enable_posix" => ["yes"]
  ]);
  foreach ($env as $e) {
        printf(" - %s\n", $e);
@@@ -34,8 -32,8 +32,8 @@@
  
  before_script:
   - make -f travis/pecl/Makefile php
 - - make -f travis/pecl/Makefile pecl PECL=raphf:raphf:1.1.1
 - - make -f travis/pecl/Makefile pecl PECL=propro:propro:1.0.2
 + - make -f travis/pecl/Makefile pecl PECL=raphf:raphf:2.0.0
 + - make -f travis/pecl/Makefile pecl PECL=propro:propro:2.0.1
   - make -f travis/pecl/Makefile ext PECL=http
  
  script:
diff --combined src/php_http_client.c
index d0e6e80107c28dc65de29971d3d348a2689fba86,453e43c6ade56c18f5177abdf1698050b9116242..4118ab18263fd7156a7852ba3860c610bc95dac0
   */
  static HashTable php_http_client_drivers;
  
 +static void php_http_client_driver_hash_dtor(zval *pData)
 +{
 +      pefree(Z_PTR_P(pData), 1);
 +}
 +
  ZEND_RESULT_CODE php_http_client_driver_add(php_http_client_driver_t *driver)
  {
 -      return zend_hash_add(&php_http_client_drivers, driver->name_str, driver->name_len + 1, (void *) driver, sizeof(php_http_client_driver_t), NULL);
 +      return zend_hash_add_mem(&php_http_client_drivers, driver->driver_name, (void *) driver, sizeof(php_http_client_driver_t))
 +                      ? SUCCESS : FAILURE;
  }
  
 -ZEND_RESULT_CODE php_http_client_driver_get(const char *name_str, size_t name_len, php_http_client_driver_t *driver)
 +php_http_client_driver_t *php_http_client_driver_get(zend_string *name)
  {
 +      zval *ztmp;
        php_http_client_driver_t *tmp;
  
 -      if ((name_str && SUCCESS == zend_hash_find(&php_http_client_drivers, name_str, name_len + 1, (void *) &tmp))
 -      ||      (SUCCESS == zend_hash_get_current_data(&php_http_client_drivers, (void *) &tmp))) {
 -              *driver = *tmp;
 -              return SUCCESS;
 +      if (name && (tmp = zend_hash_find_ptr(&php_http_client_drivers, name))) {
 +              return tmp;
        }
 -      return FAILURE;
 +      if ((ztmp = zend_hash_get_current_data(&php_http_client_drivers))) {
 +              return Z_PTR_P(ztmp);
 +      }
 +      return NULL;
  }
  
 -static int apply_driver_list(void *p, void *arg TSRMLS_DC)
 +static int apply_driver_list(zval *p, void *arg)
  {
 -      php_http_client_driver_t *d = p;
 -      zval *zname;
 +      php_http_client_driver_t *d = Z_PTR_P(p);
 +      zval zname;
  
 -      MAKE_STD_ZVAL(zname);
 -      ZVAL_STRINGL(zname, d->name_str, d->name_len, 1);
 +      ZVAL_STR_COPY(&zname, d->driver_name);
  
 -      zend_hash_next_index_insert(arg, &zname, sizeof(zval *), NULL);
 +      zend_hash_next_index_insert(arg, &zname);
        return ZEND_HASH_APPLY_KEEP;
  }
  
 -void php_http_client_driver_list(HashTable *ht TSRMLS_DC)
 +void php_http_client_driver_list(HashTable *ht)
  {
 -      zend_hash_apply_with_argument(&php_http_client_drivers, apply_driver_list, ht TSRMLS_CC);
 +      zend_hash_apply_with_argument(&php_http_client_drivers, apply_driver_list, ht);
  }
  
 -void php_http_client_options_set_subr(zval *this_ptr, char *key, size_t len, zval *opts, int overwrite TSRMLS_DC)
 +static zend_class_entry *php_http_client_class_entry;
 +zend_class_entry *php_http_client_get_class_entry(void)
 +{
 +      return php_http_client_class_entry;
 +}
 +
 +void php_http_client_options_set_subr(zval *instance, char *key, size_t len, zval *opts, int overwrite)
  {
        if (overwrite || (opts && zend_hash_num_elements(Z_ARRVAL_P(opts)))) {
 -              zend_class_entry *this_ce = Z_OBJCE_P(getThis());
 -              zval *old_opts, *new_opts, **entry = NULL;
 +              zend_class_entry *this_ce = Z_OBJCE_P(instance);
 +              zval old_opts_tmp, *old_opts, new_opts, *entry = NULL;
  
 -              MAKE_STD_ZVAL(new_opts);
 -              array_init(new_opts);
 -              old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
 +              array_init(&new_opts);
 +              old_opts = zend_read_property(this_ce, instance, ZEND_STRL("options"), 0, &old_opts_tmp);
                if (Z_TYPE_P(old_opts) == IS_ARRAY) {
 -                      array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts));
 +                      array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL(new_opts));
                }
  
                if (overwrite) {
                        if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) {
                                Z_ADDREF_P(opts);
 -                              zend_symtable_update(Z_ARRVAL_P(new_opts), key, len, (void *) &opts, sizeof(zval *), NULL);
 +                              zend_symtable_str_update(Z_ARRVAL(new_opts), key, len, opts);
                        } else {
 -                              zend_symtable_del(Z_ARRVAL_P(new_opts), key, len);
 +                              zend_symtable_str_del(Z_ARRVAL(new_opts), key, len);
                        }
                } else if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) {
 -                      if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(new_opts), key, len, (void *) &entry)) {
 -                              array_join(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry), 0, 0);
 +                      if ((entry = zend_symtable_str_find(Z_ARRVAL(new_opts), key, len))) {
 +                              array_join(Z_ARRVAL_P(opts), Z_ARRVAL_P(entry), 0, 0);
                        } else {
                                Z_ADDREF_P(opts);
 -                              zend_symtable_update(Z_ARRVAL_P(new_opts), key, len, (void *) &opts, sizeof(zval *), NULL);
 +                              zend_symtable_str_update(Z_ARRVAL(new_opts), key, len, opts);
                        }
                }
  
 -              zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC);
 +              zend_update_property(this_ce, instance, ZEND_STRL("options"), &new_opts);
                zval_ptr_dtor(&new_opts);
        }
  }
  
 -void php_http_client_options_set(zval *this_ptr, zval *opts TSRMLS_DC)
 +void php_http_client_options_set(zval *instance, zval *opts)
  {
 -      php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
 -      HashPosition pos;
 -      zval *new_opts;
 -      zend_class_entry *this_ce = Z_OBJCE_P(getThis());
 -      zend_bool is_client = instanceof_function(this_ce, php_http_client_class_entry TSRMLS_CC);
 +      php_http_arrkey_t key;
 +      zval new_opts;
 +      zend_class_entry *this_ce = Z_OBJCE_P(instance);
 +      zend_bool is_client = instanceof_function(this_ce, php_http_client_class_entry);
  
 -      MAKE_STD_ZVAL(new_opts);
 -      array_init(new_opts);
 +      array_init(&new_opts);
  
        if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) {
 -              zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC);
 +              zend_update_property(this_ce, instance, ZEND_STRL("options"), &new_opts);
                zval_ptr_dtor(&new_opts);
        } else {
 -              zval *old_opts, *add_opts, **opt;
 +              zval old_opts_tmp, *old_opts, add_opts, *opt;
  
 -              MAKE_STD_ZVAL(add_opts);
 -              array_init(add_opts);
 +              array_init(&add_opts);
                /* some options need extra attention -- thus cannot use array_merge() directly */
 -              FOREACH_KEYVAL(pos, opts, key, opt) {
 -                      if (key.type == HASH_KEY_IS_STRING) {
 -#define KEYMATCH(k, s) ((sizeof(s)==k.len) && !strcasecmp(k.str, s))
 -                              if (Z_TYPE_PP(opt) == IS_ARRAY && (KEYMATCH(key, "ssl") || KEYMATCH(key, "cookies"))) {
 -                                      php_http_client_options_set_subr(getThis(), key.str, key.len, *opt, 0 TSRMLS_CC);
 -                              } else if (is_client && (KEYMATCH(key, "recordHistory") || KEYMATCH(key, "responseMessageClass"))) {
 -                                      zend_update_property(this_ce, getThis(), key.str, key.len-1, *opt TSRMLS_CC);
 -                              } else if (Z_TYPE_PP(opt) == IS_NULL) {
 -                                      old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
 +              ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(opts), key.h, key.key, opt)
 +              {
 +                      if (key.key) {
 +                              if (Z_TYPE_P(opt) == IS_ARRAY && (zend_string_equals_literal(key.key, "ssl") || zend_string_equals_literal(key.key, "cookies"))) {
 +                                      php_http_client_options_set_subr(instance, key.key->val, key.key->len, opt, 0);
 +                              } else if (is_client && (zend_string_equals_literal(key.key, "recordHistory") || zend_string_equals_literal(key.key, "responseMessageClass"))) {
 +                                      zend_update_property(this_ce, instance, key.key->val, key.key->len, opt);
 +                              } else if (Z_TYPE_P(opt) == IS_NULL) {
 +                                      old_opts = zend_read_property(this_ce, instance, ZEND_STRL("options"), 0, &old_opts_tmp);
                                        if (Z_TYPE_P(old_opts) == IS_ARRAY) {
 -                                              zend_symtable_del(Z_ARRVAL_P(old_opts), key.str, key.len);
 +                                              zend_symtable_del(Z_ARRVAL_P(old_opts), key.key);
                                        }
                                } else {
 -                                      Z_ADDREF_P(*opt);
 -                                      add_assoc_zval_ex(add_opts, key.str, key.len, *opt);
 +                                      Z_TRY_ADDREF_P(opt);
 +                                      add_assoc_zval_ex(&add_opts, key.key->val, key.key->len, opt);
                                }
                        }
                }
 +              ZEND_HASH_FOREACH_END();
  
 -              old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
 +              old_opts = zend_read_property(this_ce, instance, ZEND_STRL("options"), 0, &old_opts_tmp);
                if (Z_TYPE_P(old_opts) == IS_ARRAY) {
 -                      array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts));
 +                      array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL(new_opts));
                }
 -              array_join(Z_ARRVAL_P(add_opts), Z_ARRVAL_P(new_opts), 0, 0);
 -              zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC);
 +              array_join(Z_ARRVAL(add_opts), Z_ARRVAL(new_opts), 0, 0);
 +              zend_update_property(this_ce, instance, ZEND_STRL("options"), &new_opts);
                zval_ptr_dtor(&new_opts);
                zval_ptr_dtor(&add_opts);
        }
  }
  
 -void php_http_client_options_get_subr(zval *this_ptr, char *key, size_t len, zval *return_value TSRMLS_DC)
 +void php_http_client_options_get_subr(zval *instance, char *key, size_t len, zval *return_value)
  {
 -      zend_class_entry *this_ce = Z_OBJCE_P(getThis());
 -      zval **options, *opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
 +      zend_class_entry *this_ce = Z_OBJCE_P(instance);
 +      zval *options, opts_tmp, *opts = zend_read_property(this_ce, instance, ZEND_STRL("options"), 0, &opts_tmp);
  
 -      if ((Z_TYPE_P(opts) == IS_ARRAY) && (SUCCESS == zend_symtable_find(Z_ARRVAL_P(opts), key, len, (void *) &options))) {
 -              RETVAL_ZVAL(*options, 1, 0);
 +      if ((Z_TYPE_P(opts) == IS_ARRAY) && (options = zend_symtable_str_find(Z_ARRVAL_P(opts), key, len))) {
 +              RETVAL_ZVAL(options, 1, 0);
        }
  }
  
@@@ -167,7 -157,7 +167,7 @@@ static void queue_dtor(void *enqueued
        }
  }
  
 -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)
 +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)
  {
        php_http_client_t *free_h = NULL;
  
        }
        zend_llist_init(&h->requests, sizeof(php_http_client_enqueue_t), queue_dtor, 0);
        zend_llist_init(&h->responses, sizeof(void *), NULL, 0);
 -      TSRMLS_SET_CTX(h->ts);
  
        if (h->ops->init) {
                if (!(h = h->ops->init(h, init_arg))) {
 -                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initialize client");
 -                      if (free_h) {
 -                              efree(free_h);
 -                      }
 +                      php_error_docref(NULL, E_WARNING, "Could not initialize client");
 +                      PTR_FREE(free_h);
                }
        }
  
@@@ -227,9 -220,11 +227,9 @@@ void php_http_client_free(php_http_clie
  
  ZEND_RESULT_CODE php_http_client_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue)
  {
 -      TSRMLS_FETCH_FROM_CTX(h->ts);
 -
        if (h->ops->enqueue) {
                if (php_http_client_enqueued(h, enqueue->request, NULL)) {
 -                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to enqueue request; request already in queue");
 +                      php_error_docref(NULL, E_WARNING, "Failed to enqueue request; request already in queue");
                        return FAILURE;
                }
                return h->ops->enqueue(h, enqueue);
  
  ZEND_RESULT_CODE php_http_client_dequeue(php_http_client_t *h, php_http_message_t *request)
  {
 -      TSRMLS_FETCH_FROM_CTX(h->ts);
 -
        if (h->ops->dequeue) {
                php_http_client_enqueue_t *enqueue = php_http_client_enqueued(h, request, NULL);
  
                if (!enqueue) {
 -                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to dequeue request; request not in queue");
 +                      php_error_docref(NULL, E_WARNING, "Failed to dequeue request; request not in queue");
                        return FAILURE;
                }
                return h->ops->dequeue(h, enqueue);
@@@ -326,13 -323,12 +326,13 @@@ ZEND_RESULT_CODE php_http_client_getopt
        return FAILURE;
  }
  
 -zend_class_entry *php_http_client_class_entry;
  static zend_object_handlers php_http_client_object_handlers;
  
 -void php_http_client_object_free(void *object TSRMLS_DC)
 +void php_http_client_object_free(zend_object *object)
  {
 -      php_http_client_object_t *o = (php_http_client_object_t *) object;
 +      php_http_client_object_t *o = PHP_HTTP_OBJ(object, NULL);
 +
 +      PTR_FREE(o->gc);
  
        php_http_client_free(&o->client);
        if (o->debug.fci.size > 0) {
        }
        php_http_object_method_dtor(&o->notify);
        php_http_object_method_free(&o->update);
 -      zend_object_std_dtor((zend_object *) o TSRMLS_CC);
 -      efree(o);
 +      zend_object_std_dtor(object);
  }
  
 -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)
 +php_http_client_object_t *php_http_client_object_new_ex(zend_class_entry *ce, php_http_client_t *client)
  {
        php_http_client_object_t *o;
  
 -      o = ecalloc(1, sizeof(php_http_client_object_t));
 -      zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
 -      object_properties_init((zend_object *) o, ce);
 +      o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
 +      zend_object_std_init(&o->zo, ce);
 +      object_properties_init(&o->zo, ce);
  
        o->client = client;
  
 -      if (ptr) {
 -              *ptr = o;
 -      }
 +      o->zo.handlers = &php_http_client_object_handlers;
  
 -      o->zv.handle = zend_objects_store_put(o, NULL, php_http_client_object_free, NULL TSRMLS_CC);
 -      o->zv.handlers = &php_http_client_object_handlers;
 +      return o;
 +}
  
 -      return o->zv;
 +zend_object *php_http_client_object_new(zend_class_entry *ce)
 +{
 +      return &php_http_client_object_new_ex(ce, NULL)->zo;
  }
  
 -zend_object_value php_http_client_object_new(zend_class_entry *ce TSRMLS_DC)
 +static HashTable *php_http_client_object_get_gc(zval *object, zval **table, int *n)
  {
 -      return php_http_client_object_new_ex(ce, NULL, NULL TSRMLS_CC);
 +      php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, object);
 +      zend_llist_element *el = NULL;
 +      HashTable *props = Z_OBJPROP_P(object);
 +      uint32_t count = zend_hash_num_elements(props) + zend_llist_count(&obj->client->responses) + zend_llist_count(&obj->client->requests) + 2;
 +      zval *val;
 +
 +      *n = 0;
 +      *table = obj->gc = erealloc(obj->gc, sizeof(zval) * count);
 +
 +#if PHP_HTTP_HAVE_CURL
 +      if (obj->client->ops == php_http_client_curl_get_ops()) {
 +              php_http_client_curl_t *curl = obj->client->ctx;
 +
 +              if (curl->ev_ops == php_http_client_curl_user_ops_get()) {
 +                      php_http_client_curl_user_context_t *ctx = curl->ev_ctx;
 +
 +                      ZVAL_COPY_VALUE(&obj->gc[(*n)++], &ctx->user);
 +              }
 +      }
 +#endif
 +
 +      if (obj->debug.fci.size > 0) {
 +              ZVAL_COPY_VALUE(&obj->gc[(*n)++], &obj->debug.fci.function_name);
 +      }
 +
 +      for (el = obj->client->responses.head; el; el = el->next) {
 +              php_http_message_object_t *response_obj = *(php_http_message_object_t **) el->data;
 +              ZVAL_OBJ(&obj->gc[(*n)++], &response_obj->zo);
 +      }
 +
 +      for (el = obj->client->requests.head; el; el = el->next) {
 +              php_http_client_enqueue_t *q = (php_http_client_enqueue_t *) el->data;
 +              php_http_message_object_t *request_obj = q->opaque; /* FIXME */
 +              ZVAL_OBJ(&obj->gc[(*n)++], &request_obj->zo);
 +      }
 +
 +      ZEND_HASH_FOREACH_VAL(props, val)
 +      {
 +              ZVAL_COPY_VALUE(&obj->gc[(*n)++], val);
 +      }
 +      ZEND_HASH_FOREACH_END();
 +
 +      return NULL;
  }
  
 -static void handle_history(zval *zclient, php_http_message_t *request, php_http_message_t *response TSRMLS_DC)
 +static void handle_history(zval *zclient, php_http_message_t *request, php_http_message_t *response)
  {
 -      zval *new_hist, *old_hist = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), 0 TSRMLS_CC);
 -      php_http_message_t *zipped = php_http_message_zip(response, request);
 -      zend_object_value ov = php_http_message_object_new_ex(php_http_message_class_entry, zipped, NULL TSRMLS_CC);
 +      zval new_hist, old_hist_tmp, *old_hist = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), 0, &old_hist_tmp);
 +      php_http_message_t *req_copy = php_http_message_copy(request, NULL);
 +      php_http_message_t *res_copy = php_http_message_copy(response, NULL);
 +      php_http_message_t *zipped = php_http_message_zip(res_copy, req_copy);
 +      php_http_message_object_t *obj = php_http_message_object_new_ex(php_http_message_get_class_entry(), zipped);
  
 -      MAKE_STD_ZVAL(new_hist);
 -      ZVAL_OBJVAL(new_hist, ov, 0);
 +      ZVAL_OBJ(&new_hist, &obj->zo);
  
        if (Z_TYPE_P(old_hist) == IS_OBJECT) {
 -              php_http_message_object_prepend(new_hist, old_hist, 1 TSRMLS_CC);
 +              php_http_message_object_prepend(&new_hist, old_hist, 1);
        }
  
 -      zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), new_hist TSRMLS_CC);
 +      zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), &new_hist);
        zval_ptr_dtor(&new_hist);
  }
  
@@@ -436,56 -390,63 +436,56 @@@ static ZEND_RESULT_CODE handle_response
        zval zclient;
        php_http_message_t *msg;
        php_http_client_progress_state_t *progress;
 -      TSRMLS_FETCH_FROM_CTX(client->ts);
  
 -      INIT_PZVAL(&zclient);
 -      ZVAL_OBJVAL(&zclient, ((php_http_client_object_t*) arg)->zv, 0);
 +      ZVAL_OBJ(&zclient, &((php_http_client_object_t*) arg)->zo);
  
        if ((msg = *response)) {
                php_http_message_object_t *msg_obj;
 -              zval *info, *zresponse, *zrequest;
 +              zval info, zresponse, zrequest, rec_hist_tmp;
                HashTable *info_ht;
  
                /* ensure the message is of type response (could be uninitialized in case of early error, like DNS) */
                php_http_message_set_type(msg, PHP_HTTP_RESPONSE);
  
 -              if (z_is_true(zend_read_property(php_http_client_class_entry, &zclient, ZEND_STRL("recordHistory"), 0 TSRMLS_CC))) {
 -                      handle_history(&zclient, e->request, *response TSRMLS_CC);
 +              if (zend_is_true(zend_read_property(php_http_client_class_entry, &zclient, ZEND_STRL("recordHistory"), 0, &rec_hist_tmp))) {
 +                      handle_history(&zclient, e->request, *response);
                }
  
                /* hard detach, redirects etc. are in the history */
                php_http_message_free(&msg->parent);
                *response = NULL;
  
 -              MAKE_STD_ZVAL(zresponse);
 -              ZVAL_OBJVAL(zresponse, php_http_message_object_new_ex(php_http_client_response_class_entry, msg, &msg_obj TSRMLS_CC), 0);
 -
 -              MAKE_STD_ZVAL(zrequest);
 -              ZVAL_OBJVAL(zrequest, ((php_http_message_object_t *) e->opaque)->zv, 1);
 +              msg_obj = php_http_message_object_new_ex(php_http_get_client_response_class_entry(), msg);
 +              ZVAL_OBJECT(&zresponse, &msg_obj->zo, 1);
 +              ZVAL_OBJECT(&zrequest, &((php_http_message_object_t *) e->opaque)->zo, 1);
  
 -              php_http_message_object_prepend(zresponse, zrequest, 1 TSRMLS_CC);
 +              php_http_message_object_prepend(&zresponse, &zrequest, 1);
  
 -              MAKE_STD_ZVAL(info);
 -              object_init(info);
 -              info_ht = HASH_OF(info);
 +              object_init(&info);
 +              info_ht = HASH_OF(&info);
                php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, e->request, &info_ht);
 -              zend_update_property(php_http_client_response_class_entry, zresponse, ZEND_STRL("transferInfo"), info TSRMLS_CC);
 +              zend_update_property(php_http_get_client_response_class_entry(), &zresponse, ZEND_STRL("transferInfo"), &info);
                zval_ptr_dtor(&info);
  
 -              zend_objects_store_add_ref_by_handle(msg_obj->zv.handle TSRMLS_CC);
                zend_llist_add_element(&client->responses, &msg_obj);
  
                if (e->closure.fci.size) {
 -                      zval *retval = NULL;
 +                      zval retval;
                        zend_error_handling zeh;
  
 -                      zend_fcall_info_argn(&e->closure.fci TSRMLS_CC, 1, &zresponse);
 -                      zend_replace_error_handling(EH_NORMAL, NULL, &zeh TSRMLS_CC);
 +                      ZVAL_UNDEF(&retval);
 +                      zend_fcall_info_argn(&e->closure.fci, 1, &zresponse);
 +                      zend_replace_error_handling(EH_NORMAL, NULL, &zeh);
                        ++client->callback.depth;
 -                      zend_fcall_info_call(&e->closure.fci, &e->closure.fcc, &retval, NULL TSRMLS_CC);
 +                      zend_fcall_info_call(&e->closure.fci, &e->closure.fcc, &retval, NULL);
                        --client->callback.depth;
 -                      zend_restore_error_handling(&zeh TSRMLS_CC);
 -                      zend_fcall_info_argn(&e->closure.fci TSRMLS_CC, 0);
 +                      zend_restore_error_handling(&zeh);
 +                      zend_fcall_info_argn(&e->closure.fci, 0);
  
 -                      if (retval) {
 -                              if (Z_TYPE_P(retval) == IS_BOOL) {
 -                                      dequeue = Z_BVAL_P(retval);
 -                              }
 -                              zval_ptr_dtor(&retval);
 +                      if (Z_TYPE(retval) == IS_TRUE) {
 +                              dequeue = 1;
                        }
 +                      zval_ptr_dtor(&retval);
                }
  
                zval_ptr_dtor(&zresponse);
  
  static void handle_progress(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *progress)
  {
 -      zval *zrequest, *zprogress, *zclient, **args[2];
 +      zval zclient, args[2];
        php_http_client_object_t *client_obj = arg;
        zend_error_handling zeh;
 -      TSRMLS_FETCH_FROM_CTX(client->ts);
 -
 -      MAKE_STD_ZVAL(zclient);
 -      ZVAL_OBJVAL(zclient, client_obj->zv, 1);
 -
 -      MAKE_STD_ZVAL(zrequest);
 -      ZVAL_OBJVAL(zrequest, ((php_http_message_object_t *) e->opaque)->zv, 1);
 -      args[0] = &zrequest;
 -
 -      MAKE_STD_ZVAL(zprogress);
 -      object_init(zprogress);
 -      add_property_bool(zprogress, "started", progress->started);
 -      add_property_bool(zprogress, "finished", progress->finished);
 -      add_property_string(zprogress, "info", STR_PTR(progress->info), 1);
 -      add_property_double(zprogress, "dltotal", progress->dl.total);
 -      add_property_double(zprogress, "dlnow", progress->dl.now);
 -      add_property_double(zprogress, "ultotal", progress->ul.total);
 -      add_property_double(zprogress, "ulnow", progress->ul.now);
 -      args[1] = &zprogress;
 -
 -      zend_replace_error_handling(EH_NORMAL, NULL, &zeh TSRMLS_CC);
 +
 +      ZVAL_OBJECT(&zclient, &client_obj->zo, 1);
 +      ZVAL_OBJECT(&args[0], &((php_http_message_object_t *) e->opaque)->zo, 1);
 +      object_init(&args[1]);
 +      add_property_bool(&args[1], "started", progress->started);
 +      add_property_bool(&args[1], "finished", progress->finished);
 +      add_property_string(&args[1], "info", STR_PTR(progress->info));
 +      add_property_double(&args[1], "dltotal", progress->dl.total);
 +      add_property_double(&args[1], "dlnow", progress->dl.now);
 +      add_property_double(&args[1], "ultotal", progress->ul.total);
 +      add_property_double(&args[1], "ulnow", progress->ul.now);
 +
 +      zend_replace_error_handling(EH_NORMAL, NULL, &zeh);
        ++client->callback.depth;
 -      php_http_object_method_call(&client_obj->notify, zclient, NULL, 2, args TSRMLS_CC);
 +      php_http_object_method_call(&client_obj->notify, &zclient, NULL, 2, args);
        --client->callback.depth;
 -      zend_restore_error_handling(&zeh TSRMLS_CC);
 +      zend_restore_error_handling(&zeh);
  
        zval_ptr_dtor(&zclient);
 -      zval_ptr_dtor(&zrequest);
 -      zval_ptr_dtor(&zprogress);
 +      zval_ptr_dtor(&args[0]);
 +      zval_ptr_dtor(&args[1]);
  }
  
  static void handle_debug(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, unsigned type, const char *data, size_t size)
  {
 -      zval *ztype, *zdata, *zreq, *zclient;
 +      zval ztype, zdata, zreq, zclient;
        php_http_client_object_t *client_obj = arg;
        zend_error_handling zeh;
 -      TSRMLS_FETCH_FROM_CTX(client->ts);
 -
 -      MAKE_STD_ZVAL(zclient);
 -      ZVAL_OBJVAL(zclient, client_obj->zv, 1);
 -      MAKE_STD_ZVAL(zreq);
 -      ZVAL_OBJVAL(zreq, ((php_http_message_object_t *) e->opaque)->zv, 1);
 -      MAKE_STD_ZVAL(ztype);
 -      ZVAL_LONG(ztype, type);
 -      MAKE_STD_ZVAL(zdata);
 -      ZVAL_STRINGL(zdata, data, size, 1);
 -
 -      zend_replace_error_handling(EH_NORMAL, NULL, &zeh TSRMLS_CC);
 -      if (SUCCESS == zend_fcall_info_argn(&client_obj->debug.fci TSRMLS_CC, 4, &zclient, &zreq, &ztype, &zdata)) {
 -              ++client_obj->client->callback.depth;
 -              zend_fcall_info_call(&client_obj->debug.fci, &client_obj->debug.fcc, NULL, NULL TSRMLS_CC);
 -              --client_obj->client->callback.depth;
 +
 +      ZVAL_OBJECT(&zclient, &client_obj->zo, 1);
 +      ZVAL_OBJECT(&zreq, &((php_http_message_object_t *) e->opaque)->zo, 1);
 +      ZVAL_LONG(&ztype, type);
 +      ZVAL_STRINGL(&zdata, data, size);
 +
 +      zend_replace_error_handling(EH_NORMAL, NULL, &zeh);
 +      if (SUCCESS == zend_fcall_info_argn(&client_obj->debug.fci, 4, &zclient, &zreq, &ztype, &zdata)) {
 +              ++client->callback.depth;
 +              zend_fcall_info_call(&client_obj->debug.fci, &client_obj->debug.fcc, NULL, NULL);
 +              --client->callback.depth;
                zend_fcall_info_args_clear(&client_obj->debug.fci, 0);
        }
 -      zend_restore_error_handling(&zeh TSRMLS_CC);
 +      zend_restore_error_handling(&zeh);
  
        zval_ptr_dtor(&zclient);
        zval_ptr_dtor(&zreq);
  static void response_dtor(void *data)
  {
        php_http_message_object_t *msg_obj = *(php_http_message_object_t **) data;
 -      TSRMLS_FETCH_FROM_CTX(msg_obj->message->ts);
  
 -      zend_objects_store_del_ref_by_handle_ex(msg_obj->zv.handle, msg_obj->zv.handlers TSRMLS_CC);
 +      zend_object_release(&msg_obj->zo);
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_construct, 0, 0, 0)
  ZEND_END_ARG_INFO();
  static PHP_METHOD(HttpClient, __construct)
  {
 -              char *driver_str = NULL, *persistent_handle_str = NULL;
 -              int driver_len = 0, persistent_handle_len = 0;
 -              php_http_client_driver_t driver;
 +              zend_string *driver_name = NULL, *persistent_handle_name = NULL;
 +              php_http_client_driver_t *driver;
                php_resource_factory_t *rf = NULL;
                php_http_client_object_t *obj;
 -              zval *os;
 +              zval os;
  
 -              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);
 +              php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|S!S!", &driver_name, &persistent_handle_name), invalid_arg, return);
  
 -              if (SUCCESS != php_http_client_driver_get(driver_str, driver_len, &driver)) {
 -                      php_http_throw(unexpected_val, "Failed to locate \"%s\" client request handler", driver_str);
 +              if (!zend_hash_num_elements(&php_http_client_drivers)) {
 +                      php_http_throw(unexpected_val, "No http\\Client drivers available", NULL);
 +                      return;
 +              }
 +              if (!(driver = php_http_client_driver_get(driver_name))) {
 +                      php_http_throw(unexpected_val, "Failed to locate \"%s\" client request handler", driver_name ? driver_name->val : "default");
                        return;
                }
  
 -              MAKE_STD_ZVAL(os);
 -              object_init_ex(os, spl_ce_SplObjectStorage);
 -              zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), os TSRMLS_CC);
 +              object_init_ex(&os, spl_ce_SplObjectStorage);
 +              zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), &os);
                zval_ptr_dtor(&os);
  
 -              if (persistent_handle_len) {
 -                      char *name_str;
 -                      size_t name_len;
 +              if (persistent_handle_name) {
                        php_persistent_handle_factory_t *pf;
  
 -                      name_len = spprintf(&name_str, 0, "http\\Client\\%s", driver.name_str);
 -                      php_http_pretty_key(name_str + sizeof("http\\Client"), driver.name_len, 1, 1);
 -
 -                      if ((pf = php_persistent_handle_concede(NULL , name_str, name_len, persistent_handle_str, persistent_handle_len, NULL, NULL TSRMLS_CC))) {
 +                      if ((pf = php_persistent_handle_concede(NULL, driver->client_name, persistent_handle_name, NULL, NULL))) {
                                rf = php_persistent_handle_resource_factory_init(NULL, pf);
                        }
 -
 -                      efree(name_str);
                }
  
 -              obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +              obj = PHP_HTTP_OBJ(NULL, getThis());
  
 -              php_http_expect(obj->client = php_http_client_init(NULL, driver.client_ops, rf, NULL TSRMLS_CC), runtime, return);
 +              php_http_expect(obj->client = php_http_client_init(NULL, driver->client_ops, rf, NULL), runtime, return);
  
 -              php_http_object_method_init(&obj->notify, getThis(), ZEND_STRL("notify") TSRMLS_CC);
 +              php_http_object_method_init(&obj->notify, getThis(), ZEND_STRL("notify"));
  
                obj->client->callback.response.func = handle_response;
                obj->client->callback.response.arg = obj;
@@@ -622,7 -602,7 +622,7 @@@ static PHP_METHOD(HttpClient, reset
        php_http_client_object_t *obj;
        php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
  
 -      obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +      obj = PHP_HTTP_OBJ(NULL, getThis());
  
        obj->iterator = 0;
        php_http_client_reset(obj->client);
        RETVAL_ZVAL(getThis(), 1, 0);
  }
  
 -static HashTable *combined_options(zval *client, zval *request TSRMLS_DC)
 +static HashTable *combined_options(zval *client, zval *request)
  {
        HashTable *options;
 -      int num_options = 0;
 -      zval *z_roptions = NULL, *z_coptions = zend_read_property(php_http_client_class_entry, client, ZEND_STRL("options"), 0 TSRMLS_CC);
 +      unsigned num_options = 0;
 +      zval z_roptions, z_options_tmp, *z_coptions = zend_read_property(php_http_client_class_entry, client, ZEND_STRL("options"), 0, &z_options_tmp);
  
        if (Z_TYPE_P(z_coptions) == IS_ARRAY) {
                num_options = zend_hash_num_elements(Z_ARRVAL_P(z_coptions));
        }
 -      zend_call_method_with_0_params(&request, NULL, NULL, "getOptions", &z_roptions);
 -      if (z_roptions && Z_TYPE_P(z_roptions) == IS_ARRAY) {
 -              int num = zend_hash_num_elements(Z_ARRVAL_P(z_roptions));
 +      ZVAL_UNDEF(&z_roptions);
 +      zend_call_method_with_0_params(request, NULL, NULL, "getOptions", &z_roptions);
 +      if (Z_TYPE(z_roptions) == IS_ARRAY) {
 +              unsigned num = zend_hash_num_elements(Z_ARRVAL(z_roptions));
                if (num > num_options) {
                        num_options = num;
                }
        if (Z_TYPE_P(z_coptions) == IS_ARRAY) {
                array_copy(Z_ARRVAL_P(z_coptions), options);
        }
 -      if (z_roptions) {
 -              if (Z_TYPE_P(z_roptions) == IS_ARRAY) {
 -                      array_join(Z_ARRVAL_P(z_roptions), options, 0, 0);
 -              }
 -              zval_ptr_dtor(&z_roptions);
 +      if (Z_TYPE(z_roptions) == IS_ARRAY) {
 +              array_join(Z_ARRVAL(z_roptions), options, 0, 0);
        }
 +      zval_ptr_dtor(&z_roptions);
 +
        return options;
  }
  
  static void msg_queue_dtor(php_http_client_enqueue_t *e)
  {
        php_http_message_object_t *msg_obj = e->opaque;
 -      TSRMLS_FETCH_FROM_CTX(msg_obj->message->ts);
  
 -      zend_objects_store_del_ref_by_handle_ex(msg_obj->zv.handle, msg_obj->zv.handlers TSRMLS_CC);
 +      zend_object_release(&msg_obj->zo);
        zend_hash_destroy(e->options);
        FREE_HASHTABLE(e->options);
  
        if (e->closure.fci.size) {
                zval_ptr_dtor(&e->closure.fci.function_name);
 -              if (e->closure.fci.object_ptr) {
 -                      zval_ptr_dtor(&e->closure.fci.object_ptr);
 +              if (e->closure.fci.object) {
 +                      zend_object_release(e->closure.fci.object);
                }
        }
  }
@@@ -689,10 -670,10 +689,10 @@@ static PHP_METHOD(HttpClient, enqueue
        php_http_message_object_t *msg_obj;
        php_http_client_enqueue_t q;
  
 -      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);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|f", &request, php_http_get_client_request_class_entry(), &fci, &fcc), invalid_arg, return);
  
 -      obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 -      msg_obj = zend_object_store_get_object(request TSRMLS_CC);
 +      obj = PHP_HTTP_OBJ(NULL, getThis());
 +      msg_obj = PHP_HTTP_OBJ(NULL, request);
  
        if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
                php_http_throw(bad_method_call, "Failed to enqueue request; request already in queue", NULL);
        }
  
        q.request = msg_obj->message;
 -      q.options = combined_options(getThis(), request TSRMLS_CC);
 +      q.options = combined_options(getThis(), request);
        q.dtor = msg_queue_dtor;
        q.opaque = msg_obj;
        q.closure.fci = fci;
        q.closure.fcc = fcc;
  
        if (fci.size) {
 -              Z_ADDREF_P(fci.function_name);
 -              if (fci.object_ptr) {
 -                      Z_ADDREF_P(fci.object_ptr);
 +              Z_TRY_ADDREF(fci.function_name);
 +              if (fci.object) {
 +                      ++GC_REFCOUNT(fci.object);
                }
        }
  
 -      zend_objects_store_add_ref_by_handle(msg_obj->zv.handle TSRMLS_CC);
 +      Z_ADDREF_P(request);
  
        php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime,
                        msg_queue_dtor(&q);
@@@ -732,10 -713,10 +732,10 @@@ static PHP_METHOD(HttpClient, dequeue
        php_http_client_object_t *obj;
        php_http_message_object_t *msg_obj;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_request_class_entry), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_get_client_request_class_entry()), invalid_arg, return);
  
 -      obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 -      msg_obj = zend_object_store_get_object(request TSRMLS_CC);
 +      obj = PHP_HTTP_OBJ(NULL, getThis());
 +      msg_obj = PHP_HTTP_OBJ(NULL, request);
  
        if (!php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
                php_http_throw(bad_method_call, "Failed to dequeue request; request not in queue", NULL);
@@@ -760,30 -741,30 +760,30 @@@ static PHP_METHOD(HttpClient, requeue
        php_http_message_object_t *msg_obj;
        php_http_client_enqueue_t q;
  
 -      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);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|f", &request, php_http_get_client_request_class_entry(), &fci, &fcc), invalid_arg, return);
  
 -      obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 -      msg_obj = zend_object_store_get_object(request TSRMLS_CC);
 +      obj = PHP_HTTP_OBJ(NULL, getThis());
 +      msg_obj = PHP_HTTP_OBJ(NULL, request);
  
        if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
                php_http_expect(SUCCESS == php_http_client_dequeue(obj->client, msg_obj->message), runtime, return);
        }
  
        q.request = msg_obj->message;
 -      q.options = combined_options(getThis(), request TSRMLS_CC);
 +      q.options = combined_options(getThis(), request);
        q.dtor = msg_queue_dtor;
        q.opaque = msg_obj;
        q.closure.fci = fci;
        q.closure.fcc = fcc;
  
        if (fci.size) {
 -              Z_ADDREF_P(fci.function_name);
 -              if (fci.object_ptr) {
 -                      Z_ADDREF_P(fci.object_ptr);
 +              Z_TRY_ADDREF(fci.function_name);
 +              if (fci.object) {
 +                      ++GC_REFCOUNT(fci.object);
                }
        }
  
 -      zend_objects_store_add_ref_by_handle(msg_obj->zv.handle TSRMLS_CC);
 +      Z_ADDREF_P(request);
  
        php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime,
                        msg_queue_dtor(&q);
@@@ -797,10 -778,10 +797,10 @@@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_co
  ZEND_END_ARG_INFO();
  static PHP_METHOD(HttpClient, count)
  {
 -      long count_mode = -1;
 +      zend_long count_mode = -1;
  
 -      if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &count_mode)) {
 -              php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +      if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &count_mode)) {
 +              php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
  
                RETVAL_LONG(zend_llist_count(&obj->client->requests));
        }
@@@ -814,20 -795,20 +814,20 @@@ static PHP_METHOD(HttpClient, getRespon
        zval *zrequest = NULL;
        php_http_client_object_t *obj;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O", &zrequest, php_http_client_request_class_entry), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|O", &zrequest, php_http_get_client_request_class_entry()), invalid_arg, return);
  
 -      obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +      obj = PHP_HTTP_OBJ(NULL, getThis());
  
        if (zrequest) {
                /* lookup the response with the request */
                zend_llist_element *el = NULL;
 -              php_http_message_object_t *req_obj = zend_object_store_get_object(zrequest TSRMLS_CC);
 +              php_http_message_object_t *req_obj = PHP_HTTP_OBJ(NULL, zrequest);
  
                for (el = obj->client->responses.head; el; el = el->next) {
                        php_http_message_object_t *response_obj = *(php_http_message_object_t **) el->data;
  
                        if (response_obj->message->parent == req_obj->message) {
 -                              RETURN_OBJVAL(response_obj->zv, 1);
 +                              RETURN_OBJECT(&response_obj->zo, 1);
                        }
                }
  
  
                /* pop off and go */
                if (response_obj) {
 -                      RETVAL_OBJVAL(response_obj->zv, 1);
 +                      RETVAL_OBJECT(&response_obj->zo, 1);
                        zend_llist_remove_tail(&obj->client->responses);
                }
        }
@@@ -852,11 -833,11 +852,11 @@@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_ge
  ZEND_END_ARG_INFO();
  static PHP_METHOD(HttpClient, getHistory)
  {
 -      zval *zhistory;
 +      zval zhistory_tmp, *zhistory;
  
        php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
  
 -      zhistory = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("history"), 0 TSRMLS_CC);
 +      zhistory = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("history"), 0, &zhistory_tmp);
        RETVAL_ZVAL(zhistory, 1, 0);
  }
  
@@@ -868,7 -849,7 +868,7 @@@ static PHP_METHOD(HttpClient, send
  
        php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
  
 -      obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +      obj = PHP_HTTP_OBJ(NULL, getThis());
  
        php_http_expect(SUCCESS == php_http_client_exec(obj->client), runtime, return);
  
@@@ -880,7 -861,7 +880,7 @@@ ZEND_END_ARG_INFO()
  static PHP_METHOD(HttpClient, once)
  {
        if (SUCCESS == zend_parse_parameters_none()) {
 -              php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +              php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
  
                RETURN_BOOL(0 < php_http_client_once(obj->client));
        }
@@@ -893,9 -874,9 +893,9 @@@ static PHP_METHOD(HttpClient, wait
  {
        double timeout = 0;
  
 -      if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|d", &timeout)) {
 +      if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|d", &timeout)) {
                struct timeval timeout_val;
 -              php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +              php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
  
                timeout_val.tv_sec = (time_t) timeout;
                timeout_val.tv_usec = PHP_HTTP_USEC(timeout) % PHP_HTTP_MCROSEC;
@@@ -912,8 -893,8 +912,8 @@@ static PHP_METHOD(HttpClient, configure
        HashTable *settings = NULL;
        php_http_client_object_t *obj;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|H!", &settings), invalid_arg, return);
 -      obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|H!", &settings), invalid_arg, return);
 +      obj = PHP_HTTP_OBJ(NULL, getThis());
  
        php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_CONFIGURATION, settings), unexpected_val, return);
  
@@@ -928,9 -909,9 +928,9 @@@ static PHP_METHOD(HttpClient, enablePip
        zend_bool enable = 1;
        php_http_client_object_t *obj;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable), invalid_arg, return);
  
 -      obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +      obj = PHP_HTTP_OBJ(NULL, getThis());
  
        php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING, &enable), unexpected_val, return);
  
@@@ -945,9 -926,9 +945,9 @@@ static PHP_METHOD(HttpClient, enableEve
        zend_bool enable = 1;
        php_http_client_object_t *obj;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &enable), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable), invalid_arg, return);
  
 -      obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +      obj = PHP_HTTP_OBJ(NULL, getThis());
  
        php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_USE_EVENTS, &enable), unexpected_val, return);
  
  
  struct notify_arg {
        php_http_object_method_t *cb;
 -      zval **args[3];
 +      zval args[3];
        int argc;
  };
  
 -static int notify(zend_object_iterator *iter, void *puser TSRMLS_DC)
 +static int notify(zend_object_iterator *iter, void *puser)
  {
 -      zval **observer = NULL;
 +      zval *observer;
        struct notify_arg *arg = puser;
  
 -      iter->funcs->get_current_data(iter, &observer TSRMLS_CC);
 -      if (observer) {
 -              return php_http_object_method_call(arg->cb, *observer, NULL, arg->argc, arg->args TSRMLS_CC);
 +      if ((observer = iter->funcs->get_current_data(iter))) {
 +              if (SUCCESS == php_http_object_method_call(arg->cb, observer, NULL, arg->argc, arg->args)) {
 +                      return ZEND_HASH_APPLY_KEEP;
 +              }
        }
 -      return FAILURE;
 +      return ZEND_HASH_APPLY_STOP;
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_notify, 0, 0, 0)
  ZEND_END_ARG_INFO();
  static PHP_METHOD(HttpClient, notify)
  {
 -      zval *request = NULL, *zprogress = NULL, *observers;
 +      zval *request = NULL, *zprogress = NULL, observers_tmp, *observers;
        php_http_client_object_t *client_obj;
        struct notify_arg arg = {NULL};
  
 -      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);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|O!o!", &request, php_http_get_client_request_class_entry(), &zprogress), invalid_arg, return);
  
 -      client_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 -      observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC);
 +      client_obj = PHP_HTTP_OBJ(NULL, getThis());
 +      observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp);
  
        if (Z_TYPE_P(observers) != IS_OBJECT) {
                php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
  
        if (client_obj->update) {
                arg.cb = client_obj->update;
 -
 -              Z_ADDREF_P(getThis());
 -              arg.args[0] = &getThis();
 +              ZVAL_COPY(&arg.args[0], getThis());
                arg.argc = 1;
  
                if (request) {
 -                      Z_ADDREF_P(request);
 -                      arg.args[1] = &request;
 +                      ZVAL_COPY(&arg.args[1], request);
                        arg.argc += 1;
                }
 -
                if (zprogress) {
 -                      Z_ADDREF_P(zprogress);
 -                      arg.args[2] = &zprogress;
 +                      ZVAL_COPY(&arg.args[2], zprogress);
                        arg.argc += 1;
                }
  
 -              spl_iterator_apply(observers, notify, &arg TSRMLS_CC);
 +              spl_iterator_apply(observers, notify, &arg);
  
 -              zval_ptr_dtor(&getThis());
 +              zval_ptr_dtor(getThis());
                if (request) {
 -                      zval_ptr_dtor(&request);
 +                      zval_ptr_dtor(request);
                }
                if (zprogress) {
 -                      zval_ptr_dtor(&zprogress);
 +                      zval_ptr_dtor(zprogress);
                }
        }
  
@@@ -1025,13 -1010,13 +1025,13 @@@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_at
  ZEND_END_ARG_INFO();
  static PHP_METHOD(HttpClient, attach)
  {
 -      zval *observers, *observer, *retval = NULL;
 +      zval observers_tmp, *observers, *observer, retval;
        php_http_client_object_t *client_obj;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &observer, spl_ce_SplObserver), invalid_arg, return);
  
 -      client_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 -      observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC);
 +      client_obj = PHP_HTTP_OBJ(NULL, getThis());
 +      observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp);
  
        if (Z_TYPE_P(observers) != IS_OBJECT) {
                php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
        }
  
        if (!client_obj->update) {
 -              client_obj->update = php_http_object_method_init(NULL, observer, ZEND_STRL("update") TSRMLS_CC);
 +              client_obj->update = php_http_object_method_init(NULL, observer, ZEND_STRL("update"));
        }
  
 -      zend_call_method_with_1_params(&observers, NULL, NULL, "attach", &retval, observer);
 -      if (retval) {
 -              zval_ptr_dtor(&retval);
 -      }
 +      ZVAL_UNDEF(&retval);
 +      zend_call_method_with_1_params(observers, NULL, NULL, "attach", &retval, observer);
 +      zval_ptr_dtor(&retval);
  
        RETVAL_ZVAL(getThis(), 1, 0);
  }
@@@ -1054,20 -1040,21 +1054,20 @@@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_de
  ZEND_END_ARG_INFO();
  static PHP_METHOD(HttpClient, detach)
  {
 -      zval *observers, *observer, *retval = NULL;
 +      zval observers_tmp, *observers, *observer, retval;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &observer, spl_ce_SplObserver), invalid_arg, return);
  
 -      observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC);
 +      observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp);
  
        if (Z_TYPE_P(observers) != IS_OBJECT) {
                php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
                return;
        }
  
 -      zend_call_method_with_1_params(&observers, NULL, NULL, "detach", &retval, observer);
 -      if (retval) {
 -              zval_ptr_dtor(&retval);
 -      }
 +      ZVAL_UNDEF(&retval);
 +      zend_call_method_with_1_params(observers, NULL, NULL, "detach", &retval, observer);
 +      zval_ptr_dtor(&retval);
  
        RETVAL_ZVAL(getThis(), 1, 0);
  }
@@@ -1076,11 -1063,11 +1076,11 @@@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_ge
  ZEND_END_ARG_INFO();
  static PHP_METHOD(HttpClient, getObservers)
  {
 -      zval *observers;
 +      zval observers_tmp, *observers;
  
        php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
  
 -      observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC);
 +      observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp);
  
        if (Z_TYPE_P(observers) != IS_OBJECT) {
                php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
@@@ -1100,17 -1087,17 +1100,17 @@@ static PHP_METHOD(HttpClient, getProgre
        php_http_message_object_t *req_obj;
        php_http_client_progress_state_t *progress;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_request_class_entry), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_get_client_request_class_entry()), invalid_arg, return);
  
 -      obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 -      req_obj = zend_object_store_get_object(request TSRMLS_CC);
 +      obj = PHP_HTTP_OBJ(NULL, getThis());
 +      req_obj = PHP_HTTP_OBJ(NULL, request);
  
        php_http_expect(SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, req_obj->message, &progress), unexpected_val, return);
  
        object_init(return_value);
        add_property_bool(return_value, "started", progress->started);
        add_property_bool(return_value, "finished", progress->finished);
 -      add_property_string(return_value, "info", STR_PTR(progress->info), 1);
 +      add_property_string(return_value, "info", STR_PTR(progress->info));
        add_property_double(return_value, "dltotal", progress->dl.total);
        add_property_double(return_value, "dlnow", progress->dl.now);
        add_property_double(return_value, "ultotal", progress->ul.total);
@@@ -1127,10 -1114,10 +1127,10 @@@ static PHP_METHOD(HttpClient, getTransf
        php_http_client_object_t *obj;
        php_http_message_object_t *req_obj;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_client_request_class_entry), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_get_client_request_class_entry()), invalid_arg, return);
  
 -      obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 -      req_obj = zend_object_store_get_object(request TSRMLS_CC);
 +      obj = PHP_HTTP_OBJ(NULL, getThis());
 +      req_obj = PHP_HTTP_OBJ(NULL, request);
  
        object_init(return_value);
        info = HASH_OF(return_value);
@@@ -1144,9 -1131,9 +1144,9 @@@ static PHP_METHOD(HttpClient, setOption
  {
        zval *opts = NULL;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
  
 -      php_http_client_options_set(getThis(), opts TSRMLS_CC);
 +      php_http_client_options_set(getThis(), opts);
  
        RETVAL_ZVAL(getThis(), 1, 0);
  }
@@@ -1156,7 -1143,7 +1156,7 @@@ ZEND_END_ARG_INFO()
  static PHP_METHOD(HttpClient, getOptions)
  {
        if (SUCCESS == zend_parse_parameters_none()) {
 -              zval *options = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
 +              zval options_tmp, *options = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("options"), 0, &options_tmp);
                RETVAL_ZVAL(options, 1, 0);
        }
  }
@@@ -1168,9 -1155,9 +1168,9 @@@ static PHP_METHOD(HttpClient, setSslOpt
  {
        zval *opts = NULL;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
  
 -      php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 1 TSRMLS_CC);
 +      php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 1);
  
        RETVAL_ZVAL(getThis(), 1, 0);
  }
@@@ -1182,9 -1169,9 +1182,9 @@@ static PHP_METHOD(HttpClient, addSslOpt
  {
        zval *opts = NULL;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
  
 -      php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 0 TSRMLS_CC);
 +      php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 0);
  
        RETVAL_ZVAL(getThis(), 1, 0);
  }
@@@ -1194,7 -1181,7 +1194,7 @@@ ZEND_END_ARG_INFO()
  static PHP_METHOD(HttpClient, getSslOptions)
  {
        if (SUCCESS == zend_parse_parameters_none()) {
 -              php_http_client_options_get_subr(getThis(), ZEND_STRS("ssl"), return_value TSRMLS_CC);
 +              php_http_client_options_get_subr(getThis(), ZEND_STRL("ssl"), return_value);
        }
  }
  
@@@ -1205,9 -1192,9 +1205,9 @@@ static PHP_METHOD(HttpClient, setCookie
  {
        zval *opts = NULL;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
  
 -      php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts, 1 TSRMLS_CC);
 +      php_http_client_options_set_subr(getThis(), ZEND_STRL("cookies"), opts, 1);
  
        RETVAL_ZVAL(getThis(), 1, 0);
  }
@@@ -1219,9 -1206,9 +1219,9 @@@ static PHP_METHOD(HttpClient, addCookie
  {
        zval *opts = NULL;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
  
 -      php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts, 0 TSRMLS_CC);
 +      php_http_client_options_set_subr(getThis(), ZEND_STRL("cookies"), opts, 0);
  
        RETVAL_ZVAL(getThis(), 1, 0);
  }
@@@ -1231,17 -1218,16 +1231,17 @@@ ZEND_END_ARG_INFO()
  static PHP_METHOD(HttpClient, getCookies)
  {
        if (SUCCESS == zend_parse_parameters_none()) {
 -              php_http_client_options_get_subr(getThis(), ZEND_STRS("cookies"), return_value TSRMLS_CC);
 +              php_http_client_options_get_subr(getThis(), ZEND_STRL("cookies"), return_value);
        }
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableDrivers, 0, 0, 0)
  ZEND_END_ARG_INFO();
 -static PHP_METHOD(HttpClient, getAvailableDrivers) {
 +static PHP_METHOD(HttpClient, getAvailableDrivers)
 +{
        if (SUCCESS == zend_parse_parameters_none()) {
                array_init(return_value);
 -              php_http_client_driver_list(Z_ARRVAL_P(return_value) TSRMLS_CC);
 +              php_http_client_driver_list(Z_ARRVAL_P(return_value));
        }
  }
  
@@@ -1250,7 -1236,7 +1250,7 @@@ ZEND_END_ARG_INFO()
  static PHP_METHOD(HttpClient, getAvailableOptions)
  {
        if (SUCCESS == zend_parse_parameters_none()) {
 -              php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +              php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
  
                array_init(return_value);
                php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_AVAILABLE_OPTIONS, NULL, &Z_ARRVAL_P(return_value));
@@@ -1262,7 -1248,7 +1262,7 @@@ ZEND_END_ARG_INFO()
  static PHP_METHOD(HttpClient, getAvailableConfiguration)
  {
        if (SUCCESS == zend_parse_parameters_none()) {
 -              php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +              php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
  
                array_init(return_value);
                php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_AVAILABLE_CONFIGURATION, NULL, &Z_ARRVAL_P(return_value));
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setDebug, 0, 0, 1)
-       ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 1)
+       /* using IS_CALLABLE type hint would create a forwards compatibility break */
+       ZEND_ARG_INFO(0, callback)
  ZEND_END_ARG_INFO();
  static PHP_METHOD(HttpClient, setDebug)
  {
        php_http_client_object_t *client_obj;
  
        fci.size = 0;
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|f", &fci, &fcc), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|f", &fci, &fcc), invalid_arg, return);
  
 -      client_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +      client_obj = PHP_HTTP_OBJ(NULL, getThis());
  
        if (client_obj->debug.fci.size > 0) {
                zval_ptr_dtor(&client_obj->debug.fci.function_name);
        if (fci.size > 0) {
                memcpy(&client_obj->debug.fci, &fci, sizeof(fci));
                memcpy(&client_obj->debug.fcc, &fcc, sizeof(fcc));
 -              Z_ADDREF_P(fci.function_name);
 +              Z_ADDREF_P(&fci.function_name);
                client_obj->client->callback.debug.func = handle_debug;
                client_obj->client->callback.debug.arg = client_obj;
        } else {
@@@ -1342,27 -1329,24 +1343,27 @@@ PHP_MINIT_FUNCTION(http_client
        zend_class_entry ce = {0};
  
        INIT_NS_CLASS_ENTRY(ce, "http", "Client", php_http_client_methods);
 -      php_http_client_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
 +      php_http_client_class_entry = zend_register_internal_class_ex(&ce, NULL);
        php_http_client_class_entry->create_object = php_http_client_object_new;
 -      zend_class_implements(php_http_client_class_entry TSRMLS_CC, 2, spl_ce_SplSubject, spl_ce_Countable);
 +      zend_class_implements(php_http_client_class_entry, 2, spl_ce_SplSubject, spl_ce_Countable);
        memcpy(&php_http_client_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
 +      php_http_client_object_handlers.offset = XtOffsetOf(php_http_client_object_t, zo);
 +      php_http_client_object_handlers.free_obj = php_http_client_object_free;
        php_http_client_object_handlers.clone_obj = NULL;
 -      zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("observers"), ZEND_ACC_PRIVATE TSRMLS_CC);
 -      zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("options"), ZEND_ACC_PROTECTED TSRMLS_CC);
 -      zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("history"), ZEND_ACC_PROTECTED TSRMLS_CC);
 -      zend_declare_property_bool(php_http_client_class_entry, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
 -
 -      zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_INFO"), PHP_HTTP_CLIENT_DEBUG_INFO TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_IN"), PHP_HTTP_CLIENT_DEBUG_IN TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_OUT"), PHP_HTTP_CLIENT_DEBUG_OUT TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_HEADER"), PHP_HTTP_CLIENT_DEBUG_HEADER TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_BODY"), PHP_HTTP_CLIENT_DEBUG_BODY TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_SSL"), PHP_HTTP_CLIENT_DEBUG_SSL TSRMLS_CC);
 -
 -      zend_hash_init(&php_http_client_drivers, 2, NULL, NULL, 1);
 +      php_http_client_object_handlers.get_gc = php_http_client_object_get_gc;
 +      zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("observers"), ZEND_ACC_PRIVATE);
 +      zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("options"), ZEND_ACC_PROTECTED);
 +      zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("history"), ZEND_ACC_PROTECTED);
 +      zend_declare_property_bool(php_http_client_class_entry, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC);
 +
 +      zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_INFO"), PHP_HTTP_CLIENT_DEBUG_INFO);
 +      zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_IN"), PHP_HTTP_CLIENT_DEBUG_IN);
 +      zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_OUT"), PHP_HTTP_CLIENT_DEBUG_OUT);
 +      zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_HEADER"), PHP_HTTP_CLIENT_DEBUG_HEADER);
 +      zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_BODY"), PHP_HTTP_CLIENT_DEBUG_BODY);
 +      zend_declare_class_constant_long(php_http_client_class_entry, ZEND_STRL("DEBUG_SSL"), PHP_HTTP_CLIENT_DEBUG_SSL);
 +
 +      zend_hash_init(&php_http_client_drivers, 2, NULL, php_http_client_driver_hash_dtor, 1);
  
        return SUCCESS;
  }
index 225ce1cda8aa8828856880b7d5d23b1e0b6e3227,f4a995894ba8a2ddad3ce1cee1d71b6e165f2a3a..66edae664db2677cf0ef1490df05740415988cd1
  */
  
  #include "php_http_api.h"
 -#include "php_http_client.h"
 -#include "php_http_client_curl.h"
 -#include "php_http_client_curl_user.h"
  
  #include "php_network.h"
  #include "zend_closures.h"
  
  #if PHP_HTTP_HAVE_CURL
  
 -typedef struct php_http_client_curl_user_context {
 -      php_http_client_t *client;
 -      zval *user;
 -      zend_function closure;
 -      php_http_object_method_t timer;
 -      php_http_object_method_t socket;
 -      php_http_object_method_t once;
 -      php_http_object_method_t wait;
 -      php_http_object_method_t send;
 -} php_http_client_curl_user_context_t;
 -
  typedef struct php_http_client_curl_user_ev {
        php_stream *socket;
        php_http_client_curl_user_context_t *context;
@@@ -31,13 -45,13 +31,13 @@@ static void php_http_client_curl_user_h
        php_http_client_object_t *client = NULL;
        php_http_client_curl_t *curl;
  
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|rl", &zclient, php_http_client_class_entry, &zstream, &action)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "O|rl", &zclient, php_http_client_get_class_entry(), &zstream, &action)) {
                return;
        }
  
 -      client = zend_object_store_get_object(zclient TSRMLS_CC);
 +      client = PHP_HTTP_OBJ(NULL, zclient);
        if (zstream) {
 -              php_stream_from_zval(stream, &zstream);
 +              php_stream_from_zval(stream, zstream);
  
                if (SUCCESS != php_stream_cast(stream, PHP_STREAM_AS_SOCKETD, (void *) &fd, 1)) {
                        return;
@@@ -60,11 -74,14 +60,11 @@@ static void php_http_client_curl_user_t
        if (timeout_ms <= 0) {
                php_http_client_curl_loop(context->client, CURL_SOCKET_TIMEOUT, 0);
        } else if (timeout_ms > 0) {
 -              zval **args[1], *ztimeout;
 -              TSRMLS_FETCH_FROM_CTX(context->client->ts);
 +              zval args[1], *ztimeout = &args[0];
  
 -              MAKE_STD_ZVAL(ztimeout);
                ZVAL_LONG(ztimeout, timeout_ms);
 -              args[0] = &ztimeout;
 -              php_http_object_method_call(&context->timer, context->user, NULL, 1, args TSRMLS_CC);
 -              zval_ptr_dtor(&ztimeout);
 +              php_http_object_method_call(&context->timer, &context->user, NULL, 1, args);
 +              zval_ptr_dtor(ztimeout);
        }
  }
  
@@@ -73,7 -90,8 +73,7 @@@ static int php_http_client_curl_user_so
        php_http_client_curl_user_context_t *ctx = socket_data;
        php_http_client_curl_t *curl = ctx->client->ctx;
        php_http_client_curl_user_ev_t *ev = assign_data;
 -      zval **args[2], *zaction, *zsocket;
 -      TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
 +      zval args[2], *zaction = &args[1], *zsocket = &args[0];
  
  #if DBG_EVENTS
        fprintf(stderr, "S");
                case CURL_POLL_INOUT:
                case CURL_POLL_REMOVE:
                case CURL_POLL_NONE:
 -                      MAKE_STD_ZVAL(zsocket);
                        php_stream_to_zval(ev->socket, zsocket);
 -                      args[0] = &zsocket;
 -                      MAKE_STD_ZVAL(zaction);
 +                      Z_TRY_ADDREF_P(zsocket);
                        ZVAL_LONG(zaction, action);
 -                      args[1] = &zaction;
 -                      php_http_object_method_call(&ctx->socket, ctx->user, NULL, 2, args TSRMLS_CC);
 -                      zval_ptr_dtor(&zsocket);
 -                      zval_ptr_dtor(&zaction);
 +                      php_http_object_method_call(&ctx->socket, &ctx->user, NULL, 2, args);
 +                      zval_ptr_dtor(zsocket);
 +                      zval_ptr_dtor(zaction);
                        break;
  
                default:
 -                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown socket action %d", action);
 +                      php_error_docref(NULL, E_WARNING, "Unknown socket action %d", action);
                        return -1;
        }
  
        if (action == CURL_POLL_REMOVE && ev) {
 +              php_stream_close(ev->socket);
                efree(ev);
 +              curl_multi_assign(curl->handle->multi, sock, NULL);
        }
        return 0;
  }
  static ZEND_RESULT_CODE php_http_client_curl_user_once(void *context)
  {
        php_http_client_curl_user_context_t *ctx = context;
 -      TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
  
  #if DBG_EVENTS
        fprintf(stderr, "O");
  #endif
  
 -      return php_http_object_method_call(&ctx->once, ctx->user, NULL, 0, NULL TSRMLS_CC);
 +      return php_http_object_method_call(&ctx->once, &ctx->user, NULL, 0, NULL);
  }
  
  static ZEND_RESULT_CODE php_http_client_curl_user_wait(void *context, struct timeval *custom_timeout)
  {
        php_http_client_curl_user_context_t *ctx = context;
        struct timeval timeout;
 -      zval **args[1], *ztimeout;
 +      zval args[1], *ztimeout = &args[0];
        ZEND_RESULT_CODE rv;
 -      TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
  
  #if DBG_EVENTS
        fprintf(stderr, "W");
                custom_timeout = &timeout;
        }
  
 -      MAKE_STD_ZVAL(ztimeout);
        ZVAL_LONG(ztimeout, custom_timeout->tv_sec * 1000 + custom_timeout->tv_usec / 1000);
 -      args[0] = &ztimeout;
 -      rv = php_http_object_method_call(&ctx->wait, ctx->user, NULL, 1, args TSRMLS_CC);
 -      zval_ptr_dtor(&ztimeout);
 +      rv = php_http_object_method_call(&ctx->wait, &ctx->user, NULL, 1, args);
 +      zval_ptr_dtor(ztimeout);
  
        return rv;
  }
@@@ -152,6 -175,7 +152,6 @@@ static ZEND_RESULT_CODE php_http_client
  {
        php_http_client_curl_user_context_t *ctx = context;
        php_http_client_curl_t *curl = ctx->client->ctx;
 -      TSRMLS_FETCH_FROM_CTX(ctx->client->ts);
  
  #if DBG_EVENTS
        fprintf(stderr, "E");
        php_http_client_curl_loop(ctx->client, CURL_SOCKET_TIMEOUT, 0);
  
        do {
 -              if (SUCCESS != php_http_object_method_call(&ctx->send, ctx->user, NULL, 0, NULL TSRMLS_CC)) {
 +              if (SUCCESS != php_http_object_method_call(&ctx->send, &ctx->user, NULL, 0, NULL)) {
                        return FAILURE;
                }
        } while (curl->unfinished && !EG(exception));
@@@ -174,7 -198,8 +174,7 @@@ static void *php_http_client_curl_user_
        php_http_client_curl_t *curl = client->ctx;
        php_http_client_curl_user_context_t *ctx;
        php_http_object_method_t init;
 -      zval *zclosure, **args[1];
 -      TSRMLS_FETCH_FROM_CTX(client->ts);
 +      zval args[1], *zclosure = &args[0];
  
  #if DBG_EVENTS
        fprintf(stderr, "I");
  
        ctx = ecalloc(1, sizeof(*ctx));
        ctx->client = client;
 -      ctx->user = user_data;
 -      Z_ADDREF_P(ctx->user);
 +      ZVAL_COPY(&ctx->user, user_data);
  
        memset(&ctx->closure, 0, sizeof(ctx->closure));
        ctx->closure.common.type = ZEND_INTERNAL_FUNCTION;
 -      ctx->closure.common.function_name = "php_http_client_curl_user_handler";
 +      ctx->closure.common.function_name = zend_string_init(ZEND_STRL("php_http_client_curl_user_handler"), 0);
        ctx->closure.internal_function.handler = php_http_client_curl_user_handler;
  
 -      MAKE_STD_ZVAL(zclosure);
 -#if PHP_VERSION_ID >= 50400
 -      zend_create_closure(zclosure, &ctx->closure, NULL, NULL TSRMLS_CC);
 -#else
 -      zend_create_closure(zclosure, &ctx->closure TSRMLS_CC);
 -#endif
 -      args[0] = &zclosure;
 +      zend_create_closure(zclosure, &ctx->closure, NULL, NULL, NULL);
  
 -      php_http_object_method_init(&init, ctx->user, ZEND_STRL("init") TSRMLS_CC);
 -      php_http_object_method_call(&init, ctx->user, NULL, 1, args TSRMLS_CC);
 +      php_http_object_method_init(&init, &ctx->user, ZEND_STRL("init"));
 +      php_http_object_method_call(&init, &ctx->user, NULL, 1, args);
        php_http_object_method_dtor(&init);
 -      zval_ptr_dtor(&zclosure);
 +      zval_ptr_dtor(zclosure);
  
 -      php_http_object_method_init(&ctx->timer, ctx->user, ZEND_STRL("timer") TSRMLS_CC);
 -      php_http_object_method_init(&ctx->socket, ctx->user, ZEND_STRL("socket") TSRMLS_CC);
 -      php_http_object_method_init(&ctx->once, ctx->user, ZEND_STRL("once") TSRMLS_CC);
 -      php_http_object_method_init(&ctx->wait, ctx->user, ZEND_STRL("wait") TSRMLS_CC);
 -      php_http_object_method_init(&ctx->send, ctx->user, ZEND_STRL("send") TSRMLS_CC);
 +      php_http_object_method_init(&ctx->timer, &ctx->user, ZEND_STRL("timer"));
 +      php_http_object_method_init(&ctx->socket, &ctx->user, ZEND_STRL("socket"));
 +      php_http_object_method_init(&ctx->once, &ctx->user, ZEND_STRL("once"));
 +      php_http_object_method_init(&ctx->wait, &ctx->user, ZEND_STRL("wait"));
 +      php_http_object_method_init(&ctx->send, &ctx->user, ZEND_STRL("send"));
  
        curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETDATA, ctx);
        curl_multi_setopt(curl->handle->multi, CURLMOPT_SOCKETFUNCTION, php_http_client_curl_user_socket);
@@@ -232,7 -264,6 +232,7 @@@ static void php_http_client_curl_user_d
        php_http_object_method_dtor(&ctx->wait);
        php_http_object_method_dtor(&ctx->send);
  
 +      zend_string_release(ctx->closure.common.function_name);
        zval_ptr_dtor(&ctx->user);
  
        efree(ctx);
@@@ -252,15 -283,11 +252,16 @@@ php_http_client_curl_ops_t *php_http_cl
        return &php_http_client_curl_user_ops;
  }
  
 -zend_class_entry *php_http_client_curl_user_class_entry;
 +static zend_class_entry *php_http_client_curl_user_class_entry;
 +
 +zend_class_entry *php_http_client_curl_user_get_class_entry()
 +{
 +      return php_http_client_curl_user_class_entry;
 +}
  
  ZEND_BEGIN_ARG_INFO_EX(ai_init, 0, 0, 1)
-       ZEND_ARG_TYPE_INFO(0, run, IS_CALLABLE, 0)
+       /* using IS_CALLABLE type hint would create a forwards compatibility break */
+       ZEND_ARG_INFO(0, run)
  ZEND_END_ARG_INFO();
  ZEND_BEGIN_ARG_INFO_EX(ai_timer, 0, 0, 1)
  #if PHP_VERSION_ID >= 70000
  #endif
  ZEND_END_ARG_INFO();
  ZEND_BEGIN_ARG_INFO_EX(ai_socket, 0, 0, 2)
 +      ZEND_ARG_INFO(0, socket)
  #if PHP_VERSION_ID >= 70000
 -      ZEND_ARG_TYPE_INFO(0, socket, IS_RESOURCE, 0)
        ZEND_ARG_TYPE_INFO(0, action, IS_LONG, 0)
  #else
 -      ZEND_ARG_INFO(0, socket)
        ZEND_ARG_INFO(0, action)
  #endif
  ZEND_END_ARG_INFO();
@@@ -304,13 -332,13 +305,13 @@@ PHP_MINIT_FUNCTION(http_client_curl_use
        zend_class_entry ce = {0};
  
        INIT_NS_CLASS_ENTRY(ce, "http\\Client\\Curl", "User", php_http_client_curl_user_methods);
 -      php_http_client_curl_user_class_entry = zend_register_internal_interface(&ce TSRMLS_CC);
 +      php_http_client_curl_user_class_entry = zend_register_internal_interface(&ce);
  
 -      zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_NONE"), CURL_POLL_NONE TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_IN"), CURL_POLL_IN TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_OUT"), CURL_POLL_OUT TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_INOUT"), CURL_POLL_INOUT TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_REMOVE"), CURL_POLL_REMOVE TSRMLS_CC);
 +      zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_NONE"), CURL_POLL_NONE);
 +      zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_IN"), CURL_POLL_IN);
 +      zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_OUT"), CURL_POLL_OUT);
 +      zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_INOUT"), CURL_POLL_INOUT);
 +      zend_declare_class_constant_long(php_http_client_curl_user_class_entry, ZEND_STRL("POLL_REMOVE"), CURL_POLL_REMOVE);
  
        return SUCCESS;
  }
diff --combined tests/client028.phpt
index 27ab2b646f37703f78ba9ed375726aab7f3bf2b6,280c3059d36aa62948708caf4fb501d1e7862548..232f56285d560d6290e3321d13df34044020f715
@@@ -13,28 -13,28 +13,28 @@@ class UserHandler implements http\Clien
  {
        private $client;
        private $run;
-       private $fds = [
-                       "R" => [],
-                       "W" => []
-       ];
-       private $R = [];
-       private $W = [];
+       private $fds = array(
+                       "R" => array(),
+                       "W" => array()
+       );
+       private $R = array();
+       private $W = array();
        private $timeout = 1000;
        
        function __construct(http\Client $client) {
                $this->client = $client;
        }
        
-       function init(callable $run) {
+       function init($run) {
                $this->run = $run;
        }
        
 -      function timer($timeout_ms) {
 +      function timer(int $timeout_ms) {
                echo "T";
                $this->timeout = $timeout_ms;
        }
        
 -      function socket($socket, $action) {
 +      function socket($socket, int $action) {
                echo "S";
                
                switch ($action) {
@@@ -80,7 -80,7 +80,7 @@@
                return count($this->client);
        }
        
 -      function wait($timeout_ms = null) {
 +      function wait(int $timeout_ms = null) {
                echo "W";
                
                if ($timeout_ms === null) {
@@@ -124,9 -124,9 +124,9 @@@ include "helper/server.inc"
  
  server("proxy.inc", function($port) {
        $client = new http\Client;
-       $client->configure([
+       $client->configure(array(
                        "use_eventloop" => new UserHandler($client)
-       ]);
+       ));
        $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/"), function($r) {
                var_dump($r->getResponseCode());
        });
diff --combined tests/client029.phpt
index 70f1005e6a3114f19800484d0a409584948c2c79,2ed6d7934c36773a9fdbcd2d635bb4ab84970289..1c8dc4f3528700708d342f08478461847e1fc591
@@@ -7,8 -7,6 +7,8 @@@ skip_client_test()
  _ext("ev");
  
  ?> 
 +--XFAIL--
 +ext-ev leaks
  --FILE--
  <?php 
  echo "Test\n";
@@@ -25,11 -23,11 +25,11 @@@ class UserHandler implements http\Clien
                $this->client = $client;
        }
        
--      function init(callable $run) {
++      function init($run) {
                $this->run = $run;
        }
        
 -      function timer($timeout_ms) {
 +      function timer(int $timeout_ms) {
                echo "T";
                if (isset($this->timeout)) {
                        $this->timeout->set($timeout_ms/1000, 0);
@@@ -46,7 -44,7 +46,7 @@@
                }
        }
        
 -      function socket($socket, $action) {
 +      function socket($socket, int $action) {
                echo "S";
                
                switch ($action) {
@@@ -95,7 -93,7 +95,7 @@@
                throw new BadMethodCallException("this test uses Ev::run()");
        }
        
 -      function wait($timeout_ms = null) {
 +      function wait(int $timeout_ms = null) {
                throw new BadMethodCallException("this test uses Ev::run()");
        }
        
diff --combined tests/gh-issue47.phpt
index 1a09b8d3579dca58b2c05b4211f6c4ce48791ada,3378b628f3382ad4912af6cb13fd2ff0d7db254a..29205ecf16f0a8b763da910c8c36bf490ec50707
@@@ -8,12 -8,12 +8,12 @@@ include "skipif.inc"
  <?php
  echo "Test\n";
  
- $urls = [
+ $urls = array(
      "",
      "? = ="
];
);
  
 -$url0=new http\Url($urls[0]);
 +$url0=new http\Url($urls[0], null, http\Url::FROM_ENV);
  $url1=$url0->mod($urls[1]);
  
  echo $url1;
diff --combined tests/gh-issue50.phpt
index 6cef7d9aef525ab3476976d0333101a879fa6c75,91310cb5094fd6d522bfe4c21a50b2eab5c6ca09..52c764852613e5d4a94e7c8cd7fd5a9a07695fc8
@@@ -30,10 -30,10 +30,10 @@@ try 
  ===DONE===
  --EXPECTF--
  Test
 -exception 'http\Exception\RuntimeException' with message 'http\Client::dequeue(): Could not dequeue request while executing callbacks' in %sgh-issue50.php:9
 +http\Exception\RuntimeException: http\Client::dequeue(): Could not dequeue request while executing callbacks in %sgh-issue50.php:9
  Stack trace:
  #0 %sgh-issue50.php(9): http\Client->dequeue(Object(http\Client\Request))
- #1 [internal function]: {closure}(Object(http\Client), Object(http\Client\Request), 18, 'GET / HTTP/1.1\r...')
+ #1 [internal function]: {closure}(Object(http\Client), Object(http\Client\Request), 18, 'GET / HTTP/1.1%s...')
  #2 %sgh-issue50.php(14): http\Client->send()
  #3 {main}
  ===DONE===