fix warning
[m6w6/ext-http] / php_http_params.c
index faa3cbb735a4a4f76307e0905153d96177b30d4a..5adeb91c761f390bd3e6705ea71eb6eaf5225422 100644 (file)
@@ -60,29 +60,35 @@ static inline void sanitize_escaped(zval *zv TSRMLS_DC)
                ZVAL_STRINGL(zv, deq, deq_len, 0);
        }
 
-       php_stripslashes(Z_STRVAL_P(zv), &Z_STRLEN_P(zv) TSRMLS_CC);
+       php_stripcslashes(Z_STRVAL_P(zv), &Z_STRLEN_P(zv));
 }
 
-static inline void prepare_escaped(zval *zv TSRMLS_DC)
+static inline void quote_string(zval *zv, zend_bool force TSRMLS_DC)
 {
-       if (Z_TYPE_P(zv) == IS_STRING) {
-               int len = Z_STRLEN_P(zv);
+       int len = Z_STRLEN_P(zv);
 
-               Z_STRVAL_P(zv) = php_addslashes(Z_STRVAL_P(zv), Z_STRLEN_P(zv), &Z_STRLEN_P(zv), 1 TSRMLS_CC);
+       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);
 
-               if (len != Z_STRLEN_P(zv)) {
-                       zval tmp = *zv;
-                       int len = Z_STRLEN_P(zv) + 2;
-                       char *str = emalloc(len + 1);
+       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);
 
-                       str[0] = '"';
-                       memcpy(&str[1], Z_STRVAL_P(zv), Z_STRLEN_P(zv));
-                       str[len-1] = '"';
-                       str[len] = '\0';
+               str[0] = '"';
+               memcpy(&str[1], Z_STRVAL_P(zv), Z_STRLEN_P(zv));
+               str[len-1] = '"';
+               str[len] = '\0';
 
-                       zval_dtor(&tmp);
-                       ZVAL_STRINGL(zv, str, len, 0);
-               }
+               zval_dtor(&tmp);
+               ZVAL_STRINGL(zv, str, len, 0);
+       }
+}
+
+static inline void prepare_escaped(zval *zv TSRMLS_DC)
+{
+       if (Z_TYPE_P(zv) == IS_STRING) {
+               quote_string(zv, 0 TSRMLS_CC);
        } else {
                zval_dtor(zv);
                ZVAL_EMPTY_STRING(zv);
@@ -223,6 +229,10 @@ static inline void sanitize_key(unsigned flags, char *str, size_t len, zval *zv,
        if (flags & PHP_HTTP_PARAMS_ESCAPED) {
                sanitize_escaped(zv TSRMLS_CC);
        }
+       
+       if (!Z_STRLEN_P(zv)) {
+               return;
+       }
 
        eos = &Z_STRVAL_P(zv)[Z_STRLEN_P(zv)-1];
        if (*eos == '*') {
@@ -252,7 +262,7 @@ static inline void sanitize_rfc5987(zval *zv, char **language, zend_bool *latin1
        switch (Z_STRVAL_P(zv)[0]) {
        case 'I':
        case 'i':
-               if (!strncasecmp(Z_STRVAL_P(zv), ZEND_STRL("iso-8859-1"))) {
+               if (!strncasecmp(Z_STRVAL_P(zv), "iso-8859-1", lenof("iso-8859-1"))) {
                        *latin1 = 1;
                        ptr = Z_STRVAL_P(zv) + lenof("iso-8859-1");
                        break;
@@ -260,7 +270,7 @@ static inline void sanitize_rfc5987(zval *zv, char **language, zend_bool *latin1
                /* no break */
        case 'U':
        case 'u':
-               if (!strncasecmp(Z_STRVAL_P(zv), ZEND_STRL("utf-8"))) {
+               if (!strncasecmp(Z_STRVAL_P(zv), "utf-8", lenof("utf-8"))) {
                        *latin1 = 0;
                        ptr = Z_STRVAL_P(zv) + lenof("utf-8");
                        break;
@@ -286,6 +296,20 @@ static inline void sanitize_rfc5987(zval *zv, char **language, zend_bool *latin1
        }
 }
 
+static inline void sanitize_rfc5988(char *str, size_t len, zval *zv TSRMLS_DC)
+{
+       zval_dtor(zv);
+       php_trim(str, len, " ><", 3, zv, 3 TSRMLS_CC);
+}
+
+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;
@@ -342,7 +366,7 @@ static inline void sanitize_value(unsigned flags, char *str, size_t len, zval *z
                ZVAL_COPY_VALUE(tmp, zv);
                array_init(zv);
                add_assoc_zval(zv, language, tmp);
-               STR_FREE(language);
+               PTR_FREE(language);
        }
 }
 
@@ -358,7 +382,11 @@ static inline void prepare_key(unsigned flags, char *old_key, size_t old_len, ch
        }
 
        if (flags & PHP_HTTP_PARAMS_ESCAPED) {
-               prepare_escaped(&zv TSRMLS_CC);
+               if (flags & PHP_HTTP_PARAMS_RFC5988) {
+                       prepare_rfc5988(&zv TSRMLS_CC);
+               } else {
+                       prepare_escaped(&zv TSRMLS_CC);
+               }
        }
 
        *new_key = Z_STRVAL(zv);
@@ -536,8 +564,12 @@ static void push_param(HashTable *params, php_http_params_state_t *state, const
 
                        MAKE_STD_ZVAL(key);
                        ZVAL_NULL(key);
-                       sanitize_key(opts->flags, state->param.str, state->param.len, key, &rfc5987 TSRMLS_CC);
-                       state->rfc5987 = rfc5987;
+                       if (opts->flags & PHP_HTTP_PARAMS_RFC5988) {
+                               sanitize_rfc5988(state->param.str, state->param.len, key TSRMLS_CC);
+                       } else {
+                               sanitize_key(opts->flags, state->param.str, state->param.len, key, &rfc5987 TSRMLS_CC);
+                               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)) {
@@ -569,7 +601,7 @@ static void push_param(HashTable *params, php_http_params_state_t *state, const
 }
 
 static inline zend_bool check_str(const char *chk_str, size_t chk_len, const char *sep_str, size_t sep_len) {
-       return 0 < sep_len && chk_len >= sep_len && !memcmp(chk_str, sep_str, sep_len);
+       return 0 < sep_len && chk_len >= sep_len && *chk_str == *sep_str && !memcmp(chk_str + 1, sep_str + 1, sep_len - 1);
 }
 
 static size_t check_sep(php_http_params_state_t *state, php_http_params_token_t **separators)
@@ -618,7 +650,13 @@ HashTable *php_http_params_parse(HashTable *params, const php_http_params_opts_t
        }
 
        while (state.input.len) {
-               if (*state.input.str == '"' && !state.escape) {
+               if ((opts->flags & PHP_HTTP_PARAMS_RFC5988) && !state.arg.str) {
+                       if (*state.input.str == '<') {
+                               state.quotes = 1;
+                       } else if (*state.input.str == '>') {
+                               state.quotes = 0;
+                       }
+               } else if (*state.input.str == '"' && !state.escape) {
                        state.quotes = !state.quotes;
                } else {
                        state.escape = (*state.input.str == '\\');
@@ -725,6 +763,33 @@ static inline void shift_rfc5987(php_http_buffer_t *buf, zval *zvalue, const cha
        }
 }
 
+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)
+{
+       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);
+       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)
+{
+       zval *tmp = php_http_zsep(1, IS_STRING, zv);
+
+       quote_string(tmp, 1 TSRMLS_CC);
+       php_http_buffer_append(buf, vss, vsl);
+       php_http_buffer_append(buf, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
+
+       zval_ptr_dtor(&tmp);
+}
+
 static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags TSRMLS_DC)
 {
        if (Z_TYPE_P(zvalue) != IS_BOOL) {
@@ -741,12 +806,13 @@ static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *v
        }
 }
 
-static void shift_arg(php_http_buffer_t *buf, char *key_str, size_t key_len, zval *zvalue, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags, zend_bool rfc5987 TSRMLS_DC)
+static void shift_arg(php_http_buffer_t *buf, char *key_str, size_t key_len, zval *zvalue, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags TSRMLS_DC)
 {
        if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) {
                HashPosition pos;
                php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
                zval **val;
+               zend_bool rfc5987 = !strcmp(key_str, "*rfc5987*");
 
                if (!rfc5987) {
                        shift_key(buf, key_str, key_len, ass, asl, flags TSRMLS_CC);
@@ -758,17 +824,32 @@ static void shift_arg(php_http_buffer_t *buf, char *key_str, size_t key_len, zva
                                shift_key(buf, key.str, key.len-1, ass, asl, flags TSRMLS_CC);
                                shift_rfc5987(buf, *val, vss, vsl, flags TSRMLS_CC);
                        } else {
-                               shift_arg(buf, key.str, key.len-1, *val, ass, asl, vss, vsl, flags, 0 TSRMLS_CC);
+                               shift_arg(buf, key.str, key.len-1, *val, ass, asl, vss, vsl, flags TSRMLS_CC);
                        }
                        php_http_array_hashkey_stringfree(&key);
                }
        } else {
                shift_key(buf, key_str, key_len, ass, asl, flags TSRMLS_CC);
+
+               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);
+                                       return;
+                               }
+                               break;
+                       }
+               }
+
                shift_val(buf, zvalue, vss, vsl, flags TSRMLS_CC);
        }
 }
 
-static void shift_param(php_http_buffer_t *buf, char *key_str, size_t key_len, zval *zvalue, const char *pss, size_t psl, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags TSRMLS_DC)
+static void shift_param(php_http_buffer_t *buf, char *key_str, size_t key_len, zval *zvalue, const char *pss, size_t psl, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags, zend_bool rfc5987 TSRMLS_DC)
 {
        if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) {
                /* treat as arguments, unless we care for dimensions or rfc5987 */
@@ -776,14 +857,18 @@ static void shift_param(php_http_buffer_t *buf, char *key_str, size_t key_len, z
                        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);
                        php_http_buffer_free(&keybuf);
-               } else if (flags & PHP_HTTP_PARAMS_RFC5987) {
+               } else if (rfc5987) {
                        shift_key(buf, key_str, key_len, pss, psl, flags TSRMLS_CC);
                        shift_rfc5987(buf, zvalue, vss, vsl, flags TSRMLS_CC);
                } else {
-                       shift_arg(buf, key_str, key_len, zvalue, ass, asl, vss, vsl, flags, 0 TSRMLS_CC);
+                       shift_arg(buf, key_str, key_len, zvalue, ass, asl, vss, vsl, flags TSRMLS_CC);
                }
        } else {
-               shift_key(buf, key_str, key_len, pss, psl, flags TSRMLS_CC);
+               if (flags & PHP_HTTP_PARAMS_RFC5988) {
+                       shift_rfc5988(buf, key_str, key_len, pss, psl, flags TSRMLS_CC);
+               } else {
+                       shift_key(buf, key_str, key_len, pss, psl, flags TSRMLS_CC);
+               }
                shift_val(buf, zvalue, vss, vsl, flags TSRMLS_CC);
        }
 }
@@ -793,6 +878,7 @@ php_http_buffer_t *php_http_params_to_string(php_http_buffer_t *buf, HashTable *
        zval **zparam;
        HashPosition pos, pos1;
        php_http_array_hashkey_t key = php_http_array_hashkey_init(0), key1 = php_http_array_hashkey_init(0);
+       zend_bool rfc5987 = 0;
 
        if (!buf) {
                buf = php_http_buffer_init(NULL);
@@ -807,12 +893,14 @@ php_http_buffer_t *php_http_params_to_string(php_http_buffer_t *buf, HashTable *
                        if (SUCCESS != zend_hash_find(Z_ARRVAL_PP(zparam), ZEND_STRS("value"), (void *) &zvalue)) {
                                if (SUCCESS != zend_hash_find(Z_ARRVAL_PP(zparam), ZEND_STRS("*rfc5987*"), (void *) &zvalue)) {
                                        zvalue = zparam;
+                               } else {
+                                       rfc5987 = 1;
                                }
                        }
                }
 
                php_http_array_hashkey_stringify(&key);
-               shift_param(buf, key.str, key.len - 1, *zvalue, pss, psl, ass, asl, vss, vsl, flags TSRMLS_CC);
+               shift_param(buf, key.str, key.len - 1, *zvalue, pss, psl, ass, asl, vss, vsl, flags, rfc5987 TSRMLS_CC);
                php_http_array_hashkey_stringfree(&key);
 
                if (Z_TYPE_PP(zparam) == IS_ARRAY && SUCCESS != zend_hash_find(Z_ARRVAL_PP(zparam), ZEND_STRS("arguments"), (void *) &zvalue)) {
@@ -829,8 +917,7 @@ php_http_buffer_t *php_http_params_to_string(php_http_buffer_t *buf, HashTable *
                                }
 
                                php_http_array_hashkey_stringify(&key1);
-                               shift_arg(buf, key1.str, key1.len - 1, *zargs, ass, asl, vss, vsl, flags,
-                                               HASH_KEY_IS_STRING == key1.type && !strcmp(key1.str, "*rfc5987*") TSRMLS_CC);
+                               shift_arg(buf, key1.str, key1.len - 1, *zargs, ass, asl, vss, vsl, flags TSRMLS_CC);
                                php_http_array_hashkey_stringfree(&key1);
                        }
                }
@@ -877,7 +964,7 @@ void php_http_params_separator_free(php_http_params_token_t **separator)
        php_http_params_token_t **sep = separator;
        if (sep) {
                while (*sep) {
-                       STR_FREE((*sep)->str);
+                       PTR_FREE((*sep)->str);
                        efree(*sep);
                        ++sep;
                }
@@ -1172,6 +1259,7 @@ PHP_MINIT_FUNCTION(http_params)
        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);