Skip to content

Commit 13e8566

Browse files
committed
Improve error handling
1 parent f648bd9 commit 13e8566

File tree

16 files changed

+316
-117
lines changed

16 files changed

+316
-117
lines changed

ext/filter/logical_filters.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
613613
}
614614

615615
/* Use parse_url - if it returns false, we return NULL */
616-
uri_internal_t *internal_uri = php_uri_parse(uri_handler, Z_STR_P(value));
616+
uri_internal_t *internal_uri = php_uri_parse(uri_handler, Z_STR_P(value), NULL);
617617
if (internal_uri == NULL) {
618618
RETURN_VALIDATION_FAILED
619619
}

ext/openssl/xp_ssl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2736,7 +2736,7 @@ static char *php_openssl_get_url_name(const char *resourcename,
27362736
uri_handler_t *uri_handler = php_uri_get_handler(NULL);
27372737

27382738
zend_string *resource = zend_string_init(resourcename, resourcenamelen, false);
2739-
uri_internal_t *internal_uri = php_uri_parse(uri_handler, resource);
2739+
uri_internal_t *internal_uri = php_uri_parse(uri_handler, resource, NULL);
27402740
if (internal_uri == NULL) {
27412741
zend_string_release(resource);
27422742
return NULL;

ext/uri/php_lexbor.c

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ static zend_result lexbor_read_scheme(const uri_internal_t *internal_uri, zval *
7070
return SUCCESS;
7171
}
7272

73-
static zend_result lexbor_write_scheme(uri_internal_t *internal_uri, zval *value)
73+
static zend_result lexbor_write_scheme(uri_internal_t *internal_uri, zval *value, zval *errors)
7474
{
7575
//lxb_url_t *lexbor_uri = (lxb_url_t *) uri_object_internal;
7676

@@ -90,7 +90,7 @@ static zend_result lexbor_read_user(const uri_internal_t *internal_uri, zval *re
9090
return SUCCESS;
9191
}
9292

93-
static zend_result lexbor_write_user(uri_internal_t *internal_uri, zval *value)
93+
static zend_result lexbor_write_user(uri_internal_t *internal_uri, zval *value, zval *errors)
9494
{
9595
//lxb_url_t *lexbor_uri = (lxb_url_t *) internal_uri->uri;
9696

@@ -110,7 +110,7 @@ static zend_result lexbor_read_password(const uri_internal_t *internal_uri, zval
110110
return SUCCESS;
111111
}
112112

113-
static zend_result lexbor_write_password(uri_internal_t *internal_uri, zval *value)
113+
static zend_result lexbor_write_password(uri_internal_t *internal_uri, zval *value, zval *errors)
114114
{
115115
//lxb_url_t *lexbor_uri = (lxb_url_t *) internal_uri->uri;
116116

@@ -146,7 +146,7 @@ static zend_result lexbor_read_host(const uri_internal_t *internal_uri, zval *re
146146
return SUCCESS;
147147
}
148148

149-
static zend_result lexbor_write_host(uri_internal_t *internal_uri, zval *value)
149+
static zend_result lexbor_write_host(uri_internal_t *internal_uri, zval *value, zval *errors)
150150
{
151151
//lxb_url_t *lexbor_uri = (lxb_url_t *) internal_uri->uri;
152152

@@ -166,7 +166,7 @@ static zend_result lexbor_read_port(const uri_internal_t *internal_uri, zval *re
166166
return SUCCESS;
167167
}
168168

169-
static zend_result lexbor_write_port(uri_internal_t *internal_uri, zval *value)
169+
static zend_result lexbor_write_port(uri_internal_t *internal_uri, zval *value, zval *errors)
170170
{
171171
//lxb_url_t *lexbor_uri = (lxb_url_t *) internal_uri->uri;
172172

@@ -188,7 +188,7 @@ static zend_result lexbor_read_path(const uri_internal_t *internal_uri, zval *re
188188
return SUCCESS;
189189
}
190190

191-
static zend_result lexbor_write_path(uri_internal_t *internal_uri, zval *value)
191+
static zend_result lexbor_write_path(uri_internal_t *internal_uri, zval *value, zval *errors)
192192
{
193193
//lxb_url_t *lexbor_uri = (lxb_url_t *) uri_object_internal;
194194

@@ -208,7 +208,7 @@ static zend_result lexbor_read_query(const uri_internal_t *internal_uri, zval *r
208208
return SUCCESS;
209209
}
210210

211-
static zend_result lexbor_write_query(uri_internal_t *internal_uri, zval *value)
211+
static zend_result lexbor_write_query(uri_internal_t *internal_uri, zval *value, zval *errors)
212212
{
213213
//lxb_url_t *lexbor_uri = (lxb_url_t *) internal_uri->uri;
214214

@@ -228,7 +228,7 @@ static zend_result lexbor_read_fragment(const uri_internal_t *internal_uri, zval
228228
return SUCCESS;
229229
}
230230

231-
static zend_result lexbor_write_fragment(uri_internal_t *internal_uri, zval *value)
231+
static zend_result lexbor_write_fragment(uri_internal_t *internal_uri, zval *value, zval *errors)
232232
{
233233
//lxb_url_t *lexbor_uri = (lxb_url_t *) internal_uri->uri;
234234

@@ -268,27 +268,24 @@ static zend_result lexbor_init_parser(void)
268268
return SUCCESS;
269269
}
270270

271-
void fill_errors(zval *errors)
271+
void fill_errors(zval *errors, const zend_string *uri)
272272
{
273273
if (!errors || lexbor_parser->log == NULL) {
274274
return;
275275
}
276276

277-
zval errors_tmp;
278-
array_init(&errors_tmp);
277+
array_init(errors);
279278

280279
lexbor_plog_entry_t *lxb_error;
281280
while ((lxb_error = lexbor_array_obj_pop(&lexbor_parser->log->list)) != NULL) {
282281
zval error;
283282
object_init_ex(&error, whatwg_error_ce);
283+
zend_update_property_string(whatwg_error_ce, Z_OBJ(error), "uri", sizeof("uri") - 1, ZSTR_VAL(uri));
284284
zend_update_property_string(whatwg_error_ce, Z_OBJ(error), "position", sizeof("position") - 1, (const char *) lxb_error->data);
285285
zend_update_property_long(whatwg_error_ce, Z_OBJ(error), "errorCode", sizeof("errorCode") - 1, lxb_error->id);
286286

287-
add_next_index_zval(&errors_tmp, &error);
287+
add_next_index_zval(errors, &error);
288288
}
289-
290-
ZEND_TRY_ASSIGN_REF_COPY(errors, &errors_tmp);
291-
zval_ptr_dtor(&errors_tmp);
292289
}
293290

294291
static void *lexbor_parse_uri(const zend_string *url_str, const zend_string *base_url_str, zval *errors)
@@ -299,15 +296,15 @@ static void *lexbor_parse_uri(const zend_string *url_str, const zend_string *bas
299296

300297
if (base_url_str) {
301298
if ((base_url = lxb_url_parse(lexbor_parser, NULL, (unsigned char *) ZSTR_VAL(base_url_str), ZSTR_LEN(base_url_str))) == NULL) {
302-
fill_errors(errors);
299+
fill_errors(errors, base_url_str);
303300
return NULL;
304301
}
305302

306303
base_url = lexbor_parser->url;
307304
}
308305

309306
if ((url = lxb_url_parse(lexbor_parser, base_url, (unsigned char *) ZSTR_VAL(url_str), ZSTR_LEN(url_str))) == NULL) {
310-
fill_errors(errors);
307+
fill_errors(errors, url_str);
311308
return NULL;
312309
}
313310

ext/uri/php_uri.c

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "php.h"
2222
#include "Zend/zend_interfaces.h"
23+
#include "Zend/zend_exceptions.h"
2324
#include "main/php_ini.h"
2425

2526
#include "php_uri.h"
@@ -33,6 +34,8 @@ zend_class_entry *rfc3986_uri_ce;
3334
zend_object_handlers rfc3986_uri_object_handlers;
3435
zend_class_entry *whatwg_uri_ce;
3536
zend_object_handlers whatwg_uri_object_handlers;
37+
zend_class_entry *uri_exception_ce;
38+
zend_class_entry *invalid_uri_exception_ce;
3639
zend_class_entry *whatwg_error_ce;
3740

3841
static zend_array uri_handlers;
@@ -98,7 +101,7 @@ PHPAPI uri_handler_t *php_uri_get_handler(const zend_string *uri_handler_name)
98101
return uri_handler_by_name(ZSTR_VAL(uri_handler_name), ZSTR_LEN(uri_handler_name));
99102
}
100103

101-
PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, zend_string *uri_str)
104+
PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, zend_string *uri_str, zval *errors)
102105
{
103106
ZEND_ASSERT(uri_handler != NULL);
104107

@@ -108,7 +111,7 @@ PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, zend_stri
108111

109112
uri_internal_t *internal_uri = emalloc(sizeof(uri_internal_t));
110113
internal_uri->handler = uri_handler;
111-
internal_uri->uri = uri_handler->parse_uri(uri_str, NULL, NULL);
114+
internal_uri->uri = uri_handler->parse_uri(uri_str, NULL, errors);
112115

113116
if (UNEXPECTED(internal_uri->uri == NULL)) {
114117
efree(internal_uri);
@@ -178,32 +181,46 @@ PHPAPI void php_uri_free(uri_internal_t *internal_uri)
178181

179182
PHP_METHOD(Uri_WhatWgError, __construct)
180183
{
181-
zend_string *position;
184+
zend_string *uri, *position;
182185
zend_long error;
183186

184-
ZEND_PARSE_PARAMETERS_START(2, 2)
187+
ZEND_PARSE_PARAMETERS_START(3, 3)
188+
Z_PARAM_STR(uri)
185189
Z_PARAM_STR(position)
186190
Z_PARAM_LONG(error)
187191
ZEND_PARSE_PARAMETERS_END();
188192

193+
zend_update_property_str(whatwg_error_ce, Z_OBJ_P(ZEND_THIS), "uri", sizeof("uri") - 1, uri);
189194
zend_update_property_str(whatwg_error_ce, Z_OBJ_P(ZEND_THIS), "position", sizeof("position") - 1, position);
190195
zend_update_property_long(whatwg_error_ce, Z_OBJ_P(ZEND_THIS), "error", sizeof("error") - 1, error);
191196
}
192197

193198
PHPAPI void php_uri_instantiate_uri(
194199
INTERNAL_FUNCTION_PARAMETERS, const uri_handler_t *handler, const zend_string *uri_str, const zend_string *base_url_str,
195-
zval *errors, bool is_constructor
200+
bool is_constructor, bool return_errors
196201
) {
197-
void *uri = handler->parse_uri(uri_str, base_url_str, errors);
202+
zval errors;
203+
ZVAL_UNDEF(&errors);
204+
205+
void *uri = handler->parse_uri(uri_str, base_url_str, &errors);
198206
if (UNEXPECTED(uri == NULL)) {
199207
if (is_constructor) {
200-
zend_argument_value_error(1, "must be a valid URI");
208+
throw_invalid_uri_exception(&errors);
209+
zval_ptr_dtor(&errors);
201210
RETURN_THROWS();
202211
} else {
212+
if (return_errors && Z_TYPE(errors) == IS_ARRAY) {
213+
RETURN_ZVAL(&errors, false, false);
214+
}
215+
216+
zval_ptr_dtor(&errors);
217+
203218
RETURN_NULL();
204219
}
205220
}
206221

222+
ZEND_ASSERT(Z_TYPE(errors) == IS_UNDEF);
223+
207224
if (!is_constructor) {
208225
object_init_ex(return_value, handler->get_uri_ce());
209226
}
@@ -233,7 +250,7 @@ static void create_rfc3986_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor
233250
RETURN_THROWS();
234251
}
235252

236-
php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &uriparser_uri_handler, uri_str, base_url_str, NULL, is_constructor);
253+
php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &uriparser_uri_handler, uri_str, base_url_str, is_constructor, false);
237254
}
238255

239256
PHP_METHOD(Uri_Rfc3986Uri, create)
@@ -249,13 +266,11 @@ PHP_METHOD(Uri_Rfc3986Uri, __construct)
249266
static void create_whatwg_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor)
250267
{
251268
zend_string *uri_str, *base_url_str = NULL;
252-
zval *errors = NULL;
253269

254-
ZEND_PARSE_PARAMETERS_START(1, 3)
270+
ZEND_PARSE_PARAMETERS_START(1, 2)
255271
Z_PARAM_PATH_STR(uri_str)
256272
Z_PARAM_OPTIONAL
257273
Z_PARAM_PATH_STR_OR_NULL(base_url_str)
258-
Z_PARAM_ZVAL(errors)
259274
ZEND_PARSE_PARAMETERS_END();
260275

261276
if (ZSTR_LEN(uri_str) == 0) {
@@ -268,7 +283,7 @@ static void create_whatwg_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor)
268283
RETURN_THROWS();
269284
}
270285

271-
php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &lexbor_uri_handler, uri_str, base_url_str, errors, is_constructor);
286+
php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, &lexbor_uri_handler, uri_str, base_url_str, is_constructor, true);
272287
}
273288

274289
PHP_METHOD(Uri_WhatWgUri, create)
@@ -412,15 +427,21 @@ PHP_METHOD(Uri_Rfc3986Uri, __unserialize)
412427
zend_object *object = Z_OBJ_P(ZEND_THIS);
413428
uri_internal_t *internal_uri = uri_internal_from_obj(object);
414429

415-
/*if (!php_date_initialize_from_hash(&dateobj, myht)) {
416-
zend_throw_error(NULL, "Invalid serialization data for DateTime object");
417-
RETURN_THROWS();
418-
}*/
419-
420430
zend_string *str = zend_string_init("https://example.com", sizeof("https://example.com") - 1, false);
421431

432+
zval errors;
433+
ZVAL_UNDEF(&errors);
434+
422435
internal_uri->handler = uri_handler_by_name("rfc3986", sizeof("rfc3986") - 1);
423-
internal_uri->uri = internal_uri->handler->parse_uri(str, NULL, NULL);
436+
internal_uri->uri = internal_uri->handler->parse_uri(str, NULL, &errors);
437+
if (internal_uri->uri == NULL) {
438+
throw_invalid_uri_exception(&errors);
439+
zval_ptr_dtor(&errors);
440+
zend_string_release(str);
441+
RETURN_THROWS();
442+
}
443+
ZEND_ASSERT(Z_TYPE(errors) == IS_UNDEF);
444+
//zend_string_release(str); TODO Fix memory leak
424445

425446
uri_restore_custom_properties(object, internal_uri, ht);
426447
}
@@ -436,15 +457,21 @@ PHP_METHOD(Uri_WhatWgUri, __unserialize)
436457
zend_object *object = Z_OBJ_P(ZEND_THIS);
437458
uri_internal_t *internal_uri = uri_internal_from_obj(object);
438459

439-
/*if (!php_date_initialize_from_hash(&dateobj, myht)) {
440-
zend_throw_error(NULL, "Invalid serialization data for DateTime object");
441-
RETURN_THROWS();
442-
}*/
443-
444460
zend_string *str = zend_string_init("https://example.com", sizeof("https://example.com") - 1, false);
445461

462+
zval errors;
463+
ZVAL_UNDEF(&errors);
464+
446465
internal_uri->handler = uri_handler_by_name("whatwg", sizeof("whatwg") - 1);
447-
internal_uri->uri = internal_uri->handler->parse_uri(str, NULL, NULL);
466+
internal_uri->uri = internal_uri->handler->parse_uri(str, NULL, &errors);
467+
if (internal_uri->uri == NULL) {
468+
throw_invalid_uri_exception(&errors);
469+
zval_ptr_dtor(&errors);
470+
zend_string_release(str);
471+
RETURN_THROWS();
472+
}
473+
ZEND_ASSERT(Z_TYPE(errors) == IS_UNDEF);
474+
//zend_string_release(str); TODO Fix memory leak
448475

449476
uri_restore_custom_properties(object, internal_uri, ht);
450477
}
@@ -663,6 +690,8 @@ void uri_register_symbols(void)
663690
whatwg_uri_ce = register_class_Uri_WhatWgUri(uri_interface_ce);
664691
php_uri_implementation_set_object_handlers(whatwg_uri_ce, &whatwg_uri_object_handlers);
665692

