← Commit list

79a24161ab

Daniel Stenberg
Daniel Stenberg
2026-06-15
SUCCESS Duration: 195s

Subject

urlapi: refactor and simplify curl_url_set

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/urlapi.c+135 -105
@@ -1841,6 +1841,126 @@ static bool allowed_in_path(unsigned char x)
return FALSE;
}
+static CURLUcode url_encode_part(struct dynbuf *encp,
+ const char *part,
+ bool plusencode,
+ bool pathmode,
+ bool equalsencode)
+{
+ const unsigned char *i;
+
+ for(i = (const unsigned char *)part; *i; i++) {
+ CURLcode result;
+ if((*i == ' ') && plusencode)
+ result = curlx_dyn_addn(encp, "+", 1);
+ else if(ISUNRESERVED(*i) ||
+ (pathmode && allowed_in_path(*i)) ||
+ ((*i == '=') && equalsencode)) {
+ if((*i == '=') && equalsencode)
+ /* only skip the first equals sign */
+ equalsencode = FALSE;
+ result = curlx_dyn_addn(encp, i, 1);
+ }
+ else {
+ unsigned char out[3] = { '%' };
+ Curl_hexbyte(&out[1], *i);
+ result = curlx_dyn_addn(encp, out, 3);
+ }
+ if(result)
+ return cc2cu(result);
+ }
+ return CURLUE_OK;
+}
+
+static CURLUcode url_uppercasehex_part(struct dynbuf *encp,
+ const char *part)
+{
+ char *p;
+ CURLcode result = curlx_dyn_add(encp, part);
+ if(result)
+ return cc2cu(result);
+ p = curlx_dyn_ptr(encp);
+ while(*p) {
+ /* make sure percent encoded are upper case */
+ if((*p == '%') && ISXDIGIT(p[1]) && ISXDIGIT(p[2]) &&
+ (ISLOWER(p[1]) || ISLOWER(p[2]))) {
+ p[1] = Curl_raw_toupper(p[1]);
+ p[2] = Curl_raw_toupper(p[2]);
+ p += 3;
+ }
+ else
+ p++;
+ }
+ return CURLUE_OK;
+}
+
+static CURLUcode url_append_query(CURLU *u, struct dynbuf *encp)
+{
+ /* Append the 'encp' string onto the old query. Add a '&' separator if none
+ is already present at the end of the existing query */
+
+ size_t querylen = u->query ? strlen(u->query) : 0;
+ bool addamperand = querylen && (u->query[querylen - 1] != '&');
+ if(querylen) {
+ struct dynbuf qbuf;
+ CURLcode result;
+ const char *newp = curlx_dyn_ptr(encp);
+ curlx_dyn_init(&qbuf, CURL_MAX_INPUT_LENGTH);
+
+ /* add original query */
+ result = curlx_dyn_addn(&qbuf, u->query, querylen);
+ if(!result && addamperand)
+ /* add ampersand */
+ result = curlx_dyn_addn(&qbuf, "&", 1);
+ if(!result)
+ /* add new query part */
+ result = curlx_dyn_add(&qbuf, newp);
+ if(result)
+ goto nomem;
+ curlx_dyn_free(encp);
+ curlx_free(u->query);
+ u->query = curlx_dyn_ptr(&qbuf);
+ return CURLUE_OK;
+nomem:
+ curlx_dyn_free(encp);
+ return cc2cu(result);
+ }
+ else {
+ curlx_free(u->query);
+ u->query = curlx_dyn_ptr(encp);
+ }
+ return CURLUE_OK;
+}
+
+static CURLUcode url_sethost(CURLU *u, struct dynbuf *encp,
+ bool urlencode,
+ unsigned int flags)
+{
+ size_t n = curlx_dyn_len(encp);
+ bool bad = FALSE;
+ char *newp = curlx_dyn_ptr(encp);
+ if(!n)
+ /* an empty hostname is okay if told so */
+ bad = (flags & CURLU_NO_AUTHORITY) ? FALSE : TRUE;
+ else if(!urlencode) {
+ /* if the hostname part was not URL encoded here, it was set already URL
+ encoded so we need to decode it to check */
+ size_t dlen;
+ char *decoded = NULL;
+ CURLcode result = Curl_urldecode(newp, n, &decoded, &dlen, REJECT_CTRL);
+ if(result || hostname_check(u, decoded, dlen))
+ bad = TRUE;
+ curlx_free(decoded);
+ }
+ else if(hostname_check(u, (char *)CURL_UNCONST(newp), n))
+ bad = TRUE;
+ if(bad) {
+ curlx_dyn_free(encp);
+ return CURLUE_BAD_HOSTNAME;
+ }
+ return CURLUE_OK;
+}
+
CURLUcode curl_url_set(CURLU *u, CURLUPart what,
const char *part, unsigned int flags)
{
@@ -1914,8 +2034,9 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
}
DEBUGASSERT(storep);
{
- const char *newp;
+ const char *newp = NULL;
struct dynbuf enc;
+ CURLUcode status;
curlx_dyn_init(&enc, (nalloc * 3) + 1 + leadingslash);
if(leadingslash && (part[0] != '/')) {
@@ -1923,111 +2044,20 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
if(result)
return cc2cu(result);
}
- if(urlencode) {
- const unsigned char *i;
-
- for(i = (const unsigned char *)part; *i; i++) {
- CURLcode result;
- if((*i == ' ') && plusencode) {
- result = curlx_dyn_addn(&enc, "+", 1);
- if(result)
- return CURLUE_OUT_OF_MEMORY;
- }
- else if(ISUNRESERVED(*i) ||
- (pathmode && allowed_in_path(*i)) ||
- ((*i == '=') && equalsencode)) {
- if((*i == '=') && equalsencode)
- /* only skip the first equals sign */
- equalsencode = FALSE;
- result = curlx_dyn_addn(&enc, i, 1);
- if(result)
- return cc2cu(result);
- }
- else {
- unsigned char out[3] = { '%' };
- Curl_hexbyte(&out[1], *i);
- result = curlx_dyn_addn(&enc, out, 3);
- if(result)
- return cc2cu(result);
- }
- }
- }
- else {
- char *p;
- CURLcode result = curlx_dyn_add(&enc, part);
- if(result)
- return cc2cu(result);
- p = curlx_dyn_ptr(&enc);
- while(*p) {
- /* make sure percent encoded are upper case */
- if((*p == '%') && ISXDIGIT(p[1]) && ISXDIGIT(p[2]) &&
- (ISLOWER(p[1]) || ISLOWER(p[2]))) {
- p[1] = Curl_raw_toupper(p[1]);
- p[2] = Curl_raw_toupper(p[2]);
- p += 3;
- }
- else
- p++;
- }
- }
- newp = curlx_dyn_ptr(&enc);
-
- if(appendquery && newp) {
- /* Append the 'newp' string onto the old query. Add a '&' separator if
- none is present at the end of the existing query already */
-
- size_t querylen = u->query ? strlen(u->query) : 0;
- bool addamperand = querylen && (u->query[querylen - 1] != '&');
- if(querylen) {
- struct dynbuf qbuf;
- curlx_dyn_init(&qbuf, CURL_MAX_INPUT_LENGTH);
-
- if(curlx_dyn_addn(&qbuf, u->query, querylen)) /* add original query */
- goto nomem;
-
- if(addamperand) {
- if(curlx_dyn_addn(&qbuf, "&", 1))
- goto nomem;
- }
- if(curlx_dyn_add(&qbuf, newp))
- goto nomem;
- curlx_dyn_free(&enc);
- curlx_free(*storep);
- *storep = curlx_dyn_ptr(&qbuf);
- return CURLUE_OK;
-nomem:
- curlx_dyn_free(&enc);
- return CURLUE_OUT_OF_MEMORY;
- }
- }
- else if(what == CURLUPART_HOST) {
- size_t n = curlx_dyn_len(&enc);
- if(!n && (flags & CURLU_NO_AUTHORITY)) {
- /* Skip hostname check, it is allowed to be empty. */
- }
- else {
- bool bad = FALSE;
- if(!n)
- bad = TRUE; /* empty hostname is not okay */
- else if(!urlencode) {
- /* if the hostname part was not URL encoded here, it was set ready
- URL encoded so we need to decode it to check */
- size_t dlen;
- char *decoded = NULL;
- CURLcode result =
- Curl_urldecode(newp, n, &decoded, &dlen, REJECT_CTRL);
- if(result || hostname_check(u, decoded, dlen))
- bad = TRUE;
- curlx_free(decoded);
- }
- else if(hostname_check(u, (char *)CURL_UNCONST(newp), n))
- bad = TRUE;
- if(bad) {
- curlx_dyn_free(&enc);
- return CURLUE_BAD_HOSTNAME;
- }
- }
+ if(urlencode)
+ status = url_encode_part(&enc, part, plusencode, pathmode, equalsencode);
+ else
+ status = url_uppercasehex_part(&enc, part);
+ if(!status) {
+ newp = curlx_dyn_ptr(&enc);
+
+ if(appendquery && newp)
+ return url_append_query(u, &enc);
+ else if(what == CURLUPART_HOST)
+ status = url_sethost(u, &enc, urlencode, flags);
}
+ if(status)
+ return status;
curlx_free(*storep);
*storep = (char *)CURL_UNCONST(newp);