7#include <unordered_map>
9#include <boost/optional.hpp>
18int qs_strncmp(
const char * s,
const char * qs,
size_t n);
25int qs_parse(
char * qs,
char * qs_kv[],
int qs_kv_size);
29int qs_decode(
char * qs);
36 char * qs_k2v(
const char * key,
char *
const * qs_kv,
int qs_kv_size,
int nth);
41char * qs_scanvalue(
const char * key,
const char * qs,
char * val,
size_t val_len);
47#define CROW_QS_ISHEX(x) ((((x)>='0'&&(x)<='9') || ((x)>='A'&&(x)<='F') || ((x)>='a'&&(x)<='f')) ? 1 : 0)
48#define CROW_QS_HEX2DEC(x) (((x)>='0'&&(x)<='9') ? (x)-48 : ((x)>='A'&&(x)<='F') ? (x)-55 : ((x)>='a'&&(x)<='f') ? (x)-87 : 0)
49#define CROW_QS_ISQSCHR(x) ((((x)=='=')||((x)=='#')||((x)=='&')||((x)=='\0')) ? 0 : 1)
51inline int qs_strncmp(
const char * s,
const char * qs,
size_t n)
54 unsigned char u1, u2, unyb, lnyb;
58 u1 =
static_cast<unsigned char>(*s++);
59 u2 =
static_cast<unsigned char>(*qs++);
61 if ( ! CROW_QS_ISQSCHR(u1) ) { u1 =
'\0'; }
62 if ( ! CROW_QS_ISQSCHR(u2) ) { u2 =
'\0'; }
64 if ( u1 ==
'+' ) { u1 =
' '; }
67 unyb =
static_cast<unsigned char>(*s++);
68 lnyb =
static_cast<unsigned char>(*s++);
69 if ( CROW_QS_ISHEX(unyb) && CROW_QS_ISHEX(lnyb) )
70 u1 = (CROW_QS_HEX2DEC(unyb) * 16) + CROW_QS_HEX2DEC(lnyb);
75 if ( u2 ==
'+' ) { u2 =
' '; }
78 unyb =
static_cast<unsigned char>(*qs++);
79 lnyb =
static_cast<unsigned char>(*qs++);
80 if ( CROW_QS_ISHEX(unyb) && CROW_QS_ISHEX(lnyb) )
81 u2 = (CROW_QS_HEX2DEC(unyb) * 16) + CROW_QS_HEX2DEC(lnyb);
92 if ( CROW_QS_ISQSCHR(*qs) )
99inline int qs_parse(
char * qs,
char * qs_kv[],
int qs_kv_size)
104 for(i=0; i<qs_kv_size; i++) qs_kv[i] = NULL;
107 substr_ptr = qs + strcspn(qs,
"?#");
108 if (substr_ptr[0] !=
'\0')
116 qs_kv[i] = substr_ptr;
117 j = strcspn(substr_ptr,
"&");
118 if ( substr_ptr[j] ==
'\0' ) {
break; }
128 substr_ptr = qs_kv[j] + strcspn(qs_kv[j],
"=&#");
129 if ( substr_ptr[0] ==
'&' || substr_ptr[0] ==
'\0')
130 substr_ptr[0] =
'\0';
132 qs_decode(++substr_ptr);
143inline int qs_decode(
char * qs)
147 while( CROW_QS_ISQSCHR(qs[j]) )
149 if ( qs[j] ==
'+' ) { qs[i] =
' '; }
150 else if ( qs[j] ==
'%' )
152 if ( ! CROW_QS_ISHEX(qs[j+1]) || ! CROW_QS_ISHEX(qs[j+2]) )
157 qs[i] = (CROW_QS_HEX2DEC(qs[j+1]) * 16) + CROW_QS_HEX2DEC(qs[j+2]);
172inline char * qs_k2v(
const char * key,
char *
const * qs_kv,
int qs_kv_size,
int nth = 0)
175 size_t key_len, skip;
177 key_len = strlen(key);
182 for(i=0; i<qs_kv_size; i++)
185 if ( qs_strncmp(key, qs_kv[i], key_len) == 0 )
187 skip = strcspn(qs_kv[i],
"=");
188 if ( qs_kv[i][skip] ==
'=' )
192 return qs_kv[i] + skip;
202inline boost::optional<std::pair<std::string, std::string>> qs_dict_name2kv(
const char * dict_name,
char *
const * qs_kv,
int qs_kv_size,
int nth = 0)
205 size_t name_len, skip_to_eq, skip_to_brace_open, skip_to_brace_close;
207 name_len = strlen(dict_name);
212 for(i=0; i<qs_kv_size; i++)
214 if ( strncmp(dict_name, qs_kv[i], name_len) == 0 )
216 skip_to_eq = strcspn(qs_kv[i],
"=");
217 if ( qs_kv[i][skip_to_eq] ==
'=' )
219 skip_to_brace_open = strcspn(qs_kv[i],
"[");
220 if ( qs_kv[i][skip_to_brace_open] ==
'[' )
221 skip_to_brace_open++;
222 skip_to_brace_close = strcspn(qs_kv[i],
"]");
224 if ( skip_to_brace_open <= skip_to_brace_close &&
225 skip_to_brace_open > 0 &&
226 skip_to_brace_close > 0 &&
229 auto key = std::string(qs_kv[i] + skip_to_brace_open, skip_to_brace_close - skip_to_brace_open);
230 auto value = std::string(qs_kv[i] + skip_to_eq);
231 return boost::make_optional(std::make_pair(key, value));
245inline char * qs_scanvalue(
const char * key,
const char * qs,
char * val,
size_t val_len)
251 if ( (tmp = strchr(qs,
'?')) != NULL )
254 key_len = strlen(key);
255 while(qs[0] !=
'#' && qs[0] !=
'\0')
257 if ( qs_strncmp(key, qs, key_len) == 0 )
259 qs += strcspn(qs,
"&") + 1;
262 if ( qs[0] ==
'\0' )
return NULL;
264 qs += strcspn(qs,
"=&#");
268 i = strcspn(qs,
"&=#");
270 strncpy_s(val, val_len, qs, (val_len - 1)<(i + 1) ? (val_len - 1) : (i + 1));
272 strncpy(val, qs, (val_len - 1)<(i + 1) ? (val_len - 1) : (i + 1));
294 static const int MAX_KEY_VALUE_PAIRS_COUNT = 256;
304 for(
auto p:qs.key_value_pairs_)
306 key_value_pairs_.push_back((
char*)(p-qs.url_.c_str()+url_.c_str()));
313 key_value_pairs_.clear();
314 for(
auto p:qs.key_value_pairs_)
316 key_value_pairs_.push_back((
char*)(p-qs.url_.c_str()+url_.c_str()));
323 key_value_pairs_ = std::move(qs.key_value_pairs_);
324 char* old_data = (
char*)qs.url_.c_str();
325 url_ = std::move(qs.url_);
326 for(
auto& p:key_value_pairs_)
328 p += (
char*)url_.c_str() - old_data;
335 : url_(std::move(url))
340 key_value_pairs_.resize(MAX_KEY_VALUE_PAIRS_COUNT);
342 int count = qs_parse(&url_[0], &key_value_pairs_[0], MAX_KEY_VALUE_PAIRS_COUNT);
343 key_value_pairs_.resize(count);
348 key_value_pairs_.clear();
352 friend std::ostream& operator<<(std::ostream& os,
const query_string& qs)
355 for(
size_t i = 0; i < qs.key_value_pairs_.size(); ++i) {
358 os << qs.key_value_pairs_[i];
368 char*
get (
const std::string& name)
const
370 char* ret = qs_k2v(name.c_str(), key_value_pairs_.data(), key_value_pairs_.size());
375 char*
pop (
const std::string& name)
377 char* ret =
get(name);
380 for (
unsigned int i = 0; i<key_value_pairs_.size(); i++)
382 std::string str_item(key_value_pairs_[i]);
383 if (str_item.substr(0, name.size()+1) == name+
'=')
385 key_value_pairs_.erase(key_value_pairs_.begin()+i);
396 std::vector<char*>
get_list (
const std::string& name,
bool use_brackets =
true)
const
398 std::vector<char*> ret;
399 std::string plus = name + (use_brackets ?
"[]" :
"");
400 char* element =
nullptr;
405 element = qs_k2v(plus.c_str(), key_value_pairs_.data(), key_value_pairs_.size(), count++);
408 ret.push_back(element);
414 std::vector<char*>
pop_list (
const std::string& name,
bool use_brackets =
true)
416 std::vector<char*> ret =
get_list(name, use_brackets);
419 for (
unsigned int i = 0; i<key_value_pairs_.size(); i++)
421 std::string str_item(key_value_pairs_[i]);
422 if ((use_brackets ? (str_item.substr(0, name.size()+3) == name+
"[]=") : (str_item.substr(0, name.size()+1) == name+
'=')))
424 key_value_pairs_.erase(key_value_pairs_.begin()+i--);
436 std::unordered_map<std::string, std::string>
get_dict (
const std::string& name)
const
438 std::unordered_map<std::string, std::string> ret;
443 if (
auto element = qs_dict_name2kv(name.c_str(), key_value_pairs_.data(), key_value_pairs_.size(), count++))
444 ret.insert(*element);
452 std::unordered_map<std::string, std::string>
pop_dict (
const std::string& name)
454 std::unordered_map<std::string, std::string> ret =
get_dict(name);
457 for (
unsigned int i = 0; i<key_value_pairs_.size(); i++)
459 std::string str_item(key_value_pairs_[i]);
460 if (str_item.substr(0, name.size()+1) == name+
'[')
462 key_value_pairs_.erase(key_value_pairs_.begin()+i--);
469 std::vector<std::string> keys()
const
471 std::vector<std::string> ret;
472 for (
auto element: key_value_pairs_)
474 std::string str_element(element);
475 ret.emplace_back(str_element.substr(0, str_element.find(
'=')));
482 std::vector<char*> key_value_pairs_;
A class to represent any data coming after the ? in the request URL into key-value pairs.
Definition: query_string.h:292
std::unordered_map< std::string, std::string > pop_dict(const std::string &name)
Works the same as get_dict() but removes the values from the query string.
Definition: query_string.h:452
char * pop(const std::string &name)
Works similar to get() except it removes the item from the query string.
Definition: query_string.h:375
std::unordered_map< std::string, std::string > get_dict(const std::string &name) const
Definition: query_string.h:436
std::vector< char * > get_list(const std::string &name, bool use_brackets=true) const
Definition: query_string.h:396
std::vector< char * > pop_list(const std::string &name, bool use_brackets=true)
Similar to get_list() but it removes the.
Definition: query_string.h:414
char * get(const std::string &name) const
Definition: query_string.h:368