From a284561298af60ade27eb18008f29ebf63ac62b7 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 29 Jan 2015 15:06:55 +0100 Subject: [PATCH] make TALER_MINT_parse_json_data more expressive --- src/mint/taler-mint-httpd_parsing.c | 158 ++++++++++++---------------- src/mint/taler-mint-httpd_parsing.h | 37 ++++++- src/mint/taler-mint-httpd_refresh.c | 79 ++++++++------ 3 files changed, 146 insertions(+), 128 deletions(-) diff --git a/src/mint/taler-mint-httpd_parsing.c b/src/mint/taler-mint-httpd_parsing.c index 066f18913..165654193 100644 --- a/src/mint/taler-mint-httpd_parsing.c +++ b/src/mint/taler-mint-httpd_parsing.c @@ -462,76 +462,6 @@ GNUNET_MINT_parse_navigate_json (struct MHD_Connection *connection, } -/** - * Find a fixed-size field in the top-level of the JSON tree and store - * it in @a data. - * - * Sends an error response if navigation is impossible (i.e. - * the JSON object is invalid) - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param field name of the field to navigate to - * @param data where to store the extracted data - * @param data_size size of the @a data field - * @param[IN|OUT] ret return value, function does nothing if @a ret is not #GNUNET_YES - * on entry; will set @a ret to: - * #GNUNET_YES if navigation was successful - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error - */ -static void -parse_fixed_json_data (struct MHD_Connection *connection, - const json_t *root, - const char *field, - void *data, - size_t data_size, - int *ret) -{ - if (GNUNET_YES != *ret) - return; - *ret = GNUNET_MINT_parse_navigate_json (connection, - root, - JNAV_FIELD, field, - JNAV_RET_DATA, data, data_size); -} - - -/** - * Find a variable-size field in the top-level of the JSON tree and store - * it in @a data. - * - * Sends an error response if navigation is impossible (i.e. - * the JSON object is invalid) - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param field name of the field to navigate to - * @param data where to store a pointer to memory allocated for the extracted data - * @param[IN|OUT] ret return value, function does nothing if @a ret is not #GNUNET_YES - * on entry; will set @a ret to: - * #GNUNET_YES if navigation was successful - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error - */ -static void -parse_variable_json_data (struct MHD_Connection *connection, - const json_t *root, - const char *field, - void **data, - size_t *data_size, - int *ret) -{ - if (GNUNET_YES != *ret) - return; - *ret = GNUNET_MINT_parse_navigate_json (connection, - root, - JNAV_FIELD, field, - JNAV_RET_DATA_VAR, data, data_size); - -} - - /** * Parse JSON object into components based on the given field * specification. @@ -558,23 +488,51 @@ TALER_MINT_parse_json_data (struct MHD_Connection *connection, ret = GNUNET_YES; for (i=0; NULL != spec[i].field_name; i++) { - if (0 == spec[i].destination_size_in) + switch (spec[i].command) { + case JNAV_FIELD: + GNUNET_break (0); + return GNUNET_SYSERR; + case JNAV_INDEX: + GNUNET_break (0); + return GNUNET_SYSERR; + case JNAV_RET_DATA: + if (GNUNET_YES != ret) + break; + ret = GNUNET_MINT_parse_navigate_json (connection, + root, + JNAV_FIELD, + spec[i].field_name, + JNAV_RET_DATA, + spec[i].destination, + spec[i].destination_size_in); + break; + case JNAV_RET_DATA_VAR: + if (GNUNET_YES != ret) + break; ptr = NULL; - parse_variable_json_data (connection, root, - spec[i].field_name, - &ptr, - &spec[i].destination_size_out, - &ret); + ret = GNUNET_MINT_parse_navigate_json (connection, + root, + JNAV_FIELD, + spec[i].field_name, + JNAV_RET_DATA_VAR, + &ptr, + &spec[i].destination_size_out); spec[i].destination = ptr; - } - else - { - parse_fixed_json_data (connection, root, - spec[i].field_name, - spec[i].destination, - spec[i].destination_size_in, - &ret); + break; + case JNAV_RET_TYPED_JSON: + if (GNUNET_YES != ret) + break; + ptr = NULL; + ret = GNUNET_MINT_parse_navigate_json (connection, + root, + JNAV_FIELD, + spec[i].field_name, + JNAV_RET_TYPED_JSON, + spec[i].type, + &ptr); + spec[i].destination = ptr; + break; } } if (GNUNET_YES != ret) @@ -595,13 +553,34 @@ TALER_MINT_release_parsed_data (struct GNUNET_MINT_ParseFieldSpec *spec) unsigned int i; for (i=0; NULL != spec[i].field_name; i++) - if ( (0 == spec[i].destination_size_in) && - (0 != spec[i].destination_size_out) ) + { + switch (spec[i].command) { - GNUNET_free (spec[i].destination); - spec[i].destination = NULL; - spec[i].destination_size_out = 0; + case JNAV_FIELD: + GNUNET_break (0); + return; + case JNAV_INDEX: + GNUNET_break (0); + return; + case JNAV_RET_DATA: + break; + case JNAV_RET_DATA_VAR: + if (0 != spec[i].destination_size_out) + { + GNUNET_free (spec[i].destination); + spec[i].destination = NULL; + spec[i].destination_size_out = 0; + } + break; + case JNAV_RET_TYPED_JSON: + if (NULL != spec[i].destination) + { + json_decref (spec[i].destination); + spec[i].destination = NULL; + } + break; } + } } @@ -774,7 +753,6 @@ TALER_MINT_mhd_request_var_arg_data (struct MHD_Connection *connection, *out_data = out; *out_size = olen; return GNUNET_OK; - } diff --git a/src/mint/taler-mint-httpd_parsing.h b/src/mint/taler-mint-httpd_parsing.h index 1c13c9469..86205a070 100644 --- a/src/mint/taler-mint-httpd_parsing.h +++ b/src/mint/taler-mint-httpd_parsing.h @@ -162,6 +162,22 @@ struct GNUNET_MINT_ParseFieldSpec * variable-size allocations). */ size_t destination_size_out; + + /** + * Navigation command to use to extract the value. Note that + * #JNAV_RET_DATA or #JNAV_RET_DATA_VAR must be used for @e + * destination_size_in and @e destination_size_out to have a + * meaning. #JNAV_FIELD and #JNAV_INDEX must not be used here! + */ + enum TALER_MINT_JsonNavigationCommand command; + + /** + * JSON type to use, only meaningful in connection with a @e command + * value of #JNAV_RET_TYPED_JSON. Typical values are + * #JSON_ARRAY and #JSON_OBJECT. + */ + int type; + }; @@ -201,19 +217,34 @@ TALER_MINT_release_parsed_data (struct GNUNET_MINT_ParseFieldSpec *spec); * @param field name of the field * @param value where to store the value */ -#define TALER_MINT_PARSE_FIXED(field,value) { field, value, sizeof (*value), 0 } +#define TALER_MINT_PARSE_FIXED(field,value) { field, value, sizeof (*value), 0, JNAV_RET_DATA, 0 } /** * Generate line in parser specification for variable-size value. * * @param field name of the field */ -#define TALER_MINT_PARSE_VARIABLE(field) { field, NULL, 0, 0 } +#define TALER_MINT_PARSE_VARIABLE(field) { field, NULL, 0, 0, JNAV_RET_DATA_VAR, 0 } + +/** + * Generate line in parser specification for JSON array value. + * + * @param field name of the field + */ +#define TALER_MINT_PARSE_ARRAY(field) { field, NULL, 0, 0, JNAV_RET_TYPED_JSON, JSON_ARRAY } + +/** + * Generate line in parser specification for JSON object value. + * + * @param field name of the field + */ +#define TALER_MINT_PARSE_OBJECT(field) { field, NULL, 0, 0, JNAV_RET_TYPED_JSON, JSON_OBJECT } + /** * Generate line in parser specification indicating the end of the spec. */ -#define TALER_MINT_PARSE_END { NULL, NULL, 0, 0 } +#define TALER_MINT_PARSE_END { NULL, NULL, 0, 0, JNAV_FIELD, 0 } /** diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c index 7e16f2a92..89aff83ab 100644 --- a/src/mint/taler-mint-httpd_refresh.c +++ b/src/mint/taler-mint-httpd_refresh.c @@ -275,29 +275,57 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh, if ( (GNUNET_NO == res) || (NULL == root) ) return MHD_YES; - /* session_pub field must always be present */ - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "session_pub", - JNAV_RET_DATA, - &refresh_session_pub, - sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); - if (GNUNET_OK != res) - { - // FIXME: return 'internal error'? - GNUNET_break (0); + res = GNUNET_MINT_parse_navigate_json (connection, + root, + JNAV_FIELD, + "session_pub", + JNAV_RET_DATA, + &refresh_session_pub, + sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); + if (GNUNET_SYSERR == res) return MHD_NO; - } if (GNUNET_NO == res) return MHD_YES; - - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "new_denoms", + res = GNUNET_MINT_parse_navigate_json (connection, + root, + JNAV_FIELD, + "new_denoms", JNAV_RET_TYPED_JSON, JSON_ARRAY, &new_denoms); + if (GNUNET_SYSERR == res) + return MHD_NO; + if (GNUNET_NO == res) + return MHD_YES; + + res = GNUNET_MINT_parse_navigate_json (connection, + root, + JNAV_FIELD, + "melt_coins", + JNAV_RET_TYPED_JSON, + JSON_ARRAY, + &melt_coins); if (GNUNET_OK != res) - return res; + { + // FIXME: leaks! + return res; + } + + melt_sig_json = json_object_get (root, + "melt_signature"); + if (NULL == melt_sig_json) + { + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s}", + "error", + "melt_signature missing"); + } + + + num_new_denoms = json_array_size (new_denoms); + denom_pubs = GNUNET_malloc (num_new_denoms * sizeof (struct GNUNET_CRYPTO_rsa_PublicKey *)); @@ -326,27 +354,8 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh, } } - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "melt_coins", - JNAV_RET_TYPED_JSON, - JSON_ARRAY, - &melt_coins); - if (GNUNET_OK != res) - { - // FIXME: leaks! - return res; - } - melt_sig_json = json_object_get (root, - "melt_signature"); - if (NULL == melt_sig_json) - { - return TALER_MINT_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", - "melt_signature missing"); - } + coin_count = json_array_size (melt_coins); coin_public_infos = GNUNET_malloc (coin_count *