Mercurial > minori
diff 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 |
line wrap: on
line diff
--- a/src/core/http.cc Mon Jan 19 22:48:56 2026 -0500 +++ b/src/core/http.cc Wed Jan 21 11:27:01 2026 -0500 @@ -10,44 +10,96 @@ std::string UrlEncode(const std::string &data) { - /* why do I need to init curl just for this? wtf? */ - CURL *curl = curl_easy_init(); - if (!curl) - return ""; /* no way! */ + std::string res; + std::size_t sz = data.size(); + std::size_t i; + + // output string will always be at least data.size() + // so reserve that much space beforehand + res.reserve(sz); - char *output = curl_easy_escape(curl, data.data(), data.size()); - if (!output) { - curl_easy_cleanup(curl); - return ""; + for (i = 0; i < sz; i++) { + // This works correctly for UTF-8 because of the way + // the data is laid out. + static const char lut[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.!~*'()"; + unsigned char c = data[i]; + + if (std::memchr(lut, c, sizeof(lut) - 1)) { + res.push_back(c); + } else { + static const char lut[] = "0123456789ABCDEF"; + res.push_back('%'); + res.push_back(lut[c >> 4]); + res.push_back(lut[c & 15]); + } } - std::string str(output); - - curl_free(output); - curl_easy_cleanup(curl); - - return str; + return res; } +// NOTE: This function is not guaranteed to return +// UTF-8, or even text at all. std::string UrlDecode(const std::string &data) { - CURL *curl = curl_easy_init(); - if (!curl) - return ""; + std::string res; + + const char *ptr = data.data(); + std::size_t len = data.size(); + + // reserve space beforehand + res.reserve(len); + + while (len > 0) { + // find the next percent character + // there's probably a better way to do this! + const char *next = reinterpret_cast<const char *>(std::memchr(reinterpret_cast<const void *>(ptr), '%', len)); + + if (next) { + res.insert(res.end(), ptr, next); + len = (next - ptr); + ptr = next; + + // now process the two hex chars + if (len >= 3) { + unsigned char hi, lo; + + auto hex_char_to_value = [](unsigned char x, unsigned char &v) { + if (x >= 'A' && x <= 'F') { + v = x - 'A' + 0xA; + return true; + } - int outlength; - char *output = curl_easy_unescape(curl, data.data(), data.size(), &outlength); - if (!output) { - curl_easy_cleanup(curl); - return ""; + if (x >= 'a' && x <= 'f') { + v = x - 'a' + 0xA; + return true; + } + + if (x >= '0' && x <= '9') { + v = x - '0'; + return true; + } + + return false; + }; + + if (hex_char_to_value(ptr[1], hi) && hex_char_to_value(ptr[2], lo)) { + ptr += 3; + len -= 3; + } else { + len = 0; + } + } else { + // uh oh + len = 0; + } + } else { + res.insert(res.end(), ptr, ptr + len); + //not needed: ptr += len; + len = 0; + } } - std::string str(output, outlength); - - curl_free(output); - curl_easy_cleanup(curl); - - return str; + return res; } std::string EncodeParamsList(std::string base, const std::map<std::string, std::string> ¶ms)
