refactor: remove tr_url_query_view (#8049)

replace bespoke struct with std:: container
This commit is contained in:
Charles Kerr
2026-01-02 15:38:00 -06:00
parent 3a4e115c52
commit d7d0d87f78
4 changed files with 24 additions and 64 deletions

View File

@@ -235,7 +235,7 @@ bool tr_magnet_metainfo::parseMagnet(std::string_view magnet_link, tr_error* err
}
bool got_hash = false;
for (auto const& [key, value] : tr_url_query_view{ parsed->query })
for (auto const& [key, value] : parsed->query_entries())
{
if (key == "dn"sv)
{

View File

@@ -434,19 +434,18 @@ std::string tr_urlTrackerLogName(std::string_view url)
return std::string{ url };
}
tr_url_query_view::iterator& tr_url_query_view::iterator::operator++()
std::vector<std::pair<std::string_view, std::string_view>> tr_url_parsed_t::query_entries() const
{
auto pair = tr_strv_sep(&remain, '&');
keyval.first = tr_strv_sep(&pair, '=');
keyval.second = pair;
return *this;
}
tr_url_query_view::iterator tr_url_query_view::begin() const
{
auto it = iterator{};
it.remain = query;
return ++it;
auto tmp = query;
auto ret = std::vector<std::pair<std::string_view, std::string_view>>{};
ret.reserve(std::count(std::begin(tmp), std::end(tmp), '&') + 1U);
while (!std::empty(tmp))
{
auto val = tr_strv_sep(&tmp, '&');
auto key = tr_strv_sep(&val, '=');
ret.emplace_back(key, val);
}
return ret;
}
std::string tr_urlPercentDecode(std::string_view in)

View File

@@ -10,6 +10,7 @@
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <fmt/format.h>
@@ -38,6 +39,10 @@ struct tr_url_parsed_t
std::string_view fragment; // "nose"
std::string_view full; // "http://example.com:80/over/there?name=ferret#nose"
uint16_t port = 0;
// returns a vector of key,val pairs, e.g.
// `first=hello&second=world` -> [<"first","hello">,<"second","world">]
[[nodiscard]] std::vector<std::pair<std::string_view, std::string_view>> query_entries() const;
};
[[nodiscard]] std::optional<tr_url_parsed_t> tr_urlParse(std::string_view url);
@@ -50,52 +55,6 @@ struct tr_url_parsed_t
// This is to avoid logging sensitive info, e.g. a personal announcer id in the URL.
[[nodiscard]] std::string tr_urlTrackerLogName(std::string_view url);
// example use: `for (auto const [key, val] : tr_url_query_view{ querystr })`
struct tr_url_query_view
{
std::string_view const query;
explicit tr_url_query_view(std::string_view query_in)
: query{ query_in }
{
}
struct iterator
{
std::pair<std::string_view, std::string_view> keyval;
std::string_view remain;
iterator& operator++();
[[nodiscard]] constexpr auto const& operator*() const
{
return keyval;
}
[[nodiscard]] constexpr auto const* operator->() const
{
return &keyval;
}
[[nodiscard]] constexpr bool operator==(iterator const& that) const
{
return this->remain == that.remain && this->keyval == that.keyval;
}
[[nodiscard]] constexpr bool operator!=(iterator const& that) const
{
return !(*this == that);
}
};
[[nodiscard]] iterator begin() const;
[[nodiscard]] static constexpr iterator end()
{
return iterator{};
}
};
template<typename BackInsertIter>
constexpr void tr_urlPercentEncode(BackInsertIter out, std::string_view input, bool escape_reserved = true)
{

View File

@@ -160,13 +160,15 @@ TEST_F(WebUtilsTest, urlParseFuzz)
}
}
TEST_F(WebUtilsTest, urlNextQueryPair)
TEST_F(WebUtilsTest, urlQueryEntries)
{
auto constexpr Query = "a=1&b=two&c=si&d_has_no_val&e=&f&g=gee"sv;
auto const query_view = tr_url_query_view{ Query };
auto const end = std::end(query_view);
auto parsed = tr_url_parsed_t{};
parsed.query = "a=1&b=two&c=si&d_has_no_val&e=&f&g=gee"sv;
auto it = std::begin(query_view);
auto const keyvals = parsed.query_entries();
auto const end = std::cend(keyvals);
auto it = std::cbegin(keyvals);
EXPECT_NE(end, it);
EXPECT_EQ("a"sv, it->first);
EXPECT_EQ("1"sv, it->second);