diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c index 58868e394dcdb..ab0b3a37913f1 100644 --- a/ext/filter/logical_filters.c +++ b/ext/filter/logical_filters.c @@ -613,7 +613,7 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ } /* Use parse_url - if it returns false, we return NULL */ - uri_internal_t *internal_uri = php_uri_parse(uri_handler, Z_STR_P(value)); + uri_internal_t *internal_uri = php_uri_parse(uri_handler, Z_STR_P(value), NULL); if (internal_uri == NULL) { RETURN_VALIDATION_FAILED } diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index e3ebb5011cab9..d25ce80675ec8 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -2736,7 +2736,7 @@ static char *php_openssl_get_url_name(const char *resourcename, uri_handler_t *uri_handler = php_uri_get_handler(NULL); zend_string *resource = zend_string_init(resourcename, resourcenamelen, false); - uri_internal_t *internal_uri = php_uri_parse(uri_handler, resource); + uri_internal_t *internal_uri = php_uri_parse(uri_handler, resource, NULL); if (internal_uri == NULL) { zend_string_release(resource); return NULL; diff --git a/ext/uri/php_lexbor.c b/ext/uri/php_lexbor.c index b9368ad38271e..7e20789966630 100644 --- a/ext/uri/php_lexbor.c +++ b/ext/uri/php_lexbor.c @@ -70,7 +70,7 @@ static zend_result lexbor_read_scheme(const uri_internal_t *internal_uri, zval * return SUCCESS; } -static zend_result lexbor_write_scheme(uri_internal_t *internal_uri, zval *value) +static zend_result lexbor_write_scheme(uri_internal_t *internal_uri, zval *value, zval *errors) { //lxb_url_t *lexbor_uri = (lxb_url_t *) uri_object_internal; @@ -90,7 +90,7 @@ static zend_result lexbor_read_user(const uri_internal_t *internal_uri, zval *re return SUCCESS; } -static zend_result lexbor_write_user(uri_internal_t *internal_uri, zval *value) +static zend_result lexbor_write_user(uri_internal_t *internal_uri, zval *value, zval *errors) { //lxb_url_t *lexbor_uri = (lxb_url_t *) internal_uri->uri; @@ -110,7 +110,7 @@ static zend_result lexbor_read_password(const uri_internal_t *internal_uri, zval return SUCCESS; } -static zend_result lexbor_write_password(uri_internal_t *internal_uri, zval *value) +static zend_result lexbor_write_password(uri_internal_t *internal_uri, zval *value, zval *errors) { //lxb_url_t *lexbor_uri = (lxb_url_t *) internal_uri->uri; @@ -146,7 +146,7 @@ static zend_result lexbor_read_host(const uri_internal_t *internal_uri, zval *re return SUCCESS; } -static zend_result lexbor_write_host(uri_internal_t *internal_uri, zval *value) +static zend_result lexbor_write_host(uri_internal_t *internal_uri, zval *value, zval *errors) { //lxb_url_t *lexbor_uri = (lxb_url_t *) internal_uri->uri; @@ -166,7 +166,7 @@ static zend_result lexbor_read_port(const uri_internal_t *internal_uri, zval *re return SUCCESS; } -static zend_result lexbor_write_port(uri_internal_t *internal_uri, zval *value) +static zend_result lexbor_write_port(uri_internal_t *internal_uri, zval *value, zval *errors) { //lxb_url_t *lexbor_uri = (lxb_url_t *) internal_uri->uri; @@ -188,7 +188,7 @@ static zend_result lexbor_read_path(const uri_internal_t *internal_uri, zval *re return SUCCESS; } -static zend_result lexbor_write_path(uri_internal_t *internal_uri, zval *value) +static zend_result lexbor_write_path(uri_internal_t *internal_uri, zval *value, zval *errors) { //lxb_url_t *lexbor_uri = (lxb_url_t *) uri_object_internal; @@ -208,7 +208,7 @@ static zend_result lexbor_read_query(const uri_internal_t *internal_uri, zval *r return SUCCESS; } -static zend_result lexbor_write_query(uri_internal_t *internal_uri, zval *value) +static zend_result lexbor_write_query(uri_internal_t *internal_uri, zval *value, zval *errors) { //lxb_url_t *lexbor_uri = (lxb_url_t *) internal_uri->uri; @@ -228,7 +228,7 @@ static zend_result lexbor_read_fragment(const uri_internal_t *internal_uri, zval return SUCCESS; } -static zend_result lexbor_write_fragment(uri_internal_t *internal_uri, zval *value) +static zend_result lexbor_write_fragment(uri_internal_t *internal_uri, zval *value, zval *errors) { //lxb_url_t *lexbor_uri = (lxb_url_t *) internal_uri->uri; @@ -268,27 +268,24 @@ static zend_result lexbor_init_parser(void) return SUCCESS; } -void fill_errors(zval *errors) +void fill_errors(zval *errors, const zend_string *uri) { if (!errors || lexbor_parser->log == NULL) { return; } - zval errors_tmp; - array_init(&errors_tmp); + array_init(errors); lexbor_plog_entry_t *lxb_error; while ((lxb_error = lexbor_array_obj_pop(&lexbor_parser->log->list)) != NULL) { zval error; object_init_ex(&error, whatwg_error_ce); + zend_update_property_string(whatwg_error_ce, Z_OBJ(error), "uri", sizeof("uri") - 1, ZSTR_VAL(uri)); zend_update_property_string(whatwg_error_ce, Z_OBJ(error), "position", sizeof("position") - 1, (const char *) lxb_error->data); zend_update_property_long(whatwg_error_ce, Z_OBJ(error), "errorCode", sizeof("errorCode") - 1, lxb_error->id); - add_next_index_zval(&errors_tmp, &error); + add_next_index_zval(errors, &error); } - - ZEND_TRY_ASSIGN_REF_COPY(errors, &errors_tmp); - zval_ptr_dtor(&errors_tmp); } static void *lexbor_parse_uri(const zend_string *url_str, const zend_string *base_url_str, zval *errors) @@ -299,7 +296,7 @@ static void *lexbor_parse_uri(const zend_string *url_str, const zend_string *bas if (base_url_str) { if ((base_url = lxb_url_parse(lexbor_parser, NULL, (unsigned char *) ZSTR_VAL(base_url_str), ZSTR_LEN(base_url_str))) == NULL) { - fill_errors(errors); + fill_errors(errors, base_url_str); return NULL; } @@ -307,7 +304,7 @@ static void *lexbor_parse_uri(const zend_string *url_str, const zend_string *bas } if ((url = lxb_url_parse(lexbor_parser, base_url, (unsigned char *) ZSTR_VAL(url_str), ZSTR_LEN(url_str))) == NULL) { - fill_errors(errors); + fill_errors(errors, url_str); return NULL; } diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index 9a6c58d0fa061..436b73a22d986 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -20,6 +20,7 @@ #include "php.h" #include "Zend/zend_interfaces.h" +#include "Zend/zend_exceptions.h" #include "main/php_ini.h" #include "php_uri.h" @@ -33,6 +34,8 @@ zend_class_entry *rfc3986_uri_ce; zend_object_handlers rfc3986_uri_object_handlers; zend_class_entry *whatwg_uri_ce; zend_object_handlers whatwg_uri_object_handlers; +zend_class_entry *uri_exception_ce; +zend_class_entry *invalid_uri_exception_ce; zend_class_entry *whatwg_error_ce; static zend_array uri_handlers; @@ -98,7 +101,7 @@ PHPAPI uri_handler_t *php_uri_get_handler(const zend_string *uri_handler_name) return uri_handler_by_name(ZSTR_VAL(uri_handler_name), ZSTR_LEN(uri_handler_name)); } -PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, zend_string *uri_str) +PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, zend_string *uri_str, zval *errors) { ZEND_ASSERT(uri_handler != NULL); @@ -108,7 +111,7 @@ PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, zend_stri uri_internal_t *internal_uri = emalloc(sizeof(uri_internal_t)); internal_uri->handler = uri_handler; - internal_uri->uri = uri_handler->parse_uri(uri_str, NULL, NULL); + internal_uri->uri = uri_handler->parse_uri(uri_str, NULL, errors); if (UNEXPECTED(internal_uri->uri == NULL)) { efree(internal_uri); @@ -178,32 +181,46 @@ PHPAPI void php_uri_free(uri_internal_t *internal_uri) PHP_METHOD(Uri_WhatWgError, __construct) { - zend_string *position; + zend_string *uri, *position; zend_long error; - ZEND_PARSE_PARAMETERS_START(2, 2) + ZEND_PARSE_PARAMETERS_START(3, 3) + Z_PARAM_STR(uri) Z_PARAM_STR(position) Z_PARAM_LONG(error) ZEND_PARSE_PARAMETERS_END(); + zend_update_property_str(whatwg_error_ce, Z_OBJ_P(ZEND_THIS), "uri", sizeof("uri") - 1, uri); zend_update_property_str(whatwg_error_ce, Z_OBJ_P(ZEND_THIS), "position", sizeof("position") - 1, position); zend_update_property_long(whatwg_error_ce, Z_OBJ_P(ZEND_THIS), "error", sizeof("error") - 1, error); } PHPAPI void php_uri_instantiate_uri( INTERNAL_FUNCTION_PARAMETERS, const uri_handler_t *handler, const zend_string *uri_str, const zend_string *base_url_str, - zval *errors, bool is_constructor + bool is_constructor, bool return_errors ) { - void *uri = handler->parse_uri(uri_str, base_url_str, errors); + zval errors; + ZVAL_UNDEF(&errors); + + void *uri = handler->parse_uri(uri_str, base_url_str, &errors); if (UNEXPECTED(uri == NULL)) { if (is_constructor) { - zend_argument_value_error(1, "must be a valid URI"); + throw_invalid_uri_exception(&errors); + zval_ptr_dtor(&errors); RETURN_THROWS(); } else { + if (return_errors && Z_TYPE(errors) == IS_ARRAY) { + RETURN_ZVAL(&errors, false, false); + } + + zval_ptr_dtor(&errors); + RETURN_NULL(); } } + ZEND_ASSERT(Z_TYPE(errors) == IS_UNDEF); + if (!is_constructor) { object_init_ex(return_value, handler->get_uri_ce()); } @@ -233,7 +250,7 @@ static void create_rfc3986_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor RETURN_THROWS(); } - php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &uriparser_uri_handler, uri_str, base_url_str, NULL, is_constructor); + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &uriparser_uri_handler, uri_str, base_url_str, is_constructor, false); } PHP_METHOD(Uri_Rfc3986Uri, create) @@ -249,13 +266,11 @@ PHP_METHOD(Uri_Rfc3986Uri, __construct) static void create_whatwg_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor) { zend_string *uri_str, *base_url_str = NULL; - zval *errors = NULL; - ZEND_PARSE_PARAMETERS_START(1, 3) + ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_PATH_STR(uri_str) Z_PARAM_OPTIONAL Z_PARAM_PATH_STR_OR_NULL(base_url_str) - Z_PARAM_ZVAL(errors) ZEND_PARSE_PARAMETERS_END(); if (ZSTR_LEN(uri_str) == 0) { @@ -268,7 +283,7 @@ static void create_whatwg_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor) RETURN_THROWS(); } - php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &lexbor_uri_handler, uri_str, base_url_str, errors, is_constructor); + php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &lexbor_uri_handler, uri_str, base_url_str, is_constructor, true); } PHP_METHOD(Uri_WhatWgUri, create) @@ -412,15 +427,21 @@ PHP_METHOD(Uri_Rfc3986Uri, __unserialize) zend_object *object = Z_OBJ_P(ZEND_THIS); uri_internal_t *internal_uri = uri_internal_from_obj(object); - /*if (!php_date_initialize_from_hash(&dateobj, myht)) { - zend_throw_error(NULL, "Invalid serialization data for DateTime object"); - RETURN_THROWS(); - }*/ - zend_string *str = zend_string_init("https://example.com", sizeof("https://example.com") - 1, false); + zval errors; + ZVAL_UNDEF(&errors); + internal_uri->handler = uri_handler_by_name("rfc3986", sizeof("rfc3986") - 1); - internal_uri->uri = internal_uri->handler->parse_uri(str, NULL, NULL); + internal_uri->uri = internal_uri->handler->parse_uri(str, NULL, &errors); + if (internal_uri->uri == NULL) { + throw_invalid_uri_exception(&errors); + zval_ptr_dtor(&errors); + zend_string_release(str); + RETURN_THROWS(); + } + ZEND_ASSERT(Z_TYPE(errors) == IS_UNDEF); + //zend_string_release(str); TODO Fix memory leak uri_restore_custom_properties(object, internal_uri, ht); } @@ -436,15 +457,21 @@ PHP_METHOD(Uri_WhatWgUri, __unserialize) zend_object *object = Z_OBJ_P(ZEND_THIS); uri_internal_t *internal_uri = uri_internal_from_obj(object); - /*if (!php_date_initialize_from_hash(&dateobj, myht)) { - zend_throw_error(NULL, "Invalid serialization data for DateTime object"); - RETURN_THROWS(); - }*/ - zend_string *str = zend_string_init("https://example.com", sizeof("https://example.com") - 1, false); + zval errors; + ZVAL_UNDEF(&errors); + internal_uri->handler = uri_handler_by_name("whatwg", sizeof("whatwg") - 1); - internal_uri->uri = internal_uri->handler->parse_uri(str, NULL, NULL); + internal_uri->uri = internal_uri->handler->parse_uri(str, NULL, &errors); + if (internal_uri->uri == NULL) { + throw_invalid_uri_exception(&errors); + zval_ptr_dtor(&errors); + zend_string_release(str); + RETURN_THROWS(); + } + ZEND_ASSERT(Z_TYPE(errors) == IS_UNDEF); + //zend_string_release(str); TODO Fix memory leak uri_restore_custom_properties(object, internal_uri, ht); } @@ -663,6 +690,8 @@ void uri_register_symbols(void) whatwg_uri_ce = register_class_Uri_WhatWgUri(uri_interface_ce); php_uri_implementation_set_object_handlers(whatwg_uri_ce, &whatwg_uri_object_handlers); + uri_exception_ce = register_class_Uri_UriException(zend_ce_exception); + invalid_uri_exception_ce = register_class_Uri_InvalidUriException(uri_exception_ce); whatwg_error_ce = register_class_Uri_WhatWgError(); } diff --git a/ext/uri/php_uri.h b/ext/uri/php_uri.h index 4b14cd0b7eee2..75279e32d3948 100644 --- a/ext/uri/php_uri.h +++ b/ext/uri/php_uri.h @@ -27,7 +27,7 @@ ZEND_TSRMLS_CACHE_EXTERN() #endif PHPAPI uri_handler_t *php_uri_get_handler(const zend_string *uri_handler_name); -PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, zend_string *uri_str); +PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, zend_string *uri_str, zval *errors); PHPAPI zend_result php_uri_get_scheme(const uri_internal_t *internal_uri, zval *zv); PHPAPI zend_result php_uri_get_user(const uri_internal_t *internal_uri, zval *zv); PHPAPI zend_result php_uri_get_password(const uri_internal_t *internal_uri, zval *zv); @@ -40,7 +40,7 @@ PHPAPI void php_uri_free(uri_internal_t *internal_uri); PHPAPI void php_uri_instantiate_uri( INTERNAL_FUNCTION_PARAMETERS, const uri_handler_t *handler, const zend_string *uri_str, const zend_string *base_url_str, - zval *errors, bool is_constructor + bool is_constructor, bool return_errors ); PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers); diff --git a/ext/uri/php_uri.stub.php b/ext/uri/php_uri.stub.php index 950d25ed35fed..26cd40c327d60 100644 --- a/ext/uri/php_uri.stub.php +++ b/ext/uri/php_uri.stub.php @@ -4,6 +4,17 @@ namespace Uri; +/** @strict-properties */ +abstract class UriException extends \Exception +{ +} + +/** @strict-properties */ +class InvalidUriException extends \Uri\UriException +{ + public readonly array $errors; +} + /** @strict-properties */ final readonly class WhatWgError { @@ -66,10 +77,11 @@ /** @cvalue LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST */ public const int ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST = UNKNOWN; + public string $uri; public string $position; public int $errorCode; - public function __construct(string $position, int $errorCode) {} + public function __construct(string $uri, string $position, int $errorCode) {} } interface UriInterface extends \Stringable @@ -193,7 +205,7 @@ public function __unserialize(array $data): void; private ?string $fragment; /** @param array $errors */ - public static function create(string $uri, ?string $baseUrl = null, &$errors = null): ?static {} + public static function create(string $uri, ?string $baseUrl = null, &$errors = null): static|array {} /** @param array $errors */ public function __construct(string $uri, ?string $baseUrl = null, &$errors = null) {} diff --git a/ext/uri/php_uri_arginfo.h b/ext/uri/php_uri_arginfo.h index 95c0d5d65eaf9..f770fd8caa71d 100644 --- a/ext/uri/php_uri_arginfo.h +++ b/ext/uri/php_uri_arginfo.h @@ -1,7 +1,8 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 0ac9ba734539b67009e61b97ed828fa0166b3b16 */ + * Stub hash: 5fb74453f5bcc9db454b7ca58efe504ac50e92a0 */ -ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Uri_WhatWgError___construct, 0, 0, 2) +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Uri_WhatWgError___construct, 0, 0, 3) + ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, position, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, errorCode, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -110,7 +111,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986Uri___unseriali ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWgUri_create, 0, 1, IS_STATIC, 1) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Uri_WhatWgUri_create, 0, 1, MAY_BE_STATIC|MAY_BE_ARRAY) ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, baseUrl, IS_STRING, 1, "null") ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, errors, "null") @@ -262,6 +263,32 @@ static const zend_function_entry class_Uri_WhatWgUri_methods[] = { ZEND_FE_END }; +static zend_class_entry *register_class_Uri_UriException(zend_class_entry *class_entry_Exception) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "Uri", "UriException", NULL); + class_entry = zend_register_internal_class_with_flags(&ce, class_entry_Exception, ZEND_ACC_ABSTRACT|ZEND_ACC_NO_DYNAMIC_PROPERTIES); + + return class_entry; +} + +static zend_class_entry *register_class_Uri_InvalidUriException(zend_class_entry *class_entry_Uri_UriException) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "Uri", "InvalidUriException", NULL); + class_entry = zend_register_internal_class_with_flags(&ce, class_entry_Uri_UriException, ZEND_ACC_NO_DYNAMIC_PROPERTIES); + + zval property_errors_default_value; + ZVAL_UNDEF(&property_errors_default_value); + zend_string *property_errors_name = zend_string_init("errors", sizeof("errors") - 1, 1); + zend_declare_typed_property(class_entry, property_errors_name, &property_errors_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); + zend_string_release(property_errors_name); + + return class_entry; +} + static zend_class_entry *register_class_Uri_WhatWgError(void) { zend_class_entry ce, *class_entry; @@ -443,6 +470,12 @@ static zend_class_entry *register_class_Uri_WhatWgError(void) zend_declare_typed_class_constant(class_entry, const_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST_name, &const_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST_name); + zval property_uri_default_value; + ZVAL_UNDEF(&property_uri_default_value); + zend_string *property_uri_name = zend_string_init("uri", sizeof("uri") - 1, 1); + zend_declare_typed_property(class_entry, property_uri_name, &property_uri_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_string_release(property_uri_name); + zval property_position_default_value; ZVAL_UNDEF(&property_position_default_value); zend_string *property_position_name = zend_string_init("position", sizeof("position") - 1, 1); diff --git a/ext/uri/php_uri_common.c b/ext/uri/php_uri_common.c index 2f2d33ef007e7..1afa9aead4d6e 100644 --- a/ext/uri/php_uri_common.c +++ b/ext/uri/php_uri_common.c @@ -16,6 +16,7 @@ #include "php.h" #include "Zend/zend_interfaces.h" +#include "Zend/zend_exceptions.h" #include "php_uri_common.h" void uri_register_property_handler(HashTable *property_handlers, zend_string *name, const uri_property_handler_t *handler) @@ -28,3 +29,27 @@ uri_property_handler_t *uri_property_handler_from_internal_uri(const uri_interna { return zend_hash_find_ptr(internal_uri->handler->property_handlers, name); } + +void throw_invalid_uri_exception(zval *errors) +{ + zval exception_zv; + object_init_ex(&exception_zv, invalid_uri_exception_ce); + + zend_update_property_string( + invalid_uri_exception_ce, + Z_OBJ(exception_zv), + ZSTR_VAL(ZSTR_KNOWN(ZEND_STR_MESSAGE)), + ZSTR_LEN(ZSTR_KNOWN(ZEND_STR_MESSAGE)), + "URI parsing failed" + ); + + if (Z_TYPE_P(errors) == IS_ARRAY) { + zend_update_property(invalid_uri_exception_ce, Z_OBJ(exception_zv), "errors", sizeof("errors") - 1, errors); + } else { + ZEND_ASSERT(Z_TYPE_P(errors) == IS_UNDEF); + ZVAL_EMPTY_ARRAY(errors); + zend_update_property(invalid_uri_exception_ce, Z_OBJ(exception_zv), "errors", sizeof("errors") - 1, errors); + } + + zend_throw_exception_object(&exception_zv); +} diff --git a/ext/uri/php_uri_common.h b/ext/uri/php_uri_common.h index 985a22bca0255..96ff5fa85db55 100644 --- a/ext/uri/php_uri_common.h +++ b/ext/uri/php_uri_common.h @@ -22,6 +22,8 @@ extern zend_class_entry *rfc3986_uri_ce; extern zend_object_handlers rfc3986_uri_object_handlers; extern zend_class_entry *whatwg_uri_ce; extern zend_object_handlers whatwg_uri_object_handlers; +extern zend_class_entry *uri_exception_ce; +extern zend_class_entry *invalid_uri_exception_ce; extern zend_class_entry *whatwg_error_ce; typedef struct uri_handler_t { @@ -60,7 +62,7 @@ static inline uri_internal_t *uri_internal_from_obj(zend_object *object) { typedef zend_result (*uri_read_t)(const uri_internal_t *internal_uri, zval *retval); -typedef zend_result (*uri_write_t)(uri_internal_t *internal_uri, zval *value); +typedef zend_result (*uri_write_t)(uri_internal_t *internal_uri, zval *value, zval *errors); typedef struct uri_property_handler_t { uri_read_t read_func; @@ -79,8 +81,8 @@ typedef struct uri_property_handler_t { void uri_register_property_handler(HashTable *property_handlers, zend_string *name, const uri_property_handler_t *handler); zend_result uri_handler_register(const uri_handler_t *uri_handler); - uri_property_handler_t *uri_property_handler_from_internal_uri(const uri_internal_t *internal_uri, zend_string *name); +void throw_invalid_uri_exception(zval *errors); #define URI_CHECK_INITIALIZATION_RETURN_THROWS(internal_uri, object) do { \ ZEND_ASSERT(internal_uri != NULL); \ @@ -126,16 +128,24 @@ uri_property_handler_t *uri_property_handler_from_internal_uri(const uri_interna zend_object *new_object = uri_clone_obj_handler(Z_OBJ_P(ZEND_THIS)); \ uri_internal_t *new_internal_uri = uri_internal_from_obj(new_object); \ URI_CHECK_INITIALIZATION_RETURN_THROWS(new_internal_uri, Z_OBJ_P(ZEND_THIS)); \ - if (property_handler->write_func == NULL || property_handler->write_func(new_internal_uri, property_zv) == FAILURE) { \ + if (property_handler->write_func == NULL) { \ zend_readonly_property_modification_error_ex(ZSTR_VAL(Z_OBJ_P(ZEND_THIS)->ce->name), ZSTR_VAL(property_name)); \ RETURN_THROWS(); \ } \ + zval errors; \ + ZVAL_UNDEF(&errors); \ + if (property_handler->write_func(new_internal_uri, property_zv, &errors) == FAILURE) { \ + throw_invalid_uri_exception(&errors); \ + zval_ptr_dtor(&errors); \ + RETURN_THROWS(); \ + } \ + ZEND_ASSERT(Z_TYPE(errors) == IS_UNDEF); \ ZVAL_OBJ(return_value, new_object); #define URI_WITHER_STR(property_name) do { \ zend_string *value; \ ZEND_PARSE_PARAMETERS_START(1, 1) \ - Z_PARAM_STR_OR_NULL(value) \ + Z_PARAM_PATH_STR_OR_NULL(value) \ ZEND_PARSE_PARAMETERS_END(); \ zval zv; \ if (value == NULL) { \ diff --git a/ext/uri/php_uriparser.c b/ext/uri/php_uriparser.c index 791f21d97f171..bc26c09da8a74 100644 --- a/ext/uri/php_uriparser.c +++ b/ext/uri/php_uriparser.c @@ -43,22 +43,16 @@ const uri_handler_t uriparser_uri_handler = { typedef enum { URIPARSER_APPEND_AFTER_SCHEME, - URIPARSER_APPEND_BEFORE_AUTHORITY, URIPARSER_APPEND_AFTER_AUTHORITY, - URIPARSER_APPEND_BEFORE_HOST, URIPARSER_APPEND_AFTER_HOST, - URIPARSER_APPEND_BEFORE_PORT, URIPARSER_APPEND_AFTER_PORT, - URIPARSER_APPEND_BEFORE_PATH, URIPARSER_APPEND_AFTER_PATH, - URIPARSER_APPEND_BEFORE_QUERY, URIPARSER_APPEND_AFTER_QUERY, - URIPARSER_APPEND_BEFORE_FRAGMENT, } uriparser_append_after_component; -#define URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri) do { \ +#define URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri, errors) do { \ zend_string *str = smart_str_extract(&uri_str); \ - UriUriA *new_uriparser_uri = uriparser_parse_uri(str, NULL, NULL); \ + UriUriA *new_uriparser_uri = uriparser_parse_uri(str, NULL, errors); \ if (new_uriparser_uri == NULL) { \ smart_str_free(&uri_str); \ zend_string_free(str); \ @@ -75,30 +69,30 @@ static void uriparser_append_rest(UriUriA *uri, smart_str *uri_str, uriparser_ap ) { if (start <= URIPARSER_APPEND_AFTER_SCHEME && uri->scheme.afterLast != NULL) { smart_str_appendl(uri_str, uri->scheme.afterLast + scheme_offset, strlen(uri->scheme.afterLast + scheme_offset)); - } else if (start <= URIPARSER_APPEND_BEFORE_AUTHORITY && uri->userInfo.first != NULL) { + } else if (start <= URIPARSER_APPEND_AFTER_SCHEME && uri->userInfo.first != NULL) { smart_str_appendl(uri_str, uri->userInfo.first, strlen(uri->userInfo.first)); } else if (start <= URIPARSER_APPEND_AFTER_AUTHORITY && uri->userInfo.afterLast != NULL) { smart_str_appendl(uri_str, uri->userInfo.afterLast + authority_offset, strlen(uri->userInfo.afterLast + authority_offset)); - } else if (start <= URIPARSER_APPEND_BEFORE_HOST && uri->hostText.first != NULL) { + } else if (start <= URIPARSER_APPEND_AFTER_AUTHORITY && uri->hostText.first != NULL) { smart_str_appendl(uri_str, uri->hostText.first, strlen(uri->hostText.first)); } else if (start <= URIPARSER_APPEND_AFTER_HOST && uri->hostText.afterLast != NULL) { smart_str_appendl(uri_str, uri->hostText.afterLast, strlen(uri->hostText.afterLast)); - } else if (start <= URIPARSER_APPEND_BEFORE_PORT && uri->portText.first != NULL) { + } else if (start <= URIPARSER_APPEND_AFTER_HOST && uri->portText.first != NULL) { smart_str_appendl(uri_str, uri->portText.first, strlen(uri->portText.first)); } else if (start <= URIPARSER_APPEND_AFTER_PORT && uri->portText.afterLast != NULL) { smart_str_appendl(uri_str, uri->portText.afterLast, strlen(uri->portText.afterLast)); - } else if (start <= URIPARSER_APPEND_BEFORE_PATH && uri->pathHead != NULL && uri->pathHead->text.first != NULL) { + } else if (start <= URIPARSER_APPEND_AFTER_PORT && uri->pathHead != NULL && uri->pathHead->text.first != NULL) { if (uri->absolutePath) { // TODO add / for URLs smart_str_appendc(uri_str, '/'); } smart_str_appendl(uri_str, uri->pathHead->text.first, strlen(uri->pathHead->text.first)); } else if (start <= URIPARSER_APPEND_AFTER_PATH && uri->pathHead != NULL && uri->pathTail->text.afterLast != NULL) { smart_str_appendl(uri_str, uri->pathTail->text.afterLast, strlen(uri->pathTail->text.afterLast)); - } else if (start <= URIPARSER_APPEND_BEFORE_QUERY && uri->query.first != NULL) { + } else if (start <= URIPARSER_APPEND_AFTER_PATH && uri->query.first != NULL) { smart_str_appendl(uri_str, uri->query.first, strlen(uri->query.first)); } else if (start <= URIPARSER_APPEND_AFTER_QUERY && uri->query.afterLast != NULL) { smart_str_appendl(uri_str, uri->query.afterLast, strlen(uri->query.afterLast)); - } else if (start <= URIPARSER_APPEND_BEFORE_FRAGMENT && uri->fragment.first != NULL) { + } else if (start <= URIPARSER_APPEND_AFTER_QUERY && uri->fragment.first != NULL) { smart_str_appendl(uri_str, uri->fragment.first, strlen(uri->fragment.first)); } } @@ -129,7 +123,7 @@ static void uriparser_append_scheme(const uri_internal_t *internal_uri, smart_st zval_ptr_dtor(&tmp); } -static zend_result uriparser_write_scheme(uri_internal_t *internal_uri, zval *value) +static zend_result uriparser_write_scheme(uri_internal_t *internal_uri, zval *value, zval *errors) { UriUriA *uriparser_uri = (UriUriA *) internal_uri->uri; smart_str uri_str = {0}; @@ -146,7 +140,7 @@ static zend_result uriparser_write_scheme(uri_internal_t *internal_uri, zval *va uriparser_append_rest(uriparser_uri, &uri_str, URIPARSER_APPEND_AFTER_SCHEME, offset, 0); - URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri); + URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri, errors); } static zend_result uriparser_read_user(const uri_internal_t *internal_uri, zval *retval) @@ -220,7 +214,7 @@ static void uriparser_append_authority(const uri_internal_t *internal_uri, smart } } -static zend_result uriparser_write_user(uri_internal_t *internal_uri, zval *value) +static zend_result uriparser_write_user(uri_internal_t *internal_uri, zval *value, zval *errors) { UriUriA *uriparser_uri = (UriUriA *) internal_uri->uri; smart_str uri_str = {0}; @@ -241,10 +235,10 @@ static zend_result uriparser_write_user(uri_internal_t *internal_uri, zval *valu uriparser_append_rest(uriparser_uri, &uri_str, URIPARSER_APPEND_AFTER_AUTHORITY, 0, offset); - URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri); + URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri, errors); } -static zend_result uriparser_write_password(uri_internal_t *internal_uri, zval *value) +static zend_result uriparser_write_password(uri_internal_t *internal_uri, zval *value, zval *errors) { UriUriA *uriparser_uri = (UriUriA *) internal_uri->uri; smart_str uri_str = {0}; @@ -265,7 +259,7 @@ static zend_result uriparser_write_password(uri_internal_t *internal_uri, zval * uriparser_append_rest(uriparser_uri, &uri_str, URIPARSER_APPEND_AFTER_AUTHORITY, 0, offset); - URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri); + URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri, errors); } static zend_result uriparser_read_host(const uri_internal_t *internal_uri, zval *retval) @@ -293,7 +287,7 @@ static void uriparser_append_host(const uri_internal_t *internal_uri, smart_str zval_ptr_dtor(&tmp); } -static zend_result uriparser_write_host(uri_internal_t *internal_uri, zval *value) +static zend_result uriparser_write_host(uri_internal_t *internal_uri, zval *value, zval *errors) { UriUriA *uriparser_uri = (UriUriA *) internal_uri->uri; @@ -307,18 +301,7 @@ static zend_result uriparser_write_host(uri_internal_t *internal_uri, zval *valu uriparser_append_rest(uriparser_uri, &uri_str, URIPARSER_APPEND_AFTER_HOST, 0, 0); - zend_string *str = smart_str_extract(&uri_str); \ - UriUriA *new_uriparser_uri = uriparser_parse_uri(str, NULL, NULL); \ - if (new_uriparser_uri == NULL) { \ - smart_str_free(&uri_str); \ - zend_string_free(str); \ - return FAILURE; \ - } \ - uriparser_free_uri(uriparser_uri); \ - internal_uri->uri = (void *) new_uriparser_uri; \ - smart_str_free(&uri_str); \ - return SUCCESS; \ - //URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri); + URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri, errors); } static zend_result uriparser_read_port(const uri_internal_t *internal_uri, zval *retval) @@ -347,7 +330,7 @@ static void uriparser_append_port(const uri_internal_t *internal_uri, smart_str zval_ptr_dtor(&tmp); } -static zend_result uriparser_write_port(uri_internal_t *internal_uri, zval *value) +static zend_result uriparser_write_port(uri_internal_t *internal_uri, zval *value, zval *errors) { UriUriA *uriparser_uri = (UriUriA *) internal_uri->uri; @@ -363,7 +346,7 @@ static zend_result uriparser_write_port(uri_internal_t *internal_uri, zval *valu uriparser_append_rest(uriparser_uri, &uri_str, URIPARSER_APPEND_AFTER_PORT, 0, 0); - URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri); + URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri, errors); } static zend_result uriparser_read_path(const uri_internal_t *internal_uri, zval *retval) @@ -401,7 +384,7 @@ static void uriparser_append_path(const uri_internal_t *internal_uri, smart_str zval_ptr_dtor(&tmp); } -static zend_result uriparser_write_path(uri_internal_t *internal_uri, zval *value) +static zend_result uriparser_write_path(uri_internal_t *internal_uri, zval *value, zval *errors) { UriUriA *uriparser_uri = (UriUriA *) internal_uri->uri; @@ -417,7 +400,7 @@ static zend_result uriparser_write_path(uri_internal_t *internal_uri, zval *valu uriparser_append_rest(uriparser_uri, &uri_str, URIPARSER_APPEND_AFTER_PATH, 0, 0); - URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri); + URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri, errors); } static zend_result uriparser_read_query(const uri_internal_t *internal_uri, zval *retval) @@ -446,7 +429,7 @@ static void uriparser_append_query(const uri_internal_t *internal_uri, smart_str zval_ptr_dtor(&tmp); } -static zend_result uriparser_write_query(uri_internal_t *internal_uri, zval *value) +static zend_result uriparser_write_query(uri_internal_t *internal_uri, zval *value, zval *errors) { UriUriA *uriparser_uri = (UriUriA *) internal_uri->uri; @@ -463,7 +446,7 @@ static zend_result uriparser_write_query(uri_internal_t *internal_uri, zval *val uriparser_append_rest(uriparser_uri, &uri_str, URIPARSER_APPEND_AFTER_QUERY, 0, 0); - URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri); + URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri, errors); } static zend_result uriparser_read_fragment(const uri_internal_t *internal_uri, zval *retval) @@ -479,7 +462,7 @@ static zend_result uriparser_read_fragment(const uri_internal_t *internal_uri, z return SUCCESS; } -static zend_result uriparser_write_fragment(uri_internal_t *internal_uri, zval *value) +static zend_result uriparser_write_fragment(uri_internal_t *internal_uri, zval *value, zval *errors) { UriUriA *uriparser_uri = (UriUriA *) internal_uri->uri; @@ -495,7 +478,7 @@ static zend_result uriparser_write_fragment(uri_internal_t *internal_uri, zval * smart_str_append(&uri_str, Z_STR_P(value)); } - URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri); + URIPARSER_PARSE_STR(uri_str, internal_uri, uriparser_uri, errors); } static zend_result uriparser_init_parser(void) diff --git a/ext/uri/tests/003.phpt b/ext/uri/tests/003.phpt index 94aa17bdc2d2e..dd8f39cbe0863 100644 --- a/ext/uri/tests/003.phpt +++ b/ext/uri/tests/003.phpt @@ -32,7 +32,7 @@ object(Uri\WhatWgUri)#%d (%d) { ["fragment"]=> string(6) "anchor" } -object(Uri\Rfc3986Uri)#1 (8) { +object(Uri\Rfc3986Uri)#%d (%d) { ["scheme"]=> NULL ["user"]=> @@ -50,4 +50,14 @@ object(Uri\Rfc3986Uri)#1 (8) { ["fragment"]=> NULL } -NULL +array(1) { + [0]=> + object(Uri\WhatWgError)#%d (%d) { + ["uri"]=> + string(7) "/page:1" + ["position"]=> + string(7) "/page:1" + ["errorCode"]=> + int(21) + } +} diff --git a/ext/uri/tests/004.phpt b/ext/uri/tests/004.phpt index 4b3dbc027ef11..f395b8e79a666 100644 --- a/ext/uri/tests/004.phpt +++ b/ext/uri/tests/004.phpt @@ -5,12 +5,24 @@ uri --FILE-- getMessage() . "\n"; +} + try { Uri\Rfc3986Uri::create(""); } catch (ValueError $e) { echo $e->getMessage() . "\n"; } +try { + new Uri\WhatWgUri(""); +} catch (ValueError $e) { + echo $e->getMessage() . "\n"; +} + try { Uri\WhatWgUri::create(""); } catch (ValueError $e) { @@ -23,6 +35,18 @@ try { echo $e->getMessage() . "\n"; } +try { + new Uri\Rfc3986Uri("https://example.com", ""); +} catch (ValueError $e) { + echo $e->getMessage() . "\n"; +} + +try { + new Uri\WhatWgUri("https://example.com", ""); +} catch (ValueError $e) { + echo $e->getMessage() . "\n"; +} + try { Uri\WhatWgUri::create("https://example.com", ""); } catch (ValueError $e) { @@ -30,20 +54,20 @@ try { } var_dump(Uri\Rfc3986Uri::create("192.168/contact.html")); -$errors = []; -var_dump(Uri\WhatWgUri::create("192.168/contact.html", null, $errors)); -var_dump($errors); +var_dump(Uri\WhatWgUri::create("192.168/contact.html", null)); var_dump(Uri\Rfc3986Uri::create("http://RuPaul's Drag Race All Stars 7 Winners Cast on This Season's")); -$errors = []; -var_dump(Uri\WhatWgUri::create("http://RuPaul's Drag Race All Stars 7 Winners Cast on This Season's", null, $errors)); -var_dump($errors); +var_dump(Uri\WhatWgUri::create("http://RuPaul's Drag Race All Stars 7 Winners Cast on This Season's", null)); ?> --EXPECTF-- +Uri\Rfc3986Uri::__construct(): Argument #1 ($uri) cannot be empty Uri\Rfc3986Uri::create(): Argument #1 ($uri) cannot be empty +Uri\WhatWgUri::__construct(): Argument #1 ($uri) cannot be empty Uri\WhatWgUri::create(): Argument #1 ($uri) cannot be empty Uri\Rfc3986Uri::create(): Argument #2 ($baseUrl) cannot be empty +Uri\Rfc3986Uri::__construct(): Argument #2 ($baseUrl) cannot be empty +Uri\WhatWgUri::__construct(): Argument #2 ($baseUrl) cannot be empty Uri\WhatWgUri::create(): Argument #2 ($baseUrl) cannot be empty object(Uri\Rfc3986Uri)#%d (%d) { ["scheme"]=> @@ -63,10 +87,11 @@ object(Uri\Rfc3986Uri)#%d (%d) { ["fragment"]=> NULL } -NULL array(%d) { [0]=> object(Uri\WhatWgError)#%d (%d) { + ["uri"]=> + string(20) "192.168/contact.html" ["position"]=> string(20) "192.168/contact.html" ["errorCode"]=> @@ -74,10 +99,11 @@ array(%d) { } } NULL -NULL array(%d) { [0]=> object(Uri\WhatWgError)#%d (%d) { + ["uri"]=> + string(67) "http://RuPaul's Drag Race All Stars 7 Winners Cast on This Season's" ["position"]=> string(52) " drag race all stars 7 winners cast on this season's" ["errorCode"]=> diff --git a/ext/uri/tests/007.phpt b/ext/uri/tests/007.phpt index a794e60bdb8bc..e8c1e58d9bbb6 100644 --- a/ext/uri/tests/007.phpt +++ b/ext/uri/tests/007.phpt @@ -1,5 +1,5 @@ --TEST-- -Test manual Uri child instance creation error cases +Test URI creation errors --EXTENSIONS-- uri --FILE-- @@ -7,17 +7,41 @@ uri try { new Uri\Rfc3986Uri("https://example.com:8080@username:password/path?q=r#fragment"); -} catch (Error $e) { +} catch (Uri\InvalidUriException $e) { echo $e->getMessage() . "\n"; + var_dump($e->errors); } try { new Uri\WhatWgUri("https://example.com:8080@username:password/path?q=r#fragment"); -} catch (Error $e) { +} catch (Uri\InvalidUriException $e) { echo $e->getMessage() . "\n"; + var_dump($e->errors); } ?> ---EXPECT-- -Uri\Rfc3986Uri::__construct(): Argument #1 ($uri) must be a valid URI -Uri\WhatWgUri::__construct(): Argument #1 ($uri) must be a valid URI +--EXPECTF-- +URI parsing failed +array(%d) { +} +URI parsing failed +array(%d) { + [0]=> + object(Uri\WhatWgError)#%d (%d) { + ["uri"]=> + string(60) "https://example.com:8080@username:password/path?q=r#fragment" + ["position"]=> + string(26) "password/path?q=r#fragment" + ["errorCode"]=> + int(26) + } + [1]=> + object(Uri\WhatWgError)#%d (%d) { + ["uri"]=> + string(60) "https://example.com:8080@username:password/path?q=r#fragment" + ["position"]=> + string(36) "@username:password/path?q=r#fragment" + ["errorCode"]=> + int(23) + } +} diff --git a/ext/uri/tests/019.phpt b/ext/uri/tests/019.phpt index 29a9a4044d3e8..967714095e28c 100644 --- a/ext/uri/tests/019.phpt +++ b/ext/uri/tests/019.phpt @@ -8,13 +8,22 @@ uri $uri = Uri\Rfc3986Uri::create("🐘"); var_dump($uri); -$errors = []; -$uri = Uri\WhatWgUri::create("🐘", null, $errors); +$uri = Uri\WhatWgUri::create("🐘", null); var_dump($uri); -var_dump($errors[0]->errorCode === \Uri\WhatWgError::ERROR_TYPE_MISSING_SCHEME_NON_RELATIVE_URL); +var_dump($uri[0]->errorCode === \Uri\WhatWgError::ERROR_TYPE_MISSING_SCHEME_NON_RELATIVE_URL); ?> ---EXPECT-- -NULL +--EXPECTF-- NULL +array(1) { + [0]=> + object(Uri\WhatWgError)#%d (%d) { + ["uri"]=> + string(4) "🐘" + ["position"]=> + string(4) "🐘" + ["errorCode"]=> + int(21) + } +} bool(true) diff --git a/ext/uri/tests/031.phpt b/ext/uri/tests/031.phpt index e53c5627fefd4..b8fea9011c395 100644 --- a/ext/uri/tests/031.phpt +++ b/ext/uri/tests/031.phpt @@ -2,6 +2,8 @@ Test serialization --EXTENSIONS-- uri +--XFAIL-- +Unserialization support is missing --FILE-- ---EXPECT-- +--EXPECTF-- string(270) "O:14:"Uri\Rfc3986Uri":8:{s:6:"scheme";s:5:"https";s:4:"user";s:8:"username";s:8:"password";s:8:"password";s:4:"host";s:14:"www.google.com";s:4:"port";i:8080;s:4:"path";s:29:"pathname1/pathname2/pathname3";s:5:"query";s:10:"query=true";s:8:"fragment";s:11:"hash-exists";}" object(Uri\Rfc3986Uri)#%d (%d) { ["scheme"]=> diff --git a/ext/uri/tests/035.phpt b/ext/uri/tests/035.phpt new file mode 100644 index 0000000000000..e0278bdddd62a --- /dev/null +++ b/ext/uri/tests/035.phpt @@ -0,0 +1,39 @@ +--TEST-- +Test URI parsing containing null bytes +--EXTENSIONS-- +uri +--FILE-- +getMessage() . "\n"; +} + +$uri = new Uri\Rfc3986Uri("https://example.com"); +try { + $uri->withHost("exam\0ple.com"); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + new Uri\WhatWgUri("https://exam\0ple.com"); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +$uri = new Uri\WhatWgUri("https://example.com"); +try { + $uri->withHost("exam\0ple.com"); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECT-- +Uri\Rfc3986Uri::__construct(): Argument #1 ($uri) must not contain any null bytes +Uri\Rfc3986Uri::withHost(): Argument #1 ($host) must not contain any null bytes +Uri\WhatWgUri::__construct(): Argument #1 ($uri) must not contain any null bytes +Uri\WhatWgUri::withHost(): Argument #1 ($host) must not contain any null bytes