urlapi: add CURLUPART_ZONEID to set and get

The zoneid can be used with IPv6 numerical addresses.

Updated test 1560 to verify.

Closes #3834
This commit is contained in:
Daniel Stenberg 2019-05-03 13:18:12 +02:00
parent 0eec832603
commit 2d0e9b40d3
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
8 changed files with 74 additions and 23 deletions

View File

@ -35,7 +35,6 @@
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
@ -373,11 +372,6 @@
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

View File

@ -5,7 +5,7 @@
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" *
.\" * This software is licensed as described in the file COPYING, which
.\" * you should have received as part of this distribution. The terms
@ -76,6 +76,10 @@ Scheme cannot be URL decoded on get.
.IP CURLUPART_PASSWORD
.IP CURLUPART_OPTIONS
.IP CURLUPART_HOST
If the host part is an IPv6 numeric address, the zoneid will not be part of
the extracted host but is provided separately in \fICURLUPART_ZONEID\fP.
.IP CURLUPART_ZONEID
If the host name is a numeric IPv6 address, this field might also be set.
.IP CURLUPART_PORT
Port cannot be URL decoded on get.
.IP CURLUPART_PATH
@ -104,7 +108,7 @@ If this function returns an error, no URL part is returned.
}
.fi
.SH AVAILABILITY
Added in curl 7.62.0
Added in curl 7.62.0. CURLUPART_ZONEID was added in 7.65.0.
.SH "SEE ALSO"
.BR curl_url_cleanup "(3), " curl_url "(3), " curl_url_set "(3), "
.BR curl_url_dup "(3), "

View File

@ -62,6 +62,8 @@ Scheme cannot be URL decoded on set.
.IP CURLUPART_HOST
The host name can use IDNA. The string must then be encoded as your locale
says or UTF-8 (when winidn is used).
.IP CURLUPART_ZONEID
If the host name is a numeric IPv6 address, this field can also be set.
.IP CURLUPART_PORT
Port cannot be URL encoded on set. The given port number is provided as a
string and the decimal number must be between 1 and 65535. Anything else will
@ -127,7 +129,7 @@ If this function returns an error, no URL part is returned.
curl_url_cleanup(url);
.fi
.SH AVAILABILITY
Added in curl 7.62.0
Added in curl 7.62.0. CURLUPART_ZONEID was added in 7.65.0.
.SH "SEE ALSO"
.BR curl_url_cleanup "(3), " curl_url "(3), " curl_url_get "(3), "
.BR curl_url_dup "(3), "

View File

@ -764,6 +764,7 @@ CURLUPART_QUERY 7.62.0
CURLUPART_SCHEME 7.62.0
CURLUPART_URL 7.62.0
CURLUPART_USER 7.62.0
CURLUPART_ZONEID 7.65.0
CURLUSESSL_ALL 7.17.0
CURLUSESSL_CONTROL 7.17.0
CURLUSESSL_NONE 7.17.0

View File

@ -60,7 +60,8 @@ typedef enum {
CURLUPART_PORT,
CURLUPART_PATH,
CURLUPART_QUERY,
CURLUPART_FRAGMENT
CURLUPART_FRAGMENT,
CURLUPART_ZONEID /* added in 7.65.0 */
} CURLUPart;
#define CURLU_DEFAULT_PORT (1<<0) /* return default port number */

View File

