URLParser.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #pragma once
  2. #include <cstdlib> // for strtol, size_t
  3. #include <regex> // for match_results, match_results<>::value_type, sub...
  4. #include <stdexcept> // for invalid_argument
  5. #include <string> // for string, allocator, operator+, char_traits, oper...
  6. namespace bell {
  7. class URLParser {
  8. public:
  9. static std::string urlEncode(const std::string& value) {
  10. std::string new_str = "";
  11. static auto hex_digt = "0123456789ABCDEF";
  12. std::string result;
  13. result.reserve(value.size() << 1);
  14. for (auto ch : value) {
  15. if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') ||
  16. (ch >= 'a' && ch <= 'z') || ch == '-' || ch == '_' || ch == '!' ||
  17. ch == '\'' || ch == '(' || ch == ')' || ch == '*' || ch == '~' ||
  18. ch == '.') // !'()*-._~
  19. {
  20. result.push_back(ch);
  21. } else {
  22. result += std::string("%") +
  23. hex_digt[static_cast<unsigned char>(ch) >> 4] +
  24. hex_digt[static_cast<unsigned char>(ch) & 15];
  25. }
  26. }
  27. return result;
  28. }
  29. static std::string urlDecode(const std::string& value) {
  30. std::string result;
  31. result.reserve(value.size());
  32. for (std::size_t i = 0; i < value.size(); ++i) {
  33. auto ch = value[i];
  34. if (ch == '%' && (i + 2) < value.size()) {
  35. auto hex = value.substr(i + 1, 2);
  36. auto dec = static_cast<char>(std::strtol(hex.c_str(), nullptr, 16));
  37. result.push_back(dec);
  38. i += 2;
  39. } else if (ch == '+') {
  40. result.push_back(' ');
  41. } else {
  42. result.push_back(ch);
  43. }
  44. }
  45. return result;
  46. }
  47. std::string host;
  48. int port = -1;
  49. std::string schema = "http";
  50. std::string path;
  51. #ifdef BELL_DISABLE_REGEX
  52. void parse(const char* url, std::vector<std::string>& match);
  53. #else
  54. static const std::regex urlParseRegex;
  55. #endif
  56. static URLParser parse(const std::string& url) {
  57. URLParser parser;
  58. // apply parser.urlParseRegex to url
  59. #ifdef BELL_DISABLE_REGEX
  60. std::vector<std::string> match(6);
  61. parser.parse(url.c_str(), match);
  62. #else
  63. std::cmatch match;
  64. std::regex_match(url.c_str(), match, parser.urlParseRegex);
  65. #endif
  66. if (match.size() < 3) {
  67. throw std::invalid_argument("Invalid URL");
  68. }
  69. parser.schema = match[1];
  70. parser.host = match[2];
  71. parser.path = match[3];
  72. if (match[4] != "") {
  73. parser.path += match[4];
  74. }
  75. // check if parser.host contains ':'
  76. if (parser.host.find(':') != std::string::npos) {
  77. auto port = std::stoi(
  78. parser.host.substr(parser.host.find(':') + 1, parser.host.size()));
  79. auto host = parser.host.substr(0, parser.host.find(':'));
  80. parser.port = port;
  81. parser.host = host;
  82. }
  83. if (parser.port == -1) {
  84. parser.port = parser.schema == "http" ? 80 : 443;
  85. }
  86. return parser;
  87. }
  88. };
  89. } // namespace bell