diff --git a/ext/uri/config.m4 b/ext/uri/config.m4
index 8606b56705d55..0ba1654094422 100644
--- a/ext/uri/config.m4
+++ b/ext/uri/config.m4
@@ -17,7 +17,11 @@ URIPARSER_SOURCES="$URIPARSER_DIR/src/UriCommon.c $URIPARSER_DIR/src/UriCompare.
$URIPARSER_DIR/src/UriEscape.c $URIPARSER_DIR/src/UriFile.c $URIPARSER_DIR/src/UriIp4.c $URIPARSER_DIR/src/UriIp4Base.c \
$URIPARSER_DIR/src/UriMemory.c $URIPARSER_DIR/src/UriNormalize.c $URIPARSER_DIR/src/UriNormalizeBase.c \
$URIPARSER_DIR/src/UriParse.c $URIPARSER_DIR/src/UriParseBase.c $URIPARSER_DIR/src/UriQuery.c \
-$URIPARSER_DIR/src/UriRecompose.c $URIPARSER_DIR/src/UriResolve.c $URIPARSER_DIR/src/UriShorten.c"
+$URIPARSER_DIR/src/UriRecompose.c $URIPARSER_DIR/src/UriResolve.c $URIPARSER_DIR/src/UriSetFragment.c \
+$URIPARSER_DIR/src/UriSetHostAuto.c $URIPARSER_DIR/src/UriSetHostCommon.c $URIPARSER_DIR/src/UriSetHostIp4.c \
+$URIPARSER_DIR/src/UriSetHostIp6.c $URIPARSER_DIR/src/UriSetHostIpFuture.c $URIPARSER_DIR/src/UriSetHostRegName.c \
+$URIPARSER_DIR/src/UriSetPath.c $URIPARSER_DIR/src/UriSetPort.c $URIPARSER_DIR/src/UriSetQuery.c \
+$URIPARSER_DIR/src/UriSetScheme.c $URIPARSER_DIR/src/UriSetUserInfo.c $URIPARSER_DIR/src/UriShorten.c"
PHP_NEW_EXTENSION(uri, [php_uri.c php_uri_common.c uri_parser_rfc3986.c uri_parser_whatwg.c uri_parser_php_parse_url.c $URIPARSER_SOURCES], [no],,[-I$ext_srcdir/$URIPARSER_DIR/include -DURI_STATIC_BUILD -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
PHP_ADD_EXTENSION_DEP(uri, lexbor)
diff --git a/ext/uri/config.w32 b/ext/uri/config.w32
index 8d1452ccfb862..e7dd18cc55aa7 100644
--- a/ext/uri/config.w32
+++ b/ext/uri/config.w32
@@ -5,5 +5,8 @@ AC_DEFINE("URI_NO_UNICODE", 1, "Define to 1 for disabling unicode support of uri
ADD_FLAG("CFLAGS_URI", "/D URI_STATIC_BUILD");
ADD_EXTENSION_DEP('uri', 'lexbor');
-ADD_SOURCES("ext/uri/uriparser/src", "UriCommon.c UriCompare.c UriCopy.c UriEscape.c UriFile.c UriIp4.c UriIp4Base.c UriMemory.c UriNormalize.c UriNormalizeBase.c UriParse.c UriParseBase.c UriQuery.c UriRecompose.c UriResolve.c UriShorten.c", "uri");
+ADD_SOURCES("ext/uri/uriparser/src", "UriCommon.c UriCompare.c UriCopy.c UriEscape.c UriFile.c UriIp4.c UriIp4Base.c \
+ UriMemory.c UriNormalize.c UriNormalizeBase.c UriParse.c UriParseBase.c UriQuery.c UriRecompose.c UriResolve.c \
+ UriSetFragment.c UriSetHostAuto.c UriSetHostCommon.c UriSetHostIp4.c UriSetHostIp6.c UriSetHostIpFuture.c UriSetHostRegName.c \
+ UriSetPath.c UriSetPort.c UriSetQuery.c UriSetScheme.c UriSetUserInfo.c UriShorten.c", "uri");
PHP_INSTALL_HEADERS("ext/uri", "php_uri.h php_uri_common.h uri_parser_rfc3986.h uri_parser_whatwg.h uri_parser_php_parse_url.h uriparser/src uriparser/include");
diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c
index 17278c0f422e8..36ae017288e4e 100644
--- a/ext/uri/php_uri.c
+++ b/ext/uri/php_uri.c
@@ -500,7 +500,12 @@ PHP_METHOD(Uri_Rfc3986_Uri, getRawScheme)
uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME, URI_COMPONENT_READ_RAW);
}
-static void read_uriparser_userinfo(INTERNAL_FUNCTION_PARAMETERS, uri_component_read_mode_t read_mode)
+PHP_METHOD(Uri_Rfc3986_Uri, withScheme)
+{
+ uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_SCHEME);
+}
+
+static void rfc3986_userinfo_read(INTERNAL_FUNCTION_PARAMETERS, uri_component_read_mode_t read_mode)
{
ZEND_PARSE_PARAMETERS_NONE();
@@ -515,12 +520,48 @@ static void read_uriparser_userinfo(INTERNAL_FUNCTION_PARAMETERS, uri_component_
PHP_METHOD(Uri_Rfc3986_Uri, getUserInfo)
{
- read_uriparser_userinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_COMPONENT_READ_NORMALIZED_ASCII);
+ rfc3986_userinfo_read(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_COMPONENT_READ_NORMALIZED_ASCII);
}
PHP_METHOD(Uri_Rfc3986_Uri, getRawUserInfo)
{
- read_uriparser_userinfo(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_COMPONENT_READ_RAW);
+ rfc3986_userinfo_read(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_COMPONENT_READ_RAW);
+}
+
+PHP_METHOD(Uri_Rfc3986_Uri, withUserInfo)
+{
+ zend_string *value;
+
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_PATH_STR_OR_NULL(value)
+ ZEND_PARSE_PARAMETERS_END();
+
+ zval zv;
+ if (value == NULL) {
+ ZVAL_NULL(&zv);
+ } else {
+ ZVAL_STR(&zv, value);
+ }
+
+ uri_internal_t *internal_uri = Z_URI_INTERNAL_P(ZEND_THIS);
+ URI_ASSERT_INITIALIZATION(internal_uri);
+
+ zend_object *new_object = uri_clone_obj_handler(Z_OBJ_P(ZEND_THIS));
+ ZEND_ASSERT(new_object != NULL);
+
+ uri_internal_t *new_internal_uri = uri_internal_from_obj(new_object);
+ URI_ASSERT_INITIALIZATION(new_internal_uri);
+
+ zval errors;
+ ZVAL_UNDEF(&errors);
+ if (UNEXPECTED(php_uri_parser_rfc3986_userinfo_write(new_internal_uri, &zv, NULL) == FAILURE)) {
+ zval_ptr_dtor(&errors);
+ zend_object_release(new_object);
+ RETURN_THROWS();
+ }
+
+ ZEND_ASSERT(Z_ISUNDEF(errors));
+ RETVAL_OBJ(new_object);
}
PHP_METHOD(Uri_Rfc3986_Uri, getUsername)
@@ -553,11 +594,21 @@ PHP_METHOD(Uri_Rfc3986_Uri, getRawHost)
uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_RAW);
}
+PHP_METHOD(Uri_Rfc3986_Uri, withHost)
+{
+ uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST);
+}
+
PHP_METHOD(Uri_Rfc3986_Uri, getPort)
{
uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT, URI_COMPONENT_READ_RAW);
}
+PHP_METHOD(Uri_Rfc3986_Uri, withPort)
+{
+ uri_write_component_long_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT);
+}
+
PHP_METHOD(Uri_Rfc3986_Uri, getPath)
{
uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH, URI_COMPONENT_READ_NORMALIZED_ASCII);
@@ -568,6 +619,11 @@ PHP_METHOD(Uri_Rfc3986_Uri, getRawPath)
uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH, URI_COMPONENT_READ_RAW);
}
+PHP_METHOD(Uri_Rfc3986_Uri, withPath)
+{
+ uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH);
+}
+
PHP_METHOD(Uri_Rfc3986_Uri, getQuery)
{
uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY, URI_COMPONENT_READ_NORMALIZED_ASCII);
@@ -578,6 +634,11 @@ PHP_METHOD(Uri_Rfc3986_Uri, getRawQuery)
uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY, URI_COMPONENT_READ_RAW);
}
+PHP_METHOD(Uri_Rfc3986_Uri, withQuery)
+{
+ uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY);
+}
+
PHP_METHOD(Uri_Rfc3986_Uri, getFragment)
{
uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT, URI_COMPONENT_READ_NORMALIZED_ASCII);
@@ -588,6 +649,11 @@ PHP_METHOD(Uri_Rfc3986_Uri, getRawFragment)
uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT, URI_COMPONENT_READ_RAW);
}
+PHP_METHOD(Uri_Rfc3986_Uri, withFragment)
+{
+ uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT);
+}
+
static void throw_cannot_recompose_uri_to_string(zend_object *object)
{
zend_throw_exception_ex(NULL, 0, "Cannot recompose %s to a string", ZSTR_VAL(object->ce->name));
@@ -833,29 +899,9 @@ PHP_METHOD(Uri_WhatWg_Url, getUnicodeHost)
uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST, URI_COMPONENT_READ_NORMALIZED_UNICODE);
}
-PHP_METHOD(Uri_WhatWg_Url, withHost)
-{
- uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_HOST);
-}
-
-PHP_METHOD(Uri_WhatWg_Url, withPort)
-{
- uri_write_component_long_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PORT);
-}
-
-PHP_METHOD(Uri_WhatWg_Url, withPath)
+PHP_METHOD(Uri_WhatWg_Url, getFragment)
{
- uri_write_component_str(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_PATH);
-}
-
-PHP_METHOD(Uri_WhatWg_Url, withQuery)
-{
- uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_QUERY);
-}
-
-PHP_METHOD(Uri_WhatWg_Url, withFragment)
-{
- uri_write_component_str_or_null(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT);
+ uri_read_component(INTERNAL_FUNCTION_PARAM_PASSTHRU, URI_PROPERTY_NAME_FRAGMENT, URI_COMPONENT_READ_NORMALIZED_UNICODE);
}
PHP_METHOD(Uri_WhatWg_Url, equals)
diff --git a/ext/uri/php_uri.stub.php b/ext/uri/php_uri.stub.php
index 9fbd40d98e5e9..b4063bee8f596 100644
--- a/ext/uri/php_uri.stub.php
+++ b/ext/uri/php_uri.stub.php
@@ -32,10 +32,14 @@ public function getScheme(): ?string {}
public function getRawScheme(): ?string {}
+ public function withScheme(?string $scheme): static {}
+
public function getUserInfo(): ?string {}
public function getRawUserInfo(): ?string {}
+ public function withUserInfo(#[\SensitiveParameter] ?string $userinfo): static {}
+
public function getUsername(): ?string {}
public function getRawUsername(): ?string {}
@@ -48,20 +52,30 @@ public function getHost(): ?string {}
public function getRawHost(): ?string {}
+ public function withHost(?string $host): static {}
+
public function getPort(): ?int {}
+ public function withPort(?int $port): static {}
+
public function getPath(): string {}
public function getRawPath(): string {}
+ public function withPath(string $path): static {}
+
public function getQuery(): ?string {}
public function getRawQuery(): ?string {}
+ public function withQuery(?string $query): static {}
+
public function getFragment(): ?string {}
public function getRawFragment(): ?string {}
+ public function withFragment(?string $fragment): static {}
+
public function equals(\Uri\Rfc3986\Uri $uri, \Uri\UriComparisonMode $comparisonMode = \Uri\UriComparisonMode::ExcludeFragment): bool {}
public function toString(): string {}
@@ -157,26 +171,31 @@ public function getAsciiHost(): ?string {}
public function getUnicodeHost(): ?string {}
+ /** @implementation-alias Uri\Rfc3986\Uri::withHost */
public function withHost(?string $host): static {}
/** @implementation-alias Uri\Rfc3986\Uri::getPort */
public function getPort(): ?int {}
+ /** @implementation-alias Uri\Rfc3986\Uri::withPort */
public function withPort(?int $port): static {}
/** @implementation-alias Uri\Rfc3986\Uri::getPath */
public function getPath(): string {}
+ /** @implementation-alias Uri\Rfc3986\Uri::withPath */
public function withPath(string $path): static {}
/** @implementation-alias Uri\Rfc3986\Uri::getQuery */
public function getQuery(): ?string {}
+ /** @implementation-alias Uri\Rfc3986\Uri::withQuery */
public function withQuery(?string $query): static {}
/** @implementation-alias Uri\Rfc3986\Uri::getFragment */
public function getFragment(): ?string {}
+ /** @implementation-alias Uri\Rfc3986\Uri::withFragment */
public function withFragment(?string $fragment): static {}
public function equals(\Uri\WhatWg\Url $url, \Uri\UriComparisonMode $comparisonMode = \Uri\UriComparisonMode::ExcludeFragment): bool {}
diff --git a/ext/uri/php_uri_arginfo.h b/ext/uri/php_uri_arginfo.h
index 65630f113a3d3..12a498357ea28 100644
--- a/ext/uri/php_uri_arginfo.h
+++ b/ext/uri/php_uri_arginfo.h
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
- * Stub hash: e2c448000b1e00485bc988f073ea61dfc984e953 */
+ * Stub hash: bf37e0babfcc453ab0c75d0e87e142dfa3b5e61e */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_parse, 0, 1, IS_STATIC, 1)
ZEND_ARG_TYPE_INFO(0, uri, IS_STRING, 0)
@@ -16,10 +16,18 @@ ZEND_END_ARG_INFO()
#define arginfo_class_Uri_Rfc3986_Uri_getRawScheme arginfo_class_Uri_Rfc3986_Uri_getScheme
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_withScheme, 0, 1, IS_STATIC, 0)
+ ZEND_ARG_TYPE_INFO(0, scheme, IS_STRING, 1)
+ZEND_END_ARG_INFO()
+
#define arginfo_class_Uri_Rfc3986_Uri_getUserInfo arginfo_class_Uri_Rfc3986_Uri_getScheme
#define arginfo_class_Uri_Rfc3986_Uri_getRawUserInfo arginfo_class_Uri_Rfc3986_Uri_getScheme
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_withUserInfo, 0, 1, IS_STATIC, 0)
+ ZEND_ARG_TYPE_INFO(0, userinfo, IS_STRING, 1)
+ZEND_END_ARG_INFO()
+
#define arginfo_class_Uri_Rfc3986_Uri_getUsername arginfo_class_Uri_Rfc3986_Uri_getScheme
#define arginfo_class_Uri_Rfc3986_Uri_getRawUsername arginfo_class_Uri_Rfc3986_Uri_getScheme
@@ -32,22 +40,42 @@ ZEND_END_ARG_INFO()
#define arginfo_class_Uri_Rfc3986_Uri_getRawHost arginfo_class_Uri_Rfc3986_Uri_getScheme
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_withHost, 0, 1, IS_STATIC, 0)
+ ZEND_ARG_TYPE_INFO(0, host, IS_STRING, 1)
+ZEND_END_ARG_INFO()
+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_getPort, 0, 0, IS_LONG, 1)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_withPort, 0, 1, IS_STATIC, 0)
+ ZEND_ARG_TYPE_INFO(0, port, IS_LONG, 1)
+ZEND_END_ARG_INFO()
+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_getPath, 0, 0, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_Uri_Rfc3986_Uri_getRawPath arginfo_class_Uri_Rfc3986_Uri_getPath
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_withPath, 0, 1, IS_STATIC, 0)
+ ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
#define arginfo_class_Uri_Rfc3986_Uri_getQuery arginfo_class_Uri_Rfc3986_Uri_getScheme
#define arginfo_class_Uri_Rfc3986_Uri_getRawQuery arginfo_class_Uri_Rfc3986_Uri_getScheme
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_withQuery, 0, 1, IS_STATIC, 0)
+ ZEND_ARG_TYPE_INFO(0, query, IS_STRING, 1)
+ZEND_END_ARG_INFO()
+
#define arginfo_class_Uri_Rfc3986_Uri_getFragment arginfo_class_Uri_Rfc3986_Uri_getScheme
#define arginfo_class_Uri_Rfc3986_Uri_getRawFragment arginfo_class_Uri_Rfc3986_Uri_getScheme
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_withFragment, 0, 1, IS_STATIC, 0)
+ ZEND_ARG_TYPE_INFO(0, fragment, IS_STRING, 1)
+ZEND_END_ARG_INFO()
+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_equals, 0, 1, _IS_BOOL, 0)
ZEND_ARG_OBJ_INFO(0, uri, Uri\\Rfc3986\\\125ri, 0)
ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, comparisonMode, Uri\\\125riComparisonMode, 0, "Uri\\UriComparisonMode::ExcludeFragment")
@@ -117,33 +145,23 @@ ZEND_END_ARG_INFO()
#define arginfo_class_Uri_WhatWg_Url_getUnicodeHost arginfo_class_Uri_Rfc3986_Uri_getScheme
-ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withHost, 0, 1, IS_STATIC, 0)
- ZEND_ARG_TYPE_INFO(0, host, IS_STRING, 1)
-ZEND_END_ARG_INFO()
+#define arginfo_class_Uri_WhatWg_Url_withHost arginfo_class_Uri_Rfc3986_Uri_withHost
#define arginfo_class_Uri_WhatWg_Url_getPort arginfo_class_Uri_Rfc3986_Uri_getPort
-ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withPort, 0, 1, IS_STATIC, 0)
- ZEND_ARG_TYPE_INFO(0, port, IS_LONG, 1)
-ZEND_END_ARG_INFO()
+#define arginfo_class_Uri_WhatWg_Url_withPort arginfo_class_Uri_Rfc3986_Uri_withPort
#define arginfo_class_Uri_WhatWg_Url_getPath arginfo_class_Uri_Rfc3986_Uri_getPath
-ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withPath, 0, 1, IS_STATIC, 0)
- ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0)
-ZEND_END_ARG_INFO()
+#define arginfo_class_Uri_WhatWg_Url_withPath arginfo_class_Uri_Rfc3986_Uri_withPath
#define arginfo_class_Uri_WhatWg_Url_getQuery arginfo_class_Uri_Rfc3986_Uri_getScheme
-ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withQuery, 0, 1, IS_STATIC, 0)
- ZEND_ARG_TYPE_INFO(0, query, IS_STRING, 1)
-ZEND_END_ARG_INFO()
+#define arginfo_class_Uri_WhatWg_Url_withQuery arginfo_class_Uri_Rfc3986_Uri_withQuery
#define arginfo_class_Uri_WhatWg_Url_getFragment arginfo_class_Uri_Rfc3986_Uri_getScheme
-ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_withFragment, 0, 1, IS_STATIC, 0)
- ZEND_ARG_TYPE_INFO(0, fragment, IS_STRING, 1)
-ZEND_END_ARG_INFO()
+#define arginfo_class_Uri_WhatWg_Url_withFragment arginfo_class_Uri_Rfc3986_Uri_withFragment
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_WhatWg_Url_equals, 0, 1, _IS_BOOL, 0)
ZEND_ARG_OBJ_INFO(0, url, Uri\\WhatWg\\\125rl, 0)
@@ -169,21 +187,28 @@ ZEND_METHOD(Uri_Rfc3986_Uri, parse);
ZEND_METHOD(Uri_Rfc3986_Uri, __construct);
ZEND_METHOD(Uri_Rfc3986_Uri, getScheme);
ZEND_METHOD(Uri_Rfc3986_Uri, getRawScheme);
+ZEND_METHOD(Uri_Rfc3986_Uri, withScheme);
ZEND_METHOD(Uri_Rfc3986_Uri, getUserInfo);
ZEND_METHOD(Uri_Rfc3986_Uri, getRawUserInfo);
+ZEND_METHOD(Uri_Rfc3986_Uri, withUserInfo);
ZEND_METHOD(Uri_Rfc3986_Uri, getUsername);
ZEND_METHOD(Uri_Rfc3986_Uri, getRawUsername);
ZEND_METHOD(Uri_Rfc3986_Uri, getPassword);
ZEND_METHOD(Uri_Rfc3986_Uri, getRawPassword);
ZEND_METHOD(Uri_Rfc3986_Uri, getHost);
ZEND_METHOD(Uri_Rfc3986_Uri, getRawHost);
+ZEND_METHOD(Uri_Rfc3986_Uri, withHost);
ZEND_METHOD(Uri_Rfc3986_Uri, getPort);
+ZEND_METHOD(Uri_Rfc3986_Uri, withPort);
ZEND_METHOD(Uri_Rfc3986_Uri, getPath);
ZEND_METHOD(Uri_Rfc3986_Uri, getRawPath);
+ZEND_METHOD(Uri_Rfc3986_Uri, withPath);
ZEND_METHOD(Uri_Rfc3986_Uri, getQuery);
ZEND_METHOD(Uri_Rfc3986_Uri, getRawQuery);
+ZEND_METHOD(Uri_Rfc3986_Uri, withQuery);
ZEND_METHOD(Uri_Rfc3986_Uri, getFragment);
ZEND_METHOD(Uri_Rfc3986_Uri, getRawFragment);
+ZEND_METHOD(Uri_Rfc3986_Uri, withFragment);
ZEND_METHOD(Uri_Rfc3986_Uri, equals);
ZEND_METHOD(Uri_Rfc3986_Uri, toString);
ZEND_METHOD(Uri_Rfc3986_Uri, toRawString);
@@ -201,11 +226,6 @@ ZEND_METHOD(Uri_WhatWg_Url, withUsername);
ZEND_METHOD(Uri_WhatWg_Url, withPassword);
ZEND_METHOD(Uri_WhatWg_Url, getAsciiHost);
ZEND_METHOD(Uri_WhatWg_Url, getUnicodeHost);
-ZEND_METHOD(Uri_WhatWg_Url, withHost);
-ZEND_METHOD(Uri_WhatWg_Url, withPort);
-ZEND_METHOD(Uri_WhatWg_Url, withPath);
-ZEND_METHOD(Uri_WhatWg_Url, withQuery);
-ZEND_METHOD(Uri_WhatWg_Url, withFragment);
ZEND_METHOD(Uri_WhatWg_Url, equals);
ZEND_METHOD(Uri_WhatWg_Url, toAsciiString);
ZEND_METHOD(Uri_WhatWg_Url, toUnicodeString);
@@ -219,21 +239,28 @@ static const zend_function_entry class_Uri_Rfc3986_Uri_methods[] = {
ZEND_ME(Uri_Rfc3986_Uri, __construct, arginfo_class_Uri_Rfc3986_Uri___construct, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getScheme, arginfo_class_Uri_Rfc3986_Uri_getScheme, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getRawScheme, arginfo_class_Uri_Rfc3986_Uri_getRawScheme, ZEND_ACC_PUBLIC)
+ ZEND_ME(Uri_Rfc3986_Uri, withScheme, arginfo_class_Uri_Rfc3986_Uri_withScheme, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getUserInfo, arginfo_class_Uri_Rfc3986_Uri_getUserInfo, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getRawUserInfo, arginfo_class_Uri_Rfc3986_Uri_getRawUserInfo, ZEND_ACC_PUBLIC)
+ ZEND_ME(Uri_Rfc3986_Uri, withUserInfo, arginfo_class_Uri_Rfc3986_Uri_withUserInfo, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getUsername, arginfo_class_Uri_Rfc3986_Uri_getUsername, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getRawUsername, arginfo_class_Uri_Rfc3986_Uri_getRawUsername, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getPassword, arginfo_class_Uri_Rfc3986_Uri_getPassword, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getRawPassword, arginfo_class_Uri_Rfc3986_Uri_getRawPassword, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getHost, arginfo_class_Uri_Rfc3986_Uri_getHost, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getRawHost, arginfo_class_Uri_Rfc3986_Uri_getRawHost, ZEND_ACC_PUBLIC)
+ ZEND_ME(Uri_Rfc3986_Uri, withHost, arginfo_class_Uri_Rfc3986_Uri_withHost, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getPort, arginfo_class_Uri_Rfc3986_Uri_getPort, ZEND_ACC_PUBLIC)
+ ZEND_ME(Uri_Rfc3986_Uri, withPort, arginfo_class_Uri_Rfc3986_Uri_withPort, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getPath, arginfo_class_Uri_Rfc3986_Uri_getPath, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getRawPath, arginfo_class_Uri_Rfc3986_Uri_getRawPath, ZEND_ACC_PUBLIC)
+ ZEND_ME(Uri_Rfc3986_Uri, withPath, arginfo_class_Uri_Rfc3986_Uri_withPath, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getQuery, arginfo_class_Uri_Rfc3986_Uri_getQuery, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getRawQuery, arginfo_class_Uri_Rfc3986_Uri_getRawQuery, ZEND_ACC_PUBLIC)
+ ZEND_ME(Uri_Rfc3986_Uri, withQuery, arginfo_class_Uri_Rfc3986_Uri_withQuery, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getFragment, arginfo_class_Uri_Rfc3986_Uri_getFragment, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, getRawFragment, arginfo_class_Uri_Rfc3986_Uri_getRawFragment, ZEND_ACC_PUBLIC)
+ ZEND_ME(Uri_Rfc3986_Uri, withFragment, arginfo_class_Uri_Rfc3986_Uri_withFragment, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, equals, arginfo_class_Uri_Rfc3986_Uri_equals, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, toString, arginfo_class_Uri_Rfc3986_Uri_toString, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_Rfc3986_Uri, toRawString, arginfo_class_Uri_Rfc3986_Uri_toRawString, ZEND_ACC_PUBLIC)
@@ -265,15 +292,15 @@ static const zend_function_entry class_Uri_WhatWg_Url_methods[] = {
ZEND_ME(Uri_WhatWg_Url, withPassword, arginfo_class_Uri_WhatWg_Url_withPassword, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_WhatWg_Url, getAsciiHost, arginfo_class_Uri_WhatWg_Url_getAsciiHost, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_WhatWg_Url, getUnicodeHost, arginfo_class_Uri_WhatWg_Url_getUnicodeHost, ZEND_ACC_PUBLIC)
- ZEND_ME(Uri_WhatWg_Url, withHost, arginfo_class_Uri_WhatWg_Url_withHost, ZEND_ACC_PUBLIC)
+ ZEND_RAW_FENTRY("withHost", zim_Uri_Rfc3986_Uri_withHost, arginfo_class_Uri_WhatWg_Url_withHost, ZEND_ACC_PUBLIC, NULL, NULL)
ZEND_RAW_FENTRY("getPort", zim_Uri_Rfc3986_Uri_getPort, arginfo_class_Uri_WhatWg_Url_getPort, ZEND_ACC_PUBLIC, NULL, NULL)
- ZEND_ME(Uri_WhatWg_Url, withPort, arginfo_class_Uri_WhatWg_Url_withPort, ZEND_ACC_PUBLIC)
+ ZEND_RAW_FENTRY("withPort", zim_Uri_Rfc3986_Uri_withPort, arginfo_class_Uri_WhatWg_Url_withPort, ZEND_ACC_PUBLIC, NULL, NULL)
ZEND_RAW_FENTRY("getPath", zim_Uri_Rfc3986_Uri_getPath, arginfo_class_Uri_WhatWg_Url_getPath, ZEND_ACC_PUBLIC, NULL, NULL)
- ZEND_ME(Uri_WhatWg_Url, withPath, arginfo_class_Uri_WhatWg_Url_withPath, ZEND_ACC_PUBLIC)
+ ZEND_RAW_FENTRY("withPath", zim_Uri_Rfc3986_Uri_withPath, arginfo_class_Uri_WhatWg_Url_withPath, ZEND_ACC_PUBLIC, NULL, NULL)
ZEND_RAW_FENTRY("getQuery", zim_Uri_Rfc3986_Uri_getQuery, arginfo_class_Uri_WhatWg_Url_getQuery, ZEND_ACC_PUBLIC, NULL, NULL)
- ZEND_ME(Uri_WhatWg_Url, withQuery, arginfo_class_Uri_WhatWg_Url_withQuery, ZEND_ACC_PUBLIC)
+ ZEND_RAW_FENTRY("withQuery", zim_Uri_Rfc3986_Uri_withQuery, arginfo_class_Uri_WhatWg_Url_withQuery, ZEND_ACC_PUBLIC, NULL, NULL)
ZEND_RAW_FENTRY("getFragment", zim_Uri_Rfc3986_Uri_getFragment, arginfo_class_Uri_WhatWg_Url_getFragment, ZEND_ACC_PUBLIC, NULL, NULL)
- ZEND_ME(Uri_WhatWg_Url, withFragment, arginfo_class_Uri_WhatWg_Url_withFragment, ZEND_ACC_PUBLIC)
+ ZEND_RAW_FENTRY("withFragment", zim_Uri_Rfc3986_Uri_withFragment, arginfo_class_Uri_WhatWg_Url_withFragment, ZEND_ACC_PUBLIC, NULL, NULL)
ZEND_ME(Uri_WhatWg_Url, equals, arginfo_class_Uri_WhatWg_Url_equals, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_WhatWg_Url, toAsciiString, arginfo_class_Uri_WhatWg_Url_toAsciiString, ZEND_ACC_PUBLIC)
ZEND_ME(Uri_WhatWg_Url, toUnicodeString, arginfo_class_Uri_WhatWg_Url_toUnicodeString, ZEND_ACC_PUBLIC)
@@ -322,6 +349,9 @@ static zend_class_entry *register_class_Uri_Rfc3986_Uri(void)
INIT_NS_CLASS_ENTRY(ce, "Uri\\Rfc3986", "Uri", class_Uri_Rfc3986_Uri_methods);
class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_READONLY_CLASS);
+
+ zend_add_parameter_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "withuserinfo", sizeof("withuserinfo") - 1), 0, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0);
+
return class_entry;
}
diff --git a/ext/uri/tests/023.phpt b/ext/uri/tests/023.phpt
index a1ca06bd6f6e5..e3a1324685219 100644
--- a/ext/uri/tests/023.phpt
+++ b/ext/uri/tests/023.phpt
@@ -5,6 +5,26 @@ uri
--FILE--
withScheme("http");
+$uri3 = $uri2->withScheme(null);
+
+var_dump($uri1->getScheme());
+var_dump($uri2->getScheme());
+var_dump($uri3->getScheme());
+
+try {
+ $uri3->withScheme("");
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ $uri3->withScheme("http%73");
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
$url1 = Uri\WhatWg\Url::parse("https://example.com");
$url2 = $url1->withScheme("http");
@@ -27,5 +47,10 @@ try {
--EXPECT--
string(5) "https"
string(4) "http"
+NULL
+The specified scheme is malformed
+The specified scheme is malformed
+string(5) "https"
+string(4) "http"
The specified scheme is malformed
The specified scheme is malformed
diff --git a/ext/uri/tests/026.phpt b/ext/uri/tests/026.phpt
index 47a8597fa2e7d..00c679ab87057 100644
--- a/ext/uri/tests/026.phpt
+++ b/ext/uri/tests/026.phpt
@@ -5,19 +5,75 @@ uri
--FILE--
withHost("test.com");
+$uri3 = $uri2->withHost("t%65st.com"); // test.com
+$uri4 = $uri3->withHost(null);
+$uri5 = $uri4->withHost("192.168.0.1");
+$uri6 = $uri5->withHost("[2001:db8:3333:4444:5555:6666:7777:8888]");
+
+var_dump($uri1->getHost());
+var_dump($uri2->getHost());
+var_dump($uri3->getHost());
+var_dump($uri3->getRawHost());
+var_dump($uri4->getRawHost());
+var_dump($uri5->getRawHost());
+var_dump($uri6->getRawHost());
+
+try {
+ $uri3->withHost("test.com:8080");
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ $uri3->withHost("t%3As%2Ft.com"); // t:s/t.com
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ $uri3->withHost("t:s/t.com"); // t:s/t.com
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ $uri2->withHost("");
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+$uri1 = Uri\Rfc3986\Uri::parse("ftp://user:pass@foo.com?query=abc#foo");
+$uri2 = $uri1->withHost("test.com");
+
+var_dump($uri1->getHost());
+var_dump($uri2->getHost());
+
+try {
+ $uri1->withHost(null);
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
$url1 = Uri\WhatWg\Url::parse("https://example.com");
$url2 = $url1->withHost("test.com");
$url3 = $url2->withHost("t%65st.com"); // test.com
+$url4 = $url3->withHost("192.168.0.1");
+$url5 = $url4->withHost("[2001:db8:3333:4444:5555:6666:7777:8888]");
+
+var_dump($url1->getAsciiHost());
+var_dump($url2->getAsciiHost());
+var_dump($url3->getAsciiHost());
+var_dump($url4->getAsciiHost());
+var_dump($url5->getAsciiHost());
+
try {
$url3->withHost("test.com:8080");
} catch (Uri\WhatWg\InvalidUrlException $e) {
echo $e->getMessage() . "\n";
}
-var_dump($url1->getAsciiHost());
-var_dump($url2->getAsciiHost());
-var_dump($url3->getAsciiHost());
-
try {
$url3->withHost("t%3As%2Ft.com"); // t:s/t.com
} catch (Uri\WhatWg\InvalidUrlException $e) {
@@ -44,10 +100,24 @@ var_dump($url2->getAsciiHost());
?>
--EXPECTF--
+string(11) "example.com"
+string(8) "test.com"
+string(8) "test.com"
+string(10) "t%65st.com"
+NULL
+string(11) "192.168.0.1"
+string(40) "[2001:db8:3333:4444:5555:6666:7777:8888]"
+The specified host is malformed
The specified host is malformed
+string(7) "foo.com"
+string(8) "test.com"
+Cannot remove the host from a URI that has a userinfo
string(11) "example.com"
string(8) "test.com"
string(8) "test.com"
+string(11) "192.168.0.1"
+string(40) "[2001:db8:3333:4444:5555:6666:7777:8888]"
+The specified host is malformed
The specified host is malformed (DomainInvalidCodePoint)
The specified host is malformed
The specified host is malformed (HostMissing)
diff --git a/ext/uri/tests/026_userinfo.phpt b/ext/uri/tests/026_userinfo.phpt
new file mode 100644
index 0000000000000..2eabc81061ef2
--- /dev/null
+++ b/ext/uri/tests/026_userinfo.phpt
@@ -0,0 +1,45 @@
+--TEST--
+Test property mutation - userinfo
+--EXTENSIONS--
+uri
+--FILE--
+withUserInfo("user");
+$uri3 = $uri2->withUserInfo(null);
+$uri4 = $uri3->withUserInfo("%75s%2Fr:pass"); // us/r:pass
+
+var_dump($uri1->getUserInfo());
+var_dump($uri2->getUserInfo());
+var_dump($uri3->getUserInfo());
+var_dump($uri4->getUserInfo());
+var_dump($uri4->getRawUserInfo());
+
+$uri1 = Uri\Rfc3986\Uri::parse("/foo");
+$uri2 = $uri1->withUserInfo(null);
+var_dump($uri2->getPort());
+
+try {
+ $uri4->withUserInfo("u:s/r");
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+$uri5 = Uri\Rfc3986\Uri::parse("file:///foo/bar/");
+$uri6 = $uri5->withUserinfo("user:pass");
+
+var_dump($uri5->getUserInfo());
+var_dump($uri6->getUserInfo());
+
+?>
+--EXPECT--
+NULL
+string(4) "user"
+NULL
+string(11) "us%2Fr:pass"
+string(13) "%75s%2Fr:pass"
+NULL
+The specified userinfo is malformed
+NULL
+string(9) "user:pass"
diff --git a/ext/uri/tests/027.phpt b/ext/uri/tests/027.phpt
index 79c121dd7f383..781932f5889ea 100644
--- a/ext/uri/tests/027.phpt
+++ b/ext/uri/tests/027.phpt
@@ -5,6 +5,36 @@ uri
--FILE--
withPort(22);
+$uri3 = $uri2->withPort(null);
+
+var_dump($uri1->getPort());
+var_dump($uri2->getPort());
+var_dump($uri3->getPort());
+
+$uri1 = Uri\Rfc3986\Uri::parse("ftp://foo.com:443?query=abc#foo");
+$uri2 = $uri1->withPort(8080);
+
+var_dump($uri1->getPort());
+var_dump($uri2->getPort());
+
+$uri1 = Uri\Rfc3986\Uri::parse("file:///foo/bar");
+$uri2 = $uri1->withPort(80);
+
+var_dump($uri1->getPort());
+var_dump($uri2->getPort());
+
+$uri1 = Uri\Rfc3986\Uri::parse("/foo");
+$uri2 = $uri1->withPort(null);
+var_dump($uri2->getPort());
+
+try {
+ $uri1->withPort(1);
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
$url1 = Uri\WhatWg\Url::parse("https://example.com:8080");
$url2 = $url1->withPort(22);
$url3 = $url2->withPort(null);
@@ -33,4 +63,13 @@ NULL
int(443)
int(8080)
NULL
+int(80)
+NULL
+Cannot set a port without having a host
+int(8080)
+int(22)
+NULL
+int(443)
+int(8080)
+NULL
NULL
diff --git a/ext/uri/tests/028.phpt b/ext/uri/tests/028.phpt
index fd565c900e02f..80f331c259379 100644
--- a/ext/uri/tests/028.phpt
+++ b/ext/uri/tests/028.phpt
@@ -5,6 +5,38 @@ uri
--FILE--
withPath("/foo");
+$uri3 = $uri2->withPath("/t%65st");
+$uri4 = $uri3->withPath("/foo%2Fbar");
+$uri5 = $uri4->withPath("");
+
+var_dump($uri1->getPath());
+var_dump($uri2->getPath());
+var_dump($uri3->getPath());
+var_dump($uri3->getRawPath());
+var_dump($uri4->getPath());
+var_dump($uri4->getRawPath());
+var_dump($uri5->getPath());
+
+try {
+ $uri5->withPath("test");
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ $uri5->withPath("/#");
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+$uri1 = Uri\Rfc3986\Uri::parse("/foo");
+$uri2 = $uri1->withPath("bar");
+
+var_dump($uri1->getPath());
+var_dump($uri2->getPath());
+
$url1 = Uri\WhatWg\Url::parse("https://example.com/foo/bar/");
$url2 = $url1->withPath("/foo");
$url3 = $url2->withPath("");
@@ -29,6 +61,17 @@ var_dump($url2->getPath());
--EXPECT--
string(9) "/foo/bar/"
string(4) "/foo"
+string(5) "/test"
+string(7) "/t%65st"
+string(10) "/foo%2Fbar"
+string(10) "/foo%2Fbar"
+string(0) ""
+The specified path is malformed
+The specified path is malformed
+string(4) "/foo"
+string(3) "bar"
+string(9) "/foo/bar/"
+string(4) "/foo"
string(1) "/"
string(7) "/t%65st"
string(10) "/foo%2Fbar"
diff --git a/ext/uri/tests/029.phpt b/ext/uri/tests/029.phpt
index e23008a65ad6a..99bb15eba6454 100644
--- a/ext/uri/tests/029.phpt
+++ b/ext/uri/tests/029.phpt
@@ -5,6 +5,33 @@ uri
--FILE--
withQuery("foo=baz");
+$uri3 = $uri2->withQuery(null);
+
+var_dump($uri1->getQuery());
+var_dump($uri2->getQuery());
+var_dump($uri3->getQuery());
+
+$uri1 = Uri\Rfc3986\Uri::parse("https://example.com");
+$uri2 = $uri1->withQuery("?foo=bar&foo=baz");
+$uri3 = $uri1->withQuery("foo=bar&foo=baz");
+$uri4 = $uri3->withQuery("t%65st");
+$uri5 = $uri4->withQuery("foo=foo%26bar&baz=/qux%3D");
+
+var_dump($uri1->getQuery());
+var_dump($uri2->getQuery());
+var_dump($uri3->getQuery());
+var_dump($uri4->getQuery());
+var_dump($uri4->getRawQuery());
+var_dump($uri5->getQuery());
+
+try {
+ $uri5->withQuery("#");
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
$url1 = Uri\WhatWg\Url::parse("https://example.com?foo=bar");
$url2 = $url1->withQuery("?foo=baz");
$url3 = $url2->withQuery(null);
@@ -33,6 +60,16 @@ string(7) "foo=bar"
string(7) "foo=baz"
NULL
NULL
+string(16) "?foo=bar&foo=baz"
+string(15) "foo=bar&foo=baz"
+string(4) "test"
+string(6) "t%65st"
+string(25) "foo=foo%26bar&baz=/qux%3D"
+The specified query is malformed
+string(7) "foo=bar"
+string(7) "foo=baz"
+NULL
+NULL
string(15) "foo=bar&foo=baz"
string(15) "foo=bar&foo=baz"
string(6) "t%65st"
diff --git a/ext/uri/tests/030.phpt b/ext/uri/tests/030.phpt
index 6bb85e6720c95..87714069b2882 100644
--- a/ext/uri/tests/030.phpt
+++ b/ext/uri/tests/030.phpt
@@ -5,6 +5,32 @@ uri
--FILE--
withFragment("fragment2");
+$uri3 = $uri2->withFragment(null);
+
+var_dump($uri1->getFragment());
+var_dump($uri2->getFragment());
+var_dump($uri3->getFragment());
+
+try {
+ $uri3->withFragment(" ");
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ $uri1->withFragment("#fragment2");
+} catch (Uri\InvalidUriException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+$uri1 = Uri\Rfc3986\Uri::parse("https://example.com?abc=def");
+$uri2 = $uri1->withFragment("fragment");
+
+var_dump($uri1->getFragment());
+var_dump($uri2->getFragment());
+
$url1 = Uri\WhatWg\Url::parse("https://example.com#fragment1");
$url2 = $url1->withFragment("#fragment2");
$url3 = $url2->withFragment(null);
@@ -26,6 +52,13 @@ var_dump($url2->getFragment());
string(9) "fragment1"
string(9) "fragment2"
NULL
+The specified fragment is malformed
+The specified fragment is malformed
+NULL
+string(8) "fragment"
+string(9) "fragment1"
+string(9) "fragment2"
+NULL
string(3) "%20"
NULL
string(8) "fragment"
diff --git a/ext/uri/tests/035.phpt b/ext/uri/tests/035.phpt
index 2712038d4e3d7..3c39870373742 100644
--- a/ext/uri/tests/035.phpt
+++ b/ext/uri/tests/035.phpt
@@ -11,6 +11,13 @@ try {
echo $e->getMessage() . "\n";
}
+$uri = new Uri\Rfc3986\Uri("https://example.com");
+try {
+ $uri->withHost("exam\0ple.com");
+} catch (Error $e) {
+ echo $e->getMessage() . "\n";
+}
+
try {
new Uri\WhatWg\Url("https://exam\0ple.com");
} catch (Error $e) {
@@ -27,5 +34,6 @@ try {
?>
--EXPECT--
Uri\Rfc3986\Uri::__construct(): Argument #1 ($uri) must not contain any null bytes
+Uri\Rfc3986\Uri::withHost(): Argument #1 ($host) must not contain any null bytes
Uri\WhatWg\Url::__construct(): Argument #1 ($uri) must not contain any null bytes
Uri\WhatWg\Url::withHost(): Argument #1 ($host) must not contain any null bytes
diff --git a/ext/uri/tests/057.phpt b/ext/uri/tests/057.phpt
index e2a109ccdacb9..458bdb468e341 100644
--- a/ext/uri/tests/057.phpt
+++ b/ext/uri/tests/057.phpt
@@ -14,7 +14,7 @@ try {
Uri\WhatWg\Url::parse(" https://example.org ", errors: $f->x);
} catch (Throwable $e) {
echo $e::class, ": ", $e->getMessage(), PHP_EOL;
-}
+}
?>
--EXPECT--
diff --git a/ext/uri/tests/059.phpt b/ext/uri/tests/059.phpt
new file mode 100644
index 0000000000000..971ebc7ee1bbf
--- /dev/null
+++ b/ext/uri/tests/059.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Test normalization after using RFC 3986 withers
+--EXTENSIONS--
+uri
+--FILE--
+getPath());
+var_dump($uri->getRawPath());
+
+$newUri = $uri->withPath('/updated-path');
+var_dump($newUri->getPath());
+var_dump($newUri->getRawPath());
+
+?>
+--EXPECT--
+string(14) "/path-example/"
+string(16) "/path-%65xample/"
+string(13) "/updated-path"
+string(13) "/updated-path"
diff --git a/ext/uri/uri_parser_rfc3986.c b/ext/uri/uri_parser_rfc3986.c
index f9581e6d93ed2..aab6ec80acf5f 100644
--- a/ext/uri/uri_parser_rfc3986.c
+++ b/ext/uri/uri_parser_rfc3986.c
@@ -99,6 +99,21 @@ ZEND_ATTRIBUTE_NONNULL static UriUriA *get_uri_for_reading(php_uri_parser_rfc398
}
}
+ZEND_ATTRIBUTE_NONNULL static UriUriA *get_uri_for_writing(uri_internal_t *internal_uri)
+{
+ php_uri_parser_rfc3986_uris *uriparser_uris = internal_uri->uri;
+
+ return &uriparser_uris->uri;
+}
+
+ZEND_ATTRIBUTE_NONNULL static void reset_normalized_uri_after_writing(uri_internal_t *internal_uri)
+{
+ php_uri_parser_rfc3986_uris *uriparser_uris = internal_uri->uri;
+
+ uriFreeUriMembersMmA(&uriparser_uris->normalized_uri, mm);
+ uriparser_uris->normalized_uri_initialized = false;
+}
+
ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_scheme_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode);
@@ -112,6 +127,27 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_scheme_read(con
return SUCCESS;
}
+static zend_result php_uri_parser_rfc3986_scheme_write(struct uri_internal_t *internal_uri, zval *value, zval *errors)
+{
+ UriUriA *uriparser_uri = get_uri_for_writing(internal_uri);
+ int result;
+
+ if (Z_TYPE_P(value) == IS_NULL) {
+ result = uriSetSchemeMmA(uriparser_uri, NULL, NULL, mm);
+ } else {
+ result = uriSetSchemeMmA(uriparser_uri, Z_STRVAL_P(value), Z_STRVAL_P(value) + Z_STRLEN_P(value), mm);
+ }
+
+ if (result != URI_SUCCESS) {
+ zend_throw_exception(uri_invalid_uri_exception_ce, "The specified scheme is malformed", 0);
+ return FAILURE;
+ }
+
+ reset_normalized_uri_after_writing(internal_uri);
+
+ return SUCCESS;
+}
+
ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_userinfo_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode);
@@ -125,6 +161,30 @@ ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_userinfo_read(const ur
return SUCCESS;
}
+zend_result php_uri_parser_rfc3986_userinfo_write(struct uri_internal_t *internal_uri, zval *value, zval *errors)
+{
+ UriUriA *uriparser_uri = get_uri_for_writing(internal_uri);
+ int result;
+
+ if (Z_TYPE_P(value) == IS_NULL) {
+ result = uriSetUserInfoMmA(uriparser_uri, NULL, NULL, mm);
+ } else {
+ result = uriSetUserInfoMmA(uriparser_uri, Z_STRVAL_P(value), Z_STRVAL_P(value) + Z_STRLEN_P(value), mm);
+ }
+
+ switch (result) {
+ case URI_SUCCESS:
+ reset_normalized_uri_after_writing(internal_uri);
+ return SUCCESS;
+ case URI_ERROR_SETUSERINFO_HOST_NOT_SET:
+ zend_throw_exception(uri_invalid_uri_exception_ce, "Cannot set a userinfo without having a host", 0);
+ return FAILURE;
+ default:
+ zend_throw_exception(uri_invalid_uri_exception_ce, "The specified userinfo is malformed", 0);
+ return FAILURE;
+ }
+}
+
ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_username_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode);
@@ -190,6 +250,33 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_host_read(const
return SUCCESS;
}
+static zend_result php_uri_parser_rfc3986_host_write(struct uri_internal_t *internal_uri, zval *value, zval *errors)
+{
+ UriUriA *uriparser_uri = get_uri_for_writing(internal_uri);
+ int result;
+
+ if (Z_TYPE_P(value) == IS_NULL) {
+ result = uriSetHostAutoMmA(uriparser_uri, NULL, NULL, mm);
+ } else {
+ result = uriSetHostAutoMmA(uriparser_uri, Z_STRVAL_P(value), Z_STRVAL_P(value) + Z_STRLEN_P(value), mm);
+ }
+
+ switch (result) {
+ case URI_SUCCESS:
+ reset_normalized_uri_after_writing(internal_uri);
+ return SUCCESS;
+ case URI_ERROR_SETHOST_PORT_SET:
+ zend_throw_exception(uri_invalid_uri_exception_ce, "Cannot remove the host from a URI that has a port", 0);
+ return FAILURE;
+ case URI_ERROR_SETHOST_USERINFO_SET:
+ zend_throw_exception(uri_invalid_uri_exception_ce, "Cannot remove the host from a URI that has a userinfo", 0);
+ return FAILURE;
+ default:
+ zend_throw_exception(uri_invalid_uri_exception_ce, "The specified host is malformed", 0);
+ return FAILURE;
+ }
+}
+
ZEND_ATTRIBUTE_NONNULL static zend_long port_str_to_zend_long_checked(const char *str, size_t len)
{
if (len > MAX_LENGTH_OF_LONG) {
@@ -221,6 +308,32 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_port_read(const
return SUCCESS;
}
+static zend_result php_uri_parser_rfc3986_port_write(struct uri_internal_t *internal_uri, zval *value, zval *errors)
+{
+ UriUriA *uriparser_uri = get_uri_for_writing(internal_uri);
+ int result;
+
+ if (Z_TYPE_P(value) == IS_NULL) {
+ result = uriSetPortTextMmA(uriparser_uri, NULL, NULL, mm);
+ } else {
+ zend_string *tmp = zend_long_to_str(Z_LVAL_P(value));
+ result = uriSetPortTextMmA(uriparser_uri, ZSTR_VAL(tmp), ZSTR_VAL(tmp) + ZSTR_LEN(tmp), mm);
+ zend_string_release(tmp);
+ }
+
+ switch (result) {
+ case URI_SUCCESS:
+ reset_normalized_uri_after_writing(internal_uri);
+ return SUCCESS;
+ case URI_ERROR_SETPORT_HOST_NOT_SET:
+ zend_throw_exception(uri_invalid_uri_exception_ce, "Cannot set a port without having a host", 0);
+ return FAILURE;
+ default:
+ zend_throw_exception(uri_invalid_uri_exception_ce, "The specified port is malformed", 0);
+ return FAILURE;
+ }
+}
+
ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_path_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode);
@@ -249,6 +362,27 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_path_read(const
return SUCCESS;
}
+static zend_result php_uri_parser_rfc3986_path_write(struct uri_internal_t *internal_uri, zval *value, zval *errors)
+{
+ UriUriA *uriparser_uri = get_uri_for_writing(internal_uri);
+ int result;
+
+ if (Z_STRLEN_P(value) == 0) {
+ result = uriSetPathMmA(uriparser_uri, NULL, NULL, mm);
+ } else {
+ result = uriSetPathMmA(uriparser_uri, Z_STRVAL_P(value), Z_STRVAL_P(value) + Z_STRLEN_P(value), mm);
+ }
+
+ if (result != URI_SUCCESS) {
+ zend_throw_exception(uri_invalid_uri_exception_ce, "The specified path is malformed", 0);
+ return FAILURE;
+ }
+
+ reset_normalized_uri_after_writing(internal_uri);
+
+ return SUCCESS;
+}
+
ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_query_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode);
@@ -262,6 +396,27 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_query_read(cons
return SUCCESS;
}
+static zend_result php_uri_parser_rfc3986_query_write(struct uri_internal_t *internal_uri, zval *value, zval *errors)
+{
+ UriUriA *uriparser_uri = get_uri_for_writing(internal_uri);
+ int result;
+
+ if (Z_TYPE_P(value) == IS_NULL) {
+ result = uriSetQueryMmA(uriparser_uri, NULL, NULL, mm);
+ } else {
+ result = uriSetQueryMmA(uriparser_uri, Z_STRVAL_P(value), Z_STRVAL_P(value) + Z_STRLEN_P(value), mm);
+ }
+
+ if (result != URI_SUCCESS) {
+ zend_throw_exception(uri_invalid_uri_exception_ce, "The specified query is malformed", 0);
+ return FAILURE;
+ }
+
+ reset_normalized_uri_after_writing(internal_uri);
+
+ return SUCCESS;
+}
+
ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_fragment_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode);
@@ -275,6 +430,27 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_fragment_read(c
return SUCCESS;
}
+static zend_result php_uri_parser_rfc3986_fragment_write(struct uri_internal_t *internal_uri, zval *value, zval *errors)
+{
+ UriUriA *uriparser_uri = get_uri_for_writing(internal_uri);
+ int result;
+
+ if (Z_TYPE_P(value) == IS_NULL) {
+ result = uriSetFragmentMmA(uriparser_uri, NULL, NULL, mm);
+ } else {
+ result = uriSetFragmentMmA(uriparser_uri, Z_STRVAL_P(value), Z_STRVAL_P(value) + Z_STRLEN_P(value), mm);
+ }
+
+ if (result != URI_SUCCESS) {
+ zend_throw_exception(uri_invalid_uri_exception_ce, "The specified fragment is malformed", 0);
+ return FAILURE;
+ }
+
+ reset_normalized_uri_after_writing(internal_uri);
+
+ return SUCCESS;
+}
+
static php_uri_parser_rfc3986_uris *uriparser_create_uris(void)
{
php_uri_parser_rfc3986_uris *uriparser_uris = ecalloc(1, sizeof(*uriparser_uris));
@@ -419,13 +595,13 @@ const uri_parser_t php_uri_parser_rfc3986 = {
.uri_to_string = php_uri_parser_rfc3986_to_string,
.free_uri = php_uri_parser_rfc3986_free,
{
- .scheme = {.read_func = php_uri_parser_rfc3986_scheme_read, .write_func = NULL},
+ .scheme = {.read_func = php_uri_parser_rfc3986_scheme_read, .write_func = php_uri_parser_rfc3986_scheme_write},
.username = {.read_func = php_uri_parser_rfc3986_username_read, .write_func = NULL},
.password = {.read_func = php_uri_parser_rfc3986_password_read, .write_func = NULL},
- .host = {.read_func = php_uri_parser_rfc3986_host_read, .write_func = NULL},
- .port = {.read_func = php_uri_parser_rfc3986_port_read, .write_func = NULL},
- .path = {.read_func = php_uri_parser_rfc3986_path_read, .write_func = NULL},
- .query = {.read_func = php_uri_parser_rfc3986_query_read, .write_func = NULL},
- .fragment = {.read_func = php_uri_parser_rfc3986_fragment_read, .write_func = NULL},
+ .host = {.read_func = php_uri_parser_rfc3986_host_read, .write_func = php_uri_parser_rfc3986_host_write},
+ .port = {.read_func = php_uri_parser_rfc3986_port_read, .write_func = php_uri_parser_rfc3986_port_write},
+ .path = {.read_func = php_uri_parser_rfc3986_path_read, .write_func = php_uri_parser_rfc3986_path_write},
+ .query = {.read_func = php_uri_parser_rfc3986_query_read, .write_func = php_uri_parser_rfc3986_query_write},
+ .fragment = {.read_func = php_uri_parser_rfc3986_fragment_read, .write_func = php_uri_parser_rfc3986_fragment_write},
}
};
diff --git a/ext/uri/uri_parser_rfc3986.h b/ext/uri/uri_parser_rfc3986.h
index 461136a9f06cc..7f54b194ec366 100644
--- a/ext/uri/uri_parser_rfc3986.h
+++ b/ext/uri/uri_parser_rfc3986.h
@@ -29,6 +29,7 @@ typedef struct php_uri_parser_rfc3986_uris {
} php_uri_parser_rfc3986_uris;
zend_result php_uri_parser_rfc3986_userinfo_read(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval);
+zend_result php_uri_parser_rfc3986_userinfo_write(struct uri_internal_t *internal_uri, zval *value, zval *errors);
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_url, bool silent);
diff --git a/ext/uri/uriparser/include/uriparser/Uri.h b/ext/uri/uriparser/include/uriparser/Uri.h
index 9f08559a1858f..f8abc09f8d4b0 100644
--- a/ext/uri/uriparser/include/uriparser/Uri.h
+++ b/ext/uri/uriparser/include/uriparser/Uri.h
@@ -134,7 +134,11 @@ typedef struct URI_TYPE(PathSegmentStruct) {
typedef struct URI_TYPE(HostDataStruct) {
UriIp4 * ip4; /**< IPv4 address */
UriIp6 * ip6; /**< IPv6 address */
- URI_TYPE(TextRange) ipFuture; /**< IPvFuture address */
+ URI_TYPE(TextRange) ipFuture; /**< IPvFuture address
+ @note
+ With non-NULL members in UriUriStructA.hostData context,
+ this text range's pointers must be idential to those
+ of UriUriStructA.hostText at all times. */
} URI_TYPE(HostData); /**< @copydoc UriHostDataStructA */
@@ -213,6 +217,48 @@ URI_PUBLIC UriBool URI_FUNC(HasHost)(const URI_TYPE(Uri) * uri);
+/**
+ * Converts an IPv6 text representation into 16 bytes.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param output OUT: Output destination, can be NULL
+ * @param first IN: First character of IPv6 text to parse
+ * @param afterLast IN: Position to stop parsing at
+ * @return Error code or URI_SUCCESS on success
+ *
+ * @see uriParseIpFourAddressA
+ * @see uriParseIpSixAddressMmA
+ * @see uriIsWellFormedHostIp6A
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(ParseIpSixAddress)(UriIp6 * output,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+
+
+/**
+ * Converts an IPv6 text representation into 16 bytes.
+ *
+ * @param output OUT: Output destination, can be NULL
+ * @param first IN: First character of IPv6 text to parse
+ * @param afterLast IN: Position to stop parsing at
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return Error code or URI_SUCCESS on success
+ *
+ * @see uriParseIpFourAddressA
+ * @see uriParseIpSixAddressA
+ * @see uriIsWellFormedHostIp6MmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(ParseIpSixAddressMm)(UriIp6 * output,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+
+
/**
* Parses a RFC 3986 %URI.
* Uses default libc-based memory manager.
@@ -1185,6 +1231,1178 @@ URI_PUBLIC int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri,
+/**
+ * Determines if the given text range contains a well-formed fragment
+ * according to RFC 3986 or not.
+ *
+ * @param first IN: Pointer to first character
+ * @param afterLast IN: Pointer to character after the last one still in
+ * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetFragmentA
+ * @see uriSetFragmentMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedFragment)(const URI_CHAR * first, const URI_CHAR * afterLast);
+
+
+
+/**
+ * Determines if the given text range contains a well-formed IPv4 address
+ * according to RFC 3986 or not.
+ *
+ * @param first IN: Pointer to first character
+ * @param afterLast IN: Pointer to character after the last one still in
+ * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp4MmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedHostIp4)(const URI_CHAR * first, const URI_CHAR * afterLast);
+
+
+
+/**
+ * Determines if the given text range contains a well-formed IPv6 address
+ * according to RFC 3986 or not.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param first IN: Pointer to first character
+ * @param afterLast IN: Pointer to character after the last one still in
+ * @return URI_SUCCESS if non-NULL and well-formed, else an error code
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6MmA
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriParseIpSixAddressA
+ * @see uriParseIpSixAddressMmA
+ * @since 0.9.9
+ */
+int URI_FUNC(IsWellFormedHostIp6)(const URI_CHAR * first, const URI_CHAR * afterLast);
+
+
+
+/**
+ * Determines if the given text range contains a well-formed IPv6 address
+ * according to RFC 3986 or not.
+ *
+ * @param first IN: Pointer to first character
+ * @param afterLast IN: Pointer to character after the last one still in
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return URI_SUCCESS if non-NULL and well-formed, else an error code
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureMmA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @since 0.9.9
+ */
+int URI_FUNC(IsWellFormedHostIp6Mm)(const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
+
+
+
+/**
+ * Determines if the given text range contains a well-formed IPvFuture address
+ * according to RFC 3986 or not.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param first IN: Pointer to first character
+ * @param afterLast IN: Pointer to character after the last one still in
+ * @return URI_SUCCESS if non-NULL and well-formed, else an error code
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureMmA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostIpFutureMmA
+ * @since 0.9.9
+ */
+int URI_FUNC(IsWellFormedHostIpFuture)(const URI_CHAR * first, const URI_CHAR * afterLast);
+
+
+
+/**
+ * Determines if the given text range contains a well-formed IPvFuture address
+ * according to RFC 3986 or not.
+ *
+ * @param first IN: Pointer to first character
+ * @param afterLast IN: Pointer to character after the last one still in
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return URI_SUCCESS if non-NULL and well-formed, else an error code
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostIpFutureMmA
+ * @since 0.9.9
+ */
+int URI_FUNC(IsWellFormedHostIpFutureMm)(const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
+
+
+
+/**
+ * Determines if the given text range contains a well-formed registered host name
+ * according to RFC 3986 or not.
+ *
+ * @param first IN: Pointer to first character
+ * @param afterLast IN: Pointer to character after the last one still in
+ * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetHostRegNameA
+ * @see uriSetHostRegNameMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedHostRegName)(const URI_CHAR * first, const URI_CHAR * afterLast);
+
+
+
+/**
+ * Determines if the given text range contains a well-formed path
+ * according to RFC 3986 or not.
+ *
+ * @param first IN: Pointer to first character
+ * @param afterLast IN: Pointer to character after the last one still in
+ * @param hasHost IN: Wether the target %URI has a non-NULL host set or not
+ * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetPathA
+ * @see uriSetPathMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedPath)(const URI_CHAR * first, const URI_CHAR * afterLast, UriBool hasHost);
+
+
+
+/**
+ * Determines if the given text range contains a well-formed port text
+ * according to RFC 3986 or not.
+ *
+ * @param first IN: Pointer to first character
+ * @param afterLast IN: Pointer to character after the last one still in
+ * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetPortTextA
+ * @see uriSetPortTextMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedPort)(const URI_CHAR * first, const URI_CHAR * afterLast);
+
+
+
+/**
+ * Determines if the given text range contains a well-formed query
+ * according to RFC 3986 or not.
+ *
+ * @param first IN: Pointer to first character
+ * @param afterLast IN: Pointer to character after the last one still in
+ * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetQueryA
+ * @see uriSetQueryMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedQuery)(const URI_CHAR * first, const URI_CHAR * afterLast);
+
+
+/**
+ * Determines if the given text range contains a well-formed scheme
+ * according to RFC 3986 or not.
+ *
+ * @param first IN: Pointer to first character
+ * @param afterLast IN: Pointer to character after the last one still in
+ * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetSchemeA
+ * @see uriSetSchemeMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedScheme)(const URI_CHAR * first, const URI_CHAR * afterLast);
+
+
+
+/**
+ * Determines if the given text range contains a well-formed user info
+ * according to RFC 3986 or not.
+ *
+ * @param first IN: Pointer to first character
+ * @param afterLast IN: Pointer to character after the last one still in
+ * @return URI_TRUE if non-NULL and well-formed, else URI_FALSE
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriSetUserInfoA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedUserInfo)(const URI_CHAR * first, const URI_CHAR * afterLast);
+
+
+
+/**
+ * Sets the fragment of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetFragment)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+
+
+/**
+ * Sets the fragment of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetFragmentMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIp6MmA
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostIpFutureMmA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostAuto)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIp6MmA
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostIpFutureMmA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostAutoMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostRegName)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostRegNameMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostIp4)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostIp4Mm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp6A
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostIp6)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp6A
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostIp6Mm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostIpFuture)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostIpFutureMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+
+
+/**
+ * Sets the path of the given %URI to the given value.
+ *
+ * Non-NULL values must start with a leading slash for %URIs that have a host.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedPathA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPathMmA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetPath)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+
+
+/**
+ * Sets the path of the given %URI to the given value.
+ *
+ * Non-NULL values must start with a leading slash for %URIs that have a host.
+ *
+ * The %URI must have a non-NULL host set.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedPathA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPathA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetPathMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+
+
+/**
+ * Sets the port text of the given %URI to the given value.
+ *
+ * The %URI must have a non-NULL host set.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedPortA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetPortText)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+
+
+/**
+ * Sets the port text of the given %URI to the given value.
+ *
+ * The %URI must have a non-NULL host set.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedPortA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetPortTextMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+
+
+/**
+ * Sets the query of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedQueryA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetQuery)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+
+
+/**
+ * Sets the query of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedQueryA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetQueryMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+
+
+/**
+ * Sets the scheme of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedSchemeA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetScheme)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+
+
+/**
+ * Sets the scheme of the given %URI to the given value.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedSchemeA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetSchemeMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+
+
+/**
+ * Sets the user info of the given %URI to the given value.
+ *
+ * The %URI must have a non-NULL host set.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetUserInfo)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+
+
+/**
+ * Sets the user info of the given %URI to the given value.
+ *
+ * The %URI must have a non-NULL host set.
+ *
+ * Parameters first and afterLast must both be NULL
+ * or non-NULL at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but URI_ERROR_MALLOC, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri INOUT: %URI to modify
+ * @param first IN: Pointer to first character, can be NULL
+ * @param afterLast IN: Pointer to character after the last one still in, can be NULL
+ * @param memory IN: Memory manager to use, NULL for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetUserInfoMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+
+
#ifdef __cplusplus
}
#endif
diff --git a/ext/uri/uriparser/include/uriparser/UriBase.h b/ext/uri/uriparser/include/uriparser/UriBase.h
index 46c02135bb112..f1820c96f8a8e 100644
--- a/ext/uri/uriparser/include/uriparser/UriBase.h
+++ b/ext/uri/uriparser/include/uriparser/UriBase.h
@@ -148,6 +148,17 @@ typedef int UriBool; /**< Boolean type */
/* Error specific to uriTestMemoryManager */
#define URI_ERROR_MEMORY_MANAGER_FAULTY 11 /* [>=0.9.0] The UriMemoryManager given did not pass the test suite */
+/* Error specific to uriSetUserInfo */
+#define URI_ERROR_SETUSERINFO_HOST_NOT_SET 12 /* [>=0.9.9] The %URI given does not have the host set */
+
+/* Error specific to uriSetPort */
+#define URI_ERROR_SETPORT_HOST_NOT_SET 13 /* [>=0.9.9] The %URI given does not have the host set */
+
+/* Error specific to uriSetHost* */
+#define URI_ERROR_SETHOST_USERINFO_SET 14 /* [>=0.9.9] The %URI given does have user info set */
+#define URI_ERROR_SETHOST_PORT_SET 15 /* [>=0.9.9] The %URI given does have a port set */
+
+
#ifndef URI_DOXYGEN
# include /* For NULL, snprintf */
diff --git a/ext/uri/uriparser/include/uriparser/UriIp4.h b/ext/uri/uriparser/include/uriparser/UriIp4.h
index c2e59a6bf2d13..4b847abe3ab7c 100644
--- a/ext/uri/uriparser/include/uriparser/UriIp4.h
+++ b/ext/uri/uriparser/include/uriparser/UriIp4.h
@@ -88,12 +88,15 @@ extern "C" {
/**
- * Converts a IPv4 text representation into four bytes.
+ * Converts an IPv4 text representation into four bytes.
*
* @param octetOutput Output destination
* @param first First character of IPv4 text to parse
* @param afterLast Position to stop parsing at
* @return Error code or 0 on success
+ *
+ * @see uriParseIpSixAddressA
+ * @see uriParseIpSixAddressMmA
*/
URI_PUBLIC int URI_FUNC(ParseIpFourAddress)(unsigned char * octetOutput,
const URI_CHAR * first, const URI_CHAR * afterLast);
diff --git a/ext/uri/uriparser/src/UriCommon.c b/ext/uri/uriparser/src/UriCommon.c
index ccec5d4d5c8bf..2d4e947088bc6 100644
--- a/ext/uri/uriparser/src/UriCommon.c
+++ b/ext/uri/uriparser/src/UriCommon.c
@@ -68,6 +68,10 @@
+#include
+
+
+
/*extern*/ const URI_CHAR * const URI_FUNC(SafeToPointTo) = _UT("X");
/*extern*/ const URI_CHAR * const URI_FUNC(ConstPwd) = _UT(".");
/*extern*/ const URI_CHAR * const URI_FUNC(ConstParent) = _UT("..");
@@ -83,6 +87,32 @@ void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri) {
+int URI_FUNC(FreeUriPath)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
+ assert(uri != NULL);
+ assert(memory != NULL);
+
+ if (uri->pathHead != NULL) {
+ URI_TYPE(PathSegment) * segWalk = uri->pathHead;
+ while (segWalk != NULL) {
+ URI_TYPE(PathSegment) * const next = segWalk->next;
+ if ((uri->owner == URI_TRUE) && (segWalk->text.first != segWalk->text.afterLast)) {
+ memory->free(memory, (URI_CHAR *)segWalk->text.first);
+ }
+ segWalk->text.first = NULL;
+ segWalk->text.afterLast = NULL;
+ segWalk->next = NULL;
+ memory->free(memory, segWalk);
+ segWalk = next;
+ }
+ uri->pathHead = NULL;
+ uri->pathTail = NULL;
+ }
+
+ return URI_SUCCESS;
+}
+
+
+
/* Compares two text ranges for equal text content */
int URI_FUNC(CompareRange)(
const URI_TYPE(TextRange) * a,
@@ -137,11 +167,11 @@ UriBool URI_FUNC(CopyRange)(URI_TYPE(TextRange) * destRange,
UriBool URI_FUNC(CopyRangeAsNeeded)(URI_TYPE(TextRange) * destRange,
- const URI_TYPE(TextRange) * sourceRange, UriBool useSafe, UriMemoryManager * memory) {
+ const URI_TYPE(TextRange) * sourceRange, UriMemoryManager * memory) {
if (sourceRange->first == NULL) {
destRange->first = NULL;
destRange->afterLast = NULL;
- } else if (sourceRange->first == sourceRange->afterLast && useSafe) {
+ } else if (sourceRange->first == sourceRange->afterLast) {
destRange->first = URI_FUNC(SafeToPointTo);
destRange->afterLast = URI_FUNC(SafeToPointTo);
} else {
@@ -464,14 +494,6 @@ unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig) {
-URI_CHAR URI_FUNC(HexToLetter)(unsigned int value) {
- /* Uppercase recommended in section 2.1. of RFC 3986 *
- * https://datatracker.ietf.org/doc/html/rfc3986#section-2.1 */
- return URI_FUNC(HexToLetterEx)(value, URI_TRUE);
-}
-
-
-
URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase) {
switch (value) {
case 0: return _UT('0');
@@ -498,11 +520,15 @@ URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase) {
/* Checks if a URI has the host component set. */
UriBool URI_FUNC(HasHost)(const URI_TYPE(Uri) * uri) {
+ /* NOTE: .hostData.ipFuture.first is not being checked, *
+ * because we do check .hostText.first and *
+ * .hostData.ipFuture.first has to be identical to *
+ * .hostText.first if set, and hence there is *
+ * no more information to be gained. */
return (uri != NULL)
&& ((uri->hostText.first != NULL)
|| (uri->hostData.ip4 != NULL)
|| (uri->hostData.ip6 != NULL)
- || (uri->hostData.ipFuture.first != NULL)
);
}
@@ -631,6 +657,130 @@ UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri,
+static UriBool URI_FUNC(PrependNewDotSegment)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
+ assert(uri != NULL);
+ assert(memory != NULL);
+
+ {
+ URI_TYPE(PathSegment) * const segment = memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment)));
+
+ if (segment == NULL) {
+ return URI_FALSE; /* i.e. raise malloc error */
+ }
+
+ segment->next = uri->pathHead;
+
+ {
+ URI_TYPE(TextRange) dotRange;
+ dotRange.first = URI_FUNC(ConstPwd);
+ dotRange.afterLast = URI_FUNC(ConstPwd) + 1;
+
+ if (uri->owner == URI_TRUE) {
+ if (URI_FUNC(CopyRange)(&(segment->text), &dotRange, memory) == URI_FALSE) {
+ memory->free(memory, segment);
+ return URI_FALSE; /* i.e. raise malloc error */
+ }
+ } else {
+ segment->text = dotRange; /* copies all members */
+ }
+ }
+
+ uri->pathHead = segment;
+ }
+
+ return URI_TRUE;
+}
+
+
+
+/* When dropping a scheme from a URI without a host and with a colon (":")
+ * in the first path segment, a consecutive reparse would rightfully
+ * mis-classify the first path segment as a scheme due to the colon.
+ * To protect against this case, we prepend an artifical "." segment
+ * to the path in here; the function is called after the scheme has
+ * just been dropped.
+ *
+ * 0. We start with parsed URI "scheme:path1:/path2/path3".
+ * 1. We drop the scheme naively and yield "path1:/path2/path3".
+ * 2. We prepend "." and yield unambiguous "./path1:/path2/path3".
+ *
+ * From the view of the RFC 3986 grammar, this is replacing rule path-rootless
+ * by path-noscheme content.
+ *
+ * Returns URI_TRUE for (a) nothing to do or (b) successful changes.
+ * Returns URI_FALSE to signal out-of-memory.
+ */
+UriBool URI_FUNC(FixPathNoScheme)(URI_TYPE(Uri) * uri,
+ UriMemoryManager * memory) {
+ assert(uri != NULL);
+ assert(memory != NULL);
+
+ if ((uri->absolutePath == URI_TRUE)
+ || (uri->pathHead == NULL)
+ || (uri->scheme.first != NULL)
+ || URI_FUNC(HasHost)(uri)) {
+ return URI_TRUE; /* i.e. nothing to do */
+ }
+
+ /* Check for troublesome first path segment containing a colon */
+ {
+ UriBool colonFound = URI_FALSE;
+ const URI_CHAR * walker = uri->pathHead->text.first;
+
+ while (walker < uri->pathHead->text.afterLast) {
+ if (walker[0] == _UT(':')) {
+ colonFound = URI_TRUE;
+ break;
+ }
+ walker++;
+ }
+
+ assert((walker == uri->pathHead->text.afterLast) || (colonFound == URI_TRUE));
+
+ if (colonFound == URI_FALSE) {
+ return URI_TRUE; /* i.e. nothing to do */
+ }
+ }
+
+ /* Insert "." segment in front */
+ return URI_FUNC(PrependNewDotSegment)(uri, memory);
+}
+
+
+
+/* When dropping a host from a URI without a scheme, an absolute path
+ * and and empty first path segment, a consecutive reparse would rightfully
+ * mis-classify the first path segment as a host marker due to the "//".
+ * To protect against this case, we prepend an artifical "." segment
+ * to the path in here; the function is called after the host has
+ * just been dropped.
+ *
+ * 0. We start with parsed URI "//host//path1/path2".
+ * 1. We drop the host naively and yield "//path1/path2".
+ * 2. We insert "./" and yield unambiguous "/.//path1/path2".
+ *
+ * Returns URI_TRUE for (a) nothing to do or (b) successful changes.
+ * Returns URI_FALSE to signal out-of-memory.
+ */
+UriBool URI_FUNC(EnsureThatPathIsNotMistakenForHost)(URI_TYPE(Uri) * uri,
+ UriMemoryManager * memory) {
+ assert(uri != NULL);
+ assert(memory != NULL);
+
+ if ((URI_FUNC(HasHost)(uri) == URI_TRUE)
+ || (uri->absolutePath == URI_FALSE)
+ || (uri->pathHead == NULL)
+ || (uri->pathHead == uri->pathTail) /* i.e. no second slash */
+ || (uri->pathHead->text.first != uri->pathHead->text.afterLast)) {
+ return URI_TRUE; /* i.e. nothing to do */
+ }
+
+ /* Insert "." segment in front */
+ return URI_FUNC(PrependNewDotSegment)(uri, memory);
+}
+
+
+
void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri,
UriMemoryManager * memory) {
/* Fix path if only one empty segment */
diff --git a/ext/uri/uriparser/src/UriCommon.h b/ext/uri/uriparser/src/UriCommon.h
index 8dffab9f9f602..96beb087a03d3 100644
--- a/ext/uri/uriparser/src/UriCommon.h
+++ b/ext/uri/uriparser/src/UriCommon.h
@@ -78,6 +78,8 @@ extern const URI_CHAR * const URI_FUNC(ConstParent);
void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri);
+int URI_FUNC(FreeUriPath)(URI_TYPE(Uri) * uri, UriMemoryManager * memory);
+
int URI_FUNC(CompareRange)(
const URI_TYPE(TextRange) * a,
const URI_TYPE(TextRange) * b);
@@ -85,7 +87,7 @@ int URI_FUNC(CompareRange)(
UriBool URI_FUNC(CopyRange)(URI_TYPE(TextRange) * destRange,
const URI_TYPE(TextRange) * sourceRange, UriMemoryManager * memory);
UriBool URI_FUNC(CopyRangeAsNeeded)(URI_TYPE(TextRange) * destRange,
- const URI_TYPE(TextRange) * sourceRange, UriBool useSafe, UriMemoryManager * memory);
+ const URI_TYPE(TextRange) * sourceRange, UriMemoryManager * memory);
UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri,
UriMemoryManager * memory);
@@ -93,7 +95,6 @@ UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri,
UriBool relative, UriBool pathOwned, UriMemoryManager * memory);
unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig);
-URI_CHAR URI_FUNC(HexToLetter)(unsigned int value);
URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase);
UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source,
@@ -102,6 +103,8 @@ UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest,
const URI_TYPE(Uri) * source, UriMemoryManager * memory);
UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri, UriMemoryManager * memory);
+UriBool URI_FUNC(FixPathNoScheme)(URI_TYPE(Uri) * uri, UriMemoryManager * memory);
+UriBool URI_FUNC(EnsureThatPathIsNotMistakenForHost)(URI_TYPE(Uri) * uri, UriMemoryManager * memory);
void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri,
UriMemoryManager * memory);
diff --git a/ext/uri/uriparser/src/UriConfig.h b/ext/uri/uriparser/src/UriConfig.h
index 3139da04f72c1..82b46c27ff804 100644
--- a/ext/uri/uriparser/src/UriConfig.h
+++ b/ext/uri/uriparser/src/UriConfig.h
@@ -41,7 +41,7 @@
-#define PACKAGE_VERSION "0.9.8"
+#define PACKAGE_VERSION "0.9.9"
/*
#define HAVE_WPRINTF*
diff --git a/ext/uri/uriparser/src/UriCopy.c b/ext/uri/uriparser/src/UriCopy.c
index 103e2e7796751..85f2a8aa17926 100644
--- a/ext/uri/uriparser/src/UriCopy.c
+++ b/ext/uri/uriparser/src/UriCopy.c
@@ -103,7 +103,7 @@ static void URI_FUNC(PreventLeakageAfterCopy)(URI_TYPE(Uri) * uri,
int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri,
const URI_TYPE(Uri) * sourceUri, UriMemoryManager * memory) {
- unsigned int doneMask = URI_NORMALIZED;
+ unsigned int revertMask = URI_NORMALIZED;
if (sourceUri == NULL || destUri == NULL) {
return URI_ERROR_NULL;
@@ -113,32 +113,32 @@ int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri,
URI_FUNC(ResetUri)(destUri);
- if (URI_FUNC(CopyRangeAsNeeded)(&destUri->scheme, &sourceUri->scheme, URI_FALSE, memory) == URI_FALSE) {
+ if (URI_FUNC(CopyRangeAsNeeded)(&destUri->scheme, &sourceUri->scheme, memory) == URI_FALSE) {
return URI_ERROR_MALLOC;
}
- doneMask |= URI_NORMALIZE_SCHEME;
+ revertMask |= URI_NORMALIZE_SCHEME;
- if (URI_FUNC(CopyRangeAsNeeded)(&destUri->userInfo, &sourceUri->userInfo, URI_FALSE, memory) == URI_FALSE) {
- URI_FUNC(PreventLeakageAfterCopy)(destUri, doneMask, memory);
+ if (URI_FUNC(CopyRangeAsNeeded)(&destUri->userInfo, &sourceUri->userInfo, memory) == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
return URI_ERROR_MALLOC;
}
- doneMask |= URI_NORMALIZE_USER_INFO;
+ revertMask |= URI_NORMALIZE_USER_INFO;
- if (URI_FUNC(CopyRangeAsNeeded)(&destUri->hostText, &sourceUri->hostText, URI_TRUE, memory) == URI_FALSE) {
- URI_FUNC(PreventLeakageAfterCopy)(destUri, doneMask, memory);
+ if (URI_FUNC(CopyRangeAsNeeded)(&destUri->hostText, &sourceUri->hostText, memory) == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
return URI_ERROR_MALLOC;
}
- doneMask |= URI_NORMALIZE_HOST;
+ revertMask |= URI_NORMALIZE_HOST;
if (sourceUri->hostData.ip4 == NULL) {
destUri->hostData.ip4 = NULL;
} else {
destUri->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4));
if (destUri->hostData.ip4 == NULL) {
- URI_FUNC(PreventLeakageAfterCopy)(destUri, doneMask, memory);
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
return URI_ERROR_MALLOC;
}
*(destUri->hostData.ip4) = *(sourceUri->hostData.ip4);
@@ -149,26 +149,26 @@ int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri,
} else {
destUri->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6));
if (destUri->hostData.ip6 == NULL) {
- URI_FUNC(PreventLeakageAfterCopy)(destUri, doneMask, memory);
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
return URI_ERROR_MALLOC;
}
*(destUri->hostData.ip6) = *(sourceUri->hostData.ip6);
}
- if (sourceUri->hostData.ipFuture.first != NULL && sourceUri->hostText.first == sourceUri->hostData.ipFuture.first) {
+ if (sourceUri->hostData.ipFuture.first != NULL) {
destUri->hostData.ipFuture.first = destUri->hostText.first;
destUri->hostData.ipFuture.afterLast = destUri->hostText.afterLast;
- } else if (URI_FUNC(CopyRangeAsNeeded)(&destUri->hostData.ipFuture, &sourceUri->hostData.ipFuture, URI_FALSE, memory) == URI_FALSE) {
- URI_FUNC(PreventLeakageAfterCopy)(destUri, doneMask, memory);
+ } else if (URI_FUNC(CopyRangeAsNeeded)(&destUri->hostData.ipFuture, &sourceUri->hostData.ipFuture, memory) == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
return URI_ERROR_MALLOC;
}
- if (URI_FUNC(CopyRangeAsNeeded)(&destUri->portText, &sourceUri->portText, URI_FALSE, memory) == URI_FALSE) {
- URI_FUNC(PreventLeakageAfterCopy)(destUri, doneMask, memory);
+ if (URI_FUNC(CopyRangeAsNeeded)(&destUri->portText, &sourceUri->portText, memory) == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
return URI_ERROR_MALLOC;
}
- doneMask |= URI_NORMALIZE_PORT;
+ revertMask |= URI_NORMALIZE_PORT;
destUri->pathHead = NULL;
destUri->pathTail = NULL;
@@ -180,7 +180,7 @@ int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri,
while (sourceWalker != NULL) {
URI_TYPE(PathSegment) * destWalker = memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
if (destWalker == NULL) {
- URI_FUNC(PreventLeakageAfterCopy)(destUri, doneMask, memory);
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
return URI_ERROR_MALLOC;
}
@@ -191,11 +191,11 @@ int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri,
if (destUri->pathHead == NULL) {
destUri->pathHead = destWalker;
- doneMask |= URI_NORMALIZE_PATH;
+ revertMask |= URI_NORMALIZE_PATH;
}
- if (URI_FUNC(CopyRangeAsNeeded)(&destWalker->text, &sourceWalker->text, URI_TRUE, memory) == URI_FALSE) {
- URI_FUNC(PreventLeakageAfterCopy)(destUri, doneMask, memory);
+ if (URI_FUNC(CopyRangeAsNeeded)(&destWalker->text, &sourceWalker->text, memory) == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
return URI_ERROR_MALLOC;
}
@@ -210,15 +210,15 @@ int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri,
}
}
- if (URI_FUNC(CopyRangeAsNeeded)(&destUri->query, &sourceUri->query, URI_FALSE, memory) == URI_FALSE) {
- URI_FUNC(PreventLeakageAfterCopy)(destUri, doneMask, memory);
+ if (URI_FUNC(CopyRangeAsNeeded)(&destUri->query, &sourceUri->query, memory) == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
return URI_ERROR_MALLOC;
}
- doneMask |= URI_NORMALIZE_QUERY;
+ revertMask |= URI_NORMALIZE_QUERY;
- if (URI_FUNC(CopyRangeAsNeeded)(&destUri->fragment, &sourceUri->fragment, URI_FALSE, memory) == URI_FALSE) {
- URI_FUNC(PreventLeakageAfterCopy)(destUri, doneMask, memory);
+ if (URI_FUNC(CopyRangeAsNeeded)(&destUri->fragment, &sourceUri->fragment, memory) == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
return URI_ERROR_MALLOC;
}
diff --git a/ext/uri/uriparser/src/UriEscape.c b/ext/uri/uriparser/src/UriEscape.c
index ab8305fa9735c..366955f4adad4 100644
--- a/ext/uri/uriparser/src/UriEscape.c
+++ b/ext/uri/uriparser/src/UriEscape.c
@@ -229,9 +229,12 @@ URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst,
/* Percent encode */
{
const unsigned char code = (unsigned char)read[0];
+ /* Uppercase recommended in (last sentence of) section 2.1 *
+ * of RFC 3986: *
+ * https://datatracker.ietf.org/doc/html/rfc3986#section-2.1 */
write[0] = _UT('%');
- write[1] = URI_FUNC(HexToLetter)(code >> 4);
- write[2] = URI_FUNC(HexToLetter)(code & 0x0f);
+ write[1] = URI_FUNC(HexToLetterEx)(code >> 4, URI_TRUE);
+ write[2] = URI_FUNC(HexToLetterEx)(code & 0x0f, URI_TRUE);
write += 3;
}
prevWasCr = URI_FALSE;
diff --git a/ext/uri/uriparser/src/UriNormalize.c b/ext/uri/uriparser/src/UriNormalize.c
index 56b19573665e5..631d9a05a4d95 100644
--- a/ext/uri/uriparser/src/UriNormalize.c
+++ b/ext/uri/uriparser/src/UriNormalize.c
@@ -83,11 +83,11 @@
static int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri, unsigned int inMask,
unsigned int * outMask, UriMemoryManager * memory);
-static UriBool URI_FUNC(MakeRangeOwner)(unsigned int * doneMask,
+static UriBool URI_FUNC(MakeRangeOwner)(unsigned int * revertMask,
unsigned int maskTest, URI_TYPE(TextRange) * range,
UriMemoryManager * memory);
static UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri,
- unsigned int * doneMask, UriMemoryManager * memory);
+ unsigned int * revertMask, UriMemoryManager * memory);
static void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * first,
const URI_CHAR ** afterLast);
@@ -329,10 +329,10 @@ static URI_INLINE void URI_FUNC(FixPercentEncodingEngine)(
write++;
} else {
/* 6.2.2.1 Case Normalization: *
- * lowercase percent-encodings */
+ * uppercase percent-encodings */
write[0] = _UT('%');
- write[1] = URI_FUNC(HexToLetter)(left);
- write[2] = URI_FUNC(HexToLetter)(right);
+ write[1] = URI_FUNC(HexToLetterEx)(left, URI_TRUE);
+ write[2] = URI_FUNC(HexToLetterEx)(right, URI_TRUE);
write += 3;
}
@@ -397,17 +397,17 @@ static URI_INLINE UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** f
-static URI_INLINE UriBool URI_FUNC(MakeRangeOwner)(unsigned int * doneMask,
+static URI_INLINE UriBool URI_FUNC(MakeRangeOwner)(unsigned int * revertMask,
unsigned int maskTest, URI_TYPE(TextRange) * range,
UriMemoryManager * memory) {
- if (((*doneMask & maskTest) == 0)
+ if (((*revertMask & maskTest) == 0)
&& (range->first != NULL)
&& (range->afterLast != NULL)
&& (range->afterLast > range->first)) {
if (URI_FUNC(CopyRange)(range, range, memory) == URI_FALSE) {
return URI_FALSE;
}
- *doneMask |= maskTest;
+ *revertMask |= maskTest;
}
return URI_TRUE;
}
@@ -415,24 +415,24 @@ static URI_INLINE UriBool URI_FUNC(MakeRangeOwner)(unsigned int * doneMask,
static URI_INLINE UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri,
- unsigned int * doneMask, UriMemoryManager * memory) {
+ unsigned int * revertMask, UriMemoryManager * memory) {
URI_TYPE(PathSegment) * walker = uri->pathHead;
- if (!URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_SCHEME,
+ if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_SCHEME,
&(uri->scheme), memory)
- || !URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_USER_INFO,
+ || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_USER_INFO,
&(uri->userInfo), memory)
- || !URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_QUERY,
+ || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_QUERY,
&(uri->query), memory)
- || !URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_FRAGMENT,
+ || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_FRAGMENT,
&(uri->fragment), memory)) {
return URI_FALSE; /* Raises malloc error */
}
/* Host */
- if ((*doneMask & URI_NORMALIZE_HOST) == 0) {
+ if ((*revertMask & URI_NORMALIZE_HOST) == 0) {
if (uri->hostData.ipFuture.first != NULL) {
/* IPvFuture */
- if (!URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_HOST,
+ if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_HOST,
&(uri->hostData.ipFuture), memory)) {
return URI_FALSE; /* Raises malloc error */
}
@@ -440,7 +440,7 @@ static URI_INLINE UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri,
uri->hostText.afterLast = uri->hostData.ipFuture.afterLast;
} else if (uri->hostText.first != NULL) {
/* Regname */
- if (!URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_HOST,
+ if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_HOST,
&(uri->hostText), memory)) {
return URI_FALSE; /* Raises malloc error */
}
@@ -448,9 +448,9 @@ static URI_INLINE UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri,
}
/* Path */
- if ((*doneMask & URI_NORMALIZE_PATH) == 0) {
+ if ((*revertMask & URI_NORMALIZE_PATH) == 0) {
while (walker != NULL) {
- if (!URI_FUNC(MakeRangeOwner)(doneMask, 0, &(walker->text), memory)) {
+ if (!URI_FUNC(MakeRangeOwner)(revertMask, 0, &(walker->text), memory)) {
/* Free allocations done so far and kill path */
/* Kill path to one before walker (if any) */
@@ -479,13 +479,13 @@ static URI_INLINE UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri,
}
walker = walker->next;
}
- *doneMask |= URI_NORMALIZE_PATH;
+ *revertMask |= URI_NORMALIZE_PATH;
}
/* Port text, must come last so we don't have to undo that one if it fails. *
* Otherwise we would need and extra enum flag for it although the port *
* cannot go unnormalized... */
- if (!URI_FUNC(MakeRangeOwner)(doneMask, 0, &(uri->portText), memory)) {
+ if (!URI_FUNC(MakeRangeOwner)(revertMask, 0, &(uri->portText), memory)) {
return URI_FALSE; /* Raises malloc error */
}
@@ -621,7 +621,7 @@ static void URI_FUNC(AdvancePastLeadingZeros)(
static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
unsigned int inMask, unsigned int * outMask,
UriMemoryManager * memory) {
- unsigned int doneMask = URI_NORMALIZED;
+ unsigned int revertMask = URI_NORMALIZED;
/* Not just doing inspection? -> memory manager required! */
if (outMask == NULL) {
@@ -671,10 +671,10 @@ static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
URI_FUNC(LowercaseInplace)(uri->scheme.first, uri->scheme.afterLast);
} else {
if (!URI_FUNC(LowercaseMalloc)(&(uri->scheme.first), &(uri->scheme.afterLast), memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
return URI_ERROR_MALLOC;
}
- doneMask |= URI_NORMALIZE_SCHEME;
+ revertMask |= URI_NORMALIZE_SCHEME;
}
}
@@ -688,10 +688,10 @@ static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
} else {
if (!URI_FUNC(LowercaseMalloc)(&(uri->hostData.ipFuture.first),
&(uri->hostData.ipFuture.afterLast), memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
return URI_ERROR_MALLOC;
}
- doneMask |= URI_NORMALIZE_HOST;
+ revertMask |= URI_NORMALIZE_HOST;
}
uri->hostText.first = uri->hostData.ipFuture.first;
uri->hostText.afterLast = uri->hostData.ipFuture.afterLast;
@@ -706,10 +706,10 @@ static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
&(uri->hostText.first),
&(uri->hostText.afterLast),
memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
return URI_ERROR_MALLOC;
}
- doneMask |= URI_NORMALIZE_HOST;
+ revertMask |= URI_NORMALIZE_HOST;
}
URI_FUNC(LowercaseInplaceExceptPercentEncoding)(uri->hostText.first,
@@ -753,10 +753,10 @@ static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
} else {
if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->userInfo.first),
&(uri->userInfo.afterLast), memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
return URI_ERROR_MALLOC;
}
- doneMask |= URI_NORMALIZE_USER_INFO;
+ revertMask |= URI_NORMALIZE_USER_INFO;
}
}
}
@@ -801,20 +801,20 @@ static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
while (walker != NULL) {
if (!URI_FUNC(FixPercentEncodingMalloc)(&(walker->text.first),
&(walker->text.afterLast), memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
return URI_ERROR_MALLOC;
}
walker = walker->next;
}
- doneMask |= URI_NORMALIZE_PATH;
+ revertMask |= URI_NORMALIZE_PATH;
}
/* 6.2.2.3 Path Segment Normalization */
if (!URI_FUNC(RemoveDotSegmentsEx)(uri, relative,
(uri->owner == URI_TRUE)
- || ((doneMask & URI_NORMALIZE_PATH) != 0),
+ || ((revertMask & URI_NORMALIZE_PATH) != 0),
memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
return URI_ERROR_MALLOC;
}
URI_FUNC(FixEmptyTrailSegment)(uri, memory);
@@ -841,10 +841,10 @@ static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
} else {
if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->query.first),
&(uri->query.afterLast), memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
return URI_ERROR_MALLOC;
}
- doneMask |= URI_NORMALIZE_QUERY;
+ revertMask |= URI_NORMALIZE_QUERY;
}
}
@@ -855,18 +855,18 @@ static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
} else {
if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->fragment.first),
&(uri->fragment.afterLast), memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
return URI_ERROR_MALLOC;
}
- doneMask |= URI_NORMALIZE_FRAGMENT;
+ revertMask |= URI_NORMALIZE_FRAGMENT;
}
}
}
/* Dup all not duped yet */
if ((outMask == NULL) && !uri->owner) {
- if (!URI_FUNC(MakeOwnerEngine)(uri, &doneMask, memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
+ if (!URI_FUNC(MakeOwnerEngine)(uri, &revertMask, memory)) {
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
return URI_ERROR_MALLOC;
}
uri->owner = URI_TRUE;
@@ -878,7 +878,7 @@ static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
- unsigned int doneMask = URI_NORMALIZED;
+ unsigned int revertMask = URI_NORMALIZED;
URI_CHECK_MEMORY_MANAGER(memory); /* may return */
@@ -890,8 +890,8 @@ int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
return URI_SUCCESS;
}
- if (! URI_FUNC(MakeOwnerEngine)(uri, &doneMask, memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
+ if (! URI_FUNC(MakeOwnerEngine)(uri, &revertMask, memory)) {
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
return URI_ERROR_MALLOC;
}
diff --git a/ext/uri/uriparser/src/UriParse.c b/ext/uri/uriparser/src/UriParse.c
index a672c8eb1f2fc..8bb18f65ac166 100644
--- a/ext/uri/uriparser/src/UriParse.c
+++ b/ext/uri/uriparser/src/UriParse.c
@@ -480,7 +480,7 @@ static const URI_CHAR * URI_FUNC(ParseIpFuture)(URI_TYPE(ParserState) * state,
case _UT('v'):
case _UT('V'):
*/
- if (first + 1 >= afterLast) {
+ if (afterLast - first < 2) {
URI_FUNC(StopSyntax)(state, afterLast, memory);
return NULL;
}
@@ -755,7 +755,7 @@ static const URI_CHAR * URI_FUNC(ParseIPv6address2)(
}
/* "::"? */
- if (first + 1 >= afterLast) {
+ if (afterLast - first < 2) {
URI_FUNC(StopSyntax)(state, afterLast, memory);
return NULL;
}
@@ -773,7 +773,7 @@ static const URI_CHAR * URI_FUNC(ParseIPv6address2)(
setZipper = 1;
/* ":::+"? */
- if (first + 1 >= afterLast) {
+ if (afterLast - first < 2) {
URI_FUNC(StopSyntax)(state, afterLast, memory);
return NULL; /* No ']' yet */
}
@@ -1583,14 +1583,14 @@ static const URI_CHAR * URI_FUNC(ParsePctEncoded)(
switch (*first) {
case _UT('%'):
*/
- if (first + 1 >= afterLast) {
+ if (afterLast - first < 2) {
URI_FUNC(StopSyntax)(state, afterLast, memory);
return NULL;
}
switch (first[1]) {
case URI_SET_HEXDIG:
- if (first + 2 >= afterLast) {
+ if (afterLast - first < 3) {
URI_FUNC(StopSyntax)(state, afterLast, memory);
return NULL;
}
@@ -2286,12 +2286,10 @@ int URI_FUNC(FreeUriMembersMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
/* Host data - IPvFuture (may affect host text) */
if (uri->hostData.ipFuture.first != NULL) {
- /* NOTE: .hostData.ipFuture may hold the very same range pointers
- * as .hostText; then we need to prevent freeing memory twice. */
- if (uri->hostText.first == uri->hostData.ipFuture.first) {
- uri->hostText.first = NULL;
- uri->hostText.afterLast = NULL;
- }
+ /* NOTE: .hostData.ipFuture holds the very same range pointers
+ * as .hostText; we must not free memory twice. */
+ uri->hostText.first = NULL;
+ uri->hostText.afterLast = NULL;
if (uri->hostData.ipFuture.first != uri->hostData.ipFuture.afterLast) {
memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first);
@@ -2332,20 +2330,7 @@ int URI_FUNC(FreeUriMembersMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
}
/* Path */
- if (uri->pathHead != NULL) {
- URI_TYPE(PathSegment) * segWalk = uri->pathHead;
- while (segWalk != NULL) {
- URI_TYPE(PathSegment) * const next = segWalk->next;
- if (uri->owner && (segWalk->text.first != NULL)
- && (segWalk->text.first < segWalk->text.afterLast)) {
- memory->free(memory, (URI_CHAR *)segWalk->text.first);
- }
- memory->free(memory, segWalk);
- segWalk = next;
- }
- uri->pathHead = NULL;
- uri->pathTail = NULL;
- }
+ URI_FUNC(FreeUriPath)(uri, memory);
if (uri->owner) {
/* Query */
diff --git a/ext/uri/uriparser/src/UriSetFragment.c b/ext/uri/uriparser/src/UriSetFragment.c
new file mode 100644
index 0000000000000..f2327c1afa4d0
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetFragment.c
@@ -0,0 +1,306 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetFragment.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetFragment.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include
+# else
+# include
+# include
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include
+# include "UriCommon.h"
+# include "UriMemory.h"
+#endif
+
+
+
+#include
+
+
+
+#define URI_SET_DIGIT \
+ _UT('0'): \
+ case _UT('1'): \
+ case _UT('2'): \
+ case _UT('3'): \
+ case _UT('4'): \
+ case _UT('5'): \
+ case _UT('6'): \
+ case _UT('7'): \
+ case _UT('8'): \
+ case _UT('9')
+
+
+
+#define URI_SET_HEX_LETTER_UPPER \
+ _UT('A'): \
+ case _UT('B'): \
+ case _UT('C'): \
+ case _UT('D'): \
+ case _UT('E'): \
+ case _UT('F')
+
+
+
+#define URI_SET_HEX_LETTER_LOWER \
+ _UT('a'): \
+ case _UT('b'): \
+ case _UT('c'): \
+ case _UT('d'): \
+ case _UT('e'): \
+ case _UT('f')
+
+
+
+#define URI_SET_HEXDIG \
+ URI_SET_DIGIT: \
+ case URI_SET_HEX_LETTER_UPPER: \
+ case URI_SET_HEX_LETTER_LOWER
+
+
+
+#define URI_SET_ALPHA \
+ URI_SET_HEX_LETTER_UPPER: \
+ case URI_SET_HEX_LETTER_LOWER: \
+ case _UT('g'): \
+ case _UT('G'): \
+ case _UT('h'): \
+ case _UT('H'): \
+ case _UT('i'): \
+ case _UT('I'): \
+ case _UT('j'): \
+ case _UT('J'): \
+ case _UT('k'): \
+ case _UT('K'): \
+ case _UT('l'): \
+ case _UT('L'): \
+ case _UT('m'): \
+ case _UT('M'): \
+ case _UT('n'): \
+ case _UT('N'): \
+ case _UT('o'): \
+ case _UT('O'): \
+ case _UT('p'): \
+ case _UT('P'): \
+ case _UT('q'): \
+ case _UT('Q'): \
+ case _UT('r'): \
+ case _UT('R'): \
+ case _UT('s'): \
+ case _UT('S'): \
+ case _UT('t'): \
+ case _UT('T'): \
+ case _UT('u'): \
+ case _UT('U'): \
+ case _UT('v'): \
+ case _UT('V'): \
+ case _UT('w'): \
+ case _UT('W'): \
+ case _UT('x'): \
+ case _UT('X'): \
+ case _UT('y'): \
+ case _UT('Y'): \
+ case _UT('z'): \
+ case _UT('Z')
+
+
+
+#define URI_SET_SUB_DELIMS \
+ _UT('!'): \
+ case _UT('$'): \
+ case _UT('&'): \
+ case _UT('\''): \
+ case _UT('('): \
+ case _UT(')'): \
+ case _UT('*'): \
+ case _UT('+'): \
+ case _UT(','): \
+ case _UT(';'): \
+ case _UT('=')
+
+
+
+#define URI_SET_UNRESERVED \
+ URI_SET_ALPHA: \
+ case URI_SET_DIGIT: \
+ case _UT('-'): \
+ case _UT('.'): \
+ case _UT('_'): \
+ case _UT('~')
+
+
+
+UriBool URI_FUNC(IsWellFormedFragment)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ /* The related part of the grammar in RFC 3986 reads:
+ *
+ * fragment = *( pchar / "/" / "?" )
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ */
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_UNRESERVED:
+ break;
+
+ /* pct-encoded */
+ case _UT('%'):
+ if (afterLast - first < 3) {
+ return URI_FALSE;
+ }
+ switch (first[1]) {
+ case URI_SET_HEXDIG:
+ break;
+ default:
+ return URI_FALSE;
+ }
+ switch (first[2]) {
+ case URI_SET_HEXDIG:
+ break;
+ default:
+ return URI_FALSE;
+ }
+ first += 2;
+ break;
+
+ case URI_SET_SUB_DELIMS:
+ break;
+
+ /* ":" / "@" and "/" / "?" */
+ case _UT(':'):
+ case _UT('@'):
+ case _UT('/'):
+ case _UT('?'):
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+ }
+ return URI_TRUE;
+}
+
+
+
+int URI_FUNC(SetFragmentMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ /* Input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ if ((first != NULL) && (URI_FUNC(IsWellFormedFragment)(first, afterLast) == URI_FALSE)) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Clear old value */
+ if ((uri->owner == URI_TRUE) && (uri->fragment.first != uri->fragment.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->fragment.first);
+ }
+ uri->fragment.first = NULL;
+ uri->fragment.afterLast = NULL;
+
+ /* Already done? */
+ if (first == NULL) {
+ return URI_SUCCESS;
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ const int res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value */
+ {
+ URI_TYPE(TextRange) sourceRange;
+ sourceRange.first = first;
+ sourceRange.afterLast = afterLast;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&uri->fragment, &sourceRange, memory) == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+ }
+
+ return URI_SUCCESS;
+}
+
+
+
+int URI_FUNC(SetFragment)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetFragmentMm)(uri, first, afterLast, NULL);
+}
+
+
+
+#endif
diff --git a/ext/uri/uriparser/src/UriSetHostAuto.c b/ext/uri/uriparser/src/UriSetHostAuto.c
new file mode 100644
index 0000000000000..628b532aa2a5a
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetHostAuto.c
@@ -0,0 +1,155 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostAuto.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostAuto.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include
+# else
+# include
+# include
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include
+# include "UriSetHostBase.h"
+# include "UriSetHostCommon.h"
+# include "UriMemory.h"
+#endif
+
+
+
+#include
+
+
+
+int URI_FUNC(SetHostAutoMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ if ((first == NULL) || (first >= afterLast)) {
+ return URI_FUNC(SetHostRegNameMm)(uri, first, afterLast, memory);
+ }
+
+ /* Auto-detect type and then apply */
+ {
+ UriHostType hostType;
+
+ /* IPv6 or IPvFuture? */
+ if (first[0] == _UT('[')) {
+ if ((afterLast - first < 2) || (afterLast[-1] != _UT(']'))) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Drop the bracket wrap */
+ first++;
+ afterLast--;
+
+ if (first >= afterLast) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ switch (first[0]) {
+ case _UT('v'):
+ case _UT('V'):
+ {
+ /* IPvFuture or malformed */
+ const int res = URI_FUNC(IsWellFormedHostIpFutureMm)(first, afterLast, memory);
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC));
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ hostType = URI_HOST_TYPE_IPFUTURE;
+ }
+ break;
+ default:
+ {
+ /* IPv6 or malformed */
+ const int res = URI_FUNC(IsWellFormedHostIp6Mm)(first, afterLast, memory);
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC));
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ hostType = URI_HOST_TYPE_IP6;
+ }
+ break;
+ }
+ /* IPv4? */
+ } else if (URI_FUNC(IsWellFormedHostIp4)(first, afterLast)) {
+ hostType = URI_HOST_TYPE_IP4;
+ } else {
+ /* RegName! */
+ hostType = URI_HOST_TYPE_REGNAME;
+ }
+
+ return URI_FUNC(InternalSetHostMm)(uri, hostType, first, afterLast, memory);
+ }
+}
+
+
+
+int URI_FUNC(SetHostAuto)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetHostAutoMm)(uri, first, afterLast, NULL);
+}
+
+
+
+#endif
diff --git a/ext/uri/uriparser/src/UriSetHostBase.h b/ext/uri/uriparser/src/UriSetHostBase.h
new file mode 100644
index 0000000000000..79b643cc0c4b0
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetHostBase.h
@@ -0,0 +1,53 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef URI_SET_HOST_BASE_H
+#define URI_SET_HOST_BASE_H 1
+
+
+
+typedef enum UriHostTypeEnum {
+ URI_HOST_TYPE_IP4,
+ URI_HOST_TYPE_IP6,
+ URI_HOST_TYPE_IPFUTURE,
+ URI_HOST_TYPE_REGNAME
+} UriHostType;
+
+
+
+#endif /* URI_SET_HOST_BASE_H */
diff --git a/ext/uri/uriparser/src/UriSetHostCommon.c b/ext/uri/uriparser/src/UriSetHostCommon.c
new file mode 100644
index 0000000000000..343db849dfff2
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetHostCommon.c
@@ -0,0 +1,266 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file UriSetHostCommon.c
+ * Holds code used by multiple SetHost* functions.
+ * NOTE: This source file includes itself twice.
+ */
+
+/* What encodings are enabled? */
+#include
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostCommon.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostCommon.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include
+# else
+# include
+# include
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include
+# include
+# include "UriCommon.h"
+# include "UriMemory.h"
+# include "UriSetHostBase.h"
+# include "UriSetHostCommon.h"
+#endif
+
+
+
+#include
+
+
+
+int URI_FUNC(InternalSetHostMm)(URI_TYPE(Uri) * uri,
+ UriHostType hostType,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ /* Superficial input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ /* The RFC 3986 grammar reads:
+ * authority = [ userinfo "@" ] host [ ":" port ]
+ * So no user info or port without a host. */
+ if (first == NULL) {
+ if (uri->userInfo.first != NULL) {
+ return URI_ERROR_SETHOST_USERINFO_SET;
+ } else if (uri->portText.first != NULL) {
+ return URI_ERROR_SETHOST_PORT_SET;
+ }
+ }
+
+ /* Syntax-check the new value */
+ if (first != NULL) {
+ switch (hostType) {
+ case URI_HOST_TYPE_IP4:
+ if (URI_FUNC(IsWellFormedHostIp4)(first, afterLast) == URI_FALSE) {
+ return URI_ERROR_SYNTAX;
+ }
+ break;
+ case URI_HOST_TYPE_IP6:
+ {
+ const int res = URI_FUNC(IsWellFormedHostIp6Mm)(first, afterLast, memory);
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC));
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+ break;
+ case URI_HOST_TYPE_IPFUTURE:
+ {
+ const int res = URI_FUNC(IsWellFormedHostIpFutureMm)(first, afterLast, memory);
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC));
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+ break;
+ case URI_HOST_TYPE_REGNAME:
+ if (URI_FUNC(IsWellFormedHostRegName)(first, afterLast) == URI_FALSE) {
+ return URI_ERROR_SYNTAX;
+ }
+ break;
+ default:
+ assert(0 && "Unsupported URI host type");
+ }
+ }
+
+ {
+ /* Clear old value */
+ const UriBool hadHostBefore = URI_FUNC(HasHost)(uri);
+ if (uri->hostData.ipFuture.first != NULL) {
+ /* NOTE: .hostData.ipFuture holds the very same range pointers
+ * as .hostText; we must not free memory twice. */
+ uri->hostText.first = NULL;
+ uri->hostText.afterLast = NULL;
+
+ if ((uri->owner == URI_TRUE) && (uri->hostData.ipFuture.first != uri->hostData.ipFuture.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first);
+ }
+ uri->hostData.ipFuture.first = NULL;
+ uri->hostData.ipFuture.afterLast = NULL;
+ } else if (uri->hostText.first != NULL) {
+ if ((uri->owner == URI_TRUE) && (uri->hostText.first != uri->hostText.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->hostText.first);
+ }
+ uri->hostText.first = NULL;
+ uri->hostText.afterLast = NULL;
+ }
+
+ if (uri->hostData.ip4 != NULL) {
+ memory->free(memory, uri->hostData.ip4);
+ uri->hostData.ip4 = NULL;
+ } else if (uri->hostData.ip6 != NULL) {
+ memory->free(memory, uri->hostData.ip6);
+ uri->hostData.ip6 = NULL;
+ }
+
+ /* Already done setting? */
+ if (first == NULL) {
+ /* Yes, but disambiguate as needed */
+ if (hadHostBefore == URI_TRUE) {
+ uri->absolutePath = URI_TRUE;
+
+ {
+ const UriBool success = URI_FUNC(EnsureThatPathIsNotMistakenForHost)(uri, memory);
+ return (success == URI_TRUE)
+ ? URI_SUCCESS
+ : URI_ERROR_MALLOC;
+ }
+ }
+
+ return URI_SUCCESS;
+ }
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ const int res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value; NOTE that .hostText is set for all four host types */
+ {
+ URI_TYPE(TextRange) sourceRange;
+ sourceRange.first = first;
+ sourceRange.afterLast = afterLast;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&uri->hostText, &sourceRange, memory) == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+
+ uri->absolutePath = URI_FALSE; /* always URI_FALSE for URIs with host */
+
+ /* Fill .hostData as needed */
+ switch (hostType) {
+ case URI_HOST_TYPE_IP4:
+ {
+ uri->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4));
+ if (uri->hostData.ip4 == NULL) {
+ return URI_ERROR_MALLOC;
+ }
+
+ {
+ const int res = URI_FUNC(ParseIpFourAddress)(uri->hostData.ip4->data, first, afterLast);
+#if defined(NDEBUG)
+ (void)res; /* i.e. mark as unused */
+#else
+ assert(res == URI_SUCCESS); /* because checked for well-formedness earlier */
+#endif
+ }
+ }
+ break;
+ case URI_HOST_TYPE_IP6:
+ {
+ uri->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6));
+ if (uri->hostData.ip6 == NULL) {
+ return URI_ERROR_MALLOC;
+ }
+
+ {
+ const int res = URI_FUNC(ParseIpSixAddressMm)(uri->hostData.ip6, first, afterLast, memory);
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_MALLOC)); /* because checked for well-formedness earlier */
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+ }
+ break;
+ case URI_HOST_TYPE_IPFUTURE:
+ uri->hostData.ipFuture.first = uri->hostText.first;
+ uri->hostData.ipFuture.afterLast = uri->hostText.afterLast;
+ break;
+ case URI_HOST_TYPE_REGNAME:
+ break;
+ default:
+ assert(0 && "Unsupported URI host type");
+ }
+ }
+
+ return URI_SUCCESS;
+}
+
+
+
+#endif
diff --git a/ext/uri/uriparser/src/UriSetHostCommon.h b/ext/uri/uriparser/src/UriSetHostCommon.h
new file mode 100644
index 0000000000000..1914d8480eb4a
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetHostCommon.h
@@ -0,0 +1,79 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if (defined(URI_PASS_ANSI) && !defined(URI_SET_HOST_COMMON_H_ANSI)) \
+ || (defined(URI_PASS_UNICODE) && !defined(URI_SET_HOST_COMMON_H_UNICODE)) \
+ || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* What encodings are enabled? */
+#include
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostCommon.h"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostCommon.h"
+# undef URI_PASS_UNICODE
+# endif
+/* Only one pass for each encoding */
+#elif (defined(URI_PASS_ANSI) && !defined(URI_SET_HOST_COMMON_H_ANSI) \
+ && defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \
+ && !defined(URI_SET_HOST_COMMON_H_UNICODE) && defined(URI_ENABLE_UNICODE))
+# ifdef URI_PASS_ANSI
+# define URI_SET_HOST_COMMON_H_ANSI 1
+# include
+# else
+# define URI_SET_HOST_COMMON_H_UNICODE 1
+# include
+# endif
+
+
+
+int URI_FUNC(InternalSetHostMm)(URI_TYPE(Uri) * uri,
+ UriHostType hostType,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+
+
+#endif
+#endif
diff --git a/ext/uri/uriparser/src/UriSetHostIp4.c b/ext/uri/uriparser/src/UriSetHostIp4.c
new file mode 100644
index 0000000000000..e07e249c23d2a
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetHostIp4.c
@@ -0,0 +1,105 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostIp4.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostIp4.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include
+# else
+# include
+# include
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include
+# include
+# include "UriMemory.h"
+# include "UriSetHostBase.h"
+# include "UriSetHostCommon.h"
+#endif
+
+
+
+UriBool URI_FUNC(IsWellFormedHostIp4)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ {
+ unsigned char octetOutput[4];
+ return (URI_FUNC(ParseIpFourAddress)(octetOutput, first, afterLast) == URI_SUCCESS)
+ ? URI_TRUE
+ : URI_FALSE;
+ }
+}
+
+
+
+int URI_FUNC(SetHostIp4Mm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_IP4, first, afterLast, memory);
+}
+
+
+
+int URI_FUNC(SetHostIp4)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetHostIp4Mm)(uri, first, afterLast, NULL);
+}
+
+
+
+#endif
diff --git a/ext/uri/uriparser/src/UriSetHostIp6.c b/ext/uri/uriparser/src/UriSetHostIp6.c
new file mode 100644
index 0000000000000..f99365558ff0b
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetHostIp6.c
@@ -0,0 +1,182 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostIp6.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostIp6.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include
+# else
+# include
+# include
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include
+# include "UriMemory.h"
+# include "UriSetHostBase.h"
+# include "UriSetHostCommon.h"
+#endif
+
+
+
+#include
+#include /* for memcpy */
+
+
+
+#define URI_MAX_IP6_LEN (8 * 4 + 7 * 1) /* i.e. 8 full quads plus 7 colon separators */
+
+
+
+int URI_FUNC(ParseIpSixAddressMm)(UriIp6 * output,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ /* NOTE: output is allowed to be NULL */
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ /* Are we dealing with potential IPvFuture input? */
+ if (first < afterLast) {
+ switch (first[0]) {
+ case _UT('v'):
+ case _UT('V'):
+ return URI_ERROR_SYNTAX;
+ default:
+ break;
+ }
+ }
+
+ /* Are we dealing with IPv6 input? */
+ {
+ /* Assemble "//[..]" input wrap for upcoming parse as a URI
+ * NOTE: If the input contains closing "]" on its own, the resulting
+ * string will not be valid URI syntax, and hence there is
+ * no risk of false positives from "bracket injection". */
+ URI_CHAR candidate[3 + URI_MAX_IP6_LEN + 1 + 1] = _UT("//[");
+ const size_t inputLenChars = (afterLast - first);
+
+ /* Detect overflow */
+ if (inputLenChars > URI_MAX_IP6_LEN) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ memcpy(candidate + 3, first, inputLenChars * sizeof(URI_CHAR));
+ memcpy(candidate + 3 + inputLenChars, _UT("]"), 2 * sizeof(URI_CHAR)); /* includes zero terminator */
+
+ /* Parse as an RFC 3986 URI */
+ {
+ const size_t candidateLenChars = 3 + inputLenChars + 1;
+ URI_TYPE(Uri) uri;
+ const int res = URI_FUNC(ParseSingleUriExMm)(&uri, candidate, candidate + candidateLenChars, NULL, memory);
+
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC));
+
+ if (res == URI_SUCCESS) {
+ assert(uri.hostData.ip6 != NULL);
+
+ if (output != NULL) {
+ memcpy(output->data, uri.hostData.ip6->data, sizeof(output->data));
+ }
+
+ URI_FUNC(FreeUriMembersMm)(&uri, memory);
+ }
+
+ return res;
+ }
+ }
+}
+
+
+
+int URI_FUNC(ParseIpSixAddress)(UriIp6 * output,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(ParseIpSixAddressMm)(output, first, afterLast, NULL);
+}
+
+
+
+int URI_FUNC(IsWellFormedHostIp6Mm)(const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ return URI_FUNC(ParseIpSixAddressMm)(NULL, first, afterLast, memory);
+}
+
+
+
+int URI_FUNC(IsWellFormedHostIp6)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+ return URI_FUNC(IsWellFormedHostIp6Mm)(first, afterLast, NULL);
+}
+
+
+
+int URI_FUNC(SetHostIp6Mm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_IP6, first, afterLast, memory);
+}
+
+
+
+int URI_FUNC(SetHostIp6)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetHostIp6Mm)(uri, first, afterLast, NULL);
+}
+
+
+
+#endif
diff --git a/ext/uri/uriparser/src/UriSetHostIpFuture.c b/ext/uri/uriparser/src/UriSetHostIpFuture.c
new file mode 100644
index 0000000000000..aa84a82f4fe68
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetHostIpFuture.c
@@ -0,0 +1,174 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostIpFuture.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostIpFuture.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include
+# else
+# include
+# include
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include
+# include "UriMemory.h"
+# include "UriSetHostBase.h"
+# include "UriSetHostCommon.h"
+#endif
+
+
+
+#include
+#include /* for memcpy */
+
+
+
+int URI_FUNC(IsWellFormedHostIpFutureMm)(const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ /* Are we dealing with potential IPv6 input? */
+ if (first < afterLast) {
+ switch (first[0]) {
+ case _UT('v'):
+ case _UT('V'):
+ break;
+ default:
+ return URI_ERROR_SYNTAX;
+ }
+ }
+
+ /* Are we dealing with IPvFuture input? */
+ {
+ /* Assemble "//[..]" input wrap for upcoming parse as a URI
+ * NOTE: If the input contains closing "]" on its own, the resulting
+ * string will not be valid URI syntax, and hence there is
+ * no risk of false positives from "bracket injection". */
+ const size_t inputLenChars = (afterLast - first);
+ const size_t MAX_SIZE_T = (size_t)-1;
+
+ /* Detect overflow */
+ if (MAX_SIZE_T - inputLenChars < 3 + 1 + 1) {
+ return URI_ERROR_MALLOC;
+ }
+
+ {
+ const size_t candidateLenChars = 3 + inputLenChars + 1;
+
+ /* Detect overflow */
+ if (MAX_SIZE_T / sizeof(URI_CHAR) < candidateLenChars + 1) {
+ return URI_ERROR_MALLOC;
+ }
+
+ {
+ URI_CHAR * const candidate = memory->malloc(memory, (candidateLenChars + 1) * sizeof(URI_CHAR));
+
+ if (candidate == NULL) {
+ return URI_ERROR_MALLOC;
+ }
+
+ memcpy(candidate, _UT("//["), 3 * sizeof(URI_CHAR));
+ memcpy(candidate + 3, first, inputLenChars * sizeof(URI_CHAR));
+ memcpy(candidate + 3 + inputLenChars, _UT("]"), 2 * sizeof(URI_CHAR)); /* includes zero terminator */
+
+ /* Parse as an RFC 3986 URI */
+ {
+ URI_TYPE(Uri) uri;
+ const int res = URI_FUNC(ParseSingleUriExMm)(&uri, candidate, candidate + candidateLenChars, NULL, memory);
+
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC));
+
+ if (res == URI_SUCCESS) {
+ assert(uri.hostData.ipFuture.first != NULL);
+ URI_FUNC(FreeUriMembersMm)(&uri, memory);
+ }
+
+ memory->free(memory, candidate);
+
+ return res;
+ }
+ }
+ }
+ }
+}
+
+
+
+int URI_FUNC(IsWellFormedHostIpFuture)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+ return URI_FUNC(IsWellFormedHostIpFutureMm)(first, afterLast, NULL);
+}
+
+
+
+int URI_FUNC(SetHostIpFutureMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_IPFUTURE, first, afterLast, memory);
+}
+
+
+
+int URI_FUNC(SetHostIpFuture)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetHostIpFutureMm)(uri, first, afterLast, NULL);
+}
+
+
+
+#endif
diff --git a/ext/uri/uriparser/src/UriSetHostRegName.c b/ext/uri/uriparser/src/UriSetHostRegName.c
new file mode 100644
index 0000000000000..d09e2e98e3616
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetHostRegName.c
@@ -0,0 +1,246 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostRegName.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostRegName.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include
+# else
+# include
+# include
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include
+# include "UriMemory.h"
+# include "UriSetHostBase.h"
+# include "UriSetHostCommon.h"
+#endif
+
+
+
+#define URI_SET_DIGIT \
+ _UT('0'): \
+ case _UT('1'): \
+ case _UT('2'): \
+ case _UT('3'): \
+ case _UT('4'): \
+ case _UT('5'): \
+ case _UT('6'): \
+ case _UT('7'): \
+ case _UT('8'): \
+ case _UT('9')
+
+
+
+#define URI_SET_HEX_LETTER_UPPER \
+ _UT('A'): \
+ case _UT('B'): \
+ case _UT('C'): \
+ case _UT('D'): \
+ case _UT('E'): \
+ case _UT('F')
+
+
+
+#define URI_SET_HEX_LETTER_LOWER \
+ _UT('a'): \
+ case _UT('b'): \
+ case _UT('c'): \
+ case _UT('d'): \
+ case _UT('e'): \
+ case _UT('f')
+
+
+
+#define URI_SET_HEXDIG \
+ URI_SET_DIGIT: \
+ case URI_SET_HEX_LETTER_UPPER: \
+ case URI_SET_HEX_LETTER_LOWER
+
+
+
+#define URI_SET_ALPHA \
+ URI_SET_HEX_LETTER_UPPER: \
+ case URI_SET_HEX_LETTER_LOWER: \
+ case _UT('g'): \
+ case _UT('G'): \
+ case _UT('h'): \
+ case _UT('H'): \
+ case _UT('i'): \
+ case _UT('I'): \
+ case _UT('j'): \
+ case _UT('J'): \
+ case _UT('k'): \
+ case _UT('K'): \
+ case _UT('l'): \
+ case _UT('L'): \
+ case _UT('m'): \
+ case _UT('M'): \
+ case _UT('n'): \
+ case _UT('N'): \
+ case _UT('o'): \
+ case _UT('O'): \
+ case _UT('p'): \
+ case _UT('P'): \
+ case _UT('q'): \
+ case _UT('Q'): \
+ case _UT('r'): \
+ case _UT('R'): \
+ case _UT('s'): \
+ case _UT('S'): \
+ case _UT('t'): \
+ case _UT('T'): \
+ case _UT('u'): \
+ case _UT('U'): \
+ case _UT('v'): \
+ case _UT('V'): \
+ case _UT('w'): \
+ case _UT('W'): \
+ case _UT('x'): \
+ case _UT('X'): \
+ case _UT('y'): \
+ case _UT('Y'): \
+ case _UT('z'): \
+ case _UT('Z')
+
+
+
+#define URI_SET_SUB_DELIMS \
+ _UT('!'): \
+ case _UT('$'): \
+ case _UT('&'): \
+ case _UT('\''): \
+ case _UT('('): \
+ case _UT(')'): \
+ case _UT('*'): \
+ case _UT('+'): \
+ case _UT(','): \
+ case _UT(';'): \
+ case _UT('=')
+
+
+
+#define URI_SET_UNRESERVED \
+ URI_SET_ALPHA: \
+ case URI_SET_DIGIT: \
+ case _UT('-'): \
+ case _UT('.'): \
+ case _UT('_'): \
+ case _UT('~')
+
+
+
+UriBool URI_FUNC(IsWellFormedHostRegName)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ /* reg-name = *( unreserved / pct-encoded / sub-delims ) */
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_UNRESERVED:
+ break;
+
+ /* pct-encoded */
+ case _UT('%'):
+ if (afterLast - first < 3) {
+ return URI_FALSE;
+ }
+ switch (first[1]) {
+ case URI_SET_HEXDIG:
+ break;
+ default:
+ return URI_FALSE;
+ }
+ switch (first[2]) {
+ case URI_SET_HEXDIG:
+ break;
+ default:
+ return URI_FALSE;
+ }
+ first += 2;
+ break;
+
+ case URI_SET_SUB_DELIMS:
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+ }
+ return URI_TRUE;
+}
+
+
+
+int URI_FUNC(SetHostRegNameMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_REGNAME, first, afterLast, memory);
+}
+
+
+
+int URI_FUNC(SetHostRegName)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetHostRegNameMm)(uri, first, afterLast, NULL);
+}
+
+
+
+#endif
diff --git a/ext/uri/uriparser/src/UriSetPath.c b/ext/uri/uriparser/src/UriSetPath.c
new file mode 100644
index 0000000000000..abd783b3c65ae
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetPath.c
@@ -0,0 +1,495 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetPath.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetPath.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include
+# else
+# include
+# include
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include
+# include "UriCommon.h"
+# include "UriMemory.h"
+#endif
+
+
+
+#include
+
+
+
+#define URI_SET_DIGIT \
+ _UT('0'): \
+ case _UT('1'): \
+ case _UT('2'): \
+ case _UT('3'): \
+ case _UT('4'): \
+ case _UT('5'): \
+ case _UT('6'): \
+ case _UT('7'): \
+ case _UT('8'): \
+ case _UT('9')
+
+
+
+#define URI_SET_HEX_LETTER_UPPER \
+ _UT('A'): \
+ case _UT('B'): \
+ case _UT('C'): \
+ case _UT('D'): \
+ case _UT('E'): \
+ case _UT('F')
+
+
+
+#define URI_SET_HEX_LETTER_LOWER \
+ _UT('a'): \
+ case _UT('b'): \
+ case _UT('c'): \
+ case _UT('d'): \
+ case _UT('e'): \
+ case _UT('f')
+
+
+
+#define URI_SET_HEXDIG \
+ URI_SET_DIGIT: \
+ case URI_SET_HEX_LETTER_UPPER: \
+ case URI_SET_HEX_LETTER_LOWER
+
+
+
+#define URI_SET_ALPHA \
+ URI_SET_HEX_LETTER_UPPER: \
+ case URI_SET_HEX_LETTER_LOWER: \
+ case _UT('g'): \
+ case _UT('G'): \
+ case _UT('h'): \
+ case _UT('H'): \
+ case _UT('i'): \
+ case _UT('I'): \
+ case _UT('j'): \
+ case _UT('J'): \
+ case _UT('k'): \
+ case _UT('K'): \
+ case _UT('l'): \
+ case _UT('L'): \
+ case _UT('m'): \
+ case _UT('M'): \
+ case _UT('n'): \
+ case _UT('N'): \
+ case _UT('o'): \
+ case _UT('O'): \
+ case _UT('p'): \
+ case _UT('P'): \
+ case _UT('q'): \
+ case _UT('Q'): \
+ case _UT('r'): \
+ case _UT('R'): \
+ case _UT('s'): \
+ case _UT('S'): \
+ case _UT('t'): \
+ case _UT('T'): \
+ case _UT('u'): \
+ case _UT('U'): \
+ case _UT('v'): \
+ case _UT('V'): \
+ case _UT('w'): \
+ case _UT('W'): \
+ case _UT('x'): \
+ case _UT('X'): \
+ case _UT('y'): \
+ case _UT('Y'): \
+ case _UT('z'): \
+ case _UT('Z')
+
+
+
+#define URI_SET_SUB_DELIMS \
+ _UT('!'): \
+ case _UT('$'): \
+ case _UT('&'): \
+ case _UT('\''): \
+ case _UT('('): \
+ case _UT(')'): \
+ case _UT('*'): \
+ case _UT('+'): \
+ case _UT(','): \
+ case _UT(';'): \
+ case _UT('=')
+
+
+
+#define URI_SET_UNRESERVED \
+ URI_SET_ALPHA: \
+ case URI_SET_DIGIT: \
+ case _UT('-'): \
+ case _UT('.'): \
+ case _UT('_'): \
+ case _UT('~')
+
+
+
+UriBool URI_FUNC(IsWellFormedPath)(const URI_CHAR * first, const URI_CHAR * afterLast, UriBool hasHost) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ if ((hasHost == URI_TRUE) && ((first >= afterLast) || (first[0] != _UT('/')))) {
+ return URI_FALSE;
+ }
+
+ /* The related part of the grammar in RFC 3986 (section 3.3) reads:
+ *
+ * path = path-abempty ; begins with "/" or is empty
+ * / path-absolute ; begins with "/" but not "//"
+ * / path-noscheme ; begins with a non-colon segment
+ * / path-rootless ; begins with a segment
+ * / path-empty ; zero characters
+ *
+ * path-abempty = *( "/" segment )
+ * path-absolute = "/" [ segment-nz *( "/" segment ) ]
+ * path-noscheme = segment-nz-nc *( "/" segment )
+ * path-rootless = segment-nz *( "/" segment )
+ * path-empty = 0
+ *
+ * segment = *pchar
+ * segment-nz = 1*pchar
+ * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
+ * ; non-zero-length segment without any colon ":"
+ *
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ *
+ * The check below simplifies this to ..
+ *
+ * path = *( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" )
+ *
+ * .. and leaves the rest to pre-return removal of ambiguity
+ * from cases like "path1:/path2" and "//path1/path2" inside SetPath.
+ */
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_UNRESERVED:
+ break;
+
+ /* pct-encoded */
+ case _UT('%'):
+ if (afterLast - first < 3) {
+ return URI_FALSE;
+ }
+ switch (first[1]) {
+ case URI_SET_HEXDIG:
+ break;
+ default:
+ return URI_FALSE;
+ }
+ switch (first[2]) {
+ case URI_SET_HEXDIG:
+ break;
+ default:
+ return URI_FALSE;
+ }
+ first += 2;
+ break;
+
+ case URI_SET_SUB_DELIMS:
+ break;
+
+ /* ":" / "@" and "/" */
+ case _UT(':'):
+ case _UT('@'):
+ case _UT('/'):
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+ }
+ return URI_TRUE;
+}
+
+
+
+static void URI_FUNC(DropEmptyFirstPathSegment)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
+ assert(uri != NULL);
+ assert(memory != NULL);
+ assert(uri->pathHead != NULL);
+ assert(uri->pathHead->text.first == uri->pathHead->text.afterLast);
+
+ {
+ URI_TYPE(PathSegment) * const originalHead = uri->pathHead;
+
+ uri->pathHead = uri->pathHead->next;
+
+ originalHead->text.first = NULL;
+ originalHead->text.afterLast = NULL;
+ memory->free(memory, originalHead);
+ }
+}
+
+
+
+/* URIs without a host encode a leading slash in the path as .absolutePath == URI_TRUE.
+ * This function checks for a leading empty path segment (that would have the "visual effect"
+ * of a leading slash during stringification) and transforms it into .absolutePath == URI_TRUE
+ * instead, if present. */
+static void URI_FUNC(TransformEmptyLeadPathSegments)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
+ assert(uri != NULL);
+ assert(memory != NULL);
+
+ if ((URI_FUNC(HasHost)(uri) == URI_TRUE)
+ || (uri->pathHead == NULL)
+ || (uri->pathHead->text.first != uri->pathHead->text.afterLast)) {
+ return; /* i.e. nothing to do */
+ }
+
+ assert(uri->absolutePath == URI_FALSE);
+
+ URI_FUNC(DropEmptyFirstPathSegment)(uri, memory);
+
+ uri->absolutePath = URI_TRUE;
+}
+
+
+
+static int URI_FUNC(InternalSetPath)(URI_TYPE(Uri) * destUri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ assert(destUri != NULL);
+ assert(first != NULL);
+ assert(afterLast != NULL);
+ assert(memory != NULL);
+ assert(destUri->pathHead == NULL); /* set by SetPathMm right before */
+ assert(destUri->pathTail == NULL); /* set by SetPathMm right before */
+ assert(destUri->absolutePath == URI_FALSE); /* set by SetPathMm right before */
+
+ /* Skip the leading slash from target URIs with a host (so that we can
+ * transfer the path 1:1 further down) */
+ if (URI_FUNC(HasHost)(destUri) == URI_TRUE) {
+ /* NOTE: This is because SetPathMm called IsWellFormedPath earlier: */
+ assert((afterLast - first >= 1) && (first[0] == _UT('/')));
+ first++;
+ } else if (first == afterLast) {
+ /* This avoids (1) all the expensive but unnecessary work below
+ * and also (2) mis-encoding as single empty path segment
+ * that would need (detection and) repair further down otherwise */
+ return URI_SUCCESS;
+ }
+
+ /* Assemble "///.." input wrap for upcoming parse as a URI */
+ {
+ const size_t inputLenChars = (afterLast - first);
+ const size_t MAX_SIZE_T = (size_t)-1;
+
+ /* Detect overflow */
+ if (MAX_SIZE_T - inputLenChars < 3 + 1) {
+ return URI_ERROR_MALLOC;
+ }
+
+ {
+ const size_t candidateLenChars = 3 + inputLenChars;
+
+ /* Detect overflow */
+ if (MAX_SIZE_T / sizeof(URI_CHAR) < candidateLenChars + 1) {
+ return URI_ERROR_MALLOC;
+ }
+
+ {
+ URI_CHAR * const candidate = memory->malloc(memory, (candidateLenChars + 1) * sizeof(URI_CHAR));
+
+ if (candidate == NULL) {
+ return URI_ERROR_MALLOC;
+ }
+
+ memcpy(candidate, _UT("///"), 3 * sizeof(URI_CHAR));
+ memcpy(candidate + 3, first, inputLenChars * sizeof(URI_CHAR));
+ candidate[3 + inputLenChars] = _UT('\0');
+
+ /* Parse as an RFC 3986 URI */
+ {
+ URI_TYPE(Uri) tempUri;
+ const int res = URI_FUNC(ParseSingleUriExMm)(&tempUri,
+ candidate,
+ candidate + candidateLenChars,
+ NULL,
+ memory);
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC));
+ if (res != URI_SUCCESS) {
+ memory->free(memory, candidate);
+ return res;
+ }
+
+ /* Nothing but path and host is supposed to be set by the parse, in particular not: */
+ assert(tempUri.query.first == NULL);
+ assert(tempUri.fragment.first == NULL);
+
+ /* Ensure that the strings in the path segments are all owned by `tempUri`
+ * because we want to (1) rip out and keep the full path list further down
+ * and (2) be able to free the parsed string (`candidate`) also. */
+ {
+ const int res = URI_FUNC(MakeOwnerMm)(&tempUri, memory);
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_MALLOC));
+ if (res != URI_SUCCESS) {
+ URI_FUNC(FreeUriMembersMm)(&tempUri, memory);
+ memory->free(memory, candidate);
+ return res;
+ }
+ assert(tempUri.owner == URI_TRUE);
+ }
+
+ /* Move path to destination URI */
+ assert(tempUri.absolutePath == URI_FALSE); /* always URI_FALSE for URIs with host */
+ destUri->pathHead = tempUri.pathHead;
+ destUri->pathTail = tempUri.pathTail;
+ destUri->absolutePath = URI_FALSE;
+
+ tempUri.pathHead = NULL;
+ tempUri.pathTail = NULL;
+
+ /* Free the rest of the temp URI */
+ URI_FUNC(FreeUriMembersMm)(&tempUri, memory);
+ memory->free(memory, candidate);
+
+ /* Restore use of .absolutePath as needed */
+ URI_FUNC(TransformEmptyLeadPathSegments)(destUri, memory);
+
+ /* Disambiguate as needed */
+ {
+ const UriBool success = URI_FUNC(FixPathNoScheme)(destUri, memory);
+ if (success == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+ }
+ {
+ const UriBool success = URI_FUNC(EnsureThatPathIsNotMistakenForHost)(destUri, memory);
+ if (success == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return URI_SUCCESS;
+}
+
+
+
+int URI_FUNC(SetPathMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ /* Input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ if ((first != NULL) && (URI_FUNC(IsWellFormedPath)(first, afterLast, URI_FUNC(HasHost)(uri)) == URI_FALSE)) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Clear old value */
+ {
+ const int res = URI_FUNC(FreeUriPath)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ uri->absolutePath = URI_FALSE;
+ }
+
+ /* Already done? */
+ if (first == NULL) {
+ return URI_SUCCESS;
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ const int res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value */
+ {
+ const int res = URI_FUNC(InternalSetPath)(uri, first, afterLast, memory);
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX) || (res == URI_ERROR_MALLOC));
+ return res;
+ }
+}
+
+
+
+int URI_FUNC(SetPath)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetPathMm)(uri, first, afterLast, NULL);
+}
+
+
+
+#endif
diff --git a/ext/uri/uriparser/src/UriSetPort.c b/ext/uri/uriparser/src/UriSetPort.c
new file mode 100644
index 0000000000000..3331b717e21e7
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetPort.c
@@ -0,0 +1,179 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetPort.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetPort.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include
+# else
+# include
+# include
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include
+# include "UriCommon.h"
+# include "UriMemory.h"
+#endif
+
+
+
+#include
+
+
+
+#define URI_SET_DIGIT \
+ _UT('0'): \
+ case _UT('1'): \
+ case _UT('2'): \
+ case _UT('3'): \
+ case _UT('4'): \
+ case _UT('5'): \
+ case _UT('6'): \
+ case _UT('7'): \
+ case _UT('8'): \
+ case _UT('9')
+
+
+
+UriBool URI_FUNC(IsWellFormedPort)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ /* NOTE: Grammar reads "port = *DIGIT" which includes the empty string. */
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_DIGIT:
+ break;
+ default:
+ return URI_FALSE;
+ }
+ first++;
+ }
+ return URI_TRUE;
+}
+
+
+
+int URI_FUNC(SetPortTextMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ /* Input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ /* The RFC 3986 grammar reads:
+ * authority = [ userinfo "@" ] host [ ":" port ]
+ * So no port without a host. */
+ if ((first != NULL) && (URI_FUNC(HasHost)(uri) == URI_FALSE)) {
+ return URI_ERROR_SETPORT_HOST_NOT_SET;
+ }
+
+ if ((first != NULL) && (URI_FUNC(IsWellFormedPort)(first, afterLast) == URI_FALSE)) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Clear old value */
+ if ((uri->owner == URI_TRUE) && (uri->portText.first != uri->portText.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->portText.first);
+ }
+ uri->portText.first = NULL;
+ uri->portText.afterLast = NULL;
+
+ /* Already done? */
+ if (first == NULL) {
+ return URI_SUCCESS;
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ const int res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value */
+ {
+ URI_TYPE(TextRange) sourceRange;
+ sourceRange.first = first;
+ sourceRange.afterLast = afterLast;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&uri->portText, &sourceRange, memory) == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+ }
+
+ return URI_SUCCESS;
+}
+
+
+
+int URI_FUNC(SetPortText)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetPortTextMm)(uri, first, afterLast, NULL);
+}
+
+
+
+#endif
diff --git a/ext/uri/uriparser/src/UriSetQuery.c b/ext/uri/uriparser/src/UriSetQuery.c
new file mode 100644
index 0000000000000..567ff6d1d8aa7
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetQuery.c
@@ -0,0 +1,306 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetQuery.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetQuery.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include
+# else
+# include
+# include
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include
+# include "UriCommon.h"
+# include "UriMemory.h"
+#endif
+
+
+
+#include
+
+
+
+#define URI_SET_DIGIT \
+ _UT('0'): \
+ case _UT('1'): \
+ case _UT('2'): \
+ case _UT('3'): \
+ case _UT('4'): \
+ case _UT('5'): \
+ case _UT('6'): \
+ case _UT('7'): \
+ case _UT('8'): \
+ case _UT('9')
+
+
+
+#define URI_SET_HEX_LETTER_UPPER \
+ _UT('A'): \
+ case _UT('B'): \
+ case _UT('C'): \
+ case _UT('D'): \
+ case _UT('E'): \
+ case _UT('F')
+
+
+
+#define URI_SET_HEX_LETTER_LOWER \
+ _UT('a'): \
+ case _UT('b'): \
+ case _UT('c'): \
+ case _UT('d'): \
+ case _UT('e'): \
+ case _UT('f')
+
+
+
+#define URI_SET_HEXDIG \
+ URI_SET_DIGIT: \
+ case URI_SET_HEX_LETTER_UPPER: \
+ case URI_SET_HEX_LETTER_LOWER
+
+
+
+#define URI_SET_ALPHA \
+ URI_SET_HEX_LETTER_UPPER: \
+ case URI_SET_HEX_LETTER_LOWER: \
+ case _UT('g'): \
+ case _UT('G'): \
+ case _UT('h'): \
+ case _UT('H'): \
+ case _UT('i'): \
+ case _UT('I'): \
+ case _UT('j'): \
+ case _UT('J'): \
+ case _UT('k'): \
+ case _UT('K'): \
+ case _UT('l'): \
+ case _UT('L'): \
+ case _UT('m'): \
+ case _UT('M'): \
+ case _UT('n'): \
+ case _UT('N'): \
+ case _UT('o'): \
+ case _UT('O'): \
+ case _UT('p'): \
+ case _UT('P'): \
+ case _UT('q'): \
+ case _UT('Q'): \
+ case _UT('r'): \
+ case _UT('R'): \
+ case _UT('s'): \
+ case _UT('S'): \
+ case _UT('t'): \
+ case _UT('T'): \
+ case _UT('u'): \
+ case _UT('U'): \
+ case _UT('v'): \
+ case _UT('V'): \
+ case _UT('w'): \
+ case _UT('W'): \
+ case _UT('x'): \
+ case _UT('X'): \
+ case _UT('y'): \
+ case _UT('Y'): \
+ case _UT('z'): \
+ case _UT('Z')
+
+
+
+#define URI_SET_SUB_DELIMS \
+ _UT('!'): \
+ case _UT('$'): \
+ case _UT('&'): \
+ case _UT('\''): \
+ case _UT('('): \
+ case _UT(')'): \
+ case _UT('*'): \
+ case _UT('+'): \
+ case _UT(','): \
+ case _UT(';'): \
+ case _UT('=')
+
+
+
+#define URI_SET_UNRESERVED \
+ URI_SET_ALPHA: \
+ case URI_SET_DIGIT: \
+ case _UT('-'): \
+ case _UT('.'): \
+ case _UT('_'): \
+ case _UT('~')
+
+
+
+UriBool URI_FUNC(IsWellFormedQuery)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ /* The related part of the grammar in RFC 3986 reads:
+ *
+ * query = *( pchar / "/" / "?" )
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ */
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_UNRESERVED:
+ break;
+
+ /* pct-encoded */
+ case _UT('%'):
+ if (afterLast - first < 3) {
+ return URI_FALSE;
+ }
+ switch (first[1]) {
+ case URI_SET_HEXDIG:
+ break;
+ default:
+ return URI_FALSE;
+ }
+ switch (first[2]) {
+ case URI_SET_HEXDIG:
+ break;
+ default:
+ return URI_FALSE;
+ }
+ first += 2;
+ break;
+
+ case URI_SET_SUB_DELIMS:
+ break;
+
+ /* ":" / "@" and "/" / "?" */
+ case _UT(':'):
+ case _UT('@'):
+ case _UT('/'):
+ case _UT('?'):
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+ }
+ return URI_TRUE;
+}
+
+
+
+int URI_FUNC(SetQueryMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ /* Input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ if ((first != NULL) && (URI_FUNC(IsWellFormedQuery)(first, afterLast) == URI_FALSE)) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Clear old value */
+ if ((uri->owner == URI_TRUE) && (uri->query.first != uri->query.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->query.first);
+ }
+ uri->query.first = NULL;
+ uri->query.afterLast = NULL;
+
+ /* Already done? */
+ if (first == NULL) {
+ return URI_SUCCESS;
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ const int res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value */
+ {
+ URI_TYPE(TextRange) sourceRange;
+ sourceRange.first = first;
+ sourceRange.afterLast = afterLast;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&uri->query, &sourceRange, memory) == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+ }
+
+ return URI_SUCCESS;
+}
+
+
+
+int URI_FUNC(SetQuery)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetQueryMm)(uri, first, afterLast, NULL);
+}
+
+
+
+#endif
diff --git a/ext/uri/uriparser/src/UriSetScheme.c b/ext/uri/uriparser/src/UriSetScheme.c
new file mode 100644
index 0000000000000..73a75b82350fd
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetScheme.c
@@ -0,0 +1,272 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetScheme.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetScheme.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include
+# else
+# include
+# include
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include
+# include "UriCommon.h"
+# include "UriMemory.h"
+#endif
+
+
+
+#include
+
+
+
+#define URI_SET_DIGIT \
+ _UT('0'): \
+ case _UT('1'): \
+ case _UT('2'): \
+ case _UT('3'): \
+ case _UT('4'): \
+ case _UT('5'): \
+ case _UT('6'): \
+ case _UT('7'): \
+ case _UT('8'): \
+ case _UT('9')
+
+
+
+#define URI_SET_HEX_LETTER_UPPER \
+ _UT('A'): \
+ case _UT('B'): \
+ case _UT('C'): \
+ case _UT('D'): \
+ case _UT('E'): \
+ case _UT('F')
+
+
+
+#define URI_SET_HEX_LETTER_LOWER \
+ _UT('a'): \
+ case _UT('b'): \
+ case _UT('c'): \
+ case _UT('d'): \
+ case _UT('e'): \
+ case _UT('f')
+
+
+
+#define URI_SET_HEXDIG \
+ URI_SET_DIGIT: \
+ case URI_SET_HEX_LETTER_UPPER: \
+ case URI_SET_HEX_LETTER_LOWER
+
+
+
+#define URI_SET_ALPHA \
+ URI_SET_HEX_LETTER_UPPER: \
+ case URI_SET_HEX_LETTER_LOWER: \
+ case _UT('g'): \
+ case _UT('G'): \
+ case _UT('h'): \
+ case _UT('H'): \
+ case _UT('i'): \
+ case _UT('I'): \
+ case _UT('j'): \
+ case _UT('J'): \
+ case _UT('k'): \
+ case _UT('K'): \
+ case _UT('l'): \
+ case _UT('L'): \
+ case _UT('m'): \
+ case _UT('M'): \
+ case _UT('n'): \
+ case _UT('N'): \
+ case _UT('o'): \
+ case _UT('O'): \
+ case _UT('p'): \
+ case _UT('P'): \
+ case _UT('q'): \
+ case _UT('Q'): \
+ case _UT('r'): \
+ case _UT('R'): \
+ case _UT('s'): \
+ case _UT('S'): \
+ case _UT('t'): \
+ case _UT('T'): \
+ case _UT('u'): \
+ case _UT('U'): \
+ case _UT('v'): \
+ case _UT('V'): \
+ case _UT('w'): \
+ case _UT('W'): \
+ case _UT('x'): \
+ case _UT('X'): \
+ case _UT('y'): \
+ case _UT('Y'): \
+ case _UT('z'): \
+ case _UT('Z')
+
+
+
+UriBool URI_FUNC(IsWellFormedScheme)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ /* The related part of the grammar in RFC 3986 reads:
+ *
+ * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ */
+ if (first >= afterLast) {
+ return URI_FALSE;
+ }
+
+ switch (first[0]) {
+ case URI_SET_ALPHA:
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_ALPHA:
+ case URI_SET_DIGIT:
+ case _UT('+'):
+ case _UT('-'):
+ case _UT('.'):
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+ }
+ return URI_TRUE;
+}
+
+
+
+int URI_FUNC(SetSchemeMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ /* Input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ if ((first != NULL) && (URI_FUNC(IsWellFormedScheme)(first, afterLast) == URI_FALSE)) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Clear old value */
+ if ((uri->owner == URI_TRUE) && (uri->scheme.first != uri->scheme.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->scheme.first);
+ }
+ uri->scheme.first = NULL;
+ uri->scheme.afterLast = NULL;
+
+ /* Already done setting? */
+ if (first == NULL) {
+ /* Yes, but disambiguate as needed */
+ const UriBool success = URI_FUNC(FixPathNoScheme)(uri, memory);
+ return (success == URI_TRUE)
+ ? URI_SUCCESS
+ : URI_ERROR_MALLOC;
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ const int res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value */
+ {
+ URI_TYPE(TextRange) sourceRange;
+ sourceRange.first = first;
+ sourceRange.afterLast = afterLast;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&uri->scheme, &sourceRange, memory) == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+ }
+
+ return URI_SUCCESS;
+}
+
+
+
+int URI_FUNC(SetScheme)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetSchemeMm)(uri, first, afterLast, NULL);
+}
+
+
+
+#endif
diff --git a/ext/uri/uriparser/src/UriSetUserInfo.c b/ext/uri/uriparser/src/UriSetUserInfo.c
new file mode 100644
index 0000000000000..d30f984395a24
--- /dev/null
+++ b/ext/uri/uriparser/src/UriSetUserInfo.c
@@ -0,0 +1,306 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetUserInfo.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetUserInfo.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include
+# else
+# include
+# include
+# endif
+
+
+
+#ifndef URI_DOXYGEN
+# include
+# include "UriCommon.h"
+# include "UriMemory.h"
+#endif
+
+
+
+#include
+
+
+
+#define URI_SET_DIGIT \
+ _UT('0'): \
+ case _UT('1'): \
+ case _UT('2'): \
+ case _UT('3'): \
+ case _UT('4'): \
+ case _UT('5'): \
+ case _UT('6'): \
+ case _UT('7'): \
+ case _UT('8'): \
+ case _UT('9')
+
+
+
+#define URI_SET_HEX_LETTER_UPPER \
+ _UT('A'): \
+ case _UT('B'): \
+ case _UT('C'): \
+ case _UT('D'): \
+ case _UT('E'): \
+ case _UT('F')
+
+
+
+#define URI_SET_HEX_LETTER_LOWER \
+ _UT('a'): \
+ case _UT('b'): \
+ case _UT('c'): \
+ case _UT('d'): \
+ case _UT('e'): \
+ case _UT('f')
+
+
+
+#define URI_SET_HEXDIG \
+ URI_SET_DIGIT: \
+ case URI_SET_HEX_LETTER_UPPER: \
+ case URI_SET_HEX_LETTER_LOWER
+
+
+
+#define URI_SET_ALPHA \
+ URI_SET_HEX_LETTER_UPPER: \
+ case URI_SET_HEX_LETTER_LOWER: \
+ case _UT('g'): \
+ case _UT('G'): \
+ case _UT('h'): \
+ case _UT('H'): \
+ case _UT('i'): \
+ case _UT('I'): \
+ case _UT('j'): \
+ case _UT('J'): \
+ case _UT('k'): \
+ case _UT('K'): \
+ case _UT('l'): \
+ case _UT('L'): \
+ case _UT('m'): \
+ case _UT('M'): \
+ case _UT('n'): \
+ case _UT('N'): \
+ case _UT('o'): \
+ case _UT('O'): \
+ case _UT('p'): \
+ case _UT('P'): \
+ case _UT('q'): \
+ case _UT('Q'): \
+ case _UT('r'): \
+ case _UT('R'): \
+ case _UT('s'): \
+ case _UT('S'): \
+ case _UT('t'): \
+ case _UT('T'): \
+ case _UT('u'): \
+ case _UT('U'): \
+ case _UT('v'): \
+ case _UT('V'): \
+ case _UT('w'): \
+ case _UT('W'): \
+ case _UT('x'): \
+ case _UT('X'): \
+ case _UT('y'): \
+ case _UT('Y'): \
+ case _UT('z'): \
+ case _UT('Z')
+
+
+
+#define URI_SET_SUB_DELIMS \
+ _UT('!'): \
+ case _UT('$'): \
+ case _UT('&'): \
+ case _UT('\''): \
+ case _UT('('): \
+ case _UT(')'): \
+ case _UT('*'): \
+ case _UT('+'): \
+ case _UT(','): \
+ case _UT(';'): \
+ case _UT('=')
+
+
+
+#define URI_SET_UNRESERVED \
+ URI_SET_ALPHA: \
+ case URI_SET_DIGIT: \
+ case _UT('-'): \
+ case _UT('.'): \
+ case _UT('_'): \
+ case _UT('~')
+
+
+
+UriBool URI_FUNC(IsWellFormedUserInfo)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ /* userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) */
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_UNRESERVED:
+ break;
+
+ /* pct-encoded */
+ case _UT('%'):
+ if (afterLast - first < 3) {
+ return URI_FALSE;
+ }
+ switch (first[1]) {
+ case URI_SET_HEXDIG:
+ break;
+ default:
+ return URI_FALSE;
+ }
+ switch (first[2]) {
+ case URI_SET_HEXDIG:
+ break;
+ default:
+ return URI_FALSE;
+ }
+ first += 2;
+ break;
+
+ case URI_SET_SUB_DELIMS:
+ break;
+
+ /* ":" */
+ case _UT(':'):
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+ }
+ return URI_TRUE;
+}
+
+
+
+int URI_FUNC(SetUserInfoMm)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ /* Input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ /* The RFC 3986 grammar reads:
+ * authority = [ userinfo "@" ] host [ ":" port ]
+ * So no user info without a host. */
+ if ((first != NULL) && (URI_FUNC(HasHost)(uri) == URI_FALSE)) {
+ return URI_ERROR_SETUSERINFO_HOST_NOT_SET;
+ }
+
+ if ((first != NULL) && (URI_FUNC(IsWellFormedUserInfo)(first, afterLast) == URI_FALSE)) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Clear old value */
+ if ((uri->owner == URI_TRUE) && (uri->userInfo.first != uri->userInfo.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->userInfo.first);
+ }
+ uri->userInfo.first = NULL;
+ uri->userInfo.afterLast = NULL;
+
+ /* Already done? */
+ if (first == NULL) {
+ return URI_SUCCESS;
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ const int res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value */
+ {
+ URI_TYPE(TextRange) sourceRange;
+ sourceRange.first = first;
+ sourceRange.afterLast = afterLast;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&uri->userInfo, &sourceRange, memory) == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+ }
+
+ return URI_SUCCESS;
+}
+
+
+
+int URI_FUNC(SetUserInfo)(URI_TYPE(Uri) * uri,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetUserInfoMm)(uri, first, afterLast, NULL);
+}
+
+
+
+#endif