diff --git a/lib/altsvc.c b/lib/altsvc.c index eb072bb49d..e0834cb663 100644 --- a/lib/altsvc.c +++ b/lib/altsvc.c @@ -144,6 +144,20 @@ static struct altsvc *altsvc_create(struct Curl_str *srchost, srcport, dstport); } +/* append the new entry to the list after possibly removing an old entry + first */ +static void altsvc_append(struct altsvcinfo *asi, struct altsvc *as) +{ + while(Curl_llist_count(&asi->list) >= MAX_ALTSVC_ENTRIES) { + /* It's full. Remove the first entry in the list */ + struct Curl_llist_node *e = Curl_llist_head(&asi->list); + struct altsvc *oldas = Curl_node_elem(e); + Curl_node_remove(e); + altsvc_free(oldas); + } + Curl_llist_append(&asi->list, as, &as->node); +} + /* only returns SERIOUS errors */ static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line) { @@ -180,7 +194,6 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line) curlx_str_newline(&line)) ; else { - struct altsvc *as; char dbuf[MAX_ALTSVC_DATELEN + 1]; time_t expires = 0; time_t now = time(NULL); @@ -192,12 +205,12 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line) Curl_getdate_capped(dbuf, &expires); if(now < expires) { - as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn, - (size_t)srcport, (size_t)dstport); + struct altsvc *as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn, + (size_t)srcport, (size_t)dstport); if(as) { as->expires = expires; as->persist = persist ? 1 : 0; - Curl_llist_append(&asi->list, as, &as->node); + altsvc_append(asi, as); } else return CURLE_OUT_OF_MEMORY; @@ -594,7 +607,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, else as->expires = maxage + secs; as->persist = persist; - Curl_llist_append(&asi->list, as, &as->node); + altsvc_append(asi, as); infof(data, "Added alt-svc: %.*s:%d over %s", (int)curlx_strlen(&dsthost), curlx_str(&dsthost), dstport, Curl_alpnid2str(dstalpnid)); diff --git a/lib/altsvc.h b/lib/altsvc.h index d1fed4fe1d..dc1740bce1 100644 --- a/lib/altsvc.h +++ b/lib/altsvc.h @@ -28,6 +28,9 @@ #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC) #include "llist.h" +/* the maximum number of alt-svc entries kept in a single cache */ +#define MAX_ALTSVC_ENTRIES 5000 + struct althost { char *host; uint16_t port; diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 78e3f26585..c3496b133f 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -221,7 +221,7 @@ test1638 test1639 test1640 test1641 test1642 test1643 test1644 \ \ test1650 test1651 test1652 test1653 test1654 test1655 test1656 test1657 \ test1658 test1659 test1660 test1661 test1662 test1663 test1664 test1665 \ -test1666 test1667 test1668 \ +test1666 test1667 test1668 test1669 \ \ test1670 test1671 test1672 test1673 \ \ diff --git a/tests/data/test1669 b/tests/data/test1669 new file mode 100644 index 0000000000..204b45b506 --- /dev/null +++ b/tests/data/test1669 @@ -0,0 +1,37 @@ + + + + +unittest +Alt-Svc + + + + + +unittest +alt-svc + + +# This date is exactly "20190124 22:34:21" UTC + +CURL_TIME=1548369261 + + +alt-svc load cache with >5000 entries + + +%LOGDIR/%TESTNUMBER + + +%repeat[5010 x h2 example.com 443 h3 shiny.example.com 8443 "20191231 00:00:00" 0 0%0a]% + + + + + +Allocations: 5100 +Maximum allocated: 600000 + + + diff --git a/tests/unit/Makefile.inc b/tests/unit/Makefile.inc index 459aee5f84..d8b2ed2d2e 100644 --- a/tests/unit/Makefile.inc +++ b/tests/unit/Makefile.inc @@ -41,7 +41,7 @@ TESTS_C = \ unit1636.c \ unit1650.c unit1651.c unit1652.c unit1653.c unit1654.c unit1655.c unit1656.c \ unit1657.c unit1658.c unit1660.c unit1661.c unit1663.c unit1664.c \ - unit1666.c unit1667.c unit1668.c \ + unit1666.c unit1667.c unit1668.c unit1669.c \ unit1979.c unit1980.c \ unit2600.c unit2601.c unit2602.c unit2603.c unit2604.c unit2605.c \ unit3200.c unit3205.c \ diff --git a/tests/unit/unit1669.c b/tests/unit/unit1669.c new file mode 100644 index 0000000000..625e004084 --- /dev/null +++ b/tests/unit/unit1669.c @@ -0,0 +1,58 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "unitcheck.h" + +#include "urldata.h" +#include "altsvc.h" + +static CURLcode test_unit1669(const char *arg) +{ + UNITTEST_BEGIN_SIMPLE + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_ALTSVC) + char outname[256]; + CURL *curl; + CURLcode result; + struct altsvcinfo *asi = Curl_altsvc_init(); + abort_if(!asi, "Curl_altsvc_init"); + result = Curl_altsvc_load(asi, arg); + fail_if(result, "Curl_altsvc_load"); + if(result) + goto fail; + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + fail_if(!curl, "curl_easy_init"); + if(!curl) + goto fail; + fail_unless(Curl_llist_count(&asi->list) == MAX_ALTSVC_ENTRIES, + "wrong number of entries"); + curl_msnprintf(outname, sizeof(outname), "%s-out", arg); + + curl_easy_cleanup(curl); +fail: + Curl_altsvc_cleanup(&asi); +#endif + + UNITTEST_END(curl_global_cleanup()) +}