Merge branch 'master' into phpng
authorMichael Wallner <mike@php.net>
Fri, 12 Jun 2015 08:30:13 +0000 (10:30 +0200)
committerMichael Wallner <mike@php.net>
Fri, 12 Jun 2015 08:30:13 +0000 (10:30 +0200)
1  2 
config9.m4
php_http.c
php_http_client_curl.c
php_http_env_response.c
php_http_info.h
php_http_message_parser.c
php_http_misc.h
php_http_params.c
php_http_params.h
php_http_url.c

diff --cc config9.m4
Simple merge
diff --cc php_http.c
Simple merge
@@@ -653,9 -630,11 +661,10 @@@ static php_http_message_t *php_http_cur
  
  static void php_http_curlm_responsehandler(php_http_client_t *context)
  {
-       int remaining = 0;
+       int err_count = 0, remaining = 0;
+       php_http_curle_storage_t *st, *err = NULL;
        php_http_client_enqueue_t *enqueue;
        php_http_client_curl_t *curl = context->ctx;
 -      TSRMLS_FETCH_FROM_CTX(context->ts);
  
        do {
                CURLMsg *msg = curl_multi_info_read(curl->handle, &remaining);
@@@ -2306,10 -2302,10 +2333,10 @@@ static ZEND_RESULT_CODE php_http_client
  #endif
  
                        if (ev_rc < 0) {
 -                              php_error_docref(NULL TSRMLS_CC, E_ERROR, "Error in event_base_dispatch()");
 +                              php_error_docref(NULL, E_ERROR, "Error in event_base_dispatch()");
                                return FAILURE;
                        }
-               } while (curl->unfinished);
+               } while (curl->unfinished && !EG(exception));
        } else
  #endif
        {
@@@ -207,7 -228,10 +207,9 @@@ php_http_cache_status_t php_http_env_is
  
  static zend_bool php_http_env_response_is_cacheable(php_http_env_response_t *r, php_http_message_t *request)
  {
-       if (r->ops->get_status(r) >= 400) {
 -      TSRMLS_FETCH_FROM_CTX(r->ts);
+       long status = r->ops->get_status(r);
+       if (status && status / 100 != 2) {
                return 0;
        }
  
@@@ -1157,8 -1214,16 +1159,13 @@@ static PHP_METHOD(HttpEnvResponse, __in
                PHP_HTTP_ENV_RESPONSE_OBJECT_INIT(obj);
  
                php_http_message_object_init_body_object(obj);
-               php_http_message_body_append(obj->message->body, ob_str, ob_len);
 -              php_http_message_body_append(obj->message->body, ob_str, ob_len);
 -#if PHP_VERSION_ID >= 50400
+               if (ob_flags & PHP_OUTPUT_HANDLER_CLEAN) {
+                       php_stream_truncate_set_size(php_http_message_body_stream(obj->message->body), 0);
++              } else {
++                      php_http_message_body_append(obj->message->body, ob_str, ob_len);
+               }
                RETURN_TRUE;
 -#else
 -              RETURN_EMPTY_STRING();
 -#endif
        }
  }
  
diff --cc php_http_info.h
@@@ -41,6 -41,6 +41,8 @@@ typedef struct php_http_info_data 
        php_http_version_t version;
  } php_http_info_data_t;
  
++#undef PHP_HTTP_REQUEST
++#undef PHP_HTTP_RESPONSE
  typedef enum php_http_info_type {
        PHP_HTTP_NONE = 0,
        PHP_HTTP_REQUEST,
Simple merge
diff --cc php_http_misc.h
@@@ -139,30 -139,77 +139,35 @@@ static inline const char *php_http_loca
  
  /* ZEND */
  
 -#if PHP_VERSION_ID < 50400
 -#     define object_properties_init(o, ce) zend_hash_copy(((zend_object *) o)->properties, &(ce->default_properties), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*))
 -#     define PHP_HTTP_ZEND_LITERAL_DC 
 -#     define PHP_HTTP_ZEND_LITERAL_CC
 -#     define PHP_HTTP_ZEND_LITERAL_CCN
 -#     define ZVAL_COPY_VALUE(zv, arr) do { \
 -              (zv)->value = (arr)->value; \
 -              Z_TYPE_P(zv) = Z_TYPE_P(arr); \
 -      } while (0)
 -#else
 -#     define PHP_HTTP_ZEND_LITERAL_DC , const zend_literal *literal_key
 -#     define PHP_HTTP_ZEND_LITERAL_CC , (literal_key)
 -#     define PHP_HTTP_ZEND_LITERAL_CCN , NULL
++#ifdef PHP_DEBUG
++#     undef  HASH_OF
++#     define HASH_OF(p) ((HashTable*)(Z_TYPE_P(p)==IS_ARRAY ? Z_ARRVAL_P(p) : ((Z_TYPE_P(p)==IS_OBJECT ? Z_OBJ_HT_P(p)->get_properties((p)) : NULL))))
+ #endif
 -#if PHP_VERSION_ID < 50500
 -#undef SUCCESS
 -#undef FAILURE
 -typedef enum {
 -      SUCCESS = 0,
 -      FAILURE = -1
 -} ZEND_RESULT_CODE;
 -#endif
 -
 -#if PHP_VERSION_ID < 50700
 -#     define z_is_true zend_is_true
 -#else
 -#     define z_is_true(z) zend_is_true(z TSRMLS_CC)
 -#endif
 -
 -#define INIT_PZVAL_ARRAY(zv, ht) \
 -      { \
 -              INIT_PZVAL((zv)); \
 -              Z_TYPE_P(zv) = IS_ARRAY; \
 -              Z_ARRVAL_P(zv) = (ht); \
 -      }
 -
 -static inline zval *php_http_zconv(int type, zval *z)
 +static inline void *PHP_HTTP_OBJ(zend_object *zo, zval *zv)
  {
 -      switch (type) {
 -              case IS_NULL:   convert_to_null_ex(&z);         break;
 -              case IS_BOOL:   convert_to_boolean_ex(&z);      break;
 -              case IS_LONG:   convert_to_long_ex(&z);         break;
 -              case IS_DOUBLE: convert_to_double_ex(&z);       break;
 -              case IS_STRING: convert_to_string_ex(&z);       break;
 -              case IS_ARRAY:  convert_to_array_ex(&z);        break;
 -              case IS_OBJECT: convert_to_object_ex(&z);       break;
 +      if (!zo) {
 +              zo = Z_OBJ_P(zv);
        }
 -      return z;
 +      return (char *) zo - zo->handlers->offset;
  }
  
 -static inline zval *php_http_ztyp(int type, zval *z)
 +static inline zend_string *php_http_cs2zs(char *s, size_t l)
  {
 -      SEPARATE_ARG_IF_REF(z);
 -      return (Z_TYPE_P(z) == type) ? z : php_http_zconv(type, z);
 -}
 +      zend_string *str = erealloc(s, sizeof(*str) + l);
  
 -static inline zval *php_http_zsep(zend_bool add_ref, int type, zval *z)
 -{
 -      if (add_ref) {
 -              Z_ADDREF_P(z);
 -      }
 -      if (Z_TYPE_P(z) != type) {
 -              return php_http_zconv(type, z);
 -      } else {
 -              SEPARATE_ZVAL_IF_NOT_REF(&z);
 -              return z;
 -      }
 +      memmove(str->val, str, l);
 +      str->val[l] = 0;
 +      str->len = l;
 +      str->h = 0;
 +
 +      GC_REFCOUNT(str) = 1;
 +      GC_TYPE_INFO(str) = IS_STRING;
 +
 +      return str;
  }
  
 -static inline ZEND_RESULT_CODE php_http_ini_entry(const char *name_str, size_t name_len, const char **value_str, size_t *value_len, zend_bool orig TSRMLS_DC)
 +static inline ZEND_RESULT_CODE php_http_ini_entry(const char *name_str, size_t name_len, const char **val_str, size_t *val_len, zend_bool orig)
  {
        zend_ini_entry *ini_entry;
  
@@@ -57,35 -57,38 +57,59 @@@ static inline void sanitize_escaped(zva
                char *deq = estrndup(Z_STRVAL_P(zv) + 1, deq_len);
  
                zval_dtor(zv);
 -              ZVAL_STRINGL(zv, deq, deq_len, 0);
 +              ZVAL_STR(zv, php_http_cs2zs(deq, deq_len));
        }
  
 -      php_stripcslashes(Z_STRVAL_P(zv), &Z_STRLEN_P(zv));
 +      php_stripcslashes(Z_STR_P(zv));
  }
  
- static inline void prepare_escaped(zval *zv)
 -static inline void quote_string(zval *zv, zend_bool force TSRMLS_DC)
++static inline void quote_string(zend_string **zs, zend_bool force)
  {
-       if (Z_TYPE_P(zv) == IS_STRING) {
 -      int len = Z_STRLEN_P(zv);
++      int len = (*zs)->len;
 -      Z_STRVAL_P(zv) = php_addcslashes(Z_STRVAL_P(zv), Z_STRLEN_P(zv), &Z_STRLEN_P(zv), 1,
 -                      ZEND_STRL("\0..\37\173\\\"") TSRMLS_CC);
++      *zs = php_addcslashes(*zs, 1, ZEND_STRL("\0..\37\173\\\""));
 -      if (force || len != Z_STRLEN_P(zv) || strpbrk(Z_STRVAL_P(zv), "()<>@,;:\"[]?={} ")) {
 -              zval tmp = *zv;
 -              int len = Z_STRLEN_P(zv) + 2;
 -              char *str = emalloc(len + 1);
++      if (force || len != (*zs)->len || strpbrk((*zs)->val, "()<>@,;:\"[]?={} ")) {
++              int len = (*zs)->len + 2;
 -              str[0] = '"';
 -              memcpy(&str[1], Z_STRVAL_P(zv), Z_STRLEN_P(zv));
 -              str[len-1] = '"';
 -              str[len] = '\0';
++              *zs = zend_string_extend(*zs, len, 0);
 -              zval_dtor(&tmp);
 -              ZVAL_STRINGL(zv, str, len, 0);
++              memmove(&(*zs)->val[1], (*zs)->val, (*zs)->len);
++              (*zs)->val[0] = '"';
++              (*zs)->val[len-1] = '"';
++              (*zs)->val[len] = '\0';
++
++              zend_string_forget_hash_val(*zs);
+       }
+ }
 -static inline void prepare_escaped(zval *zv TSRMLS_DC)
++/*    if (Z_TYPE_P(zv) == IS_STRING) {
 +              size_t len = Z_STRLEN_P(zv);
 +              zend_string *stripped = php_addcslashes(Z_STR_P(zv), 0,
 +                              ZEND_STRL("\0..\37\173\\\""));
 +
 +              if (len != stripped->len || strpbrk(stripped->val, "()<>@,;:\"[]?={} ")) {
 +                      size_t len = stripped->len + 2;
 +                      char *str = emalloc(len + 1);
 +
 +                      str[0] = '"';
 +                      memcpy(&str[1], stripped->val, stripped->len);
 +                      str[len-1] = '"';
 +                      str[len] = '\0';
 +
 +                      zval_dtor(zv);
 +                      zend_string_release(stripped);
 +                      ZVAL_STR(zv, php_http_cs2zs(str, len));
 +              } else {
 +                      zval_dtor(zv);
 +                      ZVAL_STR(zv, stripped);
 +              }
++*/
++
++static inline void prepare_escaped(zval *zv)
+ {
+       if (Z_TYPE_P(zv) == IS_STRING) {
 -              quote_string(zv, 0 TSRMLS_CC);
++              quote_string(&Z_STR_P(zv), 0);
        } else {
                zval_dtor(zv);
                ZVAL_EMPTY_STRING(zv);
@@@ -291,6 -296,20 +315,23 @@@ static inline void sanitize_rfc5987(zva
        }
  }
  
 -      php_trim(str, len, " ><", 3, zv, 3 TSRMLS_CC);
+ static inline void sanitize_rfc5988(char *str, size_t len, zval *zv TSRMLS_DC)
+ {
++      zend_string *zs = zend_string_init(str, len, 0);
++
+       zval_dtor(zv);
++      ZVAL_STR(zv, php_trim(zs, " ><", 3, 3));
++      zend_string_release(zs);
+ }
+ static inline void prepare_rfc5988(zval *zv TSRMLS_DC)
+ {
+       if (Z_TYPE_P(zv) != IS_STRING) {
+               zval_dtor(zv);
+               ZVAL_EMPTY_STRING(zv);
+       }
+ }
  static void utf8encode(zval *zv)
  {
        size_t pos, len = 0;
@@@ -363,18 -382,21 +404,22 @@@ static inline void prepare_key(unsigne
        }
  
        if (flags & PHP_HTTP_PARAMS_ESCAPED) {
-               prepare_escaped(&zv);
+               if (flags & PHP_HTTP_PARAMS_RFC5988) {
 -                      prepare_rfc5988(&zv TSRMLS_CC);
++                      prepare_rfc5988(&zv);
+               } else {
 -                      prepare_escaped(&zv TSRMLS_CC);
++                      prepare_escaped(&zv);
+               }
        }
  
 -      *new_key = Z_STRVAL(zv);
 +      *new_key = estrndup(Z_STRVAL(zv), Z_STRLEN(zv));
        *new_len = Z_STRLEN(zv);
 +      zval_ptr_dtor(&zv);
  }
  
 -static inline void prepare_value(unsigned flags, zval *zv TSRMLS_DC)
 +static inline void prepare_value(unsigned flags, zval *zv)
  {
        if (flags & PHP_HTTP_PARAMS_URLENCODED) {
 -              prepare_urlencoded(zv TSRMLS_CC);
 +              prepare_urlencoded(zv);
        }
  
        if (flags & PHP_HTTP_PARAMS_ESCAPED) {
@@@ -540,33 -559,41 +585,37 @@@ static void push_param(HashTable *param
                }
        } else if (state->param.str) {
                if (0 < (state->param.len = state->input.str - state->param.str)) {
 -                      zval *prm, *arg, *val, *key;
 +                      zval prm, arg, val, key;
                        zend_bool rfc5987 = 0;
  
 -                      MAKE_STD_ZVAL(key);
 -                      ZVAL_NULL(key);
 +                      ZVAL_NULL(&key);
-                       sanitize_key(opts->flags, state->param.str, state->param.len, &key, &rfc5987);
-                       state->rfc5987 = rfc5987;
+                       if (opts->flags & PHP_HTTP_PARAMS_RFC5988) {
 -                              sanitize_rfc5988(state->param.str, state->param.len, key TSRMLS_CC);
++                              sanitize_rfc5988(state->param.str, state->param.len, &key);
+                       } else {
 -                              sanitize_key(opts->flags, state->param.str, state->param.len, key, &rfc5987 TSRMLS_CC);
++                              sanitize_key(opts->flags, state->param.str, state->param.len, &key, &rfc5987);
+                               state->rfc5987 = rfc5987;
+                       }
 -                      if (Z_TYPE_P(key) != IS_STRING) {
 -                              merge_param(params, key, &state->current.val, &state->current.args TSRMLS_CC);
 -                      } else if (Z_STRLEN_P(key)) {
 -                              MAKE_STD_ZVAL(prm);
 -                              array_init_size(prm, 2);
 -
 -                              MAKE_STD_ZVAL(val);
 -                              if (opts->defval) {
 -                                      ZVAL_COPY_VALUE(val, opts->defval);
 -                                      zval_copy_ctor(val);
 +                      if (Z_TYPE(key) == IS_ARRAY) {
 +                              merge_param(params, &key, &state->current.val, &state->current.args);
 +                      } else if (Z_TYPE(key) == IS_STRING && Z_STRLEN(key)) {
-                               //array_init_size(&prm, 2);
++                              // FIXME: array_init_size(&prm, 2);
 +                              array_init(&prm);
 +
 +                              if (!Z_ISUNDEF(opts->defval)) {
 +                                      ZVAL_COPY_VALUE(&val, &opts->defval);
 +                                      zval_copy_ctor(&val);
                                } else {
 -                                      ZVAL_TRUE(val);
 +                                      ZVAL_TRUE(&val);
                                }
                                if (rfc5987 && (opts->flags & PHP_HTTP_PARAMS_RFC5987)) {
 -                                      zend_hash_update(Z_ARRVAL_P(prm), "*rfc5987*", sizeof("*rfc5987*"), (void *) &val, sizeof(zval *), (void *) &state->current.val);
 +                                      state->current.val = zend_hash_str_update(Z_ARRVAL(prm), "*rfc5987*", lenof("*rfc5987*"), &val);
                                } else {
 -                                      zend_hash_update(Z_ARRVAL_P(prm), "value", sizeof("value"), (void *) &val, sizeof(zval *), (void *) &state->current.val);
 +                                      state->current.val = zend_hash_str_update(Z_ARRVAL(prm), "value", lenof("value"), &val);
                                }
-                               //array_init_size(&arg, 3);
 -
 -                              MAKE_STD_ZVAL(arg);
 -                              array_init_size(arg, 3);
 -                              zend_hash_update(Z_ARRVAL_P(prm), "arguments", sizeof("arguments"), (void *) &arg, sizeof(zval *), (void *) &state->current.args);
 -
 -                              zend_symtable_update(params, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void *) &prm, sizeof(zval *), (void *) &state->current.param);
++                              // FIXME: array_init_size(&arg, 3);
 +                              array_init(&arg);
 +                              state->current.args = zend_hash_str_update(Z_ARRVAL(prm), "arguments", lenof("arguments"), &arg);
 +                              state->current.param = zend_symtable_str_update(params, Z_STRVAL(key), Z_STRLEN(key), &prm);
                        }
                        zval_ptr_dtor(&key);
                }
@@@ -735,30 -763,46 +790,57 @@@ static inline void shift_rfc5987(php_ht
        }
  }
  
 -static inline void shift_rfc5988(php_http_buffer_t *buf, char *key_str, size_t key_len, const char *ass, size_t asl, unsigned flags TSRMLS_DC)
++static inline void shift_rfc5988(php_http_buffer_t *buf, char *key_str, size_t key_len, const char *ass, size_t asl, unsigned flags)
+ {
+       char *str;
+       size_t len;
+       if (buf->used) {
+               php_http_buffer_append(buf, ass, asl);
+       }
 -      prepare_key(flags, key_str, key_len, &str, &len TSRMLS_CC);
++      prepare_key(flags, key_str, key_len, &str, &len);
+       php_http_buffer_appends(buf, "<");
+       php_http_buffer_append(buf, str, len);
+       php_http_buffer_appends(buf, ">");
+       efree(str);
+ }
 -static inline void shift_rfc5988_val(php_http_buffer_t *buf, zval *zv, const char *vss, size_t vsl, unsigned flags TSRMLS_DC)
++static inline void shift_rfc5988_val(php_http_buffer_t *buf, zval *zv, const char *vss, size_t vsl, unsigned flags)
+ {
 -      zval *tmp = php_http_zsep(1, IS_STRING, zv);
++      zend_string *zs = zval_get_string(zv);
 -      quote_string(tmp, 1 TSRMLS_CC);
++      quote_string(&zs, 1);
+       php_http_buffer_append(buf, vss, vsl);
 -      php_http_buffer_append(buf, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
++      php_http_buffer_append(buf, zs->val, zs->len);
 -      zval_ptr_dtor(&tmp);
++      zend_string_release(zs);
+ }
 -static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags TSRMLS_DC)
 +static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags)
  {
 -      if (Z_TYPE_P(zvalue) != IS_BOOL) {
 -              zval *tmp = php_http_zsep(1, IS_STRING, zvalue);
 +      zval tmp;
 +      zend_string *zs;
  
 -              prepare_value(flags, tmp TSRMLS_CC);
 -              php_http_buffer_append(buf, vss, vsl);
 -              php_http_buffer_append(buf, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
 +      switch (Z_TYPE_P(zvalue)) {
 +      case IS_TRUE:
 +              break;
  
 -              zval_ptr_dtor(&tmp);
 -      } else if (!Z_BVAL_P(zvalue)) {
 +      case IS_FALSE:
                php_http_buffer_append(buf, vss, vsl);
                php_http_buffer_appends(buf, "0");
 +              break;
 +
 +      default:
 +              zs = zval_get_string(zvalue);
 +
 +              ZVAL_STR(&tmp, zs);
 +              prepare_value(flags, &tmp);
 +              php_http_buffer_append(buf, vss, vsl);
 +              php_http_buffer_append(buf, Z_STRVAL(tmp), Z_STRLEN(tmp));
 +
 +              zval_ptr_dtor(&tmp);
 +              break;
        }
  }
  
@@@ -771,24 -815,37 +853,39 @@@ static void shift_arg(php_http_buffer_
                zend_bool rfc5987 = !strcmp(key_str, "*rfc5987*");
  
                if (!rfc5987) {
 -                      shift_key(buf, key_str, key_len, ass, asl, flags TSRMLS_CC);
 +                      shift_key(buf, key_str, key_len, ass, asl, flags);
                }
 -              FOREACH_KEYVAL(pos, zvalue, key, val) {
 +              ZEND_HASH_FOREACH_KEY_VAL_IND(ht, key.h, key.key, val)
 +              {
                        /* did you mean recursion? */
 -                      php_http_array_hashkey_stringify(&key);
 -                      if (rfc5987 && (Z_TYPE_PP(val) == IS_ARRAY || Z_TYPE_PP(val) == IS_OBJECT)) {
 -                              shift_key(buf, key.str, key.len-1, ass, asl, flags TSRMLS_CC);
 -                              shift_rfc5987(buf, *val, vss, vsl, flags TSRMLS_CC);
 +                      php_http_arrkey_stringify(&key, NULL);
 +                      if (rfc5987 && (Z_TYPE_P(val) == IS_ARRAY || Z_TYPE_P(val) == IS_OBJECT)) {
 +                              shift_key(buf, key.key->val, key.key->len, ass, asl, flags);
 +                              shift_rfc5987(buf, val, vss, vsl, flags);
                        } else {
 -                              shift_arg(buf, key.str, key.len-1, *val, ass, asl, vss, vsl, flags TSRMLS_CC);
 +                              shift_arg(buf, key.key->val, key.key->len, val, ass, asl, vss, vsl, flags);
                        }
 -                      php_http_array_hashkey_stringfree(&key);
 +                      php_http_arrkey_dtor(&key);
                }
 +              ZEND_HASH_FOREACH_END();
        } else {
 -              shift_key(buf, key_str, key_len, ass, asl, flags TSRMLS_CC);
 +              shift_key(buf, key_str, key_len, ass, asl, flags);
+               if (flags & PHP_HTTP_PARAMS_RFC5988) {
+                       switch (key_len) {
+                       case lenof("rel"):
+                       case lenof("title"):
+                       case lenof("anchor"):
+                               /* some args must be quoted */
+                               if (0 <= php_http_select_str(key_str, 3, "rel", "title", "anchor")) {
 -                                      shift_rfc5988_val(buf, zvalue, vss, vsl, flags TSRMLS_CC);
++                                      shift_rfc5988_val(buf, zvalue, vss, vsl, flags);
+                                       return;
+                               }
+                               break;
+                       }
+               }
 -              shift_val(buf, zvalue, vss, vsl, flags TSRMLS_CC);
 +              shift_val(buf, zvalue, vss, vsl, flags);
        }
  }
  
@@@ -798,17 -855,21 +895,22 @@@ static void shift_param(php_http_buffer
                /* treat as arguments, unless we care for dimensions or rfc5987 */
                if (flags & PHP_HTTP_PARAMS_DIMENSION) {
                        php_http_buffer_t *keybuf = php_http_buffer_from_string(key_str, key_len);
 -                      prepare_dimension(buf, keybuf, zvalue, pss, psl, vss, vsl, flags TSRMLS_CC);
 +                      prepare_dimension(buf, keybuf, zvalue, pss, psl, vss, vsl, flags);
                        php_http_buffer_free(&keybuf);
                } else if (rfc5987) {
 -                      shift_key(buf, key_str, key_len, pss, psl, flags TSRMLS_CC);
 -                      shift_rfc5987(buf, zvalue, vss, vsl, flags TSRMLS_CC);
 +                      shift_key(buf, key_str, key_len, pss, psl, flags);
 +                      shift_rfc5987(buf, zvalue, vss, vsl, flags);
                } else {
 -                      shift_arg(buf, key_str, key_len, zvalue, ass, asl, vss, vsl, flags TSRMLS_CC);
 +                      shift_arg(buf, key_str, key_len, zvalue, ass, asl, vss, vsl, flags);
                }
        } else {
 -                      shift_rfc5988(buf, key_str, key_len, pss, psl, flags TSRMLS_CC);
 +              shift_key(buf, key_str, key_len, pss, psl, flags);
+               if (flags & PHP_HTTP_PARAMS_RFC5988) {
 -                      shift_key(buf, key_str, key_len, pss, psl, flags TSRMLS_CC);
++                      shift_rfc5988(buf, key_str, key_len, pss, psl, flags);
+               } else {
 -              shift_val(buf, zvalue, vss, vsl, flags TSRMLS_CC);
++                      shift_key(buf, key_str, key_len, pss, psl, flags);
+               }
 +              shift_val(buf, zvalue, vss, vsl, flags);
        }
  }
  
@@@ -1187,28 -1245,29 +1289,29 @@@ PHP_MINIT_FUNCTION(http_params
        zend_class_entry ce = {0};
  
        INIT_NS_CLASS_ENTRY(ce, "http", "Params", php_http_params_methods);
 -      php_http_params_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
 +      php_http_params_class_entry = zend_register_internal_class(&ce);
        php_http_params_class_entry->create_object = php_http_params_object_new;
 -      zend_class_implements(php_http_params_class_entry TSRMLS_CC, 1, zend_ce_arrayaccess);
 -
 -      zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_PARAM_SEP"), ZEND_STRL(",") TSRMLS_CC);
 -      zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_ARG_SEP"), ZEND_STRL(";") TSRMLS_CC);
 -      zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_VAL_SEP"), ZEND_STRL("=") TSRMLS_CC);
 -      zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("COOKIE_PARAM_SEP"), ZEND_STRL("") TSRMLS_CC);
 -
 -      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RAW"), PHP_HTTP_PARAMS_RAW TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_ESCAPED"), PHP_HTTP_PARAMS_ESCAPED TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_URLENCODED"), PHP_HTTP_PARAMS_URLENCODED TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DIMENSION"), PHP_HTTP_PARAMS_DIMENSION TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RFC5987"), PHP_HTTP_PARAMS_RFC5987 TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RFC5988"), PHP_HTTP_PARAMS_RFC5988 TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DEFAULT"), PHP_HTTP_PARAMS_DEFAULT TSRMLS_CC);
 -      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_QUERY"), PHP_HTTP_PARAMS_QUERY TSRMLS_CC);
 -
 -      zend_declare_property_null(php_http_params_class_entry, ZEND_STRL("params"), ZEND_ACC_PUBLIC TSRMLS_CC);
 -      zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("param_sep"), ZEND_STRL(","), ZEND_ACC_PUBLIC TSRMLS_CC);
 -      zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("arg_sep"), ZEND_STRL(";"), ZEND_ACC_PUBLIC TSRMLS_CC);
 -      zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("val_sep"), ZEND_STRL("="), ZEND_ACC_PUBLIC TSRMLS_CC);
 -      zend_declare_property_long(php_http_params_class_entry, ZEND_STRL("flags"), PHP_HTTP_PARAMS_DEFAULT, ZEND_ACC_PUBLIC TSRMLS_CC);
 +      zend_class_implements(php_http_params_class_entry, 1, zend_ce_arrayaccess);
 +
 +      zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_PARAM_SEP"), ZEND_STRL(","));
 +      zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_ARG_SEP"), ZEND_STRL(";"));
 +      zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_VAL_SEP"), ZEND_STRL("="));
 +      zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("COOKIE_PARAM_SEP"), ZEND_STRL(""));
 +
 +      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RAW"), PHP_HTTP_PARAMS_RAW);
 +      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_ESCAPED"), PHP_HTTP_PARAMS_ESCAPED);
 +      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_URLENCODED"), PHP_HTTP_PARAMS_URLENCODED);
 +      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DIMENSION"), PHP_HTTP_PARAMS_DIMENSION);
 +      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RFC5987"), PHP_HTTP_PARAMS_RFC5987);
++      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RFC5988"), PHP_HTTP_PARAMS_RFC5988);
 +      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DEFAULT"), PHP_HTTP_PARAMS_DEFAULT);
 +      zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_QUERY"), PHP_HTTP_PARAMS_QUERY);
 +
 +      zend_declare_property_null(php_http_params_class_entry, ZEND_STRL("params"), ZEND_ACC_PUBLIC);
 +      zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("param_sep"), ZEND_STRL(","), ZEND_ACC_PUBLIC);
 +      zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("arg_sep"), ZEND_STRL(";"), ZEND_ACC_PUBLIC);
 +      zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("val_sep"), ZEND_STRL("="), ZEND_ACC_PUBLIC);
 +      zend_declare_property_long(php_http_params_class_entry, ZEND_STRL("flags"), PHP_HTTP_PARAMS_DEFAULT, ZEND_ACC_PUBLIC);
  
        return SUCCESS;
  }
Simple merge
diff --cc php_http_url.c
@@@ -562,18 -549,18 +564,18 @@@ HashTable *php_http_url_to_struct(cons
                }
        }
  
 -      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;
+       const char *arg_sep_str = "&";
+       size_t arg_sep_len = 1;
        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;
        }
@@@ -1541,12 -1571,12 +1573,12 @@@ ZEND_END_ARG_INFO()
  PHP_METHOD(HttpUrl, mod)
  {
        zval *new_url = NULL;
-       zend_long flags = PHP_HTTP_URL_JOIN_PATH | PHP_HTTP_URL_JOIN_QUERY;
 -      long flags = PHP_HTTP_URL_JOIN_PATH | PHP_HTTP_URL_JOIN_QUERY | PHP_HTTP_URL_SANITIZE_PATH;
++      zend_long flags = PHP_HTTP_URL_JOIN_PATH | PHP_HTTP_URL_JOIN_QUERY | PHP_HTTP_URL_SANITIZE_PATH;
        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;
  
@@@ -1627,39 -1657,39 +1659,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);
- #if defined(PHP_HTTP_HAVE_IDN) || defined(HAVE_UIDNA_IDNTOASCII)
+ #if defined(PHP_HTTP_HAVE_IDN2) || 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;
  }