Skip to content

Commit 05416f2

Browse files
committed
Review fixes and serialization update according to the RFC
1 parent dbcf895 commit 05416f2

File tree

8 files changed

+177
-90
lines changed

8 files changed

+177
-90
lines changed

build/gen_stub.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3054,6 +3054,9 @@ class PropertyInfo extends VariableLike
30543054
private const PHP_85_KNOWN = [
30553055
"self" => "ZEND_STR_SELF",
30563056
"parent" => "ZEND_STR_PARENT",
3057+
"userinfo" => "ZEND_STR_USERINFO",
3058+
"username" => "ZEND_STR_USERNAME",
3059+
"password" => "ZEND_STR_PASSWORD",
30573060
];
30583061

30593062
/**

ext/standard/url.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -924,9 +924,5 @@ PHP_FUNCTION(get_headers)
924924

925925
PHP_MINIT_FUNCTION(url)
926926
{
927-
if (uri_handler_register(&parse_url_uri_handler) == FAILURE) {
928-
return FAILURE;
929-
}
930-
931-
return SUCCESS;
927+
return uri_handler_register(&parse_url_uri_handler);
932928
}

ext/uri/CREDITS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
uri
2+
Máté Kocsis, Tim Düsterhus, Ignace Nyamagana Butera, Arnaud Le Blanc, Nicolas Grekas

ext/uri/php_lexbor.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ const uri_handler_t lexbor_uri_handler = {
5252
if (Z_TYPE_P(value) == IS_STRING && Z_STRLEN_P(value) > 0) { \
5353
lexbor_str_init_append(&str, lexbor_parser->mraw, (const lxb_char_t *) Z_STRVAL_P(value), Z_STRLEN_P(value)); \
5454
} else if (Z_TYPE_P(value) == IS_LONG && Z_LVAL_P(value) != 0) { \
55-
ZVAL_STR(value, zend_long_to_str(Z_LVAL_P(value))); \
56-
lexbor_str_init_append(&str, lexbor_parser->mraw, (const lxb_char_t *) Z_STRVAL_P(value), Z_STRLEN_P(value)); \
55+
ZVAL_STR(value, zend_long_to_str(Z_LVAL_P(value))); \
56+
lexbor_str_init_append(&str, lexbor_parser->mraw, (const lxb_char_t *) Z_STRVAL_P(value), Z_STRLEN_P(value)); \
5757
} else { \
5858
lexbor_str_init(&str, lexbor_parser->mraw, 0); \
5959
} \
@@ -73,7 +73,7 @@ const uri_handler_t lexbor_uri_handler = {
7373
case URI_COMPONENT_READ_NORMALIZED_UNICODE: /* Intentional fallthrough */ \
7474
case URI_COMPONENT_READ_NORMALIZED_ASCII: { \
7575
ZVAL_STRINGL(retval, (const char *) start, len); \
76-
break; \
76+
break; \
7777
} \
7878
EMPTY_SWITCH_DEFAULT_CASE() \
7979
} \
@@ -415,9 +415,7 @@ static zend_result lexbor_read_path(const uri_internal_t *internal_uri, uri_comp
415415
{
416416
lxb_url_t *lexbor_uri = (lxb_url_t *) internal_uri->uri;
417417

418-
if (lexbor_uri->path.opaque) {
419-
LEXBOR_READ_ASCII_URI_COMPONENT(lexbor_uri->path.str.data, lexbor_uri->path.str.length, read_mode, retval);
420-
} else if (lexbor_uri->path.str.length) {
418+
if (lexbor_uri->path.str.length) {
421419
LEXBOR_READ_ASCII_URI_COMPONENT(lexbor_uri->path.str.data, lexbor_uri->path.str.length, read_mode, retval);
422420
} else {
423421
ZVAL_EMPTY_STRING(retval);

ext/uri/php_uri.c

Lines changed: 57 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ PHPAPI void php_uri_instantiate_uri(
364364
void *base_url = NULL;
365365
if (base_url_object != NULL) {
366366
uri_internal_t *internal_base_url = uri_internal_from_obj(base_url_object);
367-
URI_CHECK_INITIALIZATION(internal_base_url);
367+
URI_ASSERT_INITIALIZATION(internal_base_url);
368368
base_url = internal_base_url->uri;
369369
}
370370

@@ -522,7 +522,7 @@ PHP_METHOD(Uri_Rfc3986_Uri, getPort)
522522

523523
PHP_METHOD(Uri_Rfc3986_Uri, withPort)
524524
{
525-
URI_WITHER_LONG(ZSTR_KNOWN(ZEND_STR_PORT));
525+
URI_WITHER_LONG_OR_NULL(ZSTR_KNOWN(ZEND_STR_PORT));
526526
}
527527

528528
PHP_METHOD(Uri_Rfc3986_Uri, getPath)
@@ -574,10 +574,10 @@ static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, zend_object *that_object, z
574574
{
575575
zend_object *this_object = Z_OBJ_P(ZEND_THIS);
576576
uri_internal_t *this_internal_uri = uri_internal_from_obj(this_object);
577-
URI_CHECK_INITIALIZATION(this_internal_uri);
577+
URI_ASSERT_INITIALIZATION(this_internal_uri);
578578

579579
uri_internal_t *that_internal_uri = uri_internal_from_obj(that_object);
580-
URI_CHECK_INITIALIZATION(that_internal_uri);
580+
URI_ASSERT_INITIALIZATION(that_internal_uri);
581581

582582
if (this_object->ce != that_object->ce &&
583583
!instanceof_function(this_object->ce, that_object->ce) &&
@@ -595,15 +595,16 @@ static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, zend_object *that_object, z
595595
}
596596

597597
zend_string *this_str = this_internal_uri->handler->uri_to_string(
598-
this_internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, exclude_fragment);
598+
this_internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, exclude_fragment);
599599
if (this_str == NULL) {
600600
zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(this_object->ce->name));
601601
RETURN_THROWS();
602602
}
603603

604604
zend_string *that_str = that_internal_uri->handler->uri_to_string(
605-
that_internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, exclude_fragment);
605+
that_internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, exclude_fragment);
606606
if (that_str == NULL) {
607+
zend_string_release(this_str);
607608
zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(that_object->ce->name));
608609
RETURN_THROWS();
609610
}
@@ -634,7 +635,7 @@ PHP_METHOD(Uri_Rfc3986_Uri, toRawString)
634635

635636
zend_object *this_object = Z_OBJ_P(ZEND_THIS);
636637
uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
637-
URI_CHECK_INITIALIZATION(internal_uri);
638+
URI_ASSERT_INITIALIZATION(internal_uri);
638639

639640
zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false);
640641
if (uri_str == NULL) {
@@ -651,7 +652,7 @@ PHP_METHOD(Uri_Rfc3986_Uri, toString)
651652

652653
zend_object *this_object = Z_OBJ_P(ZEND_THIS);
653654
uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
654-
URI_CHECK_INITIALIZATION(internal_uri);
655+
URI_ASSERT_INITIALIZATION(internal_uri);
655656

656657
zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_NORMALIZED_ASCII, false);
657658
if (uri_str == NULL) {
@@ -672,7 +673,7 @@ PHP_METHOD(Uri_Rfc3986_Uri, resolve)
672673

673674
zend_object *this_object = Z_OBJ_P(ZEND_THIS);
674675
uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
675-
URI_CHECK_INITIALIZATION(internal_uri);
676+
URI_ASSERT_INITIALIZATION(internal_uri);
676677

677678
php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, internal_uri->handler, uri_str, this_object, true, false, NULL);
678679
}
@@ -683,71 +684,63 @@ PHP_METHOD(Uri_Rfc3986_Uri, __serialize)
683684

684685
zend_object *this_object = Z_OBJ_P(ZEND_THIS);
685686
uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
686-
URI_CHECK_INITIALIZATION(internal_uri);
687-
688-
HashTable *result = zend_array_dup(this_object->handlers->get_properties(this_object));
689-
if (zend_hash_str_find_ind(result, URI_SERIALIZED_PROPERTY_NAME, sizeof(URI_SERIALIZED_PROPERTY_NAME) - 1) != NULL) {
690-
zend_hash_destroy(result);
691-
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object: $__uri property is not allowed", ZSTR_VAL(this_object->ce->name));
692-
RETURN_THROWS();
693-
}
687+
URI_ASSERT_INITIALIZATION(internal_uri);
694688

689+
/* Serialize state: "uri" key in the first array */
695690
zend_string *uri_str = internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false);
696691
if (uri_str == NULL) {
697692
zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to string", ZSTR_VAL(this_object->ce->name));
698693
RETURN_THROWS();
699694
}
695+
zval tmp;
696+
ZVAL_STR(&tmp, uri_str);
700697

701-
zval uri_zv;
702-
ZVAL_STR(&uri_zv, uri_str);
703-
zend_hash_str_add_new(result, URI_SERIALIZED_PROPERTY_NAME, sizeof(URI_SERIALIZED_PROPERTY_NAME) - 1, &uri_zv);
704-
705-
ZVAL_ARR(return_value, result);
706-
}
707-
708-
static void uri_restore_custom_properties(zend_object *object, uri_internal_t *internal_uri, HashTable *ht)
709-
{
710-
zend_string *prop_name;
711-
zval *prop_val;
698+
array_init(return_value);
712699

713-
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, prop_name, prop_val) {
714-
if (!prop_name || Z_TYPE_P(prop_val) == IS_REFERENCE ||
715-
zend_string_equals_literal(prop_name, URI_SERIALIZED_PROPERTY_NAME)
716-
) {
717-
continue;
718-
}
700+
zval arr;
701+
array_init(&arr);
702+
zend_hash_str_add_new(Z_ARRVAL(arr), URI_SERIALIZED_PROPERTY_NAME, sizeof(URI_SERIALIZED_PROPERTY_NAME) - 1, &tmp);
703+
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr);
719704

