1 | JSON Encoder
|
---|
2 | ============
|
---|
3 |
|
---|
4 | Approach
|
---|
5 | --------
|
---|
6 |
|
---|
7 | The JSON encoder exists to support qlog implementation. There is no intention to
|
---|
8 | implement a decoder at this time. The encoder is intended to support automation
|
---|
9 | using immediate calls without the use of an intermediate syntax tree
|
---|
10 | representation and is expected to be zero-allocation in most cases. This enables
|
---|
11 | highly efficient serialization when called from QUIC code without dynamic memory
|
---|
12 | allocation.
|
---|
13 |
|
---|
14 | An example usage is as follows:
|
---|
15 |
|
---|
16 | ```c
|
---|
17 | int generate_json(BIO *b)
|
---|
18 | {
|
---|
19 | int ret = 1;
|
---|
20 | JSON_ENC z;
|
---|
21 |
|
---|
22 | if (!ossl_json_init(&z, b, 0))
|
---|
23 | return 0;
|
---|
24 |
|
---|
25 | ossl_json_object_begin(&z);
|
---|
26 | {
|
---|
27 | ossl_json_key(&z, "key");
|
---|
28 | ossl_json_str(&z, "value");
|
---|
29 |
|
---|
30 | ossl_json_key(&z, "key2");
|
---|
31 | ossl_json_u64(&z, 42);
|
---|
32 |
|
---|
33 | ossl_json_key(&z, "key3");
|
---|
34 | ossl_json_array_begin(&z);
|
---|
35 | {
|
---|
36 | ossl_json_null(&z);
|
---|
37 | ossl_json_f64(&z, 42.0);
|
---|
38 | ossl_json_str(&z, "string");
|
---|
39 | }
|
---|
40 | ossl_json_array_end(&z);
|
---|
41 | }
|
---|
42 | ossl_json_object_end(&z);
|
---|
43 |
|
---|
44 | if (ossl_json_get_error_flag(&z))
|
---|
45 | ret = 0;
|
---|
46 |
|
---|
47 | ossl_json_cleanup(&z);
|
---|
48 | return ret;
|
---|
49 | }
|
---|
50 | ```
|
---|
51 |
|
---|
52 | The zero-allocation, immediate-output design means that most API calls
|
---|
53 | correspond directly to immediately generated output; however there is some
|
---|
54 | minimal state tracking. The API guarantees that it will never generate invalid
|
---|
55 | JSON, with two exceptions:
|
---|
56 |
|
---|
57 | - it is the caller's responsibility to avoid generating duplicate keys;
|
---|
58 | - it is the caller's responsibility to provide valid UTF-8 strings.
|
---|
59 |
|
---|
60 | Since the JSON encoder is for internal use only, its structure is defined in
|
---|
61 | headers and can be incorporated into other objects without a heap allocation.
|
---|
62 | The JSON encoder maintains an internal write buffer and a small state tracking
|
---|
63 | stack (1 bit per level of depth in a JSON hierarchy).
|
---|
64 |
|
---|
65 | JSON-SEQ
|
---|
66 | --------
|
---|
67 |
|
---|
68 | The encoder supports JSON-SEQ (RFC 7464), as this is an optimal format for
|
---|
69 | outputting qlog for our purposes.
|
---|
70 |
|
---|
71 | Number Handling
|
---|
72 | ---------------
|
---|
73 |
|
---|
74 | It is an unfortunate reality that many JSON implementations are not able to
|
---|
75 | handle integers outside `[-2**53 + 1, 2**53 - 1]`. This leads to the I-JSON
|
---|
76 | specification, RFC 7493, which recommends that values outside these ranges are
|
---|
77 | encoded as strings.
|
---|
78 |
|
---|
79 | An optional I-JSON mode is offered, in which case integers outside these ranges
|
---|
80 | are automatically serialized as strings instead.
|
---|
81 |
|
---|
82 | Error Handling
|
---|
83 | --------------
|
---|
84 |
|
---|
85 | Error handling is deferred to improve ergonomics. If any call to a JSON encoder
|
---|
86 | fails, all future calls also fail and the caller is expected to ascertain that
|
---|
87 | the encoding process failed by calling `ossl_json_get_error_flag`.
|
---|
88 |
|
---|
89 | API
|
---|
90 | ---
|
---|
91 |
|
---|
92 | The API is documented in `include/internal/json_enc.h`.
|
---|