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