I'm writing an HTTP client in C++11/14 (VS 2015) for practice with asynchronous and network programming using ASIO (standalone, not boost, by the way, so please refrain from boost-specific solutions). This is a fairly basic question, but I nonetheless would appreciate an answer.
struct Header {
Header(const std::string& key, const std::string& val); // initializes key/val
std::string key, val;
bool operator==(const Header& header); // returns true if key/val are equal
friend std::ostream& operator<<(std::ostream& os, const Header& header) {
os << header.key << ": " << header.val;
return os;
}
};
I've run into an issue, though. Some HTTP headers can be repeated. Others should not be. In particular, when I generate the "Host: website.com" header, I want to check and see if the user has not already input a Host parameter.
- My initial thought was to use
std::unordered_set<Header>
and provide a hash function that only hashes the Key value, thus preventing duplicates. However, some headers are perfectly valid to duplicate. Set-Cookie for example I then thought of creating a vector similar to this:
static const std::unordered_set<std::string, HashIgnoreCase>& AllowedDuplicates{ "set-cookie", "cookie", }; // HashIgnoreCase uses std::hash<std::string> on lowercase-converted strings.
Then use that to check user-provided values. However, this seemed ugly since I'd have on
std::unordered_set<Header>
for most headers and astd::vector<Header>
for the duplicate headers.- Another idea would be to completely restrict the user from providing headers that should be singular, such as throwing an exception (or some clever static_assert) to prevent values like "Host" and "Content-Length" from being provided by the user, but that seems functionally restrictive, which is not typically my goal.
What would be the best way to go about this?