Finished query string parsing implementation (PR #109)

This commit is contained in:
eidheim 2017-05-27 09:07:13 +02:00
commit 550bbfe9d7
2 changed files with 66 additions and 20 deletions

View file

@ -107,13 +107,39 @@ namespace SimpleWeb {
Content content;
std::unordered_multimap<std::string, std::string, case_insensitive_hash, case_insensitive_equals> header;
std::unordered_multimap<std::string, std::string, case_insensitive_hash, case_insensitive_equals> query_string;
REGEX_NS::smatch path_match;
std::string remote_endpoint_address;
unsigned short remote_endpoint_port;
/// Returns query keys with percent-decoded values.
std::unordered_multimap<std::string, std::string, case_insensitive_hash, case_insensitive_equals> parse_query_string() {
std::unordered_multimap<std::string, std::string, case_insensitive_hash, case_insensitive_equals> result;
auto qs_start_pos = path.find('?');
if (qs_start_pos != std::string::npos && qs_start_pos + 1 < path.size()) {
++qs_start_pos;
static REGEX_NS::regex pattern("([\\w+%]+)=?([^&]*)");
int submatches[] = {1, 2};
auto it_begin = REGEX_NS::sregex_token_iterator(path.begin() + qs_start_pos, path.end(), pattern, submatches);
auto it_end = REGEX_NS::sregex_token_iterator();
for (auto it = it_begin; it != it_end; ++it) {
auto query_it = result.emplace(it->str(), (++it)->str());
auto &value = query_it->second;
for (size_t c = 0; c < value.size(); ++c) {
if (value[c] == '+')
value[c] = ' ';
else if (value[c] == '%' && c + 2 < value.size()) {
auto hex = value.substr(c + 1, 2);
auto chr = static_cast<char>(std::strtol(hex.c_str(), nullptr, 16));
value.replace(c, 3, &chr, 1);
}
}
}
}
return result;
}
private:
Request(const socket_type &socket): content(streambuf) {
try {
@ -321,25 +347,6 @@ namespace SimpleWeb {
request->method=line.substr(0, method_end);
request->path=line.substr(method_end+1, path_end-method_end-1);
//search and populte query_string
size_t qs_start;
if ((qs_start = request->path.find('?')) != std::string::npos)
{
std::string qs = request->path.substr(qs_start, request->path.size() - qs_start - 1);
REGEX_NS::regex pattern("([\\w+%]+)=?([^&]*)");
int submatches[] = { 1, 2 };
auto qs_begin = REGEX_NS::sregex_token_iterator(qs.begin(), qs.end(), pattern, submatches);
auto qs_end = REGEX_NS::sregex_token_iterator();
for (auto it = qs_begin; it != qs_end; it++)
{
std::string key = it->str();
std::string value = (++it)->str();
request->query_string.emplace(std::make_pair(key, value));
}
request->path = request->path.substr(0, qs_start);
}
size_t protocol_end;
if((protocol_end=line.find('/', path_end+1))!=std::string::npos) {
if(line.compare(path_end+1, protocol_end-path_end-1, "HTTP")!=0)

View file

@ -117,4 +117,43 @@ int main() {
clientTest2.constructor_parse_test2();
clientTest2.parse_response_header_test();
boost::asio::io_service io_service;
boost::asio::ip::tcp::socket socket(io_service);
SimpleWeb::Server<HTTP>::Request request(socket);
{
request.path = "/?";
auto queries = request.parse_query_string();
assert(queries.empty());
}
{
request.path = "/";
auto queries = request.parse_query_string();
assert(queries.empty());
}
{
request.path = "/?a=1%202%20%203&b=3+4&c&d=æ%25ø%26å%3F";
auto queries = request.parse_query_string();
{
auto range = queries.equal_range("a");
assert(range.first != range.second);
assert(range.first->second == "1 2 3");
}
{
auto range = queries.equal_range("b");
assert(range.first != range.second);
assert(range.first->second == "3 4");
}
{
auto range = queries.equal_range("c");
assert(range.first != range.second);
assert(range.first->second == "");
}
{
auto range = queries.equal_range("d");
assert(range.first != range.second);
assert(range.first->second == "æ%ø&å?");
}
}
}