From: Alex Rousskov Date: Wed, 14 Jun 2023 14:09:38 +0000 (+0000) Subject: Fix key equality comparison in LookupTable map (#1379) X-Git-Tag: SQUID_7_0_1~428 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b91a85582f3781f3105d09b9221668519b6dffb6;p=thirdparty%2Fsquid.git Fix key equality comparison in LookupTable map (#1379) An std::unordered_map with case-insensitive keys must use a case-insensitive key equality comparison. lookupTable_t used (the default) std::equal_to comparison which is case-sensitive. The full extent of this bug effects is unknown, but Squid was mishandling Cache-Control and Surrogate-Control directives with non-canonical (i.e. other than all-lower-case) spelling. Similar problems affected WWW-Authenticate Digest parameter names, but the related code remains inconsistent, with both case-sensitive and case-insensitive checks applied to some of the key names in Auth::Digest::Config::decode(). Also removed a similarly buggy (and, technically, unused) "typical use" example from the CaseInsensitiveSBufHash class description. C++ documentation and Squid code are better sources of usage examples when it comes to STL-used concepts like hash function objects. This minimal fix excludes LookupTable class polishing. The bug was introduced in 2015 commit 81ab22b. --- diff --git a/src/base/LookupTable.h b/src/base/LookupTable.h index 2cf6023e67..e410960915 100644 --- a/src/base/LookupTable.h +++ b/src/base/LookupTable.h @@ -70,7 +70,7 @@ public: } private: - typedef std::unordered_map lookupTable_t; + using lookupTable_t = std::unordered_map; lookupTable_t lookupTable; EnumType invalidValue; }; diff --git a/src/sbuf/Algorithms.h b/src/sbuf/Algorithms.h index 64c475c2c6..866c522994 100644 --- a/src/sbuf/Algorithms.h +++ b/src/sbuf/Algorithms.h @@ -112,18 +112,25 @@ struct hash }; } -/** hash functor for SBufs, meant so support case-insensitive std::unordered_map - * - * Typical use: - * \code - * auto m = std::unordered_map(); - * \endcode - */ +/// hash functor for case-insensitive SBufs +/// \sa std::hash class CaseInsensitiveSBufHash { public: std::size_t operator()(const SBuf &) const noexcept; }; +/// equality functor for case-insensitive SBufs +/// \sa std::equal_to +class CaseInsensitiveSBufEqual +{ +public: + bool operator()(const SBuf &lhs, const SBuf &rhs) const + { + // Optimization: Do not iterate strings of different lengths. + return lhs.length() == rhs.length() && (lhs.compare(rhs, caseInsensitive) == 0); + } +}; + #endif /* SQUID_SBUFALGOS_H_ */ diff --git a/src/tests/testLookupTable.cc b/src/tests/testLookupTable.cc index 337fb0d6e0..c194954617 100644 --- a/src/tests/testLookupTable.cc +++ b/src/tests/testLookupTable.cc @@ -57,6 +57,11 @@ TestLookupTable::testLookupTableLookup() CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("six")), ENUM_6); CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("seven")), ENUM_7); + // element found despite a different key spelling + CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("One")), ENUM_1); + CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("fOUr")), ENUM_4); + CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("seveN")), ENUM_7); + // element not found CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("eleventy")), ENUM_INVALID); }