mirror of
https://github.com/curl/curl.git
synced 2025-02-23 15:10:03 +08:00
urlapi: strip off scope id from numerical IPv6 addresses
... to make the host name "usable". Store the scope id and put it back when extracting a URL out of it. Also makes curl_url_set() syntax check CURLUPART_HOST. Fixes #3817 Closes #3822
This commit is contained in:
parent
0281262819
commit
bdb2dbc103
@ -35,6 +35,7 @@
|
||||
1.16 Try to URL encode given URL
|
||||
1.17 Add support for IRIs
|
||||
1.18 try next proxy if one doesn't work
|
||||
1.19 add CURLUPART_SCOPEID
|
||||
1.20 SRV and URI DNS records
|
||||
1.21 Have the URL API offer IDN decoding
|
||||
1.22 CURLINFO_PAUSE_STATE
|
||||
@ -372,6 +373,11 @@
|
||||
|
||||
https://github.com/curl/curl/issues/896
|
||||
|
||||
1.19 add CURLUPART_SCOPEID
|
||||
|
||||
Add support for CURLUPART_SCOPEID to curl_url_set() and curl_url_get(). It is
|
||||
only really used when the host name is an IPv6 numerical address.
|
||||
|
||||
1.20 SRV and URI DNS records
|
||||
|
||||
Offer support for resolving SRV and URI DNS records for libcurl to know which
|
||||
|
63
lib/urlapi.c
63
lib/urlapi.c
@ -56,6 +56,7 @@ struct Curl_URL {
|
||||
char *password;
|
||||
char *options; /* IMAP only? */
|
||||
char *host;
|
||||
char *scopeid; /* for numerical IPv6 addresses */
|
||||
char *port;
|
||||
char *path;
|
||||
char *query;
|
||||
@ -74,6 +75,7 @@ static void free_urlhandle(struct Curl_URL *u)
|
||||
free(u->password);
|
||||
free(u->options);
|
||||
free(u->host);
|
||||
free(u->scopeid);
|
||||
free(u->port);
|
||||
free(u->path);
|
||||
free(u->query);
|
||||
@ -504,7 +506,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname)
|
||||
portptr = &hostname[len];
|
||||
else if('%' == endbracket) {
|
||||
int zonelen = len;
|
||||
if(1 == sscanf(hostname + zonelen, "25%*[^]]%c%n", &endbracket, &len)) {
|
||||
if(1 == sscanf(hostname + zonelen, "%*[^]]%c%n", &endbracket, &len)) {
|
||||
if(']' != endbracket)
|
||||
return CURLUE_MALFORMED_INPUT;
|
||||
portptr = &hostname[--zonelen + len + 1];
|
||||
@ -587,25 +589,45 @@ static CURLUcode junkscan(char *part)
|
||||
return CURLUE_OK;
|
||||
}
|
||||
|
||||
static CURLUcode hostname_check(char *hostname, unsigned int flags)
|
||||
static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
|
||||
{
|
||||
const char *l = NULL; /* accepted characters */
|
||||
size_t len;
|
||||
size_t hlen = strlen(hostname);
|
||||
(void)flags;
|
||||
|
||||
if(hostname[0] == '[') {
|
||||
hostname++;
|
||||
l = "0123456789abcdefABCDEF::.%";
|
||||
l = "0123456789abcdefABCDEF::.";
|
||||
hlen -= 2;
|
||||
}
|
||||
|
||||
if(l) {
|
||||
/* only valid letters are ok */
|
||||
len = strspn(hostname, l);
|
||||
if(hlen != len)
|
||||
/* hostname with bad content */
|
||||
return CURLUE_MALFORMED_INPUT;
|
||||
if(hlen != len) {
|
||||
/* this could now be '%[zone id]' */
|
||||
char scopeid[16];
|
||||
if(hostname[len] == '%') {
|
||||
int i = 0;
|
||||
char *h = &hostname[len + 1];
|
||||
/* pass '25' if present and is a url encoded percent sign */
|
||||
if(!strncmp(h, "25", 2) && h[2] && (h[2] != ']'))
|
||||
h += 2;
|
||||
while(*h && (*h != ']') && (i < 15))
|
||||
scopeid[i++] = *h++;
|
||||
if(!i || (']' != *h))
|
||||
return CURLUE_MALFORMED_INPUT;
|
||||
scopeid[i] = 0;
|
||||
u->scopeid = strdup(scopeid);
|
||||
if(!u->scopeid)
|
||||
return CURLUE_OUT_OF_MEMORY;
|
||||
hostname[len] = ']'; /* insert end bracket */
|
||||
hostname[len + 1] = 0; /* terminate the hostname */
|
||||
}
|
||||
else
|
||||
return CURLUE_MALFORMED_INPUT;
|
||||
/* hostname is fine */
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* letters from the second string is not ok */
|
||||
@ -856,7 +878,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = hostname_check(hostname, flags);
|
||||
result = hostname_check(u, hostname);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
@ -1021,6 +1043,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
|
||||
char *scheme;
|
||||
char *options = u->options;
|
||||
char *port = u->port;
|
||||
char *allochost = NULL;
|
||||
if(u->scheme && strcasecompare("file", u->scheme)) {
|
||||
url = aprintf("file://%s%s%s",
|
||||
u->path,
|
||||
@ -1059,6 +1082,18 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
|
||||
if(h && !(h->flags & PROTOPT_URLOPTIONS))
|
||||
options = NULL;
|
||||
|
||||
if((u->host[0] == '[') && u->scopeid) {
|
||||
/* make it '[ host %25 scopeid ]' */
|
||||
size_t hostlen = strlen(u->host);
|
||||
size_t alen = hostlen + 3 + strlen(u->scopeid) + 1;
|
||||
allochost = malloc(alen);
|
||||
if(!allochost)
|
||||
return CURLUE_OUT_OF_MEMORY;
|
||||
memcpy(allochost, u->host, hostlen - 1);
|
||||
msnprintf(&allochost[hostlen - 1], alen - hostlen + 1,
|
||||
"%%25%s]", u->scopeid);
|
||||
}
|
||||
|
||||
url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
scheme,
|
||||
u->user ? u->user : "",
|
||||
@ -1067,7 +1102,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
|
||||
options ? ";" : "",
|
||||
options ? options : "",
|
||||
(u->user || u->password || options) ? "@": "",
|
||||
u->host,
|
||||
allochost ? allochost : u->host,
|
||||
port ? ":": "",
|
||||
port ? port : "",
|
||||
(u->path && (u->path[0] != '/')) ? "/": "",
|
||||
@ -1076,6 +1111,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
|
||||
(u->query && u->query[0]) ? u->query : "",
|
||||
u->fragment? "#": "",
|
||||
u->fragment? u->fragment : "");
|
||||
free(allochost);
|
||||
}
|
||||
if(!url)
|
||||
return CURLUE_OUT_OF_MEMORY;
|
||||
@ -1191,6 +1227,8 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
|
||||
break;
|
||||
case CURLUPART_HOST:
|
||||
storep = &u->host;
|
||||
free(u->scopeid);
|
||||
u->scopeid = NULL;
|
||||
break;
|
||||
case CURLUPART_PORT:
|
||||
{
|
||||
@ -1370,6 +1408,13 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
free(*storep);
|
||||
*storep = (char *)newp;
|
||||
}
|
||||
|
@ -31,4 +31,14 @@ lib1560
|
||||
</tool>
|
||||
</client>
|
||||
|
||||
<verify>
|
||||
<stdout>
|
||||
we got [fe80::20c:29ff:fe9c:409b]
|
||||
we got https://[::1]/hello.html
|
||||
we got https://example.com/hello.html
|
||||
we got https://[fe80::20c:29ff:fe9c:409b%25eth0]/hello.html
|
||||
we got [fe80::20c:29ff:fe9c:409b]
|
||||
success
|
||||
</stdout>
|
||||
</verify>
|
||||
</testcase>
|
||||
|
@ -153,7 +153,13 @@ static struct testcase get_parts_list[] ={
|
||||
"http | [11] | [12] | [13] | [fd00:a41::50] | [15] | / | [16] | [17]",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"https://[::1%252]:1234",
|
||||
"https | [11] | [12] | [13] | [::1%252] | 1234 | / | [16] | [17]",
|
||||
"https | [11] | [12] | [13] | [::1] | 1234 | / | [16] | [17]",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
|
||||
/* here's "bad" zone id */
|
||||
{"https://[fe80::20c:29ff:fe9c:409b%eth0]:1234",
|
||||
"https | [11] | [12] | [13] | [fe80::20c:29ff:fe9c:409b] | 1234 "
|
||||
"| / | [16] | [17]",
|
||||
CURLU_DEFAULT_SCHEME, 0, CURLUE_OK},
|
||||
{"https://127.0.0.1:443",
|
||||
"https | [11] | [12] | [13] | 127.0.0.1 | [15] | / | [16] | [17]",
|
||||
@ -273,6 +279,18 @@ static struct testcase get_parts_list[] ={
|
||||
};
|
||||
|
||||
static struct urltestcase get_url_list[] = {
|
||||
{"https://[fe80::20c:29ff:fe9c:409b%]:1234",
|
||||
"",
|
||||
0, 0, CURLUE_MALFORMED_INPUT},
|
||||
{"https://[fe80::20c:29ff:fe9c:409b%25]:1234",
|
||||
"https://[fe80::20c:29ff:fe9c:409b%2525]:1234/",
|
||||
0, 0, CURLUE_OK},
|
||||
{"https://[fe80::20c:29ff:fe9c:409b%eth0]:1234",
|
||||
"https://[fe80::20c:29ff:fe9c:409b%25eth0]:1234/",
|
||||
0, 0, CURLUE_OK},
|
||||
{"https://[::%25fakeit]/moo",
|
||||
"https://[::%25fakeit]/moo",
|
||||
0, 0, CURLUE_OK},
|
||||
{"smtp.example.com/path/html",
|
||||
"smtp://smtp.example.com/path/html",
|
||||
CURLU_GUESS_SCHEME, 0, CURLUE_OK},
|
||||
@ -831,10 +849,111 @@ static int append(void)
|
||||
return error;
|
||||
}
|
||||
|
||||
static int scopeid(void)
|
||||
{
|
||||
CURLU *u;
|
||||
int error = 0;
|
||||
CURLUcode rc;
|
||||
char *url;
|
||||
|
||||
u = curl_url();
|
||||
rc = curl_url_set(u, CURLUPART_URL,
|
||||
"https://[fe80::20c:29ff:fe9c:409b%25eth0]/hello.html", 0);
|
||||
if(rc != CURLUE_OK) {
|
||||
fprintf(stderr, "%s:%d curl_url_set returned %d\n",
|
||||
__FILE__, __LINE__, (int)rc);
|
||||
error++;
|
||||
}
|
||||
|
||||
rc = curl_url_get(u, CURLUPART_HOST, &url, 0);
|
||||
if(rc != CURLUE_OK) {
|
||||
fprintf(stderr, "%s:%d curl_url_get CURLUPART_HOST returned %d\n",
|
||||
__FILE__, __LINE__, (int)rc);
|
||||
error++;
|
||||
}
|
||||
else {
|
||||
printf("we got %s\n", url);
|
||||
curl_free(url);
|
||||
}
|
||||
|
||||
rc = curl_url_set(u, CURLUPART_HOST, "[::1]", 0);
|
||||
if(rc != CURLUE_OK) {
|
||||
fprintf(stderr, "%s:%d curl_url_set CURLUPART_HOST returned %d\n",
|
||||
__FILE__, __LINE__, (int)rc);
|
||||
error++;
|
||||
}
|
||||
|
||||
rc = curl_url_get(u, CURLUPART_URL, &url, 0);
|
||||
if(rc != CURLUE_OK) {
|
||||
fprintf(stderr, "%s:%d curl_url_get CURLUPART_URL returned %d\n",
|
||||
__FILE__, __LINE__, (int)rc);
|
||||
error++;
|
||||
}
|
||||
else {
|
||||
printf("we got %s\n", url);
|
||||
curl_free(url);
|
||||
}
|
||||
|
||||
rc = curl_url_set(u, CURLUPART_HOST, "example.com", 0);
|
||||
if(rc != CURLUE_OK) {
|
||||
fprintf(stderr, "%s:%d curl_url_set CURLUPART_HOST returned %d\n",
|
||||
__FILE__, __LINE__, (int)rc);
|
||||
error++;
|
||||
}
|
||||
|
||||
rc = curl_url_get(u, CURLUPART_URL, &url, 0);
|
||||
if(rc != CURLUE_OK) {
|
||||
fprintf(stderr, "%s:%d curl_url_get CURLUPART_URL returned %d\n",
|
||||
__FILE__, __LINE__, (int)rc);
|
||||
error++;
|
||||
}
|
||||
else {
|
||||
printf("we got %s\n", url);
|
||||
curl_free(url);
|
||||
}
|
||||
|
||||
rc = curl_url_set(u, CURLUPART_HOST,
|
||||
"[fe80::20c:29ff:fe9c:409b%25eth0]", 0);
|
||||
if(rc != CURLUE_OK) {
|
||||
fprintf(stderr, "%s:%d curl_url_set CURLUPART_HOST returned %d\n",
|
||||
__FILE__, __LINE__, (int)rc);
|
||||
error++;
|
||||
}
|
||||
|
||||
rc = curl_url_get(u, CURLUPART_URL, &url, 0);
|
||||
if(rc != CURLUE_OK) {
|
||||
fprintf(stderr, "%s:%d curl_url_get CURLUPART_URL returned %d\n",
|
||||
__FILE__, __LINE__, (int)rc);
|
||||
error++;
|
||||
}
|
||||
else {
|
||||
printf("we got %s\n", url);
|
||||
curl_free(url);
|
||||
}
|
||||
|
||||
rc = curl_url_get(u, CURLUPART_HOST, &url, 0);
|
||||
if(rc != CURLUE_OK) {
|
||||
fprintf(stderr, "%s:%d curl_url_get CURLUPART_HOST returned %d\n",
|
||||
__FILE__, __LINE__, (int)rc);
|
||||
error++;
|
||||
}
|
||||
else {
|
||||
printf("we got %s\n", url);
|
||||
curl_free(url);
|
||||
}
|
||||
|
||||
curl_url_cleanup(u);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int test(char *URL)
|
||||
{
|
||||
(void)URL; /* not used */
|
||||
|
||||
if(scopeid())
|
||||
return 6;
|
||||
|
||||
if(append())
|
||||
return 5;
|
||||
|
||||
|
@ -168,7 +168,7 @@ UNITTEST_START
|
||||
u = curl_url();
|
||||
if(!u)
|
||||
goto fail;
|
||||
ipv6port = strdup("[fe80::250:56ff:fea7:da15%!25eth3]:80");
|
||||
ipv6port = strdup("[fe80::250:56ff:fea7:da15!25eth3]:80");
|
||||
if(!ipv6port)
|
||||
goto fail;
|
||||
ret = Curl_parse_port(u, ipv6port);
|
||||
@ -184,7 +184,7 @@ UNITTEST_START
|
||||
if(!ipv6port)
|
||||
goto fail;
|
||||
ret = Curl_parse_port(u, ipv6port);
|
||||
fail_unless(ret != CURLUE_OK, "Curl_parse_port returned non-error");
|
||||
fail_unless(ret == CURLUE_OK, "Curl_parse_port returned error");
|
||||
fail:
|
||||
free(ipv6port);
|
||||
curl_url_cleanup(u);
|
||||
|
Loading…
Reference in New Issue
Block a user