mirror of
https://github.com/monero-project/monero.git
synced 2026-01-07 18:05:33 -05:00
epee: optimize uri conversion functions
- greatly reduced # of string allocations (only 1 per function) - fixed typo in function name (conver -> convert) - used more standard library functions to simplify manual logic and remove pointer arithmetic - removed all functions in header that were only used by these 2 functions - replaced const std::string& parameter with std::string_view - use compile-time generated lookup table for O(1) encoding of characters
This commit is contained in:
parent
48ad374b0d
commit
1de0750bf2
3 changed files with 57 additions and 118 deletions
|
|
@ -34,27 +34,8 @@ namespace epee
|
|||
{
|
||||
namespace net_utils
|
||||
{
|
||||
inline const char* get_hex_vals()
|
||||
{
|
||||
static constexpr const char hexVals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
||||
return hexVals;
|
||||
}
|
||||
|
||||
inline const char* get_unsave_chars()
|
||||
{
|
||||
//static constexpr char unsave_chars[] = "\"<>%\\^[]`+$,@:;/!#?=&";
|
||||
static constexpr const char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&";
|
||||
return unsave_chars;
|
||||
}
|
||||
|
||||
bool is_unsafe(unsigned char compare_char);
|
||||
std::string dec_to_hex(char num, int radix);
|
||||
int get_index(const char *s, char c);
|
||||
std::string hex_to_dec_2bytes(const char *s);
|
||||
std::string convert(char val);
|
||||
std::string conver_to_url_format(const std::string& uri);
|
||||
std::string convert_from_url_format(const std::string& uri);
|
||||
|
||||
std::string convert_to_url_format(std::string_view uri);
|
||||
std::string convert_from_url_format(std::string_view uri);
|
||||
namespace http
|
||||
{
|
||||
class abstract_http_client
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include <charconv>
|
||||
#include <math.h>
|
||||
#include "net/abstract_http_client.h"
|
||||
#include "net/http_base.h"
|
||||
|
|
@ -7,113 +8,70 @@
|
|||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
|
||||
|
||||
namespace {
|
||||
constexpr auto hex_byte_len = 2; // 00 to FF
|
||||
constexpr char uri_escape_char = '%'; // placed before each byte i.e. %61
|
||||
// immediately invoked lambda expression that creates a lookup table at compile-time.
|
||||
// each safe byte for URL is '\0\0', each unsafe byte has the hex representation of the byte.
|
||||
constexpr auto encoding_table = []() -> std::array<std::array<unsigned char, hex_byte_len>, 256> {
|
||||
std::array<std::array<unsigned char, hex_byte_len>, 256> temp{}; // everything is zeroed-out.
|
||||
std::string_view unsafe{"\"<>%\\^[]`+$,@:;!#&"};
|
||||
for (std::size_t i = 0; i < temp.size(); ++i) {
|
||||
if((i <= 32) || (i >= 123) || (unsafe.find(i) != unsafe.npos)) {
|
||||
// encode the unsafe characters.
|
||||
const auto first {i / 16};
|
||||
const auto second {i % 16};
|
||||
temp[i][0] = (first < 0xA) ? ('0' + first) : ('A' + (first - 0xA));
|
||||
temp[i][1] = (second < 0xA) ? ('0' + second) : ('A' + (second - 0xA));
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}(); // note : all this is done at compile-time.
|
||||
} // namespace
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool is_unsafe(unsigned char compare_char)
|
||||
std::string convert_to_url_format(std::string_view uri)
|
||||
{
|
||||
if(compare_char <= 32 || compare_char >= 123)
|
||||
return true;
|
||||
|
||||
const char* punsave = get_unsave_chars();
|
||||
|
||||
for(int ichar_pos = 0; 0!=punsave[ichar_pos] ;ichar_pos++)
|
||||
if(compare_char == punsave[ichar_pos])
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string dec_to_hex(char num, int radix)
|
||||
{
|
||||
int temp=0;
|
||||
std::string csTmp;
|
||||
int num_char;
|
||||
|
||||
num_char = (int) num;
|
||||
if (num_char < 0)
|
||||
num_char = 256 + num_char;
|
||||
|
||||
while (num_char >= radix)
|
||||
{
|
||||
temp = num_char % radix;
|
||||
num_char = (int)floor((float)num_char / (float)radix);
|
||||
csTmp = get_hex_vals()[temp];
|
||||
std::string result (uri.size() * (hex_byte_len + 1), '\0'); // reserve the max possible size, shrink later.
|
||||
auto write_it {result.begin()};
|
||||
for (const unsigned char character : uri) {
|
||||
const std::array<unsigned char, hex_byte_len>& encoding = encoding_table[character];
|
||||
if (encoding.front() == '\0') {
|
||||
*(write_it++) = character;
|
||||
} else {
|
||||
*write_it = uri_escape_char;
|
||||
write_it = std::copy(encoding.begin(), encoding.end(), write_it + 1);
|
||||
}
|
||||
}
|
||||
|
||||
csTmp += get_hex_vals()[num_char];
|
||||
|
||||
if(csTmp.size() < 2)
|
||||
{
|
||||
csTmp += '0';
|
||||
}
|
||||
|
||||
std::reverse(csTmp.begin(), csTmp.end());
|
||||
//_mbsrev((unsigned char*)csTmp.data());
|
||||
|
||||
return csTmp;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
int get_index(const char *s, char c)
|
||||
{
|
||||
const char *ptr = (const char*)memchr(s, c, 16);
|
||||
return ptr ? ptr-s : -1;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string hex_to_dec_2bytes(const char *s)
|
||||
{
|
||||
const char *hex = get_hex_vals();
|
||||
int i0 = get_index(hex, toupper(s[0]));
|
||||
int i1 = get_index(hex, toupper(s[1]));
|
||||
if (i0 < 0 || i1 < 0)
|
||||
return std::string("%") + std::string(1, s[0]) + std::string(1, s[1]);
|
||||
return std::string(1, i0 * 16 | i1);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string convert(char val)
|
||||
{
|
||||
std::string csRet;
|
||||
csRet += "%";
|
||||
csRet += dec_to_hex(val, 16);
|
||||
return csRet;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string conver_to_url_format(const std::string& uri)
|
||||
{
|
||||
|
||||
std::string result;
|
||||
|
||||
for(size_t i = 0; i!= uri.size(); i++)
|
||||
{
|
||||
if(is_unsafe(uri[i]))
|
||||
result += convert(uri[i]);
|
||||
else
|
||||
result += uri[i];
|
||||
|
||||
}
|
||||
|
||||
result.resize(std::distance(result.begin(), write_it));
|
||||
return result;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string convert_from_url_format(const std::string& uri)
|
||||
std::string convert_from_url_format(std::string_view uri)
|
||||
{
|
||||
|
||||
std::string result;
|
||||
|
||||
for(size_t i = 0; i!= uri.size(); i++)
|
||||
{
|
||||
if(uri[i] == '%' && i + 2 < uri.size())
|
||||
{
|
||||
result += hex_to_dec_2bytes(uri.c_str() + i + 1);
|
||||
i += 2;
|
||||
std::string result (uri.size(), '\0'); // reserve the max possible size, shrink later.
|
||||
auto write_it {result.begin()};
|
||||
for (auto it {uri.cbegin()}, end {uri.cend()}; it < end; ++it) {
|
||||
const auto character {*it};
|
||||
if (character != uri_escape_char || std::distance(it, end) < (hex_byte_len + 1)) {
|
||||
*(write_it++) = character;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
result += uri[i];
|
||||
|
||||
unsigned char decoded{};
|
||||
const auto hex_begin = it + 1; // skip '%'
|
||||
const auto hex_end {hex_begin + hex_byte_len};
|
||||
const auto [ptr, ec] = std::from_chars(hex_begin, hex_end, decoded, 16);
|
||||
if (ec == std::errc{} && ptr == hex_end) {
|
||||
*(write_it++) = decoded;
|
||||
} else {
|
||||
write_it = std::copy(it, hex_end, write_it); // in case of failure, copy the original string's contents.
|
||||
}
|
||||
it += hex_byte_len;
|
||||
}
|
||||
|
||||
result.resize(std::distance(result.begin(), write_it));
|
||||
return result;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -14850,12 +14850,12 @@ std::string wallet2::make_uri(const std::string &address, const std::string &pay
|
|||
|
||||
if (!recipient_name.empty())
|
||||
{
|
||||
uri += (n_fields++ ? "&" : "?") + std::string("recipient_name=") + epee::net_utils::conver_to_url_format(recipient_name);
|
||||
uri += (n_fields++ ? "&" : "?") + std::string("recipient_name=") + epee::net_utils::convert_to_url_format(recipient_name);
|
||||
}
|
||||
|
||||
if (!tx_description.empty())
|
||||
{
|
||||
uri += (n_fields++ ? "&" : "?") + std::string("tx_description=") + epee::net_utils::conver_to_url_format(tx_description);
|
||||
uri += (n_fields++ ? "&" : "?") + std::string("tx_description=") + epee::net_utils::convert_to_url_format(tx_description);
|
||||
}
|
||||
|
||||
return uri;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue