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 --cc config9.m4
Simple merge
diff --cc php_http.c
Simple merge
diff --cc php_http_api.h
Simple merge
diff --cc php_http_env.c
  #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) {
@@@ -476,15 -430,15 +422,16 @@@ ZEND_RESULT_CODE php_http_env_set_respo
        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;
  }
@@@ -902,12 -803,8 +802,8 @@@ 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 --cc php_http_env.h
@@@ -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
Simple merge
@@@ -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);
  }
  
diff --cc php_http_url.c
@@@ -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;
@@@ -828,12 -825,179 +835,176 @@@ static ZEND_RESULT_CODE parse_userinfo(
        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);
@@@ -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 0000000,a504174..caa1745
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===