Skip to content

Add Uri\WhatWg classes to ext/uri #18672

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
Jun 10, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Remove the create_invalid_uri_exception URI handler
  • Loading branch information
kocsismate committed Jun 10, 2025
commit fe930af84b698b3aa1a39a9fb2f8c978233498fe
62 changes: 40 additions & 22 deletions ext/uri/php_lexbor.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "php_uri_common.h"
#include "Zend/zend_enum.h"
#include "Zend/zend_smart_str.h"
#include "Zend/zend_exceptions.h"
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
Expand Down Expand Up @@ -225,6 +226,30 @@ static void fill_errors(zval *errors)
}
}

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);
}

static void throw_invalid_url_exception_during_write(zval *errors)
{
fill_errors(errors);
throw_invalid_url_exception(errors);
}

static lxb_status_t lexbor_serialize_callback(const lxb_char_t *data, size_t length, void *ctx)
{
smart_str *uri_str = ctx;
Expand Down Expand Up @@ -255,7 +280,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) {
fill_errors(errors);
throw_invalid_url_exception_during_write(errors);

return FAILURE;
}
Expand Down Expand Up @@ -284,7 +309,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) {
fill_errors(errors);
throw_invalid_url_exception_during_write(errors);

return FAILURE;
}
Expand Down Expand Up @@ -313,7 +338,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) {
fill_errors(errors);
throw_invalid_url_exception_during_write(errors);

return FAILURE;
}
Expand Down Expand Up @@ -385,7 +410,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) {
fill_errors(errors);
throw_invalid_url_exception_during_write(errors);

return FAILURE;
}
Expand Down Expand Up @@ -414,7 +439,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) {
fill_errors(errors);
throw_invalid_url_exception_during_write(errors);

return FAILURE;
}
Expand Down Expand Up @@ -443,7 +468,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) {
fill_errors(errors);
throw_invalid_url_exception_during_write(errors);

return FAILURE;
}
Expand Down Expand Up @@ -472,7 +497,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) {
fill_errors(errors);
throw_invalid_url_exception_during_write(errors);

return FAILURE;
}
Expand Down Expand Up @@ -501,7 +526,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) {
fill_errors(errors);
throw_invalid_url_exception_during_write(errors);

return FAILURE;
}
Expand Down Expand Up @@ -538,29 +563,23 @@ void lexbor_request_shutdown(void)
lexbor_urls = 0;
}

static void *lexbor_parse_uri(const zend_string *uri_str, const void *base_url, zval *errors)
lxb_url_t *lexbor_parse_uri_ex(const zend_string *uri_str, const lxb_url_t *lexbor_base_url, zval *errors, bool silent)
{
lexbor_cleanup_parser();

const lxb_url_t *lexbor_base_url = base_url;
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);

if (url == NULL && !silent) {
throw_invalid_url_exception(errors);
}

return url;
}

static void lexbor_create_invalid_uri_exception(zval *exception_zv, zval *errors)
static void *lexbor_parse_uri(const zend_string *uri_str, const void *base_url, zval *errors, bool silent)
{
ZEND_ASSERT(Z_TYPE_P(errors) == IS_ARRAY && "Lexbor always returns an array of errors when URI parsing fails");

object_init_ex(exception_zv, 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_P(exception_zv), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value);
zval_ptr_dtor_str(&value);

zend_update_property(uri_whatwg_invalid_url_exception_ce, Z_OBJ_P(exception_zv), ZEND_STRL("errors"), errors);
return lexbor_parse_uri_ex(uri_str, base_url, errors, silent);
}

