/proc/self/cwd/source/common/json/json_streamer.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "source/common/json/json_streamer.h" |
2 | | |
3 | | #include "source/common/buffer/buffer_util.h" |
4 | | #include "source/common/json/json_sanitizer.h" |
5 | | |
6 | | namespace Envoy { |
7 | | namespace Json { |
8 | | |
9 | | // To ensure the streamer is being used correctly, we use assertions to enforce |
10 | | // that only the topmost map/array in the stack is being written to. To make |
11 | | // this easier to do from the Level classes, we provider Streamer::topLevel() as |
12 | | // a member function, but this is only needed when compiled for debug. |
13 | | // |
14 | | // We only compile Streamer::topLevel in debug to avoid having it be a coverage |
15 | | // gap. However, assertions fail to compile in release mode if they reference |
16 | | // non-existent functions or member variables, so we only compile the assertions |
17 | | // in debug mode. |
18 | | #ifdef NDEBUG |
19 | | #define ASSERT_THIS_IS_TOP_LEVEL \ |
20 | | do { \ |
21 | | } while (0) |
22 | | #define ASSERT_LEVELS_EMPTY \ |
23 | | do { \ |
24 | | } while (0) |
25 | | #else |
26 | 0 | #define ASSERT_THIS_IS_TOP_LEVEL ASSERT(streamer_.topLevel() == this) |
27 | 0 | #define ASSERT_LEVELS_EMPTY ASSERT(levels_.empty()) |
28 | | #endif |
29 | | |
30 | | Streamer::Level::Level(Streamer& streamer, absl::string_view opener, absl::string_view closer) |
31 | 0 | : streamer_(streamer), closer_(closer) { |
32 | 0 | streamer_.addConstantString(opener); |
33 | 0 | #ifndef NDEBUG |
34 | 0 | streamer_.push(this); |
35 | 0 | #endif |
36 | 0 | } |
37 | | |
38 | 0 | Streamer::Level::~Level() { |
39 | 0 | streamer_.addConstantString(closer_); |
40 | 0 | #ifndef NDEBUG |
41 | 0 | streamer_.pop(this); |
42 | 0 | #endif |
43 | 0 | } |
44 | | |
45 | 0 | Streamer::MapPtr Streamer::makeRootMap() { |
46 | 0 | ASSERT_LEVELS_EMPTY; |
47 | 0 | return std::make_unique<Map>(*this); |
48 | 0 | } |
49 | | |
50 | 0 | Streamer::ArrayPtr Streamer::makeRootArray() { |
51 | 0 | ASSERT_LEVELS_EMPTY; |
52 | 0 | return std::make_unique<Array>(*this); |
53 | 0 | } |
54 | | |
55 | 0 | Streamer::MapPtr Streamer::Level::addMap() { |
56 | 0 | ASSERT_THIS_IS_TOP_LEVEL; |
57 | 0 | nextField(); |
58 | 0 | return std::make_unique<Map>(streamer_); |
59 | 0 | } |
60 | | |
61 | 0 | Streamer::ArrayPtr Streamer::Level::addArray() { |
62 | 0 | ASSERT_THIS_IS_TOP_LEVEL; |
63 | 0 | nextField(); |
64 | 0 | return std::make_unique<Array>(streamer_); |
65 | 0 | } |
66 | | |
67 | 0 | void Streamer::Level::addNumber(double number) { |
68 | 0 | ASSERT_THIS_IS_TOP_LEVEL; |
69 | 0 | nextField(); |
70 | 0 | streamer_.addNumber(number); |
71 | 0 | } |
72 | | |
73 | 0 | void Streamer::Level::addNumber(uint64_t number) { |
74 | 0 | ASSERT_THIS_IS_TOP_LEVEL; |
75 | 0 | nextField(); |
76 | 0 | streamer_.addNumber(number); |
77 | 0 | } |
78 | | |
79 | 0 | void Streamer::Level::addNumber(int64_t number) { |
80 | 0 | ASSERT_THIS_IS_TOP_LEVEL; |
81 | 0 | nextField(); |
82 | 0 | streamer_.addNumber(number); |
83 | 0 | } |
84 | | |
85 | 0 | void Streamer::Level::addString(absl::string_view str) { |
86 | 0 | ASSERT_THIS_IS_TOP_LEVEL; |
87 | 0 | nextField(); |
88 | 0 | streamer_.addSanitized("\"", str, "\""); |
89 | 0 | } |
90 | | |
91 | | #ifndef NDEBUG |
92 | 0 | void Streamer::pop(Level* level) { |
93 | 0 | ASSERT(levels_.top() == level); |
94 | 0 | levels_.pop(); |
95 | 0 | } |
96 | | |
97 | 0 | void Streamer::push(Level* level) { levels_.push(level); } |
98 | | #endif |
99 | | |
100 | 0 | void Streamer::Level::nextField() { |
101 | 0 | if (is_first_) { |
102 | 0 | is_first_ = false; |
103 | 0 | } else { |
104 | 0 | streamer_.addConstantString(","); |
105 | 0 | } |
106 | 0 | } |
107 | | |
108 | 0 | void Streamer::Map::nextField() { |
109 | 0 | if (expecting_value_) { |
110 | 0 | expecting_value_ = false; |
111 | 0 | } else { |
112 | 0 | Level::nextField(); |
113 | 0 | } |
114 | 0 | } |
115 | | |
116 | 0 | void Streamer::Map::addKey(absl::string_view key) { |
117 | 0 | ASSERT_THIS_IS_TOP_LEVEL; |
118 | 0 | ASSERT(!expecting_value_); |
119 | 0 | nextField(); |
120 | 0 | streamer_.addSanitized("\"", key, "\":"); |
121 | 0 | expecting_value_ = true; |
122 | 0 | } |
123 | | |
124 | 0 | void Streamer::Map::addEntries(const Entries& entries) { |
125 | 0 | for (const NameValue& entry : entries) { |
126 | 0 | addKey(entry.first); |
127 | 0 | addValue(entry.second); |
128 | 0 | } |
129 | 0 | } |
130 | | |
131 | 0 | void Streamer::Level::addValue(const Value& value) { |
132 | 0 | switch (value.index()) { |
133 | 0 | case 0: |
134 | 0 | addString(absl::get<absl::string_view>(value)); |
135 | 0 | break; |
136 | 0 | case 1: |
137 | 0 | addNumber(absl::get<double>(value)); |
138 | 0 | break; |
139 | 0 | case 2: |
140 | 0 | addNumber(absl::get<uint64_t>(value)); |
141 | 0 | break; |
142 | 0 | case 3: |
143 | 0 | addNumber(absl::get<int64_t>(value)); |
144 | 0 | break; |
145 | 0 | default: |
146 | 0 | IS_ENVOY_BUG(absl::StrCat("addValue invalid index: ", value.index())); |
147 | 0 | break; |
148 | 0 | } |
149 | 0 | } |
150 | | |
151 | 0 | void Streamer::Array::addEntries(const Entries& values) { |
152 | 0 | for (const Value& value : values) { |
153 | 0 | addValue(value); |
154 | 0 | } |
155 | 0 | } |
156 | | |
157 | 0 | void Streamer::addNumber(double number) { |
158 | 0 | if (std::isnan(number)) { |
159 | 0 | response_.addFragments({"null"}); |
160 | 0 | } else { |
161 | 0 | Buffer::Util::serializeDouble(number, response_); |
162 | 0 | } |
163 | 0 | } |
164 | | |
165 | 0 | void Streamer::addNumber(uint64_t number) { response_.addFragments({absl::StrCat(number)}); } |
166 | | |
167 | 0 | void Streamer::addNumber(int64_t number) { response_.addFragments({absl::StrCat(number)}); } |
168 | | |
169 | | void Streamer::addSanitized(absl::string_view prefix, absl::string_view str, |
170 | 0 | absl::string_view suffix) { |
171 | 0 | absl::string_view sanitized = Json::sanitize(sanitize_buffer_, str); |
172 | 0 | response_.addFragments({prefix, sanitized, suffix}); |
173 | 0 | } |
174 | | |
175 | | } // namespace Json |
176 | | } // namespace Envoy |