Skip to content

uri: Do not create new UrlValidationErrorType objects #19009

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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.5.0alpha2

- URI:
. Return the singleton UrlValidationErrorType instances from Uri\WhatWg\Url
instead of creating new objects that are different from the singleton.
(timwolla)

03 Jul 2025, PHP 8.5.0alpha1

Expand Down
76 changes: 37 additions & 39 deletions ext/uri/php_lexbor.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ 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 zend_string *fill_errors(zval *errors)
static const char *fill_errors(zval *errors)
{
if (errors == NULL) {
return NULL;
Expand All @@ -87,140 +87,138 @@ static zend_string *fill_errors(zval *errors)
return NULL;
}

zend_string *result = NULL;
const char *result = NULL;
lexbor_plog_entry_t *lxb_error;
while ((lxb_error = lexbor_array_obj_pop(&lexbor_parser.log->list)) != NULL) {
zval error;
object_init_ex(&error, uri_whatwg_url_validation_error_ce);
zend_update_property_string(uri_whatwg_url_validation_error_ce, Z_OBJ(error), ZEND_STRL("context"), (const char *) lxb_error->data);

zend_string *error_str;
const char *error_str;
zval failure;
switch (lxb_error->id) {
case LXB_URL_ERROR_TYPE_DOMAIN_TO_ASCII:
error_str = ZSTR_INIT_LITERAL("DomainToAscii", false);
error_str = "DomainToAscii";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_DOMAIN_TO_UNICODE:
error_str = ZSTR_INIT_LITERAL("DomainToUnicode", false);
error_str = "DomainToUnicode";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_DOMAIN_INVALID_CODE_POINT:
error_str = ZSTR_INIT_LITERAL("DomainInvalidCodePoint", false);
error_str = "DomainInvalidCodePoint";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_HOST_INVALID_CODE_POINT:
error_str = ZSTR_INIT_LITERAL("HostInvalidCodePoint", false);
error_str = "HostInvalidCodePoint";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_EMPTY_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4EmptyPart", false);
error_str = "Ipv4EmptyPart";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_TOO_MANY_PARTS:
error_str = ZSTR_INIT_LITERAL("Ipv4TooManyParts", false);
error_str = "Ipv4TooManyParts";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_NON_NUMERIC_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4NonNumericPart", false);
error_str = "Ipv4NonNumericPart";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_NON_DECIMAL_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4NonDecimalPart", false);
error_str = "Ipv4NonDecimalPart";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_OUT_OF_RANGE_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4OutOfRangePart", false);
error_str = "Ipv4OutOfRangePart";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV6_UNCLOSED:
error_str = ZSTR_INIT_LITERAL("Ipv6Unclosed", false);
error_str = "Ipv6Unclosed";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV6_INVALID_COMPRESSION:
error_str = ZSTR_INIT_LITERAL("Ipv6InvalidCompression", false);
error_str = "Ipv6InvalidCompression";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV6_TOO_MANY_PIECES:
error_str = ZSTR_INIT_LITERAL("Ipv6TooManyPieces", false);
error_str = "Ipv6TooManyPieces";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV6_MULTIPLE_COMPRESSION:
error_str = ZSTR_INIT_LITERAL("Ipv6MultipleCompression", false);
error_str = "Ipv6MultipleCompression";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV6_INVALID_CODE_POINT:
error_str = ZSTR_INIT_LITERAL("Ipv6InvalidCodePoint", false);
error_str = "Ipv6InvalidCodePoint";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV6_TOO_FEW_PIECES:
error_str = ZSTR_INIT_LITERAL("Ipv6TooFewPieces", false);
error_str = "Ipv6TooFewPieces";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_MANY_PIECES:
error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6TooManyPieces", false);
error_str = "Ipv4InIpv6TooManyPieces";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_INVALID_CODE_POINT:
error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6InvalidCodePoint", false);
error_str = "Ipv4InIpv6InvalidCodePoint";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_OUT_OF_RANGE_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6OutOfRangePart", false);
error_str = "Ipv4InIpv6OutOfRangePart";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_FEW_PARTS:
error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6TooFewParts", false);
error_str = "Ipv4InIpv6TooFewParts";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_INVALID_URL_UNIT:
error_str = ZSTR_INIT_LITERAL("InvalidUrlUnit", false);
error_str = "InvalidUrlUnit";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_SPECIAL_SCHEME_MISSING_FOLLOWING_SOLIDUS:
error_str = ZSTR_INIT_LITERAL("SpecialSchemeMissingFollowingSolidus", false);
error_str = "SpecialSchemeMissingFollowingSolidus";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_MISSING_SCHEME_NON_RELATIVE_URL:
error_str = ZSTR_INIT_LITERAL("MissingSchemeNonRelativeUrl", false);
error_str = "MissingSchemeNonRelativeUrl";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_INVALID_REVERSE_SOLIDUS:
error_str = ZSTR_INIT_LITERAL("InvalidReverseSoldius", false);
error_str = "InvalidReverseSoldius";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_INVALID_CREDENTIALS:
error_str = ZSTR_INIT_LITERAL("InvalidCredentials", false);
error_str = "InvalidCredentials";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_HOST_MISSING:
error_str = ZSTR_INIT_LITERAL("HostMissing", false);
error_str = "HostMissing";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_PORT_OUT_OF_RANGE:
error_str = ZSTR_INIT_LITERAL("PortOutOfRange", false);
error_str = "PortOutOfRange";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_PORT_INVALID:
error_str = ZSTR_INIT_LITERAL("PortInvalid", false);
error_str = "PortInvalid";
ZVAL_TRUE(&failure);
break;
case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER:
error_str = ZSTR_INIT_LITERAL("FileInvalidWindowsDriveLetter", false);
error_str = "FileInvalidWindowsDriveLetter";
ZVAL_FALSE(&failure);
break;
case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST:
error_str = ZSTR_INIT_LITERAL("FileInvalidWindowsDriveLetterHost", false);
error_str = "FileInvalidWindowsDriveLetterHost";
ZVAL_FALSE(&failure);
break;
EMPTY_SWITCH_DEFAULT_CASE()
}

zval error_type;
zend_enum_new(&error_type, uri_whatwg_url_validation_error_type_ce, error_str, NULL);
ZVAL_OBJ(&error_type, zend_enum_get_case_cstr(uri_whatwg_url_validation_error_type_ce, error_str));
zend_update_property_ex(uri_whatwg_url_validation_error_ce, Z_OBJ(error), ZSTR_KNOWN(ZEND_STR_TYPE), &error_type);
zend_string_release_ex(error_str, false);
zval_ptr_dtor(&error_type);

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

Expand All @@ -236,14 +234,14 @@ static zend_string *fill_errors(zval *errors)

static void throw_invalid_url_exception_during_write(zval *errors, const char *component)
{
zend_string *reason = fill_errors(errors);
const char *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 ? reason : "",
reason ? ")" : ""
);
zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors);
Expand Down Expand Up @@ -567,10 +565,10 @@ 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));
zend_string *reason = fill_errors(errors);
const char *reason = fill_errors(errors);

if (url == NULL && !silent) {
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_object *exception = zend_throw_exception_ex(uri_whatwg_invalid_url_exception_ce, 0, "The specified URI is malformed%s%s%s", reason ? " (" : "", reason ? reason : "", reason ? ")" : "");
zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors);
}

Expand Down
18 changes: 18 additions & 0 deletions ext/uri/tests/054.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Test UrlValidationErrorType singleton
--EXTENSIONS--
uri
--FILE--
<?php

try {
new \Uri\WhatWg\Url('http://localhost:99999');
} catch (Uri\WhatWg\InvalidUrlException $e) {
echo $e->getMessage() . "\n";
var_dump($e->errors[0]->type === \Uri\WhatWg\UrlValidationErrorType::PortOutOfRange);
}

?>
--EXPECT--
The specified URI is malformed (PortOutOfRange)
bool(true)