tlx
parse_uri_form_data.hpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * tlx/string/parse_uri_form_data.hpp
3  *
4  * Part of tlx - http://panthema.net/tlx
5  *
6  * Copyright (C) 2020 Timo Bingmann <tb@panthema.net>
7  *
8  * All rights reserved. Published under the Boost Software License, Version 1.0
9  ******************************************************************************/
10 
11 #ifndef TLX_STRING_PARSE_URI_FORM_DATA_HEADER
12 #define TLX_STRING_PARSE_URI_FORM_DATA_HEADER
13 
14 #include <cstring>
15 #include <string>
16 #include <vector>
17 
18 namespace tlx {
19 
20 //! \addtogroup tlx_string
21 //! \{
22 
23 /*!
24  * Helper function to decode %20 and + in urlencoded form data like
25  * "query=string+with+spaces&submit=yes%21&".
26  */
27 static inline
29  const char* str, const char* end = nullptr) {
30  std::string out;
31  if (end == nullptr)
32  out.reserve(strlen(str));
33  else
34  out.reserve(end - str);
35  char a, b;
36 
37  while (*str && str != end) {
38  if (*str == '%' && (a = str[1]) != 0 && (b = str[2]) != 0) {
39  if (a >= '0' && a <= '9')
40  a -= '0';
41  else if (a >= 'a' && a <= 'f')
42  a -= 'a' - 10;
43  else if (a >= 'A' && a <= 'F')
44  a -= 'A' - 10;
45  else {
46  // invalid hex digits, copy '%' and continue
47  out += *str++;
48  continue;
49  }
50 
51  if (b >= '0' && b <= '9')
52  b -= '0';
53  else if (b >= 'a' && b <= 'f')
54  b -= 'a' - 10;
55  else if (b >= 'A' && b <= 'F')
56  b -= 'A' - 10;
57  else {
58  // invalid hex digits, copy '%' and continue
59  out += *str++;
60  continue;
61  }
62 
63  out += static_cast<char>(16 * a + b);
64  str += 3;
65  }
66  else if (*str == '+') {
67  out += ' ';
68  str++;
69  }
70  else {
71  out += *str++;
72  }
73  }
74  return out;
75 }
76 
77 /*!
78  * Parse a urlencoded form data like "query=string+with+spaces&submit=yes%21&"
79  * into a list of keys and values. The keys and values are returned as pairs in
80  * the two vectors, to avoid using std::pair or another struct.
81  */
82 static inline
83 void parse_uri_form_data(const char* query_string,
84  std::vector<std::string>* key,
85  std::vector<std::string>* value) {
86 
87  key->clear(), value->clear();
88  const char* c = query_string;
89 
90  while (*c != 0) {
91  const char* begin = c;
92  while (*c != '=' && *c != 0) {
93  ++c;
94  }
95 
96  if (c == begin)
97  return;
98 
99  std::string k = parse_uri_form_data_decode(begin, c);
100 
101  if (*c == 0) {
102  key->emplace_back(std::move(k));
103  value->emplace_back(std::string());
104  return;
105  }
106 
107  begin = ++c;
108  while (*c != '&' && *c != 0) {
109  ++c;
110  }
111 
112  std::string v = parse_uri_form_data_decode(begin, c);
113 
114  key->emplace_back(std::move(k));
115  value->emplace_back(std::move(v));
116 
117  if (*c != '&')
118  break;
119  ++c;
120  }
121 }
122 
123 /*!
124  * Parse a urlencoded form data like "query=string+with+spaces&submit=yes%21&"
125  * into a list of keys and values. The keys and values are returned as pairs in
126  * the two vectors, to avoid using std::pair or another struct.
127  */
128 static inline
129 void parse_uri_form_data(const std::string& query_string,
130  std::vector<std::string>* key,
131  std::vector<std::string>* value) {
132  return parse_uri_form_data(query_string.c_str(), key, value);
133 }
134 
135 //! \}
136 
137 } // namespace tlx
138 
139 #endif // !TLX_STRING_PARSE_URI_FORM_DATA_HEADER
140 
141 /******************************************************************************/
static void parse_uri_form_data(const char *query_string, std::vector< std::string > *key, std::vector< std::string > *value)
Parse a urlencoded form data like "query=string+with+spaces&submit=yes%21&" into a list of keys and v...
static std::string parse_uri_form_data_decode(const char *str, const char *end=nullptr)
Helper function to decode %20 and + in urlencoded form data like "query=string+with+spaces&submit=yes...