Merge branch 'master' into phpng
authorMichael Wallner <mike@php.net>
Thu, 12 Mar 2015 08:30:46 +0000 (09:30 +0100)
committerMichael Wallner <mike@php.net>
Thu, 12 Mar 2015 08:30:46 +0000 (09:30 +0100)
1  2 
config9.m4
php_http.c
php_http_api.h
php_http_env.c
php_http_env.h
php_http_header_parser.c
php_http_querystring.c
php_http_url.c
tests/querystring003.phpt

diff --combined config9.m4
index 8a1011818c9fd9a00c0f8ae9b60abce5604fe743,02075136667636706976d8274c2af7eefe5099b0..bd5ba2f08feb59dc9ee852cdfff7d16d15fe5947
@@@ -122,6 -122,11 +122,11 @@@ dnl ---
        done
        if test "x$IDNA_DIR" = "x"; then
                AC_MSG_RESULT([not found])
+               case $host_os in
+               darwin*)
+                       AC_CHECK_HEADERS(unicode/uidna.h)
+                       PHP_CHECK_FUNC(uidna_IDNToASCII, icucore);;
+               esac
        else
                AC_MSG_RESULT([found in $IDNA_DIR])
                AC_DEFINE([PHP_HTTP_HAVE_IDN], [1], [Have libidn support])
@@@ -505,12 -510,6 +510,6 @@@ dnl ---
                fi
        ])
  
- dnl ----
- dnl JSON
- dnl ----
-       HTTP_HAVE_PHP_EXT([json])
  dnl ----
  dnl ICONV
  dnl ----
@@@ -555,11 -554,10 +554,10 @@@ dnl ---
        dnl shared extension deps
        HTTP_SHARED_DEP([hash])
        HTTP_SHARED_DEP([iconv])
-       HTTP_SHARED_DEP([json])
        
        dnl extension deps
        PHP_ADD_EXTENSION_DEP([http], [raphf], true)
-       PHP_ADD_EXTENSION_DEP([http], [propo], true)
+       PHP_ADD_EXTENSION_DEP([http], [propro], true)
        
        PHP_SUBST([HTTP_SHARED_LIBADD])
  
        PHP_INSTALL_HEADERS(ext/http, $PHP_HTTP_HEADERS)
  
        AC_DEFINE([HAVE_HTTP], [1], [Have extended HTTP support])
 +      if $HTTP_HAVE_A_REQUEST_LIB; then
 +              AC_DEFINE([PHP_HTTP_HAVE_CLIENT], [1], [Have HTTP client support])
 +      fi
  fi
diff --combined php_http.c
index 98df8433b403f1c3b12113204c660ea00aa97339,bd7baff1078fffbad0a4cb5bd1b3e7be73b6c497..d430e1f13538fce89cfb75a8005e18a0c5e6d6ad
@@@ -44,7 -44,6 +44,6 @@@ zend_function_entry http_functions[] = 
  
  PHP_MINIT_FUNCTION(http);
  PHP_MSHUTDOWN_FUNCTION(http);
- PHP_RINIT_FUNCTION(http);
  PHP_RSHUTDOWN_FUNCTION(http);
  PHP_MINFO_FUNCTION(http);
  
@@@ -57,9 -56,6 +56,6 @@@ static zend_module_dep http_module_deps
  #endif
  #ifdef PHP_HTTP_HAVE_ICONV
        ZEND_MOD_REQUIRED("iconv")
- #endif
- #ifdef PHP_HTTP_HAVE_JSON
-       ZEND_MOD_REQUIRED("json")
  #endif
        {NULL, NULL, NULL, 0}
  };
@@@ -72,7 -68,7 +68,7 @@@ zend_module_entry http_module_entry = 
        http_functions,
        PHP_MINIT(http),
        PHP_MSHUTDOWN(http),
-       PHP_RINIT(http),
+       NULL,
        PHP_RSHUTDOWN(http),
        PHP_MINFO(http),
        PHP_PECL_HTTP_VERSION,
@@@ -117,6 -113,14 +113,6 @@@ static inline void php_http_globals_fre
  }
  #endif
  
 -#if ZTS && PHP_DEBUG && !HAVE_GCOV
 -zend_php_http_globals *php_http_globals(void)
 -{
 -      TSRMLS_FETCH();
 -      return PHP_HTTP_G;
 -}
 -#endif
 -
  PHP_INI_BEGIN()
        STD_PHP_INI_ENTRY("http.etag.mode", "crc32b", PHP_INI_ALL, OnUpdateString, env.etag_mode, zend_php_http_globals, php_http_globals)
  PHP_INI_END()
@@@ -128,7 -132,6 +124,7 @@@ PHP_MINIT_FUNCTION(http
        REGISTER_INI_ENTRIES();
        
        if (0
 +      || SUCCESS != PHP_MINIT_CALL(http_object)
        || SUCCESS != PHP_MINIT_CALL(http_exception)
        || SUCCESS != PHP_MINIT_CALL(http_cookie)
        || SUCCESS != PHP_MINIT_CALL(http_encoding)
@@@ -178,17 -181,6 +174,6 @@@ PHP_MSHUTDOWN_FUNCTION(http
        return SUCCESS;
  }
  
- PHP_RINIT_FUNCTION(http)
- {
-       if (0
-       || SUCCESS != PHP_RINIT_CALL(http_env)
-       ) {
-               return FAILURE;
-       }
-       
-       return SUCCESS;
- }
  PHP_RSHUTDOWN_FUNCTION(http)
  {
        if (0
diff --combined php_http_api.h
index 68fdac88015029a05592dda8732e12d17288a2bb,08b6ba82829520be42d0e8ba15878fb2e3a0a1b1..2313413f30af7761cd216f34bbd45718c8f8df20
@@@ -49,9 -49,7 +49,7 @@@
  #     define PHP_HTTP_HAVE_HASH
  #endif
  
- #if (defined(HAVE_JSON) || defined(PHP_HTTP_HAVE_EXT_JSON)) && (PHP_HTTP_SHARED_DEPS || !defined(COMPILE_DL_JSON))
- #     define PHP_HTTP_HAVE_JSON
- #endif
+ #include <stddef.h>
  
  #ifdef PHP_WIN32
  #     define CURL_STATICLIB
  
  ZEND_BEGIN_MODULE_GLOBALS(php_http)
        struct php_http_env_globals env;
 +#ifdef PHP_HTTP_HAVE_CLIENT
 +      struct {
 +#ifdef PHP_HTTP_HAVE_CURL
 +              struct php_http_client_curl_globals curl;
 +#endif
 +      } client;
 +#endif
  ZEND_END_MODULE_GLOBALS(php_http)
  
  ZEND_EXTERN_MODULE_GLOBALS(php_http);
  
  #ifdef ZTS
  #     include "TSRM/TSRM.h"
 -#     define PHP_HTTP_G ((zend_php_http_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(php_http_globals_id)])
 +#     define PHP_HTTP_G ((zend_php_http_globals *) (*((void ***) tsrm_get_ls_cache()))[TSRM_UNSHUFFLE_RSRC_ID(php_http_globals_id)])
  #     undef TSRMLS_FETCH_FROM_CTX
 -#     define TSRMLS_FETCH_FROM_CTX(ctx) void ***tsrm_ls = ((ctx)?(ctx):ts_resource_ex(0, NULL))
 +#     define TSRMLS_FETCH_FROM_CTX(ctx) ERROR
  #else
  #     define PHP_HTTP_G (&php_http_globals)
  #endif
diff --combined php_http_env.c
index 0ede201e875a349a850f9b443225119c0d248938,c60d4c0b41d42787a682854a70e168700ed62e3f..f5c72d66bd661f50d3c83475d95126bb330fd185
  #include "php_http_api.h"
  #include "php_variables.h"
  
- PHP_RINIT_FUNCTION(http_env)
- {
-       /* populate form data on non-POST requests */
-       if (SG(request_info).request_method && strcasecmp(SG(request_info).request_method, "POST") && SG(request_info).content_type && *SG(request_info).content_type) {
-               uint ct_len = strlen(SG(request_info).content_type);
-               char *ct_str = estrndup(SG(request_info).content_type, ct_len);
-               php_http_params_opts_t opts;
-               HashTable params;
-               php_http_params_opts_default_get(&opts);
-               opts.input.str = ct_str;
-               opts.input.len = ct_len;
-               SG(request_info).content_type_dup = ct_str;
-               ZEND_INIT_SYMTABLE(&params);
-               if (php_http_params_parse(&params, &opts)) {
-                       zend_string *key_str;
-                       zend_ulong key_num;
-                       if (HASH_KEY_IS_STRING == zend_hash_get_current_key(&params, &key_str, &key_num)) {
-                               sapi_post_entry *post_entry = NULL;
-                               if ((post_entry = zend_hash_find_ptr(&SG(known_post_content_types), key_str))) {
-                                       SG(request_info).post_entry = post_entry;
-                                       if (post_entry->post_reader) {
-                                               post_entry->post_reader();
-                                       }
-                                       if (sapi_module.default_post_reader) {
-                                               sapi_module.default_post_reader();
-                                       }
-                                       sapi_handle_post(&PG(http_globals)[TRACK_VARS_POST]);
-                                       /*
-                                        * the rfc1867 handler is an awkward buddy
-                                        * FIXME: this leaks because php_auto_globals_create_files()
-                                        * as well as the rfc1867_handler call
-                                        * array_init(&PG(http_globals)[TRACK_VARS_FILES])
-                                        */
-                                       Z_TRY_ADDREF(PG(http_globals)[TRACK_VARS_FILES]);
-                                       zend_hash_str_update(&EG(symbol_table), "_FILES", lenof("_FILES"), &PG(http_globals)[TRACK_VARS_FILES]);
-                               }
-                       }
-                       zend_hash_destroy(&params);
-               }
-       }
-       PTR_SET(SG(request_info).content_type_dup, NULL);
-       return SUCCESS;
- }
 +
  PHP_RSHUTDOWN_FUNCTION(http_env)
  {
        if (PHP_HTTP_G->env.request.headers) {
@@@ -80,7 -25,7 +26,7 @@@
        }
  
        if (PHP_HTTP_G->env.server_var) {
 -              zval_ptr_dtor(&PHP_HTTP_G->env.server_var);
 +              zval_ptr_dtor(PHP_HTTP_G->env.server_var);
                PHP_HTTP_G->env.server_var = NULL;
        }
  
  
  void php_http_env_get_request_headers(HashTable *headers TSRMLS_DC)
  {
 -      php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
 -      zval **hsv, **header;
 -      HashPosition pos;
 +      php_http_arrkey_t key;
 +      zval *hsv, *header;
  
        if (!PHP_HTTP_G->env.request.headers) {
                ALLOC_HASHTABLE(PHP_HTTP_G->env.request.headers);
 -              zend_hash_init(PHP_HTTP_G->env.request.headers, 0, NULL, ZVAL_PTR_DTOR, 0);
 -
 -              zend_is_auto_global("_SERVER", lenof("_SERVER") TSRMLS_CC);
 +              ZEND_INIT_SYMTABLE(PHP_HTTP_G->env.request.headers);
  
 -              if (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void *) &hsv) && Z_TYPE_PP(hsv) == IS_ARRAY) {
 -                      FOREACH_KEY(pos, *hsv, key) {
 -                              if (key.type == HASH_KEY_IS_STRING && key.len > 6 && *key.str == 'H' && !strncmp(key.str, "HTTP_", 5)) {
 -                                      key.len -= 5;
 -                                      key.str = php_http_pretty_key(estrndup(key.str + 5, key.len - 1), key.len - 1, 1, 1);
 +              if ((hsv = php_http_env_get_superglobal(ZEND_STRL("_SERVER")))) {
 +                      ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(hsv), key.h, key.key, header)
 +                      {
 +                              if (key.key && key.key->len > 5 && *key.key->val == 'H' && !strncmp(key.key->val, "HTTP_", 5)) {
 +                                      size_t key_len = key.key->len - 5;
 +                                      char *key_str = php_http_pretty_key(estrndup(&key.key->val[5], key_len), key_len, 1, 1);
  
 -                                      zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos);
 -                                      Z_ADDREF_P(*header);
 -                                      zend_symtable_update(PHP_HTTP_G->env.request.headers, key.str, key.len, (void *) header, sizeof(zval *), NULL);
 +                                      Z_TRY_ADDREF_P(header);
 +                                      zend_symtable_str_update(PHP_HTTP_G->env.request.headers, key_str, key_len, header);
  
 -                                      efree(key.str);
 -                              } else if (key.type == HASH_KEY_IS_STRING && key.len > 9 && *key.str == 'C' && !strncmp(key.str, "CONTENT_", 8)) {
 -                                      key.str = php_http_pretty_key(estrndup(key.str, key.len - 1), key.len - 1, 1, 1);
 +                                      efree(key_str);
 +                              } else if (key.key && key.key->len > 8 && *key.key->val == 'C' && !strncmp(key.key->val, "CONTENT_", 8)) {
 +                                      char *key_str = php_http_pretty_key(estrndup(key.key->val, key.key->len), key.key->len, 1, 1);
  
 -                                      zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void *) &header, &pos);
 -                                      Z_ADDREF_P(*header);
 -                                      zend_symtable_update(PHP_HTTP_G->env.request.headers, key.str, key.len, (void *) header, sizeof(zval *), NULL);
 +                                      Z_TRY_ADDREF_P(header);
 +                                      zend_symtable_str_update(PHP_HTTP_G->env.request.headers, key_str, key.key->len, header);
  
 -                                      efree(key.str);
 +                                      efree(key_str);
                                }
                        }
 +                      ZEND_HASH_FOREACH_END();
                }
        }
  
        if (headers) {
 -              zend_hash_copy(headers, PHP_HTTP_G->env.request.headers, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
 +              array_copy(PHP_HTTP_G->env.request.headers, headers);
        }
  }
  
 -char *php_http_env_get_request_header(const char *name_str, size_t name_len, size_t *len, php_http_message_t *request TSRMLS_DC)
 +char *php_http_env_get_request_header(const char *name_str, size_t name_len, size_t *len, php_http_message_t *request)
  {
        HashTable *request_headers;
 -      zval **zvalue = NULL;
 +      zval *zvalue = NULL;
        char *val = NULL, *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
  
        if (request) {
                request_headers = &request->hdrs;
        } else {
 -              php_http_env_get_request_headers(NULL TSRMLS_CC);
 +              php_http_env_get_request_headers(NULL);
                request_headers = PHP_HTTP_G->env.request.headers;
        }
  
 -      if (SUCCESS == zend_symtable_find(request_headers, key, name_len + 1, (void *) &zvalue)) {
 -              zval *zcopy = php_http_ztyp(IS_STRING, *zvalue);
 +      if ((zvalue = zend_symtable_str_find(request_headers, key, name_len))) {
 +              zend_string *zs = zval_get_string(zvalue);
  
 -              val = estrndup(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy));
 +              val = estrndup(zs->val, zs->len);
                if (len) {
 -                      *len = Z_STRLEN_P(zcopy);
 +                      *len = zs->len;
                }
 -              zval_ptr_dtor(&zcopy);
 +              zend_string_release(zs);
        }
  
        efree(key);
        return val;
  }
  
 -int php_http_env_got_request_header(const char *name_str, size_t name_len, php_http_message_t *request TSRMLS_DC)
 +zend_bool php_http_env_got_request_header(const char *name_str, size_t name_len, php_http_message_t *request)
  {
        HashTable *request_headers;
        char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
 -      int got;
 +      zend_bool got;
  
        if (request) {
                request_headers = &request->hdrs;
        } else {
 -              php_http_env_get_request_headers(NULL TSRMLS_CC);
 +              php_http_env_get_request_headers(NULL);
                request_headers = PHP_HTTP_G->env.request.headers;
        }
 -      got = zend_symtable_exists(request_headers, key, name_len + 1);
 +      got = zend_symtable_str_exists(request_headers, key, name_len);
        efree(key);
  
        return got;
  }
  
 -zval *php_http_env_get_superglobal(const char *key, size_t key_len TSRMLS_DC)
 +zval *php_http_env_get_superglobal(const char *key, size_t key_len)
  {
 -      zval **hsv;
 +      zval *hsv;
 +      zend_string *key_str = zend_string_init(key, key_len, 0);
  
 -      zend_is_auto_global(key, key_len TSRMLS_CC);
 +      zend_is_auto_global(key_str);
 +      hsv = zend_hash_find(&EG(symbol_table), key_str);
 +      zend_string_release(key_str);
  
 -      if ((SUCCESS != zend_hash_find(&EG(symbol_table), key, key_len + 1, (void *) &hsv)) || (Z_TYPE_PP(hsv) != IS_ARRAY)) {
 +      if (Z_TYPE_P(hsv) != IS_ARRAY) {
                return NULL;
        }
  
 -      return *hsv;
 +      return hsv;
  }
  
 -zval *php_http_env_get_server_var(const char *key, size_t key_len, zend_bool check TSRMLS_DC)
 +zval *php_http_env_get_server_var(const char *key, size_t key_len, zend_bool check)
  {
 -      zval *hsv, **var;
 -      char *env;
 +      zval *hsv, *var;
  
 -      /* if available, this is a lot faster than accessing $_SERVER */
 +      /* if available, this is a lot faster than accessing $_SERVER * /
        if (sapi_module.getenv) {
 -              if ((!(env = sapi_module.getenv((char *) key, key_len TSRMLS_CC))) || (check && !*env)) {
 +              char *env;
 +
 +              if ((!(env = sapi_module.getenv((char *) key, key_len))) || (check && !*env)) {
                        return NULL;
                }
                if (PHP_HTTP_G->env.server_var) {
                ZVAL_STRING(PHP_HTTP_G->env.server_var, env, 1);
                return PHP_HTTP_G->env.server_var;
        }
 +      / * */
  
 -      if (!(hsv = php_http_env_get_superglobal(ZEND_STRL("_SERVER") TSRMLS_CC))) {
 +      if (!(hsv = php_http_env_get_superglobal(ZEND_STRL("_SERVER")))) {
                return NULL;
        }
 -      if ((SUCCESS != zend_symtable_find(Z_ARRVAL_P(hsv), key, key_len + 1, (void *) &var))) {
 +      if (!(var = zend_symtable_str_find(Z_ARRVAL_P(hsv), key, key_len))) {
                return NULL;
        }
 -      if (check && !((Z_TYPE_PP(var) == IS_STRING) && Z_STRVAL_PP(var) && Z_STRLEN_PP(var))) {
 +      if (check && !((Z_TYPE_P(var) == IS_STRING) && Z_STRVAL_P(var) && Z_STRLEN_P(var))) {
                return NULL;
        }
 -      return *var;
 +      return var;
  }
  
 -php_http_message_body_t *php_http_env_get_request_body(TSRMLS_D)
 +php_http_message_body_t *php_http_env_get_request_body(void)
  {
        if (!PHP_HTTP_G->env.request.body) {
                php_stream *s = php_stream_temp_new();
 -#if PHP_VERSION_ID >= 50600
                php_stream *input = php_stream_open_wrapper("php://input", "r", 0, NULL);
  
                /* php://input does not support stat */
                php_stream_copy_to_stream_ex(input, s, -1, NULL);
                php_stream_close(input);
 -#else
 -              if (SG(request_info).post_data || SG(request_info).raw_post_data) {
 -                      /* php://input does not support seek() in PHP <= 5.5 */
 -                      if (SG(request_info).raw_post_data) {
 -                              php_stream_write(s, SG(request_info).raw_post_data, SG(request_info).raw_post_data_length);
 -                      } else {
 -                              php_stream_write(s, SG(request_info).post_data, SG(request_info).post_data_length);
 -                      }
 -              } else if (sapi_module.read_post && !SG(read_post_bytes)) {
 -                      char *buf = emalloc(4096);
 -                      int len;
  
 -                      while (0 < (len = sapi_module.read_post(buf, 4096 TSRMLS_CC))) {
 -                              SG(read_post_bytes) += len;
 -                              php_stream_write(s, buf, len);
 -
 -                              if (len < 4096) {
 -                                      break;
 -                              }
 -                      }
 -                      efree(buf);
 -              }
 -#endif
                php_stream_rewind(s);
 -              PHP_HTTP_G->env.request.body = php_http_message_body_init(NULL, s TSRMLS_CC);
 +              PHP_HTTP_G->env.request.body = php_http_message_body_init(NULL, s);
        }
  
        return PHP_HTTP_G->env.request.body;
  }
  
 -const char *php_http_env_get_request_method(php_http_message_t *request TSRMLS_DC)
 +const char *php_http_env_get_request_method(php_http_message_t *request)
  {
        const char *m;
  
        return m ? m : "GET";
  }
  
 -php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t length, php_http_message_t *request TSRMLS_DC)
 +php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t length, php_http_message_t *request)
  {
 -      zval *zentry;
 +      zval zentry;
        char *range, *rp, c;
        long begin = -1, end = -1, *ptr;
  
 -      if (!(range = php_http_env_get_request_header(ZEND_STRL("Range"), NULL, request TSRMLS_CC))) {
 +      if (!(range = php_http_env_get_request_header(ZEND_STRL("Range"), NULL, request))) {
                return PHP_HTTP_RANGE_NO;
        }
        if (strncmp(range, "bytes=", lenof("bytes="))) {
                                        }
                                }
  
 -                              MAKE_STD_ZVAL(zentry);
 -                              array_init(zentry);
 -                              add_index_long(zentry, 0, begin);
 -                              add_index_long(zentry, 1, end);
 -                              zend_hash_next_index_insert(ranges, &zentry, sizeof(zval *), NULL);
 +                              array_init(&zentry);
 +                              add_index_long(&zentry, 0, begin);
 +                              add_index_long(&zentry, 1, end);
 +                              zend_hash_next_index_insert(ranges, &zentry);
  
                                begin = -1;
                                end = -1;
        return PHP_HTTP_RANGE_OK;
  }
  
 -static void grab_headers(void *data, void *arg TSRMLS_DC)
 +static void grab_headers(void *data, void *arg)
  {
        php_http_buffer_appendl(PHP_HTTP_BUFFER(arg), ((sapi_header_struct *)data)->header);
        php_http_buffer_appends(PHP_HTTP_BUFFER(arg), PHP_HTTP_CRLF);
  }
  
 -ZEND_RESULT_CODE php_http_env_get_response_headers(HashTable *headers_ht TSRMLS_DC)
 +static void grab_header(void *data, void *arg)
 +{
 +      struct {
 +              char *name_str;
 +              size_t name_len;
 +              char *value_ptr;
 +      } *args = arg;
 +      sapi_header_struct *header = data;
 +
 +      if (    header->header_len > args->name_len
 +      && header->header[args->name_len] == ':'
 +      && !strncmp(header->header, args->name_str, args->name_len)
 +      ) {
 +              args->value_ptr = &header->header[args->name_len + 1];
 +              while (PHP_HTTP_IS_CTYPE(space, *args->value_ptr)) {
 +                      ++args->value_ptr;
 +              }
 +      }
 +}
 +
 +ZEND_RESULT_CODE php_http_env_get_response_headers(HashTable *headers_ht)
  {
        ZEND_RESULT_CODE status;
        php_http_buffer_t headers;
  
        php_http_buffer_init(&headers);
 -      zend_llist_apply_with_argument(&SG(sapi_headers).headers, grab_headers, &headers TSRMLS_CC);
 +      zend_llist_apply_with_argument(&SG(sapi_headers).headers, grab_headers, &headers);
        php_http_buffer_fix(&headers);
  
 -      status = php_http_header_parse(headers.data, headers.used, headers_ht, NULL, NULL TSRMLS_CC);
 +      status = php_http_header_parse(headers.data, headers.used, headers_ht, NULL, NULL);
        php_http_buffer_dtor(&headers);
  
        return status;
  }
  
 -char *php_http_env_get_response_header(const char *name_str, size_t name_len TSRMLS_DC)
 +char *php_http_env_get_response_header(const char *name_str, size_t name_len)
  {
 -      char *val = NULL;
 -      HashTable headers;
 +      struct {
 +              char *name_str;
 +              size_t name_len;
 +              char *value_ptr;
 +      } args;
  
 -      zend_hash_init(&headers, 0, NULL, ZVAL_PTR_DTOR, 0);
 -      if (SUCCESS == php_http_env_get_response_headers(&headers TSRMLS_CC)) {
 -              zval **zvalue;
 -              char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
 +      args.name_str = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
 +      args.name_len = name_len;
 +      args.value_ptr = NULL;
 +      zend_llist_apply_with_argument(&SG(sapi_headers).headers, grab_header, &args);
 +      efree(args.name_str);
  
 -              if (SUCCESS == zend_symtable_find(&headers, key, name_len + 1, (void *) &zvalue)) {
 -                      zval *zcopy = php_http_ztyp(IS_STRING, *zvalue);
 -
 -                      val = estrndup(Z_STRVAL_P(zcopy), Z_STRLEN_P(zcopy));
 -                      zval_ptr_dtor(&zcopy);
 -              }
 -
 -              efree(key);
 -      }
 -      zend_hash_destroy(&headers);
 -
 -      return val;
 +      return args.value_ptr ? estrdup(args.value_ptr) : NULL;
  }
  
 -long php_http_env_get_response_code(TSRMLS_D)
 +long php_http_env_get_response_code(void)
  {
        long code = SG(sapi_headers).http_response_code;
        return code ? code : 200;
  }
  
 -ZEND_RESULT_CODE php_http_env_set_response_code(long http_code TSRMLS_DC)
 +ZEND_RESULT_CODE php_http_env_set_response_code(long http_code)
  {
 -      return sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) http_code TSRMLS_CC);
 +      return sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) (zend_intptr_t) http_code);
  }
  
 -ZEND_RESULT_CODE php_http_env_set_response_status_line(long code, php_http_version_t *v TSRMLS_DC)
 +ZEND_RESULT_CODE php_http_env_set_response_status_line(long code, php_http_version_t *v)
  {
        sapi_header_line h = {NULL, 0, 0};
        ZEND_RESULT_CODE ret;
  
        h.line_len = spprintf(&h.line, 0, "HTTP/%u.%u %ld %s", v->major, v->minor, code, php_http_env_get_response_status_for_code(code));
 -      ret = sapi_header_op(SAPI_HEADER_REPLACE, (void *) &h TSRMLS_CC);
 +      ret = sapi_header_op(SAPI_HEADER_REPLACE, (void *) &h);
        efree(h.line);
  
        return ret;
  }
  
 -ZEND_RESULT_CODE php_http_env_set_response_protocol_version(php_http_version_t *v TSRMLS_DC)
 +ZEND_RESULT_CODE php_http_env_set_response_protocol_version(php_http_version_t *v)
  {
 -      return php_http_env_set_response_status_line(php_http_env_get_response_code(TSRMLS_C), v TSRMLS_CC);
 +      return php_http_env_set_response_status_line(php_http_env_get_response_code(), v);
  }
  
 -ZEND_RESULT_CODE php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace TSRMLS_DC)
 +ZEND_RESULT_CODE php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace)
  {
        sapi_header_line h = {estrndup(header_str, header_len), header_len, http_code};
 -      ZEND_RESULT_CODE ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC);
 +      ZEND_RESULT_CODE ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h);