@ -56,7 +56,7 @@ struct Curl_URL {
char *password;
char *options; /* IMAP only? */
char *host;
char *scopeid; /* for numerical IPv6 addresses */
char *zoneid; /* for numerical IPv6 addresses */
char *port;
char *path;
char *query;
@ -75,7 +75,7 @@ static void free_urlhandle(struct Curl_URL *u)
free(u->password);
free(u->options);
free(u->host);
free(u->scopeid);
free(u->zoneid);
free(u->port);
free(u->path);
free(u->query);
@ -606,7 +606,7 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
len = strspn(hostname, l);
if(hlen != len) {
/* this could now be '%[zone id]' */
char scopeid[16];
char zoneid[16];
if(hostname[len] == '%') {
int i = 0;
char *h = &hostname[len + 1];
@ -614,12 +614,12 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
if(!strncmp(h, "25", 2) && h[2] && (h[2] != ']'))
h += 2;
while(*h && (*h != ']') && (i < 15))
scopeid[i++] = *h++;
zoneid[i++] = *h++;
if(!i || (']' != *h))
return CURLUE_MALFORMED_INPUT;
scopeid[i] = 0;
u->scopeid = strdup(scopeid);
if(!u->scopeid)
zoneid[i] = 0;
u->zoneid = strdup(zoneid);
if(!u->zoneid)
return CURLUE_OUT_OF_MEMORY;
hostname[len] = ']'; /* insert end bracket */
hostname[len + 1] = 0; /* terminate the hostname */
@ -997,6 +997,9 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
ptr = u->host;
ifmissing = CURLUE_NO_HOST;
break;
case CURLUPART_ZONEID:
ptr = u->zoneid;
break;
case CURLUPART_PORT:
ptr = u->port;
ifmissing = CURLUE_NO_PORT;
@ -1082,16 +1085,16 @@ 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 ]' */
if((u->host[0] == '[') && u->zoneid) {
/* make it '[ host %25 zoneid ]' */
size_t hostlen = strlen(u->host);
size_t alen = hostlen + 3 + strlen(u->scopeid) + 1;
size_t alen = hostlen + 3 + strlen(u->zoneid) + 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);
"%%25%s]", u->zoneid);
}
url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
@ -1184,6 +1187,9 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
case CURLUPART_HOST:
storep = &u->host;
break;
case CURLUPART_ZONEID:
storep = &u->zoneid;
break;
case CURLUPART_PORT:
u->portnum = 0;
storep = &u->port;
@ -1227,8 +1233,11 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
break;
case CURLUPART_HOST:
storep = &u->host;
free(u->scopeid);
u->scopeid = NULL;
free(u->zoneid);
u->zoneid = NULL;
break;
case CURLUPART_ZONEID:
storep = &u->zoneid;
break;
case CURLUPART_PORT:
{

View File

@ -38,6 +38,8 @@ 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]
we got eth0
we got https://[fe80::20c:29ff:fe9c:409b%25clown]/hello.html
success
</stdout>
</verify>

View File

@ -414,6 +414,10 @@ static int checkurl(const char *url, const char *out)
/* !checksrc! disable SPACEBEFORECOMMA 1 */
static struct setcase set_parts_list[] = {
{"https://[::1%25fake]:1234/",
"zoneid=NULL,",
"https://[::1]:1234/",
0, 0, CURLUE_OK, CURLUE_OK},
{"https://host:1234/",
"port=NULL,",
"https://host/",
@ -547,6 +551,8 @@ static CURLUPart part2id(char *part)
return CURLUPART_QUERY;
if(!strcmp("fragment", part))
return CURLUPART_FRAGMENT;
if(!strcmp("zoneid", part))
return CURLUPART_ZONEID;
return 9999; /* bad input => bad output */
}
@ -571,6 +577,9 @@ static CURLUcode updateurl(CURLU *u, const char *cmd, unsigned int setflags)
/* for debugging this */
fprintf(stderr, "%s = %s [%d]\n", part, value, (int)what);
#endif
if(what > CURLUPART_ZONEID)
fprintf(stderr, "UNKNOWN part '%s'\n", part);
if(!strcmp("NULL", value))
uc = curl_url_set(u, what, NULL, setflags);
else if(!strcmp("\"\"", value))
@ -942,6 +951,35 @@ static int scopeid(void)
curl_free(url);
}
rc = curl_url_get(u, CURLUPART_ZONEID, &url, 0);
if(rc != CURLUE_OK) {
fprintf(stderr, "%s:%d curl_url_get CURLUPART_ZONEID returned %d\n",
__FILE__, __LINE__, (int)rc);
error++;
}
else {
printf("we got %s\n", url);
curl_free(url);
}
rc = curl_url_set(u, CURLUPART_ZONEID, "clown", 0);
if(rc != CURLUE_OK) {
fprintf(stderr, "%s:%d curl_url_set CURLUPART_ZONEID 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);
}
curl_url_cleanup(u);
return error;