Home | History | Annotate | Line # | Download | only in quic-design
      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`.
     93