diff options
Diffstat (limited to 'libs/libcurl/src/urlapi.c')
-rw-r--r-- | libs/libcurl/src/urlapi.c | 181 |
1 files changed, 101 insertions, 80 deletions
diff --git a/libs/libcurl/src/urlapi.c b/libs/libcurl/src/urlapi.c index abce1abacf..7a938bbe9c 100644 --- a/libs/libcurl/src/urlapi.c +++ b/libs/libcurl/src/urlapi.c @@ -59,11 +59,11 @@ #define MAX_SCHEME_LEN 40
/*
- * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * If USE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
* sure we have _some_ value for AF_INET6 without polluting our fake value
* everywhere.
*/
-#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
+#if !defined(USE_IPV6) && !defined(AF_INET6)
#define AF_INET6 (AF_INET + 1)
#endif
@@ -79,7 +79,9 @@ struct Curl_URL { char *path;
char *query;
char *fragment;
- long portnum; /* the numerical version */
+ unsigned short portnum; /* the numerical version (if 'port' is set) */
+ BIT(query_present); /* to support blank */
+ BIT(fragment_present); /* to support blank */
};
#define DEFAULT_SCHEME "https"
@@ -232,10 +234,8 @@ size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen, /* the length of the scheme is the name part only */
size_t len = i;
if(buf) {
+ Curl_strntolower(buf, url, i);
buf[i] = 0;
- while(i--) {
- buf[i] = Curl_raw_tolower(url[i]);
- }
}
return len;
}
@@ -264,6 +264,7 @@ static CURLcode concat_url(char *base, const char *relurl, char **newurl) const char *useurl = relurl;
CURLcode result = CURLE_OK;
CURLUcode uc;
+ bool skip_slash = FALSE;
*newurl = NULL;
/* protsep points to the start of the host name */
@@ -283,48 +284,50 @@ static CURLcode concat_url(char *base, const char *relurl, char **newurl) *pathsep = 0;
/* we have a relative path to append to the last slash if there's one
- available, or if the new URL is just a query string (starts with a
- '?') we append the new one at the end of the entire currently worked
- out URL */
- if(useurl[0] != '?') {
+ available, or the new URL is just a query string (starts with a '?') or
+ a fragment (starts with '#') we append the new one at the end of the
+ current URL */
+ if((useurl[0] != '?') && (useurl[0] != '#')) {
pathsep = strrchr(protsep, '/');
if(pathsep)
*pathsep = 0;
- }
- /* Check if there's any slash after the host name, and if so, remember
- that position instead */
- pathsep = strchr(protsep, '/');
- if(pathsep)
- protsep = pathsep + 1;
- else
- protsep = NULL;
+ /* Check if there's any slash after the host name, and if so, remember
+ that position instead */
+ pathsep = strchr(protsep, '/');
+ if(pathsep)
+ protsep = pathsep + 1;
+ else
+ protsep = NULL;
- /* now deal with one "./" or any amount of "../" in the newurl
- and act accordingly */
+ /* now deal with one "./" or any amount of "../" in the newurl
+ and act accordingly */
- if((useurl[0] == '.') && (useurl[1] == '/'))
- useurl += 2; /* just skip the "./" */
+ if((useurl[0] == '.') && (useurl[1] == '/'))
+ useurl += 2; /* just skip the "./" */
- while((useurl[0] == '.') &&
- (useurl[1] == '.') &&
- (useurl[2] == '/')) {
- level++;
- useurl += 3; /* pass the "../" */
- }
+ while((useurl[0] == '.') &&
+ (useurl[1] == '.') &&
+ (useurl[2] == '/')) {
+ level++;
+ useurl += 3; /* pass the "../" */
+ }
- if(protsep) {
- while(level--) {
- /* cut off one more level from the right of the original URL */
- pathsep = strrchr(protsep, '/');
- if(pathsep)
- *pathsep = 0;
- else {
- *protsep = 0;
- break;
+ if(protsep) {
+ while(level--) {
+ /* cut off one more level from the right of the original URL */
+ pathsep = strrchr(protsep, '/');
+ if(pathsep)
+ *pathsep = 0;
+ else {
+ *protsep = 0;
+ break;
+ }
}
}
}
+ else
+ skip_slash = TRUE;
}
else {
/* We got a new absolute path for this server */
@@ -370,7 +373,7 @@ static CURLcode concat_url(char *base, const char *relurl, char **newurl) return result;
/* check if we need to append a slash */
- if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
+ if(('/' == useurl[0]) || (protsep && !*protsep) || skip_slash)
;
else {
result = Curl_dyn_addn(&newest, "/", 1);
@@ -532,7 +535,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host, if(portptr) {
char *rest = NULL;
- long port;
+ unsigned long port;
size_t keep = portptr - hostname;
/* Browser behavior adaptation. If there's a colon with no digits after,
@@ -550,15 +553,13 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host, if(!ISDIGIT(*portptr))
return CURLUE_BAD_PORT_NUMBER;
- port = strtol(portptr, &rest, 10); /* Port number must be decimal */
+ errno = 0;
+ port = strtoul(portptr, &rest, 10); /* Port number must be decimal */
- if(port > 0xffff)
+ if(errno || (port > 0xffff) || *rest)
return CURLUE_BAD_PORT_NUMBER;
- if(rest[0])
- return CURLUE_BAD_PORT_NUMBER;
-
- u->portnum = port;
+ u->portnum = (unsigned short) port;
/* generate a new port number string to get rid of leading zeroes etc */
free(u->port);
u->port = aprintf("%ld", port);
@@ -680,6 +681,7 @@ static int ipv4_normalize(struct dynbuf *host) if(*c == '[')
return HOST_IPV6;
+ errno = 0; /* for strtoul */
while(!done) {
char *endp = NULL;
unsigned long l;
@@ -687,6 +689,13 @@ static int ipv4_normalize(struct dynbuf *host) /* most importantly this doesn't allow a leading plus or minus */
return HOST_NAME;
l = strtoul(c, &endp, 0);
+ if(errno)
+ return HOST_NAME;
+#if SIZEOF_LONG > 4
+ /* a value larger than 32 bits */
+ if(l > UINT_MAX)
+ return HOST_NAME;
+#endif
parts[n] = l;
c = endp;
@@ -706,16 +715,6 @@ static int ipv4_normalize(struct dynbuf *host) default:
return HOST_NAME;
}
-
- /* overflow */
- if((l == ULONG_MAX) && (errno == ERANGE))
- return HOST_NAME;
-
-#if SIZEOF_LONG > 4
- /* a value larger than 32 bits */
- if(l > UINT_MAX)
- return HOST_NAME;
-#endif
}
switch(n) {
@@ -846,8 +845,8 @@ out: return uc;
}
-CURLUcode Curl_url_set_authority(CURLU *u, const char *authority,
- unsigned int flags)
+/* used for HTTP/2 server push */
+CURLUcode Curl_url_set_authority(CURLU *u, const char *authority)
{
CURLUcode result;
struct dynbuf host;
@@ -855,8 +854,8 @@ CURLUcode Curl_url_set_authority(CURLU *u, const char *authority, DEBUGASSERT(authority);
Curl_dyn_init(&host, CURL_MAX_INPUT_LENGTH);
- result = parse_authority(u, authority, strlen(authority), flags,
- &host, !!u->scheme);
+ result = parse_authority(u, authority, strlen(authority),
+ CURLU_DISALLOW_USER, &host, !!u->scheme);
if(result)
Curl_dyn_free(&host);
else {
@@ -1242,6 +1241,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) fragment = strchr(path, '#');
if(fragment) {
fraglen = pathlen - (fragment - path);
+ u->fragment_present = TRUE;
if(fraglen > 1) {
/* skip the leading '#' in the copy but include the terminating null */
if(flags & CURLU_URLENCODE) {
@@ -1269,6 +1269,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) size_t qlen = fragment ? (size_t)(fragment - query) :
pathlen - (query - path);
pathlen -= qlen;
+ u->query_present = TRUE;
if(qlen > 1) {
if(flags & CURLU_URLENCODE) {
struct dynbuf enc;
@@ -1404,6 +1405,8 @@ CURLU *curl_url_dup(const CURLU *in) DUP(u, in, fragment);
DUP(u, in, zoneid);
u->portnum = in->portnum;
+ u->fragment_present = in->fragment_present;
+ u->query_present = in->query_present;
}
return u;
fail:
@@ -1488,10 +1491,16 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what, ptr = u->query;
ifmissing = CURLUE_NO_QUERY;
plusdecode = urldecode;
+ if(ptr && !ptr[0] && !(flags & CURLU_GET_EMPTY))
+ /* there was a blank query and the user do not ask for it */
+ ptr = NULL;
break;
case CURLUPART_FRAGMENT:
ptr = u->fragment;
ifmissing = CURLUE_NO_FRAGMENT;
+ if(!ptr && u->fragment_present && flags & CURLU_GET_EMPTY)
+ /* there was a blank fragment and the user asks for it */
+ ptr = "";
break;
case CURLUPART_URL: {
char *url;
@@ -1499,13 +1508,18 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what, char *options = u->options;
char *port = u->port;
char *allochost = NULL;
+ bool show_fragment =
+ u->fragment || (u->fragment_present && flags & CURLU_GET_EMPTY);
+ bool show_query =
+ (u->query && u->query[0]) ||
+ (u->query_present && flags & CURLU_GET_EMPTY);
punycode = (flags & CURLU_PUNYCODE)?1:0;
depunyfy = (flags & CURLU_PUNY2IDN)?1:0;
if(u->scheme && strcasecompare("file", u->scheme)) {
url = aprintf("file://%s%s%s",
u->path,
- u->fragment? "#": "",
- u->fragment? u->fragment : "");
+ show_fragment ? "#": "",
+ u->fragment ? u->fragment : "");
}
else if(!u->host)
return CURLUE_NO_HOST;
@@ -1593,9 +1607,9 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what, port ? ":": "",
port ? port : "",
u->path ? u->path : "/",
- (u->query && u->query[0]) ? "?": "",
- (u->query && u->query[0]) ? u->query : "",
- u->fragment? "#": "",
+ show_query ? "?": "",
+ u->query ? u->query : "",
+ show_fragment ? "#": "",
u->fragment? u->fragment : "");
free(allochost);
}
@@ -1687,7 +1701,6 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, const char *part, unsigned int flags)
{
char **storep = NULL;
- long port = 0;
bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0;
bool plusencode = FALSE;
bool urlskipslash = FALSE;
@@ -1730,9 +1743,11 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, break;
case CURLUPART_QUERY:
storep = &u->query;
+ u->query_present = FALSE;
break;
case CURLUPART_FRAGMENT:
storep = &u->fragment;
+ u->fragment_present = FALSE;
break;
default:
return CURLUE_UNKNOWN_PART;
@@ -1794,18 +1809,26 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, storep = &u->zoneid;
break;
case CURLUPART_PORT:
- {
- char *endp;
- urlencode = FALSE; /* never */
- port = strtol(part, &endp, 10); /* Port number must be decimal */
- if((port <= 0) || (port > 0xffff))
- return CURLUE_BAD_PORT_NUMBER;
- if(*endp)
- /* weirdly provided number, not good! */
+ if(!ISDIGIT(part[0]))
+ /* not a number */
return CURLUE_BAD_PORT_NUMBER;
- storep = &u->port;
- }
- break;
+ else {
+ char *tmp;
+ char *endp;
+ unsigned long port;
+ errno = 0;
+ port = strtoul(part, &endp, 10); /* must be decimal */
+ if(errno || (port > 0xffff) || *endp)
+ /* weirdly provided number, not good! */
+ return CURLUE_BAD_PORT_NUMBER;
+ tmp = strdup(part);
+ if(!tmp)
+ return CURLUE_OUT_OF_MEMORY;
+ free(u->port);
+ u->port = tmp;
+ u->portnum = (unsigned short)port;
+ return CURLUE_OK;
+ }
case CURLUPART_PATH:
urlskipslash = TRUE;
leadingslash = TRUE; /* enforce */
@@ -1816,9 +1839,11 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, appendquery = (flags & CURLU_APPENDQUERY)?1:0;
equalsencode = appendquery;
storep = &u->query;
+ u->query_present = TRUE;
break;
case CURLUPART_FRAGMENT:
storep = &u->fragment;
+ u->fragment_present = TRUE;
break;
case CURLUPART_URL: {
/*
@@ -1966,9 +1991,5 @@ nomem: free(*storep);
*storep = (char *)newp;
}
- /* set after the string, to make it not assigned if the allocation above
- fails */
- if(port)
- u->portnum = port;
return CURLUE_OK;
}
|