diff --git a/.github/scripts/codespell.sh b/.github/scripts/codespell.sh
index ac5f27dc47..c5ddf90a47 100755
--- a/.github/scripts/codespell.sh
+++ b/.github/scripts/codespell.sh
@@ -16,6 +16,7 @@ codespell \
--skip 'projects/vms/*' \
--skip 'RELEASE-NOTES' \
--skip 'scripts/wcurl' \
+ --skip 'tests/unit/unit1625.c' \
--ignore-regex '.*spellchecker:disable-line' \
--ignore-words '.github/scripts/codespell-ignore.words' \
--
diff --git a/.github/scripts/typos.toml b/.github/scripts/typos.toml
index 5e5a0346cf..8f6e0f5983 100644
--- a/.github/scripts/typos.toml
+++ b/.github/scripts/typos.toml
@@ -30,4 +30,5 @@ extend-exclude = [
"projects/Windows/tmpl/libcurl.vcxproj",
"scripts/wcurl",
"tests/data/test*",
+ "tests/unit/unit1625.c",
]
diff --git a/lib/http.c b/lib/http.c
index d1039b5da3..a1253be680 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -1402,6 +1402,8 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
*
* Returns TRUE if 'headerline' contains the 'header' with given 'content'
* (within a comma-separated list of tokens). Pass 'header' WITH the colon.
+ *
+ * @unittest: 1625
*/
bool Curl_compareheader(const char *headerline, /* line to check */
const char *header, /* header keyword _with_ colon */
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 1b906a3144..41565b91cc 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -214,7 +214,7 @@ test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \
test1598 test1599 test1600 test1601 test1602 test1603 test1604 test1605 \
test1606 test1607 test1608 test1609 test1610 test1611 test1612 test1613 \
test1614 test1615 test1616 test1617 \
-test1620 test1621 test1622 test1623 test1624 \
+test1620 test1621 test1622 test1623 test1624 test1625 \
\
test1630 test1631 test1632 test1633 test1634 test1635 test1636 test1637 \
\
diff --git a/tests/data/test1625 b/tests/data/test1625
new file mode 100644
index 0000000000..58d661c385
--- /dev/null
+++ b/tests/data/test1625
@@ -0,0 +1,25 @@
+
+
+
+
+unittest
+Curl_compareheader
+
+
+
+
+
+unittest
+http
+
+
+Curl_compareheader unit test
+
+
+
+
+
+31 invokes
+
+
+
diff --git a/tests/unit/Makefile.inc b/tests/unit/Makefile.inc
index 149636cbcc..c9996276c8 100644
--- a/tests/unit/Makefile.inc
+++ b/tests/unit/Makefile.inc
@@ -37,6 +37,7 @@ TESTS_C = \
unit1600.c unit1601.c unit1602.c unit1603.c unit1605.c unit1606.c \
unit1607.c unit1608.c unit1609.c unit1610.c unit1611.c unit1612.c unit1614.c \
unit1615.c unit1616.c unit1620.c \
+ unit1625.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 \
diff --git a/tests/unit/unit1625.c b/tests/unit/unit1625.c
new file mode 100644
index 0000000000..031422df63
--- /dev/null
+++ b/tests/unit/unit1625.c
@@ -0,0 +1,136 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#ifndef CURL_DISABLE_HTTP
+
+#include "urldata.h"
+#include "url.h"
+
+struct check1625 {
+ const char *in;
+ const char *hdr;
+ const char *extract;
+ bool expect;
+};
+
+static CURLcode test_unit1625(const char *arg)
+{
+ size_t i;
+ static const struct check1625 list[] = {
+ /* basic case */
+ { "Encoding: gzip, chunked", "Encoding:", "chunked", TRUE },
+ /* single value */
+ { "Encoding: chunked", "Encoding:", "chunked", TRUE },
+ /* third token */
+ { "Encoding: a, b, chunked", "Encoding:", "chunked", TRUE },
+ /* fourth token */
+ { "Encoding: a, b, c, chunked", "Encoding:", "chunked", TRUE },
+ /* in middle of three tokens */
+ { "Encoding: a, chunked, ninja", "Encoding:", "chunked", TRUE },
+ /* empty incoming header */
+ { "Encoding:", "Encoding:", "chunked", FALSE },
+ /* just spaces in header */
+ { "Encoding: ", "Encoding:", "chunked", FALSE },
+ /* last among several with no spaces */
+ { "Encoding: ab,cd,ef,gh,ig,kl", "Encoding:", "kl", TRUE },
+ /* double commas */
+ { "Encoding: ab,,kl", "Encoding:", "kl", TRUE },
+ /* repeated commas */
+ { "Encoding: ab,cd,,,,kl", "Encoding:", "kl", TRUE },
+ /* first token of four */
+ { "Encoding: chunked, a, b, c", "Encoding:", "chunked", TRUE },
+ /* different case */
+ { "Encoding: gzip, chunked", "Encoding:", "CHUNKED", TRUE },
+ /* another different case */
+ { "Encoding: gzip, CHUNKED", "Encoding:", "chunked", TRUE },
+ /* incoming header different case */
+ { "encoDING: gzip, CHUNKED", "encoding:", "chunked", TRUE },
+ /* incoming header upper case */
+ { "ENCODING: gzip, chunked", "encoding:", "chunked", TRUE },
+ /* the other value */
+ { "Encoding: gzip, chunked", "Encoding:", "gzip", TRUE },
+ /* without space */
+ { "Encoding: gzip,chunked", "Encoding:", "gzip", TRUE },
+ /* multiple spaces */
+ { "Encoding: gzip, chunked", "Encoding:", "chunked", TRUE },
+ /* tabs */
+ { "Encoding: gzip, \tchunked", "Encoding:", "chunked", TRUE },
+ /* end with CR */
+ { "Encoding: gzip\r\n", "Encoding:", "gzip", TRUE },
+ /* end with LF */
+ { "Encoding: gzip\n", "Encoding:", "gzip", TRUE },
+ /* end with tab */
+ { "Encoding: gzip\t", "Encoding:", "gzip", TRUE },
+ /* end with space + LF */
+ { "Encoding: gzip \n", "Encoding:", "gzip", TRUE },
+ /* missing value */
+ { "Encoding: gzip, chunked", "Encoding:", "br", FALSE },
+ /* wrong header */
+ { "Encoding: gzip, chunked", "Encodin:", "chunked", FALSE },
+ /* prefix only */
+ { "Encoding: gzip2, chunked", "Encoding:", "gzip", FALSE },
+ /* prefix with letter */
+ { "Encoding: gzipp, chunked", "Encoding:", "gzip", FALSE },
+ /* suffix only */
+ { "Encoding: agzip, chunked", "Encoding:", "gzip", FALSE },
+ /* not the right header */
+ { "Decoding: gzip, chunked", "Encoding:", "gzip", FALSE },
+ /* hyphenated */
+ { "Encoding: super-nice", "Encoding:", "super-nice", TRUE },
+ /* hyphenated second token */
+ { "Encoding: extra-good, super-nice", "Encoding:", "super-nice", TRUE },
+ };
+ (void)arg;
+
+ for(i = 0; i < CURL_ARRAYSIZE(list); i++) {
+ bool check = Curl_compareheader(list[i].in,
+ list[i].hdr, strlen(list[i].hdr),
+ list[i].extract, strlen(list[i].extract));
+ if(check != list[i].expect) {
+ curl_mprintf("Input: %s\n"
+ "Header: %s\n"
+ "Look for: %s\n"
+ "Returned: %s\n",
+ list[i].in, list[i].hdr, list[i].extract,
+ check ? "TRUE" : "FALSE");
+ break;
+ }
+ }
+
+ curl_mprintf("%zu invokes\n", i);
+
+ if(i != CURL_ARRAYSIZE(list))
+ return CURLE_FAILED_INIT;
+
+ return CURLE_OK;
+}
+#else
+/* for HTTP-disabled builds */
+static CURLcode test_unit1625(const char *arg)
+{
+ (void)arg;
+ return CURLE_OK;
+}
+#endif