From: Michael Wallner Date: Wed, 27 Jul 2016 13:24:35 +0000 (+0200) Subject: Merge branch 'v2.6.x' X-Git-Tag: RELEASE_3_1_0_BETA1~4 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=commitdiff_plain;h=e1d5ca36e13696a2e87b618165669fc7c53709c1 Merge branch 'v2.6.x' --- e1d5ca36e13696a2e87b618165669fc7c53709c1 diff --cc src/php_http_info.c index 6eef822,8008215..9045cd4 --- a/src/php_http_info.c +++ b/src/php_http_info.c @@@ -30,11 -30,11 +30,11 @@@ void php_http_info_dtor(php_http_info_ PTR_SET(PHP_HTTP_INFO(i).request.method, NULL); PTR_SET(PHP_HTTP_INFO(i).request.url, NULL); break; -- ++ case PHP_HTTP_RESPONSE: PTR_SET(PHP_HTTP_INFO(i).response.status, NULL); break; -- ++ default: break; } @@@ -49,31 -49,43 +49,43 @@@ void php_http_info_free(php_http_info_ } } -php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_header TSRMLS_DC) +php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_header) { - const char *end, *http; + const char *end, *http, *off; zend_bool free_info = !info; -- ++ /* sane parameter */ if ((!pre_header) || (!*pre_header)) { return NULL; } -- ++ /* where's the end of the line */ if (!(end = php_http_locate_eol(pre_header, NULL))) { end = pre_header + strlen(pre_header); } -- ++ /* there must be HTTP/1.x in the line */ if (!(http = php_http_locate_str(pre_header, end - pre_header, "HTTP/", lenof("HTTP/")))) { return NULL; } -- - info = php_http_info_init(info TSRMLS_CC); + - if (!php_http_version_parse(&info->http.version, http TSRMLS_CC)) { + info = php_http_info_init(info); + - /* and nothing than SPACE or NUL after HTTP/X.x */ - if (!php_http_version_parse(&info->http.version, http) - || (http[lenof("HTTP/X.x")] && (!PHP_HTTP_IS_CTYPE(space, http[lenof("HTTP/X.x")])))) { ++ if (!php_http_version_parse(&info->http.version, http)) { + if (free_info) { + php_http_info_free(&info); + } + return NULL; + } + + /* clumsy fix for changed libcurl behaviour in 7.49.1, see https://github.com/curl/curl/issues/888 */ + off = &http[lenof("HTTP/X")]; + if (info->http.version.major < 2) { + off += 2; + } + + /* and nothing than SPACE or NUL after HTTP/X(.x) */ + if (*off && (!PHP_HTTP_IS_CTYPE(space, *off))) { if (free_info) { php_http_info_free(&info); } @@@ -90,11 -102,11 +102,11 @@@ /* is response */ if (pre_header == http) { - const char *status = NULL, *code = http + sizeof("HTTP/X.x"); - + const char *status = NULL, *code = off; - ++ info->type = PHP_HTTP_RESPONSE; - while (' ' == *code) ++code; + while (code < end && ' ' == *code) ++code; - if (code && end > code) { + if (end > code) { /* rfc7230#3.1.2 The status-code element is a 3-digit integer code */ PHP_HTTP_INFO(info).response.code = 100*(*code++ - '0'); PHP_HTTP_INFO(info).response.code += 10*(*code++ - '0'); @@@ -115,14 -127,14 +127,14 @@@ } else { PHP_HTTP_INFO(info).response.status = NULL; } -- ++ return info; } -- ++ /* is request */ - else if (*(http - 1) == ' ' && (!http[lenof("HTTP/X.x")] || http[lenof("HTTP/X.x")] == '\r' || http[lenof("HTTP/X.x")] == '\n')) { + else if (*(http - 1) == ' ' && (!*off || *off == '\r' || *off == '\n')) { const char *url = strchr(pre_header, ' '); -- ++ info->type = PHP_HTTP_REQUEST; if (url && http > url) { size_t url_len = url - pre_header; @@@ -151,7 -163,7 +163,7 @@@ PHP_HTTP_INFO(info).request.method = NULL; PHP_HTTP_INFO(info).request.url = NULL; } -- ++ return info; } diff --cc src/php_http_params.c index c9feccb,fc75f0e..8988f43 --- a/src/php_http_params.c +++ b/src/php_http_params.c @@@ -229,26 -214,22 +229,26 @@@ static void prepare_dimension(php_http_ php_http_buffer_cut(&prefix, keybuf->used, prefix.used - keybuf->used); } + ZEND_HASH_FOREACH_END(); + ZEND_HASH_DEC_APPLY_COUNT(ht); + php_http_buffer_dtor(&prefix); } - --ht->nApplyCount; } -static inline void sanitize_key(unsigned flags, char *str, size_t len, zval *zv, zend_bool *rfc5987 TSRMLS_DC) +static inline void sanitize_key(unsigned flags, const char *str, size_t len, zval *zv, zend_bool *rfc5987) { char *eos; + zend_string *zs = zend_string_init(str, len, 0); zval_dtor(zv); - php_trim(str, len, NULL, 0, zv, 3 TSRMLS_CC); + ZVAL_STR(zv, php_trim(zs, NULL, 0, 3)); + zend_string_release(zs); if (flags & PHP_HTTP_PARAMS_ESCAPED) { - sanitize_escaped(zv TSRMLS_CC); + sanitize_escaped(zv); } -- ++ if (!Z_STRLEN_P(zv)) { return; } @@@ -551,13 -520,15 +551,15 @@@ static void merge_param(HashTable *para *current_param = ptr; } -static void push_param(HashTable *params, php_http_params_state_t *state, const php_http_params_opts_t *opts TSRMLS_DC) +static void push_param(HashTable *params, php_http_params_state_t *state, const php_http_params_opts_t *opts) { if (state->val.str) { - if (0 < (state->val.len = state->input.str - state->val.str)) { + if (!state->current.val) { + return; + } else if (0 < (state->val.len = state->input.str - state->val.str)) { - sanitize_value(opts->flags, state->val.str, state->val.len, *(state->current.val), state->rfc5987 TSRMLS_CC); + sanitize_value(opts->flags, state->val.str, state->val.len, state->current.val, state->rfc5987); } else { - ZVAL_EMPTY_STRING(*(state->current.val)); + ZVAL_EMPTY_STRING(state->current.val); } state->rfc5987 = 0; } else if (state->arg.str) { @@@ -639,7 -617,7 +641,7 @@@ static size_t check_sep(php_http_params if (state->quotes || state->escape) { return 0; } -- ++ if (sep) while (*sep) { if (check_str(state->input.str, state->input.len, (*sep)->str, (*sep)->len)) { return (*sep)->len; @@@ -689,10 -667,10 +691,10 @@@ HashTable *php_http_params_parse(HashTa } else { state.escape = (*state.input.str == '\\'); } -- ++ if (!state.param.str) { /* initialize */ - skip_sep(0, &state, opts->param, opts->arg, opts->val TSRMLS_CC); + skip_sep(0, &state, opts->param, opts->arg, opts->val); state.param.str = state.input.str; } else { size_t sep_len; @@@ -743,7 -721,7 +745,7 @@@ } } } -- ++ if (state.input.len) { ++state.input.str; --state.input.len; diff --cc src/php_http_version.c index e763a85,c861a64..7f7d342 --- a/src/php_http_version.c +++ b/src/php_http_version.c @@@ -44,19 -44,30 +44,30 @@@ php_http_version_t *php_http_version_pa major = *ptr++ - '0'; if (major >= 0 && major <= 9) { separator = *ptr++; - if (separator) { - if (separator != '.' && separator != ',') { - php_error_docref(NULL, E_NOTICE, "Non-standard version separator '%c' in HTTP protocol version '%s'", separator, ptr - 2); - } + switch (separator) { + default: - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Non-standard version separator '%c' in HTTP protocol version '%s'", separator, ptr - 2); ++ php_error_docref(NULL, E_NOTICE, "Non-standard version separator '%c' in HTTP protocol version '%s'", separator, ptr - 2); + /* no break */ + case '.': + case ',': minor = *ptr - '0'; - if (minor >= 0 && minor <= 9) { - return php_http_version_init(v, major, minor); + break; + + case ' ': + if (major > 1) { + minor = 0; + } else { + goto error; } } + if (minor >= 0 && minor <= 9) { - return php_http_version_init(v, major, minor TSRMLS_CC); ++ return php_http_version_init(v, major, minor); + } } } + error: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse HTTP protocol version '%s'", str); + php_error_docref(NULL, E_WARNING, "Could not parse HTTP protocol version '%s'", str); return NULL; } diff --cc tests/gh-issue47.phpt index 0000000,6956588..1a09b8d mode 000000,100644..100644 --- a/tests/gh-issue47.phpt +++ b/tests/gh-issue47.phpt @@@ -1,0 -1,27 +1,27 @@@ + --TEST-- + Null pointer deref in sanitize_value + --SKIPIF-- + + --FILE-- + mod($urls[1]); + + echo $url1; + + ?> + + ===DONE=== + --EXPECTF-- + Test + http://%s/ + ===DONE===