693+
uri_exception_ce = register_class_Uri_UriException(zend_ce_exception);
694+
invalid_uri_exception_ce = register_class_Uri_InvalidUriException(uri_exception_ce);
666695
whatwg_error_ce = register_class_Uri_WhatWgError();
667696
}
668697

ext/uri/php_uri.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ ZEND_TSRMLS_CACHE_EXTERN()
2727
#endif
2828

2929
PHPAPI uri_handler_t *php_uri_get_handler(const zend_string *uri_handler_name);
30-
PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, zend_string *uri_str);
30+
PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, zend_string *uri_str, zval *errors);
3131
PHPAPI zend_result php_uri_get_scheme(const uri_internal_t *internal_uri, zval *zv);
3232
PHPAPI zend_result php_uri_get_user(const uri_internal_t *internal_uri, zval *zv);
3333
PHPAPI zend_result php_uri_get_password(const uri_internal_t *internal_uri, zval *zv);
@@ -40,7 +40,7 @@ PHPAPI void php_uri_free(uri_internal_t *internal_uri);
4040

4141
PHPAPI void php_uri_instantiate_uri(
4242
INTERNAL_FUNCTION_PARAMETERS, const uri_handler_t *handler, const zend_string *uri_str, const zend_string *base_url_str,
43-
zval *errors, bool is_constructor
43+
bool is_constructor, bool return_errors
4444
);
4545
PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers);
4646

ext/uri/php_uri.stub.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@
44

55
namespace Uri;
66

7+
/** @strict-properties */
8+
abstract class UriException extends \Exception
9+
{
10+
}
11+
12+
/** @strict-properties */
13+
class InvalidUriException extends \Uri\UriException
14+
{
15+
public readonly array $errors;
16+
}
17+
718
/** @strict-properties */
819
final readonly class WhatWgError
920
{
@@ -66,10 +77,11 @@
6677
/** @cvalue LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST */
6778
public const int ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST = UNKNOWN;
6879

80+
public string $uri;
6981
public string $position;
7082
public int $errorCode;
7183

72-
public function __construct(string $position, int $errorCode) {}
84+
public function __construct(string $uri, string $position, int $errorCode) {}
7385
}
7486

7587
interface UriInterface extends \Stringable
@@ -193,7 +205,7 @@ public function __unserialize(array $data): void;
193205
private ?string $fragment;
194206

195207
/** @param array $errors */
196-
public static function create(string $uri, ?string $baseUrl = null, &$errors = null): ?static {}
208+
public static function create(string $uri, ?string $baseUrl = null, &$errors = null): static|array {}
197209

198210
/** @param array $errors */
199211
public function __construct(string $uri, ?string $baseUrl = null, &$errors = null) {}

0 commit comments

Comments
 (0)