| JSON Encoder |
| ============ |
| |
| Approach |
| -------- |
| |
| The JSON encoder exists to support qlog implementation. There is no intention to |
| implement a decoder at this time. The encoder is intended to support automation |
| using immediate calls without the use of an intermediate syntax tree |
| representation and is expected to be zero-allocation in most cases. This enables |
| highly efficient serialization when called from QUIC code without dynamic memory |
| allocation. |
| |
| An example usage is as follows: |
| |
| ```c |
| int generate_json(BIO *b) |
| { |
| int ret = 1; |
| JSON_ENC z; |
| |
| if (!ossl_json_init(&z, b, 0)) |
| return 0; |
| |
| ossl_json_object_begin(&z); |
| { |
| ossl_json_key(&z, "key"); |
| ossl_json_str(&z, "value"); |
| |
| ossl_json_key(&z, "key2"); |
| ossl_json_u64(&z, 42); |
| |
| ossl_json_key(&z, "key3"); |
| ossl_json_array_begin(&z); |
| { |
| ossl_json_null(&z); |
| ossl_json_f64(&z, 42.0); |
| ossl_json_str(&z, "string"); |
| } |
| ossl_json_array_end(&z); |
| } |
| ossl_json_object_end(&z); |
| |
| if (ossl_json_get_error_flag(&z)) |
| ret = 0; |
| |
| ossl_json_cleanup(&z); |
| return ret; |
| } |
| ``` |
| |
| The zero-allocation, immediate-output design means that most API calls |
| correspond directly to immediately generated output; however there is some |
| minimal state tracking. The API guarantees that it will never generate invalid |
| JSON, with two exceptions: |
| |
| - it is the caller's responsibility to avoid generating duplicate keys; |
| - it is the caller's responsibility to provide valid UTF-8 strings. |
| |
| Since the JSON encoder is for internal use only, its structure is defined in |
| headers and can be incorporated into other objects without a heap allocation. |
| The JSON encoder maintains an internal write buffer and a small state tracking |
| stack (1 bit per level of depth in a JSON hierarchy). |
| |
| JSON-SEQ |
| -------- |
| |
| The encoder supports JSON-SEQ (RFC 7464), as this is an optimal format for |
| outputting qlog for our purposes. |
| |
| Number Handling |
| --------------- |
| |
| It is an unfortunate reality that many JSON implementations are not able to |
| handle integers outside `[-2**53 + 1, 2**53 - 1]`. This leads to the I-JSON |
| specification, RFC 7493, which recommends that values outside these ranges are |
| encoded as strings. |
| |
| An optional I-JSON mode is offered, in which case integers outside these ranges |
| are automatically serialized as strings instead. |
| |
| Error Handling |
| -------------- |
| |
| Error handling is deferred to improve ergonomics. If any call to a JSON encoder |
| fails, all future calls also fail and the caller is expected to ascertain that |
| the encoding process failed by calling `ossl_json_get_error_flag`. |
| |
| API |
| --- |
| |
| The API is documented in `include/internal/json_enc.h`. |