diff --git a/lib/hsts.c b/lib/hsts.c
index c00481fe60..ff21ad98d5 100644
--- a/lib/hsts.c
+++ b/lib/hsts.c
@@ -91,6 +91,20 @@ void Curl_hsts_cleanup(struct hsts **hp)
}
}
+/* append the new entry to the list after possibly removing an old entry
+ first */
+static void hsts_append(struct hsts *h, struct stsentry *sts)
+{
+ if(Curl_llist_count(&h->list) == MAX_HSTS_ENTRIES) {
+ /* It's full. Remove the first entry in the list */
+ struct Curl_llist_node *e = Curl_llist_head(&h->list);
+ struct stsentry *oldsts = Curl_node_elem(e);
+ Curl_node_remove(e);
+ hsts_free(oldsts);
+ }
+ Curl_llist_append(&h->list, sts, &sts->node);
+}
+
static CURLcode hsts_create(struct hsts *h,
const char *hostname,
size_t hlen,
@@ -111,7 +125,7 @@ static CURLcode hsts_create(struct hsts *h,
memcpy(sts->host, hostname, hlen);
sts->expires = expires;
sts->includeSubDomains = subdomains;
- Curl_llist_append(&h->list, sts, &sts->node);
+ hsts_append(h, sts);
}
return CURLE_OK;
}
diff --git a/lib/hsts.h b/lib/hsts.h
index e0f6363bb3..6bd6cdb9a5 100644
--- a/lib/hsts.h
+++ b/lib/hsts.h
@@ -28,6 +28,8 @@
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS)
#include "llist.h"
+#define MAX_HSTS_ENTRIES 1000
+
#if defined(DEBUGBUILD) || defined(UNITTESTS)
extern time_t deltatime;
#endif
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index c3496b133f..0256d0b6fc 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -223,7 +223,7 @@ test1650 test1651 test1652 test1653 test1654 test1655 test1656 test1657 \
test1658 test1659 test1660 test1661 test1662 test1663 test1664 test1665 \
test1666 test1667 test1668 test1669 \
\
-test1670 test1671 test1672 test1673 \
+test1670 test1671 test1672 test1673 test1674 \
\
test1680 test1681 test1682 test1683 test1684 test1685 \
\
diff --git a/tests/data/test1674 b/tests/data/test1674
new file mode 100644
index 0000000000..00b440856e
--- /dev/null
+++ b/tests/data/test1674
@@ -0,0 +1,38 @@
+
+
+
+
+unittest
+HSTS
+
+
+
+
+
+unittest
+HSTS
+
+
+# This date is exactly "20190124 22:34:21" UTC
+
+CURL_TIME=1548369261
+
+
+HSTS load more than 1,000 entries from file
+
+
+# test 1674 renders the input file itself, then reads it
+
+%LOGDIR/hsts%TESTNUMBER
+
+
+
+
+
+Number of entries: 1000
+
+
+Allocations: 1100
+
+
+
diff --git a/tests/unit/Makefile.inc b/tests/unit/Makefile.inc
index d8b2ed2d2e..0ab45a4df1 100644
--- a/tests/unit/Makefile.inc
+++ b/tests/unit/Makefile.inc
@@ -42,6 +42,7 @@ TESTS_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 unit1669.c \
+ unit1674.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/unit1674.c b/tests/unit/unit1674.c
new file mode 100644
index 0000000000..0491db95c2
--- /dev/null
+++ b/tests/unit/unit1674.c
@@ -0,0 +1,82 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS)
+
+#include "urldata.h"
+#include "hsts.h"
+
+/* create a HSTS file with lots of unique host names all using the same
+ fixed expire time */
+static void render_unit1674(const char *file)
+{
+ FILE *f = curlx_fopen(file, FOPEN_WRITETEXT);
+ size_t i;
+ if(!f)
+ return;
+ for(i = 0; i < (MAX_HSTS_ENTRIES + 5); i++) {
+ curl_mfprintf(f, "host%zu.readfrom.example \"20211001 04:47:41\"\n", i);
+ }
+ curlx_fclose(f);
+}
+
+static CURLcode test_unit1674(const char *arg)
+{
+ UNITTEST_BEGIN_SIMPLE
+
+ struct hsts *h = Curl_hsts_init();
+ CURL *easy;
+ char savename[256];
+
+ abort_unless(h, "Curl_hsts_init()");
+
+ render_unit1674(arg);
+
+ curl_global_init(CURL_GLOBAL_ALL);
+ easy = curl_easy_init();
+ if(!easy) {
+ Curl_hsts_cleanup(&h);
+ abort_unless(easy, "curl_easy_init()");
+ }
+
+ Curl_hsts_loadfile(easy, h, arg);
+
+ curl_mprintf("Number of entries: %zu\n", Curl_llist_count(&h->list));
+
+ curl_msnprintf(savename, sizeof(savename), "%s.save", arg);
+ (void)Curl_hsts_save(easy, h, savename);
+ Curl_hsts_cleanup(&h);
+ curl_easy_cleanup(easy);
+
+ UNITTEST_END(curl_global_cleanup())
+}
+#else
+static CURLcode test_unit1674(const char *arg)
+{
+ UNITTEST_BEGIN_SIMPLE
+ puts("nothing to do when HTTP or HSTS are disabled");
+ UNITTEST_END_SIMPLE
+}
+#endif