1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
#ifndef _PARSE_H
#define _PARSE_H
// Various routines that deal with parsing; both HTTP requests and more generic text.
#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 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);
// 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);
// 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);
// 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)
|