Skip to content

uri: Improve exceptions for Uri\WhatWg\Url #18855

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 32 additions & 33 deletions ext/uri/php_lexbor.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,21 @@ static void lexbor_cleanup_parser(void)
* When errors is NULL, the caller is not interested in the additional error information,
* so the function does nothing.
*/
static void fill_errors(zval *errors)
static zend_string *fill_errors(zval *errors)
{
if (errors == NULL) {
return;
return NULL;
}

ZEND_ASSERT(Z_ISUNDEF_P(errors));

array_init(errors);

if (lexbor_parser.log == NULL) {
return;
return NULL;
}

zend_string *result = NULL;
lexbor_plog_entry_t *lxb_error;
while ((lxb_error = lexbor_array_obj_pop(&lexbor_parser.log->list)) != NULL) {
zval error;
Expand Down Expand Up @@ -223,32 +224,29 @@ static void fill_errors(zval *errors)

zend_update_property(uri_whatwg_url_validation_error_ce, Z_OBJ(error), ZEND_STRL("failure"), &failure);

if (Z_TYPE(failure) == IS_TRUE) {
result = error_str;
}

add_next_index_zval(errors, &error);
}
}

static void throw_invalid_url_exception(zval *errors)
{
ZEND_ASSERT(errors != NULL && Z_TYPE_P(errors) == IS_ARRAY);

zval exception;

object_init_ex(&exception, uri_whatwg_invalid_url_exception_ce);

zval value;
ZVAL_STRING(&value, "URL parsing failed");
zend_update_property_ex(uri_whatwg_invalid_url_exception_ce, Z_OBJ(exception), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value);
zval_ptr_dtor_str(&value);

zend_update_property(uri_whatwg_invalid_url_exception_ce, Z_OBJ(exception), ZEND_STRL("errors"), errors);

zend_throw_exception_object(&exception);
return result;
}

static void throw_invalid_url_exception_during_write(zval *errors)
static void throw_invalid_url_exception_during_write(zval *errors, const char *component)
{
fill_errors(errors);
throw_invalid_url_exception(errors);
zend_string *reason = fill_errors(errors);
zend_object *exception = zend_throw_exception_ex(
uri_whatwg_invalid_url_exception_ce,
0,
"The specified %s is malformed%s%s%s",
component,
reason ? " (" : "",
reason ? ZSTR_VAL(reason) : "",
reason ? ")" : ""
);
zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors);
}