++
        efree(h.line);
        return ret;
  }
  
 -ZEND_RESULT_CODE php_http_env_set_response_header_va(long http_code, zend_bool replace, const char *fmt, va_list argv TSRMLS_DC)
 +ZEND_RESULT_CODE php_http_env_set_response_header_va(long http_code, zend_bool replace, const char *fmt, va_list argv)
  {
        ZEND_RESULT_CODE ret = FAILURE;
        sapi_header_line h = {NULL, 0, http_code};
  
        if (h.line) {
                if (h.line_len) {
 -                      ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC);
 +                      ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h);
                }
                efree(h.line);
        }
        return ret;
  }
  
 -ZEND_RESULT_CODE php_http_env_set_response_header_format(long http_code, zend_bool replace TSRMLS_DC, const char *fmt, ...)
 +ZEND_RESULT_CODE php_http_env_set_response_header_format(long http_code, zend_bool replace, const char *fmt, ...)
  {
        ZEND_RESULT_CODE ret;
        va_list args;
  
        va_start(args, fmt);
 -      ret = php_http_env_set_response_header_va(http_code, replace, fmt, args TSRMLS_CC);
 +      ret = php_http_env_set_response_header_va(http_code, replace, fmt, args);
        va_end(args);
  
        return ret;
  }
  
 -ZEND_RESULT_CODE php_http_env_set_response_header_value(long http_code, const char *name_str, size_t name_len, zval *value, zend_bool replace TSRMLS_DC)
 +ZEND_RESULT_CODE php_http_env_set_response_header_value(long http_code, const char *name_str, size_t name_len, zval *value, zend_bool replace)
  {
        if (!value) {
                sapi_header_line h = {(char *) name_str, name_len, http_code};
  
 -              return sapi_header_op(SAPI_HEADER_DELETE, (void *) &h TSRMLS_CC);
 +              return sapi_header_op(SAPI_HEADER_DELETE, (void *) &h);
        }
  
 -      if(Z_TYPE_P(value) == IS_ARRAY || Z_TYPE_P(value) == IS_OBJECT) {
 -              HashPosition pos;
 +      if (Z_TYPE_P(value) == IS_ARRAY || Z_TYPE_P(value) == IS_OBJECT) {
                int first = replace;
 -              zval **data_ptr;
 +              zval *data_ptr;
 +              HashTable *ht = HASH_OF(value);
  
 -              FOREACH_HASH_VAL(pos, HASH_OF(value), data_ptr) {
 -                      if (SUCCESS != php_http_env_set_response_header_value(http_code, name_str, name_len, *data_ptr, first TSRMLS_CC)) {
 +              ZEND_HASH_FOREACH_VAL_IND(ht, data_ptr)
 +              {
 +                      if (SUCCESS != php_http_env_set_response_header_value(http_code, name_str, name_len, data_ptr, first)) {
                                return FAILURE;
                        }
                        first = 0;
                }
 +              ZEND_HASH_FOREACH_END();
  
                return SUCCESS;
        } else {
 -              zval *data = php_http_ztyp(IS_STRING, value);
 +              zend_string *data = zval_get_string(value);
  
 -              if (!Z_STRLEN_P(data)) {
 -                      zval_ptr_dtor(&data);
 -                      return php_http_env_set_response_header_value(http_code, name_str, name_len, NULL, replace TSRMLS_CC);
 +              if (!data->len) {
 +                      zend_string_release(data);
 +                      return php_http_env_set_response_header_value(http_code, name_str, name_len, NULL, replace);
                } else {
                        sapi_header_line h;
                        ZEND_RESULT_CODE ret;
  
                        if (name_len > INT_MAX) {
 -                              name_len = INT_MAX;
 +                              return FAILURE;
                        }
                        h.response_code = http_code;
 -                      h.line_len = spprintf(&h.line, 0, "%.*s: %.*s", (int) name_len, name_str, Z_STRLEN_P(data), Z_STRVAL_P(data));
 +                      h.line_len = spprintf(&h.line, 0, "%.*s: %.*s", (int) name_len, name_str, data->len, data->val);
  
 -                      ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h TSRMLS_CC);
 +                      ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h);
  
 -                      zval_ptr_dtor(&data);
 +                      zend_string_release(data);
                        PTR_FREE(h.line);
  
                        return ret;
@@@ -583,21 -535,21 +530,21 @@@ ZEND_END_ARG_INFO()
  static PHP_METHOD(HttpEnv, getRequestHeader)
  {
        char *header_name_str = NULL;
 -      int header_name_len = 0;
 +      size_t header_name_len = 0;
  
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &header_name_str, &header_name_len)) {
                return;
        }
        if (header_name_str && header_name_len) {
                size_t header_length;
 -              char *header_value = php_http_env_get_request_header(header_name_str, header_name_len, &header_length, NULL TSRMLS_CC);
 +              char *header_value = php_http_env_get_request_header(header_name_str, header_name_len, &header_length, NULL);
  
                if (header_value) {
 -                      RETURN_STRINGL(header_value, header_length, 0);
 +                      RETURN_STR(php_http_cs2zs(header_value, header_length));
                }
        } else {
                array_init(return_value);
 -              php_http_env_get_request_headers(Z_ARRVAL_P(return_value) TSRMLS_CC);
 +              php_http_env_get_request_headers(Z_ARRVAL_P(return_value));
        }
  }
  
@@@ -606,16 -558,16 +553,16 @@@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getRe
  ZEND_END_ARG_INFO();
  static PHP_METHOD(HttpEnv, getRequestBody)
  {
 -      zend_object_value ov;
        php_http_message_body_t *body;
 +      php_http_message_body_object_t *body_obj;
        zend_class_entry *class_entry = php_http_message_body_class_entry;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &class_entry), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &class_entry), invalid_arg, return);
  
 -      body = php_http_env_get_request_body(TSRMLS_C);
 -      if (SUCCESS == php_http_new(&ov, class_entry, (php_http_new_t) php_http_message_body_object_new_ex, php_http_message_body_class_entry, body, NULL TSRMLS_CC)) {
 +      body = php_http_env_get_request_body();
 +      if (SUCCESS == php_http_new((void *) &body_obj, class_entry, (php_http_new_t) php_http_message_body_object_new_ex, php_http_message_body_class_entry, body)) {
                php_http_message_body_addref(body);
 -              RETVAL_OBJVAL(ov, 0);
 +              RETVAL_OBJ(&body_obj->zo);
        }
  }
  
@@@ -624,7 -576,7 +571,7 @@@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getRe
  ZEND_END_ARG_INFO();
  static PHP_METHOD(HttpEnv, getResponseStatusForCode)
  {
 -      long code;
 +      zend_long code;
        const char *status;
  
        if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
        }
  
        if ((status = php_http_env_get_response_status_for_code(code))) {
 -              RETURN_STRING(status, 1);
 +              RETURN_STRING(status);
        }
  }
  
@@@ -645,7 -597,7 +592,7 @@@ static PHP_METHOD(HttpEnv, getResponseS
        }
  
        array_init(return_value);
 -#define PHP_HTTP_RESPONSE_CODE(code, status) add_index_string(return_value, code, status, 1);
 +#define PHP_HTTP_RESPONSE_CODE(code, status) add_index_string(return_value, code, status);
  #include "php_http_response_codes.h"
  #undef PHP_HTTP_RESPONSE_CODE
  }
@@@ -656,20 -608,20 +603,20 @@@ ZEND_END_ARG_INFO()
  static PHP_METHOD(HttpEnv, getResponseHeader)
  {
        char *header_name_str = NULL;
 -      int header_name_len = 0;
 +      size_t header_name_len = 0;
  
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &header_name_str, &header_name_len)) {
                return;
        }
        if (header_name_str && header_name_len) {
 -              char *header_value = php_http_env_get_response_header(header_name_str, header_name_len TSRMLS_CC);
 +              char *header_value = php_http_env_get_response_header(header_name_str, header_name_len);
  
                if (header_value) {
 -                      RETURN_STRING(header_value, 0);
 +                      RETURN_STR(php_http_cs2zs(header_value, strlen(header_value)));
                }
        } else {
                array_init(return_value);
 -              php_http_env_get_response_headers(Z_ARRVAL_P(return_value) TSRMLS_CC);
 +              php_http_env_get_response_headers(Z_ARRVAL_P(return_value));
        }
  }
  
