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