1
0
mirror of https://github.com/moparisthebest/curl synced 2025-02-28 17:31:46 -05:00

alt-svc: add protocol version selection masking

So that users can mask in/out specific HTTP versions when Alt-Svc is
used.

 - Removed "h2c" and updated test case accordingly
 - Changed how the altsvc struct is laid out
 - Added ifdefs to make the unittest run even in a quiche-tree

Closes #4201
This commit is contained in:
Daniel Stenberg 2019-08-07 20:10:27 +02:00
parent a93b43cde8
commit 69b3ff5118
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
5 changed files with 69 additions and 64 deletions

View File

@ -54,9 +54,7 @@ static enum alpnid alpn2alpnid(char *name)
return ALPN_h1; return ALPN_h1;
if(strcasecompare(name, "h2")) if(strcasecompare(name, "h2"))
return ALPN_h2; return ALPN_h2;
if(strcasecompare(name, "h2c")) #if defined(USE_QUICHE) && !defined(UNITTESTS)
return ALPN_h2c;
#ifdef USE_QUICHE
if(strcasecompare(name, "h3-22")) if(strcasecompare(name, "h3-22"))
return ALPN_h3; return ALPN_h3;
#else #else
@ -74,10 +72,8 @@ const char *Curl_alpnid2str(enum alpnid id)
return "h1"; return "h1";
case ALPN_h2: case ALPN_h2:
return "h2"; return "h2";
case ALPN_h2c:
return "h2c";
case ALPN_h3: case ALPN_h3:
#ifdef USE_QUICHE #if defined(USE_QUICHE) && !defined(UNITTESTS)
return "h3-22"; return "h3-22";
#else #else
return "h3"; return "h3";
@ -90,8 +86,8 @@ const char *Curl_alpnid2str(enum alpnid id)
static void altsvc_free(struct altsvc *as) static void altsvc_free(struct altsvc *as)
{ {
free(as->srchost); free(as->src.host);
free(as->dsthost); free(as->dst.host);
free(as); free(as);
} }
@ -106,17 +102,17 @@ static struct altsvc *altsvc_createid(const char *srchost,
if(!as) if(!as)
return NULL; return NULL;
as->srchost = strdup(srchost); as->src.host = strdup(srchost);
if(!as->srchost) if(!as->src.host)
goto error; goto error;
as->dsthost = strdup(dsthost); as->dst.host = strdup(dsthost);
if(!as->dsthost) if(!as->dst.host)
goto error; goto error;
as->srcalpnid = srcalpnid; as->src.alpnid = srcalpnid;
as->dstalpnid = dstalpnid; as->dst.alpnid = dstalpnid;
as->srcport = curlx_ultous(srcport); as->src.port = curlx_ultous(srcport);
as->dstport = curlx_ultous(dstport); as->dst.port = curlx_ultous(dstport);
return as; return as;
error: error:
@ -235,8 +231,8 @@ static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
"\"%d%02d%02d " "\"%d%02d%02d "
"%02d:%02d:%02d\" " "%02d:%02d:%02d\" "
"%u %d\n", "%u %d\n",
Curl_alpnid2str(as->srcalpnid), as->srchost, as->srcport, Curl_alpnid2str(as->src.alpnid), as->src.host, as->src.port,
Curl_alpnid2str(as->dstalpnid), as->dsthost, as->dstport, Curl_alpnid2str(as->dst.alpnid), as->dst.host, as->dst.port,
stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
stamp.tm_hour, stamp.tm_min, stamp.tm_sec, stamp.tm_hour, stamp.tm_min, stamp.tm_sec,
as->persist, as->prio); as->persist, as->prio);
@ -261,7 +257,7 @@ struct altsvcinfo *Curl_altsvc_init(void)
#ifdef USE_NGHTTP2 #ifdef USE_NGHTTP2
| CURLALTSVC_H2 | CURLALTSVC_H2
#endif #endif
#ifdef USE_HTTP3 #ifdef ENABLE_QUIC
| CURLALTSVC_H3 | CURLALTSVC_H3
#endif #endif
; ;
@ -374,9 +370,9 @@ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
for(e = asi->list.head; e; e = n) { for(e = asi->list.head; e; e = n) {
struct altsvc *as = e->ptr; struct altsvc *as = e->ptr;
n = e->next; n = e->next;
if((srcalpnid == as->srcalpnid) && if((srcalpnid == as->src.alpnid) &&
(srcport == as->srcport) && (srcport == as->src.port) &&
strcasecompare(srchost, as->srchost)) { strcasecompare(srchost, as->src.host)) {
Curl_llist_remove(&asi->list, e, NULL); Curl_llist_remove(&asi->list, e, NULL);
altsvc_free(as); altsvc_free(as);
asi->num--; asi->num--;
@ -544,15 +540,15 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
bool Curl_altsvc_lookup(struct altsvcinfo *asi, bool Curl_altsvc_lookup(struct altsvcinfo *asi,
enum alpnid srcalpnid, const char *srchost, enum alpnid srcalpnid, const char *srchost,
int srcport, int srcport,
enum alpnid *dstalpnid, const char **dsthost, struct altsvc **dstentry,
int *dstport) const int versions) /* one or more bits */
{ {
struct curl_llist_element *e; struct curl_llist_element *e;
struct curl_llist_element *n; struct curl_llist_element *n;
time_t now = time(NULL); time_t now = time(NULL);
DEBUGASSERT(asi); DEBUGASSERT(asi);
DEBUGASSERT(srchost); DEBUGASSERT(srchost);
DEBUGASSERT(dsthost); DEBUGASSERT(dstentry);
for(e = asi->list.head; e; e = n) { for(e = asi->list.head; e; e = n) {
struct altsvc *as = e->ptr; struct altsvc *as = e->ptr;
@ -563,13 +559,12 @@ bool Curl_altsvc_lookup(struct altsvcinfo *asi,
altsvc_free(as); altsvc_free(as);
continue; continue;
} }
if((as->srcalpnid == srcalpnid) && if((as->src.alpnid == srcalpnid) &&
strcasecompare(as->srchost, srchost) && strcasecompare(as->src.host, srchost) &&
as->srcport == srcport) { (as->src.port == srcport) &&
(versions & as->dst.alpnid)) {
/* match */ /* match */
*dstalpnid = as->dstalpnid; *dstentry = as;
*dsthost = as->dsthost;
*dstport = as->dstport;
return TRUE; return TRUE;
} }
} }

View File

@ -28,20 +28,21 @@
#include "llist.h" #include "llist.h"
enum alpnid { enum alpnid {
ALPN_none, ALPN_none = 0,
ALPN_h1, ALPN_h1 = CURLALTSVC_H1,
ALPN_h2, ALPN_h2 = CURLALTSVC_H2,
ALPN_h2c, ALPN_h3 = CURLALTSVC_H3
ALPN_h3 };
struct althost {
char *host;
unsigned short port;
enum alpnid alpnid;
}; };
struct altsvc { struct altsvc {
char *srchost; struct althost src;
char *dsthost; struct althost dst;
unsigned short srcport;
unsigned short dstport;
enum alpnid srcalpnid;
enum alpnid dstalpnid;
time_t expires; time_t expires;
bool persist; bool persist;
int prio; int prio;
@ -68,8 +69,8 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
bool Curl_altsvc_lookup(struct altsvcinfo *asi, bool Curl_altsvc_lookup(struct altsvcinfo *asi,
enum alpnid srcalpnid, const char *srchost, enum alpnid srcalpnid, const char *srchost,
int srcport, int srcport,
enum alpnid *dstalpnid, const char **dsthost, struct altsvc **dstentry,
int *dstport); int versions); /* one or more CURLALTSVC_H* bits */
#else #else
/* disabled */ /* disabled */
#define Curl_altsvc_save(a,b) #define Curl_altsvc_save(a,b)

View File

@ -3158,42 +3158,51 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
if(data->asi && !host && (port == -1) && if(data->asi && !host && (port == -1) &&
(conn->handler->protocol == CURLPROTO_HTTPS)) { (conn->handler->protocol == CURLPROTO_HTTPS)) {
/* no connect_to match, try alt-svc! */ /* no connect_to match, try alt-svc! */
const char *nhost; enum alpnid srcalpnid;
int nport;
enum alpnid nalpnid;
enum alpnid salpnid;
bool hit; bool hit;
struct altsvc *as;
const int allowed_versions = ( ALPN_h1
#ifdef USE_NGHTTP2
| ALPN_h2
#endif
#ifdef ENABLE_QUIC
| ALPN_h3
#endif
) & data->asi->flags;
host = conn->host.rawalloc; host = conn->host.rawalloc;
#ifdef USE_NGHTTP2 #ifdef USE_NGHTTP2
/* with h2 support, check that first */ /* with h2 support, check that first */
salpnid = ALPN_h2; srcalpnid = ALPN_h2;
hit = Curl_altsvc_lookup(data->asi, hit = Curl_altsvc_lookup(data->asi,
salpnid, host, conn->remote_port, /* from */ srcalpnid, host, conn->remote_port, /* from */
&nalpnid, &nhost, &nport /* to */); &as /* to */,
allowed_versions);
if(!hit) if(!hit)
#endif #endif
{ {
salpnid = ALPN_h1; srcalpnid = ALPN_h1;
hit = Curl_altsvc_lookup(data->asi, hit = Curl_altsvc_lookup(data->asi,
salpnid, host, conn->remote_port, /* from */ srcalpnid, host, conn->remote_port, /* from */
&nalpnid, &nhost, &nport /* to */); &as /* to */,
allowed_versions);
} }
if(hit) { if(hit) {
char *hostd = strdup((char *)nhost); char *hostd = strdup((char *)as->dst.host);
if(!hostd) if(!hostd)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
conn->conn_to_host.rawalloc = hostd; conn->conn_to_host.rawalloc = hostd;
conn->conn_to_host.name = hostd; conn->conn_to_host.name = hostd;
conn->bits.conn_to_host = TRUE; conn->bits.conn_to_host = TRUE;
conn->conn_to_port = nport; conn->conn_to_port = as->dst.port;
conn->bits.conn_to_port = TRUE; conn->bits.conn_to_port = TRUE;
conn->bits.altused = TRUE; conn->bits.altused = TRUE;
infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d\n", infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d\n",
Curl_alpnid2str(salpnid), host, conn->remote_port, Curl_alpnid2str(srcalpnid), host, conn->remote_port,
Curl_alpnid2str(nalpnid), hostd, nport); Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
if(salpnid != nalpnid) { if(srcalpnid != as->dst.alpnid) {
/* protocol version switch */ /* protocol version switch */
switch(nalpnid) { switch(as->dst.alpnid) {
case ALPN_h1: case ALPN_h1:
conn->httpversion = 11; conn->httpversion = 11;
break; break;

View File

@ -32,7 +32,7 @@ unit1654
<file name="log/1654" mode="text"> <file name="log/1654" mode="text">
h2 example.com 443 h3 shiny.example.com 8443 "20191231 00:00:00" 0 1 h2 example.com 443 h3 shiny.example.com 8443 "20191231 00:00:00" 0 1
# a comment # a comment
h2c example.com 443 h3 shiny.example.com 8443 "20291231 23:30:00" 0 1 h2 foo.example.com 443 h3 shiny.example.com 8443 "20291231 23:30:00" 0 1
h1 example.com 443 h3 shiny.example.com 8443 "20121231 00:00:01" 0 1 h1 example.com 443 h3 shiny.example.com 8443 "20121231 00:00:01" 0 1
h3 example.com 443 h3 shiny.example.com 8443 "20131231 00:00:00" 0 1 h3 example.com 443 h3 shiny.example.com 8443 "20131231 00:00:00" 0 1
# also a comment # also a comment
@ -45,14 +45,14 @@ rubbish
# Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html # Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html
# This file was generated by libcurl! Edit at your own risk. # This file was generated by libcurl! Edit at your own risk.
h2 example.com 443 h3 shiny.example.com 8443 "20191231 00:00:00" 0 1 h2 example.com 443 h3 shiny.example.com 8443 "20191231 00:00:00" 0 1
h2c example.com 443 h3 shiny.example.com 8443 "20291231 23:30:00" 0 1 h2 foo.example.com 443 h3 shiny.example.com 8443 "20291231 23:30:00" 0 1
h1 example.com 443 h3 shiny.example.com 8443 "20121231 00:00:01" 0 1 h1 example.com 443 h3 shiny.example.com 8443 "20121231 00:00:01" 0 1
h3 example.com 443 h3 shiny.example.com 8443 "20131231 00:00:00" 0 1 h3 example.com 443 h3 shiny.example.com 8443 "20131231 00:00:00" 0 1
h1 example.org 8080 h2 example.com 8080 "20190125 22:34:21" 0 0 h1 example.org 8080 h2 example.com 8080 "20190125 22:34:21" 0 0
h1 2.example.org 8080 h3 2.example.org 8080 "20190125 22:34:21" 0 0 h1 2.example.org 8080 h3 2.example.org 8080 "20190125 22:34:21" 0 0
h1 3.example.org 8080 h2 example.com 8080 "20190125 22:34:21" 0 0 h1 3.example.org 8080 h2 example.com 8080 "20190125 22:34:21" 0 0
h1 3.example.org 8080 h3 yesyes.com 8080 "20190125 22:34:21" 0 0 h1 3.example.org 8080 h3 yesyes.com 8080 "20190125 22:34:21" 0 0
h2c example.org 80 h2 example.com 443 "20190124 22:36:21" 0 0 h2 example.org 80 h2 example.com 443 "20190124 22:36:21" 0 0
</file> </file>
</verify> </verify>
</testcase> </testcase>

View File

@ -90,7 +90,7 @@ UNITTEST_START
fail_unless(asi->num == 8, "wrong number of entries"); fail_unless(asi->num == 8, "wrong number of entries");
result = Curl_altsvc_parse(curl, asi, "h2=\"example.com:443\"; ma = 120;", result = Curl_altsvc_parse(curl, asi, "h2=\"example.com:443\"; ma = 120;",
ALPN_h2c, "example.org", 80); ALPN_h2, "example.org", 80);
if(result) { if(result) {
fprintf(stderr, "Curl_altsvc_parse(4) failed!\n"); fprintf(stderr, "Curl_altsvc_parse(4) failed!\n");
unitfail++; unitfail++;