@@@ -680,7 -632,7 +627,7 @@@ static PHP_METHOD(HttpEnv, getResponseC
        if (SUCCESS != zend_parse_parameters_none()) {
                return;
        }
 -      RETURN_LONG(php_http_env_get_response_code(TSRMLS_C));
 +      RETURN_LONG(php_http_env_get_response_code());
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_setResponseHeader, 0, 0, 1)
@@@ -692,15 -644,15 +639,15 @@@ ZEND_END_ARG_INFO()
  static PHP_METHOD(HttpEnv, setResponseHeader)
  {
        char *header_name_str;
 -      int header_name_len;
 +      size_t header_name_len;
        zval *header_value = NULL;
 -      long code = 0;
 +      zend_long code = 0;
        zend_bool replace_header = 1;
  
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!lb", &header_name_str, &header_name_len, &header_value, &code, &replace_header)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!lb", &header_name_str, &header_name_len, &header_value, &code, &replace_header)) {
                return;
        }
 -      RETURN_BOOL(SUCCESS == php_http_env_set_response_header_value(code, header_name_str, header_name_len, header_value, replace_header TSRMLS_CC));
 +      RETURN_BOOL(SUCCESS == php_http_env_set_response_header_value(code, header_name_str, header_name_len, header_value, replace_header));
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_setResponseCode, 0, 0, 1)
  ZEND_END_ARG_INFO();
  static PHP_METHOD(HttpEnv, setResponseCode)
  {
 -      long code;
 +      zend_long code;
  
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &code)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l", &code)) {
                return;
        }
 -      RETURN_BOOL(SUCCESS == php_http_env_set_response_code(code TSRMLS_CC));
 +      RETURN_BOOL(SUCCESS == php_http_env_set_response_code(code));
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateLanguage, 0, 0, 1)
@@@ -729,7 -681,6 +676,7 @@@ static PHP_METHOD(HttpEnv, negotiateLan
                return;
        }
        if (rs_array) {
 +              ZVAL_DEREF(rs_array);
                zval_dtor(rs_array);
                array_init(rs_array);
        }
@@@ -746,11 -697,10 +693,11 @@@ static PHP_METHOD(HttpEnv, negotiateCha
        HashTable *supported;
        zval *rs_array = NULL;
  
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "H|z", &supported, &rs_array)) {
                return;
        }
        if (rs_array) {
 +              ZVAL_DEREF(rs_array);
                zval_dtor(rs_array);
                array_init(rs_array);
        }
@@@ -766,11 -716,10 +713,11 @@@ static PHP_METHOD(HttpEnv, negotiateEnc
        HashTable *supported;
        zval *rs_array = NULL;
  
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "H|z", &supported, &rs_array)) {
                return;
        }
        if (rs_array) {
 +              ZVAL_DEREF(rs_array);
                zval_dtor(rs_array);
                array_init(rs_array);
        }
@@@ -786,11 -735,10 +733,11 @@@ static PHP_METHOD(HttpEnv, negotiateCon
        HashTable *supported;
        zval *rs_array = NULL;
  
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "H|z", &supported, &rs_array)) {
                return;
        }
        if (rs_array) {
 +              ZVAL_DEREF(rs_array);
                zval_dtor(rs_array);
                array_init(rs_array);
        }
@@@ -808,19 -756,19 +755,19 @@@ static PHP_METHOD(HttpEnv, negotiate
        HashTable *supported, *rs;
        zval *rs_array = NULL;
        char *value_str, *sep_str = NULL;
 -      int value_len, sep_len = 0;
 +      size_t value_len, sep_len = 0;
  
        if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sH|s!z", &value_str, &value_len, &supported, &sep_str, &sep_len, &rs_array)) {
                return;
        }
  
 -
        if (rs_array) {
 +              ZVAL_DEREF(rs_array);
                zval_dtor(rs_array);
                array_init(rs_array);
        }
  
 -      if ((rs = php_http_negotiate(value_str, value_len, supported, sep_str, sep_len TSRMLS_CC))) {
 +      if ((rs = php_http_negotiate(value_str, value_len, supported, sep_str, sep_len))) {
                PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs, supported, rs_array);
        } else {
                PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array);
@@@ -848,53 -796,6 +795,6 @@@ static zend_function_entry php_http_env
        EMPTY_FUNCTION_ENTRY
  };
  
- #ifdef PHP_HTTP_HAVE_JSON
- #include "ext/json/php_json.h"
- static SAPI_POST_HANDLER_FUNC(php_http_json_post_handler)
- {
-       zval *zarg = arg;
-       zend_string *json = NULL;
-       if (SG(request_info).request_body) {
-               /* FG(stream_wrappers) not initialized yet, so we cannot use php://input */
-               php_stream_rewind(SG(request_info).request_body);
-               json = php_stream_copy_to_mem(SG(request_info).request_body, PHP_STREAM_COPY_ALL, 0);
-       }
-       if (json) {
-               if (json->len) {
-                       zval tmp;
-                       ZVAL_NULL(&tmp);
-                       php_json_decode(&tmp, json->val, json->len, 1, PG(max_input_nesting_level));
-                       if (Z_TYPE(tmp) == IS_ARRAY) {
-                               array_copy(Z_ARRVAL(tmp), Z_ARRVAL_P(zarg));
-                       }
-                       zval_ptr_dtor(&tmp);
-               }
-               zend_string_release(json);
-       }
- }
- static void php_http_env_register_json_handler(void)
- {
-       sapi_post_entry entry = {NULL, 0, NULL, NULL};
-       entry.post_reader = sapi_read_standard_form_data;
-       entry.post_handler = php_http_json_post_handler;
-       entry.content_type = "text/json";
-       entry.content_type_len = lenof("text/json");
-       sapi_register_post_entry(&entry);
-       entry.content_type = "application/json";
-       entry.content_type_len = lenof("application/json");
-       sapi_register_post_entry(&entry);
- }
- #endif
  zend_class_entry *php_http_env_class_entry;
  
  PHP_MINIT_FUNCTION(http_env)
        zend_class_entry ce = {0};
  
        INIT_NS_CLASS_ENTRY(ce, "http", "Env", php_http_env_methods);
 -      php_http_env_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
 +      php_http_env_class_entry = zend_register_internal_class(&ce);
  
- #ifdef PHP_HTTP_HAVE_JSON
-       php_http_env_register_json_handler();
- #endif
        return SUCCESS;
  }
  
diff --combined php_http_env.h
index 1cb302d13a3665cd11613e33f06e4765242b37b7,3fc80aba1e489bbb821a33b9e331eeea96ba2a20..273ba16c4ffa9c0481184d41a2ff8cda46ab9ca0
@@@ -37,12 -37,12 +37,12 @@@ typedef enum php_http_range_status 
        PHP_HTTP_RANGE_ERR
  } php_http_range_status_t;
  
 -PHP_HTTP_API php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t entity_length, php_http_message_t *request TSRMLS_DC);
 -PHP_HTTP_API void php_http_env_get_request_headers(HashTable *headers TSRMLS_DC);
 -PHP_HTTP_API char *php_http_env_get_request_header(const char *name_str, size_t name_len, size_t *len, php_http_message_t *request TSRMLS_DC);
 -PHP_HTTP_API int php_http_env_got_request_header(const char *name_str, size_t name_len, php_http_message_t *request TSRMLS_DC);
 -PHP_HTTP_API php_http_message_body_t *php_http_env_get_request_body(TSRMLS_D);
 -PHP_HTTP_API const char *php_http_env_get_request_method(php_http_message_t *request TSRMLS_DC);
 +PHP_HTTP_API php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t entity_length, php_http_message_t *request);
 +PHP_HTTP_API void php_http_env_get_request_headers(HashTable *headers);
 +PHP_HTTP_API char *php_http_env_get_request_header(const char *name_str, size_t name_len, size_t *len, php_http_message_t *request);
 +PHP_HTTP_API zend_bool php_http_env_got_request_header(const char *name_str, size_t name_len, php_http_message_t *request);
 +PHP_HTTP_API php_http_message_body_t *php_http_env_get_request_body(void);
 +PHP_HTTP_API const char *php_http_env_get_request_method(php_http_message_t *request);
  
  typedef enum php_http_content_disposition {
        PHP_HTTP_CONTENT_DISPOSITION_NONE,
@@@ -56,28 -56,23 +56,28 @@@ typedef enum php_http_cache_status 
        PHP_HTTP_CACHE_MISS
  } php_http_cache_status_t;
  
 -PHP_HTTP_API long php_http_env_get_response_code(TSRMLS_D);
 +PHP_HTTP_API long php_http_env_get_response_code(void);
  PHP_HTTP_API const char *php_http_env_get_response_status_for_code(unsigned code);
 -PHP_HTTP_API ZEND_RESULT_CODE php_http_env_get_response_headers(HashTable *headers_ht TSRMLS_DC);
 -PHP_HTTP_API char *php_http_env_get_response_header(const char *name_str, size_t name_len TSRMLS_DC);
 -PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_code(long http_code TSRMLS_DC);
 -PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_protocol_version(php_http_version_t *v TSRMLS_DC);
 -PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace TSRMLS_DC);
 -PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header_value(long http_code, const char *name_str, size_t name_len, zval *value, zend_bool replace TSRMLS_DC);
 -PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header_format(long http_code, zend_bool replace TSRMLS_DC, const char *fmt, ...);
 -PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header_va(long http_code, zend_bool replace, const char *fmt, va_list argv TSRMLS_DC);
 -
 -PHP_HTTP_API zval *php_http_env_get_server_var(const char *key_str, size_t key_len, zend_bool check TSRMLS_DC);
 -#define php_http_env_got_server_var(v) (NULL != php_http_env_get_server_var((v), strlen(v), 1 TSRMLS_CC))
 -PHP_HTTP_API zval *php_http_env_get_superglobal(const char *key, size_t key_len TSRMLS_DC);
 +PHP_HTTP_API ZEND_RESULT_CODE php_http_env_get_response_headers(HashTable *headers_ht);
 +PHP_HTTP_API char *php_http_env_get_response_header(const char *name_str, size_t name_len);
 +PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_code(long http_code);
 +PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_protocol_version(php_http_version_t *v);
 +PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace);
 +PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header_value(long http_code, const char *name_str, size_t name_len, zval *value, zend_bool replace);
 +PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header_format(long http_code, zend_bool replace, const char *fmt, ...);
 +PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header_va(long http_code, zend_bool replace, const char *fmt, va_list argv);
 +
 +PHP_HTTP_API zval *php_http_env_get_server_var(const char *key_str, size_t key_len, zend_bool check);
 +PHP_HTTP_API zval *php_http_env_get_superglobal(const char *key, size_t key_len);
 +
 +static inline zend_bool php_http_env_got_server_var(const char *v)
 +{
 +      return NULL != php_http_env_get_server_var(v, strlen(v), 1);
 +}
 +
  PHP_HTTP_API zend_class_entry *php_http_env_class_entry;
  PHP_MINIT_FUNCTION(http_env);
- PHP_RINIT_FUNCTION(http_env);
  PHP_RSHUTDOWN_FUNCTION(http_env);
  
  #endif
diff --combined php_http_header_parser.c
index cf30c84c48bc5ba0be2415a9a5572224adcfa940,2fbcb9394dbae1f5cd8761468ae4ff7799f988f4..f4dcf95e9e63828d9b43db7accd9024e28d8cf82
@@@ -30,13 -30,15 +30,13 @@@ static const php_http_header_parser_sta
                {PHP_HTTP_HEADER_PARSER_STATE_DONE,                     0}
  };
  
 -php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t *parser TSRMLS_DC)
 +php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t *parser)
  {
        if (!parser) {
                parser = emalloc(sizeof(*parser));
        }
        memset(parser, 0, sizeof(*parser));
  
 -      TSRMLS_SET_CTX(parser->ts);
 -
        return parser;
  }
  
@@@ -95,18 -97,19 +95,18 @@@ void php_http_header_parser_free(php_ht
  }
  
  /* NOTE: 'str' has to be null terminated */
 -static void php_http_header_parser_error(size_t valid_len, char *str, size_t len, const char *eol_str TSRMLS_DC)
 +static void php_http_header_parser_error(size_t valid_len, char *str, size_t len, const char *eol_str )
  {
 -      int escaped_len;
 -      char *escaped_str;
 +      zend_string *escaped_str = zend_string_init(str, len, 0);
  
 -      escaped_str = php_addcslashes(str, len, &escaped_len, 0, ZEND_STRL("\x0..\x1F\x7F..\xFF") TSRMLS_CC);
 +      escaped_str = php_addcslashes(escaped_str, 1, ZEND_STRL("\x0..\x1F\x7F..\xFF"));
  
        if (valid_len != len && (!eol_str || (str+valid_len) != eol_str)) {
 -              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse headers: unexpected character '\\%03o' at pos %zu of '%.*s'", str[valid_len], valid_len, escaped_len, escaped_str);
 +              php_error_docref(NULL, E_WARNING, "Failed to parse headers: unexpected character '\\%03o' at pos %zu of '%s'", str[valid_len], valid_len, escaped_str->val);
        } else if (eol_str) {
 -              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse headers: unexpected end of line at pos %zu of '%.*s'", eol_str - str, escaped_len, escaped_str);
 +              php_error_docref(NULL, E_WARNING, "Failed to parse headers: unexpected end of line at pos %zu of '%s'", eol_str - str, escaped_str->val);
        } else {
 -              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse headers: unexpected end of input at pos %zu of '%.*s'", len, escaped_len, escaped_str);
 +              php_error_docref(NULL, E_WARNING, "Failed to parse headers: unexpected end of input at pos %zu of '%s'", len, escaped_str->val);
        }
  
        efree(escaped_str);
  
  php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg)
  {
 -      TSRMLS_FETCH_FROM_CTX(parser->ts);
 -
        while (buffer->used || !php_http_header_parser_states[php_http_header_parser_state_is(parser)].need_data) {
  #if DBG_PARSER
                const char *state[] = {"START", "KEY", "VALUE", "VALUE_EX", "HEADER_DONE", "DONE"};
                                        /* end of headers */
                                        php_http_buffer_cut(buffer, 0, eol_len);
                                        php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_DONE);
 -                              } else if (php_http_info_parse(&parser->info, php_http_buffer_fix(buffer)->data TSRMLS_CC)) {
 +                              } else if (php_http_info_parse(&parser->info, php_http_buffer_fix(buffer)->data)) {
                                        /* new message starting with request/response line */
                                        if (callback_func) {
 -                                              callback_func(callback_arg, &headers, &parser->info TSRMLS_CC);
 +                                              callback_func(callback_arg, &headers, &parser->info);
                                        }
                                        php_http_info_dtor(&parser->info);
                                        php_http_buffer_cut(buffer, 0, eol_str + eol_len - buffer->data);
  
                        case PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE:
                                if (parser->_key.str && parser->_val.str) {
 -                                      zval array, **exist;
 +                                      zval tmp, *exist;
                                        size_t valid_len = strlen(parser->_val.str);
  
                                        /* check for truncation */
                                        }
  
                                        if (!headers && callback_func) {
 -                                              callback_func(callback_arg, &headers, NULL TSRMLS_CC);
 +                                              callback_func(callback_arg, &headers, NULL);
                                        }
  
 -                                      INIT_PZVAL_ARRAY(&array, headers);
                                        php_http_pretty_key(parser->_key.str, parser->_key.len, 1, 1);
 -                                      if (SUCCESS == zend_symtable_find(headers, parser->_key.str, parser->_key.len + 1, (void *) &exist)) {
 -                                              convert_to_array(*exist);
 -                                              add_next_index_stringl(*exist, parser->_val.str, parser->_val.len, 0);
 +                                      if ((exist = zend_symtable_str_find(headers, parser->_key.str, parser->_key.len))) {
 +                                              convert_to_array(exist);
 +                                              add_next_index_str(exist, php_http_cs2zs(parser->_val.str, parser->_val.len));
                                        } else {
 -                                              add_assoc_stringl_ex(&array, parser->_key.str, parser->_key.len + 1, parser->_val.str, parser->_val.len, 0);
 +                                              ZVAL_STR(&tmp, php_http_cs2zs(parser->_val.str, parser->_val.len));
 +                                              zend_symtable_str_update(headers, parser->_key.str, parser->_key.len, &tmp);
                                        }
                                        parser->_val.str = NULL;
                                }
  
  php_http_header_parser_state_t php_http_header_parser_parse_stream(php_http_header_parser_t *parser, php_http_buffer_t *buf, php_stream *s, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg)
  {
-       php_http_message_parser_state_t state = PHP_HTTP_MESSAGE_PARSER_STATE_START;
+       php_http_header_parser_state_t state = PHP_HTTP_HEADER_PARSER_STATE_START;
        TSRMLS_FETCH_FROM_CTX(parser->ts);
  
        if (!buf->data) {
  zend_class_entry *php_http_header_parser_class_entry;
  static zend_object_handlers php_http_header_parser_object_handlers;
  
 -zend_object_value php_http_header_parser_object_new(zend_class_entry *ce TSRMLS_DC)
 +zend_object *php_http_header_parser_object_new(zend_class_entry *ce)
  {
 -      return php_http_header_parser_object_new_ex(ce, NULL, NULL TSRMLS_CC);
 +      return &php_http_header_parser_object_new_ex(ce, NULL)->zo;
  }
  
 -zend_object_value php_http_header_parser_object_new_ex(zend_class_entry *ce, php_http_header_parser_t *parser, php_http_header_parser_object_t **ptr TSRMLS_DC)
 +php_http_header_parser_object_t *php_http_header_parser_object_new_ex(zend_class_entry *ce, php_http_header_parser_t *parser)
  {
        php_http_header_parser_object_t *o;
  
 -      o = ecalloc(1, sizeof(php_http_header_parser_object_t));
 -      zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
 -      object_properties_init((zend_object *) o, ce);
 -
 -      if (ptr) {
 -              *ptr = o;
 -      }
 +      o = ecalloc(1, sizeof(php_http_header_parser_object_t) + zend_object_properties_size(ce));
 +      zend_object_std_init(&o->zo, ce);
 +      object_properties_init(&o->zo, ce);
  
        if (parser) {
                o->parser = parser;
        } else {
 -              o->parser = php_http_header_parser_init(NULL TSRMLS_CC);
 +              o->parser = php_http_header_parser_init(NULL);
        }
        o->buffer = php_http_buffer_new();
  
 -      o->zv.handle = zend_objects_store_put((zend_object *) o, NULL, php_http_header_parser_object_free, NULL TSRMLS_CC);
 -      o->zv.handlers = &php_http_header_parser_object_handlers;
 +      o->zo.handlers = &php_http_header_parser_object_handlers;
  
 -      return o->zv;
 +      return o;
  }
  
 -void php_http_header_parser_object_free(void *object TSRMLS_DC)
 +void php_http_header_parser_object_free(zend_object *object)
  {
 -      php_http_header_parser_object_t *o = (php_http_header_parser_object_t *) object;
 +      php_http_header_parser_object_t *o = PHP_HTTP_OBJ(object, NULL);
  
        if (o->parser) {
                php_http_header_parser_free(&o->parser);
        if (o->buffer) {
                php_http_buffer_free(&o->buffer);
        }
 -      zend_object_std_dtor((zend_object *) o TSRMLS_CC);
 -      efree(o);
 +      zend_object_std_dtor(object);
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeaderParser_getState, 0, 0, 0)
  ZEND_END_ARG_INFO();
  static PHP_METHOD(HttpHeaderParser, getState)
  {
 -      php_http_header_parser_object_t *parser_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +      php_http_header_parser_object_t *parser_obj = PHP_HTTP_OBJ(NULL, getThis());
  
        zend_parse_parameters_none();
        /* always return the real state */
@@@ -394,17 -405,16 +394,17 @@@ static PHP_METHOD(HttpHeaderParser, par
        php_http_header_parser_object_t *parser_obj;
        zval *zmsg;
        char *data_str;
 -      int data_len;
 -      long flags;
 +      size_t data_len;
 +      zend_long flags;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "slz", &data_str, &data_len, &flags, &zmsg), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "slz", &data_str, &data_len, &flags, &zmsg), invalid_arg, return);
  
 +      ZVAL_DEREF(zmsg);
        if (Z_TYPE_P(zmsg) != IS_ARRAY) {
                zval_dtor(zmsg);
                array_init(zmsg);
        }
 -      parser_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +      parser_obj = PHP_HTTP_OBJ(NULL, getThis());
        php_http_buffer_append(parser_obj->buffer, data_str, data_len);
        RETVAL_LONG(php_http_header_parser_parse(parser_obj->parser, parser_obj->buffer, flags, Z_ARRVAL_P(zmsg), NULL, NULL));
  }
@@@ -420,20 -430,19 +420,20 @@@ static PHP_METHOD(HttpHeaderParser, str
        zend_error_handling zeh;
        zval *zmsg, *zstream;
        php_stream *s;
 -      long flags;
 +      zend_long flags;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &zstream, &flags, &zmsg), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "rlz", &zstream, &flags, &zmsg), invalid_arg, return);
  
 -      zend_replace_error_handling(EH_THROW, php_http_exception_unexpected_val_class_entry, &zeh TSRMLS_CC);
 -      php_stream_from_zval(s, &zstream);
 -      zend_restore_error_handling(&zeh TSRMLS_CC);
 +      zend_replace_error_handling(EH_THROW, php_http_exception_unexpected_val_class_entry, &zeh);
 +      php_stream_from_zval(s, zstream);
 +      zend_restore_error_handling(&zeh);
  
 +      ZVAL_DEREF(zmsg);
        if (Z_TYPE_P(zmsg) != IS_ARRAY) {
                zval_dtor(zmsg);
                array_init(zmsg);
        }
 -      parser_obj = zend_object_store_get_object(getThis() TSRMLS_CC);
 +      parser_obj = PHP_HTTP_OBJ(NULL, getThis());
        RETVAL_LONG(php_http_header_parser_parse_stream(parser_obj->parser, parser_obj->buffer, s, flags, Z_ARRVAL_P(zmsg), NULL, NULL));
  }
  
@@@ -449,22 -458,20 +449,22 @@@ PHP_MINIT_FUNCTION(http_header_parser
        zend_class_entry ce;
  
        INIT_NS_CLASS_ENTRY(ce, "http\\Header", "Parser", php_http_header_parser_methods);
 -      php_http_header_parser_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
 +      php_http_header_parser_class_entry = zend_register_internal_class(&ce);
        memcpy(&php_http_header_parser_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
        php_http_header_parser_class_entry->create_object = php_http_header_parser_object_new;
 +      php_http_header_parser_object_handlers.offset = XtOffsetOf(php_http_header_parser_object_t, zo);
        php_http_header_parser_object_handlers.clone_obj = NULL;
 +      php_http_header_parser_object_handlers.free_obj = php_http_header_parser_object_free;
  
 -      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("CLEANUP"), PHP_HTTP_HEADER_PARSER_CLEANUP TSRMLS_CC);
 +      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("CLEANUP"), PHP_HTTP_HEADER_PARSER_CLEANUP);
  
 -      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_FAILURE"), PHP_HTTP_HEADER_PARSER_STATE_FAILURE TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_START"), PHP_HTTP_HEADER_PARSER_STATE_START TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_KEY"), PHP_HTTP_HEADER_PARSER_STATE_KEY TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_VALUE"), PHP_HTTP_HEADER_PARSER_STATE_VALUE TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_VALUE_EX"), PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_HEADER_DONE"), PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_DONE"), PHP_HTTP_HEADER_PARSER_STATE_DONE TSRMLS_CC);
 +      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_FAILURE"), PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
 +      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_START"), PHP_HTTP_HEADER_PARSER_STATE_START);
 +      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_KEY"), PHP_HTTP_HEADER_PARSER_STATE_KEY);
 +      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_VALUE"), PHP_HTTP_HEADER_PARSER_STATE_VALUE);
 +      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_VALUE_EX"), PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX);
 +      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_HEADER_DONE"), PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
 +      zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_DONE"), PHP_HTTP_HEADER_PARSER_STATE_DONE);
  
        return SUCCESS;
  }
