return false;
}
- unordered_multimap<string, string> parameters = extract_headers(lines, url);
+ HTTPHeaderMultimap parameters = extract_headers(lines, url);
// Remove “Content-encoding: metacube”.
- // TODO: Make case-insensitive.
- const auto encoding_it = parameters.find("Content-encoding");
+ const auto encoding_it = parameters.find("Content-Encoding");
if (encoding_it != parameters.end() && encoding_it->second == "metacube") {
parameters.erase(encoding_it);
}
// Change “Server: foo” to “Server: metacube/0.1 (reflecting: foo)”
- // TODO: Make case-insensitive.
// XXX: Use a Via: instead?
if (parameters.count("Server") == 0) {
parameters.insert(make_pair("Server", SERVER_IDENTIFICATION));
}
// Erase “Connection: close”; we'll set it on the sending side if needed.
- // TODO: Make case-insensitive.
parameters.erase("Connection");
// Construct the new HTTP header.
return ret;
}
-unordered_multimap<string, string> extract_headers(const vector<string> &lines, const string &log_context)
+HTTPHeaderMultimap extract_headers(const vector<string> &lines, const string &log_context)
{
- unordered_multimap<string, string> parameters;
+ HTTPHeaderMultimap parameters;
for (size_t i = 1; i < lines.size(); ++i) {
size_t split = lines[i].find(":");
if (split == string::npos) {
#include <stddef.h>
#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 HTTPLess {
+ bool operator() (const std::string &a, const std::string &b) const
+ {
+ return std::lexicographical_compare(
+ begin(a), end(a), begin(b), end(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, HTTPLess>;
+
// 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::unordered_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
}
// Parse the headers, for logging purposes.
- // TODO: Case-insensitivity.
- unordered_multimap<string, string> headers = extract_headers(lines, client->remote_addr);
+ HTTPHeaderMultimap headers = extract_headers(lines, client->remote_addr);
const auto referer_it = headers.find("Referer");
if (referer_it != headers.end()) {
client->referer = referer_it->second;