diff --git a/lib/altsvc.c b/lib/altsvc.c index 11c75d45df..c57d3f6b40 100644 --- a/lib/altsvc.c +++ b/lib/altsvc.c @@ -471,6 +471,8 @@ static void altsvc_flush(struct altsvcinfo *asi, } } +#define ALTSVC_MA 1 +#define ALTSVC_PERSIST 2 static void altsvc_parse_params(const char **pp, time_t *pmaxage, bool *ppersist) @@ -482,36 +484,44 @@ static void altsvc_parse_params(const char **pp, for(;;) { struct Curl_str name; struct Curl_str val; - const char *vp; curl_off_t num; - bool quoted; + int keyword = 0; /* allow some extra whitespaces around name and value */ - if(curlx_str_until(pp, &name, 20, '=') || - curlx_str_single(pp, '=') || - curlx_str_cspn(pp, &val, ",;")) + if(curlx_str_until(pp, &name, MAX_ALTSVC_LINE, '=') || + curlx_str_single(pp, '=')) break; /* skip further parameter parsing */ curlx_str_trimblanks(&name); + curlx_str_passblanks(pp); + if(**pp == '\"') { + if(curlx_str_quotedword(pp, &val, MAX_ALTSVC_LINE)) + break; + } + else { + if(curlx_str_cspn(pp, &val, ",;\r\n")) + break; + } 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; + keyword = ALTSVC_MA; + else if(curlx_str_casecompare(&name, "persist")) + keyword = ALTSVC_PERSIST; + + if(keyword) { + const char *vp = curlx_str(&val); + const char *vend = vp + curlx_strlen(&val); + if(curlx_str_number(&vp, &num, TIME_T_MAX)) + break; /* not a number, skip further parameter parsing */ + if(vp != vend) + break; /* not entirely a number, skip further parameter parsing */ + if(keyword == ALTSVC_MA) + *pmaxage = (time_t)num; + else if(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 */ diff --git a/tests/unit/unit1654.c b/tests/unit/unit1654.c index 3f851d1bc7..706f9a0169 100644 --- a/tests/unit/unit1654.c +++ b/tests/unit/unit1654.c @@ -34,8 +34,10 @@ static CURLcode test_unit1654(const char *arg) CURL *curl = NULL; CURLcode result; struct altsvcinfo *asi = Curl_altsvc_init(); + struct altsvc *dstentry = NULL; struct Curl_peer *origin = NULL; const struct Curl_scheme *scheme = &Curl_scheme_https; + bool same_destination = FALSE; abort_if(!asi, "Curl_altsvc_i"); result = Curl_altsvc_load(asi, arg); @@ -160,6 +162,28 @@ static CURLcode test_unit1654(const char *arg) origin, ALPN_h2); fail_if(result, "Curl_altsvc_parse(12) failed!"); + /* Unknown extension parameters must not hide later known parameters. */ + if(Curl_peer_create(curl, scheme, "params.example", 443, &origin)) + goto fail; + result = Curl_altsvc_parse(curl, asi, + "h2=\":443\"; long-extension-parameter=token; " + "ext=token; " + "quoted=\"a;\\\"b\"; ma=120; persist=1\r\n", + origin, ALPN_h1); + fail_if(result, "Curl_altsvc_parse(13) failed!"); + if(!Curl_altsvc_lookup(asi, origin, ALPN_h1, &dstentry, + CURLALTSVC_H2, &same_destination)) { + fail_unless(FALSE, "alt-svc entry not found"); + goto fail; + } + fail_unless(dstentry->expires == 1548369261 + 120, + "unknown parameters hid ma"); + fail_unless(dstentry->persist, "unknown parameters hid persist"); + fail_unless(same_destination, "wrong alt-svc destination"); + + result = Curl_altsvc_parse(curl, asi, "clear\r\n", origin, ALPN_h1); + fail_if(result, "Curl_altsvc_parse(14) failed!"); + Curl_altsvc_save(curl, asi, outname); fail: