diff options
-rw-r--r-- | include/apr_json.h | 20 | ||||
-rw-r--r-- | jose/apr_jose_encode.c | 102 | ||||
-rw-r--r-- | json/apr_json.c | 52 | ||||
-rw-r--r-- | json/apr_json_decode.c | 2 |
4 files changed, 109 insertions, 67 deletions
diff --git a/include/apr_json.h b/include/apr_json.h index c05f6704c..55c4806b5 100644 --- a/include/apr_json.h +++ b/include/apr_json.h @@ -271,6 +271,22 @@ APR_DECLARE(apr_json_value_t *) /** * Associate a value with a key in a JSON object. * @param obj The JSON object. + * @param key Pointer to the key string. + * @param klen Length of the key, or APR_JSON_VALUE_STRING if NUL + * terminated. + * @param val Value to associate with the key. + * @param pool Pool to use. + * @return APR_SUCCESS on success, APR_EINVAL if the key is + * NULL or not a string, or the object is not an APR_JSON_OBJECT. + * @remark If the value is NULL the key value pair is deleted. + */ +APR_DECLARE(apr_status_t) apr_json_object_set(apr_json_value_t *obj, + const char *key, apr_ssize_t klen, apr_json_value_t *val, + apr_pool_t *pool) __attribute__((nonnull(1, 2, 5))); + +/** + * Associate a value with a key in a JSON object, preserving whitespace. + * @param obj The JSON object. * @param key Pointer to the key string, including any whitespace * required. * @param val Value to associate with the key. @@ -279,9 +295,9 @@ APR_DECLARE(apr_json_value_t *) * NULL or not a string, or the object is not an APR_JSON_OBJECT. * @remark If the value is NULL the key value pair is deleted. */ -APR_DECLARE(apr_status_t) apr_json_object_set(apr_json_value_t *obj, +APR_DECLARE(apr_status_t) apr_json_object_set_ex(apr_json_value_t *obj, apr_json_value_t *key, apr_json_value_t *val, - apr_pool_t *pool) __attribute__((nonnull(1, 4))); + apr_pool_t *pool) __attribute__((nonnull(1, 2, 4))); /** * Look up the value associated with a key in a JSON object. diff --git a/jose/apr_jose_encode.c b/jose/apr_jose_encode.c index 43a4adc8b..71088b8ca 100644 --- a/jose/apr_jose_encode.c +++ b/jose/apr_jose_encode.c @@ -263,7 +263,7 @@ static apr_status_t apr_jose_encode_json_jwe(apr_bucket_brigade *brigade, apr_pool_t *p) { - apr_json_value_t *json, *key, *val; + apr_json_value_t *json; char *buf; const char *buf64; apr_size_t len; @@ -300,10 +300,9 @@ static apr_status_t apr_jose_encode_json_jwe(apr_bucket_brigade *brigade, apr_brigade_cleanup(bb); - key = apr_json_string_create(p, "protected", - APR_JSON_VALUE_STRING); - val = apr_json_string_create(p, buf, len); - apr_json_object_set(json, key, val, p); + apr_json_object_set(json, "protected", + APR_JSON_VALUE_STRING, + apr_json_string_create(p, buf, len), p); } @@ -311,9 +310,8 @@ static apr_status_t apr_jose_encode_json_jwe(apr_bucket_brigade *brigade, if (e->unprotected) { - key = apr_json_string_create(p, "unprotected", - APR_JSON_VALUE_STRING); - apr_json_object_set(json, key, e->unprotected, p); + apr_json_object_set(json, "unprotected", + APR_JSON_VALUE_STRING, e->unprotected, p); } @@ -341,9 +339,8 @@ static apr_status_t apr_jose_encode_json_jwe(apr_bucket_brigade *brigade, /* create header */ - key = apr_json_string_create(p, "header", - APR_JSON_VALUE_STRING); - apr_json_object_set(json, key, recip->header, p); + apr_json_object_set(json, "header", + APR_JSON_VALUE_STRING, recip->header, p); apr_brigade_cleanup(bb); @@ -353,10 +350,9 @@ static apr_status_t apr_jose_encode_json_jwe(apr_bucket_brigade *brigade, recip->ekey.len, APR_ENCODE_BASE64URL, &len64); - key = apr_json_string_create(p, "encrypted_key", - APR_JSON_VALUE_STRING); - val = apr_json_string_create(p, buf64, len64); - apr_json_object_set(json, key, val, p); + apr_json_object_set(json, "encrypted_key", + APR_JSON_VALUE_STRING, + apr_json_string_create(p, buf64, len64), p); } @@ -368,10 +364,9 @@ static apr_status_t apr_jose_encode_json_jwe(apr_bucket_brigade *brigade, /* create recipients element */ - key = apr_json_string_create(p, "recipients", - APR_JSON_VALUE_STRING); recips = apr_json_array_create(p, jwe->recipients->nelts); - apr_json_object_set(json, key, recips, p); + apr_json_object_set(json, "recipients", + APR_JSON_VALUE_STRING, recips, p); /* populate each recipient */ @@ -405,9 +400,8 @@ static apr_status_t apr_jose_encode_json_jwe(apr_bucket_brigade *brigade, /* create header */ - key = apr_json_string_create(p, "header", - APR_JSON_VALUE_STRING); - apr_json_object_set(r, key, recip->header, p); + apr_json_object_set(r, "header", + APR_JSON_VALUE_STRING, recip->header, p); apr_brigade_cleanup(bb); @@ -417,10 +411,9 @@ static apr_status_t apr_jose_encode_json_jwe(apr_bucket_brigade *brigade, recip->ekey.len, APR_ENCODE_BASE64URL, &len64); - key = apr_json_string_create(p, "encrypted_key", - APR_JSON_VALUE_STRING); - val = apr_json_string_create(p, buf64, len64); - apr_json_object_set(r, key, val, p); + apr_json_object_set(r, "encrypted_key", + APR_JSON_VALUE_STRING, + apr_json_string_create(p, buf64, len64), p); } if (APR_SUCCESS != status) { @@ -436,9 +429,8 @@ static apr_status_t apr_jose_encode_json_jwe(apr_bucket_brigade *brigade, buf64 = apr_pencode_base64_binary(p, e->iv.data, e->iv.len, APR_ENCODE_BASE64URL, &len64); - key = apr_json_string_create(p, "iv", APR_JSON_VALUE_STRING); - val = apr_json_string_create(p, buf64, len64); - apr_json_object_set(json, key, val, p); + apr_json_object_set(json, "iv", APR_JSON_VALUE_STRING, + apr_json_string_create(p, buf64, len64), p); } /* create aad */ @@ -448,9 +440,8 @@ static apr_status_t apr_jose_encode_json_jwe(apr_bucket_brigade *brigade, buf64 = apr_pencode_base64_binary(p, e->aad.data, e->aad.len, APR_ENCODE_BASE64URL, &len64); - key = apr_json_string_create(p, "aad", APR_JSON_VALUE_STRING); - val = apr_json_string_create(p, buf64, len64); - apr_json_object_set(json, key, val, p); + apr_json_object_set(json, "aad", APR_JSON_VALUE_STRING, + apr_json_string_create(p, buf64, len64), p); } /* create ciphertext */ @@ -460,9 +451,8 @@ static apr_status_t apr_jose_encode_json_jwe(apr_bucket_brigade *brigade, buf64 = apr_pencode_base64_binary(p, e->cipher.data, e->cipher.len, APR_ENCODE_BASE64URL, &len64); - key = apr_json_string_create(p, "ciphertext", APR_JSON_VALUE_STRING); - val = apr_json_string_create(p, buf64, len64); - apr_json_object_set(json, key, val, p); + apr_json_object_set(json, "ciphertext", APR_JSON_VALUE_STRING, + apr_json_string_create(p, buf64, len64), p); } /* create tag */ @@ -472,9 +462,8 @@ static apr_status_t apr_jose_encode_json_jwe(apr_bucket_brigade *brigade, buf64 = apr_pencode_base64_binary(p, e->tag.data, e->tag.len, APR_ENCODE_BASE64URL, &len64); - key = apr_json_string_create(p, "tag", APR_JSON_VALUE_STRING); - val = apr_json_string_create(p, buf64, len64); - apr_json_object_set(json, key, val, p); + apr_json_object_set(json, "tag", APR_JSON_VALUE_STRING, + apr_json_string_create(p, buf64, len64), p); } } @@ -493,7 +482,7 @@ static apr_status_t apr_jose_encode_json_jws(apr_bucket_brigade *brigade, apr_brigade_flush flush, void *ctx, apr_jose_t *jose, apr_jose_cb_t *cb, apr_pool_t *p) { - apr_json_value_t *json, *key, *val; + apr_json_value_t *json; char *buf; const char *buf64; apr_size_t len; @@ -530,9 +519,8 @@ static apr_status_t apr_jose_encode_json_jws(apr_bucket_brigade *brigade, /* add the payload to our json */ - key = apr_json_string_create(p, "payload", APR_JSON_VALUE_STRING); - val = apr_json_string_create(p, buf64, len64); - apr_json_object_set(json, key, val, p); + apr_json_object_set(json, "payload", APR_JSON_VALUE_STRING, + apr_json_string_create(p, buf64, len64), p); /* calculate the flattened signature */ @@ -551,9 +539,8 @@ static apr_status_t apr_jose_encode_json_jws(apr_bucket_brigade *brigade, return status; } - key = apr_json_string_create(p, "protected", APR_JSON_VALUE_STRING); - val = apr_json_string_create(p, buf, len); - apr_json_object_set(json, key, val, p); + apr_json_object_set(json, "protected", APR_JSON_VALUE_STRING, + apr_json_string_create(p, buf, len), p); status = apr_brigade_write(bb, flush, ctx, ".", 1); if (APR_SUCCESS != status) { @@ -576,8 +563,8 @@ static apr_status_t apr_jose_encode_json_jws(apr_bucket_brigade *brigade, /* create header */ - key = apr_json_string_create(p, "header", APR_JSON_VALUE_STRING); - apr_json_object_set(json, key, jws->signature->header, p); + apr_json_object_set(json, "header", APR_JSON_VALUE_STRING, + jws->signature->header, p); apr_brigade_cleanup(bb); @@ -587,9 +574,8 @@ static apr_status_t apr_jose_encode_json_jws(apr_bucket_brigade *brigade, jws->signature->sig.data, jws->signature->sig.len, APR_ENCODE_BASE64URL, &len64); - key = apr_json_string_create(p, "signature", APR_JSON_VALUE_STRING); - val = apr_json_string_create(p, buf64, len64); - apr_json_object_set(json, key, val, p); + apr_json_object_set(json, "signature", APR_JSON_VALUE_STRING, + apr_json_string_create(p, buf64, len64), p); } @@ -602,9 +588,9 @@ static apr_status_t apr_jose_encode_json_jws(apr_bucket_brigade *brigade, /* create signatures element */ - key = apr_json_string_create(p, "signatures", APR_JSON_VALUE_STRING); sigs = apr_json_array_create(p, jws->signatures->nelts); - apr_json_object_set(json, key, sigs, p); + apr_json_object_set(json, "signatures", APR_JSON_VALUE_STRING, + sigs, p); /* populate each signature */ @@ -630,9 +616,8 @@ static apr_status_t apr_jose_encode_json_jws(apr_bucket_brigade *brigade, /* add protected header to array */ - key = apr_json_string_create(p, "protected", APR_JSON_VALUE_STRING); - val = apr_json_string_create(p, buf, len); - apr_json_object_set(s, key, val, p); + apr_json_object_set(s, "protected", APR_JSON_VALUE_STRING, + apr_json_string_create(p, buf, len), p); status = apr_brigade_write(bb, flush, ctx, ".", 1); if (APR_SUCCESS != status) { @@ -655,8 +640,8 @@ static apr_status_t apr_jose_encode_json_jws(apr_bucket_brigade *brigade, /* create header */ - key = apr_json_string_create(p, "header", APR_JSON_VALUE_STRING); - apr_json_object_set(s, key, sig->header, p); + apr_json_object_set(s, "header", APR_JSON_VALUE_STRING, + sig->header, p); apr_brigade_cleanup(bb); @@ -666,9 +651,8 @@ static apr_status_t apr_jose_encode_json_jws(apr_bucket_brigade *brigade, sig->sig.len, APR_ENCODE_BASE64URL, &len64); - key = apr_json_string_create(p, "signature", APR_JSON_VALUE_STRING); - val = apr_json_string_create(p, buf64, len64); - apr_json_object_set(s, key, val, p); + apr_json_object_set(s, "signature", APR_JSON_VALUE_STRING, + apr_json_string_create(p, buf64, len64), p); } if (APR_SUCCESS != status) { diff --git a/json/apr_json.c b/json/apr_json.c index ad4281cc2..4b5867fc0 100644 --- a/json/apr_json.c +++ b/json/apr_json.c @@ -129,13 +129,55 @@ apr_json_value_t *apr_json_null_create(apr_pool_t *pool) return json; } -apr_status_t apr_json_object_set(apr_json_value_t *object, apr_json_value_t *key, - apr_json_value_t *val, apr_pool_t *pool) +apr_status_t apr_json_object_set(apr_json_value_t *object, + const char *key, apr_ssize_t klen, apr_json_value_t *val, + apr_pool_t *pool) { apr_json_kv_t *kv; apr_hash_t *hash; - if (object->type != APR_JSON_OBJECT || !key + if (object->type != APR_JSON_OBJECT) { + return APR_EINVAL; + } + + if (klen == APR_JSON_VALUE_STRING) { + klen = strlen(key); + } + + hash = object->value.object->hash; + + kv = apr_hash_get(hash, key, klen); + + if (!val) { + if (kv) { + apr_hash_set(hash, key, klen, NULL); + APR_RING_REMOVE((kv), link); + } + return APR_SUCCESS; + } + + if (!kv) { + kv = apr_palloc(pool, sizeof(apr_json_kv_t)); + APR_RING_ELEM_INIT(kv, link); + APR_JSON_OBJECT_INSERT_TAIL(object->value.object, kv); + apr_hash_set(hash, key, klen, + kv); + } + + kv->k = apr_json_string_create(pool, key, klen); + kv->v = val; + + return APR_SUCCESS; +} + +apr_status_t apr_json_object_set_ex(apr_json_value_t *object, + apr_json_value_t *key, apr_json_value_t *val, + apr_pool_t *pool) +{ + apr_json_kv_t *kv; + apr_hash_t *hash; + + if (object->type != APR_JSON_OBJECT || key->type != APR_JSON_STRING) { return APR_EINVAL; } @@ -316,7 +358,7 @@ apr_json_value_t *apr_json_overlay(apr_pool_t *p, if (!apr_hash_get(overlay->value.object->hash, kv->k->value.string.p, kv->k->value.string.len)) { - apr_json_object_set(res, kv->k, kv->v, p); + apr_json_object_set_ex(res, kv->k, kv->v, p); } else if (APR_JSON_FLAGS_STRICT & flags) { @@ -329,7 +371,7 @@ apr_json_value_t *apr_json_overlay(apr_pool_t *p, kv != APR_RING_SENTINEL(&(overlay->value.object)->list, apr_json_kv_t, link); kv = APR_RING_NEXT((kv), link)) { - apr_json_object_set(res, kv->k, kv->v, p); + apr_json_object_set_ex(res, kv->k, kv->v, p); } diff --git a/json/apr_json_decode.c b/json/apr_json_decode.c index c790d6fdc..5ef2cb854 100644 --- a/json/apr_json_decode.c +++ b/json/apr_json_decode.c @@ -501,7 +501,7 @@ static apr_status_t apr_json_decode_object(apr_json_scanner_t * self, if ((status = apr_json_decode_value(self, &value))) goto out; - apr_json_object_set(json, key, value, self->pool); + apr_json_object_set_ex(json, key, value, self->pool); if (self->p == self->e) { status = APR_EOF; |