123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- #pragma once
- #include <cstdlib> // for strtol, size_t
- #include <regex> // for match_results, match_results<>::value_type, sub...
- #include <stdexcept> // for invalid_argument
- #include <string> // for string, allocator, operator+, char_traits, oper...
- namespace bell {
- class URLParser {
- public:
- static std::string urlEncode(const std::string& value) {
- std::string new_str = "";
- static auto hex_digt = "0123456789ABCDEF";
- std::string result;
- result.reserve(value.size() << 1);
- for (auto ch : value) {
- if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') ||
- (ch >= 'a' && ch <= 'z') || ch == '-' || ch == '_' || ch == '!' ||
- ch == '\'' || ch == '(' || ch == ')' || ch == '*' || ch == '~' ||
- ch == '.') // !'()*-._~
- {
- result.push_back(ch);
- } else {
- result += std::string("%") +
- hex_digt[static_cast<unsigned char>(ch) >> 4] +
- hex_digt[static_cast<unsigned char>(ch) & 15];
- }
- }
- return result;
- }
- static std::string urlDecode(const std::string& value) {
- std::string result;
- result.reserve(value.size());
- for (std::size_t i = 0; i < value.size(); ++i) {
- auto ch = value[i];
- if (ch == '%' && (i + 2) < value.size()) {
- auto hex = value.substr(i + 1, 2);
- auto dec = static_cast<char>(std::strtol(hex.c_str(), nullptr, 16));
- result.push_back(dec);
- i += 2;
- } else if (ch == '+') {
- result.push_back(' ');
- } else {
- result.push_back(ch);
- }
- }
- return result;
- }
- std::string host;
- int port = -1;
- std::string schema = "http";
- std::string path;
- #ifdef BELL_DISABLE_REGEX
- void parse(const char* url, std::vector<std::string>& match);
- #else
- static const std::regex urlParseRegex;
- #endif
- static URLParser parse(const std::string& url) {
- URLParser parser;
- // apply parser.urlParseRegex to url
- #ifdef BELL_DISABLE_REGEX
- std::vector<std::string> match(6);
- parser.parse(url.c_str(), match);
- #else
- std::cmatch match;
- std::regex_match(url.c_str(), match, parser.urlParseRegex);
- #endif
- if (match.size() < 3) {
- throw std::invalid_argument("Invalid URL");
- }
- parser.schema = match[1];
- parser.host = match[2];
- parser.path = match[3];
- if (match[4] != "") {
- parser.path += match[4];
- }
- // check if parser.host contains ':'
- if (parser.host.find(':') != std::string::npos) {
- auto port = std::stoi(
- parser.host.substr(parser.host.find(':') + 1, parser.host.size()));
- auto host = parser.host.substr(0, parser.host.find(':'));
- parser.port = port;
- parser.host = host;
- }
- if (parser.port == -1) {
- parser.port = parser.schema == "http" ? 80 : 443;
- }
- return parser;
- }
- };
- } // namespace bell
|