1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
|
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012- OpenVPN Inc.
//
// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
//
#ifndef OPENVPN_HTTP_URLENCODE_H
#define OPENVPN_HTTP_URLENCODE_H
#include <string>
#include <vector>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/split.hpp>
#include <openvpn/common/string.hpp>
#include <openvpn/common/hexstr.hpp>
#include <openvpn/common/unicode.hpp>
#include <openvpn/http/parseutil.hpp>
namespace openvpn::URL {
OPENVPN_EXCEPTION(url_error);
inline std::string encode(const std::string &str)
{
std::string ret;
ret.reserve(str.length() * 2); // just a guess
for (auto &c : str)
{
if (HTTP::Util::is_escaped(c))
{
ret += '%';
ret += render_hex_number((unsigned char)c, true);
}
else
ret += c;
}
return ret;
}
inline std::string decode(const std::string &encoded)
{
enum State
{
TEXT,
PERCENT,
DIGIT
};
int value = 0;
State state = TEXT;
std::string ret;
ret.reserve(encoded.size()); // just a guess
for (auto &c : encoded)
{
switch (state)
{
case TEXT:
{
if (c == '%')
state = PERCENT;
else
ret += c;
break;
}
case PERCENT:
{
const int v = parse_hex_char(c);
if (v < 0)
throw url_error(std::string("decode error after %: ") + encoded);
value = v;
state = DIGIT;
break;
}
case DIGIT:
{
const int v = parse_hex_char(c);
if (v < 0)
throw url_error(std::string("decode error after %: ") + encoded);
ret += static_cast<unsigned char>((value * 16) + v);
state = TEXT;
}
}
}
if (state != TEXT)
throw url_error(std::string("decode error: %-encoding item not closed out: ") + encoded);
if (!Unicode::is_valid_utf8(ret))
throw url_error(std::string("not UTF-8: ") + encoded);
return ret;
}
inline std::vector<std::string> decode_path(std::string path)
{
std::vector<std::string> list;
if (!path.empty() && path[0] == '/')
path = path.substr(1);
Split::by_char_void<decltype(list), NullLex, Split::NullLimit>(list, path, '/');
for (auto &i : list)
i = decode(i);
return list;
}
} // namespace openvpn::URL
#endif
|