720-
zend_update_property_ex(object->ce, object, prop_name, prop_val);
721-
if (UNEXPECTED(EG(exception) != NULL)) {
722-
break;
723-
}
724-
} ZEND_HASH_FOREACH_END();
705+
/* Serialize regular properties: second array */
706+
ZVAL_ARR(&arr, this_object->handlers->get_properties(this_object));
707+
Z_TRY_ADDREF(arr);
708+
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr);
725709
}
726710

727711
static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS, const char *handler_name)
728712
{
729-
HashTable *properties;
713+
HashTable *data;
730714

731715
ZEND_PARSE_PARAMETERS_START(1, 1)
732-
Z_PARAM_ARRAY_HT(properties)
716+
Z_PARAM_ARRAY_HT(data)
733717
ZEND_PARSE_PARAMETERS_END();
734718

735719
zend_object *object = Z_OBJ_P(ZEND_THIS);
736-
uri_internal_t *internal_uri = uri_internal_from_obj(object);
737720

738-
zval *uri_zv = zend_hash_str_find_ind(properties, URI_SERIALIZED_PROPERTY_NAME, sizeof(URI_SERIALIZED_PROPERTY_NAME) - 1);
739-
if (uri_zv == NULL) {
740-
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object: missing \"__uri\" field", ZSTR_VAL(object->ce->name));
721+
/* Verify the expected number of elements, this implicitly ensures that no additional elements are present. */
722+
if (zend_hash_num_elements(data) != 2) {
723+
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
724+
RETURN_THROWS();
725+
}
726+
727+
/* Unserialize state: "uri" key in the first array */
728+
zval *arr = zend_hash_index_find(data, 0);
729+
if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) {
730+
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
741731
RETURN_THROWS();
742732
}
743-
if (Z_TYPE_P(uri_zv) != IS_STRING) {
744-
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object: \"__uri\" field is not a string", ZSTR_VAL(object->ce->name));
733+
734+
zval *uri_zv = zend_hash_str_find_ind(Z_ARRVAL_P(arr), URI_SERIALIZED_PROPERTY_NAME, sizeof(URI_SERIALIZED_PROPERTY_NAME) - 1);
735+
if (uri_zv == NULL || Z_TYPE_P(uri_zv) != IS_STRING) {
736+
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
745737
RETURN_THROWS();
746738
}
747739