static lxb_status_t lexbor_serialize_callback(const lxb_char_t *data, size_t length, void *ctx)
Expand Down Expand Up @@ -281,7 +279,7 @@ static zend_result lexbor_write_scheme(struct uri_internal_t *internal_uri, zval
zval_string_or_null_to_lexbor_str(value, &str);

if (lxb_url_api_protocol_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors);
throw_invalid_url_exception_during_write(errors, "scheme");

return FAILURE;
}
Expand Down Expand Up @@ -310,7 +308,7 @@ static zend_result lexbor_write_username(uri_internal_t *internal_uri, zval *val
zval_string_or_null_to_lexbor_str(value, &str);

if (lxb_url_api_username_set(lexbor_uri, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors);
throw_invalid_url_exception_during_write(errors, "username");

return FAILURE;
}
Expand Down Expand Up @@ -339,7 +337,7 @@ static zend_result lexbor_write_password(struct uri_internal_t *internal_uri, zv
zval_string_or_null_to_lexbor_str(value, &str);

if (lxb_url_api_password_set(lexbor_uri, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors);
throw_invalid_url_exception_during_write(errors, "password");

return FAILURE;
}
Expand Down Expand Up @@ -411,7 +409,7 @@ static zend_result lexbor_write_host(struct uri_internal_t *internal_uri, zval *
zval_string_or_null_to_lexbor_str(value, &str);

if (lxb_url_api_hostname_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors);
throw_invalid_url_exception_during_write(errors, "host");

return FAILURE;
}
Expand Down Expand Up @@ -440,7 +438,7 @@ static zend_result lexbor_write_port(struct uri_internal_t *internal_uri, zval *
zval_long_or_null_to_lexbor_str(value, &str);

if (lxb_url_api_port_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors);
throw_invalid_url_exception_during_write(errors, "port");

return FAILURE;
}
Expand Down Expand Up @@ -469,7 +467,7 @@ static zend_result lexbor_write_path(struct uri_internal_t *internal_uri, zval *
zval_string_or_null_to_lexbor_str(value, &str);

if (lxb_url_api_pathname_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors);
throw_invalid_url_exception_during_write(errors, "path");

return FAILURE;
}
Expand Down Expand Up @@ -498,7 +496,7 @@ static zend_result lexbor_write_query(struct uri_internal_t *internal_uri, zval
zval_string_or_null_to_lexbor_str(value, &str);

if (lxb_url_api_search_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors);
throw_invalid_url_exception_during_write(errors, "query string");

return FAILURE;
}
Expand Down Expand Up @@ -527,7 +525,7 @@ static zend_result lexbor_write_fragment(struct uri_internal_t *internal_uri, zv
zval_string_or_null_to_lexbor_str(value, &str);

if (lxb_url_api_hash_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors);
throw_invalid_url_exception_during_write(errors, "fragment");

return FAILURE;
}
Expand Down Expand Up @@ -569,10 +567,11 @@ lxb_url_t *lexbor_parse_uri_ex(const zend_string *uri_str, const lxb_url_t *lexb
lexbor_cleanup_parser();

lxb_url_t *url = lxb_url_parse(&lexbor_parser, lexbor_base_url, (unsigned char *) ZSTR_VAL(uri_str), ZSTR_LEN(uri_str));
fill_errors(errors);
zend_string *reason = fill_errors(errors);

if (url == NULL && !silent) {
throw_invalid_url_exception(errors);
zend_object *exception = zend_throw_exception_ex(uri_whatwg_invalid_url_exception_ce, 0, "The specified URI is malformed%s%s%s", reason ? " (" : "", reason ? ZSTR_VAL(reason) : "", reason ? ")" : "");
zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors);
}

return url;
Expand Down
4 changes: 2 additions & 2 deletions ext/uri/tests/004.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ var_dump(Uri\WhatWg\Url::parse("192.168/contact.html", null));
var_dump(Uri\WhatWg\Url::parse("http://RuPaul's Drag Race All Stars 7 Winners Cast on This Season's", null));

?>
--EXPECTF--
URL parsing failed
--EXPECT--
The specified URI is malformed (MissingSchemeNonRelativeUrl)
NULL
NULL
NULL
2 changes: 1 addition & 1 deletion ext/uri/tests/007.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var_dump($failures);

?>
--EXPECTF--
URL parsing failed
The specified URI is malformed (PortInvalid)
array(%d) {
[0]=>
object(Uri\WhatWg\UrlValidationError)#%d (%d) {
Expand Down
4 changes: 2 additions & 2 deletions ext/uri/tests/023.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ try {
--EXPECT--
string(5) "https"
string(4) "http"
URL parsing failed
URL parsing failed
The specified scheme is malformed
The specified scheme is malformed
4 changes: 2 additions & 2 deletions ext/uri/tests/026.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ string(8) "test.com"
string(8) "test.com"
string(8) "test.com"
NULL
URL parsing failed
The specified host is malformed (DomainInvalidCodePoint)
object(Uri\WhatWg\Url)#%d (%d) {
["scheme"]=>
string(5) "https"
Expand All @@ -62,6 +62,6 @@ object(Uri\WhatWg\Url)#%d (%d) {
["fragment"]=>
NULL
}
URL parsing failed
The specified host is malformed (HostMissing)
string(7) "foo.com"
string(8) "test.com"
2 changes: 1 addition & 1 deletion ext/uri/tests/051.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var_dump($softErrors);

?>
--EXPECTF--
URL parsing failed
The specified URI is malformed (Ipv4TooManyParts)
string(23) "https://example.com/foo"
array(%d) {
[0]=>
Expand Down