1
#pragma once
2

            
3
#include <memory>
4
#include <stack>
5
#include <string>
6
#include <type_traits>
7
#include <variant>
8

            
9
#include "envoy/buffer/buffer.h"
10

            
11
#include "source/common/buffer/buffer_util.h"
12
#include "source/common/json/constants.h"
13
#include "source/common/json/json_sanitizer.h"
14

            
15
#include "absl/strings/string_view.h"
16
#include "absl/types/variant.h"
17

            
18
namespace Envoy {
19
namespace Json {
20

            
21
// To ensure the streamer is being used correctly, we use assertions to enforce
22
// that only the topmost map/array in the stack is being written to. To make
23
// this easier to do from the Level classes, we provider Streamer::topLevel() as
24
// a member function, but this is only needed when compiled for debug.
25
//
26
// We only compile Streamer::topLevel in debug to avoid having it be a coverage
27
// gap. However, assertions fail to compile in release mode if they reference
28
// non-existent functions or member variables, so we only compile the assertions
29
// in debug mode.
30
#ifdef NDEBUG
31
#define ASSERT_THIS_IS_TOP_LEVEL                                                                   \
32
12763
  do {                                                                                             \
33
12763
  } while (0)
34
#define ASSERT_LEVELS_EMPTY                                                                        \
35
168
  do {                                                                                             \
36
168
  } while (0)
37
#else
38
#define ASSERT_THIS_IS_TOP_LEVEL ASSERT(this->streamer_.topLevel() == this)
39
#define ASSERT_LEVELS_EMPTY ASSERT(this->levels_.empty())
40
#endif
41

            
42
// Buffer wrapper that implements the necessary abstraction for the template
43
// StreamerBase.
44
// This could be used to stream JSON output of StreamerBase to a Buffer.
45
class BufferOutput {
46
public:
47
12276
  void add(absl::string_view a) { buffer_.addFragments({a}); }
48
6107
  void add(absl::string_view a, absl::string_view b, absl::string_view c) {
49
6107
    buffer_.addFragments({a, b, c});
50
6107
  }
51

            
52
63
  explicit BufferOutput(Buffer::Instance& output) : buffer_(output) {}
53
  Buffer::Instance& buffer_;
54
};
55

            
56
// String wrapper that implements the necessary abstraction for the template
57
// StreamerBase.
58
// This could be used to stream JSON output of StreamerBase to a single string.
59
class StringOutput {
60
public:
61
3872
  void add(absl::string_view a) { buffer_.append(a); }
62
2481
  void add(absl::string_view a, absl::string_view b, absl::string_view c) {
63
2481
    absl::StrAppend(&buffer_, a, b, c);
64
2481
  }
65
1116
  explicit StringOutput(std::string& output) : buffer_(output) {}
66

            
67
  std::string& buffer_;
68
};
69

            
70
/**
71
 * Provides an API for streaming JSON output, as an alternative to populating a
72
 * JSON structure with an image of what you want to serialize, or using a
73
 * protobuf with reflection. The advantage of this approach is that it does not
74
 * require building an intermediate data structure with redundant copies of all
75
 * strings, maps, and arrays.
76
 *
77
 * NOTE: This template take a type that can be used to stream output. This is either
78
 * BufferOutput, StringOutput or any other types that have implemented
79
 * add(absl::string_view) and
80
 * add(absl::string_view, absl::string_view, absl::string_view) methods.
81
 */
82
template <class OutputBufferType> class StreamerBase {
83
public:
84
  using Value = absl::variant<absl::string_view, double, uint64_t, int64_t, bool, absl::monostate>;
85

            
86
  /**
87
   * @param response The buffer in which to stream output.
88
   * NOTE: The response must could be used to construct instance of OutputBufferType.
89
   */
90
1024
  template <class T> explicit StreamerBase(T& response) : response_(response) {}
91

            
92
  class Array;
93
  using ArrayPtr = std::unique_ptr<Array>;
94
  class Map;
95
  using MapPtr = std::unique_ptr<Map>;
96

            
97
  /**
98
   * Represents the current map or array. We keep track of what character is
99
   * needed to close it, and whether or not the first entry has been added.
100
   */
101
  class Level {
102
  public:
103
    Level(StreamerBase& streamer, absl::string_view opener, absl::string_view closer)
104
2605
        : streamer_(streamer), closer_(closer) {
105
2605
      streamer_.addWithoutSanitizing(opener);
106
#ifndef NDEBUG
107
      streamer_.push(this);
108
#endif
109
2605
    }
110
2605
    virtual ~Level() {
111
2605
      streamer_.addWithoutSanitizing(closer_);
112
#ifndef NDEBUG
113
      streamer_.pop(this);
114
#endif
115
2605
    }
116

            
117
    /**
118
     * This must be called on the top level map or array. It's a programming
119
     * error to call this method on a map that's not the top level.
120
     * It's also a programming error to call this on map that isn't expecting
121
     * a value. You must call Map::addKey prior to calling this.
122
     *
123
     * @return a newly created subordinate map, which becomes the new top level until destroyed.
124
     */
125
2270
    MapPtr addMap() {
126
2270
      ASSERT_THIS_IS_TOP_LEVEL;
127
2270
      nextField();
128
2270
      return std::make_unique<Map>(streamer_);
129
2270
    }
130

            
131
    /**
132
     * This must be called on the top level map or array. It's a programming
133
     * error to call this method on a map or array that's not the top level.
134
     * It's also a programming error to call this on map that isn't expecting
135
     * a value. You must call Map::addKey prior to calling this.
136
     *
137
     * @return a newly created subordinate array, which becomes the new top level until destroyed.
138
     */
139
167
    ArrayPtr addArray() {
140
167
      ASSERT_THIS_IS_TOP_LEVEL;
141
167
      nextField();
142
167
      return std::make_unique<Array>(streamer_);
143
167
    }
144

            
145
    /**
146
     * Adds a numeric value to the current array or map. It's a programming
147
     * error to call this method on a map or array that's not the top level.
148
     * It's also a programming error to call this on map that isn't expecting
149
     * a value. You must call Map::addKey prior to calling this.
150
     */
151
1699
    void addNumber(double number) {
152
1699
      ASSERT_THIS_IS_TOP_LEVEL;
153
1699
      nextField();
154
1699
      streamer_.addNumber(number);
155
1699
    }
156
1612
    void addNumber(uint64_t number) {
157
1612
      ASSERT_THIS_IS_TOP_LEVEL;
158
1612
      nextField();
159
1612
      streamer_.addNumber(number);
160
1612
    }
161
13
    void addNumber(int64_t number) {
162
13
      ASSERT_THIS_IS_TOP_LEVEL;
163
13
      nextField();
164
13
      streamer_.addNumber(number);
165
13
    }
166

            
167
    /**
168
     * Adds a string constant value to the current array or map. The string
169
     * will be sanitized per JSON rules.
170
     *
171
     * It's a programming error to call this method on a map or array that's not
172
     * the top level. It's also a programming error to call this on map that
173
     * isn't expecting a value. You must call Map::addKey prior to calling this.
174
     */
175
1747
    void addString(absl::string_view str) {
176
1747
      ASSERT_THIS_IS_TOP_LEVEL;
177
1747
      nextField();
178
1747
      streamer_.addString(str);
179
1747
    }
180

            
181
    /**
182
     * Adds a bool constant value to the current array or map. It's a programming
183
     * error to call this method on a map or array that's not the top level.
184
     * It's also a programming error to call this on map that isn't expecting
185
     * a value. You must call Map::addKey prior to calling this.
186
     */
187
59
    void addBool(bool b) {
188
59
      ASSERT_THIS_IS_TOP_LEVEL;
189
59
      nextField();
190
59
      streamer_.addBool(b);
191
59
    }
192

            
193
    /**
194
     * Adds a null constant value to the current array or map. It's a programming
195
     * error to call this method on a map or array that's not the top level.
196
     * It's also a programming error to call this on map that isn't expecting
197
     * a value. You must call Map::addKey prior to calling this.
198
     */
199
2
    void addNull() {
200
2
      ASSERT_THIS_IS_TOP_LEVEL;
201
2
      nextField();
202
2
      streamer_.addNull();
203
2
    }
204

            
205
    /**
206
     * Adds a pre-serialized JSON fragment to the current array or map.
207
     * The fragment is inserted as-is without any escaping or validation.
208
     * The caller is responsible for ensuring the fragment is valid JSON.
209
     *
210
     * Use case: embedding JSON objects/arrays from external sources
211
     * (e.g., parsed JSON that was serialized via asJsonString()).
212
     *
213
     * It's a programming error to call this method on a map or array that's not
214
     * the top level. It's also a programming error to call this on map that
215
     * isn't expecting a value. You must call Map::addKey prior to calling this.
216
     */
217
6
    void addRawJson(absl::string_view json) {
218
6
      ASSERT_THIS_IS_TOP_LEVEL;
219
6
      nextField();
220
6
      streamer_.addWithoutSanitizing(json);
221
6
    }
222

            
223
  protected:
224
    /**
225
     * Initiates a new field, serializing a comma separator if this is not the
226
     * first one.
227
     */
228
7575
    virtual void nextField() {
229
7575
      if (is_first_) {
230
2598
        is_first_ = false;
231
5006
      } else {
232
4977
        streamer_.addWithoutSanitizing(",");
233
4977
      }
234
7575
    }
235

            
236
    /**
237
     * Renders a string or a number in json format. Doubles that are NaN are
238
     * rendered as 'null'. Strings are json-sanitized if needed, and surrounded
239
     * by quotes.
240
     *
241
     * @param Value the value to render.
242
     */
243
4544
    void addValue(const Value& value) {
244
4544
      static_assert(absl::variant_size_v<Value> == 6, "Value must be a variant with 6 types");
245

            
246
4544
      switch (value.index()) {
247
1556
      case 0:
248
1556
        static_assert(std::is_same_v<absl::variant_alternative_t<0, Value>, absl::string_view>,
249
1556
                      "value at index 0 must be an absl::string_vlew");
250
1556
        addString(absl::get<absl::string_view>(value));
251
1556
        break;
252
1356
      case 1:
253
1356
        static_assert(std::is_same_v<absl::variant_alternative_t<1, Value>, double>,
254
1356
                      "value at index 1 must be a double");
255
1356
        addNumber(absl::get<double>(value));
256
1356
        break;
257
1612
      case 2:
258
1612
        static_assert(std::is_same_v<absl::variant_alternative_t<2, Value>, uint64_t>,
259
1612
                      "value at index 2 must be a uint64_t");
260
1612
        addNumber(absl::get<uint64_t>(value));
261
1612
        break;
262
4
      case 3:
263
4
        static_assert(std::is_same_v<absl::variant_alternative_t<3, Value>, int64_t>,
264
4
                      "value at index 3 must be an int64_t");
265
4
        addNumber(absl::get<int64_t>(value));
266
4
        break;
267
14
      case 4:
268
14
        static_assert(std::is_same_v<absl::variant_alternative_t<4, Value>, bool>,
269
14
                      "value at index 4 must be a bool");
270
14
        addBool(absl::get<bool>(value));
271
14
        break;
272
2
      case 5:
273
2
        static_assert(std::is_same_v<absl::variant_alternative_t<5, Value>, absl::monostate>,
274
2
                      "value at index 5 must be an absl::monostate");
275
2
        addNull();
276
2
        break;
277
4544
      }
278
4544
    }
279

            
280
  protected:
281
    bool is_first_{true}; // Used to control whether a comma-separator is added for a new entry.
282
    StreamerBase& streamer_;
283
    absl::string_view closer_;
284
  };
285
  using LevelPtr = std::unique_ptr<Level>;
286

            
287
  /**
288
   * Represents a JSON map while it is being serialized. No data is buffered
289
   * in the structure; just enough state to be able emit delimiters properly.
290
   */
291
  class Map : public Level {
292
  public:
293
    using NameValue = std::pair<const absl::string_view, Value>;
294
    using Entries = absl::Span<const NameValue>;
295

            
296
2431
    Map(StreamerBase& streamer) : Level(streamer, "{", "}") {}
297

            
298
    /**
299
     * Initiates a new map key. This must be followed by rendering a value,
300
     * sub-array, or sub-map. It is a programming error to delete a map that has
301
     * rendered a key without a matching value. It's also a programming error to
302
     * call this method on a map that's not the current top level.
303
     *
304
     * See also addEntries, which directly populates a list of name/value
305
     * pairs in a single call.
306
     */
307
5188
    void addKey(absl::string_view key) {
308
5188
      ASSERT_THIS_IS_TOP_LEVEL;
309
5188
      ASSERT(!expecting_value_);
310
5188
      nextField();
311
5188
      this->streamer_.addSanitized("\"", key, "\":");
312
5188
      expecting_value_ = true;
313
5188
    }
314

            
315
    /**
316
     * Populates a list of name/value pairs in a single call. This function
317
     * makes it easy to populate structures with scalar values. It's a
318
     * programming error to call this method on a map that's not the current top
319
     * level.
320
     */
321
2196
    void addEntries(const Entries& entries) {
322
4398
      for (const NameValue& entry : entries) {
323
4398
        addKey(entry.first);
324
4398
        this->addValue(entry.second);
325
4398
      }
326
2196
    }
327

            
328
  protected:
329
10376
    void nextField() override {
330
10376
      if (expecting_value_) {
331
5188
        expecting_value_ = false;
332
5188
      } else {
333
5188
        Level::nextField();
334
5188
      }
335
10376
    }
336

            
337
  private:
338
    bool expecting_value_{false};
339
  };
340

            
341
  /**
342
   * Represents a JSON array while it is being serialized. No data is buffered
343
   * in the structure; just enough state to be able emit delimiters properly.
344
   */
345
  class Array : public Level {
346
  public:
347
174
    Array(StreamerBase& streamer) : Level(streamer, "[", "]") {}
348
    using Entries = absl::Span<const Value>;
349

            
350
    /**
351
     * Adds values to an array. The values may be numeric or strings; strings
352
     * will be escaped if needed. It's a programming error to call this method
353
     * on an array that's not the current top level.
354
     *
355
     * @param entries the array of numeric or string values.
356
     */
357
16
    void addEntries(const Entries& entries) {
358
146
      for (const Value& value : entries) {
359
146
        this->addValue(value);
360
146
      }
361
16
    }
362
  };
363

            
364
  /**
365
   * Makes a root map for the streamer.
366
   *
367
   * You must create a root map or array before any of the JSON population
368
   * functions can be called, as those are only available on Map and Array
369
   * objects.
370
   */
371
161
  MapPtr makeRootMap() {
372
161
    ASSERT_LEVELS_EMPTY;
373
161
    return std::make_unique<Map>(*this);
374
161
  }
375

            
376
  /**
377
   * Makes a root array for the streamer.
378
   *
379
   * You must create a root map or array before any of the JSON population
380
   * functions can be called, as those are only available on Map and Array
381
   * objects.
382
   */
383
7
  ArrayPtr makeRootArray() {
384
7
    ASSERT_LEVELS_EMPTY;
385
7
    return std::make_unique<Array>(*this);
386
7
  }
387

            
388
  /**
389
   * Takes a raw string, sanitizes it using JSON syntax, surrounds it
390
   * with a prefix and suffix, and streams it out.
391
   */
392
7457
  void addSanitized(absl::string_view prefix, absl::string_view token, absl::string_view suffix) {
393
7457
    absl::string_view sanitized = Json::sanitize(sanitize_buffer_, token);
394
7457
    response_.add(prefix, sanitized, suffix);
395
7457
  }
396

            
397
  /**
398
   * Serializes a string to the output stream. The input string value will be sanitized and
399
   * surrounded by quotes.
400
   * @param str the string to be serialized.
401
   */
402
2269
  void addString(absl::string_view str) { addSanitized("\"", str, "\""); }
403

            
404
  /**
405
   * Serializes a number.
406
   */
407
1770
  void addNumber(double d) {
408
1770
    if (std::isnan(d)) {
409
935
      response_.add(Constants::Null);
410
1645
    } else {
411
835
      Buffer::Util::serializeDouble(d, response_);
412
835
    }
413
1770
  }
414
  /**
415
   * Serializes a integer number.
416
   * NOTE: All numbers in JSON is float. When loading output of this serializer, the parser's
417
   * implementation decides if the full precision of big integer could be preserved or not.
418
   * See discussion here https://stackoverflow.com/questions/13502398/json-integers-limit-on-size
419
   * and spec https://www.rfc-editor.org/rfc/rfc7159#section-6 for more details.
420
   */
421
1614
  void addNumber(uint64_t u) { response_.add(absl::StrCat(u)); }
422
13
  void addNumber(int64_t i) { response_.add(absl::StrCat(i)); }
423

            
424
  /**
425
   * Serializes a bool to the output stream.
426
   */
427
66
  void addBool(bool b) { response_.add(b ? Constants::True : Constants::False); }
428

            
429
  /**
430
   * Serializes a null to the output stream.
431
   */
432
265
  void addNull() { response_.add(Constants::Null); }
433

            
434
private:
435
  /**
436
   * Adds a string to the output stream without sanitizing it.
437
   */
438
10193
  void addWithoutSanitizing(absl::string_view str) { response_.add(str); }
439

            
440
#ifndef NDEBUG
441
  /**
442
   * @return the top Level*. This is used for asserts.
443
   */
444
  Level* topLevel() const { return levels_.top(); }
445

            
446
  /**
447
   * Pushes a new level onto the stack.
448
   */
449
  void push(Level* level) { levels_.push(level); }
450

            
451
  /**
452
   * Pops a level off of a stack, asserting that it matches.
453
   */
454
  void pop(Level* level) {
455
    ASSERT(levels_.top() == level);
456
    levels_.pop();
457
  }
458

            
459
#endif
460

            
461
  OutputBufferType response_;
462
  std::string sanitize_buffer_;
463

            
464
#ifndef NDEBUG
465
  // Keeps a stack of Maps or Arrays (subclasses of Level) to facilitate
466
  // assertions that only the top-level map/array can be written.
467
  std::stack<Level*> levels_;
468
#endif
469
};
470

            
471
/**
472
 * A Streamer that streams to a Buffer::Instance.
473
 */
474
using BufferStreamer = StreamerBase<BufferOutput>;
475

            
476
/**
477
 * A Streamer that streams to a string.
478
 */
479
using StringStreamer = StreamerBase<StringOutput>;
480

            
481
} // namespace Json
482
} // namespace Envoy