@@ -537,20 +537,20 @@ static zend_result php_uri_parser_rfc3986_fragment_write(void *uri, const zval *
537537 }
538538}
539539
540- static php_uri_parser_rfc3986_uris * uriparser_create_uris (void )
540+ php_uri_parser_rfc3986_uris * uriparser_create_uris (void )
541541{
542542 php_uri_parser_rfc3986_uris * uriparser_uris = ecalloc (1 , sizeof (* uriparser_uris ));
543543 uriparser_uris -> normalized_uri_initialized = false;
544544
545545 return uriparser_uris ;
546546}
547547
548- php_uri_parser_rfc3986_uris * php_uri_parser_rfc3986_parse_ex (const char * uri_str , size_t uri_str_len , const php_uri_parser_rfc3986_uris * uriparser_base_urls , bool silent )
548+ php_uri_parser_rfc3986_uris * php_uri_parser_rfc3986_parse_ex (const char * uri_str , const size_t uri_str_len , const php_uri_parser_rfc3986_uris * uriparser_base_urls , const bool silent )
549549{
550550 UriUriA uri = {0 };
551551
552552 /* Parse the URI. */
553- int result = uriParseSingleUriExMmA (& uri , uri_str , uri_str + uri_str_len , NULL , mm );
553+ const int result = uriParseSingleUriExMmA (& uri , uri_str , uri_str + uri_str_len , NULL , mm );
554554 if (result != URI_SUCCESS ) {
555555 if (!silent ) {
556556 switch (result ) {
@@ -572,7 +572,7 @@ php_uri_parser_rfc3986_uris *php_uri_parser_rfc3986_parse_ex(const char *uri_str
572572
573573 /* Combine the parsed URI with the base URI and store the result in 'tmp',
574574 * since the target and source URLs must be distinct. */
575- int result = uriAddBaseUriExMmA (& tmp , & uri , & uriparser_base_urls -> uri , URI_RESOLVE_STRICTLY , mm );
575+ const int result = uriAddBaseUriExMmA (& tmp , & uri , & uriparser_base_urls -> uri , URI_RESOLVE_STRICTLY , mm );
576576 if (result != URI_SUCCESS ) {
577577 if (!silent ) {
578578 switch (result ) {
@@ -727,7 +727,7 @@ ZEND_ATTRIBUTE_NONNULL bool php_uri_parser_rfc3986_validate_host(const zend_stri
727727 return uriIsWellFormedHostRegNameA (p , p + len );
728728}
729729
730- ZEND_ATTRIBUTE_NONNULL bool php_uri_parser_rfc3986_validate_port (zend_long port )
730+ ZEND_ATTRIBUTE_NONNULL bool php_uri_parser_rfc3986_validate_port (const zend_long port )
731731{
732732 zend_string * tmp = zend_long_to_str (port );
733733 const char * p = ZSTR_VAL (tmp );
@@ -765,109 +765,93 @@ ZEND_ATTRIBUTE_NONNULL bool php_uri_parser_rfc3986_validate_fragment(const zend_
765765 return uriIsWellFormedFragmentA (p , p + len );
766766}
767767
768- ZEND_ATTRIBUTE_NONNULL zend_string * php_uri_parser_rfc3986_recompose_from_zval (
768+ ZEND_ATTRIBUTE_NONNULL_ARGS (2 ,3 ,4 ,5 ,6 ,7 ,8 ) php_uri_parser_rfc3986_uris * php_uri_parser_rfc3986_build_from_zval (
769+ const php_uri_parser_rfc3986_uris * uriparser_base_uris ,
769770 const zval * scheme , const zval * userinfo , const zval * host , const zval * port ,
770771 const zval * path , const zval * query , const zval * fragment
771772) {
772- if (Z_TYPE_P (host ) == IS_NULL ) {
773- /* The path must not begin with "//" if the URI doesn't contain a host */
774- if (zend_string_starts_with_literal (Z_STR_P (path ), "//" )) {
775- zend_throw_exception (php_uri_ce_invalid_uri_exception , "The path must not begin with \"//\" when the URI doesn't contain a host" , 0 );
776- return NULL ;
777- }
773+ php_uri_parser_rfc3986_uris * uriparser_uris = uriparser_create_uris ();
778774
779- /* The userinfo and port components must not be present if the URI doesn't contain a host */
780- if (Z_TYPE_P (userinfo ) != IS_NULL || Z_TYPE_P (port ) != IS_NULL ) {
781- zend_throw_exception (php_uri_ce_invalid_uri_exception , "The URI must contain a host if either the userinfo or the port component is present" , 0 );
782- return NULL ;
783- }
784- } else {
785- /* The path must be either empty or begin with a "/" if the URI contains a host */
786- if (Z_STRLEN_P (path ) > 0 && Z_STRVAL_P (path )[0 ] != '/' ) {
787- zend_throw_exception (php_uri_ce_invalid_uri_exception , "A path must be either empty or begin with \"/\" when the URI contains a host" , 0 );
788- return NULL ;
789- }
790- }
775+ if (Z_STRLEN_P (path ) > 0 ) {
776+ /* The first segment of the path must not contain ":" if the URI doesn't contain a scheme */
777+ if (Z_TYPE_P (scheme ) == IS_NULL ) {
778+ const char * p = Z_STRVAL_P (path );
779+ while (* p != '\0' && * p != '/' ) {
780+ if (* p == ':' ) {
781+ zend_throw_exception (php_uri_ce_invalid_uri_exception , "The path must not begin with \":\" when the URI doesn't contain a scheme" , 0 );
782+ goto failure ;
783+ }
791784
792- /* The first segment of the path must not contain ":" if the URI doesn't contain a scheme */
793- if (Z_TYPE_P (scheme ) == IS_NULL ) {
794- const char * p = Z_STRVAL_P (path );
795- while (* p != '\0' && * p != '/' ) {
796- if (* p == ':' ) {
797- zend_throw_exception (php_uri_ce_invalid_uri_exception , "The path must not begin with \":\" when the URI doesn't contain a scheme" , 0 );
798- return NULL ;
785+ p ++ ;
799786 }
787+ }
800788
801- p ++ ;
789+ /* The path must not begin with "//" if the URI doesn't contain a host */
790+ if (Z_TYPE_P (host ) == IS_NULL && zend_string_starts_with_literal (Z_STR_P (path ), "//" )) {
791+ zend_throw_exception (php_uri_ce_invalid_uri_exception , "The path must not begin with \"//\" when the URI doesn't contain a host" , 0 );
792+ goto failure ;
802793 }
803794 }
804795
805- /* result = "" */
806- smart_str uri_str = {0 };
807-
808- /*
809- if defined(scheme) then
810- append scheme to result;
811- append ":" to result;
812- endif;
813- */
814- if (Z_TYPE_P (scheme ) != IS_NULL ) {
815- smart_str_append (& uri_str , Z_STR_P (scheme ));
816- smart_str_appendc (& uri_str , ':' );
817- }
818-
819- /*
820- if defined(authority) then
821- append "//" to result;
822- append authority to result;
823- endif;
824- */
825- /* Check if authority is defined */
826- if (Z_TYPE_P (host ) != IS_NULL ) {
827- smart_str_appends (& uri_str , "//" );
828-
829- if (Z_TYPE_P (userinfo ) != IS_NULL ) {
830- smart_str_append (& uri_str , Z_STR_P (userinfo ));
831- smart_str_appendc (& uri_str , '@' );
832- }
796+ zend_result result = php_uri_parser_rfc3986_scheme_write (uriparser_uris , scheme , NULL );
797+ if (result == FAILURE ) {
798+ goto failure ;
799+ }
800+ result = php_uri_parser_rfc3986_host_write (uriparser_uris , host , NULL );
801+ if (result == FAILURE ) {
802+ goto failure ;
803+ }
804+ /* Intentionally writing userinfo after host to avoid error when the userinfo is set but the host is missing */
805+ result = php_uri_parser_rfc3986_userinfo_write (uriparser_uris , userinfo , NULL );
806+ if (result == FAILURE ) {
807+ goto failure ;
808+ }
809+ /* Intentionally writing userinfo after host to avoid error when the port is set but the host is missing */
810+ result = php_uri_parser_rfc3986_port_write (uriparser_uris , port , NULL );
811+ if (result == FAILURE ) {
812+ goto failure ;
813+ }
814+ result = php_uri_parser_rfc3986_path_write (uriparser_uris , path , NULL );
815+ if (result == FAILURE ) {
816+ goto failure ;
817+ }
818+ result = php_uri_parser_rfc3986_query_write (uriparser_uris , query , NULL );
819+ if (result == FAILURE ) {
820+ goto failure ;
821+ }
822+ result = php_uri_parser_rfc3986_fragment_write (uriparser_uris , fragment , NULL );
823+ if (result == FAILURE ) {
824+ goto failure ;
825+ }
833826
834- if (Z_TYPE_P (host ) != IS_NULL ) {
835- smart_str_append (& uri_str , Z_STR_P (host ));
836- }
827+ if (uriparser_base_uris != NULL ) {
828+ UriUriA tmp = {0 };
837829
838- if (Z_TYPE_P (port ) != IS_NULL ) {
839- smart_str_appendc (& uri_str , ':' );
840- smart_str_append_long (& uri_str , Z_LVAL_P (port ));
830+ const int base_uri_result = uriAddBaseUriExMmA (& tmp , & uriparser_uris -> uri , & uriparser_base_uris -> uri , URI_RESOLVE_STRICTLY , mm );
831+ if (base_uri_result != URI_SUCCESS ) {
832+ uriFreeUriMembersMmA (& tmp , mm );
833+ switch (base_uri_result ) {
834+ case URI_ERROR_ADDBASE_REL_BASE :
835+ zend_throw_exception (php_uri_ce_invalid_uri_exception , "The specified base URI must be absolute" , 0 );
836+ goto failure ;
837+ default :
838+ /* This should be unreachable in practice. */
839+ zend_throw_exception (php_uri_ce_error , "Failed to resolve the specified URI against the base URI" , 0 );
840+ goto failure ;
841+ }
841842 }
842- }
843843
844- /* append path to result; */
845- smart_str_append (& uri_str , Z_STR_P (path ));
846-
847- /*
848- if defined(query) then
849- append "?" to result;
850- append query to result;
851- endif;
852- */
853- if (Z_TYPE_P (query ) != IS_NULL ) {
854- smart_str_appendc (& uri_str , '?' );
855- smart_str_append (& uri_str , Z_STR_P (query ));
844+ uriMakeOwnerMmA (& tmp , mm );
845+ uriFreeUriMembersMmA (& uriparser_uris -> uri , mm );
846+ uriparser_uris -> uri = tmp ;
856847 }
857848
858- /*
859- if defined(fragment) then
860- append "#" to result;
861- append fragment to result;
862- endif;
863- */
864- if (Z_TYPE_P (fragment ) != IS_NULL ) {
865- smart_str_appendc (& uri_str , '#' );
866- smart_str_append (& uri_str , Z_STR_P (fragment ));
867- }
849+ return uriparser_uris ;
868850
869- /* return result; */
870- return smart_str_extract (& uri_str );
851+ failure :
852+ uriFreeUriMembersMmA (& uriparser_uris -> uri , mm );
853+ efree (uriparser_uris );
854+ return NULL ;
871855}
872856
873857PHPAPI const php_uri_parser php_uri_parser_rfc3986 = {
0 commit comments