[rs-commit] r49 - in /redwax-tool/trunk: redwax-tool.c redwax-tool.h redwax_openssl.c redwax_p11kit.c redwax_util.c redwax_util.h
rs-commit at redwax.eu
rs-commit at redwax.eu
Mon Nov 22 00:06:13 CET 2021
Author: minfrin at redwax.eu
Date: Mon Nov 22 00:06:12 2021
New Revision: 49
Log:
Add --metadata-out to print certificate metadata, and
--format-out to specify what format the metadata should
be in.
Modified:
redwax-tool/trunk/redwax-tool.c
redwax-tool/trunk/redwax-tool.h
redwax-tool/trunk/redwax_openssl.c
redwax-tool/trunk/redwax_p11kit.c
redwax-tool/trunk/redwax_util.c
redwax-tool/trunk/redwax_util.h
Modified: redwax-tool/trunk/redwax-tool.c
==============================================================================
--- redwax-tool/trunk/redwax-tool.c (original)
+++ redwax-tool/trunk/redwax-tool.c Mon Nov 22 00:06:12 2021
@@ -65,6 +65,9 @@
APR_HOOK_LINK(process_pkcs11_out);
APR_HOOK_LINK(complete_pkcs11_module_out);
APR_HOOK_LINK(process_pkcs11_module_out);
+ APR_HOOK_LINK(process_metadata_out);
+ APR_HOOK_LINK(complete_format_out);
+ APR_HOOK_LINK(set_format_out);
APR_HOOK_LINK(search_chain);
APR_HOOK_LINK(search_key);
APR_HOOK_LINK(compare_certificate);
@@ -109,6 +112,12 @@
(redwax_tool_t * r, const char *arg), (r, arg), DECLINED);
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(rt, REDWAX, int, complete_pkcs11_module_out,
(redwax_tool_t * r, const char *mod, redwax_token_quoted_e quoted), (r, mod, quoted), DECLINED);
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(rt, REDWAX, int, process_metadata_out,
+ (redwax_tool_t * r, const char *arg), (r, arg), DECLINED);
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(rt, REDWAX, int, set_format_out,
+ (redwax_tool_t * r, const char *arg), (r, arg), DECLINED);
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(rt, REDWAX, int, complete_format_out,
+ (redwax_tool_t * r, apr_hash_t *formats), (r, formats), DECLINED);
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(rt, REDWAX, apr_status_t, search_chain,
(redwax_tool_t * r, const redwax_certificate_t *cert), (r, cert), DECLINED);
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(rt, REDWAX, apr_status_t, search_key,
@@ -163,6 +172,8 @@
#define REDWAX_TOOL_PKCS12_OUT 289
#define REDWAX_TOOL_PKCS11_OUT 290
#define REDWAX_TOOL_PKCS11_MODULE_OUT 291
+#define REDWAX_TOOL_METADATA_OUT 292
+#define REDWAX_TOOL_FORMAT_OUT 293
#define REDWAX_EXIT_OK 0
#define REDWAX_EXIT_INIT 1
@@ -239,6 +250,8 @@
{ "pkcs12-out", REDWAX_TOOL_PKCS12_OUT, 1, " --pkcs12-out=file\t\tWrite certificates, intermediate certificates,\n\t\t\t\troot certificates, crls, and keys into a PKCS12\n\t\t\t\tfile. Use '-' for stdout." },
{ "pkcs11-out", REDWAX_TOOL_PKCS11_OUT, 1, " --pkcs11-out=url\t\tWrite certificates, intermediate certificates,\n\t\t\t\troot certificates, crls, and keys into a PKCS11\n\t\t\t\ttoken identified by the given url." },
{ "pkcs11-module-out", REDWAX_TOOL_PKCS11_MODULE_OUT, 1, " --pkcs11-module-out=mod\tSpecify the name of the PKCS11 module to be used,\n\t\t\t\toverriding system defaults. If relative, use the\n\t\t\t\tdefault PKCS11 module path, otherwise specify the\n\t\t\t\tabsolute path. Include the extension of the module." },
+ { "metadata-out", REDWAX_TOOL_METADATA_OUT, 1, " --metadata-out=file\t\tWrite metadata of each certificate and key to the\n\t\t\t\tgiven file in the format given by the format\n\t\t\t\tparameter." },
+ { "format-out", REDWAX_TOOL_FORMAT_OUT, 1, " --format-out=xml|json\t\tFormat of output metadata." },
{ NULL }
};
@@ -1500,6 +1513,31 @@
return APR_SUCCESS;
}
+static apr_status_t redwax_complete_format_out(redwax_tool_t *r, const char *arg,
+ redwax_token_quoted_e quoted)
+{
+ apr_hash_t *formats = apr_hash_make(r->pool);
+
+ apr_hash_index_t *hi;
+ void *val;
+ int arglen = strlen(arg);
+
+ rt_run_complete_format_out(r, formats);
+
+ for (hi = apr_hash_first(r->pool, formats); hi; hi = apr_hash_next(hi)) {
+ apr_hash_this(hi, NULL, NULL, &val);
+
+ if (!strncmp(arg, (const char *)val, arglen)) {
+
+ apr_file_printf(r->out, "%s \n",
+ redwax_pescape_echo_quoted(r->pool,
+ (const char *)val, quoted, 1));
+ }
+ }
+
+ return APR_SUCCESS;
+}
+
apr_status_t redwax_file_out(redwax_tool_t *r, const char *path,
apr_status_t (out)(redwax_tool_t *r, const char *path, const char *secret))
{
@@ -1942,6 +1980,22 @@
return APR_SUCCESS;
}
+static apr_status_t redwax_metadata_out(redwax_tool_t *r, const char *arg)
+{
+
+ apr_status_t status = rt_run_process_metadata_out(r, arg);
+
+ return status;
+}
+
+static apr_status_t redwax_format_out(redwax_tool_t *r, const char *arg)
+{
+
+ apr_status_t status = rt_run_set_format_out(r, arg);
+
+ return status;
+}
+
void redwax_add_default_hooks()
{
rt_hook_complete_filter(redwax_complete_filter_passthrough, NULL, NULL, APR_HOOK_MIDDLE);
@@ -2179,6 +2233,14 @@
redwax_pkcs11_module_out(r, optarg);
break;
}
+ case REDWAX_TOOL_METADATA_OUT: {
+ redwax_metadata_out(r, optarg);
+ break;
+ }
+ case REDWAX_TOOL_FORMAT_OUT: {
+ redwax_format_out(r, optarg);
+ break;
+ }
}
}
@@ -2306,6 +2368,14 @@
}
case REDWAX_TOOL_SECRET_TOKEN_OUT: {
redwax_complete_file(r, optarg, state.isquoted);
+ break;
+ }
+ case REDWAX_TOOL_METADATA_OUT: {
+ redwax_complete_file(r, optarg, state.isquoted);
+ break;
+ }
+ case REDWAX_TOOL_FORMAT_OUT: {
+ redwax_complete_format_out(r, optarg, state.isquoted);
break;
}
}
@@ -2492,6 +2562,14 @@
redwax_complete_file(r, "", state.isquoted);
break;
}
+ case REDWAX_TOOL_METADATA_OUT: {
+ redwax_complete_file(r, "", state.isquoted);
+ break;
+ }
+ case REDWAX_TOOL_FORMAT_OUT: {
+ redwax_complete_format_out(r, "", state.isquoted);
+ break;
+ }
}
break;
@@ -2578,6 +2656,7 @@
apr_file_open_stdin(&r.in, r.pool);
apr_file_open_stdout(&r.out, r.pool);
+ r.format = REDWAX_FORMAT_JSON;
r.key_in = 1;
r.certs_in = apr_array_make(r.pool, 10, sizeof(redwax_certificate_t));
Modified: redwax-tool/trunk/redwax-tool.h
==============================================================================
--- redwax-tool/trunk/redwax-tool.h (original)
+++ redwax-tool/trunk/redwax-tool.h Mon Nov 22 00:06:12 2021
@@ -41,6 +41,13 @@
const char *token;
int needs_write;
} redwax_pkcs11_t;
+
+typedef enum redwax_format_e {
+ REDWAX_FORMAT_TEXT = 0,
+ REDWAX_FORMAT_XML,
+ REDWAX_FORMAT_JSON,
+ REDWAX_FORMAT_YAML,
+} redwax_format_e;
typedef struct redwax_tool_t {
apr_pool_t *pool;
@@ -79,6 +86,7 @@
redwax_pkcs11_t pkcs11_in;
redwax_pkcs11_t pkcs11_out;
apr_time_t *now;
+ redwax_format_e format;
int top;
int cert_out;
int chain_out;
@@ -137,6 +145,7 @@
const char *header;
const unsigned char *der;
apr_size_t len;
+ const char *origin;
const char *name;
void *ctx;
redwax_certificate_common_t common;
@@ -151,6 +160,7 @@
const char *header;
const unsigned char *der;
apr_size_t len;
+ const char *origin;
void *ctx;
} redwax_crl_t;
@@ -198,6 +208,7 @@
const char *header;
const unsigned char *der;
apr_size_t len;
+ const char *origin;
const char *name;
void *ctx;
redwax_key_common_t common;
@@ -445,6 +456,30 @@
(redwax_tool_t *r, const char *arg));
/**
+ * Hook to handle the output of metadata.
+ *
+ * @param r The redwax-tool context.
+ */
+APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, process_metadata_out,
+ (redwax_tool_t *r, const char *arg));
+
+/**
+ * Hook to complete the metadata format.
+ *
+ * @param r The redwax-tool context.
+ */
+APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, complete_format_out,
+ (redwax_tool_t *r, apr_hash_t *formats));
+
+/**
+ * Hook to set the metadata format.
+ *
+ * @param r The redwax-tool context.
+ */
+APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, set_format_out,
+ (redwax_tool_t *r, const char *arg));
+
+/**
* Hook to complete verification parameters.
*
* @param r The redwax-tool context.
Modified: redwax-tool/trunk/redwax_openssl.c
==============================================================================
--- redwax-tool/trunk/redwax_openssl.c (original)
+++ redwax-tool/trunk/redwax_openssl.c Mon Nov 22 00:06:12 2021
@@ -26,6 +26,8 @@
#include "config.h"
#include "redwax-tool.h"
+
+#include "redwax_util.h"
#if HAVE_OPENSSL_PEM_H
@@ -906,6 +908,8 @@
cert->der = data;
cert->len = len;
+ cert->origin = file;
+
rt_run_normalise_certificate(r, cert, 1);
}
@@ -940,6 +944,8 @@
cert->len = i2d_X509(x, &der);
cert->der = der;
+ cert->origin = file;
+
rt_run_normalise_certificate(r, cert, 1);
redwax_print_error(r, "pem-in: trusted: %s\n",
@@ -969,6 +975,8 @@
crl->header = header;
crl->der = data;
crl->len = len;
+
+ crl->origin = file;
// X509_CRL_free(c);
}
@@ -1075,6 +1083,8 @@
key->header = header;
key->len = BIO_get_mem_data(kbio, &key->der);
+
+ key->origin = file;
rt_run_normalise_key(r, key, 1);
@@ -2074,6 +2084,191 @@
}
return APR_SUCCESS;
+}
+
+apr_status_t redwax_openssl_writev(void *ctx, const struct iovec *vec,
+ apr_size_t nvec)
+{
+ apr_size_t nbytes;
+
+ return apr_file_writev(ctx, vec, nvec, &nbytes);
+}
+
+static apr_status_t redwax_openssl_process_metadata_out(redwax_tool_t *r,
+ const char *file)
+{
+// X509 *x = NULL;
+
+ redwax_metadata_t *m;
+
+// EVP_PKEY *pkey = NULL;
+
+ apr_file_t *out;
+ int i;
+ apr_status_t status;
+
+ if (!strcmp(file, "-")) {
+ out = r->out;
+ }
+ else {
+ status = apr_file_open(&out, file, APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE,
+ APR_FPROT_OS_DEFAULT, r->pool);
+ if (APR_SUCCESS != status) {
+ return status;
+ }
+
+ }
+
+ redwax_metadata_push_root(r->pool, "Vault", redwax_openssl_writev, out, r->format, &m);
+
+ if (r->cert_out) {
+
+ redwax_metadata_push_array(m, "Certificates", !r->certs_out->nelts);
+
+ for (i = 0; i < r->certs_out->nelts; i++)
+ {
+ const redwax_certificate_t *cert = &APR_ARRAY_IDX(r->certs_out,
+ i, const redwax_certificate_t);
+
+
+#if 0
+ const unsigned char *der = cert->der;
+
+ X509 *xi = d2i_X509(NULL, &der, cert->len);
+
+ if (!xi) {
+ redwax_openssl_print_errors(r);
+ X509_free(x);
+ return APR_ENOENT;
+ }
+#endif
+
+ redwax_print_error(r, "metadata-out: certificate: %s\n",
+ cert->common.subject);
+
+ redwax_metadata_push_object(m, "Certificate", 0);
+ redwax_metadata_add_string(m, "Origin", cert->origin);
+ redwax_metadata_pop_object(m);
+
+ }
+
+ redwax_metadata_pop_array(m);
+
+ }
+
+ if (r->chain_out) {
+
+ redwax_metadata_push_array(m, "Chains", !r->intermediates_out->nelts);
+
+ for (i = 0; i < r->intermediates_out->nelts; i++)
+ {
+ const redwax_certificate_t *cert = &APR_ARRAY_IDX(r->intermediates_out,
+ i, const redwax_certificate_t);
+
+#if 0
+ const unsigned char *der = cert->der;
+
+ X509 *xi = d2i_X509(NULL, &der, cert->len);
+
+ if (!xi) {
+ redwax_openssl_print_errors(r);
+ X509_free(x);
+ return APR_ENOENT;
+ }
+#endif
+
+ redwax_print_error(r, "metadata-out: intermediate: %s\n",
+ cert->common.subject);
+
+ redwax_metadata_push_object(m, "Certificate", 0);
+ redwax_metadata_add_string(m, "Origin", cert->origin);
+ redwax_metadata_pop_object(m);
+
+ }
+
+ redwax_metadata_pop_array(m);
+ }
+
+ if (r->root_out || r->trust_out) {
+ for (i = 0; i < r->trusted_out->nelts; i++)
+ {
+ const redwax_certificate_t *cert = &APR_ARRAY_IDX(r->trusted_out, i, const redwax_certificate_t);
+
+#if 0
+ const unsigned char *der = cert->der;
+
+ X509 *xi = d2i_X509_AUX(NULL, &der, cert->len);
+
+ if (!xi) {
+ redwax_openssl_print_errors(r);
+ X509_free(x);
+ return APR_ENOENT;
+ }
+#endif
+
+ redwax_print_error(r, "metadata-out: trusted: %s\n",
+ cert->common.subject);
+
+ redwax_metadata_push_object(m, "Certificate", 0);
+ redwax_metadata_add_string(m, "Origin", cert->origin);
+ redwax_metadata_pop_object(m);
+
+ }
+ }
+
+ if (r->key_out) {
+
+ redwax_metadata_push_array(m, "Keys", !r->keys_out->nelts);
+
+ for (i = 0; i < r->keys_out->nelts; i++)
+ {
+ const redwax_key_t
+ *key = &APR_ARRAY_IDX(r->keys_out, i, const redwax_key_t);
+
+ redwax_print_error(r, "metadata-out: key\n");
+
+ redwax_metadata_push_object(m, "Key", 0);
+ redwax_metadata_add_string(m, "Origin", key->origin);
+ redwax_metadata_pop_object(m);
+
+ }
+
+ redwax_metadata_pop_array(m);
+ }
+
+ redwax_metadata_pop_root(m);
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t redwax_openssl_complete_format_out(redwax_tool_t *r,
+ apr_hash_t *params)
+{
+ apr_hash_set(params, "xml", APR_HASH_KEY_STRING, "xml");
+ apr_hash_set(params, "json", APR_HASH_KEY_STRING, "json");
+ apr_hash_set(params, "yaml", APR_HASH_KEY_STRING, "yaml");
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t redwax_openssl_set_format_out(redwax_tool_t *r, const char *arg)
+{
+ if (!strcmp(arg, "xml")) {
+ r->format = REDWAX_FORMAT_XML;
+ return APR_SUCCESS;
+ }
+
+ if (!strcmp(arg, "json")) {
+ r->format = REDWAX_FORMAT_JSON;
+ return APR_SUCCESS;
+ }
+
+ if (!strcmp(arg, "yaml")) {
+ r->format = REDWAX_FORMAT_YAML;
+ return APR_SUCCESS;
+ }
+
+ return DECLINED;
}
static apr_status_t redwax_openssl_search_chain(redwax_tool_t *r,
@@ -2827,6 +3022,9 @@
rt_hook_process_filter(redwax_openssl_process_filter_search, NULL, NULL, APR_HOOK_MIDDLE);
rt_hook_process_pem_out(redwax_openssl_process_pem_out, NULL, NULL, APR_HOOK_MIDDLE);
rt_hook_process_pkcs12_out(redwax_openssl_process_pkcs12_out, NULL, NULL, APR_HOOK_MIDDLE);
+ rt_hook_process_metadata_out(redwax_openssl_process_metadata_out, NULL, NULL, APR_HOOK_MIDDLE);
+ rt_hook_complete_format_out(redwax_openssl_complete_format_out, NULL, NULL, APR_HOOK_MIDDLE);
+ rt_hook_set_format_out(redwax_openssl_set_format_out, NULL, NULL, APR_HOOK_MIDDLE);
rt_hook_search_chain(redwax_openssl_search_chain, NULL, NULL, APR_HOOK_MIDDLE);
rt_hook_search_key(redwax_openssl_search_key, NULL, NULL, APR_HOOK_MIDDLE);
rt_hook_compare_certificate(redwax_openssl_compare_certificate, NULL, NULL, APR_HOOK_MIDDLE);
Modified: redwax-tool/trunk/redwax_p11kit.c
==============================================================================
--- redwax-tool/trunk/redwax_p11kit.c (original)
+++ redwax-tool/trunk/redwax_p11kit.c Mon Nov 22 00:06:12 2021
@@ -39,6 +39,8 @@
#if HAVE_LIBGEN_H
#include <libgen.h>
#endif
+
+#include <stdlib.h>
#if HAVE_P11_KIT_MODULES_LOAD_AND_INITIALIZE
@@ -332,6 +334,16 @@
return APR_SUCCESS;
}
+static apr_status_t cleanup_free(void *dummy)
+{
+
+ if (dummy) {
+ free(dummy);
+ }
+
+ return APR_SUCCESS;
+}
+
static apr_status_t redwax_p11kit_initialise(redwax_tool_t *r)
{
global_modules =
@@ -1089,6 +1101,59 @@
return ret;
}
+static const char *redwax_p11kit_origin(redwax_tool_t *r, apr_pool_t *pool,
+ CK_FUNCTION_LIST *module, CK_TOKEN_INFO *tokenInfo,
+ CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object)
+{
+ P11KitUri *origin_uri;
+ CK_TOKEN_INFO_PTR ck_token_info;
+ char *origin;
+
+ CK_ATTRIBUTE template[] = {
+ {CKA_ID, NULL_PTR, 0},
+ {CKA_LABEL, NULL_PTR, 0},
+ {CKA_CLASS, NULL_PTR, 0}
+ };
+
+ int template_len = 3;
+ int ret;
+
+ origin_uri = p11_kit_uri_new();
+
+ apr_pool_cleanup_register(r->pool, origin_uri, cleanup_p11kituri,
+ apr_pool_cleanup_null);
+
+ ret = redwax_p11kit_read_attributes(pool, module, session, object,
+ template, template_len);
+ if (ret != CKR_OK) {
+ return NULL;
+ }
+
+ /* set token */
+ ck_token_info = p11_kit_uri_get_token_info(origin_uri);
+ memcpy(ck_token_info->label, tokenInfo->label, sizeof(tokenInfo->label));
+
+ /* set id */
+ p11_kit_uri_set_attribute(origin_uri, &template[0]);
+
+ /* set object */
+ p11_kit_uri_set_attribute(origin_uri, &template[1]);
+
+ /* set type */
+ p11_kit_uri_set_attribute(origin_uri, &template[2]);
+
+ if (P11_KIT_URI_OK
+ == p11_kit_uri_format(origin_uri, P11_KIT_URI_FOR_ANY, &origin)) {
+
+ apr_pool_cleanup_register(r->pool, origin, cleanup_free,
+ apr_pool_cleanup_null);
+
+ return origin;
+ }
+
+ return NULL;
+}
+
static apr_status_t redwax_p11kit_read_slot(redwax_tool_t *r,
P11KitUri *parsed, CK_FUNCTION_LIST *module, CK_TOKEN_INFO *tokenInfo,
CK_SLOT_ID_PTR slot_id, apr_hash_t *secrets)
@@ -1230,6 +1295,9 @@
cert->len = cert_template[0].ulValueLen;
rt_run_normalise_certificate(r, cert, 1);
+
+ cert->origin = redwax_p11kit_origin(r, pool, module,
+ tokenInfo, session, object);
if (REDWAX_CERTIFICATE_ROOT
== cert->common.category && trusted) {
@@ -1455,6 +1523,9 @@
key->common.id_len, REDWAX_ENCODE_LOWER, NULL));
}
+
+ key->origin = redwax_p11kit_origin(r, pool, module, tokenInfo,
+ session, object);
}
else {
Modified: redwax-tool/trunk/redwax_util.c
==============================================================================
--- redwax-tool/trunk/redwax_util.c (original)
+++ redwax-tool/trunk/redwax_util.c Mon Nov 22 00:06:12 2021
@@ -21,8 +21,11 @@
#include "redwax_util.h"
+#include <apr.h>
#include <apr_lib.h>
#include <apr_strings.h>
+
+#include <stdlib.h>
int redwax_certcmp(redwax_certificate_t *cert1, redwax_certificate_t *cert2)
{
@@ -542,3 +545,711 @@
return NULL;
}
+#define XML_PREAMBLE "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+
+static apr_status_t cleanup_metadata(void *dummy)
+{
+ if (dummy) {
+ redwax_metadata_t *m = dummy;
+ free(m->prefix);
+ }
+
+ return APR_SUCCESS;
+}
+
+static void redwax_metadata_prefix(redwax_metadata_t *m, int diff)
+{
+ int i = m->prefix_len;
+
+ m->prefix_len += diff * 2;
+
+ if (m->prefix_len < 0) {
+ m->prefix_len = 0;
+ }
+
+ if (m->prefix) {
+ m->prefix = realloc(m->prefix, m->prefix_len);
+
+ if (m->prefix) {
+ for (; i < m->prefix_len; i++) {
+ m->prefix[i] = ' ';
+ }
+ }
+ }
+}
+
+apr_status_t redwax_metadata_push_root(apr_pool_t *pool, const char *k,
+ apr_status_t (*wv)(void *ctx, const struct iovec *vec, apr_size_t nvec),
+ void *ctx, redwax_format_e format, redwax_metadata_t **mm)
+{
+ redwax_metadata_t *m = apr_pcalloc(pool, sizeof(redwax_metadata_t));
+
+ redwax_metadata_level_t *ml;
+
+ apr_pool_create(&m->pool, pool);
+
+ m->levels = apr_array_make(m->pool, 16, sizeof(redwax_metadata_level_t));
+ m->wv = wv;
+ m->ctx = ctx;
+ m->format = format;
+ m->prefix = malloc(0);
+
+ apr_pool_cleanup_register(pool, m, cleanup_metadata,
+ apr_pool_cleanup_null);
+
+ *mm = m;
+
+ m->level = ml = apr_array_push(m->levels);
+ m->level->k = (void *)k; // escape?
+ m->level->klen = k ? strlen(k) : 0;
+ m->level->root = 1;
+ m->level->object = 1;
+
+ switch (m->format) {
+ case REDWAX_FORMAT_TEXT:
+ break;
+ case REDWAX_FORMAT_XML: {
+
+ const struct iovec vec[] = {
+ {XML_PREAMBLE, strlen(XML_PREAMBLE)},
+ {"<", 1},
+ {ml->k, ml->klen},
+ {">", 1},
+ };
+
+ return m->wv(ctx, vec, 4);
+ }
+ case REDWAX_FORMAT_JSON: {
+
+ const struct iovec vec[] = {
+ {"{", 1}
+ };
+
+ return wv(m->ctx, vec, 1);
+ }
+ case REDWAX_FORMAT_YAML: {
+
+ const struct iovec vec[] = {
+ {"---\n", 4},
+ {ml->k, ml->klen},
+ {": ", 2}
+ };
+
+ return wv(m->ctx, vec, 3);
+ }
+ default:
+ break;
+ }
+
+ return APR_SUCCESS;
+}
+
+apr_status_t redwax_metadata_pop_root(redwax_metadata_t *m)
+{
+ redwax_metadata_level_t *ml = apr_array_pop(m->levels);
+
+ if (!ml || !ml->root) {
+ return APR_EGENERAL;
+ }
+
+ switch (m->format) {
+ case REDWAX_FORMAT_TEXT:
+ break;
+ case REDWAX_FORMAT_XML: {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"</", 2},
+ {ml->k, ml->klen},
+ {">\n", 2},
+ };
+
+ return m->wv(m->ctx, vec, 5);
+ }
+ case REDWAX_FORMAT_JSON: {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"}\n", 2}
+ };
+
+ return m->wv(m->ctx, vec, 3);
+ }
+ case REDWAX_FORMAT_YAML: {
+
+ const struct iovec vec[] = {
+ {"\n...\n", 5}
+ };
+
+ return m->wv(m->ctx, vec, 1);
+ }
+ default:
+ break;
+ }
+
+ return APR_SUCCESS;
+}
+
+apr_status_t redwax_metadata_push_array(redwax_metadata_t *m, const char *k, int empty)
+{
+ redwax_metadata_level_t *ml = m->level;
+
+ int array = ml->array;
+ int object = ml->object;
+ int next = ml->next;
+
+ m->level->next = 1;
+
+ m->level = ml = apr_array_push(m->levels);
+ m->level->k = (void *)k;
+ m->level->klen = k ? strlen(k) : 0;
+ m->level->empty = empty;
+ m->level->array = 1;
+ m->level->object = 0;
+ m->level->next = 0;
+ m->level->root = 0;
+
+ redwax_metadata_prefix(m, 1);
+
+ switch (m->format) {
+ case REDWAX_FORMAT_TEXT:
+ break;
+ case REDWAX_FORMAT_XML: {
+ if (empty) {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"<", 1},
+ {ml->k, ml->klen},
+ {" />\n", 4},
+ };
+
+ return m->wv(m->ctx, vec, 5);
+ }
+ else {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"<", 1},
+ {ml->k, ml->klen},
+ {">", 1},
+ };
+
+ return m->wv(m->ctx, vec, 5);
+ }
+
+ break;
+ }
+ case REDWAX_FORMAT_JSON: {
+
+ if (object) {
+
+ const struct iovec vec[] = {
+ {next ? "," : "", next ? 1 : 0},
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"\"", 1},
+ {ml->k, ml->klen},
+ {"\": [", 4}
+ };
+
+ return m->wv(m->ctx, vec, 6);
+ }
+ else if (array) {
+
+ const struct iovec vec[] = {
+ {next ? "," : "", next ? 1 : 0},
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"[", 1}
+ };
+
+ return m->wv(m->ctx, vec, 4);
+ }
+
+ break;
+ }
+ case REDWAX_FORMAT_YAML: {
+
+ if (object) {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {ml->k, ml->klen},
+ {": ", 2}
+ };
+
+ return m->wv(m->ctx, vec, 4);
+ }
+ else if (array) {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {ml->k, ml->klen},
+ {": ", 2}
+ };
+
+ return m->wv(m->ctx, vec, 3);
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return APR_SUCCESS;
+}
+
+apr_status_t redwax_metadata_pop_array(redwax_metadata_t *m)
+{
+ redwax_metadata_level_t *ml = apr_array_pop(m->levels);
+
+ char *prefix = m->prefix;
+ int prefix_len = m->prefix_len;
+
+ int empty = m->level->empty;
+
+ if (!ml->array) {
+ return APR_EGENERAL;
+ }
+
+ if (m->levels->nelts) {
+ m->level = &APR_ARRAY_IDX(m->levels, m->levels->nelts - 1,
+ redwax_metadata_level_t);
+ }
+
+ redwax_metadata_prefix(m, -1);
+
+ switch (m->format) {
+ case REDWAX_FORMAT_TEXT:
+ break;
+ case REDWAX_FORMAT_XML: {
+
+ if (empty) {
+
+ return APR_SUCCESS;
+ }
+ else {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {prefix, prefix_len},
+ {"</", 2},
+ {ml->k, ml->klen},
+ {">", 1},
+ };
+
+ return m->wv(m->ctx, vec, 5);
+ }
+
+ break;
+ }
+ case REDWAX_FORMAT_JSON: {
+
+ if (empty) {
+
+ const struct iovec vec[] = {
+ {"]", 1}
+ };
+
+ return m->wv(m->ctx, vec, 1);
+ }
+ else {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {prefix, prefix_len},
+ {"]", 1}
+ };
+
+ return m->wv(m->ctx, vec, 3);
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return APR_SUCCESS;
+}
+
+apr_status_t redwax_metadata_push_object(redwax_metadata_t *m, const char *k, int empty)
+{
+ redwax_metadata_level_t *ml = m->level;
+
+ int array = ml->array;
+ int object = ml->object;
+ int next = ml->next;
+
+ m->level->next = 1;
+
+ m->level = ml = apr_array_push(m->levels);
+ m->level->k = (void *)k;
+ m->level->klen = k ? strlen(k) : 0;
+ m->level->empty = empty;
+ m->level->array = 0;
+ m->level->object = 1;
+ m->level->next = 0;
+ m->level->root = 0;
+
+ redwax_metadata_prefix(m, 1);
+
+ switch (m->format) {
+ case REDWAX_FORMAT_TEXT:
+ break;
+ case REDWAX_FORMAT_XML: {
+ if (empty) {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"<", 1},
+ {ml->k, ml->klen},
+ {" />\n", 4},
+ };
+
+ return m->wv(m->ctx, vec, 5);
+ }
+ else if (array) {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"<", 1},
+ {ml->k, ml->klen},
+ {">", 1},
+ };
+
+ return m->wv(m->ctx, vec, 5);
+ }
+
+ break;
+ }
+ case REDWAX_FORMAT_JSON: {
+
+ if (object) {
+
+ const struct iovec vec[] = {
+ {next ? "," : "", next ? 1 : 0},
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"\"", 1},
+ {ml->k, ml->klen},
+ {"\": {", 4}
+ };
+
+ return m->wv(m->ctx, vec, 6);
+ }
+ else if (array) {
+
+ const struct iovec vec[] = {
+ {next ? "," : "", next ? 1 : 0},
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"{", 1}
+ };
+
+ return m->wv(m->ctx, vec, 4);
+ }
+
+ break;
+ }
+ case REDWAX_FORMAT_YAML: {
+
+ if (object) {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {ml->k, ml->klen},
+ {": ", 2}
+ };
+
+ return m->wv(m->ctx, vec, 4);
+ }
+ else if (array) {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"- ", 2}
+ };
+
+ return m->wv(m->ctx, vec, 3);
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return APR_SUCCESS;
+}
+
+apr_status_t redwax_metadata_pop_object(redwax_metadata_t *m)
+{
+ redwax_metadata_level_t *ml = apr_array_pop(m->levels);
+
+ char *prefix = m->prefix;
+ int prefix_len = m->prefix_len;
+
+ int empty = m->level->empty;
+
+ if (!ml->object) {
+ return APR_EGENERAL;
+ }
+
+ if (m->levels->nelts) {
+ m->level = &APR_ARRAY_IDX(m->levels, m->levels->nelts - 1,
+ redwax_metadata_level_t);
+ }
+
+ redwax_metadata_prefix(m, -1);
+
+ switch (m->format) {
+ case REDWAX_FORMAT_TEXT:
+ break;
+ case REDWAX_FORMAT_XML: {
+
+ if (empty) {
+
+ return APR_SUCCESS;
+ }
+ else {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {prefix, prefix_len},
+ {"</", 2},
+ {ml->k, ml->klen},
+ {">", 1},
+ };
+
+ return m->wv(m->ctx, vec, 5);
+ }
+
+ break;
+ }
+ case REDWAX_FORMAT_JSON: {
+
+ if (empty) {
+
+ const struct iovec vec[] = {
+ {"}", 1}
+ };
+
+ return m->wv(m->ctx, vec, 1);
+ }
+ else {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {prefix, prefix_len},
+ {"}", 1}
+ };
+
+ return m->wv(m->ctx, vec, 3);
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return APR_SUCCESS;
+}
+
+apr_status_t redwax_metadata_add_string(redwax_metadata_t *m, const char *key, const char *val)
+{
+ redwax_metadata_level_t *ml = m->level;
+
+ apr_status_t status = APR_SUCCESS;
+
+ void *k = (void *)key;
+ int klen = k ? strlen(k) : 0;
+ void *v = (void *)val;
+ int vlen = v ? strlen(v) : 0;
+
+ int array = ml->array;
+ int object = ml->object;
+ int next = ml->next;
+
+ ml->next = 1;
+
+ redwax_metadata_prefix(m, 1);
+
+ switch (m->format) {
+ case REDWAX_FORMAT_TEXT:
+ break;
+ case REDWAX_FORMAT_XML: {
+// FIXME: handle escaping of the value
+ if (!v) {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"<", 1},
+ {k, klen},
+ {" />", 3},
+ };
+
+ status = m->wv(m->ctx, vec, 5);
+
+ }
+ else {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"<", 1},
+ {k, klen},
+ {">", 1},
+ {v, vlen},
+ {"</", 2},
+ {k, klen},
+ {">", 1},
+ };
+
+ status = m->wv(m->ctx, vec, 9);
+ }
+
+ break;
+ }
+ case REDWAX_FORMAT_JSON: {
+
+ if (object) {
+
+ if (!v) {
+
+ const struct iovec vec[] = {
+ {next ? "," : "", next ? 1 : 0},
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"\"", 1},
+ {k, klen},
+ {"\": null", 7}
+ };
+
+ status = m->wv(m->ctx, vec, 6);
+ }
+ else {
+
+ const struct iovec vec[] = {
+ {next ? "," : "", next ? 1 : 0},
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"\"", 1},
+ {k, klen},
+ {"\": \"", 4},
+ {v, vlen},
+ {"\"", 1}
+ };
+
+ status = m->wv(m->ctx, vec, 8);
+ }
+
+ }
+ else if (array) {
+
+ if (!v) {
+
+ const struct iovec vec[] = {
+ {next ? "," : "", next ? 1 : 0},
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"null", 4}
+ };
+
+ status = m->wv(m->ctx, vec, 4);
+ }
+ else {
+
+ const struct iovec vec[] = {
+ {next ? "," : "", next ? 1 : 0},
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {"\"", 1},
+ {v, vlen},
+ {"\"", 1}
+ };
+
+ status = m->wv(m->ctx, vec, 6);
+ }
+
+ }
+
+ break;
+ }
+ case REDWAX_FORMAT_YAML: {
+
+ if (object) {
+
+ if (!v) {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {k, klen},
+ {": ", 2},
+ };
+
+ status = m->wv(m->ctx, vec, 4);
+ }
+ else {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {m->prefix, m->prefix_len},
+ {k, klen},
+ {": ", 2},
+ {v, vlen},
+ };
+
+ status = m->wv(m->ctx, vec, 5);
+ }
+
+ }
+ else if (array) {
+// FIXME: yaml indentation still not 100%
+ if (!v) {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {k, klen},
+ {":\n", 2}
+ };
+
+ status = m->wv(m->ctx, vec, 3);
+ }
+ else {
+
+ const struct iovec vec[] = {
+ {"\n", 1},
+ {k, klen},
+ {":\n", 2}
+ };
+
+ status = m->wv(m->ctx, vec, 3);
+ }
+
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ redwax_metadata_prefix(m, -1);
+
+ return APR_SUCCESS;
+}
Modified: redwax-tool/trunk/redwax_util.h
==============================================================================
--- redwax-tool/trunk/redwax_util.h (original)
+++ redwax-tool/trunk/redwax_util.h Mon Nov 22 00:06:12 2021
@@ -70,4 +70,48 @@
*/
#define REDWAX_ENCODE_LOWER 32
+/**
+ * Keep track of nesting level.
+ */
+typedef struct redwax_metadata_level_t {
+ void *k;
+ int klen;
+ int root:1;
+ int object:1;
+ int array:1;
+ int empty:1;
+ int next:1;
+} redwax_metadata_level_t;
+
+/**
+ * A structure to hold metadata context.
+ */
+typedef struct redwax_metadata_t {
+ apr_pool_t *pool;
+ apr_array_header_t *levels;
+ redwax_metadata_level_t *level;
+ apr_status_t (*wv)(void *ctx, const struct iovec *vec,
+ apr_size_t nvec);
+ void *ctx;
+ redwax_format_e format;
+ char *prefix;
+ int prefix_len;
+} redwax_metadata_t;
+
+apr_status_t redwax_metadata_push_root(apr_pool_t *pool, const char *k,
+ apr_status_t (*wv)(void *ctx, const struct iovec *vec, apr_size_t nvec),
+ void *ctx, redwax_format_e format, redwax_metadata_t **mm);
+
+apr_status_t redwax_metadata_pop_root(redwax_metadata_t *m);
+
+apr_status_t redwax_metadata_push_array(redwax_metadata_t *m, const char *k, int empty);
+
+apr_status_t redwax_metadata_pop_array(redwax_metadata_t *m);
+
+apr_status_t redwax_metadata_push_object(redwax_metadata_t *m, const char *k, int empty);
+
+apr_status_t redwax_metadata_pop_object(redwax_metadata_t *m);
+
+apr_status_t redwax_metadata_add_string(redwax_metadata_t *m, const char *k, const char *v);
+
#endif
More information about the rs-commit
mailing list