8000 Add the Uri\Rfc3986\Uri class to ext/uri without wither support by kocsismate · Pull Request #18836 · php/php-src · GitHub
[go: up one dir, main page]

Skip to content

Add the Uri\Rfc3986\Uri class to ext/uri without wither support #18836

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 15 commits into from
Jul 5, 2025
Merged
Prev Previous commit
Next Next commit
uriparser improvements
  • Loading branch information
kocsismate committed Jul 4, 2025
commit 861baefc6b4014297b1b264fc01415dadddacbfc
9 changes: 3 additions & 6 deletions ext/uri/php_uri_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,11 @@ static void uri_write_component_ex(INTERNAL_FUNCTION_PARAMETERS, uri_property_na
ZEND_ASSERT(property_handler != NULL);

zend_object *new_object = uri_clone_obj_handler(Z_OBJ_P(ZEND_THIS));
if (UNEXPECTED(EG(exception) != NULL)) {
zend_object_release(new_object);
RETURN_THROWS();
}
ZEND_ASSERT(new_object != NULL);

uri_internal_t *new_internal_uri = uri_internal_from_obj(new_object);
URI_ASSERT_INITIALIZATION(new_internal_uri);
if (property_handler->write_func == NULL) {
if (UNEXPECTED(property_handler->write_func == NULL)) {
zend_readonly_property_modification_error_ex(ZSTR_VAL(Z_OBJ_P(ZEND_THIS)->ce->name),
ZSTR_VAL(get_known_string_by_property_name(property_name)));
zend_object_release(new_object);
Expand All @@ -106,7 +103,7 @@ static void uri_write_component_ex(INTERNAL_FUNCTION_PARAMETERS, uri_property_na

zval errors;
ZVAL_UNDEF(&errors);
if (property_handler->write_func(new_internal_uri, property_zv, &errors) == FAILURE) {
if (UNEXPECTED(property_handler->write_func(new_internal_uri, property_zv, &errors) == FAILURE)) {
zval_ptr_dtor(&errors);
zend_object_release(new_object);
RETURN_THROWS();
Expand Down
91 changes: 31 additions & 60 deletions ext/uri/php_uriparser.c
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something I'm only noticing now: I think this should rather be called ext/uri/parser_rfc3986.c and php_lexbor.c would be ext/uri/parser_whatwg.c. The php_uriparser.c name is confusing to me, because uriparser is an extremely generic term.

To give another comparison with ext/random, since it is architecturally similar: Each engine has its own engine_enginename.c file, e.g. engine_xoshiro256starstar.c.

Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,21 @@ static inline size_t get_text_range_length(const UriTextRangeA *range)
return range->afterLast - range->first;
}

static UriUriA *uriparser_copy_uri(UriUriA *uriparser_uri) // TODO add to uriparser
static UriUriA *uriparser_copy_uri(UriUriA *uriparser_uri)
{
ZEND_ASSERT(uriparser_uri != NULL);

UriUriA *new_uriparser_uri = emalloc(sizeof(UriUriA));

if (uriCopyUriA(new_uriparser_uri, uriparser_uri) != URI_SUCCESS) {
efree(new_uriparser_uri);
return NULL; /* TODO check for null on call sites */
}
int result = uriCopyUriA(new_uriparser_uri, uriparser_uri);
ZEND_ASSERT(result == URI_SUCCESS && new_uriparser_uri != NULL);

return new_uriparser_uri;
}

static zend_result uriparser_normalize_uri(UriUriA *uriparser_uri)
static void uriparser_normalize_uri(UriUriA *uriparser_uri)
{
if (uriNormalizeSyntaxExA(uriparser_uri, (unsigned int)-1) != URI_SUCCESS) {
return FAILURE;
}

return SUCCESS;
ZEND_ASSERT(uriNormalizeSyntaxExA(uriparser_uri, (unsigned int)-1) == URI_SUCCESS);
}

static UriUriA *uriparser_read_uri(uriparser_uris_t *uriparser_uris, uri_component_read_mode_t read_mode)
Expand All @@ -59,13 +55,7 @@ static UriUriA *uriparser_read_uri(uriparser_uris_t *uriparser_uris, uri_compone
case URI_COMPONENT_READ_NORMALIZED_UNICODE:
if (uriparser_uris->normalized_uri == NULL) {
uriparser_uris->normalized_uri = uriparser_copy_uri(uriparser_uris->uri);
if (uriparser_normalize_uri(uriparser_uris->normalized_uri) == FAILURE) {
uriFreeUriMembersA(uriparser_uris->normalized_uri);
efree(uriparser_uris->normalized_uri);
uriparser_uris->normalized_uri = NULL;

return NULL;
}
uriparser_normalize_uri(uriparser_uris->normalized_uri);
}

return uriparser_uris->normalized_uri;
Expand All @@ -76,9 +66,7 @@ static UriUriA *uriparser_read_uri(uriparser_uris_t *uriparser_uris, uri_compone
static zend_result uriparser_read_scheme(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode);
if (UNEXPECTED(uriparser_uri == NULL)) {
return FAILURE;
}
ZEND_ASSERT(uriparser_uri != NULL);

if (uriparser_uri->scheme.first != NULL && uriparser_uri->scheme.afterLast != NULL) {
zend_string *str = zend_string_init(uriparser_uri->scheme.first, get_text_range_length(&uriparser_uri->scheme), false);
Expand All @@ -93,9 +81,7 @@ static zend_result uriparser_read_scheme(const uri_internal_t *internal_uri, uri
zend_result uriparser_read_userinfo(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode);
if (UNEXPECTED(uriparser_uri == NULL)) {
return FAILURE;
}
ZEND_ASSERT(uriparser_uri != NULL);

if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) {
ZVAL_STRINGL(retval, uriparser_uri->userInfo.first, get_text_range_length(&uriparser_uri->userInfo));
Expand All @@ -109,9 +95,7 @@ zend_result uriparser_read_userinfo(const uri_internal_t *internal_uri, uri_comp
static zend_result uriparser_read_username(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode);
if (UNEXPECTED(uriparser_uri == NULL)) {
return FAILURE;
}
ZEND_ASSERT(uriparser_uri != NULL);

if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) {
size_t length = get_text_range_length(&uriparser_uri->userInfo);
Expand All @@ -134,9 +118,7 @@ static zend_result uriparser_read_username(const uri_internal_t *internal_uri, u
static zend_result uriparser_read_password(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode);
if (UNEXPECTED(uriparser_uri == NULL)) {
return FAILURE;
}
ZEND_ASSERT(uriparser_uri != NULL);

if (uriparser_uri->userInfo.first != NULL && uriparser_uri->userInfo.afterLast != NULL) {
const char *c = memchr(uriparser_uri->userInfo.first, ':', get_text_range_length(&uriparser_uri->userInfo));
Expand All @@ -156,9 +138,7 @@ static zend_result uriparser_read_password(const uri_internal_t *internal_uri, u
static zend_result uriparser_read_host(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode);
if (UNEXPECTED(uriparser_uri == NULL)) {
return FAILURE;
}
ZEND_ASSERT(uriparser_uri != NULL);

if (uriparser_uri->hostText.first != NULL && uriparser_uri->hostText.afterLast != NULL && get_text_range_length(&uriparser_uri->hostText) > 0) {
if (uriparser_uri->hostData.ip6 != NULL) {
Expand Down Expand Up @@ -193,9 +173,7 @@ static int str_to_int(const char *str, int len)
static zend_result uriparser_read_port(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode);
if (UNEXPECTED(uriparser_uri == NULL)) {
return FAILURE;
}
ZEND_ASSERT(uriparser_uri != NULL);

if (uriparser_uri->portText.first != NULL && uriparser_uri->portText.afterLast != NULL) {
ZVAL_LONG(retval, str_to_int(uriparser_uri->portText.first, get_text_range_length(&uriparser_uri->portText)));
Expand All @@ -209,9 +187,7 @@ static zend_result uriparser_read_port(const uri_internal_t *internal_uri, uri_c
static zend_result uriparser_read_path(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode);
if (UNEXPECTED(uriparser_uri == NULL)) {
return FAILURE;
}
ZEND_ASSERT(uriparser_uri != NULL);

if (uriparser_uri->pathHead != NULL) {
const UriPathSegmentA *p;
Expand Down Expand Up @@ -241,9 +217,7 @@ static zend_result uriparser_read_path(const uri_internal_t *internal_uri, uri_c
static zend_result uriparser_read_query(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode);
if (UNEXPECTED(uriparser_uri == NULL)) {
return FAILURE;
}
ZEND_ASSERT(uriparser_uri != NULL);

if (uriparser_uri->query.first != NULL && uriparser_uri->query.afterLast != NULL) {
ZVAL_STRINGL(retval, uriparser_uri->query.first, get_text_range_length(&uriparser_uri->query));
Expand All @@ -257,9 +231,7 @@ static zend_result uriparser_read_query(const uri_internal_t *internal_uri, uri_
static zend_result uriparser_read_fragment(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
UriUriA *uriparser_uri = uriparser_read_uri(internal_uri->uri, read_mode);
if (UNEXPECTED(uriparser_uri == NULL)) {
return FAILURE;
}
ZEND_ASSERT(uriparser_uri != NULL);

if (uriparser_uri->fragment.first != NULL && uriparser_uri->fragment.afterLast != NULL) {
ZVAL_STRINGL(retval, uriparser_uri->fragment.first, get_text_range_length(&uriparser_uri->fragment));
Expand Down Expand Up @@ -373,6 +345,10 @@ void *uriparser_parse_uri(const zend_string *uri_str, const void *base_url, zval
return uriparser_parse_uri_ex(uri_str, base_url, silent);
}

/* TODO make the clone handler accept a flag to distingish between clone() calls and withers.
* When calling a wither successfully, the normalized URI is surely invalidated, therefore
* it doesn't make sense to copy it. In case of failure, an exeption is thrown, and the URI object
* is discarded altogether. */
static void *uriparser_clone_uri(void *uri)
{
uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) uri;
Expand All @@ -386,30 +362,25 @@ static void *uriparser_clone_uri(void *uri)
static zend_string *uriparser_uri_to_string(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment)
{
uriparser_uris_t *uriparser_uris = (uriparser_uris_t *) uri;
UriUriA *uriparser_uri = uriparser_uris->uri;
UriUriA *uriparser_uri;

if ((recomposition_mode == URI_RECOMPOSITION_NORMALIZED_UNICODE || recomposition_mode == URI_RECOMPOSITION_NORMALIZED_ASCII) &&
uriparser_uris->normalized_uri == NULL
) {
uriparser_uris->normalized_uri = uriparser_copy_uri(uriparser_uris->uri);
if (uriparser_normalize_uri(uriparser_uris->normalized_uri) == FAILURE) {
return NULL;
if (recomposition_mode == URI_RECOMPOSITION_RAW_ASCII || recomposition_mode == URI_RECOMPOSITION_RAW_UNICODE) {
uriparser_uri = uriparser_uris->uri;
} else {
if (uriparser_uris->normalized_uri == NULL) {
uriparser_uris->normalized_uri = uriparser_copy_uri(uriparser_uris->uri);
uriparser_normalize_uri(uriparser_uris->normalized_uri);
}
uriparser_uri = uriparser_uris->normalized_uri;
}

int charsRequired;
if (uriToStringCharsRequiredA(uriparser_uri, &charsRequired) != URI_SUCCESS) {
return NULL;
}
int charsRequired = 0;
ZEND_ASSERT(uriToStringCharsRequiredA(uriparser_uri, &charsRequired) == URI_SUCCESS);

charsRequired++;

zend_string *uri_string = zend_string_alloc(charsRequired - 1, false);
if (uriToStringA(ZSTR_VAL(uri_string), uriparser_uri, charsRequired, NULL) != URI_SUCCESS) {
zend_string_efree(uri_string);
return NULL;
}
ZEND_ASSERT(uriToStringA(ZSTR_VAL(uri_string), uriparser_uri, charsRequired, NULL) == URI_SUCCESS);

if (exclude_fragment) {
const char *pos = zend_memrchr(ZSTR_VAL(uri_string), '#', ZSTR_LEN(uri_string));
Expand Down
0