static void *lexbor_clone_uri(void *uri)
Expand Down Expand Up @@ -603,7 +622,6 @@ static void lexbor_free_uri(void *uri)
const uri_handler_t lexbor_uri_handler = {
.name = URI_PARSER_WHATWG,
.parse_uri = lexbor_parse_uri,
.create_invalid_uri_exception = lexbor_create_invalid_uri_exception,
.clone_uri = lexbor_clone_uri,
.uri_to_string = lexbor_uri_to_string,
.free_uri = lexbor_free_uri,
Expand Down
3 changes: 1 addition & 2 deletions ext/uri/php_lexbor.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@

extern const uri_handler_t lexbor_uri_handler;

void lexbor_module_init(void);
void lexbor_module_shutdown(void);
lxb_url_t *lexbor_parse_uri_ex(const zend_string *uri_str, const lxb_url_t *lexbor_base_url, zval *errors, bool silent);

zend_result lexbor_request_init(void);
void lexbor_request_shutdown(void);
Expand Down
6 changes: 2 additions & 4 deletions ext/uri/php_uri.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,9 @@ PHPAPI void php_uri_instantiate_uri(
base_url = internal_base_url->uri;
}

void *uri = handler->parse_uri(uri_str, base_url, should_throw || errors_zv != NULL ? &errors : NULL);
void *uri = handler->parse_uri(uri_str, base_url, should_throw || errors_zv != NULL ? &errors : NULL, !should_throw);
if (UNEXPECTED(uri == NULL)) {
if (should_throw) {
throw_invalid_uri_exception(handler, &errors);
zval_ptr_dtor(&errors);
RETURN_THROWS();
} else {
Expand Down Expand Up @@ -352,7 +351,7 @@ static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS, const char *handler_na
if (internal_uri->uri != NULL) {
internal_uri->handler->free_uri(internal_uri->uri);
}
internal_uri->uri = internal_uri->handler->parse_uri(Z_STR_P(uri_zv), NULL, NULL);
internal_uri->uri = internal_uri->handler->parse_uri(Z_STR_P(uri_zv), NULL, NULL, true);
if (internal_uri->uri == NULL) {
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
RETURN_THROWS();
Expand Down Expand Up @@ -617,7 +616,6 @@ zend_result uri_handler_register(const uri_handler_t *uri_handler)

ZEND_ASSERT(uri_handler->name != NULL);
ZEND_ASSERT(uri_handler->parse_uri != NULL);
ZEND_ASSERT(uri_handler->create_invalid_uri_exception != NULL);
ZEND_ASSERT(uri_handler->clone_uri != NULL);
ZEND_ASSERT(uri_handler->uri_to_string != NULL);
ZEND_ASSERT(uri_handler->free_uri != NULL);
Expand Down
10 changes: 0 additions & 10 deletions ext/uri/php_uri_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,6 @@ static zend_string *get_known_string_by_property_name(uri_property_name_t proper
}
}

void throw_invalid_uri_exception(const uri_handler_t *uri_handler, zval *errors)
{
zval exception_zv;

uri_handler->create_invalid_uri_exception(&exception_zv, errors);

zend_throw_exception_object(&exception_zv);
}

void uri_read_component(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name, uri_component_read_mode_t component_read_mode)
{
ZEND_PARSE_PARAMETERS_NONE();
Expand Down Expand Up @@ -117,7 +108,6 @@ 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) {
throw_invalid_uri_exception(new_internal_uri->handler, &errors);
zval_ptr_dtor(&errors);
zend_object_release(new_object);
RETURN_THROWS();
Expand Down
14 changes: 5 additions & 9 deletions ext/uri/php_uri_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,19 +83,16 @@ typedef struct uri_handler_t {
* returned.
*
* The errors by-ref parameter can contain errors that occurred during parsing.
* If the input value is NULL, or there were no errors, errors should not be changed.
* If the input value is NULL, or there were no errors, the errors parameter should
* not be modified.
*
* If the URI string is valid and the base_url URI is not NULL, the URI object
* is resolved against the base_url.
*/
void *(*parse_uri)(const zend_string *uri_str, const void *base_url, zval *errors);
/**
* Create a Uri\InvalidUriException instance based on the errors parameter.
* The errors parameter is either an array or an UNDEF zval.
*
* The exception object is passed by ref to the exception_zv parameter.
* If the silent parameter is true, a Uri\InvalidUriException instance must be thrown.
* If the parameter is false, the possible errors should be handled by the caller.
*/
void (*create_invalid_uri_exception)(zval *exception_zv, zval *errors);
void *(*parse_uri)(const zend_string *uri_str, const void *base_url, zval *errors, bool silent);
void *(*clone_uri)(void *uri);
zend_string *(*uri_to_string)(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment);
void (*free_uri)(void *uri);
Expand Down Expand Up @@ -129,7 +126,6 @@ static inline uri_internal_t *uri_internal_from_obj(const zend_object *object) {

zend_result uri_handler_register(const uri_handler_t *uri_handler);
const uri_property_handler_t *uri_property_handler_from_internal_uri(const uri_internal_t *internal_uri, uri_property_name_t property_name);
void throw_invalid_uri_exception(const uri_handler_t *uri_handler, zval *errors);
void uri_read_component(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name, uri_component_read_mode_t component_read_mode);
void uri_write_component_str(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name);
void uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name);
Expand Down