diff --git a/httplib.h b/httplib.h index facb8b79..2030a352 100644 --- a/httplib.h +++ b/httplib.h @@ -676,17 +676,13 @@ struct equal_to { struct hash { size_t operator()(const std::string &key) const { - return hash_core(key.data(), key.size(), 0); - } - - size_t hash_core(const char *s, size_t l, size_t h) const { - return (l == 0) ? h - : hash_core(s + 1, l - 1, - // Unsets the 6 high bits of h, therefore no - // overflow happens - (((std::numeric_limits::max)() >> 6) & - h * 33) ^ - static_cast(to_lower(*s))); + size_t h = 0; + for (auto c : key) { + // Unsets the 6 high bits of h, therefore no overflow happens + h = (((std::numeric_limits::max)() >> 6) & h * 33) ^ + static_cast(to_lower(c)); + } + return h; } }; diff --git a/test/test.cc b/test/test.cc index bb878cfd..35f78f59 100644 --- a/test/test.cc +++ b/test/test.cc @@ -643,6 +643,15 @@ TEST(FileExtensionTest, TakesTheAlphanumericSuffix) { EXPECT_EQ(long_ext, detail::file_extension("a." + long_ext)); } +TEST(CaseIgnoreHashTest, IgnoresCaseAndTakesLongKeys) { + detail::case_ignore::hash hash; + EXPECT_EQ(hash("Content-Type"), hash("content-TYPE")); + EXPECT_NE(hash("Content-Type"), hash("Content-Length")); + + // Long enough to overflow the stack if hashed one call per character. + EXPECT_EQ(hash(std::string(1 << 20, 'A')), hash(std::string(1 << 20, 'a'))); +} + TEST(FindContentTypeTest, ComparesWholeExtensions) { EXPECT_EQ("text/html", detail::find_content_type("/a.html", {}, "")); EXPECT_EQ("image/svg+xml", detail::find_content_type("/a.svg", {}, ""));