748740
zval errors;
749741
ZVAL_UNDEF(&errors);
750742

743+
uri_internal_t *internal_uri = uri_internal_from_obj(object);
751744
internal_uri->handler = uri_handler_by_name(handler_name, strlen(handler_name));
752745
if (internal_uri->uri != NULL) {
753746
internal_uri->handler->free_uri(internal_uri->uri);
@@ -756,12 +749,22 @@ static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS, const char *handler_na
756749
if (internal_uri->uri == NULL) {
757750
throw_invalid_uri_exception(internal_uri->handler, &errors);
758751
zval_ptr_dtor(&errors);
759-
zval_ptr_dtor(uri_zv);
760752
RETURN_THROWS();
761753
}
762754
zval_ptr_dtor(&errors);
763755

764-
uri_restore_custom_properties(object, internal_uri, properties);
756+
/* Unserialize regular properties: second array */
757+
arr = zend_hash_index_find(data, 1);
758+
if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) {
759+
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
760+
RETURN_THROWS();
761+
}
762+
763+
object_properties_load(object, Z_ARRVAL_P(arr));
764+
if (EG(exception)) {
765+
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
766+
RETURN_THROWS();
767+
}
765768
}
766769

767770
PHP_METHOD(Uri_Rfc3986_Uri, __unserialize)
@@ -822,7 +825,7 @@ PHP_METHOD(Uri_WhatWg_Url, withHost)
822825
ZVAL_STR_COPY(&zv, value);
823826
}
824827

825-
URI_WITHER_COMMON(ZSTR_KNOWN(ZEND_STR_HOST), &zv, return_value) \
828+
URI_WITHER_COMMON(ZSTR_KNOWN(ZEND_STR_HOST), &zv, return_value);
826829
}
827830

828831
PHP_METHOD(Uri_WhatWg_Url, equals)
@@ -845,7 +848,7 @@ PHP_METHOD(Uri_WhatWg_Url, toUnicodeString)
845848

846849
zend_object *this_object = Z_OBJ_P(ZEND_THIS);
847850
uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
848-
URI_CHECK_INITIALIZATION(internal_uri);
851+
URI_ASSERT_INITIALIZATION(internal_uri);
849852

850853
RETURN_STR(internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_UNICODE, false));
851854
}
@@ -856,7 +859,7 @@ PHP_METHOD(Uri_WhatWg_Url, toAsciiString)
856859

857860
zend_object *this_object = Z_OBJ_P(ZEND_THIS);
858861
uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
859-
URI_CHECK_INITIALIZATION(internal_uri);
862+
URI_ASSERT_INITIALIZATION(internal_uri);
860863

861864
RETURN_STR(internal_uri->handler->uri_to_string(internal_uri->uri, URI_RECOMPOSITION_RAW_ASCII, false));
862865
}
@@ -874,7 +877,7 @@ PHP_METHOD(Uri_WhatWg_Url, resolve)
874877

875878
zend_object *this_object = Z_OBJ_P(ZEND_THIS);
876879
uri_internal_t *internal_uri = uri_internal_from_obj(this_object);
877-
URI_CHECK_INITIALIZATION(internal_uri);
880+
URI_ASSERT_INITIALIZATION(internal_uri);
878881

879882
php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, internal_uri->handler, uri_str, this_object, true, false, errors);
880883
}
@@ -920,7 +923,7 @@ static zend_object *uri_clone_obj_handler(zend_object *object)
920923
ZEND_ASSERT(new_object != NULL);
921924
uri_object_t *new_uri_object = uri_object_from_obj(new_object);
922925

923-
URI_CHECK_INITIALIZATION(internal_uri);
926+
URI_ASSERT_INITIALIZATION(internal_uri);
924927