diff --combined php_http_querystring.c
index bd04f5092f9b233a9a53851f75858d4d668c8362,d2657484668ade531a876860c51354707e06a99e..83ce01b9ddbb91322e1acd1fbbf857ff8b6300ac
  
  #define QS_MERGE 1
  
 -static inline void php_http_querystring_set(zval *instance, zval *params, int flags TSRMLS_DC)
 +static inline void php_http_querystring_set(zval *instance, zval *params, int flags)
  {
 -      zval *qa;
 +      zval qa;
 +
 +      array_init(&qa);
  
        if (flags & QS_MERGE) {
 -              qa = php_http_zsep(1, IS_ARRAY, zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), 0 TSRMLS_CC));
 -      } else {
 -              MAKE_STD_ZVAL(qa);
 -              array_init(qa);
 +              zval old_tmp, *old = zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), 0, &old_tmp);
 +
 +              ZVAL_DEREF(old);
 +              if (Z_TYPE_P(old) == IS_ARRAY) {
 +                      array_copy(Z_ARRVAL_P(old), Z_ARRVAL(qa));
 +              }
        }
  
 -      php_http_querystring_update(qa, params, NULL TSRMLS_CC);
 -      zend_update_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), qa TSRMLS_CC);
 +      php_http_querystring_update(&qa, params, NULL);
 +      zend_update_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), &qa);
        zval_ptr_dtor(&qa);
  }
  
 -static inline void php_http_querystring_str(zval *instance, zval *return_value TSRMLS_DC)
 +static inline void php_http_querystring_str(zval *instance, zval *return_value)
  {
 -      zval *qa = zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), 0 TSRMLS_CC);
 +      zval qa_tmp, *qa = zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), 0, &qa_tmp);
  
 +      ZVAL_DEREF(qa);
        if (Z_TYPE_P(qa) == IS_ARRAY) {
 -              php_http_querystring_update(qa, NULL, return_value TSRMLS_CC);
 +              php_http_querystring_update(qa, NULL, return_value);
        } else {
                RETURN_EMPTY_STRING();
        }
  }
  
 -static inline void php_http_querystring_get(zval *this_ptr, int type, char *name, uint name_len, zval *defval, zend_bool del, zval *return_value TSRMLS_DC)
 +static inline void php_http_querystring_get(zval *instance, int type, char *name, uint name_len, zval *defval, zend_bool del, zval *return_value)
  {
 -      zval **arrval, *qarray = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC);
 +      zval *arrval, qarray_tmp, *qarray = zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), 0, &qarray_tmp);
  
 -      if ((Z_TYPE_P(qarray) == IS_ARRAY) && (SUCCESS == zend_symtable_find(Z_ARRVAL_P(qarray), name, name_len + 1, (void *) &arrval))) {
 -              if (type) {
 -                      zval *value = php_http_ztyp(type, *arrval);
 -                      RETVAL_ZVAL(value, 1, 1);
 +      ZVAL_DEREF(qarray);
 +      if ((Z_TYPE_P(qarray) == IS_ARRAY) && (arrval = zend_symtable_str_find(Z_ARRVAL_P(qarray), name, name_len))) {
 +              if (type && type != Z_TYPE_P(arrval)) {
 +                      zval tmp;
 +
 +                      ZVAL_DUP(&tmp, arrval);
 +                      convert_to_explicit_type(&tmp, type);
 +                      RETVAL_ZVAL(&tmp, 0, 0);
                } else {
 -                      RETVAL_ZVAL(*arrval, 1, 0);
 +                      RETVAL_ZVAL_FAST(arrval);
                }
  
                if (del) {
 -                      zval *delarr;
 +                      zval delarr;
  
 -                      MAKE_STD_ZVAL(delarr);
 -                      array_init(delarr);
 -                      add_assoc_null_ex(delarr, name, name_len + 1);
 -                      php_http_querystring_set(this_ptr, delarr, QS_MERGE TSRMLS_CC);
 +                      array_init(&delarr);
 +                      add_assoc_null_ex(&delarr, name, name_len);
 +                      php_http_querystring_set(instance, &delarr, QS_MERGE);
                        zval_ptr_dtor(&delarr);
                }
        } else if(defval) {
 -              RETURN_ZVAL(defval, 1, 0);
 +              RETURN_ZVAL_FAST(defval);
        }
  }
  
  #ifdef PHP_HTTP_HAVE_ICONV
 -ZEND_RESULT_CODE php_http_querystring_xlate(zval *dst, zval *src, const char *ie, const char *oe TSRMLS_DC)
 +ZEND_RESULT_CODE php_http_querystring_xlate(zval *dst, zval *src, const char *ie, const char *oe)
  {
 -      HashPosition pos;
 -      zval **entry = NULL;
 -      char *xlate_str = NULL, *xkey;
 -      size_t xlate_len = 0, xlen;
 -      php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
 +      zval *entry;
 +      zend_string *xkey, *xstr;
 +      php_http_arrkey_t key;
        
 -      FOREACH_KEYVAL(pos, src, key, entry) {
 -              if (key.type == HASH_KEY_IS_STRING) {
 -                      if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(key.str, key.len-1, &xkey, &xlen, oe, ie)) {
 -                              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to convert '%.*s' from '%s' to '%s'", key.len-1, key.str, ie, oe);
 +      ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(src), key.h, key.key, entry)
 +      {
 +              if (key.key) {
 +                      if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(key.key->val, key.key->len, &xkey, oe, ie)) {
 +                              php_error_docref(NULL, E_WARNING, "Failed to convert '%.*s' from '%s' to '%s'", key.key->len, key.key->val, ie, oe);
                                return FAILURE;
                        }
                }
                
 -              if (Z_TYPE_PP(entry) == IS_STRING) {
 -                      if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), &xlate_str, &xlate_len, oe, ie)) {
 -                              if (key.type == HASH_KEY_IS_STRING) {
 -                                      efree(xkey);
 +              if (Z_TYPE_P(entry) == IS_STRING) {
 +                      if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(Z_STRVAL_P(entry), Z_STRLEN_P(entry), &xstr, oe, ie)) {
 +                              if (key.key) {
 +                                      zend_string_release(xkey);
                                }
 -                              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to convert '%.*s' from '%s' to '%s'", Z_STRLEN_PP(entry), Z_STRVAL_PP(entry), ie, oe);
 +                              php_error_docref(NULL, E_WARNING, "Failed to convert '%.*s' from '%s' to '%s'", Z_STRLEN_P(entry), Z_STRVAL_P(entry), ie, oe);
                                return FAILURE;
                        }
 -                      if (key.type == HASH_KEY_IS_STRING) {
 -                              add_assoc_stringl_ex(dst, xkey, xlen+1, xlate_str, xlate_len, 0);
 +                      if (key.key) {
 +                              add_assoc_str_ex(dst, xkey->val, xkey->len, xstr);
                        } else {
 -                              add_index_stringl(dst, key.num, xlate_str, xlate_len, 0);
 +                              add_index_str(dst, key.h, xstr);
                        }
 -              } else if (Z_TYPE_PP(entry) == IS_ARRAY) {
 -                      zval *subarray;
 +              } else if (Z_TYPE_P(entry) == IS_ARRAY) {
 +                      zval subarray;
                        
 -                      MAKE_STD_ZVAL(subarray);
 -                      array_init(subarray);
 -                      if (key.type == HASH_KEY_IS_STRING) {
 -                              add_assoc_zval_ex(dst, xkey, xlen+1, subarray);
 +                      array_init(&subarray);
 +                      if (key.key) {
 +                              add_assoc_zval_ex(dst, xkey->val, xkey->len, &subarray);
                        } else {
 -                              add_index_zval(dst, key.num, subarray);
 +                              add_index_zval(dst, key.h, &subarray);
                        }
 -                      if (SUCCESS != php_http_querystring_xlate(subarray, *entry, ie, oe TSRMLS_CC)) {
 -                              if (key.type == HASH_KEY_IS_STRING) {
 -                                      efree(xkey);
 +                      if (SUCCESS != php_http_querystring_xlate(&subarray, entry, ie, oe)) {
 +                              if (key.key) {
 +                                      zend_string_release(xkey);
                                }
                                return FAILURE;
                        }
                }
                
 -              if (key.type == HASH_KEY_IS_STRING) {
 -                      efree(xkey);
 +              if (key.key) {
 +                      zend_string_release(xkey);
                }
        }
 +      ZEND_HASH_FOREACH_END();
 +
        return SUCCESS;
  }
  #endif /* HAVE_ICONV */
  
 -ZEND_RESULT_CODE php_http_querystring_ctor(zval *instance, zval *params TSRMLS_DC)
 +ZEND_RESULT_CODE php_http_querystring_ctor(zval *instance, zval *params)
  {
 -      php_http_querystring_set(instance, params, 0 TSRMLS_CC);
 +      php_http_querystring_set(instance, params, 0);
        return SUCCESS;
  }
  
 -static int apply_querystring(void *pData TSRMLS_DC)
 +static int apply_querystring(zval *val)
  {
 -      zval **val = pData;
 -
 -      if (Z_TYPE_PP(val) == IS_ARRAY) {
 -              zval **zvalue;
 +      if (Z_TYPE_P(val) == IS_ARRAY) {
 +              zval *zvalue;
  
 -              if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(val), ZEND_STRS("value"), (void *) &zvalue)) {
 -                      zval *tmp = *val;
 +              if ((zvalue = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("value")))) {
 +                      zval tmp;
  
 -                      Z_ADDREF_PP(zvalue);
 -                      *val = *zvalue;
 -                      zval_dtor(tmp);
 -                      Z_TYPE_P(tmp) = IS_NULL;
 -                      zval_ptr_dtor(&tmp);
 +                      ZVAL_COPY(&tmp, zvalue);
 +                      zval_dtor(val);
 +                      ZVAL_COPY_VALUE(val, &tmp);
                }
        }
  
        return ZEND_HASH_APPLY_KEEP;
  }
  
 -ZEND_RESULT_CODE php_http_querystring_parse(HashTable *ht, const char *str, size_t len TSRMLS_DC)
 +ZEND_RESULT_CODE php_http_querystring_parse(HashTable *ht, const char *str, size_t len)
  {
        ZEND_RESULT_CODE rv = FAILURE;
        php_http_params_opts_t opts;
        opts.flags = PHP_HTTP_PARAMS_QUERY;
  
        if (SUCCESS == php_http_ini_entry(ZEND_STRL("arg_separator.input"), &asi_str, &asi_len, 0 TSRMLS_CC) && asi_len) {
 -              zval *arr;
 +              zval arr;
  
 -              MAKE_STD_ZVAL(arr);
 -              array_init_size(arr, asi_len);
 +              array_init_size(&arr, asi_len);
  
                do {
 -                      add_next_index_stringl(arr, asi_str++, 1, 1);
 +                      add_next_index_stringl(&arr, asi_str++, 1);
                } while (*asi_str);
  
 -              opts.param = php_http_params_separator_init(arr TSRMLS_CC);
 -
 +              opts.param = php_http_params_separator_init(&arr);
                zval_ptr_dtor(&arr);
        }
  
 -      MAKE_STD_ZVAL(opts.defval);
 -      ZVAL_NULL(opts.defval);
 +      ZVAL_NULL(&opts.defval);
  
 -      if (php_http_params_parse(ht, &opts TSRMLS_CC)) {
 -              zend_hash_apply(ht, apply_querystring TSRMLS_CC);
 +      if (php_http_params_parse(ht, &opts)) {
 +              zend_hash_apply(ht, apply_querystring);
                rv = SUCCESS;
        }
  
        return rv;
  }
  
 -ZEND_RESULT_CODE php_http_querystring_update(zval *qarray, zval *params, zval *outstring TSRMLS_DC)
 +ZEND_RESULT_CODE php_http_querystring_update(zval *qarray, zval *params, zval *outstring)
  {
        /* enforce proper type */
        if (Z_TYPE_P(qarray) != IS_ARRAY) {
  
        /* modify qarray */
        if (params) {
 -              HashPosition pos;
 -              HashTable *ptr;
 -              php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
 -              zval **params_entry,  **qarray_entry;
 -              zval zv, *zv_ptr = NULL;
 +              HashTable *ht;
 +              php_http_arrkey_t key;
 +              zval zv, *params_entry, *qarray_entry;
  
 -              INIT_PZVAL(&zv);
                ZVAL_NULL(&zv);
  
                /* squeeze the hash out of the zval */
 -              if (Z_TYPE_P(params) == IS_OBJECT && instanceof_function(Z_OBJCE_P(params), php_http_querystring_class_entry TSRMLS_CC)) {
 -                      zv_ptr = php_http_ztyp(IS_ARRAY, zend_read_property(php_http_querystring_class_entry, params, ZEND_STRL("queryArray"), 0 TSRMLS_CC));
 -                      ptr = Z_ARRVAL_P(zv_ptr);
 +              if (Z_TYPE_P(params) == IS_OBJECT && instanceof_function(Z_OBJCE_P(params), php_http_querystring_class_entry)) {
 +                      zval qa_tmp, *qa = zend_read_property(php_http_querystring_class_entry, params, ZEND_STRL("queryArray"), 0, &qa_tmp);
 +
 +                      ZVAL_DEREF(qa);
 +                      convert_to_array(qa);
 +                      ht = Z_ARRVAL_P(qa);
                } else if (Z_TYPE_P(params) == IS_OBJECT || Z_TYPE_P(params) == IS_ARRAY) {
 -                      ptr = HASH_OF(params);
 +                      ht = HASH_OF(params);
                } else {
 -                      zv_ptr = php_http_ztyp(IS_STRING, params);
 +                      zend_string *zs = zval_get_string(params);
 +
                        array_init(&zv);
 -                      php_http_querystring_parse(Z_ARRVAL(zv), Z_STRVAL_P(zv_ptr), Z_STRLEN_P(zv_ptr) TSRMLS_CC);
 -                      zval_ptr_dtor(&zv_ptr);
 -                      zv_ptr = NULL;
 -                      ptr = Z_ARRVAL(zv);
 +                      php_http_querystring_parse(Z_ARRVAL(zv), zs->val, zs->len);
 +                      zend_string_release(zs);
 +
 +                      ht = Z_ARRVAL(zv);
                }
  
 -              FOREACH_HASH_KEYVAL(pos, ptr, key, params_entry) {
 +              ZEND_HASH_FOREACH_KEY_VAL_IND(ht, key.h, key.key, params_entry)
 +              {
                        /* only public properties */
 -                      if (key.type != HASH_KEY_IS_STRING || *key.str) {
 -                              if (Z_TYPE_PP(params_entry) == IS_NULL) {
 +                      if (!key.key || *key.key->val) {
 +                              if (Z_TYPE_P(params_entry) == IS_NULL) {
                                        /*
                                         * delete
                                         */
 -                                      if (key.type == HASH_KEY_IS_STRING) {
 -                                              zend_hash_del(Z_ARRVAL_P(qarray), key.str, key.len);
 +                                      if (key.key) {
 +                                              zend_hash_del(Z_ARRVAL_P(qarray), key.key);
                                        } else {
 -                                              zend_hash_index_del(Z_ARRVAL_P(qarray), key.num);
 +                                              zend_hash_index_del(Z_ARRVAL_P(qarray), key.h);
                                        }
 -                              } else if (     ((key.type == HASH_KEY_IS_STRING) && (SUCCESS == zend_hash_find(Z_ARRVAL_P(qarray), key.str, key.len, (void *) &qarray_entry)))
 -                                              ||      ((key.type == HASH_KEY_IS_LONG) && (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(qarray), key.num, (void *) &qarray_entry)))) {
 +                              } else if (     ((key.key) && (qarray_entry = zend_hash_find(Z_ARRVAL_P(qarray), key.key)))
 +                                              ||      ((!key.key) && (qarray_entry = zend_hash_index_find(Z_ARRVAL_P(qarray), key.h)))) {
                                        /*
                                         * update
                                         */
 -                                      zval equal, *entry = NULL;
 +                                      zval equal, tmp, *entry = &tmp;
  
 +                                      ZVAL_UNDEF(&tmp);
                                        /* recursive */
 -                                      if (Z_TYPE_PP(params_entry) == IS_ARRAY || Z_TYPE_PP(params_entry) == IS_OBJECT) {
 -                                              entry = php_http_zsep(1, IS_ARRAY, *qarray_entry);
 -                                              php_http_querystring_update(entry, *params_entry, NULL TSRMLS_CC);
 -                                      } else if ((FAILURE == is_equal_function(&equal, *qarray_entry, *params_entry TSRMLS_CC)) || !Z_BVAL(equal)) {
 -                                              Z_ADDREF_PP(params_entry);
 -                                              entry = *params_entry;
 +                                      if (Z_TYPE_P(params_entry) == IS_ARRAY || Z_TYPE_P(params_entry) == IS_OBJECT) {
 +                                              ZVAL_DUP(entry, qarray_entry);
 +                                              convert_to_array(entry);
 +                                              php_http_querystring_update(entry, params_entry, NULL);
 +                                      } else if ((FAILURE == is_equal_function(&equal, qarray_entry, params_entry)) || Z_TYPE(equal) != IS_TRUE) {
 +                                              Z_TRY_ADDREF_P(params_entry);
 +                                              entry = params_entry;
                                        }
  
                                        if (entry) {
 -                                              if (key.type == HASH_KEY_IS_STRING) {
 -                                                      zend_hash_update(Z_ARRVAL_P(qarray), key.str, key.len, (void *) &entry, sizeof(zval *), NULL);
 +                                              if (key.key) {
 +                                                      zend_hash_update(Z_ARRVAL_P(qarray), key.key, entry);
                                                } else {
 -                                                      zend_hash_index_update(Z_ARRVAL_P(qarray), key.num, (void *) &entry, sizeof(zval *), NULL);
 +                                                      zend_hash_index_update(Z_ARRVAL_P(qarray), key.h, entry);
                                                }
                                        }
                                } else {
 -                                      zval *entry;
 +                                      zval entry, *entry_ptr = &entry;
                                        /*
                                         * add
                                         */
 -                                      if (Z_TYPE_PP(params_entry) == IS_OBJECT) {
 -                                              MAKE_STD_ZVAL(entry);
 -                                              array_init(entry);
 -                                              php_http_querystring_update(entry, *params_entry, NULL TSRMLS_CC);
 +                                      if (Z_TYPE_P(params_entry) == IS_OBJECT) {
 +                                              array_init(&entry);
 +                                              php_http_querystring_update(&entry, params_entry, NULL);
                                        } else {
 -                                              Z_ADDREF_PP(params_entry);
 -                                              entry = *params_entry;
 +                                              Z_TRY_ADDREF_P(params_entry);
 +                                              entry_ptr = params_entry;
                                        }
 -                                      if (key.type == HASH_KEY_IS_STRING) {
 -                                              add_assoc_zval_ex(qarray, key.str, key.len, entry);
 +                                      if (key.key) {
 +                                              add_assoc_zval_ex(qarray, key.key->val, key.key->len, entry_ptr);
                                        } else {
 -                                              add_index_zval(qarray, key.num, entry);
 +                                              add_index_zval(qarray, key.h, entry_ptr);
                                        }
                                }
                        }
                }
 -              /* clean up */
 -              if (zv_ptr) {
 -                      zval_ptr_dtor(&zv_ptr);
 -              }
 +              ZEND_HASH_FOREACH_END();
 +
                zval_dtor(&zv);
        }
  
                char *s;
                size_t l;
  
 -              if (SUCCESS == php_http_url_encode_hash(Z_ARRVAL_P(qarray), NULL, 0, &s, &l TSRMLS_CC)) {
 +              if (SUCCESS == php_http_url_encode_hash(Z_ARRVAL_P(qarray), NULL, 0, &s, &l)) {
                        zval_dtor(outstring);
 -                      ZVAL_STRINGL(outstring, s, l, 0);
 +                      ZVAL_STR(outstring, php_http_cs2zs(s, l));
                } else {
 -                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to encode query string");
 +                      php_error_docref(NULL, E_WARNING, "Failed to encode query string");
                        return FAILURE;
                }
        }
@@@ -331,51 -329,61 +331,51 @@@ PHP_METHOD(HttpQueryString, __construct
        
        php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z", &params), invalid_arg, return);
  
 -      zend_replace_error_handling(EH_THROW, php_http_exception_bad_querystring_class_entry, &zeh TSRMLS_CC);
 -      php_http_querystring_set(getThis(), params, 0 TSRMLS_CC);
 -      zend_restore_error_handling(&zeh TSRMLS_CC);
 +      zend_replace_error_handling(EH_THROW, php_http_exception_bad_querystring_class_entry, &zeh);
 +      php_http_querystring_set(getThis(), params, 0);
 +      zend_restore_error_handling(&zeh);
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_getGlobalInstance, 0, 0, 0)
  ZEND_END_ARG_INFO();
  PHP_METHOD(HttpQueryString, getGlobalInstance)
  {
 -      zval *instance;
 +      zval *instance, *_GET;
 +      zend_string *zs;
  
        php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
  
 -      instance = *zend_std_get_static_property(php_http_querystring_class_entry, ZEND_STRL("instance"), 0 PHP_HTTP_ZEND_LITERAL_CCN TSRMLS_CC);
 +      zs = zend_string_init(ZEND_STRL("instance"), 0);
 +      instance = zend_std_get_static_property(php_http_querystring_class_entry, zs, 0);
 +      zend_string_release(zs);
  
 -      if (Z_TYPE_P(instance) != IS_OBJECT) {
 -              zval **_GET = NULL;
 +      if (Z_TYPE_P(instance) == IS_OBJECT) {
 +              RETVAL_ZVAL_FAST(instance);
 +      } else if ((_GET = php_http_env_get_superglobal(ZEND_STRL("_GET")))) {
 +              ZVAL_OBJ(return_value, php_http_querystring_object_new(php_http_querystring_class_entry));
  
 -              zend_is_auto_global("_GET", lenof("_GET") TSRMLS_CC);
 +              ZVAL_MAKE_REF(_GET);
 +              zend_update_property(php_http_querystring_class_entry, return_value, ZEND_STRL("queryArray"), _GET);
  
 -              if ((SUCCESS == zend_hash_find(&EG(symbol_table), "_GET", sizeof("_GET"), (void *) &_GET))
 -              &&      (Z_TYPE_PP(_GET) == IS_ARRAY)
 -              ) {
 -                      MAKE_STD_ZVAL(instance);
 -                      ZVAL_OBJVAL(instance, php_http_querystring_object_new(php_http_querystring_class_entry TSRMLS_CC), 0);
 -
 -                      SEPARATE_ZVAL_TO_MAKE_IS_REF(_GET);
 -                      convert_to_array(*_GET);
 -                      zend_update_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), *_GET TSRMLS_CC);
 -
 -                      zend_update_static_property(php_http_querystring_class_entry, ZEND_STRL("instance"), instance TSRMLS_CC);
 -                      zval_ptr_dtor(&instance);
 -              } else {
 -                      php_http_throw(unexpected_val, "Could not acquire reference to superglobal GET array", NULL);
 -              }
 +              zend_update_static_property(php_http_querystring_class_entry, ZEND_STRL("instance"), return_value);
 +      } else {
 +              php_http_throw(unexpected_val, "Could not acquire reference to superglobal GET array", NULL);
        }
  
 -      RETVAL_ZVAL(instance, 1, 0);
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_getIterator, 0, 0, 0)
  ZEND_END_ARG_INFO();
  PHP_METHOD(HttpQueryString, getIterator)
  {
 -      zval *retval = NULL, *qa;
 +      zval qa_tmp, *qa;
  
        php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
  
 -      qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC);
 +      qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0, &qa_tmp);
  
        object_init_ex(return_value, spl_ce_RecursiveArrayIterator);
 -      zend_call_method_with_1_params(&return_value, spl_ce_RecursiveArrayIterator, NULL, "__construct", &retval, qa);
 -      if (retval) {
 -              zval_ptr_dtor(&retval);
 -      }
 +      zend_call_method_with_1_params(return_value, spl_ce_RecursiveArrayIterator, NULL, "__construct", NULL, qa);
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_toString, 0, 0, 0)
@@@ -385,21 -393,21 +385,21 @@@ PHP_METHOD(HttpQueryString, toString
        if (SUCCESS != zend_parse_parameters_none()) {
                return;
        }
 -      php_http_querystring_str(getThis(), return_value TSRMLS_CC);
 +      php_http_querystring_str(getThis(), return_value);
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_toArray, 0, 0, 0)
  ZEND_END_ARG_INFO();
  PHP_METHOD(HttpQueryString, toArray)
  {
 -      zval *zqa;
 +      zval zqa_tmp, *zqa;
  
        if (SUCCESS != zend_parse_parameters_none()) {
                return;
        }
  
 -      zqa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC);
 -      RETURN_ZVAL(zqa, 1, 0);
 +      zqa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0, &zqa_tmp);
 +      RETURN_ZVAL_FAST(zqa);
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_get, 0, 0, 0)
@@@ -411,12 -419,12 +411,12 @@@ ZEND_END_ARG_INFO()
  PHP_METHOD(HttpQueryString, get)
  {
        char *name_str = NULL;
 -      int name_len = 0;
 -      long type = 0;
 +      size_t name_len = 0;
 +      zend_long type = 0;
        zend_bool del = 0;
        zval *ztype = NULL, *defval = NULL;
        
 -      if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|szzb", &name_str, &name_len, &ztype, &defval, &del)) {
 +      if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|szzb", &name_str, &name_len, &ztype, &defval, &del)) {
                if (name_str && name_len) {
                        if (ztype) {
                                if (Z_TYPE_P(ztype) == IS_LONG) {
                                        }
                                }
                        }
 -                      php_http_querystring_get(getThis(), type, name_str, name_len, defval, del, return_value TSRMLS_CC);
 +                      php_http_querystring_get(getThis(), type, name_str, name_len, defval, del, return_value);
                } else {
 -                      php_http_querystring_str(getThis(), return_value TSRMLS_CC);
 +                      php_http_querystring_str(getThis(), return_value);
                }
        }
  }
@@@ -456,11 -464,11 +456,11 @@@ PHP_METHOD(HttpQueryString, set
  {
        zval *params;
        
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &params)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "z", &params)) {
                return;
        }
        
 -      php_http_querystring_set(getThis(), params, QS_MERGE TSRMLS_CC);
 +      php_http_querystring_set(getThis(), params, QS_MERGE);
        RETVAL_ZVAL(getThis(), 1, 0);
  }
  
@@@ -469,17 -477,15 +469,17 @@@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryStri
  ZEND_END_ARG_INFO();
  PHP_METHOD(HttpQueryString, mod)
  {
 -      zval *params;
 +      zval qa_tmp, *params, *instance = getThis();
        zend_error_handling zeh;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &params), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z", &params), invalid_arg, return);
        
 -      zend_replace_error_handling(EH_THROW, php_http_exception_bad_querystring_class_entry, &zeh TSRMLS_CC);
 -      ZVAL_OBJVAL(return_value, Z_OBJ_HT_P(getThis())->clone_obj(getThis() TSRMLS_CC), 0);
 -      php_http_querystring_set(return_value, params, QS_MERGE TSRMLS_CC);
 -      zend_restore_error_handling(&zeh TSRMLS_CC);
 +      zend_replace_error_handling(EH_THROW, php_http_exception_bad_querystring_class_entry, &zeh);
 +      ZVAL_OBJ(return_value, Z_OBJ_HT_P(instance)->clone_obj(instance));
 +      /* make sure we do not inherit the reference to _GET */
 +      SEPARATE_ZVAL(zend_read_property(Z_OBJCE_P(return_value), return_value, ZEND_STRL("queryArray"), 0, &qa_tmp));
 +      php_http_querystring_set(return_value, params, QS_MERGE);
 +      zend_restore_error_handling(&zeh);
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString___getter, 0, 0, 1)
@@@ -491,14 -497,14 +491,14 @@@ ZEND_END_ARG_INFO()
  PHP_METHOD(HttpQueryString, method) \
  { \
        char *name; \
 -      int name_len; \
 +      size_t name_len; \
        zval *defval = NULL; \
        zend_bool del = 0; \
 -      if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zb", &name, &name_len, &defval, &del)) { \
 -              php_http_querystring_get(getThis(), TYPE, name, name_len, defval, del, return_value TSRMLS_CC); \
 +      if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|zb", &name, &name_len, &defval, &del)) { \
 +              php_http_querystring_get(getThis(), TYPE, name, name_len, defval, del, return_value); \
        } \
  }
 -PHP_HTTP_QUERYSTRING_GETTER(getBool, IS_BOOL);
 +PHP_HTTP_QUERYSTRING_GETTER(getBool, _IS_BOOL);
  PHP_HTTP_QUERYSTRING_GETTER(getInt, IS_LONG);
  PHP_HTTP_QUERYSTRING_GETTER(getFloat, IS_DOUBLE);
  PHP_HTTP_QUERYSTRING_GETTER(getString, IS_STRING);
@@@ -513,25 -519,26 +513,25 @@@ ZEND_END_ARG_INFO()
  PHP_METHOD(HttpQueryString, xlate)
  {
        char *ie, *oe;
 -      int ie_len, oe_len;
 -      zval *na, *qa;
 +      size_t ie_len, oe_len;
 +      zval na, qa_tmp, *qa;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &ie, &ie_len, &oe, &oe_len), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &ie, &ie_len, &oe, &oe_len), invalid_arg, return);
  
 -      MAKE_STD_ZVAL(na);
 -      array_init(na);
 -      qa = php_http_ztyp(IS_ARRAY, zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC));
 +      array_init(&na);
 +      qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0, &qa_tmp);
 +      ZVAL_DEREF(qa);
 +      convert_to_array(qa);
  
 -      php_http_expect(SUCCESS == php_http_querystring_xlate(na, qa, ie, oe TSRMLS_CC), bad_conversion,
 +      php_http_expect(SUCCESS == php_http_querystring_xlate(&na, qa, ie, oe), bad_conversion,
                        zval_ptr_dtor(&na);
 -                      zval_ptr_dtor(&qa);
                        return;
        );
  
 -      php_http_querystring_set(getThis(), na, 0 TSRMLS_CC);
 -      RETVAL_ZVAL(getThis(), 1, 0);
 +      php_http_querystring_set(getThis(), &na, 0);
 +      RETVAL_ZVAL_FAST(getThis());
        
        zval_ptr_dtor(&na);
 -      zval_ptr_dtor(&qa);
  }
  #endif /* HAVE_ICONV */
  
