Skip to content

Commit 8b86e1d

Browse files
authored
Merge pull request #25097 from rockwotj/bp-iobuf-writer-v24.2
[v24.2.x] json: fix empty string case in iobuf_writer
2 parents f9a22d4 + 29f0a88 commit 8b86e1d

File tree

2 files changed

+35
-19
lines changed

2 files changed

+35
-19
lines changed

src/v/json/iobuf_writer.h

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,17 @@ class generic_iobuf_writer
4848

4949
private:
5050
bool write_chunked_string(const iobuf& buf) {
51-
const auto last_frag = [this]() {
52-
return std::prev(this->os_->_impl.end());
53-
};
51+
const auto last_frag = [this]() { return this->os_->_impl.rbegin(); };
5452
using Ch = Base::Ch;
5553
this->Prefix(rapidjson::kStringType);
5654
const auto beg = buf.begin();
5755
const auto end = buf.end();
58-
const auto last = std::prev(end);
56+
if (beg == end) {
57+
if (!Base::WriteString("", 0)) {
58+
return false;
59+
}
60+
return this->EndValue(true);
61+
}
5962
Ch stashed{};
6063
Ch* stash_pos{};
6164
// Base::WriteString is used to JSON encode the string, and requires a
@@ -73,31 +76,33 @@ class generic_iobuf_writer
7376
// 3. Drop the final character
7477
// For each encoded fragment that is written (except the first one):
7578
// 4. Restore the stashed character over the prefix-quote
76-
for (auto i = beg; i != end; ++i) {
79+
for (auto i = beg;;) {
7780
if (!Base::WriteString(i->get(), i->size())) {
7881
return false;
7982
}
8083
if (i != beg) {
8184
// 4. Restore the stashed character over the prefix-quote
8285
*stash_pos = stashed;
8386
}
84-
if (i != last) {
85-
// 1. Trim the suffix quote
86-
this->os_->_impl.trim_back(1);
87+
++i;
88+
if (i == end) {
89+
break;
90+
}
91+
// 1. Trim the suffix quote
92+
this->os_->_impl.trim_back(1);
8793

88-
// 2. Stash the final character, ...
89-
auto last = last_frag();
90-
stashed = *std::prev(last->get_current());
91-
// 3. Drop the final character
92-
this->os_->_impl.trim_back(1);
94+
// 2. Stash the final character, ...
95+
auto last = last_frag();
96+
stashed = *std::prev(last->get_current());
97+
// 3. Drop the final character
98+
this->os_->_impl.trim_back(1);
9399

94-
// Ensure a stable address to restore the stashed character
95-
if (last != last_frag()) {
96-
this->os_->_impl.reserve_memory(1);
97-
}
98-
// 2. ...and where it is to be written.
99-
stash_pos = last_frag()->get_current();
100+
// Ensure a stable address to restore the stashed character
101+
if (last != last_frag()) {
102+
this->os_->_impl.reserve_memory(1);
100103
}
104+
// 2. ...and where it is to be written.
105+
stash_pos = last_frag()->get_current();
101106
}
102107
return this->EndValue(true);
103108
}

src/v/json/tests/json_serialization_test.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,15 @@ SEASTAR_THREAD_TEST_CASE(json_iobuf_writer_test) {
190190
BOOST_CHECK_EQUAL(out_buf, expected);
191191
BOOST_CHECK_EQUAL(to_string(out_buf), to_string(expected));
192192
}
193+
194+
{
195+
json::chunked_buffer out;
196+
json::iobuf_writer<json::chunked_buffer> os{out};
197+
iobuf buf;
198+
os.String(buf);
199+
auto out_buf = std::move(out).as_iobuf();
200+
auto expected = iobuf::from("\"\"");
201+
BOOST_CHECK_EQUAL(out_buf, expected);
202+
BOOST_CHECK_EQUAL(to_string(out_buf), to_string(expected));
203+
}
193204
}

0 commit comments

Comments
 (0)