mirror of
https://github.com/curl/curl.git
synced 2026-07-30 20:58:06 +03:00
urlapi: refactor and simplify curl_url_set
Create and make use of: - url_encode_part() - url_uppercasehex_part() - url_append_query() - url_sethost() Closes #22012
This commit is contained in:
parent
9061302a86
commit
79a24161ab
1 changed files with 134 additions and 104 deletions
238
lib/urlapi.c
238
lib/urlapi.c
|
|
@ -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;
|
||||
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);
|
||||
|
||||
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(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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue