Skip to content

Commit

Permalink
Improve error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
kocsismate committed Oct 26, 2024
1 parent f648bd9 commit 13e8566
Show file tree
Hide file tree
Showing 16 changed files with 316 additions and 117 deletions.
2 changes: 1 addition & 1 deletion ext/filter/logical_filters.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion ext/openssl/xp_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
31 changes: 14 additions & 17 deletions ext/uri/php_lexbor.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

Expand All @@ -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;

Expand Down Expand Up @@ -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;

Expand All @@ -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;

Expand All @@ -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;

Expand All @@ -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;

Expand All @@ -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;

Expand Down Expand Up @@ -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)
Expand All @@ -299,15 +296,15 @@ 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;
}

base_url = lexbor_parser->url;
}

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

Expand Down
77 changes: 53 additions & 24 deletions ext/uri/php_uri.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -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)
Expand All @@ -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) {
Expand All @@ -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)
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand Down Expand Up @@ -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();
}

Expand Down
4 changes: 2 additions & 2 deletions ext/uri/php_uri.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);

Expand Down
16 changes: 14 additions & 2 deletions ext/uri/php_uri.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {}
Expand Down
Loading

0 comments on commit 13e8566

Please sign in to comment.