Mercurial > minori
comparison src/core/http.cc @ 407:2ae34a90f8d4
http: roll our own URL encode/decode functions
works for basically every kind of data
| author | Paper <paper@tflc.us> |
|---|---|
| date | Wed, 21 Jan 2026 11:27:01 -0500 |
| parents | 811697ad826a |
| children | 9323153786dc |
comparison
equal
deleted
inserted
replaced
| 406:31ce85df55a8 | 407:2ae34a90f8d4 |
|---|---|
| 8 | 8 |
| 9 namespace HTTP { | 9 namespace HTTP { |
| 10 | 10 |
| 11 std::string UrlEncode(const std::string &data) | 11 std::string UrlEncode(const std::string &data) |
| 12 { | 12 { |
| 13 /* why do I need to init curl just for this? wtf? */ | 13 std::string res; |
| 14 CURL *curl = curl_easy_init(); | 14 std::size_t sz = data.size(); |
| 15 if (!curl) | 15 std::size_t i; |
| 16 return ""; /* no way! */ | 16 |
| 17 | 17 // output string will always be at least data.size() |
| 18 char *output = curl_easy_escape(curl, data.data(), data.size()); | 18 // so reserve that much space beforehand |
| 19 if (!output) { | 19 res.reserve(sz); |
| 20 curl_easy_cleanup(curl); | 20 |
| 21 return ""; | 21 for (i = 0; i < sz; i++) { |
| 22 } | 22 // This works correctly for UTF-8 because of the way |
| 23 | 23 // the data is laid out. |
| 24 std::string str(output); | 24 static const char lut[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.!~*'()"; |
| 25 | 25 unsigned char c = data[i]; |
| 26 curl_free(output); | 26 |
| 27 curl_easy_cleanup(curl); | 27 if (std::memchr(lut, c, sizeof(lut) - 1)) { |
| 28 | 28 res.push_back(c); |
| 29 return str; | 29 } else { |
| 30 } | 30 static const char lut[] = "0123456789ABCDEF"; |
| 31 | 31 res.push_back('%'); |
| 32 res.push_back(lut[c >> 4]); | |
| 33 res.push_back(lut[c & 15]); | |
| 34 } | |
| 35 } | |
| 36 | |
| 37 return res; | |
| 38 } | |
| 39 | |
| 40 // NOTE: This function is not guaranteed to return | |
| 41 // UTF-8, or even text at all. | |
| 32 std::string UrlDecode(const std::string &data) | 42 std::string UrlDecode(const std::string &data) |
| 33 { | 43 { |
| 34 CURL *curl = curl_easy_init(); | 44 std::string res; |
| 35 if (!curl) | 45 |
| 36 return ""; | 46 const char *ptr = data.data(); |
| 37 | 47 std::size_t len = data.size(); |
| 38 int outlength; | 48 |
| 39 char *output = curl_easy_unescape(curl, data.data(), data.size(), &outlength); | 49 // reserve space beforehand |
| 40 if (!output) { | 50 res.reserve(len); |
| 41 curl_easy_cleanup(curl); | 51 |
| 42 return ""; | 52 while (len > 0) { |
| 43 } | 53 // find the next percent character |
| 44 | 54 // there's probably a better way to do this! |
| 45 std::string str(output, outlength); | 55 const char *next = reinterpret_cast<const char *>(std::memchr(reinterpret_cast<const void *>(ptr), '%', len)); |
| 46 | 56 |
| 47 curl_free(output); | 57 if (next) { |
| 48 curl_easy_cleanup(curl); | 58 res.insert(res.end(), ptr, next); |
| 49 | 59 len = (next - ptr); |
| 50 return str; | 60 ptr = next; |
| 61 | |
| 62 // now process the two hex chars | |
| 63 if (len >= 3) { | |
| 64 unsigned char hi, lo; | |
| 65 | |
| 66 auto hex_char_to_value = [](unsigned char x, unsigned char &v) { | |
| 67 if (x >= 'A' && x <= 'F') { | |
| 68 v = x - 'A' + 0xA; | |
| 69 return true; | |
| 70 } | |
| 71 | |
| 72 if (x >= 'a' && x <= 'f') { | |
| 73 v = x - 'a' + 0xA; | |
| 74 return true; | |
| 75 } | |
| 76 | |
| 77 if (x >= '0' && x <= '9') { | |
| 78 v = x - '0'; | |
| 79 return true; | |
| 80 } | |
| 81 | |
| 82 return false; | |
| 83 }; | |
| 84 | |
| 85 if (hex_char_to_value(ptr[1], hi) && hex_char_to_value(ptr[2], lo)) { | |
| 86 ptr += 3; | |
| 87 len -= 3; | |
| 88 } else { | |
| 89 len = 0; | |
| 90 } | |
| 91 } else { | |
| 92 // uh oh | |
| 93 len = 0; | |
| 94 } | |
| 95 } else { | |
| 96 res.insert(res.end(), ptr, ptr + len); | |
| 97 //not needed: ptr += len; | |
| 98 len = 0; | |
| 99 } | |
| 100 } | |
| 101 | |
| 102 return res; | |
| 51 } | 103 } |
| 52 | 104 |
| 53 std::string EncodeParamsList(std::string base, const std::map<std::string, std::string> ¶ms) | 105 std::string EncodeParamsList(std::string base, const std::map<std::string, std::string> ¶ms) |
| 54 { | 106 { |
| 55 std::size_t count = 0; | 107 std::size_t count = 0; |
