make TALER_MINT_parse_json_data more expressive

This commit is contained in:
Christian Grothoff 2015-01-29 15:06:55 +01:00
parent ab67dec1be
commit a284561298
3 changed files with 146 additions and 128 deletions

View File

@ -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 * Parse JSON object into components based on the given field
* specification. * specification.
@ -558,23 +488,51 @@ TALER_MINT_parse_json_data (struct MHD_Connection *connection,
ret = GNUNET_YES; ret = GNUNET_YES;
for (i=0; NULL != spec[i].field_name; i++) for (i=0; NULL != spec[i].field_name; i++)
{ {
if (0 == spec[i].destination_size_in) switch (spec[i].command)
{ {
ptr = NULL; case JNAV_FIELD:
parse_variable_json_data (connection, root, GNUNET_break (0);
spec[i].field_name, return GNUNET_SYSERR;
&ptr, case JNAV_INDEX:
&spec[i].destination_size_out, GNUNET_break (0);
&ret); return GNUNET_SYSERR;
spec[i].destination = ptr; case JNAV_RET_DATA:
} if (GNUNET_YES != ret)
else break;
{ ret = GNUNET_MINT_parse_navigate_json (connection,
parse_fixed_json_data (connection, root, root,
JNAV_FIELD,
spec[i].field_name, spec[i].field_name,
JNAV_RET_DATA,
spec[i].destination, spec[i].destination,
spec[i].destination_size_in, spec[i].destination_size_in);
&ret); break;
case JNAV_RET_DATA_VAR:
if (GNUNET_YES != ret)
break;
ptr = NULL;
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;
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) if (GNUNET_YES != ret)
@ -595,13 +553,34 @@ TALER_MINT_release_parsed_data (struct GNUNET_MINT_ParseFieldSpec *spec)
unsigned int i; unsigned int i;
for (i=0; NULL != spec[i].field_name; 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)
{
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); GNUNET_free (spec[i].destination);
spec[i].destination = NULL; spec[i].destination = NULL;
spec[i].destination_size_out = 0; 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_data = out;
*out_size = olen; *out_size = olen;
return GNUNET_OK; return GNUNET_OK;
} }

View File

@ -162,6 +162,22 @@ struct GNUNET_MINT_ParseFieldSpec
* variable-size allocations). * variable-size allocations).
*/ */
size_t destination_size_out; 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 field name of the field
* @param value where to store the value * @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. * Generate line in parser specification for variable-size value.
* *
* @param field name of the field * @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. * 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 }
/** /**

View File

@ -275,29 +275,57 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
if ( (GNUNET_NO == res) || (NULL == root) ) if ( (GNUNET_NO == res) || (NULL == root) )
return MHD_YES; return MHD_YES;
/* session_pub field must always be present */ res = GNUNET_MINT_parse_navigate_json (connection,
res = GNUNET_MINT_parse_navigate_json (connection, root, root,
JNAV_FIELD, "session_pub", JNAV_FIELD,
"session_pub",
JNAV_RET_DATA, JNAV_RET_DATA,
&refresh_session_pub, &refresh_session_pub,
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
if (GNUNET_OK != res) if (GNUNET_SYSERR == res)
{
// FIXME: return 'internal error'?
GNUNET_break (0);
return MHD_NO; return MHD_NO;
}
if (GNUNET_NO == res) if (GNUNET_NO == res)
return MHD_YES; return MHD_YES;
res = GNUNET_MINT_parse_navigate_json (connection,
res = GNUNET_MINT_parse_navigate_json (connection, root, root,
JNAV_FIELD, "new_denoms", JNAV_FIELD,
"new_denoms",
JNAV_RET_TYPED_JSON, JNAV_RET_TYPED_JSON,
JSON_ARRAY, JSON_ARRAY,
&new_denoms); &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) if (GNUNET_OK != res)
{
// FIXME: leaks!
return res; 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); num_new_denoms = json_array_size (new_denoms);
denom_pubs = GNUNET_malloc (num_new_denoms * denom_pubs = GNUNET_malloc (num_new_denoms *
sizeof (struct GNUNET_CRYPTO_rsa_PublicKey *)); 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_count = json_array_size (melt_coins);
coin_public_infos = GNUNET_malloc (coin_count * coin_public_infos = GNUNET_malloc (coin_count *