From: Michael Wallner Date: Mon, 22 Aug 2016 11:38:39 +0000 (+0200) Subject: Merge branch 'v2.6.x' X-Git-Tag: RELEASE_3_1_0_BETA1~1 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=commitdiff_plain;h=c55db20a130d729ca8747346c5e5ab9fb52fd89d Merge branch 'v2.6.x' --- c55db20a130d729ca8747346c5e5ab9fb52fd89d diff --cc package.xml index 238e23a,d22b029..60a8e35 --- a/package.xml +++ b/package.xml @@@ -35,21 -31,40 +31,40 @@@ https://mdref.m6w6.name/htt mike@php.net yes - 2016-03-09 + 2016-08-22 - 3.0.1 - 3.0.0 - 2.6.0beta1 - 2.6.0 ++ 3.1.0beta1 ++ 3.1.0 - stable + beta stable BSD-2-Clause = 7.23.0) options to http\Client::configure() + + http\Client uses curl_share handles to properly share cookies and SSL/TLS sessions between requests + + Improved configure checks for default CA bundles + + Improved negotiation precision + * Fixed regression introduced by http\Params::PARSE_RFC5987: negotiation using the params parser would receive param keys without the trailing asterisk, stripped by http\Params::PARSE_RFC5987. + * Fix gh-issue #50: http\Client::dequeue() within http\Client::setDebug() causes segfault (Mike, Maik Wagner) + * Fix gh-issue #47: http\Url: Null pointer deref in sanitize_value() (Mike, @rc0r) + * Fix gh-issue #45: HTTP/2 response message parsing broken with libcurl >= 7.49.1 (Mike) + * Fix gh-issue #43: Joining query with empty original variable in query (Mike, Sander Backus) + * Fix gh-issue #42: fatal error when using punycode in URLs (Mike, Sebastian Thielen) + * Fix gh-issue #41: Use curl_version_info_data.features when initializing options (Mike) + * Fix gh-issue #40: determinde the SSL backend used by curl at runtime (Mike, @rcanavan) + * Fix gh-issue #39: Notice: http\Client::enqueue(): Could not set option proxy_service_name (Mike, @rcanavan) + * Fix gh-issue #38: Persistent curl handles: error code not properly reset (Mike, @afflerbach) + * Fix gh-issue #36: Unexpected cookies sent if persistent_handle_id is used (Mike, @rcanavan, @afflerbach) + * Fix gh-issue #34: allow setting multiple headers with the same name (Mike, @rcanavan) + * Fix gh-issue #33: allow setting prodyhost request option to NULL (Mike, @rcanavan) -* Fix gh-issue #31: add/improve configure checks for default CA bundle/path (Mike, @rcanavan) ++* Fix gh-issue #31: add/improve configure checks for default CA bundle/path (Mike, @rcanavan) ]]> @@@ -251,8 -273,12 +273,11 @@@ -- + + + + diff --cc src/php_http_client_request.c index f64c357,01e02b9..de7c0ff --- a/src/php_http_client_request.c +++ b/src/php_http_client_request.c @@@ -59,7 -53,7 +59,7 @@@ static PHP_METHOD(HttpClientRequest, __ PHP_HTTP_INFO(obj->message).request.method = estrndup(meth_str, meth_len); } if (zurl) { - PHP_HTTP_INFO(obj->message).request.url = php_http_url_from_zval(zurl, ~0); - PHP_HTTP_INFO(obj->message).request.url = php_http_url_from_zval(zurl, PHP_HTTP_URL_STDFLAGS TSRMLS_CC); ++ PHP_HTTP_INFO(obj->message).request.url = php_http_url_from_zval(zurl, PHP_HTTP_URL_STDFLAGS); } if (zheaders) { array_copy(Z_ARRVAL_P(zheaders), &obj->message->hdrs); diff --cc src/php_http_info.c index 9045cd4,13bf124..4e43fda --- a/src/php_http_info.c +++ b/src/php_http_info.c @@@ -147,9 -147,9 +147,9 @@@ php_http_info_t *php_http_info_parse(ph if (http > url) { /* CONNECT presents an authority only */ if (strcasecmp(PHP_HTTP_INFO(info).request.method, "CONNECT")) { - PHP_HTTP_INFO(info).request.url = php_http_url_parse(url, http - url, ~0); - PHP_HTTP_INFO(info).request.url = php_http_url_parse(url, http - url, PHP_HTTP_URL_STDFLAGS TSRMLS_CC); ++ PHP_HTTP_INFO(info).request.url = php_http_url_parse(url, http - url, PHP_HTTP_URL_STDFLAGS); } else { - PHP_HTTP_INFO(info).request.url = php_http_url_parse_authority(url, http - url, ~0); - PHP_HTTP_INFO(info).request.url = php_http_url_parse_authority(url, http - url, PHP_HTTP_URL_STDFLAGS TSRMLS_CC); ++ PHP_HTTP_INFO(info).request.url = php_http_url_parse_authority(url, http - url, PHP_HTTP_URL_STDFLAGS); } if (!PHP_HTTP_INFO(info).request.url) { PTR_SET(PHP_HTTP_INFO(info).request.method, NULL); diff --cc src/php_http_message.c index 591022d,0701af0..078ae4c --- a/src/php_http_message.c +++ b/src/php_http_message.c @@@ -58,20 -59,20 +58,20 @@@ php_http_message_t *php_http_message_in switch (type) { case PHP_HTTP_REQUEST: - mbody = php_http_env_get_request_body(TSRMLS_C); + mbody = php_http_env_get_request_body(); php_http_message_body_addref(mbody); - message = php_http_message_init(message, type, mbody TSRMLS_CC); - if ((sval = php_http_env_get_server_var(ZEND_STRL("SERVER_PROTOCOL"), 1 TSRMLS_CC)) && !strncmp(Z_STRVAL_P(sval), "HTTP/", lenof("HTTP/"))) { - php_http_version_parse(&message->http.version, Z_STRVAL_P(sval) TSRMLS_CC); + message = php_http_message_init(message, type, mbody); + if ((sval = php_http_env_get_server_var(ZEND_STRL("SERVER_PROTOCOL"), 1)) && !strncmp(Z_STRVAL_P(sval), "HTTP/", lenof("HTTP/"))) { + php_http_version_parse(&message->http.version, Z_STRVAL_P(sval)); } - if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_METHOD"), 1 TSRMLS_CC))) { + if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_METHOD"), 1))) { message->http.info.request.method = estrdup(Z_STRVAL_P(sval)); } - if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_URI"), 1 TSRMLS_CC))) { - message->http.info.request.url = php_http_url_parse(Z_STRVAL_P(sval), Z_STRLEN_P(sval), PHP_HTTP_URL_STDFLAGS TSRMLS_CC); + if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_URI"), 1))) { - message->http.info.request.url = php_http_url_parse(Z_STRVAL_P(sval), Z_STRLEN_P(sval), ~0); ++ message->http.info.request.url = php_http_url_parse(Z_STRVAL_P(sval), Z_STRLEN_P(sval), PHP_HTTP_URL_STDFLAGS); } - php_http_env_get_request_headers(&message->hdrs TSRMLS_CC); + php_http_env_get_request_headers(&message->hdrs); break; case PHP_HTTP_RESPONSE: @@@ -577,14 -603,14 +577,14 @@@ static void php_http_message_object_pro RETVAL_NULL(); } } -static void php_http_message_object_prophandler_set_request_url(php_http_message_object_t *obj, zval *value TSRMLS_DC) { +static void php_http_message_object_prophandler_set_request_url(php_http_message_object_t *obj, zval *value) { if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) { - PTR_SET(obj->message->http.info.request.url, php_http_url_from_zval(value, ~0)); - PTR_SET(obj->message->http.info.request.url, php_http_url_from_zval(value, PHP_HTTP_URL_STDFLAGS TSRMLS_CC)); ++ PTR_SET(obj->message->http.info.request.url, php_http_url_from_zval(value, PHP_HTTP_URL_STDFLAGS)); } } -static void php_http_message_object_prophandler_get_response_status(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { +static void php_http_message_object_prophandler_get_response_status(php_http_message_object_t *obj, zval *return_value) { if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message) && obj->message->http.info.response.status) { - RETVAL_STRING(obj->message->http.info.response.status, 1); + RETVAL_STRING(obj->message->http.info.response.status); } else { RETVAL_NULL(); } @@@ -1256,6 -1273,38 +1256,38 @@@ static PHP_METHOD(HttpMessage, setHeade RETVAL_ZVAL(getThis(), 1, 0); } -static inline void php_http_message_object_add_header(php_http_message_object_t *obj, const char *name_str, size_t name_len, zval *zvalue TSRMLS_DC) ++static inline void php_http_message_object_add_header(php_http_message_object_t *obj, const char *name_str, size_t name_len, zval *zvalue) + { + char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1); - zval *header, *cpy; ++ zend_string *hstr, *vstr; ++ zval *header, tmp; + + if (Z_TYPE_P(zvalue) == IS_NULL) { + return; + } + - cpy = php_http_header_value_to_string(zvalue TSRMLS_CC); ++ vstr = php_http_header_value_to_string(zvalue); + + if ((name_len != lenof("Set-Cookie") && strcmp(name, "Set-Cookie")) - && (header = php_http_message_header(obj->message, name, name_len, 1))) { - zval *tmp; ++ && (hstr = php_http_message_header_string(obj->message, name, name_len))) { + char *hdr_str; - size_t hdr_len = spprintf(&hdr_str, 0, "%s, %s", Z_STRVAL_P(header), Z_STRVAL_P(cpy)); - - MAKE_STD_ZVAL(tmp); - ZVAL_STRINGL(tmp, hdr_str, hdr_len, 0); - zend_symtable_update(&obj->message->hdrs, name, name_len + 1, &tmp, sizeof(void *), NULL); - zval_ptr_dtor(&header); - zval_ptr_dtor(&cpy); - } else if ((header = php_http_message_header(obj->message, name, name_len, 0))) { ++ size_t hdr_len = spprintf(&hdr_str, 0, "%s, %s", hstr->val, vstr->val); ++ ++ ZVAL_STR(&tmp, php_http_cs2zs(hdr_str, hdr_len)); ++ zend_symtable_str_update(&obj->message->hdrs, name, name_len, &tmp); ++ zend_string_release(hstr); ++ zend_string_release(vstr); ++ } else if ((header = php_http_message_header(obj->message, name, name_len))) { + convert_to_array(header); - zend_hash_next_index_insert(Z_ARRVAL_P(header), &cpy, sizeof(void *), NULL); - zval_ptr_dtor(&header); ++ ZVAL_STR(&tmp, vstr); ++ zend_hash_next_index_insert(Z_ARRVAL_P(header), &tmp); + } else { - zend_symtable_update(&obj->message->hdrs, name, name_len + 1, &cpy, sizeof(void *), NULL); ++ ZVAL_STR(&tmp, vstr); ++ zend_symtable_str_update(&obj->message->hdrs, name, name_len, &tmp); + } + efree(name); + } + ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addHeader, 0, 0, 2) ZEND_ARG_INFO(0, header) ZEND_ARG_INFO(0, value) @@@ -1264,34 -1313,14 +1296,14 @@@ static PHP_METHOD(HttpMessage, addHeade { zval *zvalue; char *name_str; - int name_len; + size_t name_len; - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name_str, &name_len, &zvalue)) { - php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &name_str, &name_len, &zvalue)) { + php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis()); - char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1); - zend_string *hstr, *vstr = php_http_header_value_to_string(zvalue); - zval tmp, *header; PHP_HTTP_MESSAGE_OBJECT_INIT(obj); - if ((name_len != lenof("Set-Cookie") && strcmp(name, "Set-Cookie")) - && (hstr = php_http_message_header_string(obj->message, name, name_len))) { - char *hdr_str; - size_t hdr_len = spprintf(&hdr_str, 0, "%s, %s", hstr->val, vstr->val); - - ZVAL_STR(&tmp, php_http_cs2zs(hdr_str, hdr_len)); - zend_symtable_str_update(&obj->message->hdrs, name, name_len, &tmp); - zend_string_release(hstr); - zend_string_release(vstr); - } else if ((header = php_http_message_header(obj->message, name, name_len))) { - convert_to_array(header); - ZVAL_STR(&tmp, vstr); - zend_hash_next_index_insert(Z_ARRVAL_P(header), &tmp); - } else { - ZVAL_STR(&tmp, vstr); - zend_symtable_str_update(&obj->message->hdrs, name, name_len, &tmp); - } - efree(name); - php_http_message_object_add_header(obj, name_str, name_len, zvalue TSRMLS_CC); ++ php_http_message_object_add_header(obj, name_str, name_len, zvalue); } RETVAL_ZVAL(getThis(), 1, 0); } @@@ -1310,7 -1339,19 +1322,20 @@@ static PHP_METHOD(HttpMessage, addHeade PHP_HTTP_MESSAGE_OBJECT_INIT(obj); - array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, append, ARRAY_JOIN_STRONLY|ARRAY_JOIN_PRETTIFY); + if (append) { - HashPosition pos; - php_http_array_hashkey_t key = php_http_array_hashkey_init(0); - zval **val; - - FOREACH_KEYVAL(pos, new_headers, key, val) { - php_http_array_hashkey_stringify(&key); - php_http_message_object_add_header(obj, key.str, key.len-1, *val TSRMLS_CC); - php_http_array_hashkey_stringfree(&key); ++ php_http_arrkey_t key = {0}; ++ zval *val; ++ ++ ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(new_headers), key.h, key.key, val) ++ { ++ php_http_arrkey_stringify(&key, NULL); ++ php_http_message_object_add_header(obj, key.key->val, key.key->len, val); ++ php_http_arrkey_dtor(&key); + } ++ ZEND_HASH_FOREACH_END(); + } else { + array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, 0, ARRAY_JOIN_PRETTIFY|ARRAY_JOIN_STRONLY); + } } RETVAL_ZVAL(getThis(), 1, 0); } @@@ -1629,9 -1670,9 +1654,9 @@@ static PHP_METHOD(HttpMessage, setReque return; } - zend_replace_error_handling(EH_THROW, php_http_exception_bad_url_class_entry, &zeh TSRMLS_CC); - url = php_http_url_from_zval(zurl, PHP_HTTP_URL_STDFLAGS TSRMLS_CC); - zend_restore_error_handling(&zeh TSRMLS_CC); + zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh); - url = php_http_url_from_zval(zurl, ~0); ++ url = php_http_url_from_zval(zurl, PHP_HTTP_URL_STDFLAGS); + zend_restore_error_handling(&zeh); if (url && php_http_url_is_empty(url)) { php_http_url_free(&url); diff --cc src/php_http_url.c index 1520ae9,8384f99..1a5f6ae --- a/src/php_http_url.c +++ b/src/php_http_url.c @@@ -785,10 -775,16 +785,16 @@@ static ZEND_RESULT_CODE parse_userinfo( switch (*ptr) { case ':': if (password) { - php_error_docref(NULL, E_WARNING, - "Failed to parse password; duplicate ':' at pos %u in '%s'", - (unsigned) (ptr - tmp), tmp); - return FAILURE; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - 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); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return FAILURE; + } + state->buffer[state->offset++] = *ptr; + break; } password = ptr + 1; state->buffer[state->offset++] = 0; @@@ -797,10 -793,16 +803,16 @@@ case '%': if (ptr[1] != '%' && (end - ptr <= 2 || !isxdigit(*(ptr+1)) || !isxdigit(*(ptr+2)))) { - php_error_docref(NULL, E_WARNING, - "Failed to parse userinfo; invalid percent encoding at pos %u in '%s'", - (unsigned) (ptr - tmp), tmp); - return FAILURE; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - 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); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return FAILURE; + } + state->buffer[state->offset++] = *ptr++; + break; } state->buffer[state->offset++] = *ptr++; state->buffer[state->offset++] = *ptr++; @@@ -898,8 -905,12 +914,12 @@@ static ZEND_RESULT_CODE parse_idn2(stru } # endif if (rv != IDN2_OK) { - php_error_docref(NULL, E_WARNING, "Failed to parse IDN; %s", idn2_strerror(rv)); - return FAILURE; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse IDN; %s", idn2_strerror(rv)); ++ php_error_docref(NULL, E_WARNING, "Failed to parse IDN; %s", idn2_strerror(rv)); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return FAILURE; + } } else { size_t idnlen = strlen(idn); memcpy(state->url.host, idn, idnlen + 1); @@@ -923,8 -935,12 +943,12 @@@ static ZEND_RESULT_CODE parse_idn(struc } # endif if (rv != IDNA_SUCCESS) { - php_error_docref(NULL, E_WARNING, "Failed to parse IDN; %s", idna_strerror(rv)); - return FAILURE; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse IDN; %s", idna_strerror(rv)); ++ php_error_docref(NULL, E_WARNING, "Failed to parse IDN; %s", idna_strerror(rv)); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return FAILURE; + } } else { size_t idnlen = strlen(idn); memcpy(state->url.host, idn, idnlen + 1); @@@ -1030,7 -1048,9 +1054,8 @@@ static ZEND_RESULT_CODE parse_widn(stru #ifdef HAVE_INET_PTON static const char *parse_ip6(struct parse_state *state, const char *ptr) { + unsigned pos = 0; const char *error = NULL, *end = state->ptr, *tmp = memchr(ptr, ']', end - ptr); - TSRMLS_FETCH_FROM_CTX(state->ts); if (tmp) { size_t addrlen = tmp - ptr + 1; @@@ -1056,7 -1078,9 +1083,9 @@@ } if (error) { - php_error_docref(NULL, E_WARNING, "Failed to parse hostinfo; %s", error); + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse hostinfo; %s at pos %u in '%s'", error, pos, ptr); ++ php_error_docref(NULL, E_WARNING, "Failed to parse hostinfo; %s at pos %u in '%s'", error, pos, ptr); + } return NULL; } @@@ -1066,8 -1090,9 +1095,8 @@@ static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *ptr) { - size_t mb, len; + size_t mb, len = state->offset; const char *end = state->ptr, *tmp = ptr, *port = NULL, *label = NULL; - TSRMLS_FETCH_FROM_CTX(state->ts); #ifdef HAVE_INET_PTON if (*ptr == '[' && !(ptr = parse_ip6(state, ptr))) { @@@ -1079,20 -1107,30 +1111,30 @@@ switch (*ptr) { case ':': if (port) { - php_error_docref(NULL, E_WARNING, - "Failed to parse port; unexpected ':' at pos %u in '%s'", - (unsigned) (ptr - tmp), tmp); - return FAILURE; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - 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); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return FAILURE; + } } port = ptr + 1; break; case '%': if (ptr[1] != '%' && (end - ptr <= 2 || !isxdigit(*(ptr+1)) || !isxdigit(*(ptr+2)))) { - php_error_docref(NULL, E_WARNING, - "Failed to parse hostinfo; invalid percent encoding at pos %u in '%s'", - (unsigned) (ptr - tmp), tmp); - return FAILURE; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - 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); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return FAILURE; + } + state->buffer[state->offset++] = *ptr++; + break; } state->buffer[state->offset++] = *ptr++; state->buffer[state->offset++] = *ptr++; @@@ -1104,11 -1142,16 +1146,16 @@@ /* sort of a compromise, just ensure we don't end up * with a dot at the beginning or two consecutive dots */ - php_error_docref(NULL, E_WARNING, - "Failed to parse %s; unexpected '%c' at pos %u in '%s'", - port ? "port" : "host", - (unsigned char) *ptr, (unsigned) (ptr - tmp), tmp); - return FAILURE; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, ++ php_error_docref(NULL, E_WARNING, + "Failed to parse %s; unexpected '%c' at pos %u in '%s'", + port ? "port" : "host", + (unsigned char) *ptr, (unsigned) (ptr - tmp), tmp); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return FAILURE; + } + break; } state->buffer[state->offset++] = *ptr; label = NULL; @@@ -1119,11 -1162,16 +1166,16 @@@ /* sort of a compromise, just ensure we don't end up * with a hyphen at the beginning */ - php_error_docref(NULL, E_WARNING, - "Failed to parse %s; unexpected '%c' at pos %u in '%s'", - port ? "port" : "host", - (unsigned char) *ptr, (unsigned) (ptr - tmp), tmp); - return FAILURE; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, ++ php_error_docref(NULL, E_WARNING, + "Failed to parse %s; unexpected '%c' at pos %u in '%s'", + port ? "port" : "host", + (unsigned char) *ptr, (unsigned) (ptr - tmp), tmp); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return FAILURE; + } + break; } /* no break */ case '_': case '~': /* unreserved */ @@@ -1138,10 -1186,15 +1190,15 @@@ 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, E_WARNING, - "Failed to parse port; unexpected char '%c' at pos %u in '%s'", - (unsigned char) *ptr, (unsigned) (ptr - tmp), tmp); - return FAILURE; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - 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); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return FAILURE; + } + break; } /* no break */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': @@@ -1160,12 -1213,20 +1217,20 @@@ if (ptr == end) { break; } else if (port) { - 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; - } else if (!(mb = parse_mb(state, PARSE_HOSTINFO, ptr, end, tmp, 0))) { - return FAILURE; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - 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); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return FAILURE; + } + break; + } else if (!(mb = parse_mb(state, PARSE_HOSTINFO, ptr, end, tmp, state->flags & PHP_HTTP_URL_SILENT_ERRORS))) { + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return FAILURE; + } + break; } label = ptr; ptr += mb - 1; @@@ -1204,9 -1265,15 +1269,14 @@@ static const char *parse_authority(stru case '@': /* userinfo delimiter */ if (host) { - php_error_docref(NULL, E_WARNING, - "Failed to parse userinfo; unexpected '@'"); - return NULL; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - 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 '@'"); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return NULL; + } + break; } host = state->ptr + 1; if (tmp != state->ptr && SUCCESS != parse_userinfo(state, tmp)) { @@@ -1252,10 -1320,16 +1322,16 @@@ static const char *parse_path(struct pa case '%': if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) { - 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; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - 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); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return NULL; + } + state->buffer[state->offset++] = *state->ptr; + break; } state->buffer[state->offset++] = *state->ptr++; state->buffer[state->offset++] = *state->ptr++; @@@ -1320,17 -1398,22 +1399,22 @@@ static const char *parse_query(struct p case '%': if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) { - 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; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - 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); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return NULL; + } + /* fallthrough, pct-encode the percent sign */ + } else { + state->buffer[state->offset++] = *state->ptr++; + state->buffer[state->offset++] = *state->ptr++; + state->buffer[state->offset++] = *state->ptr; + break; } - state->buffer[state->offset++] = *state->ptr++; - state->buffer[state->offset++] = *state->ptr++; - state->buffer[state->offset++] = *state->ptr; - break; - - /* RFC1738 unsafe */ + /* no break */ case '{': case '}': case '<': case '>': case '[': case ']': @@@ -1393,19 -1481,37 +1481,37 @@@ static const char *parse_fragment(struc do { switch (*state->ptr) { - case '%': - if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) { + case '#': + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - 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'", + "Failed to parse fragment; invalid fragment identifier at pos %u in '%s'", (unsigned) (state->ptr - tmp), tmp); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { return NULL; } - state->buffer[state->offset++] = *state->ptr++; - state->buffer[state->offset++] = *state->ptr++; state->buffer[state->offset++] = *state->ptr; break; - /* RFC1738 unsafe */ + case '%': + if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) { + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - 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); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + return NULL; + } + /* fallthrough */ + } else { + state->buffer[state->offset++] = *state->ptr++; + state->buffer[state->offset++] = *state->ptr++; + state->buffer[state->offset++] = *state->ptr; + break; + } + /* no break */ + case '{': case '}': case '<': case '>': case '[': case ']': @@@ -1561,11 -1673,15 +1671,15 @@@ php_http_url_t *php_http_url_parse_auth } if (state->ptr != state->end) { - php_error_docref(NULL, E_WARNING, - "Failed to parse URL authority, unexpected character at pos %u in '%s'", - (unsigned) (state->ptr - str), str); - efree(state); - return NULL; + if (!(state->flags & PHP_HTTP_URL_SILENT_ERRORS)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, ++ php_error_docref(NULL, E_WARNING, + "Failed to parse URL authority, unexpected character at pos %u in '%s'", + (unsigned) (state->ptr - str), str); + } + if (!(state->flags & PHP_HTTP_URL_IGNORE_ERRORS)) { + efree(state); + return NULL; + } } return (php_http_url_t *) state; @@@ -1592,17 -1695,18 +1706,23 @@@ 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 = 0; 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); + + /* always set http\Url::FROM_ENV for instances of http\Env\Url */ + if (instanceof_function(Z_OBJCE_P(getThis()), php_http_env_url_class_entry)) { + flags |= PHP_HTTP_URL_FROM_ENV; + } - zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh); + if (flags & PHP_HTTP_URL_SILENT_ERRORS) { - zend_replace_error_handling(EH_SUPPRESS, NULL, &zeh TSRMLS_CC); ++ zend_replace_error_handling(EH_SUPPRESS, NULL, &zeh); + } else if (flags & PHP_HTTP_URL_IGNORE_ERRORS) { - zend_replace_error_handling(EH_NORMAL, NULL, &zeh TSRMLS_CC); ++ zend_replace_error_handling(EH_NORMAL, NULL, &zeh); + } else { - zend_replace_error_handling(EH_THROW, php_http_exception_bad_url_class_entry, &zeh TSRMLS_CC); ++ zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh); + } { php_http_url_t *res_purl, *new_purl = NULL, *old_purl = NULL; @@@ -1645,12 -1749,18 +1765,18 @@@ ZEND_END_ARG_INFO() PHP_METHOD(HttpUrl, mod) { zval *new_url = NULL; - 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_get_exception_bad_url_class_entry(), &zeh); + if (flags & PHP_HTTP_URL_SILENT_ERRORS) { - zend_replace_error_handling(EH_SUPPRESS, NULL, &zeh TSRMLS_CC); ++ zend_replace_error_handling(EH_SUPPRESS, NULL, &zeh); + } else if (flags & PHP_HTTP_URL_IGNORE_ERRORS) { - zend_replace_error_handling(EH_NORMAL, NULL, &zeh TSRMLS_CC); ++ zend_replace_error_handling(EH_NORMAL, NULL, &zeh); + } else { - zend_replace_error_handling(EH_THROW, php_http_exception_bad_url_class_entry, &zeh TSRMLS_CC); ++ zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh); + } { php_http_url_t *new_purl = NULL, *old_purl = NULL; @@@ -1729,43 -1841,45 +1855,48 @@@ 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_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); + + INIT_NS_CLASS_ENTRY(ce, "http\\Env", "Url", php_http_url_methods); + php_http_env_url_class_entry = zend_register_internal_class_ex(&ce, php_http_url_class_entry); - zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("IGNORE_ERRORS"), PHP_HTTP_URL_IGNORE_ERRORS TSRMLS_CC); - zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("SILENT_ERRORS"), PHP_HTTP_URL_SILENT_ERRORS TSRMLS_CC); ++ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("IGNORE_ERRORS"), PHP_HTTP_URL_IGNORE_ERRORS); ++ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("SILENT_ERRORS"), PHP_HTTP_URL_SILENT_ERRORS); + - zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STDFLAGS"), PHP_HTTP_URL_STDFLAGS TSRMLS_CC); ++ zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STDFLAGS"), PHP_HTTP_URL_STDFLAGS); + return SUCCESS; } diff --cc tests/gh-issue7.phpt index 2c3f50d,38e597c..0000000 deleted file mode 100644,100644 --- a/tests/gh-issue7.phpt +++ /dev/null @@@ -1,37 -1,32 +1,0 @@@ ----TEST-- --crash with querystring and exception from error handler ----SKIPIF-- - =")) { - die("skip PHP>=7\n"); - } - ?> - ----GET-- --q[]=1&r[]=2 ----FILE-- --get("q","s")); --} catch (\Exception $e) { -- echo $e->getMessage(),"\n"; --} --try { -- $r = new http\Env\Request; -- var_dump($r->getQuery("r", "s")); --} catch (\Exception $e) { -- echo $e->getMessage(),"\n"; --} -- --?> --===DONE=== ----EXPECT-- --Test --Array to string conversion --Array to string conversion --===DONE===