925928
new_uri_object->internal.handler = internal_uri->handler;
926929

ext/uri/php_uri_common.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static inline uri_internal_t *uri_internal_from_obj(const zend_object *object) {
7777

7878
#define URI_PARSER_RFC3986 "Uri\\Rfc3986\\Uri"
7979
#define URI_PARSER_WHATWG "Uri\\WhatWg\\Url"
80-
#define URI_SERIALIZED_PROPERTY_NAME "__uri"
80+
#define URI_SERIALIZED_PROPERTY_NAME "uri"
8181

8282
typedef zend_result (*uri_read_t)(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval);
8383

@@ -103,14 +103,14 @@ zend_result uri_handler_register(const uri_handler_t *uri_handler);
103103
uri_property_handler_t *uri_property_handler_from_internal_uri(const uri_internal_t *internal_uri, zend_string *name);
104104
void throw_invalid_uri_exception(const uri_handler_t *uri_handler, zval *errors);
105105

106-
#define URI_CHECK_INITIALIZATION(internal_uri) do { \
106+
#define URI_ASSERT_INITIALIZATION(internal_uri) do { \
107107
ZEND_ASSERT(internal_uri != NULL && internal_uri->uri != NULL); \
108108
} while (0)
109109

110110
#define URI_GETTER(property_name, component_read_mode) do { \
111111
ZEND_PARSE_PARAMETERS_NONE(); \
112112
uri_internal_t *internal_uri = Z_URI_INTERNAL_P(ZEND_THIS); \
113-
URI_CHECK_INITIALIZATION(internal_uri); \
113+
URI_ASSERT_INITIALIZATION(internal_uri); \
114114
const uri_property_handler_t *property_handler = uri_property_handler_from_internal_uri(internal_uri, property_name); \
115115
ZEND_ASSERT(property_handler != NULL); \
116116
if (UNEXPECTED(property_handler->read_func(internal_uri, component_read_mode, return_value) == FAILURE)) { \
@@ -121,7 +121,7 @@ void throw_invalid_uri_exception(const uri_handler_t *uri_handler, zval *errors)
121121

122122
#define URI_WITHER_COMMON(property_name, property_zv, return_value) \
123123
uri_internal_t *internal_uri = Z_URI_INTERNAL_P(ZEND_THIS); \
124-
URI_CHECK_INITIALIZATION(internal_uri); \
124+
URI_ASSERT_INITIALIZATION(internal_uri); \
125125
const uri_property_handler_t *property_handler = uri_property_handler_from_internal_uri(internal_uri, property_name); \
126126
ZEND_ASSERT(property_handler != NULL); \
127127
zend_object *new_object = uri_clone_obj_handler(Z_OBJ_P(ZEND_THIS)); \
@@ -131,7 +131,7 @@ void throw_invalid_uri_exception(const uri_handler_t *uri_handler, zval *errors)
131131
RETURN_THROWS(); \
132132
} \
133133
uri_internal_t *new_internal_uri = uri_internal_from_obj(new_object); \
134-
URI_CHECK_INITIALIZATION(new_internal_uri); /* TODO fix memory leak of new_object */ \
134+
URI_ASSERT_INITIALIZATION(new_internal_uri); /* TODO fix memory leak of new_object */ \
135135
if (property_handler->write_func == NULL) { \
136136
zend_readonly_property_modification_error_ex(ZSTR_VAL(Z_OBJ_P(ZEND_THIS)->ce->name), ZSTR_VAL(property_name)); \
137137
zend_object_release(new_object); \
@@ -175,7 +175,7 @@ void throw_invalid_uri_exception(const uri_handler_t *uri_handler, zval *errors)
175175
URI_WITHER_COMMON(property_name, &zv, return_value) \
176176
} while (0)
177177

178-
#define URI_WITHER_LONG(property_name) do { \
178+
#define URI_WITHER_LONG_OR_NULL(property_name) do { \
179179
zend_long value; \
180180
bool value_is_null; \
181181
ZEND_PARSE_PARAMETERS_START(1, 1) \

0 commit comments

Comments
 (0)