]> git.sesse.net Git - cubemap/blobdiff - parse.h
Make HTTP header parsing case-insensitive.
[cubemap] / parse.h
diff --git a/parse.h b/parse.h
index 83c5d2a8998dff2832b879b78db04c4467608696..a2e35802d38d31e804e4b16dcf1f948df6f7cfa7 100644 (file)
--- a/parse.h
+++ b/parse.h
@@ -1,17 +1,45 @@
 #ifndef _PARSE_H
 #define _PARSE_H
 
-// Various routines that deal with parsing; both configuration files and HTTP requests.
+// Various routines that deal with parsing; both HTTP requests and more generic text.
 
-#include <map>
-#include <vector>
+#include <stddef.h>
+#include <string>
+#include <algorithm>
 #include <string>
+#include <unordered_map>
+#include <vector>
 
-struct ConfigLine {
-       std::string keyword;
-       std::vector<std::string> arguments;
-       std::map<std::string, std::string> parameters;
+// 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);
@@ -19,10 +47,23 @@ std::vector<std::string> split_tokens(const std::string &line);
 // Split a string on \n or \r\n, e.g. "foo\nbar\r\n\nbaz\r\n\r\n" -> {"foo", "bar", "baz"}.
 std::vector<std::string> split_lines(const std::string &str);
 
-// Parse the configuration file.
-std::vector<ConfigLine> parse_config(const std::string &filename);
+// Extract HTTP headers from a request or response. Ignores the first line,
+// where the verb or the return code is.
+HTTPHeaderMultimap extract_headers(const std::vector<std::string> &lines, const std::string &log_context);
 
-// Note: Limits are inclusive.
-int fetch_config_int(const std::vector<ConfigLine> &config, const std::string &keyword, int min_limit, int max_limit);
+// Add the new data to an existing string, looking for \r\n\r\n
+// (typical of HTTP requests and/or responses). Will return one
+// of the given statuses.
+//
+// Note that if you give too much data in new_data_size, you could
+// get an RP_OUT_OF_SPACE even if you expected RP_EXTRA_DATA.
+// Be careful about how large reads you give in.
+enum RequestParseStatus {
+       RP_OUT_OF_SPACE,       // If larger than 16 kB.
+       RP_NOT_FINISHED_YET,   // Did not get \r\n\r\n yet. 
+       RP_EXTRA_DATA,         // Got \r\n\r\n, but there was extra data behind it.
+       RP_FINISHED,           // Ended exactly in \r\n\r\n.
+};
+RequestParseStatus wait_for_double_newline(std::string *existing_data, const char *new_data, size_t new_data_size);
 
 #endif  // !defined(_PARSE_H)