Merge pull request #2388 from nghttp2/rewrite-quote_string

Rewrite util::quote_string
This commit is contained in:
Tatsuhiro Tsujikawa
2025-05-19 19:07:03 +09:00
committed by GitHub
5 changed files with 57 additions and 47 deletions

View File

@@ -208,10 +208,11 @@ StringRef make_string_ref(BlockAllocator &alloc, I first, I last) {
return StringRef{dst, p}; return StringRef{dst, p};
} }
// Makes a copy of |src|. The resulting string will be // Makes a copy of |r| as StringRef. The resulting string will be
// NULL-terminated. // NULL-terminated.
inline StringRef make_string_ref(BlockAllocator &alloc, const StringRef &src) { template <std::ranges::input_range R>
return make_string_ref(alloc, std::ranges::begin(src), std::ranges::end(src)); StringRef make_string_ref(BlockAllocator &alloc, R &&r) {
return make_string_ref(alloc, std::ranges::begin(r), std::ranges::end(r));
} }
// private function used in concat_string_ref. this is the base // private function used in concat_string_ref. this is the base

View File

@@ -246,7 +246,7 @@ StringRef create_altsvc_header_value(BlockAllocator &balloc,
for (auto &altsvc : altsvcs) { for (auto &altsvc : altsvcs) {
p = util::percent_encode_token(altsvc.protocol_id, p); p = util::percent_encode_token(altsvc.protocol_id, p);
p = std::ranges::copy("=\""sv, p).out; p = std::ranges::copy("=\""sv, p).out;
p = util::quote_string(p, altsvc.host); p = util::quote_string(altsvc.host, p);
*p++ = ':'; *p++ = ':';
p = std::ranges::copy(altsvc.service, p).out; p = std::ranges::copy(altsvc.service, p).out;
*p++ = '"'; *p++ = '"';

View File

@@ -150,35 +150,6 @@ bool in_attr_char(char c) {
return util::in_token(c); return util::in_token(c);
} }
StringRef quote_string(BlockAllocator &balloc, const StringRef &target) {
auto cnt = std::count(std::begin(target), std::end(target), '"');
if (cnt == 0) {
return make_string_ref(balloc, target);
}
auto iov = make_byte_ref(balloc, target.size() + cnt + 1);
auto p = quote_string(std::begin(iov), target);
*p = '\0';
return as_string_ref(std::begin(iov), p);
}
size_t quote_stringlen(const StringRef &target) {
size_t n = 0;
for (auto c : target) {
if (c == '"') {
n += 2;
} else {
++n;
}
}
return n;
}
namespace { namespace {
template <typename Iterator> template <typename Iterator>
Iterator cpydig(Iterator d, uint32_t n, size_t len) { Iterator cpydig(Iterator d, uint32_t n, size_t len) {

View File

@@ -259,28 +259,62 @@ constexpr size_t percent_encode_tokenlen(R &&r) noexcept {
return n; return n;
} }
// Returns quotedString version of |target|. Currently, this function // Quote a range [|first|, |last|) and stores the result in another
// range, beginning at |result|. It returns an output iterator to the
// element past the last element stored. Currently, this function
// just replace '"' with '\"'. // just replace '"' with '\"'.
StringRef quote_string(BlockAllocator &balloc, const StringRef &target); template <std::input_iterator I, std::weakly_incrementable O>
constexpr O quote_string(I first, I last, O result) noexcept {
template <typename OutputIt> for (; first != last; ++first) {
OutputIt quote_string(OutputIt it, const StringRef &target) { if (*first == '"') {
for (auto c : target) { *result++ = '\\';
if (c == '"') { *result++ = '"';
*it++ = '\\';
*it++ = '"';
} else { } else {
*it++ = c; *result++ = *first;
} }
} }
return it; return result;
}
template <std::ranges::input_range R, std::weakly_incrementable O>
constexpr O quote_string(R &&r, O result) {
return quote_string(std::ranges::begin(r), std::ranges::end(r),
std::move(result));
}
template <std::ranges::input_range R>
StringRef quote_string(BlockAllocator &balloc, R &&r) {
auto cnt = std::ranges::count(r, '"');
if (cnt == 0) {
return make_string_ref(balloc, std::forward<R>(r));
}
auto iov = make_byte_ref(balloc, std::ranges::distance(r) + cnt + 1);
auto p = quote_string(std::forward<R>(r), std::ranges::begin(iov));
*p = '\0';
return as_string_ref(std::ranges::begin(iov), p);
} }
// Returns the number of bytes written by quote_string with the same // Returns the number of bytes written by quote_string with the same
// |target| parameter. The return value does not include a terminal // |r| parameter. The return value does not include a terminal NUL
// NUL byte. // byte.
size_t quote_stringlen(const StringRef &target); template <std::ranges::input_range R> constexpr size_t quote_stringlen(R &&r) {
size_t n = 0;
for (auto c : r) {
if (c == '"') {
n += 2;
} else {
++n;
}
}
return n;
}
static constexpr char LOWER_XDIGITS[] = "0123456789abcdef"; static constexpr char LOWER_XDIGITS[] = "0123456789abcdef";

View File

@@ -246,6 +246,10 @@ void test_util_quote_string(void) {
assert_stdsv_equal(""sv, util::quote_string(balloc, ""_sr)); assert_stdsv_equal(""sv, util::quote_string(balloc, ""_sr));
assert_stdsv_equal("\\\"alpha\\\""sv, assert_stdsv_equal("\\\"alpha\\\""sv,
util::quote_string(balloc, "\"alpha\""_sr)); util::quote_string(balloc, "\"alpha\""_sr));
assert_size("\\\"alpha\\\""sv.size(), ==,
util::quote_stringlen("\"alpha\""_sr));
assert_size(0, ==, util::quote_stringlen(""_sr));
} }
void test_util_utox(void) { void test_util_utox(void) {