openssl/doc/designs/quic-design/json-encoder.md
Hugo Landau de60b122b2 QLOG: Editorial fixes (QLOG is spelled 'qlog')
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Neil Horman <nhorman@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/22037)
2024-02-02 11:50:29 +00:00

2.6 KiB

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:

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.