// Various routines that deal with parsing; both HTTP requests and more generic text.
#include <stddef.h>
-#include <map>
#include <string>
+#include <algorithm>
+#include <string>
+#include <unordered_map>
#include <vector>
+// Locale-unaware tolower(); matches RFC 2616 no matter what the locale is set to.
+static inline char ascii_tolower(const char ch)
+{
+ if (ch >= 'A' && ch <= 'Z') {
+ return ch + 'a' - 'A';
+ } else {
+ return ch;
+ }
+}
+
+// Case-insensitive header comparison and hashing.
+struct HTTPEqual {
+ bool operator() (const std::string &a, const std::string &b) const
+ {
+ return a.size() == b.size() &&
+ std::equal(
+ begin(a), end(a), begin(b),
+ [](char a, char b) {
+ return ascii_tolower(a) == ascii_tolower(b);
+ });
+ }
+};
+struct HTTPHash {
+ size_t operator() (const std::string &s) const
+ {
+ std::string s_low = s;
+ for (char &ch : s_low) { ch = ascii_tolower(ch); }
+ return std::hash<std::string>() (s_low);
+ }
+};
+using HTTPHeaderMultimap = std::unordered_multimap<std::string, std::string, HTTPHash, HTTPEqual>;
+
// Split a line on whitespace, e.g. "foo bar baz" -> {"foo", "bar", "baz"}.
std::vector<std::string> split_tokens(const std::string &line);
// Extract HTTP headers from a request or response. Ignores the first line,
// where the verb or the return code is.
-std::multimap<std::string, std::string> extract_headers(
- const std::vector<std::string> &lines, const std::string &log_context);
+HTTPHeaderMultimap extract_headers(const std::vector<std::string> &lines, const std::string &log_context);
// Add the new data to an existing string, looking for \r\n\r\n
// (typical of HTTP requests and/or responses). Will return one