UrlDecode.hpp
Go to the documentation of this file.
1 // @formatter:off
2 //
3 // Balau core C++ library
4 //
5 // Copyright (C) 2017 Bora Software (contact@borasoftware.com)
6 //
7 // Licensed under the Boost Software License - Version 1.0 - August 17th, 2003.
8 // See the LICENSE file for the full license text.
9 //
10 
16 
17 #ifndef COM_BORA_SOFTWARE__BALAU_NETWORK_UTILITIES__URL_DECODE
18 #define COM_BORA_SOFTWARE__BALAU_NETWORK_UTILITIES__URL_DECODE
19 
21 #include <Balau/Util/Strings.hpp>
22 
23 #include <map>
24 
25 namespace Balau::Network {
26 
30 struct UrlDecode {
38  static std::unordered_map<std::string, std::string> splitAndDecode(const std::string_view & data,
39  bool validateUtf8 = true,
40  bool throwOnError = false) {
41  std::unordered_map<std::string, std::string> decodedParameters;
42 
43  const auto parameters = split(data);
44 
45  for (auto iter = parameters.begin(); iter != parameters.end(); ++iter) {
46  auto decodedKey = decode(iter->first, validateUtf8, throwOnError);
47  auto decodedValue = decode(iter->second, validateUtf8, throwOnError);
48 
49  decodedParameters.insert(std::make_pair(std::move(decodedKey), std::move(decodedValue)));
50  }
51 
52  return decodedParameters;
53  }
54 
64  static std::unordered_map<std::string_view, std::string_view> split(const std::string_view data) {
65  std::unordered_map<std::string_view, std::string_view> keysAndValues;
66  std::vector<std::string_view> parameters = Util::Strings::split(data, "&");
67 
68  for (auto parameter : parameters) {
69  std::vector<std::string_view> keyAndValue = Util::Strings::split(parameter, "=");
70 
71  if (keyAndValue.size() == 1) {
72  // No value supplied.
73  keysAndValues.emplace(keyAndValue[0], "");
74  } else if (keyAndValue.size() != 2) {
75  ThrowBalauException(Exception::NetworkException, "Invalid parameter list");
76  } else {
77  keysAndValues.emplace(keyAndValue[0], keyAndValue[1]);
78  }
79  }
80 
81  return keysAndValues;
82  }
83 
106  static std::string decode(const std::string_view input, bool validateUtf8 = true, bool throwOnError = false) {
107  std::string output;
108  size_t index = 0;
109 
110  while (index < input.length()) {
111  switch (input[index]) {
112  case '+': {
113  output += ' ';
114  ++index;
115  break;
116  }
117 
118  case '%': {
119  std::string thisOutput;
120 
121  while (input[index] == '%') {
122  ++index;
123 
124  if (index == input.length()) {
125  // Illegal input.. % character on its own at the end.
126  if (throwOnError) {
127  ThrowBalauException(Exception::NetworkException, "Invalid percent encoded string");
128  }
129 
130  continue;
131  }
132 
133  const size_t x = index;
134  ++index;
135 
136  if (index == input.length()) {
137  // Illegal input.. % character with single following character at the end.
138  if (throwOnError) {
139  ThrowBalauException(Exception::NetworkException, "Invalid percent encoded string");
140  }
141 
142  continue;
143  }
144 
145  // Try to convert the hex character pair into an unsigned byte.
146  std::string_view v = input.substr(x, 2);
147  unsigned char b;
148  fromString(b, v, 16);
149  thisOutput += (char) b;
150  ++index;
151  }
152 
153  bool valid = true;
154 
155  if (validateUtf8) {
156  int offset = 0;
157 
158  while (offset != (int) thisOutput.length()) {
159  Character::getNextUtf8Safe(thisOutput, offset);
160 
161  if (offset < 0) {
162  // Not valid UTF-8.
163  if (throwOnError) {
164  ThrowBalauException(Exception::NetworkException, "Invalid percent encoded string");
165  }
166 
167  valid = false;
168  break;
169  }
170  }
171  }
172 
173  if (valid) {
174  output += thisOutput;
175  }
176 
177  break;
178  }
179 
180  default: {
181  output += input[index];
182  ++index;
183  break;
184  }
185  }
186  }
187 
188  return output;
189  }
190 
192 
193  UrlDecode() = delete;
194  UrlDecode(const UrlDecode &) = delete;
195  UrlDecode & operator = (const UrlDecode &) = delete;
196 };
197 
198 } // namespace Balau::Network
199 
200 #endif // COM_BORA_SOFTWARE__BALAU_NETWORK_UTILITIES__URL_DECODE
static std::unordered_map< std::string_view, std::string_view > split(const std::string_view data)
Split the URL encoded parameters into a map of string views.
Definition: UrlDecode.hpp:64
static std::unordered_map< std::string, std::string > splitAndDecode(const std::string_view &data, bool validateUtf8=true, bool throwOnError=false)
Split the URL encoded parameters then decode each one.
Definition: UrlDecode.hpp:38
#define ThrowBalauException(ExceptionClass,...)
Throw a Balau style exception, with implicit file and line number, and optional stacktrace.
Definition: BalauException.hpp:45
static std::string decode(const std::string_view input, bool validateUtf8=true, bool throwOnError=false)
Decode the percent encoded input string into a UTF-8 string, according to the following rules...
Definition: UrlDecode.hpp:106
static std::vector< std::string_view > split(const std::string_view &input, const std::regex &delimiter, bool returnDelimiters=false, bool compress=true)
Split the input string on each of the occurrences of the specified delimiter regular expression...
Definition: Strings.hpp:1240
Base class of network exceptions.
Definition: NetworkExceptions.hpp:28
Components and utilities working on network data transmission.
static char32_t getNextUtf8Safe(const std::string_view &text, int &offset)
Get the next code point from the UTF-8 string view (validating version).
Definition: Character.hpp:198
Utilities for strings.
Balau exceptions for network operations.
Utility for splitting and decoding URL encoded data.
Definition: UrlDecode.hpp:30