I've begun developing an HTTP server using cpp-netlib
(stable release 0.10.1) and from the available documentation I am not sure how to access HTTP request headers in a server handler. I am aware that it can be done using the wrapper like this:
void operator()(async_server::request const &Request, async_server::connection_ptr pConnection)
{
http::impl::request_headers_wrapper<http::tags::http_async_server> Headers = headers(Request);
}
But according to the definition of not_quite_pod_request_base
in headers.hpp
this is actually a vector of pairs, which is hard for searching if i want to e.g. find if a certain header is present. If there are no other options then of course i will stick with this, however it seems that initially it was meant as a multimap at least judging from headers_container.hpp
:
namespace boost { namespace network {
template <class Tag>
struct headers_container {
typedef std::multimap<
typename string<Tag>::type,
typename string<Tag>::type
> type;
};
} // namespace network
} // namespace boost
So can anyone either point out why there is a such redefinition or am I missing some way to actually get the multimap
or is the wrapper with the vector
the "go-to" way to work with headers in cpp-netlib
? At least to me it seems that a multimap
would be much easier to work with.
UPDATE
I also took a quick look at the POCO libraries but could not understand if their authentication classes are meant for only client sessions or server as well? If anyone can give a hint on this, maybe I can still do a switch to POCO if that makes life a lot easier.
The trait you're referring to applies to the headers in a client-side request, for the client-side implementation in cpp-netlib. There was some work being done (incomplete) to make getting a header from the request in the server be the same as for getting the request from client request/response objects.
The reason the headers on the server side are a vector of pairs is for "efficiency" in terms of space and time. If you can pay the cost of creating a multimap on the server's handler, you should probably do that instead. The usual pattern for efficiently working through headers in a request in an efficient manner is to always do a linear scan of the headers you're looking for, and processing them as they come in. Something similar to this:
string content_type, content_length;
for (const auto& header : request.headers) {
if (header.name == "Content-Type") content_type = header.value;
if (header.name == "Content-Length") content_length = header.value;
if (!content_type.empty() && !content_length.empty()) break;
}
You may generalise this using some sort of pattern (a std::map<string, std::function<void(const std::string&)>>
perhaps) if your application requires this level of header processing.
In general though, iterating through a list of vectors shouldn't take too much time. If the number of headers is large (O(10,000)) then you have other problems. The tradeoff here is between memory locality (a vector has contiguous elements as opposed to a map that has elements typically randomly allocated in different parts of memory) and efficient lookup (logarithmic time only really makes sense after a certain size).
I completely accept the point that the convenience suffers a bit. Maybe a different data structure would be helpful here (a boost::flat_map
perhaps). But an interface improvement would be to make the code that works with client request/response also work with server request/response objects.