aboutsummaryrefslogtreecommitdiffstats
path: root/lib/urlapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/urlapi.c')
-rw-r--r--lib/urlapi.c156
1 files changed, 95 insertions, 61 deletions
diff --git a/lib/urlapi.c b/lib/urlapi.c
index a0ee331d..fa514bce 100644
--- a/lib/urlapi.c
+++ b/lib/urlapi.c
@@ -64,6 +64,7 @@ struct Curl_URL {
char *fragment;
char *scratch; /* temporary scratch area */
+ char *temppath; /* temporary path pointer */
long portnum; /* the numerical version */
};
@@ -82,6 +83,7 @@ static void free_urlhandle(struct Curl_URL *u)
free(u->query);
free(u->fragment);
free(u->scratch);
+ free(u->temppath);
}
/* move the full contents of one handle onto another and
@@ -351,7 +353,7 @@ static char *concat_url(const char *base, const char *relurl)
else {
/* We got a new absolute path for this server */
- if((relurl[0] == '/') && (relurl[1] == '/')) {
+ if(relurl[1] == '/') {
/* the new URL starts with //, just keep the protocol part from the
original one */
*protsep = 0;
@@ -596,8 +598,12 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
size_t hlen = strlen(hostname);
if(hostname[0] == '[') {
+#ifdef ENABLE_IPV6
char dest[16]; /* fits a binary IPv6 address */
+#endif
const char *l = "0123456789abcdefABCDEF:.";
+ if(hlen < 5) /* '[::1]' is the shortest possible valid string */
+ return CURLUE_MALFORMED_INPUT;
hostname++;
hlen -= 2;
@@ -784,6 +790,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
if(junkscan(schemep))
return CURLUE_MALFORMED_INPUT;
+
}
else {
/* no scheme! */
@@ -804,11 +811,14 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
p++;
len = p - hostp;
- if(!len)
- return CURLUE_MALFORMED_INPUT;
-
- memcpy(hostname, hostp, len);
- hostname[len] = 0;
+ if(len) {
+ memcpy(hostname, hostp, len);
+ hostname[len] = 0;
+ }
+ else {
+ if(!(flags & CURLU_NO_AUTHORITY))
+ return CURLUE_MALFORMED_INPUT;
+ }
if((flags & CURLU_GUESS_SCHEME) && !schemep) {
/* legacy curl-style guess based on host name */
@@ -843,35 +853,60 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
if(junkscan(path))
return CURLUE_MALFORMED_INPUT;
- query = strchr(path, '?');
- if(query)
- *query++ = 0;
+ if((flags & CURLU_URLENCODE) && path[0]) {
+ /* worst case output length is 3x the original! */
+ char *newp = malloc(strlen(path) * 3);
+ if(!newp)
+ return CURLUE_OUT_OF_MEMORY;
+ path_alloced = TRUE;
+ strcpy_url(newp, path, TRUE); /* consider it relative */
+ u->temppath = path = newp;
+ }
- fragment = strchr(query?query:path, '#');
- if(fragment)
+ fragment = strchr(path, '#');
+ if(fragment) {
*fragment++ = 0;
+ if(fragment[0]) {
+ u->fragment = strdup(fragment);
+ if(!u->fragment)
+ return CURLUE_OUT_OF_MEMORY;
+ }
+ }
+
+ query = strchr(path, '?');
+ if(query) {
+ *query++ = 0;
+ /* done even if the query part is a blank string */
+ u->query = strdup(query);
+ if(!u->query)
+ return CURLUE_OUT_OF_MEMORY;
+ }
if(!path[0])
- /* if there's no path set, unset */
+ /* if there's no path left set, unset */
path = NULL;
- else if(!(flags & CURLU_PATH_AS_IS)) {
- /* sanitise paths and remove ../ and ./ sequences according to RFC3986 */
- char *newp = Curl_dedotdotify(path);
- if(!newp)
- return CURLUE_OUT_OF_MEMORY;
+ else {
+ if(!(flags & CURLU_PATH_AS_IS)) {
+ /* remove ../ and ./ sequences according to RFC3986 */
+ char *newp = Curl_dedotdotify(path);
+ if(!newp)
+ return CURLUE_OUT_OF_MEMORY;
- if(strcmp(newp, path)) {
- /* if we got a new version */
- path = newp;
- path_alloced = TRUE;
+ if(strcmp(newp, path)) {
+ /* if we got a new version */
+ if(path_alloced)
+ Curl_safefree(u->temppath);
+ u->temppath = path = newp;
+ path_alloced = TRUE;
+ }
+ else
+ free(newp);
}
- else
- free(newp);
- }
- if(path) {
+
u->path = path_alloced?path:strdup(path);
if(!u->path)
return CURLUE_OUT_OF_MEMORY;
+ u->temppath = NULL; /* used now */
}
if(hostname) {
@@ -889,28 +924,22 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
if(result)
return result;
- result = hostname_check(u, hostname);
- if(result)
- return result;
+ if(0 == strlen(hostname) && (flags & CURLU_NO_AUTHORITY)) {
+ /* Skip hostname check, it's allowed to be empty. */
+ }
+ else {
+ result = hostname_check(u, hostname);
+ if(result)
+ return result;
+ }
u->host = strdup(hostname);
if(!u->host)
return CURLUE_OUT_OF_MEMORY;
}
- if(query) {
- u->query = strdup(query);
- if(!u->query)
- return CURLUE_OUT_OF_MEMORY;
- }
- if(fragment && fragment[0]) {
- u->fragment = strdup(fragment);
- if(!u->fragment)
- return CURLUE_OUT_OF_MEMORY;
- }
-
- free(u->scratch);
- u->scratch = NULL;
+ Curl_safefree(u->scratch);
+ Curl_safefree(u->temppath);
return CURLUE_OK;
}
@@ -1075,24 +1104,23 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
else
return CURLUE_NO_SCHEME;
- if(scheme) {
- h = Curl_builtin_scheme(scheme);
- if(!port && (flags & CURLU_DEFAULT_PORT)) {
- /* there's no stored port number, but asked to deliver
- a default one for the scheme */
- if(h) {
- msnprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
- port = portbuf;
- }
- }
- else if(port) {
- /* there is a stored port number, but asked to inhibit if it matches
- the default one for the scheme */
- if(h && (h->defport == u->portnum) &&
- (flags & CURLU_NO_DEFAULT_PORT))
- port = NULL;
+ h = Curl_builtin_scheme(scheme);
+ if(!port && (flags & CURLU_DEFAULT_PORT)) {
+ /* there's no stored port number, but asked to deliver
+ a default one for the scheme */
+ if(h) {
+ msnprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
+ port = portbuf;
}
}
+ else if(port) {
+ /* there is a stored port number, but asked to inhibit if it matches
+ the default one for the scheme */
+ if(h && (h->defport == u->portnum) &&
+ (flags & CURLU_NO_DEFAULT_PORT))
+ port = NULL;
+ }
+
if(h && !(h->flags & PROTOPT_URLOPTIONS))
options = NULL;
@@ -1340,7 +1368,8 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
default:
return CURLUE_UNKNOWN_PART;
}
- if(storep) {
+ DEBUGASSERT(storep);
+ {
const char *newp = part;
size_t nalloc = strlen(part);
@@ -1432,9 +1461,14 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
}
if(what == CURLUPART_HOST) {
- if(hostname_check(u, (char *)newp)) {
- free((char *)newp);
- return CURLUE_MALFORMED_INPUT;
+ if(0 == strlen(newp) && (flags & CURLU_NO_AUTHORITY)) {
+ /* Skip hostname check, it's allowed to be empty. */
+ }
+ else {
+ if(hostname_check(u, (char *)newp)) {
+ free((char *)newp);
+ return CURLUE_MALFORMED_INPUT;
+ }
}
}