@@@ -542,7 -549,7 +542,7 @@@ PHP_METHOD(HttpQueryString, serialize
        if (SUCCESS != zend_parse_parameters_none()) {
                return;
        }
 -      php_http_querystring_str(getThis(), return_value TSRMLS_CC);
 +      php_http_querystring_str(getThis(), return_value);
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_unserialize, 0, 0, 1)
@@@ -552,14 -559,14 +552,14 @@@ PHP_METHOD(HttpQueryString, unserialize
  {
        zval *serialized;
        
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &serialized)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "z", &serialized)) {
                return;
        }
  
        if (Z_TYPE_P(serialized) == IS_STRING) {
 -              php_http_querystring_set(getThis(), serialized, 0 TSRMLS_CC);
 +              php_http_querystring_set(getThis(), serialized, 0);
        } else {
 -              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected a string as parameter");
 +              php_error_docref(NULL, E_WARNING, "Expected a string as parameter");
        }
  }
  
@@@ -568,19 -575,19 +568,19 @@@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryStri
  ZEND_END_ARG_INFO();
  PHP_METHOD(HttpQueryString, offsetGet)
  {
 -      char *offset_str;
 -      int offset_len;
 -      zval **value, *qa;
 +      zend_string *offset;
 +      zval *value, qa_tmp, *qa;
  
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &offset)) {
                return;
        }
        
 -      qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC);
 +      qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0, &qa_tmp);
 +      ZVAL_DEREF(qa);
  
        if (Z_TYPE_P(qa) == IS_ARRAY) {
 -              if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(qa), offset_str, offset_len + 1, (void *) &value)) {
 -                      RETVAL_ZVAL(*value, 1, 0);
 +              if ((value = zend_symtable_find(Z_ARRVAL_P(qa), offset))) {
 +                      RETVAL_ZVAL_FAST(value);
                }
        }
  }
@@@ -591,17 -598,27 +591,22 @@@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryStri
  ZEND_END_ARG_INFO();
  PHP_METHOD(HttpQueryString, offsetSet)
  {
 -      char *offset_str;
 -      int offset_len;
 -      zval *value, *param;
 +      zend_string *offset;
-       zval *value, param;
++      zval *value, param, znull;
        
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &offset_str, &offset_len, &value)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Sz", &offset, &value)) {
                return;
        }
  
-       array_init(&param);
 -      param = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC);
 -
 -      if (Z_TYPE_P(param) == IS_ARRAY && zend_symtable_exists(Z_ARRVAL_P(param), offset_str, offset_len + 1)) {
 -              Z_ADDREF_P(value);
 -              zend_symtable_update(Z_ARRVAL_P(param), offset_str, offset_len + 1, (void *) &value, sizeof(zval *), NULL);
 -              Z_ADDREF_P(param);
 -      } else {
 -              MAKE_STD_ZVAL(param);
 -              array_init(param);
 -              Z_ADDREF_P(value);
 -              add_assoc_zval_ex(param, offset_str, offset_len + 1, value);
 -      }
 -      php_http_querystring_set(getThis(), param, QS_MERGE TSRMLS_CC);
++      array_init_size(&param, 1);
++      /* unset first */
++      ZVAL_NULL(&znull);
++      zend_symtable_update(Z_ARRVAL(param), offset, &znull);
++      php_http_querystring_set(getThis(), &param, QS_MERGE);
++      /* then update, else QS_MERGE would merge sub-arrrays */
 +      Z_TRY_ADDREF_P(value);
 +      zend_symtable_update(Z_ARRVAL(param), offset, value);
-       php_http_querystring_set(getThis(), &param, 0);
++      php_http_querystring_set(getThis(), &param, QS_MERGE);
        zval_ptr_dtor(&param);
  }
  
@@@ -610,19 -627,19 +615,19 @@@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryStri
  ZEND_END_ARG_INFO();
  PHP_METHOD(HttpQueryString, offsetExists)
  {
 -      char *offset_str;
 -      int offset_len;
 -      zval **value, *qa;
 +      zend_string *offset;
 +      zval *value, qa_tmp, *qa;
  
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &offset)) {
                return;
        }
        
 -      qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0 TSRMLS_CC);
 +      qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0, &qa_tmp);
 +      ZVAL_DEREF(qa);
  
        if (Z_TYPE_P(qa) == IS_ARRAY) {
 -              if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(qa), offset_str, offset_len + 1, (void *) &value)) {
 -                      RETURN_BOOL(Z_TYPE_PP(value) != IS_NULL);
 +              if ((value = zend_symtable_find(Z_ARRVAL_P(qa), offset))) {
 +                      RETURN_BOOL(Z_TYPE_P(value) != IS_NULL);
                }
        }
        RETURN_FALSE;
@@@ -633,17 -650,18 +638,17 @@@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryStri
  ZEND_END_ARG_INFO();
  PHP_METHOD(HttpQueryString, offsetUnset)
  {
 -      char *offset_str;
 -      int offset_len;
 -      zval *param;
 +      zend_string *offset;
 +      zval param, znull;
        
 -      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &offset_str, &offset_len)) {
 +      if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S", &offset)) {
                return;
        }
  
 -      MAKE_STD_ZVAL(param);
 -      array_init(param);
 -      add_assoc_null_ex(param, offset_str, offset_len + 1);
 -      php_http_querystring_set(getThis(), param, QS_MERGE TSRMLS_CC);
 +      array_init(&param);
 +      ZVAL_NULL(&znull);
 +      zend_symtable_update(Z_ARRVAL(param), offset, &znull);
 +      php_http_querystring_set(getThis(), &param, QS_MERGE);
        zval_ptr_dtor(&param);
  }
  
@@@ -692,19 -710,19 +697,19 @@@ PHP_MINIT_FUNCTION(http_querystring
        zend_class_entry ce = {0};
  
        INIT_NS_CLASS_ENTRY(ce, "http", "QueryString", php_http_querystring_methods);
 -      php_http_querystring_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
 +      php_http_querystring_class_entry = zend_register_internal_class(&ce);
        php_http_querystring_class_entry->create_object = php_http_querystring_object_new;
 -      zend_class_implements(php_http_querystring_class_entry TSRMLS_CC, 3, zend_ce_serializable, zend_ce_arrayaccess, zend_ce_aggregate);
 +      zend_class_implements(php_http_querystring_class_entry, 3, zend_ce_serializable, zend_ce_arrayaccess, zend_ce_aggregate);
  
 -      zend_declare_property_null(php_http_querystring_class_entry, ZEND_STRL("instance"), (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
 -      zend_declare_property_null(php_http_querystring_class_entry, ZEND_STRL("queryArray"), ZEND_ACC_PRIVATE TSRMLS_CC);
 +      zend_declare_property_null(php_http_querystring_class_entry, ZEND_STRL("instance"), (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE));
 +      zend_declare_property_null(php_http_querystring_class_entry, ZEND_STRL("queryArray"), ZEND_ACC_PRIVATE);
  
 -      zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_BOOL"), PHP_HTTP_QUERYSTRING_TYPE_BOOL TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_INT"), PHP_HTTP_QUERYSTRING_TYPE_INT TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_FLOAT"), PHP_HTTP_QUERYSTRING_TYPE_FLOAT TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_STRING"), PHP_HTTP_QUERYSTRING_TYPE_STRING TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_ARRAY"), PHP_HTTP_QUERYSTRING_TYPE_ARRAY TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_OBJECT"), PHP_HTTP_QUERYSTRING_TYPE_OBJECT TSRMLS_CC);
 +      zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_BOOL"), PHP_HTTP_QUERYSTRING_TYPE_BOOL);
 +      zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_INT"), PHP_HTTP_QUERYSTRING_TYPE_INT);
 +      zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_FLOAT"), PHP_HTTP_QUERYSTRING_TYPE_FLOAT);
 +      zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_STRING"), PHP_HTTP_QUERYSTRING_TYPE_STRING);
 +      zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_ARRAY"), PHP_HTTP_QUERYSTRING_TYPE_ARRAY);
 +      zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_OBJECT"), PHP_HTTP_QUERYSTRING_TYPE_OBJECT);
  
        return SUCCESS;
  }
diff --combined php_http_url.c
index 6c70bc3f2566f04bdaf0b5e782a27054ff12ad66,35178dc882a8b2314c821681088e9b6d0b43d3b9..5a267d898ee086fb3be58638e42c5d49f37cf840
@@@ -59,7 -59,7 +59,7 @@@ static inline char *localhostname(void
  
  #define url(buf) ((php_http_url_t *) (buf).data)
  
 -static php_http_url_t *php_http_url_from_env(TSRMLS_D)
 +static php_http_url_t *php_http_url_from_env(void)
  {
        zval *https, *zhost, *zport;
        long port;
@@@ -71,7 -71,7 +71,7 @@@
  
        /* scheme */
        url(buf)->scheme = &buf.data[buf.used];
 -      https = php_http_env_get_server_var(ZEND_STRL("HTTPS"), 1 TSRMLS_CC);
 +      https = php_http_env_get_server_var(ZEND_STRL("HTTPS"), 1);
        if (https && !strcasecmp(Z_STRVAL_P(https), "ON")) {
                php_http_buffer_append(&buf, "https", sizeof("https"));
        } else {
@@@ -80,9 -80,9 +80,9 @@@
  
        /* host */
        url(buf)->host = &buf.data[buf.used];
 -      if ((((zhost = php_http_env_get_server_var(ZEND_STRL("HTTP_HOST"), 1 TSRMLS_CC)) ||
 -                      (zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_NAME"), 1 TSRMLS_CC)) ||
 -                      (zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_ADDR"), 1 TSRMLS_CC)))) && Z_STRLEN_P(zhost)) {
 +      if ((((zhost = php_http_env_get_server_var(ZEND_STRL("HTTP_HOST"), 1)) ||
 +                      (zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_NAME"), 1)) ||
 +                      (zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_ADDR"), 1)))) && Z_STRLEN_P(zhost)) {
                size_t stop_at = strspn(Z_STRVAL_P(zhost), "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-.");
  
                php_http_buffer_append(&buf, Z_STRVAL_P(zhost), stop_at);
@@@ -95,7 -95,7 +95,7 @@@
        }
  
        /* port */
 -      zport = php_http_env_get_server_var(ZEND_STRL("SERVER_PORT"), 1 TSRMLS_CC);
 +      zport = php_http_env_get_server_var(ZEND_STRL("SERVER_PORT"), 1);
        if (zport && IS_LONG == is_numeric_string(Z_STRVAL_P(zport), Z_STRLEN_P(zport), &port, NULL, 0)) {
                url(buf)->port = port;
        }
        } \
  } while (0)
  
 -php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_url_t *new_url, unsigned flags TSRMLS_DC)
 +php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_url_t *new_url, unsigned flags)
  {
        php_http_url_t *tmp_url = NULL;
        php_http_buffer_t buf;
  
        /* set from env if requested */
        if (flags & PHP_HTTP_URL_FROM_ENV) {
 -              php_http_url_t *env_url = php_http_url_from_env(TSRMLS_C);
 +              php_http_url_t *env_url = php_http_url_from_env();
  
 -              old_url = tmp_url = php_http_url_mod(env_url, old_url, flags ^ PHP_HTTP_URL_FROM_ENV TSRMLS_CC);
 +              old_url = tmp_url = php_http_url_mod(env_url, old_url, flags ^ PHP_HTTP_URL_FROM_ENV);
                php_http_url_free(&env_url);
        }
  
                if ((flags & PHP_HTTP_URL_JOIN_QUERY) && url_isset(new_url, query) && url_isset(old_url, query)) {
                        zval qarr, qstr;
                        
 -                      INIT_PZVAL(&qstr);
 -                      INIT_PZVAL(&qarr);
                        array_init(&qarr);
                        
 -                      ZVAL_STRING(&qstr, old_url->query, 0);
 -                      php_http_querystring_update(&qarr, &qstr, NULL TSRMLS_CC);
 -                      ZVAL_STRING(&qstr, new_url->query, 0);
 -                      php_http_querystring_update(&qarr, &qstr, NULL TSRMLS_CC);
 +                      ZVAL_STRING(&qstr, old_url->query);
 +                      php_http_querystring_update(&qarr, &qstr, NULL);
 +                      zval_ptr_dtor(&qstr);
 +                      ZVAL_STRING(&qstr, new_url->query);
 +                      php_http_querystring_update(&qarr, &qstr, NULL);
 +                      zval_ptr_dtor(&qstr);
                        
                        ZVAL_NULL(&qstr);
 -                      php_http_querystring_update(&qarr, NULL, &qstr TSRMLS_CC);
 +                      php_http_querystring_update(&qarr, NULL, &qstr);
  
                        url(buf)->query = &buf.data[buf.used];
                        url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL(qstr), Z_STRLEN(qstr) + 1));
@@@ -420,9 -420,9 +420,9 @@@ char *php_http_url_authority_to_string(
        return buf.data;
  }
  
 -php_http_url_t *php_http_url_from_zval(zval *value, unsigned flags TSRMLS_DC)
 +php_http_url_t *php_http_url_from_zval(zval *value, unsigned flags)
  {
 -      zval *zcpy;
 +      zend_string *zs;
        php_http_url_t *purl;
  
        switch (Z_TYPE_P(value)) {
                break;
  
        default:
 -              zcpy = php_http_ztyp(IS_STRING, value);
 -              purl = php_http_url_parse(Z_STRVAL_P(zcpy), Z_STRLEN_P(zcpy), flags TSRMLS_CC);
 -              zval_ptr_dtor(&zcpy);
 +              zs = zval_get_string(value);
 +              purl = php_http_url_parse(zs->val, zs->len, flags);
 +              zend_string_release(zs);
        }
  
        return purl;
  
  php_http_url_t *php_http_url_from_struct(HashTable *ht)
  {
 -      zval **e;
 +      zval *e;
        php_http_buffer_t buf;
  
        php_http_buffer_init_ex(&buf, MAX(PHP_HTTP_BUFFER_DEFAULT_SIZE, sizeof(php_http_url_t)<<2), PHP_HTTP_BUFFER_INIT_PREALLOC);
        php_http_buffer_account(&buf, sizeof(php_http_url_t));
        memset(buf.data, 0, buf.used);
  
 -      if (SUCCESS == zend_hash_find(ht, "scheme", sizeof("scheme"), (void *) &e)) {
 -              zval *cpy = php_http_ztyp(IS_STRING, *e);
 +      if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("scheme")))) {
 +              zend_string *zs = zval_get_string(e);
                url(buf)->scheme = &buf.data[buf.used];
 -              url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
 -              zval_ptr_dtor(&cpy);
 +              url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
 +              zend_string_release(zs);
        }
 -      if (SUCCESS == zend_hash_find(ht, "user", sizeof("user"), (void *) &e)) {
 -              zval *cpy = php_http_ztyp(IS_STRING, *e);
 +      if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("user")))) {
 +              zend_string *zs = zval_get_string(e);
                url(buf)->user = &buf.data[buf.used];
 -              url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
 -              zval_ptr_dtor(&cpy);
 +              url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
 +              zend_string_release(zs);
        }
 -      if (SUCCESS == zend_hash_find(ht, "pass", sizeof("pass"), (void *) &e)) {
 -              zval *cpy = php_http_ztyp(IS_STRING, *e);
 +      if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("pass")))) {
 +              zend_string *zs = zval_get_string(e);
                url(buf)->pass = &buf.data[buf.used];
 -              url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
 -              zval_ptr_dtor(&cpy);
 +              url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
 +              zend_string_release(zs);
        }
 -      if (SUCCESS == zend_hash_find(ht, "host", sizeof("host"), (void *) &e)) {
 -              zval *cpy = php_http_ztyp(IS_STRING, *e);
 +      if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("host")))) {
 +              zend_string *zs = zval_get_string(e);
                url(buf)->host = &buf.data[buf.used];
 -              url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
 -              zval_ptr_dtor(&cpy);
 +              url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
 +              zend_string_release(zs);
        }
 -      if (SUCCESS == zend_hash_find(ht, "port", sizeof("port"), (void *) &e)) {
 -              zval *cpy = php_http_ztyp(IS_LONG, *e);
 -              url(buf)->port = (unsigned short) Z_LVAL_P(cpy);
 -              zval_ptr_dtor(&cpy);
 +      if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("port")))) {
 +              url(buf)->port = (unsigned short) zval_get_long(e);
        }
 -      if (SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void *) &e)) {
 -              zval *cpy = php_http_ztyp(IS_STRING, *e);
 +      if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("path")))) {
 +              zend_string *zs = zval_get_string(e);
                url(buf)->path = &buf.data[buf.used];
 -              url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
 -              zval_ptr_dtor(&cpy);
 +              url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
 +              zend_string_release(zs);
        }
 -      if (SUCCESS == zend_hash_find(ht, "query", sizeof("query"), (void *) &e)) {
 -              zval *cpy = php_http_ztyp(IS_STRING, *e);
 +      if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("query")))) {
 +              zend_string *zs = zval_get_string(e);
                url(buf)->query = &buf.data[buf.used];
 -              url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
 -              zval_ptr_dtor(&cpy);
 +              url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
 +              zend_string_release(zs);
        }
 -      if (SUCCESS == zend_hash_find(ht, "fragment", sizeof("fragment"), (void *) &e)) {
 -              zval *cpy = php_http_ztyp(IS_STRING, *e);
 +      if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("fragment")))) {
 +              zend_string *zs = zval_get_string(e);
                url(buf)->fragment = &buf.data[buf.used];
 -              url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
 -              zval_ptr_dtor(&cpy);
 +              url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
 +              zend_string_release(zs);
        }
  
        return url(buf);
  }
  
 -HashTable *php_http_url_to_struct(const php_http_url_t *url, zval *strct TSRMLS_DC)
 +HashTable *php_http_url_to_struct(const php_http_url_t *url, zval *strct)
  {
 -      zval arr;
 +      HashTable *ht;
 +      zval tmp;
  
        if (strct) {
                switch (Z_TYPE_P(strct)) {
                                /* no break */
                        case IS_ARRAY:
                        case IS_OBJECT:
 -                              INIT_PZVAL_ARRAY((&arr), HASH_OF(strct));
 +                              ht = HASH_OF(strct);
                                break;
                }
        } else {
 -              INIT_PZVAL(&arr);
 -              array_init(&arr);
 +              ALLOC_HASHTABLE(ht);
 +              zend_hash_init(ht, 8, NULL, ZVAL_PTR_DTOR, 0);
 +      }
 +
 +#define url_struct_add(part) \
 +      if (Z_TYPE_P(strct) == IS_ARRAY) { \
 +              zend_hash_str_update(Z_ARRVAL_P(strct), part, lenof(part), &tmp); \
 +      } else { \
 +              zend_update_property(Z_OBJCE_P(strct), strct, part, lenof(part), &tmp); \
 +              zval_ptr_dtor(&tmp); \
        }
  
        if (url) {
                if (url->scheme) {
 -                      add_assoc_string(&arr, "scheme", url->scheme, 1);
 +                      ZVAL_STRING(&tmp, url->scheme);
 +                      url_struct_add("scheme");
                }
                if (url->user) {
 -                      add_assoc_string(&arr, "user", url->user, 1);
 +                      ZVAL_STRING(&tmp, url->user);
 +                      url_struct_add("user");
                }
                if (url->pass) {
 -                      add_assoc_string(&arr, "pass", url->pass, 1);
 +                      ZVAL_STRING(&tmp, url->pass);
 +                      url_struct_add("pass");
                }
                if (url->host) {
 -                      add_assoc_string(&arr, "host", url->host, 1);
 +                      ZVAL_STRING(&tmp, url->host);
 +                      url_struct_add("host");
                }
                if (url->port) {
 -                      add_assoc_long(&arr, "port", (long) url->port);
 +                      ZVAL_LONG(&tmp, url->port);
 +                      url_struct_add("port");
                }
                if (url->path) {
 -                      add_assoc_string(&arr, "path", url->path, 1);
 +                      ZVAL_STRING(&tmp, url->path);
 +                      url_struct_add("path");
                }
                if (url->query) {
 -                      add_assoc_string(&arr, "query", url->query, 1);
 +                      ZVAL_STRING(&tmp, url->query);
 +                      url_struct_add("query");
                }
                if (url->fragment) {
 -                      add_assoc_string(&arr, "fragment", url->fragment, 1);
 +                      ZVAL_STRING(&tmp, url->fragment);
 +                      url_struct_add("fragment");
                }
        }
  
 -      return Z_ARRVAL(arr);
 +      return ht;
  }
  
 -ZEND_RESULT_CODE php_http_url_encode_hash(HashTable *hash, const char *pre_encoded_str, size_t pre_encoded_len, char **encoded_str, size_t *encoded_len TSRMLS_DC)
 +ZEND_RESULT_CODE php_http_url_encode_hash(HashTable *hash, const char *pre_encoded_str, size_t pre_encoded_len, char **encoded_str, size_t *encoded_len)
  {
        const char *arg_sep_str;
        size_t arg_sep_len;
        php_http_buffer_t *qstr = php_http_buffer_new();
  
 -      php_http_url_argsep(&arg_sep_str, &arg_sep_len TSRMLS_CC);
 +      php_http_url_argsep(&arg_sep_str, &arg_sep_len);
  
 -      if (SUCCESS != php_http_url_encode_hash_ex(hash, qstr, arg_sep_str, arg_sep_len, "=", 1, pre_encoded_str, pre_encoded_len TSRMLS_CC)) {
 +      if (SUCCESS != php_http_url_encode_hash_ex(hash, qstr, arg_sep_str, arg_sep_len, "=", 1, pre_encoded_str, pre_encoded_len)) {
                php_http_buffer_free(&qstr);
                return FAILURE;
        }
        return SUCCESS;
  }
  
 -ZEND_RESULT_CODE php_http_url_encode_hash_ex(HashTable *hash, php_http_buffer_t *qstr, const char *arg_sep_str, size_t arg_sep_len, const char *val_sep_str, size_t val_sep_len, const char *pre_encoded_str, size_t pre_encoded_len TSRMLS_DC)
 +ZEND_RESULT_CODE php_http_url_encode_hash_ex(HashTable *hash, php_http_buffer_t *qstr, const char *arg_sep_str, size_t arg_sep_len, const char *val_sep_str, size_t val_sep_len, const char *pre_encoded_str, size_t pre_encoded_len)
  {
        if (pre_encoded_len && pre_encoded_str) {
                php_http_buffer_append(qstr, pre_encoded_str, pre_encoded_len);
        }
  
 -      if (!php_http_params_to_string(qstr, hash, arg_sep_str, arg_sep_len, "", 0, val_sep_str, val_sep_len, PHP_HTTP_PARAMS_QUERY TSRMLS_CC)) {
 +      if (!php_http_params_to_string(qstr, hash, arg_sep_str, arg_sep_len, "", 0, val_sep_str, val_sep_len, PHP_HTTP_PARAMS_QUERY)) {
                return FAILURE;
        }
  
  
  struct parse_state {
        php_http_url_t url;
 -#ifdef ZTS
 -      void ***ts;
 -#endif
        const char *ptr;
        const char *end;
        size_t maxlen;
@@@ -673,8 -661,9 +673,9 @@@ static size_t parse_mb_loc(unsigned *wc
        wchar_t wchar;
        size_t consumed = 0;
  #if defined(HAVE_MBRTOWC)
-       mbstate_t ps = {0};
+       mbstate_t ps;
  
+       memset(&ps, 0, sizeof(ps));
        consumed = mbrtowc(&wchar, ptr, end - ptr, &ps);
  #elif defined(HAVE_MBTOWC)
        consumed = mbtowc(&wchar, ptr, end - ptr);
@@@ -756,9 -745,16 +757,15 @@@ static size_t parse_mb(struct parse_sta
        }
  
        if (!silent) {
-               php_error_docref(NULL, E_WARNING,
-                               "Failed to parse %s; unexpected byte 0x%02x at pos %u in '%s'",
-                               parse_what[what], (unsigned char) *ptr, (unsigned) (ptr - begin), begin);
 -              TSRMLS_FETCH_FROM_CTX(state->ts);
+               if (consumed) {
 -                      php_error_docref(NULL TSRMLS_CC, E_WARNING,
++                      php_error_docref(NULL, E_WARNING,
+                                       "Failed to parse %s; unexpected multibyte sequence 0x%x at pos %u in '%s'",
+                                       parse_what[what], wchar, (unsigned) (ptr - begin), begin);
+               } else {
 -                      php_error_docref(NULL TSRMLS_CC, E_WARNING,
++                      php_error_docref(NULL, E_WARNING,
+                                       "Failed to parse %s; unexpected byte 0x%02x at pos %u in '%s'",
+                                       parse_what[what], (unsigned char) *ptr, (unsigned) (ptr - begin), begin);
+               }
        }
  
        return 0;
@@@ -768,6 -764,7 +775,6 @@@ static ZEND_RESULT_CODE parse_userinfo(
  {
        size_t mb;
        const char *password = NULL, *end = state->ptr, *tmp = ptr;
 -      TSRMLS_FETCH_FROM_CTX(state->ts);
  
        state->url.user = &state->buffer[state->offset];
  
                switch (*ptr) {
                case ':':
                        if (password) {
 -                              php_error_docref(NULL TSRMLS_CC, E_WARNING,
 +                              php_error_docref(NULL, E_WARNING,
                                                "Failed to parse password; duplicate ':' at pos %u in '%s'",
                                                (unsigned) (ptr - tmp), tmp);
                                return FAILURE;
  
                case '%':
                        if (ptr[1] != '%' && (end - ptr <= 2 || !isxdigit(*(ptr+1)) || !isxdigit(*(ptr+2)))) {
 -                              php_error_docref(NULL TSRMLS_CC, E_WARNING,
 +                              php_error_docref(NULL, E_WARNING,
                                                "Failed to parse userinfo; invalid percent encoding at pos %u in '%s'",
                                                (unsigned) (ptr - tmp), tmp);
                                return FAILURE;
        return SUCCESS;
  }
  
 -                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse UTF-8 at pos %zu of '%s'", offset, u8);
+ #if defined(PHP_WIN32) || defined(HAVE_UIDNA_IDNTOASCII)
+ typedef size_t (*parse_mb_func)(unsigned *wc, const char *ptr, const char *end);
+ static ZEND_RESULT_CODE to_utf16(parse_mb_func fn, const char *u8, uint16_t **u16, size_t *len)
+ {
+       size_t offset = 0, u8_len = strlen(u8);
+       *u16 = ecalloc(4 * sizeof(uint16_t), u8_len + 1);
+       *len = 0;
+       while (offset < u8_len) {
+               unsigned wc;
+               uint16_t buf[2], *ptr = buf;
+               size_t consumed = fn(&wc, &u8[offset], &u8[u8_len]);
+               if (!consumed) {
+                       efree(*u16);
 -                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to convert UTF-32 'U+%X' to UTF-16", wc);
++                      php_error_docref(NULL, E_WARNING, "Failed to parse UTF-8 at pos %zu of '%s'", offset, u8);
+                       return FAILURE;
+               } else {
+                       offset += consumed;
+               }
+               switch (wctoutf16(buf, wc)) {
+               case 2:
+                       (*u16)[(*len)++] = *ptr++;
+                       /* no break */
+               case 1:
+                       (*u16)[(*len)++] = *ptr++;
+                       break;
+               case 0:
+               default:
+                       efree(*u16);
 -      TSRMLS_FETCH_FROM_CTX(state->ts);
++                      php_error_docref(NULL, E_WARNING, "Failed to convert UTF-32 'U+%X' to UTF-16", wc);
+                       return FAILURE;
+               }
+       }
+       return SUCCESS;
+ }
+ #endif
+ #ifndef MAXHOSTNAMELEN
+ #     define MAXHOSTNAMELEN 256
+ #endif
+ #ifdef PHP_HTTP_HAVE_IDN
+ static ZEND_RESULT_CODE parse_idn(struct parse_state *state, size_t prev_len)
+ {
+       char *idn = NULL;
+       int rv = -1;
 -              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse IDN; %s", idna_strerror(rv));
+       if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
+               rv = idna_to_ascii_8z(state->url.host, &idn, IDNA_ALLOW_UNASSIGNED|IDNA_USE_STD3_ASCII_RULES);
+       }
+ #     ifdef PHP_HTTP_HAVE_WCHAR
+       else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) {
+               rv = idna_to_ascii_lz(state->url.host, &idn, IDNA_ALLOW_UNASSIGNED|IDNA_USE_STD3_ASCII_RULES);
+       }
+ #     endif
+       if (rv != IDNA_SUCCESS) {
 -              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse IDN; codepage not specified");
++              php_error_docref(NULL, E_WARNING, "Failed to parse IDN; %s", idna_strerror(rv));
+               return FAILURE;
+       } else {
+               size_t idnlen = strlen(idn);
+               memcpy(state->url.host, idn, idnlen + 1);
+               free(idn);
+               state->offset += idnlen - prev_len;
+               return SUCCESS;
+       }
+ }
+ #endif
+ #ifdef HAVE_UIDNA_IDNTOASCII
+ #     if HAVE_UNICODE_UIDNA_H
+ #             include <unicode/uidna.h>
+ #     else
+ typedef uint16_t UChar;
+ typedef enum { U_ZERO_ERROR = 0 } UErrorCode;
+ int32_t uidna_IDNToASCII(const UChar *src, int32_t srcLength, UChar *dest, int32_t destCapacity, int32_t options, void *parseError, UErrorCode *status);
+ #     endif
+ static ZEND_RESULT_CODE parse_uidn(struct parse_state *state)
+ {
+       char *host_ptr;
+       uint16_t *uhost_str, ahost_str[MAXHOSTNAMELEN], *ahost_ptr;
+       size_t uhost_len, ahost_len;
+       UErrorCode error = U_ZERO_ERROR;
+       TSRMLS_FETCH_FROM_CTX(state->ts);
+       if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
+               if (SUCCESS != to_utf16(parse_mb_utf8, state->url.host, &uhost_str, &uhost_len)) {
+                       return FAILURE;
+               }
+ #ifdef PHP_HTTP_HAVE_WCHAR
+       } else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) {
+               if (SUCCESS != to_utf16(parse_mb_loc, state->url.host, &uhost_str, &uhost_len)) {
+                       return FAILURE;
+               }
+ #endif
+       } else {
 -              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse IDN; ICU error %d", error);
++              php_error_docref(NULL, E_WARNING, "Failed to parse IDN; codepage not specified");
+               return FAILURE;
+       }
+       ahost_len = uidna_IDNToASCII(uhost_str, uhost_len, ahost_str, MAXHOSTNAMELEN, 3, NULL, &error);
+       efree(uhost_str);
+       if (error != U_ZERO_ERROR) {
 -      TSRMLS_FETCH_FROM_CTX(state->ts);
++              php_error_docref(NULL, E_WARNING, "Failed to parse IDN; ICU error %d", error);
+               return FAILURE;
+       }
+       host_ptr = state->url.host;
+       ahost_ptr = ahost_str;
+       PHP_HTTP_DUFF(ahost_len, *host_ptr++ = *ahost_ptr++);
+       *host_ptr = '\0';
+       state->offset += host_ptr - state->url.host;
+       return SUCCESS;
+ }
+ #endif
+ #if 0 && defined(PHP_WIN32)
+ static ZEND_RESULT_CODE parse_widn(struct parse_state *state)
+ {
+       char *host_ptr;
+       uint16_t *uhost_str, ahost_str[MAXHOSTNAMELEN], *ahost_ptr;
+       size_t uhost_len;
 -                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse IDN");
+       if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
+               if (SUCCESS != to_utf16(parse_mb_utf8, state->url.host, &uhost_str, &uhost_len)) {
 -                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse IDN");
++                      php_error_docref(NULL, E_WARNING, "Failed to parse IDN");
+                       return FAILURE;
+               }
+ #ifdef PHP_HTTP_HAVE_WCHAR
+       } else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) {
+               if (SUCCESS != to_utf16(parse_mb_loc, state->url.host, &uhost_str, &uhost_len)) {
 -              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse IDN");
++                      php_error_docref(NULL, E_WARNING, "Failed to parse IDN");
+                       return FAILURE;
+               }
+ #endif
+       } else {
 -              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse IDN");
++              php_error_docref(NULL, E_WARNING, "Failed to parse IDN");
+               return FAILURE;
+       }
+       if (!IdnToAscii(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES, uhost_str, uhost_len, ahost_str, MAXHOSTNAMELEN)) {
+               efree(uhost_str);
++              php_error_docref(NULL, E_WARNING, "Failed to parse IDN");
+               return FAILURE;
+       }
+       efree(uhost_str);
+       host_ptr = state->url.host;
+       ahost_ptr = ahost_str;
+       PHP_HTTP_DUFF(wcslen(ahost_str), *host_ptr++ = *ahost_ptr++);
+       efree(ahost_str);
+       *host_ptr = '\0';
+       state->offset += host_ptr - state->url.host;
+       return SUCCESS;
+ }
+ #endif
  static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *ptr)
  {
        size_t mb, len;
        const char *end = state->ptr, *tmp = ptr, *port = NULL;
 -      TSRMLS_FETCH_FROM_CTX(state->ts);
  
  #ifdef HAVE_INET_PTON
        if (*ptr == '[') {
                char *error = NULL, *tmp = memchr(ptr, ']', end - ptr);
                }
  
                if (error) {
 -                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse hostinfo; %s", error);
 +                      php_error_docref(NULL, E_WARNING, "Failed to parse hostinfo; %s", error);
                        return FAILURE;
                }
        }
                switch (*ptr) {
                case ':':
                        if (port) {
 -                              php_error_docref(NULL TSRMLS_CC, E_WARNING,
 +                              php_error_docref(NULL, E_WARNING,
                                                "Failed to parse port; unexpected ':' at pos %u in '%s'",
                                                (unsigned) (ptr - tmp), tmp);
                                return FAILURE;
  
                case '%':
                        if (ptr[1] != '%' && (end - ptr <= 2 || !isxdigit(*(ptr+1)) || !isxdigit(*(ptr+2)))) {
 -                              php_error_docref(NULL TSRMLS_CC, E_WARNING,
 +                              php_error_docref(NULL, E_WARNING,
                                                "Failed to parse hostinfo; invalid percent encoding at pos %u in '%s'",
                                                (unsigned) (ptr - tmp), tmp);
                                return FAILURE;
                case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
                case 'v': case 'w': case 'x': case 'y': case 'z':
                        if (port) {
 -                              php_error_docref(NULL TSRMLS_CC, E_WARNING,
 +                              php_error_docref(NULL, E_WARNING,
                                                "Failed to parse port; unexpected char '%c' at pos %u in '%s'",
                                                (unsigned char) *ptr, (unsigned) (ptr - tmp), tmp);
                                return FAILURE;
                        if (ptr == end) {
                                break;
                        } else if (port) {
 -                              php_error_docref(NULL TSRMLS_CC, E_WARNING,
 +                              php_error_docref(NULL, E_WARNING,
                                                "Failed to parse port; unexpected byte 0x%02x at pos %u in '%s'",
                                                (unsigned char) *ptr, (unsigned) (ptr - tmp), tmp);
                                return FAILURE;
                state->buffer[state->offset++] = 0;
        }
  
- #ifdef PHP_HTTP_HAVE_IDN
        if (state->flags & PHP_HTTP_URL_PARSE_TOIDN) {
-               char *idn = NULL;
-               int rv = -1;
-               if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
-                       rv = idna_to_ascii_8z(state->url.host, &idn, IDNA_ALLOW_UNASSIGNED|IDNA_USE_STD3_ASCII_RULES);
-               }
- #     ifdef PHP_HTTP_HAVE_WCHAR
-               else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) {
-                       rv = idna_to_ascii_lz(state->url.host, &idn, IDNA_ALLOW_UNASSIGNED|IDNA_USE_STD3_ASCII_RULES);
-               }
- #     endif
-               if (rv != IDNA_SUCCESS) {
-                       php_error_docref(NULL, E_WARNING, "Failed to parse IDN; %s", idna_strerror(rv));
-                       return FAILURE;
-               } else {
-                       size_t idnlen = strlen(idn);
-                       memcpy(state->url.host, idn, idnlen + 1);
-                       free(idn);
-                       state->offset += idnlen - len;
-               }
-       }
+ #ifdef PHP_HTTP_HAVE_IDN
+               return parse_idn(state, len);
+ #endif
+ #ifdef HAVE_UIDNA_IDNTOASCII
+               return parse_uidn(state);
  #endif
+ #if 0 && defined(PHP_WIN32)
+               return parse_widn(state);
+ #endif
+       }
  
        return SUCCESS;
  }
@@@ -978,7 -1129,8 +1136,7 @@@ static const char *parse_authority(stru
                case '@':
                        /* userinfo delimiter */
                        if (host) {
 -                              TSRMLS_FETCH_FROM_CTX(state->ts);
 -                              php_error_docref(NULL TSRMLS_CC, E_WARNING,
 +                              php_error_docref(NULL, E_WARNING,
                                                "Failed to parse userinfo; unexpected '@'");
                                return NULL;
                        }
@@@ -1010,6 -1162,7 +1168,6 @@@ static const char *parse_path(struct pa
  {
        size_t mb;
        const char *tmp;
 -      TSRMLS_FETCH_FROM_CTX(state->ts);
  
        /* is there actually a path to parse? */
        if (!*state->ptr) {
  
                case '%':
                        if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) {
 -                              php_error_docref(NULL TSRMLS_CC, E_WARNING,
 +                              php_error_docref(NULL, E_WARNING,
                                                "Failed to parse path; invalid percent encoding at pos %u in '%s'",
                                                (unsigned) (state->ptr - tmp), tmp);
                                return NULL;
@@@ -1077,6 -1230,7 +1235,6 @@@ static const char *parse_query(struct p
  {
        size_t mb;
        const char *tmp = state->ptr + !!*state->ptr;
 -      TSRMLS_FETCH_FROM_CTX(state->ts);
  
        /* is there actually a query to parse? */
        if (*state->ptr != '?') {
  
                case '%':
                        if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) {
 -                              php_error_docref(NULL TSRMLS_CC, E_WARNING,
 +                              php_error_docref(NULL, E_WARNING,
                                                "Failed to parse query; invalid percent encoding at pos %u in '%s'",
                                                (unsigned) (state->ptr - tmp), tmp);
                                return NULL;
@@@ -1150,6 -1304,7 +1308,6 @@@ static const char *parse_fragment(struc
  {
        size_t mb;
        const char *tmp;
 -      TSRMLS_FETCH_FROM_CTX(state->ts);
  
        /* is there actually a fragment to parse? */
        if (*state->ptr != '#') {
                switch (*state->ptr) {
                case '%':
                        if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) {
 -                              php_error_docref(NULL TSRMLS_CC, E_WARNING,
 +                              php_error_docref(NULL, E_WARNING,
                                                "Failed to parse fragment; invalid percent encoding at pos %u in '%s'",
                                                (unsigned) (state->ptr - tmp), tmp);
                                return NULL;
@@@ -1264,7 -1419,7 +1422,7 @@@ static const char *parse_scheme(struct 
        return state->ptr = tmp;
  }
  
 -php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags TSRMLS_DC)
 +php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags)
  {
        size_t maxlen = 3 * len;
        struct parse_state *state = ecalloc(1, sizeof(*state) + maxlen);
        state->ptr = str;
        state->flags = flags;
        state->maxlen = maxlen;
 -      TSRMLS_SET_CTX(state->ts);
  
        if (!parse_scheme(state)) {
 -              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse URL scheme: '%s'", state->ptr);
 +              php_error_docref(NULL, E_WARNING, "Failed to parse URL scheme: '%s'", state->ptr);
                efree(state);
                return NULL;
        }
        }
  
        if (!parse_query(state)) {
 -              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse URL query: '%s'", state->ptr);
 +              php_error_docref(NULL, E_WARNING, "Failed to parse URL query: '%s'", state->ptr);
                efree(state);
                return NULL;
        }
  
        if (!parse_fragment(state)) {
 -              php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse URL fragment: '%s'", state->ptr);
 +              php_error_docref(NULL, E_WARNING, "Failed to parse URL fragment: '%s'", state->ptr);
                efree(state);
                return NULL;
        }
        return (php_http_url_t *) state;
  }
  
 -php_http_url_t *php_http_url_parse_authority(const char *str, size_t len, unsigned flags TSRMLS_DC)
 +php_http_url_t *php_http_url_parse_authority(const char *str, size_t len, unsigned flags)
  {
        size_t maxlen = 3 * len;
        struct parse_state *state = ecalloc(1, sizeof(*state) + maxlen);
@@@ -1335,35 -1491,35 +1493,35 @@@ ZEND_END_ARG_INFO()
  PHP_METHOD(HttpUrl, __construct)
  {
        zval *new_url = NULL, *old_url = NULL;
 -      long flags = PHP_HTTP_URL_FROM_ENV;
 +      zend_long flags = PHP_HTTP_URL_FROM_ENV;
        zend_error_handling zeh;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z!z!l", &old_url, &new_url, &flags), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!z!l", &old_url, &new_url, &flags), invalid_arg, return);
  
 -      zend_replace_error_handling(EH_THROW, php_http_exception_bad_url_class_entry, &zeh TSRMLS_CC);
 +      zend_replace_error_handling(EH_THROW, php_http_exception_bad_url_class_entry, &zeh);
        {
                php_http_url_t *res_purl, *new_purl = NULL, *old_purl = NULL;
  
                if (new_url) {
 -                      new_purl = php_http_url_from_zval(new_url, flags TSRMLS_CC);
 +                      new_purl = php_http_url_from_zval(new_url, flags);
                        if (!new_purl) {
 -                              zend_restore_error_handling(&zeh TSRMLS_CC);
 +                              zend_restore_error_handling(&zeh);
                                return;
                        }
                }
                if (old_url) {
 -                      old_purl = php_http_url_from_zval(old_url, flags TSRMLS_CC);
 +                      old_purl = php_http_url_from_zval(old_url, flags);
                        if (!old_purl) {
                                if (new_purl) {
                                        php_http_url_free(&new_purl);
                                }
 -                              zend_restore_error_handling(&zeh TSRMLS_CC);
 +                              zend_restore_error_handling(&zeh);
                                return;
                        }
                }
  
 -              res_purl = php_http_url_mod(old_purl, new_purl, flags TSRMLS_CC);
 -              php_http_url_to_struct(res_purl, getThis() TSRMLS_CC);
 +              res_purl = php_http_url_mod(old_purl, new_purl, flags);
 +              php_http_url_to_struct(res_purl, getThis());
  
                php_http_url_free(&res_purl);
                if (old_purl) {
                        php_http_url_free(&new_purl);
                }
        }
 -      zend_restore_error_handling(&zeh TSRMLS_CC);
 +      zend_restore_error_handling(&zeh);
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_mod, 0, 0, 1)
@@@ -1383,19 -1539,19 +1541,19 @@@ ZEND_END_ARG_INFO()
  PHP_METHOD(HttpUrl, mod)
  {
        zval *new_url = NULL;
 -      long flags = PHP_HTTP_URL_JOIN_PATH | PHP_HTTP_URL_JOIN_QUERY;
 +      zend_long flags = PHP_HTTP_URL_JOIN_PATH | PHP_HTTP_URL_JOIN_QUERY;
        zend_error_handling zeh;
  
 -      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!|l", &new_url, &flags), invalid_arg, return);
 +      php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z!|l", &new_url, &flags), invalid_arg, return);
  
 -      zend_replace_error_handling(EH_THROW, php_http_exception_bad_url_class_entry, &zeh TSRMLS_CC);
 +      zend_replace_error_handling(EH_THROW, php_http_exception_bad_url_class_entry, &zeh);
        {
                php_http_url_t *new_purl = NULL, *old_purl = NULL;
  
                if (new_url) {
 -                      new_purl = php_http_url_from_zval(new_url, flags TSRMLS_CC);
 +                      new_purl = php_http_url_from_zval(new_url, flags);
                        if (!new_purl) {
 -                              zend_restore_error_handling(&zeh TSRMLS_CC);
 +                              zend_restore_error_handling(&zeh);
                                return;
                        }
                }
                if ((old_purl = php_http_url_from_struct(HASH_OF(getThis())))) {
                        php_http_url_t *res_purl;
  
 -                      ZVAL_OBJVAL(return_value, zend_objects_clone_obj(getThis() TSRMLS_CC), 0);
 +                      ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis()));
  
 -                      res_purl = php_http_url_mod(old_purl, new_purl, flags TSRMLS_CC);
 -                      php_http_url_to_struct(res_purl, return_value TSRMLS_CC);
 +                      res_purl = php_http_url_mod(old_purl, new_purl, flags);
 +                      php_http_url_to_struct(res_purl, return_value);
  
                        php_http_url_free(&res_purl);
                        php_http_url_free(&old_purl);
                        php_http_url_free(&new_purl);
                }
        }
 -      zend_restore_error_handling(&zeh TSRMLS_CC);
 +      zend_restore_error_handling(&zeh);
  }
  
  ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_toString, 0, 0, 0)
@@@ -1431,7 -1587,7 +1589,7 @@@ PHP_METHOD(HttpUrl, toString
  
                        php_http_url_to_string(purl, &str, &len, 0);
                        php_http_url_free(&purl);
 -                      RETURN_STRINGL(str, len, 0);
 +                      RETURN_STR(php_http_cs2zs(str, len));
                }
        }
        RETURN_EMPTY_STRING();
@@@ -1449,7 -1605,7 +1607,7 @@@ PHP_METHOD(HttpUrl, toArray
  
        /* strip any non-URL properties */
        purl = php_http_url_from_struct(HASH_OF(getThis()));
 -      php_http_url_to_struct(purl, return_value TSRMLS_CC);
 +      php_http_url_to_struct(purl, return_value);
        php_http_url_free(&purl);
  }
  
@@@ -1469,39 -1625,39 +1627,39 @@@ PHP_MINIT_FUNCTION(http_url
        zend_class_entry ce = {0};
  
        INIT_NS_CLASS_ENTRY(ce, "http", "Url", php_http_url_methods);
 -      php_http_url_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
 -
 -      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("scheme"), ZEND_ACC_PUBLIC TSRMLS_CC);
 -      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("user"), ZEND_ACC_PUBLIC TSRMLS_CC);
 -      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("pass"), ZEND_ACC_PUBLIC TSRMLS_CC);
 -      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("host"), ZEND_ACC_PUBLIC TSRMLS_CC);
 -      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("port"), ZEND_ACC_PUBLIC TSRMLS_CC);
 -      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("path"), ZEND_ACC_PUBLIC TSRMLS_CC);
 -      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("query"), ZEND_ACC_PUBLIC TSRMLS_CC);
 -      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("fragment"), ZEND_ACC_PUBLIC TSRMLS_CC);
 -
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("REPLACE"), PHP_HTTP_URL_REPLACE TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("JOIN_PATH"), PHP_HTTP_URL_JOIN_PATH TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("JOIN_QUERY"), PHP_HTTP_URL_JOIN_QUERY TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_USER"), PHP_HTTP_URL_STRIP_USER TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PASS"), PHP_HTTP_URL_STRIP_PASS TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_AUTH"), PHP_HTTP_URL_STRIP_AUTH TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PORT"), PHP_HTTP_URL_STRIP_PORT TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PATH"), PHP_HTTP_URL_STRIP_PATH TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_QUERY"), PHP_HTTP_URL_STRIP_QUERY TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_FRAGMENT"), PHP_HTTP_URL_STRIP_FRAGMENT TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_ALL"), PHP_HTTP_URL_STRIP_ALL TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("FROM_ENV"), PHP_HTTP_URL_FROM_ENV TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("SANITIZE_PATH"), PHP_HTTP_URL_SANITIZE_PATH TSRMLS_CC);
 +      php_http_url_class_entry = zend_register_internal_class(&ce);
 +
 +      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("scheme"), ZEND_ACC_PUBLIC);
 +      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("user"), ZEND_ACC_PUBLIC);
 +      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("pass"), ZEND_ACC_PUBLIC);
 +      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("host"), ZEND_ACC_PUBLIC);
 +      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("port"), ZEND_ACC_PUBLIC);
 +      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("path"), ZEND_ACC_PUBLIC);
 +      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("query"), ZEND_ACC_PUBLIC);
 +      zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("fragment"), ZEND_ACC_PUBLIC);
 +
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("REPLACE"), PHP_HTTP_URL_REPLACE);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("JOIN_PATH"), PHP_HTTP_URL_JOIN_PATH);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("JOIN_QUERY"), PHP_HTTP_URL_JOIN_QUERY);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_USER"), PHP_HTTP_URL_STRIP_USER);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PASS"), PHP_HTTP_URL_STRIP_PASS);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_AUTH"), PHP_HTTP_URL_STRIP_AUTH);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PORT"), PHP_HTTP_URL_STRIP_PORT);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PATH"), PHP_HTTP_URL_STRIP_PATH);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_QUERY"), PHP_HTTP_URL_STRIP_QUERY);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_FRAGMENT"), PHP_HTTP_URL_STRIP_FRAGMENT);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_ALL"), PHP_HTTP_URL_STRIP_ALL);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("FROM_ENV"), PHP_HTTP_URL_FROM_ENV);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("SANITIZE_PATH"), PHP_HTTP_URL_SANITIZE_PATH);
  
  #ifdef PHP_HTTP_HAVE_WCHAR
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_MBLOC"), PHP_HTTP_URL_PARSE_MBLOC TSRMLS_CC);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_MBLOC"), PHP_HTTP_URL_PARSE_MBLOC);
  #endif
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_MBUTF8"), PHP_HTTP_URL_PARSE_MBUTF8 TSRMLS_CC);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_MBUTF8"), PHP_HTTP_URL_PARSE_MBUTF8);
- #ifdef PHP_HTTP_HAVE_IDN
+ #if defined(PHP_HTTP_HAVE_IDN) || defined(HAVE_UIDNA_IDNTOASCII)
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_TOIDN"), PHP_HTTP_URL_PARSE_TOIDN TSRMLS_CC);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_TOIDN"), PHP_HTTP_URL_PARSE_TOIDN);
  #endif
 -      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_TOPCT"), PHP_HTTP_URL_PARSE_TOPCT TSRMLS_CC);
 +      zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_TOPCT"), PHP_HTTP_URL_PARSE_TOPCT);
  
        return SUCCESS;
  }
index 0000000000000000000000000000000000000000,a50417417c5dd287ad69015ccdd8d178fac4dbc9..caa1745bf2cbc0d8334eaf322a364212e65b3fd3
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,22 +1,22 @@@
 -foo=baz&bar=baz
+ --TEST--
+ querystring offset set
+ --SKIPIF--
+ <?php
+ include "skipif.inc";
+ ?>
+ --FILE--
+ <?php
+ echo "Test\n";
+ $qs = new http\QueryString("foo=bar&bar=baz");
+ echo $qs,"\n";
+ $qs["foo"] = "baz";
+ echo $qs,"\n";
+ ?>
+ ===DONE===
+ --EXPECT--
+ Test
+ foo=bar&bar=baz
++bar=baz&foo=baz
+ ===DONE===