mirror of
https://github.com/curl/curl.git
synced 2026-07-10 03:27:18 +03:00
altsvc: use Curl_peer in processing
Use `data->state.origin` when processing alt-avc information. Decomplexify parsing function. Closes #22184
This commit is contained in:
parent
2f1e94eaed
commit
cfc7922377
7 changed files with 247 additions and 198 deletions
354
lib/altsvc.c
354
lib/altsvc.c
|
|
@ -78,6 +78,12 @@ const char *Curl_alpnid2str(enum alpnid id)
|
|||
}
|
||||
}
|
||||
|
||||
static enum alpnid Curl_str2alpnid(const struct Curl_str *cstr)
|
||||
{
|
||||
return Curl_alpn2alpnid((const unsigned char *)curlx_str(cstr),
|
||||
curlx_strlen(cstr));
|
||||
}
|
||||
|
||||
#define altsvc_free(x) curlx_free(x)
|
||||
|
||||
static struct altsvc *altsvc_createid(const char *srchost,
|
||||
|
|
@ -447,23 +453,115 @@ static bool hostcompare(const char *host, const char *check)
|
|||
|
||||
/* altsvc_flush() removes all alternatives for this source origin from the
|
||||
list */
|
||||
static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
|
||||
const char *srchost, unsigned short srcport)
|
||||
static void altsvc_flush(struct altsvcinfo *asi,
|
||||
struct Curl_peer *origin,
|
||||
enum alpnid origin_alpnid)
|
||||
{
|
||||
struct Curl_llist_node *e;
|
||||
struct Curl_llist_node *n;
|
||||
for(e = Curl_llist_head(&asi->list); e; e = n) {
|
||||
struct altsvc *as = Curl_node_elem(e);
|
||||
n = Curl_node_next(e);
|
||||
if((srcalpnid == as->src.alpnid) &&
|
||||
(srcport == as->src.port) &&
|
||||
hostcompare(srchost, as->src.host)) {
|
||||
if((origin_alpnid == as->src.alpnid) &&
|
||||
(origin->port == as->src.port) &&
|
||||
hostcompare(origin->hostname, as->src.host)) {
|
||||
Curl_node_remove(e);
|
||||
altsvc_free(as);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void altsvc_parse_params(const char **pp,
|
||||
time_t *pmaxage,
|
||||
bool *ppersist)
|
||||
{
|
||||
curlx_str_passblanks(pp);
|
||||
if(curlx_str_single(pp, ';'))
|
||||
return;
|
||||
|
||||
for(;;) {
|
||||
struct Curl_str name;
|
||||
struct Curl_str val;
|
||||
const char *vp;
|
||||
curl_off_t num;
|
||||
bool quoted;
|
||||
|
||||
/* allow some extra whitespaces around name and value */
|
||||
if(curlx_str_until(pp, &name, 20, '=') ||
|
||||
curlx_str_single(pp, '=') ||
|
||||
curlx_str_cspn(pp, &val, ",;"))
|
||||
break; /* skip further parameter parsing */
|
||||
|
||||
curlx_str_trimblanks(&name);
|
||||
curlx_str_trimblanks(&val);
|
||||
/* the value might be quoted */
|
||||
vp = curlx_str(&val);
|
||||
quoted = (*vp == '\"');
|
||||
if(quoted)
|
||||
vp++;
|
||||
/* we process 2 number value parameters: 'ma' and 'persist' */
|
||||
if(curlx_str_number(&vp, &num, TIME_T_MAX))
|
||||
break; /* not a number, skip further parameter parsing */
|
||||
|
||||
if(curlx_str_casecompare(&name, "ma"))
|
||||
*pmaxage = (time_t)num;
|
||||
else if(curlx_str_casecompare(&name, "persist") && (num == 1))
|
||||
*ppersist = TRUE;
|
||||
|
||||
*pp = vp; /* point to the byte ending the value */
|
||||
curlx_str_passblanks(pp);
|
||||
if(quoted && curlx_str_single(pp, '\"'))
|
||||
break; /* was quoted but not ended in quote, skip */
|
||||
curlx_str_passblanks(pp);
|
||||
if(curlx_str_single(pp, ';'))
|
||||
break; /* no further parameters */
|
||||
}
|
||||
}
|
||||
|
||||
static bool altsvc_parse_dest(const char **pp,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_str *dsthost,
|
||||
uint16_t *pdstport)
|
||||
{
|
||||
curl_off_t port = 0;
|
||||
|
||||
if(curlx_str_single(pp, '\"'))
|
||||
return FALSE;
|
||||
|
||||
/* quoted string, with hostname or just :port ? */
|
||||
if(curlx_str_single(pp, ':')) { /* is hostname:port ? */
|
||||
if(curlx_str_single(pp, '[')) { /* DNS hostname/ipv4 */
|
||||
if(curlx_str_until(pp, dsthost, MAX_ALTSVC_HOSTLEN, ':')) {
|
||||
infof(data, "Bad alt-svc hostname, ignoring.");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else { /* IPv6 hostname */
|
||||
if(curlx_str_until(pp, dsthost, MAX_IPADR_LEN, ']') ||
|
||||
curlx_str_single(pp, ']')) {
|
||||
infof(data, "Bad alt-svc IPv6 hostname, ignoring.");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if(curlx_str_single(pp, ':'))
|
||||
return FALSE; /* not followed by ':' */
|
||||
}
|
||||
else /* is only :port, hostname is effectively origin */
|
||||
curlx_str_assign(dsthost, origin->hostname,
|
||||
strlen(origin->hostname));
|
||||
|
||||
if(curlx_str_number(pp, &port, 0xffff)) {
|
||||
infof(data, "Unknown alt-svc port number, ignoring.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*pdstport = (uint16_t)port;
|
||||
if(curlx_str_single(pp, '\"'))
|
||||
return FALSE; /* quoted string not ending here as expected */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Curl_altsvc_parse() takes an incoming alt-svc response header and stores
|
||||
* the data correctly in the cache.
|
||||
|
|
@ -477,161 +575,91 @@ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
|
|||
*/
|
||||
CURLcode Curl_altsvc_parse(struct Curl_easy *data,
|
||||
struct altsvcinfo *asi, const char *value,
|
||||
enum alpnid srcalpnid, const char *srchost,
|
||||
unsigned short srcport)
|
||||
struct Curl_peer *origin,
|
||||
enum alpnid origin_alpnid)
|
||||
{
|
||||
const char *p = value;
|
||||
struct altsvc *as;
|
||||
unsigned short dstport = srcport; /* the same by default */
|
||||
size_t entries = 0;
|
||||
struct Curl_str alpn;
|
||||
const char *p;
|
||||
|
||||
DEBUGASSERT(asi);
|
||||
DEBUGASSERT(origin);
|
||||
/* RFC 7838, The "Alt-Svc" header field value is basically
|
||||
* Alt-Svc: (clear|alpn="(host)?:port"\s*(;\s*parameter=value)*)
|
||||
* This can be repeated, comma-separated.
|
||||
*
|
||||
* We parse "best effort", ignoring values we do not recognize.
|
||||
*/
|
||||
|
||||
/* initial check for "clear" */
|
||||
/* Try to catch a standalone "clear" */
|
||||
p = value;
|
||||
if(!curlx_str_cspn(&p, &alpn, ";\n\r")) {
|
||||
curlx_str_trimblanks(&alpn);
|
||||
/* "clear" is a magic keyword */
|
||||
if(curlx_str_casecompare(&alpn, "clear")) {
|
||||
/* Flush cached alternatives for this source origin */
|
||||
altsvc_flush(asi, srcalpnid, srchost, srcport);
|
||||
altsvc_flush(asi, origin, origin_alpnid);
|
||||
return CURLE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
p = value;
|
||||
/* Not a standalone "clear", parse from start for alpn entries */
|
||||
for(p = value; *p;) {
|
||||
time_t maxage = 24 * 3600; /* default is 24 hours */
|
||||
bool persist = FALSE;
|
||||
enum alpnid dstalpnid;
|
||||
struct Curl_str dsthost;
|
||||
uint16_t dstport;
|
||||
|
||||
if(curlx_str_until(&p, &alpn, MAX_ALTSVC_LINE, '='))
|
||||
return CURLE_OK; /* strange line */
|
||||
if(curlx_str_until(&p, &alpn, MAX_ALTSVC_LINE, '='))
|
||||
break; /* not another entry, leave */
|
||||
curlx_str_trimblanks(&alpn);
|
||||
dstalpnid = Curl_str2alpnid(&alpn);
|
||||
|
||||
curlx_str_trimblanks(&alpn);
|
||||
if(curlx_str_single(&p, '='))
|
||||
break;
|
||||
|
||||
do {
|
||||
if(!curlx_str_single(&p, '=')) {
|
||||
time_t maxage = 24 * 3600; /* default is 24 hours */
|
||||
bool persist = FALSE;
|
||||
/* [protocol]="[host][:port], [protocol]="[host][:port]" */
|
||||
enum alpnid dstalpnid = Curl_str2alpnid(&alpn);
|
||||
if(!curlx_str_single(&p, '\"')) {
|
||||
struct Curl_str dsthost;
|
||||
curl_off_t port = 0;
|
||||
if(curlx_str_single(&p, ':')) {
|
||||
/* hostname starts here */
|
||||
if(curlx_str_single(&p, '[')) {
|
||||
if(curlx_str_until(&p, &dsthost, MAX_ALTSVC_HOSTLEN, ':')) {
|
||||
infof(data, "Bad alt-svc hostname, ignoring.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* IPv6 hostname */
|
||||
if(curlx_str_until(&p, &dsthost, MAX_IPADR_LEN, ']') ||
|
||||
curlx_str_single(&p, ']')) {
|
||||
infof(data, "Bad alt-svc IPv6 hostname, ignoring.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(curlx_str_single(&p, ':'))
|
||||
break;
|
||||
}
|
||||
/* Parse altsvc hostname:port */
|
||||
if(!altsvc_parse_dest(&p, data, origin, &dsthost, &dstport))
|
||||
break;
|
||||
|
||||
/* Parse optional parameters */
|
||||
altsvc_parse_params(&p, &maxage, &persist);
|
||||
|
||||
if(dstalpnid) { /* this is a known ALPN id, e.g. not ALPN_none */
|
||||
if(!entries++)
|
||||
/* Flush cached alternatives for this source origin, if any - when
|
||||
this is the first entry of the line. */
|
||||
altsvc_flush(asi, origin, origin_alpnid);
|
||||
|
||||
as = altsvc_createid(origin->hostname, strlen(origin->hostname),
|
||||
curlx_str(&dsthost),
|
||||
curlx_strlen(&dsthost),
|
||||
origin_alpnid, dstalpnid,
|
||||
origin->port, dstport);
|
||||
if(as) {
|
||||
time_t secs = time(NULL);
|
||||
/* The expires time also needs to take the Age: value (if any)
|
||||
into account. [See RFC 7838 section 3.1] */
|
||||
if(maxage > (TIME_T_MAX - secs))
|
||||
as->expires = TIME_T_MAX;
|
||||
else
|
||||
/* no destination name, use source host */
|
||||
curlx_str_assign(&dsthost, srchost, strlen(srchost));
|
||||
|
||||
if(curlx_str_number(&p, &port, 0xffff)) {
|
||||
infof(data, "Unknown alt-svc port number, ignoring.");
|
||||
break;
|
||||
}
|
||||
|
||||
dstport = (unsigned short)port;
|
||||
|
||||
if(curlx_str_single(&p, '\"'))
|
||||
break;
|
||||
|
||||
/* Handle the optional 'ma' and 'persist' flags. Unknown flags are
|
||||
skipped. */
|
||||
curlx_str_passblanks(&p);
|
||||
if(!curlx_str_single(&p, ';')) {
|
||||
for(;;) {
|
||||
struct Curl_str name;
|
||||
struct Curl_str val;
|
||||
const char *vp;
|
||||
curl_off_t num;
|
||||
bool quoted;
|
||||
/* allow some extra whitespaces around name and value */
|
||||
if(curlx_str_until(&p, &name, 20, '=') ||
|
||||
curlx_str_single(&p, '=') ||
|
||||
curlx_str_cspn(&p, &val, ",;"))
|
||||
break;
|
||||
curlx_str_trimblanks(&name);
|
||||
curlx_str_trimblanks(&val);
|
||||
/* the value might be quoted */
|
||||
vp = curlx_str(&val);
|
||||
quoted = (*vp == '\"');
|
||||
if(quoted)
|
||||
vp++;
|
||||
if(!curlx_str_number(&vp, &num, TIME_T_MAX)) {
|
||||
if(curlx_str_casecompare(&name, "ma"))
|
||||
maxage = (time_t)num;
|
||||
else if(curlx_str_casecompare(&name, "persist") && (num == 1))
|
||||
persist = TRUE;
|
||||
}
|
||||
else
|
||||
break;
|
||||
p = vp; /* point to the byte ending the value */
|
||||
curlx_str_passblanks(&p);
|
||||
if(quoted && curlx_str_single(&p, '\"'))
|
||||
break;
|
||||
curlx_str_passblanks(&p);
|
||||
if(curlx_str_single(&p, ';'))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(dstalpnid) {
|
||||
if(!entries++)
|
||||
/* Flush cached alternatives for this source origin, if any - when
|
||||
this is the first entry of the line. */
|
||||
altsvc_flush(asi, srcalpnid, srchost, srcport);
|
||||
|
||||
as = altsvc_createid(srchost, strlen(srchost),
|
||||
curlx_str(&dsthost),
|
||||
curlx_strlen(&dsthost),
|
||||
srcalpnid, dstalpnid,
|
||||
srcport, dstport);
|
||||
if(as) {
|
||||
time_t secs = time(NULL);
|
||||
/* The expires time also needs to take the Age: value (if any)
|
||||
into account. [See RFC 7838 section 3.1] */
|
||||
if(maxage > (TIME_T_MAX - secs))
|
||||
as->expires = TIME_T_MAX;
|
||||
else
|
||||
as->expires = maxage + secs;
|
||||
as->persist = persist;
|
||||
altsvc_append(asi, as);
|
||||
infof(data, "Added alt-svc: %.*s:%d over %s",
|
||||
(int)curlx_strlen(&dsthost), curlx_str(&dsthost),
|
||||
dstport, Curl_alpnid2str(dstalpnid));
|
||||
}
|
||||
else
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
as->expires = maxage + secs;
|
||||
as->persist = persist;
|
||||
altsvc_append(asi, as);
|
||||
infof(data, "Added alt-svc: %.*s:%u over %s",
|
||||
(int)curlx_strlen(&dsthost), curlx_str(&dsthost),
|
||||
dstport, Curl_alpnid2str(dstalpnid));
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
/* after the double quote there can be a comma if there is another
|
||||
string or a semicolon if no more */
|
||||
if(curlx_str_single(&p, ','))
|
||||
break;
|
||||
|
||||
/* comma means another alternative is present */
|
||||
if(curlx_str_until(&p, &alpn, MAX_ALTSVC_LINE, '='))
|
||||
break;
|
||||
curlx_str_trimblanks(&alpn);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
else
|
||||
|
||||
/* When this is followed by a comma, we expect another entry */
|
||||
if(curlx_str_single(&p, ','))
|
||||
break;
|
||||
} while(1);
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
|
@ -640,38 +668,42 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
|
|||
* Return TRUE on a match
|
||||
*/
|
||||
bool Curl_altsvc_lookup(struct altsvcinfo *asi,
|
||||
enum alpnid srcalpnid, const char *srchost,
|
||||
int srcport,
|
||||
struct Curl_peer *origin,
|
||||
enum alpnid origin_alpnid,
|
||||
struct altsvc **dstentry,
|
||||
const int versions, /* one or more bits */
|
||||
bool *psame_destination)
|
||||
{
|
||||
struct Curl_llist_node *e;
|
||||
struct Curl_llist_node *n;
|
||||
time_t now = time(NULL);
|
||||
DEBUGASSERT(asi);
|
||||
DEBUGASSERT(srchost);
|
||||
DEBUGASSERT(origin);
|
||||
DEBUGASSERT(dstentry);
|
||||
|
||||
*psame_destination = FALSE;
|
||||
for(e = Curl_llist_head(&asi->list); e; e = n) {
|
||||
struct altsvc *as = Curl_node_elem(e);
|
||||
n = Curl_node_next(e);
|
||||
if(as->expires < now) {
|
||||
/* an expired entry, remove */
|
||||
Curl_node_remove(e);
|
||||
altsvc_free(as);
|
||||
continue;
|
||||
}
|
||||
if((as->src.alpnid == srcalpnid) &&
|
||||
hostcompare(srchost, as->src.host) &&
|
||||
(as->src.port == srcport) &&
|
||||
(versions & (int)as->dst.alpnid)) {
|
||||
/* match */
|
||||
*dstentry = as;
|
||||
*psame_destination = (srcport == as->dst.port) &&
|
||||
hostcompare(srchost, as->dst.host);
|
||||
return TRUE;
|
||||
|
||||
if(Curl_llist_count(&asi->list)) {
|
||||
struct Curl_llist_node *e;
|
||||
struct Curl_llist_node *n;
|
||||
time_t now = time(NULL);
|
||||
|
||||
for(e = Curl_llist_head(&asi->list); e; e = n) {
|
||||
struct altsvc *as = Curl_node_elem(e);
|
||||
n = Curl_node_next(e);
|
||||
if(as->expires < now) {
|
||||
/* an expired entry, remove */
|
||||
Curl_node_remove(e);
|
||||
altsvc_free(as);
|
||||
continue;
|
||||
}
|
||||
if((origin_alpnid == as->src.alpnid) &&
|
||||
(versions & (int)as->dst.alpnid) &&
|
||||
(origin->port == as->src.port) &&
|
||||
hostcompare(origin->hostname, as->src.host)) {
|
||||
/* match */
|
||||
*dstentry = as;
|
||||
/* alt-svc on the same host+port or another one? */
|
||||
*psame_destination = (origin->port == as->dst.port) &&
|
||||
hostcompare(origin->hostname, as->dst.host);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
|
|
|
|||
10
lib/altsvc.h
10
lib/altsvc.h
|
|
@ -28,6 +28,8 @@
|
|||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC)
|
||||
#include "llist.h"
|
||||
|
||||
struct Curl_peer;
|
||||
|
||||
/* the maximum number of alt-svc entries kept in a single cache */
|
||||
#define MAX_ALTSVC_ENTRIES 5000
|
||||
|
||||
|
|
@ -60,11 +62,11 @@ CURLcode Curl_altsvc_ctrl(struct Curl_easy *data, const long ctrl);
|
|||
void Curl_altsvc_cleanup(struct altsvcinfo **asi);
|
||||
CURLcode Curl_altsvc_parse(struct Curl_easy *data,
|
||||
struct altsvcinfo *asi, const char *value,
|
||||
enum alpnid srcalpnid, const char *srchost,
|
||||
unsigned short srcport);
|
||||
struct Curl_peer *origin,
|
||||
enum alpnid origin_alpnid);
|
||||
bool Curl_altsvc_lookup(struct altsvcinfo *asi,
|
||||
enum alpnid srcalpnid, const char *srchost,
|
||||
int srcport,
|
||||
struct Curl_peer *origin,
|
||||
enum alpnid origin_alpnid,
|
||||
struct altsvc **dstentry,
|
||||
const int versions, /* CURLALTSVC_H* bits */
|
||||
bool *psame_destination);
|
||||
|
|
|
|||
|
|
@ -57,12 +57,6 @@ enum alpnid Curl_alpn2alpnid(const unsigned char *name, size_t len)
|
|||
return ALPN_none; /* unknown, probably rubbish input */
|
||||
}
|
||||
|
||||
enum alpnid Curl_str2alpnid(const struct Curl_str *cstr)
|
||||
{
|
||||
return Curl_alpn2alpnid((const unsigned char *)curlx_str(cstr),
|
||||
curlx_strlen(cstr));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ struct Curl_peer;
|
|||
struct Curl_str;
|
||||
|
||||
enum alpnid Curl_alpn2alpnid(const unsigned char *name, size_t len);
|
||||
enum alpnid Curl_str2alpnid(const struct Curl_str *cstr);
|
||||
|
||||
/* generic function that returns how much time there is left to run, according
|
||||
to the timeouts set */
|
||||
|
|
|
|||
|
|
@ -3208,9 +3208,7 @@ static CURLcode http_header_a(struct Curl_easy *data,
|
|||
struct SingleRequest *k = &data->req;
|
||||
enum alpnid id = (k->httpversion == 30) ? ALPN_h3 :
|
||||
(k->httpversion == 20) ? ALPN_h2 : ALPN_h1;
|
||||
return Curl_altsvc_parse(
|
||||
data, data->asi, v, id, data->state.origin->hostname,
|
||||
curlx_uitous((unsigned int)data->state.origin->port));
|
||||
return Curl_altsvc_parse(data, data->asi, v, data->state.origin, id);
|
||||
}
|
||||
#else
|
||||
(void)data;
|
||||
|
|
|
|||
11
lib/url.c
11
lib/url.c
|
|
@ -1901,7 +1901,7 @@ static CURLcode url_set_conn_peer(struct Curl_easy *data,
|
|||
struct connectdata *conn)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
const struct Curl_peer *origin = conn->origin;
|
||||
struct Curl_peer *origin = conn->origin;
|
||||
struct Curl_peer *via_peer = NULL;
|
||||
struct curl_slist *conn_to_entry = data->set.connect_to;
|
||||
|
||||
|
|
@ -1953,8 +1953,7 @@ static CURLcode url_set_conn_peer(struct Curl_easy *data,
|
|||
if(!hit && (neg->wanted & CURL_HTTP_V3x)) {
|
||||
srcalpnid = ALPN_h3;
|
||||
hit = Curl_altsvc_lookup(data->asi,
|
||||
ALPN_h3, origin->hostname,
|
||||
origin->port, /* from */
|
||||
origin, ALPN_h3, /* from */
|
||||
&as /* to */,
|
||||
allowed_alpns, &same_dest);
|
||||
}
|
||||
|
|
@ -1964,8 +1963,7 @@ static CURLcode url_set_conn_peer(struct Curl_easy *data,
|
|||
!neg->h2_prior_knowledge) {
|
||||
srcalpnid = ALPN_h2;
|
||||
hit = Curl_altsvc_lookup(data->asi,
|
||||
ALPN_h2, origin->hostname,
|
||||
origin->port, /* from */
|
||||
origin, ALPN_h2, /* from */
|
||||
&as /* to */,
|
||||
allowed_alpns, &same_dest);
|
||||
}
|
||||
|
|
@ -1974,8 +1972,7 @@ static CURLcode url_set_conn_peer(struct Curl_easy *data,
|
|||
!neg->only_10) {
|
||||
srcalpnid = ALPN_h1;
|
||||
hit = Curl_altsvc_lookup(data->asi,
|
||||
ALPN_h1, origin->hostname,
|
||||
origin->port, /* from */
|
||||
origin, ALPN_h1, /* from */
|
||||
&as /* to */,
|
||||
allowed_alpns, &same_dest);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,12 @@ static CURLcode test_unit1654(const char *arg)
|
|||
|
||||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC)
|
||||
char outname[256];
|
||||
CURL *curl;
|
||||
CURL *curl = NULL;
|
||||
CURLcode result;
|
||||
struct altsvcinfo *asi = Curl_altsvc_init();
|
||||
struct Curl_peer *origin = NULL;
|
||||
const struct Curl_scheme *scheme = &Curl_scheme_https;
|
||||
|
||||
abort_if(!asi, "Curl_altsvc_i");
|
||||
result = Curl_altsvc_load(asi, arg);
|
||||
fail_if(result, "Curl_altsvc_load");
|
||||
|
|
@ -44,101 +47,125 @@ static CURLcode test_unit1654(const char *arg)
|
|||
fail_if(!curl, "curl_easy_init");
|
||||
if(!curl)
|
||||
goto fail;
|
||||
|
||||
fail_unless(Curl_llist_count(&asi->list) == 4, "wrong number of entries");
|
||||
curl_msnprintf(outname, sizeof(outname), "%s-out", arg);
|
||||
|
||||
if(Curl_peer_create(curl, scheme, "example.org", 8080, &origin))
|
||||
goto fail;
|
||||
result = Curl_altsvc_parse(curl, asi, "h2=\"example.com:8080\"\r\n",
|
||||
ALPN_h1, "example.org", 8080);
|
||||
origin, ALPN_h1);
|
||||
fail_if(result, "Curl_altsvc_parse() failed!");
|
||||
fail_unless(Curl_llist_count(&asi->list) == 5, "wrong number of entries");
|
||||
|
||||
if(Curl_peer_create(curl, scheme, "2.example.org", 8080, &origin))
|
||||
goto fail;
|
||||
result = Curl_altsvc_parse(curl, asi, "h3=\":8080\"\r\n",
|
||||
ALPN_h1, "2.example.org", 8080);
|
||||
origin, ALPN_h1);
|
||||
fail_if(result, "Curl_altsvc_parse(2) failed!");
|
||||
fail_unless(Curl_llist_count(&asi->list) == 6, "wrong number of entries");
|
||||
|
||||
if(Curl_peer_create(curl, scheme, "3.example.org", 8080, &origin))
|
||||
goto fail;
|
||||
result = Curl_altsvc_parse(curl, asi,
|
||||
"h2=\"example.com:8080\", "
|
||||
"h3=\"yesyes.com:8080\"\r\n",
|
||||
ALPN_h1, "3.example.org", 8080);
|
||||
origin, ALPN_h1);
|
||||
fail_if(result, "Curl_altsvc_parse(3) failed!");
|
||||
/* that one should make two entries */
|
||||
fail_unless(Curl_llist_count(&asi->list) == 8, "wrong number of entries");
|
||||
|
||||
if(Curl_peer_create(curl, scheme, "example.org", 80, &origin))
|
||||
goto fail;
|
||||
result = Curl_altsvc_parse(curl, asi,
|
||||
"h2=\"example.com:443\"; ma = 120;\r\n",
|
||||
ALPN_h2, "example.org", 80);
|
||||
origin, ALPN_h2);
|
||||
fail_if(result, "Curl_altsvc_parse(4) failed!");
|
||||
fail_unless(Curl_llist_count(&asi->list) == 9, "wrong number of entries");
|
||||
|
||||
/* quoted 'ma' value */
|
||||
if(Curl_peer_create(curl, scheme, "example.net", 80, &origin))
|
||||
goto fail;
|
||||
result = Curl_altsvc_parse(curl, asi,
|
||||
"h2=\"example.net:443\"; ma=\"180\";\r\n",
|
||||
ALPN_h2, "example.net", 80);
|
||||
origin, ALPN_h2);
|
||||
fail_if(result, "Curl_altsvc_parse(5) failed!");
|
||||
fail_unless(Curl_llist_count(&asi->list) == 10, "wrong number of entries");
|
||||
|
||||
if(Curl_peer_create(curl, scheme, "curl.se", 80, &origin))
|
||||
goto fail;
|
||||
result = Curl_altsvc_parse(curl, asi,
|
||||
"h2=\":443\"; ma=180, h3=\":443\"; "
|
||||
"persist = \"1\"; ma = 120;\r\n",
|
||||
ALPN_h1, "curl.se", 80);
|
||||
origin, ALPN_h1);
|
||||
fail_if(result, "Curl_altsvc_parse(6) failed!");
|
||||
fail_unless(Curl_llist_count(&asi->list) == 12, "wrong number of entries");
|
||||
|
||||
/* clear that one again and decrease the counter */
|
||||
result = Curl_altsvc_parse(curl, asi, "clear;\r\n",
|
||||
ALPN_h1, "curl.se", 80);
|
||||
origin, ALPN_h1);
|
||||
fail_if(result, "Curl_altsvc_parse(7) failed!");
|
||||
fail_unless(Curl_llist_count(&asi->list) == 10, "wrong number of entries");
|
||||
|
||||
result = Curl_altsvc_parse(curl, asi,
|
||||
"h2=\":443\", h3=\":443\"; "
|
||||
"persist = \"1\"; ma = 120;\r\n",
|
||||
ALPN_h1, "curl.se", 80);
|
||||
origin, ALPN_h1);
|
||||
fail_if(result, "Curl_altsvc_parse(6) failed!");
|
||||
fail_unless(Curl_llist_count(&asi->list) == 12, "wrong number of entries");
|
||||
|
||||
/* clear - without semicolon */
|
||||
result = Curl_altsvc_parse(curl, asi, "clear\r\n",
|
||||
ALPN_h1, "curl.se", 80);
|
||||
origin, ALPN_h1);
|
||||
fail_if(result, "Curl_altsvc_parse(7) failed!");
|
||||
fail_unless(Curl_llist_count(&asi->list) == 10, "wrong number of entries");
|
||||
|
||||
/* only a non-existing alpn */
|
||||
if(Curl_peer_create(curl, scheme, "5.example.net", 80, &origin))
|
||||
goto fail;
|
||||
result = Curl_altsvc_parse(curl, asi,
|
||||
"h6=\"example.net:443\"; ma=\"180\";\r\n",
|
||||
ALPN_h2, "5.example.net", 80);
|
||||
origin, ALPN_h2);
|
||||
fail_if(result, "Curl_altsvc_parse(8) failed!");
|
||||
|
||||
/* missing quote in alpn host */
|
||||
if(Curl_peer_create(curl, scheme, "6.example.net", 80, &origin))
|
||||
goto fail;
|
||||
result = Curl_altsvc_parse(curl, asi,
|
||||
"h2=\"example.net:443,; ma=\"180\";\r\n",
|
||||
ALPN_h2, "6.example.net", 80);
|
||||
origin, ALPN_h2);
|
||||
fail_if(result, "Curl_altsvc_parse(9) failed!");
|
||||
|
||||
/* missing port in hostname */
|
||||
if(Curl_peer_create(curl, scheme, "7.example.net", 80, &origin))
|
||||
goto fail;
|
||||
result = Curl_altsvc_parse(curl, asi,
|
||||
"h2=\"example.net\"; ma=\"180\";\r\n",
|
||||
ALPN_h2, "7.example.net", 80);
|
||||
origin, ALPN_h2);
|
||||
fail_if(result, "Curl_altsvc_parse(10) failed!");
|
||||
|
||||
/* illegal port in hostname */
|
||||
if(Curl_peer_create(curl, scheme, "8.example.net", 80, &origin))
|
||||
goto fail;
|
||||
result = Curl_altsvc_parse(curl, asi,
|
||||
"h2=\"example.net:70000\"; ma=\"180\";\r\n",
|
||||
ALPN_h2, "8.example.net", 80);
|
||||
origin, ALPN_h2);
|
||||
fail_if(result, "Curl_altsvc_parse(11) failed!");
|
||||
|
||||
if(Curl_peer_create(curl, scheme, "test.se", 443, &origin))
|
||||
goto fail;
|
||||
result = Curl_altsvc_parse(curl, asi,
|
||||
"h2=\"test2.se:443\"; ma=\"180 \" ; unknown=2, "
|
||||
"h2=\"test3.se:443\"; ma = 120;\r\n",
|
||||
ALPN_h2, "test.se", 443);
|
||||
origin, ALPN_h2);
|
||||
fail_if(result, "Curl_altsvc_parse(12) failed!");
|
||||
|
||||
Curl_altsvc_save(curl, asi, outname);
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
fail:
|
||||
curl_easy_cleanup(curl);
|
||||
Curl_altsvc_cleanup(&asi);
|
||||
Curl_peer_unlink(&origin);
|
||||
#endif
|
||||
|
||||
UNITTEST_END(curl_global_cleanup())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue