refactor to eliminate duplicated JSON parsing logic (#4150)

This commit is contained in:
Christian Grothoff 2016-03-19 19:16:35 +01:00
parent 3d5e096fa2
commit 737e3f4bf6
10 changed files with 345 additions and 1281 deletions

View File

@ -113,12 +113,12 @@ TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh,
struct GNUNET_TIME_Absolute at;
json_t *wire;
json_t *root;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_fixed ("reserve_pub", &reserve_pub),
TMH_PARSE_member_amount ("amount", &amount),
TMH_PARSE_member_time_abs ("execution_date", &at),
TMH_PARSE_member_object ("wire", &wire),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("reserve_pub", &reserve_pub),
TALER_JSON_spec_amount ("amount", &amount),
GNUNET_JSON_spec_absolute_time ("execution_date", &at),
GNUNET_JSON_spec_json ("wire", &wire),
GNUNET_JSON_spec_end ()
};
int res;
@ -148,7 +148,7 @@ TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh,
TMH_json_validate_wireformat (wire))
{
GNUNET_break_op (0);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_arg_unknown (connection,
"wire");
}
@ -157,7 +157,7 @@ TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh,
&amount,
at,
wire);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return res;
}

View File

@ -140,19 +140,19 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
struct TMH_KS_StateHandle *ks;
struct GNUNET_HashCode my_h_wire;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_denomination_public_key ("denom_pub", &deposit.coin.denom_pub),
TMH_PARSE_member_denomination_signature ("ub_sig", &deposit.coin.denom_sig),
TMH_PARSE_member_fixed ("coin_pub", &deposit.coin.coin_pub),
TMH_PARSE_member_fixed ("merchant_pub", &deposit.merchant_pub),
TMH_PARSE_member_fixed ("H_contract", &deposit.h_contract),
TMH_PARSE_member_fixed ("H_wire", &deposit.h_wire),
TMH_PARSE_member_fixed ("coin_sig", &deposit.csig),
TMH_PARSE_member_uint64 ("transaction_id", &deposit.transaction_id),
TMH_PARSE_member_time_abs ("timestamp", &deposit.timestamp),
TMH_PARSE_member_time_abs ("refund_deadline", &deposit.refund_deadline),
TMH_PARSE_member_time_abs ("edate", &deposit.wire_deadline),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_denomination_public_key ("denom_pub", &deposit.coin.denom_pub),
TALER_JSON_spec_denomination_signature ("ub_sig", &deposit.coin.denom_sig),
GNUNET_JSON_spec_fixed_auto ("coin_pub", &deposit.coin.coin_pub),
GNUNET_JSON_spec_fixed_auto ("merchant_pub", &deposit.merchant_pub),
GNUNET_JSON_spec_fixed_auto ("H_contract", &deposit.h_contract),
GNUNET_JSON_spec_fixed_auto ("H_wire", &deposit.h_wire),
GNUNET_JSON_spec_fixed_auto ("coin_sig", &deposit.csig),
GNUNET_JSON_spec_uint64 ("transaction_id", &deposit.transaction_id),
GNUNET_JSON_spec_absolute_time ("timestamp", &deposit.timestamp),
GNUNET_JSON_spec_absolute_time ("refund_deadline", &deposit.refund_deadline),
GNUNET_JSON_spec_absolute_time ("edate", &deposit.wire_deadline),
GNUNET_JSON_spec_end ()
};
memset (&deposit, 0, sizeof (deposit));
@ -167,7 +167,7 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,
if (GNUNET_YES !=
TMH_json_validate_wireformat (wire))
{
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_arg_unknown (connection,
"wire");
}
@ -176,7 +176,7 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,
&my_h_wire))
{
TALER_LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n");
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_arg_invalid (connection,
"wire");
}
@ -185,7 +185,7 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,
sizeof (struct GNUNET_HashCode)))
{
/* Client hashed contract differently than we did, reject */
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_arg_invalid (connection,
"H_wire");
}
@ -196,7 +196,7 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,
if (NULL == dki)
{
TMH_KS_release (ks);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_arg_unknown (connection,
"denom_pub");
}
@ -209,13 +209,13 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,
&deposit.deposit_fee))
{
/* Total amount smaller than fee, invalid */
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_arg_invalid (connection,
"f");
}
res = verify_and_execute_deposit (connection,
&deposit);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return res;
}
@ -247,10 +247,10 @@ TMH_DEPOSIT_handler_deposit (struct TMH_RequestHandler *rh,
json_t *wire;
int res;
struct TALER_Amount amount;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_object ("wire", &wire),
TMH_PARSE_member_amount ("f", &amount),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_json ("wire", &wire),
TALER_JSON_spec_amount ("f", &amount),
GNUNET_JSON_spec_end ()
};
res = TMH_PARSE_post_json (connection,
@ -274,7 +274,7 @@ TMH_DEPOSIT_handler_deposit (struct TMH_RequestHandler *rh,
json,
&amount,
wire);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
json_decref (json);
return res;
}

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014, 2015 GNUnet e.V.
Copyright (C) 2014, 2015, 2016 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@ -141,89 +141,6 @@ buffer_append (struct Buffer *buf,
}
/**
* Release all memory allocated for the variable-size fields in
* the parser specification.
*
* @param spec specification to free
* @param spec_len number of items in @a spec to look at
*/
static void
release_data (struct TMH_PARSE_FieldSpecification *spec,
unsigned int spec_len)
{
unsigned int i;
for (i=0; i < spec_len; i++)
{
switch (spec[i].command)
{
case TMH_PARSE_JNC_FIELD:
GNUNET_break (0);
return;
case TMH_PARSE_JNC_INDEX:
GNUNET_break (0);
return;
case TMH_PARSE_JNC_RET_DATA:
break;
case TMH_PARSE_JNC_RET_DATA_VAR:
if (NULL != spec[i].destination)
{
GNUNET_free (* (void**) spec[i].destination);
*(void**) spec[i].destination = NULL;
*spec[i].destination_size_out = 0;
}
break;
case TMH_PARSE_JNC_RET_TYPED_JSON:
{
json_t *json;
json = *(json_t **) spec[i].destination;
if (NULL != json)
{
json_decref (json);
*(json_t**) spec[i].destination = NULL;
}
}
break;
case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY:
{
struct TALER_DenominationPublicKey *pk;
pk = spec[i].destination;
if (NULL != pk->rsa_public_key)
{
GNUNET_CRYPTO_rsa_public_key_free (pk->rsa_public_key);
pk->rsa_public_key = NULL;
}
}
break;
case TMH_PARSE_JNC_RET_RSA_SIGNATURE:
{
struct TALER_DenominationSignature *sig;
sig = spec[i].destination;
if (NULL != sig->rsa_signature)
{
GNUNET_CRYPTO_rsa_signature_free (sig->rsa_signature);
sig->rsa_signature = NULL;
}
}
break;
case TMH_PARSE_JNC_RET_AMOUNT:
memset (spec[i].destination,
0,
sizeof (struct TALER_Amount));
break;
case TMH_PARSE_JNC_RET_TIME_ABSOLUTE:
break;
case TMH_PARSE_JNC_RET_UINT64:
break;
}
}
}
/**
* Process a POST request containing a JSON object. This function
* realizes an MHD POST processor that will (incrementally) process
@ -349,8 +266,8 @@ TMH_PARSE_post_cleanup_callback (void *con_cls)
/**
* Extract base32crockford encoded data from request.
*
* Queues an error response to the connection if the parameter is missing or
* invalid.
* Queues an error response to the connection if the parameter is
* missing or invalid.
*
* @param connection the MHD connection
* @param param_name the name of the parameter with the key
@ -390,759 +307,117 @@ TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection,
}
/**
* Extraxt variable-size base32crockford encoded data from request.
*
* Queues an error response to the connection if the parameter is missing
* or the encoding is invalid.
*
* @param connection the MHD connection
* @param param_name the name of the parameter with the key
* @param[out] out_data pointer to allocate buffer and store the result
* @param[out] out_size set to the size of the buffer allocated in @a out_data
* @return
* #GNUNET_YES if the the argument is present
* #GNUNET_NO if the argument is absent or malformed
* #GNUNET_SYSERR on internal error (error response could not be sent)
*/
int
TMH_PARSE_mhd_request_var_arg_data (struct MHD_Connection *connection,
const char *param_name,
void **out_data,
size_t *out_size)
{
const char *str;
size_t slen;
size_t olen;
void *out;
str = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
param_name);
if (NULL == str)
{
return (MHD_NO ==
TMH_RESPONSE_reply_arg_missing (connection, param_name))
? GNUNET_SYSERR : GNUNET_NO;
}
slen = strlen (str);
olen = (slen * 5) / 8;
out = GNUNET_malloc (olen);
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (str,
strlen (str),
out,
olen))
{
GNUNET_free (out);
*out_size = 0;
return (MHD_NO ==
TMH_RESPONSE_reply_arg_invalid (connection, param_name))
? GNUNET_SYSERR : GNUNET_NO;
}
*out_data = out;
*out_size = olen;
return GNUNET_OK;
}
/**
* Navigate through a JSON tree.
*
* 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 ... navigation specification (see `enum TMH_PARSE_JsonNavigationCommand`)
* @return
* #GNUNET_YES if navigation was successful
* #GNUNET_NO if json is malformed, error response was generated
* #GNUNET_SYSERR on internal error (no response was generated,
* connection must be closed)
*/
int
TMH_PARSE_navigate_json (struct MHD_Connection *connection,
const json_t *root,
...)
{
va_list argp;
int ret;
json_t *path; /* what's our current path from 'root'? */
path = json_array ();
va_start (argp, root);
ret = 2; /* just not any of the valid return values */
while (2 == ret)
{
enum TMH_PARSE_JsonNavigationCommand command
= va_arg (argp,
enum TMH_PARSE_JsonNavigationCommand);
switch (command)
{
case TMH_PARSE_JNC_FIELD:
{
const char *fname = va_arg(argp, const char *);
json_array_append_new (path,
json_string (fname));
root = json_object_get (root,
fname);
if (NULL == root)
{
GNUNET_break_op (0);
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:s, s:O}",
"error", "missing field in JSON",
"field", fname,
"path", path))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
}
break;
case TMH_PARSE_JNC_INDEX:
{
int fnum = va_arg(argp, int);
json_array_append_new (path,
json_integer (fnum));
root = json_array_get (root,
fnum);
if (NULL == root)
{
GNUNET_break_op (0);
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:O}",
"error", "missing index in JSON",
"path", path))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
}
break;
case TMH_PARSE_JNC_RET_DATA:
{
void *where = va_arg (argp, void *);
size_t len = va_arg (argp, size_t);
const char *str;
int res;
str = json_string_value (root);
if (NULL == str)
{
GNUNET_break_op (0);
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:O}",
"error", "string expected",
"path", path))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
res = GNUNET_STRINGS_string_to_data (str, strlen (str),
where, len);
if (GNUNET_OK != res)
{
GNUNET_break_op (0);
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:O}",
"error", "malformed binary data in JSON",
"path", path))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
ret = GNUNET_OK;
}
break;
case TMH_PARSE_JNC_RET_DATA_VAR:
{
void **where = va_arg (argp, void **);
size_t *len = va_arg (argp, size_t *);
const char *str;
int res;
str = json_string_value (root);
if (NULL == str)
{
GNUNET_break_op (0);
ret = (MHD_YES ==
TMH_RESPONSE_reply_internal_error (connection,
"json_string_value() failed"))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
*len = (strlen (str) * 5) / 8;
if (NULL != where)
{
*where = GNUNET_malloc (*len);
res = GNUNET_STRINGS_string_to_data (str,
strlen (str),
*where,
*len);
if (GNUNET_OK != res)
{
GNUNET_break_op (0);
GNUNET_free (*where);
*where = NULL;
*len = 0;
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:O}",
"error", "malformed binary data in JSON",
"path", path))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
}
ret = GNUNET_OK;
}
break;
case TMH_PARSE_JNC_RET_TYPED_JSON:
{
int typ = va_arg (argp, int);
const json_t **r_json = va_arg (argp, const json_t **);
if ( (NULL == root) ||
( (-1 != typ) &&
(json_typeof (root) != typ)) )
{
GNUNET_break_op (0);
*r_json = NULL;
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:i, s:i, s:O}",
"error", "wrong JSON field type",
"type_expected", typ,
"type_actual", json_typeof (root),
"path", path))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
*r_json = root;
json_incref ((json_t *) root);
ret = GNUNET_OK;
}
break;
case TMH_PARSE_JNC_RET_UINT64:
{
uint64_t *r_u64 = va_arg (argp, uint64_t *);
if (json_typeof (root) != JSON_INTEGER)
{
GNUNET_break_op (0);
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:s, s:i, s:O}",
"error", "wrong JSON field type",
"type_expected", "integer",
"type_actual", json_typeof (root),
"path", path))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
*r_u64 = (uint64_t) json_integer_value (root);
ret = GNUNET_OK;
}
break;
case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY:
{
struct TALER_DenominationPublicKey *where;
size_t len;
const char *str;
int res;
void *buf;
where = va_arg (argp,
struct TALER_DenominationPublicKey *);
str = json_string_value (root);
if (NULL == str)
{
GNUNET_break_op (0);
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:O}",
"error", "string expected",
"path", path))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
len = (strlen (str) * 5) / 8;
buf = GNUNET_malloc (len);
res = GNUNET_STRINGS_string_to_data (str,
strlen (str),
buf,
len);
if (GNUNET_OK != res)
{
GNUNET_break_op (0);
GNUNET_free (buf);
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:O}",
"error", "malformed binary data in JSON",
"path", path))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
where->rsa_public_key = GNUNET_CRYPTO_rsa_public_key_decode (buf,
len);
GNUNET_free (buf);
if (NULL == where->rsa_public_key)
{
GNUNET_break_op (0);
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:O}",
"error", "malformed RSA public key in JSON",
"path", path))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
ret = GNUNET_OK;
break;
}
case TMH_PARSE_JNC_RET_RSA_SIGNATURE:
{
struct TALER_DenominationSignature *where;
size_t len;
const char *str;
int res;
void *buf;
where = va_arg (argp,
struct TALER_DenominationSignature *);
str = json_string_value (root);
if (NULL == str)
{
GNUNET_break_op (0);
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:O}",
"error", "string expected",
"path", path))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
len = (strlen (str) * 5) / 8;
buf = GNUNET_malloc (len);
res = GNUNET_STRINGS_string_to_data (str,
strlen (str),
buf,
len);
if (GNUNET_OK != res)
{
GNUNET_break_op (0);
GNUNET_free (buf);
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:O}",
"error", "malformed binary data in JSON",
"path", path))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
where->rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (buf,
len);
GNUNET_free (buf);
if (NULL == where->rsa_signature)
{
GNUNET_break_op (0);
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:O}",
"error", "malformed RSA signature in JSON",
"path", path))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
ret = GNUNET_OK;
break;
}
case TMH_PARSE_JNC_RET_AMOUNT:
{
struct TALER_Amount *where = va_arg (argp, void *);
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_amount (NULL, where),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse ((json_t *) root,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
ret = (MHD_YES !=
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:O}",
"error", "Bad format",
"path", path))
? GNUNET_SYSERR : GNUNET_NO;
break;
}
if (0 != strcmp (where->currency,
TMH_exchange_currency_string))
{
GNUNET_break_op (0);
ret = (MHD_YES !=
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:O, s:s}",
"error", "Currency not supported",
"path", path,
"currency", where->currency))
? GNUNET_SYSERR : GNUNET_NO;
memset (where, 0, sizeof (struct TALER_Amount));
break;
}
ret = GNUNET_OK;
break;
}
case TMH_PARSE_JNC_RET_TIME_ABSOLUTE:
{
struct GNUNET_TIME_Absolute *where = va_arg (argp, void *);
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_absolute_time (NULL, where),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse ((json_t *) root,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
ret = (MHD_YES !=
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:s, s:O}",
"error", "Bad format",
"hint", "expected absolute time",
"path", path))
? GNUNET_SYSERR : GNUNET_NO;
break;
}
ret = GNUNET_OK;
break;
}
default:
GNUNET_break (0);
ret = (MHD_YES ==
TMH_RESPONSE_reply_internal_error (connection,
"unhandled value in switch"))
? GNUNET_NO : GNUNET_SYSERR;
break;
}
}
va_end (argp);
json_decref (path);
return ret;
}
/**
* Parse JSON object into components based on the given field
* specification.
* specification. Generates error response on parse errors.
*
* @param connection the connection to send an error response to
* @param root the JSON node to start the navigation at.
* @param spec field specification for the parser
* @param[in,out] spec field specification for the parser
* @return
* #GNUNET_YES if navigation was successful (caller is responsible
* for freeing allocated variable-size data using
* #TMH_PARSE_release_data() when done)
* #GNUNET_JSON_parse_free() when done)
* #GNUNET_NO if json is malformed, error response was generated
* #GNUNET_SYSERR on internal error
*/
int
TMH_PARSE_json_data (struct MHD_Connection *connection,
const json_t *root,
struct TMH_PARSE_FieldSpecification *spec)
struct GNUNET_JSON_Specification *spec)
{
unsigned int i;
int ret;
const char *error_json_name;
unsigned int error_line;
ret = GNUNET_YES;
for (i=0; NULL != spec[i].field_name; i++)
ret = GNUNET_JSON_parse (root,
spec,
&error_json_name,
&error_line);
if (GNUNET_SYSERR == ret)
{
if (GNUNET_YES != ret)
break;
switch (spec[i].command)
{
case TMH_PARSE_JNC_FIELD:
GNUNET_break (0);
return GNUNET_SYSERR;
case TMH_PARSE_JNC_INDEX:
GNUNET_break (0);
return GNUNET_SYSERR;
case TMH_PARSE_JNC_RET_DATA:
ret = TMH_PARSE_navigate_json (connection,
root,
TMH_PARSE_JNC_FIELD,
spec[i].field_name,
TMH_PARSE_JNC_RET_DATA,
spec[i].destination,
spec[i].destination_size_in);
break;
case TMH_PARSE_JNC_RET_DATA_VAR:
ret = TMH_PARSE_navigate_json (connection,
root,
TMH_PARSE_JNC_FIELD,
spec[i].field_name,
TMH_PARSE_JNC_RET_DATA_VAR,
(void **) spec[i].destination,
spec[i].destination_size_out);
break;
case TMH_PARSE_JNC_RET_TYPED_JSON:
ret = TMH_PARSE_navigate_json (connection,
root,
TMH_PARSE_JNC_FIELD,
spec[i].field_name,
TMH_PARSE_JNC_RET_TYPED_JSON,
spec[i].type,
spec[i].destination);
break;
case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY:
ret = TMH_PARSE_navigate_json (connection,
root,
TMH_PARSE_JNC_FIELD,
spec[i].field_name,
TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY,
spec[i].destination);
break;
case TMH_PARSE_JNC_RET_RSA_SIGNATURE:
ret = TMH_PARSE_navigate_json (connection,
root,
TMH_PARSE_JNC_FIELD,
spec[i].field_name,
TMH_PARSE_JNC_RET_RSA_SIGNATURE,
spec[i].destination);
break;
case TMH_PARSE_JNC_RET_AMOUNT:
GNUNET_assert (sizeof (struct TALER_Amount) ==
spec[i].destination_size_in);
ret = TMH_PARSE_navigate_json (connection,
root,
TMH_PARSE_JNC_FIELD,
spec[i].field_name,
TMH_PARSE_JNC_RET_AMOUNT,
spec[i].destination);
break;
case TMH_PARSE_JNC_RET_TIME_ABSOLUTE:
GNUNET_assert (sizeof (struct GNUNET_TIME_Absolute) ==
spec[i].destination_size_in);
ret = TMH_PARSE_navigate_json (connection,
root,
TMH_PARSE_JNC_FIELD,
spec[i].field_name,
TMH_PARSE_JNC_RET_TIME_ABSOLUTE,
spec[i].destination);
break;
case TMH_PARSE_JNC_RET_UINT64:
GNUNET_assert (sizeof (uint64_t) ==
spec[i].destination_size_in);
ret = TMH_PARSE_navigate_json (connection,
root,
TMH_PARSE_JNC_FIELD,
spec[i].field_name,
TMH_PARSE_JNC_RET_UINT64,
spec[i].destination);
break;
}
if (NULL == error_json_name)
error_json_name = "<no field>";
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:s, s:I}",
"error", "parse error",
"field", error_json_name,
"line", (json_int_t) error_line))
? GNUNET_NO : GNUNET_SYSERR;
return ret;
}
if (GNUNET_YES != ret)
release_data (spec,
i - 1);
return ret;
return GNUNET_YES;
}
/**
* Release all memory allocated for the variable-size fields in
* the parser specification.
* Parse JSON array into components based on the given field
* specification. Generates error response on parse errors.
*
* @param spec specification to free
* @param connection the connection to send an error response to
* @param root the JSON node to start the navigation at.
* @param[in,out] spec field specification for the parser
* @param ... -1-terminated list of array offsets of type 'int'
* @return
* #GNUNET_YES if navigation was successful (caller is responsible
* for freeing allocated variable-size data using
* #GNUNET_JSON_parse_free() when done)
* #GNUNET_NO if json is malformed, error response was generated
* #GNUNET_SYSERR on internal error
*/
void
TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec)
int
TMH_PARSE_json_array (struct MHD_Connection *connection,
const json_t *root,
struct GNUNET_JSON_Specification *spec,
...)
{
unsigned int i;
int ret;
const char *error_json_name;
unsigned int error_line;
va_list ap;
json_int_t dim;
for (i=0; NULL != spec[i].field_name; i++) ;
release_data (spec, i);
va_start (ap, spec);
dim = 0;
while ( (-1 != (ret = va_arg (ap, int))) &&
(NULL != root) )
{
dim++;
root = json_array_get (root, ret);
}
if (NULL == root)
{
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:I}",
"error", "parse error",
"dimension", dim))
? GNUNET_NO : GNUNET_SYSERR;
return ret;
}
ret = GNUNET_JSON_parse (root,
spec,
&error_json_name,
&error_line);
if (GNUNET_SYSERR == ret)
{
if (NULL == error_json_name)
error_json_name = "<no field>";
ret = (MHD_YES ==
TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:s, s:I}",
"error", "parse error",
"field", error_json_name,
"line", (json_int_t) error_line))
? GNUNET_NO : GNUNET_SYSERR;
return ret;
}
return GNUNET_YES;
}
/**
* Generate line in parser specification for 64-bit integer
* given as an integer in JSON.
*
* @param field name of the field
* @param[out] u64 integer to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_uint64 (const char *field,
uint64_t *u64)
{
struct TMH_PARSE_FieldSpecification ret =
{ field, (void *) u64, sizeof (uint64_t), NULL, TMH_PARSE_JNC_RET_UINT64, 0 };
return ret;
}
/**
* Generate line in parser specification for JSON object value.
*
* @param field name of the field
* @param[out] jsonp address of pointer to JSON to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_object (const char *field,
json_t **jsonp)
{
struct TMH_PARSE_FieldSpecification ret =
{ field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_OBJECT };
*jsonp = NULL;
return ret;
}
/**
* Generate line in parser specification for JSON array value.
*
* @param field name of the field
* @param[out] jsonp address of JSON pointer to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_array (const char *field,
json_t **jsonp)
{
struct TMH_PARSE_FieldSpecification ret =
{ field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_ARRAY };
*jsonp = NULL;
return ret;
}
/**
* Generate line in parser specification for an absolute time.
*
* @param field name of the field
* @param[out] atime time to initialize
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_time_abs (const char *field,
struct GNUNET_TIME_Absolute *atime)
{
struct TMH_PARSE_FieldSpecification ret =
{ field, atime, sizeof(struct GNUNET_TIME_Absolute), NULL, TMH_PARSE_JNC_RET_TIME_ABSOLUTE, 0 };
return ret;
}
/**
* Generate line in parser specification for RSA public key.
*
* @param field name of the field
* @param[out] pk key to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_denomination_public_key (const char *field,
struct TALER_DenominationPublicKey *pk)
{
struct TMH_PARSE_FieldSpecification ret =
{ field, pk, 0, NULL, TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, 0 };
pk->rsa_public_key = NULL;
return ret;
}
/**
* Generate line in parser specification for RSA public key.
*
* @param field name of the field
* @param sig the signature to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_denomination_signature (const char *field,
struct TALER_DenominationSignature *sig)
{
struct TMH_PARSE_FieldSpecification ret =
{ field, sig, 0, NULL, TMH_PARSE_JNC_RET_RSA_SIGNATURE, 0 };
sig->rsa_signature = NULL;
return ret;
}
/**
* Generate line in parser specification for an amount.
*
* @param field name of the field
* @param amount a `struct TALER_Amount *` to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_amount (const char *field,
struct TALER_Amount *amount)
{
struct TMH_PARSE_FieldSpecification ret =
{ field, amount, sizeof(struct TALER_Amount), NULL, TMH_PARSE_JNC_RET_AMOUNT, 0 };
memset (amount, 0, sizeof (struct TALER_Amount));
return ret;
}
/**
* Generate line in parser specification for variable-size value.
*
* @param field name of the field
* @param[out] ptr pointer to initialize
* @param[out] ptr_size size to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_variable (const char *field,
void **ptr,
size_t *ptr_size)
{
struct TMH_PARSE_FieldSpecification ret =
{ field, ptr, 0, ptr_size, TMH_PARSE_JNC_RET_DATA_VAR, 0 };
*ptr = NULL;
return ret;
}
/* end of taler-exchange-httpd_parsing.c */

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014, 2015 GNUnet e.V.
Copyright (C) 2014, 2015, 2016 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@ -26,6 +26,7 @@
#include <microhttpd.h>
#include <jansson.h>
#include "taler_util.h"
#include "taler_json_lib.h"
/**
@ -71,149 +72,6 @@ void
TMH_PARSE_post_cleanup_callback (void *con_cls);
/**
* Constants for JSON navigation description.
*/
enum TMH_PARSE_JsonNavigationCommand
{
/**
* Access a field.
* Param: const char *
*/
TMH_PARSE_JNC_FIELD,
/**
* Access an array index.
* Param: int
*/
TMH_PARSE_JNC_INDEX,
/**
* Return base32crockford encoded data of
* constant size.
* Params: (void *, size_t)
*/
TMH_PARSE_JNC_RET_DATA,
/**
* Return base32crockford encoded data of
* variable size.
* Params: (void **, size_t *)
*/
TMH_PARSE_JNC_RET_DATA_VAR,
/**
* Return a json object, which must be
* of the given type (JSON_* type constants,
* or -1 for any type).
* Params: (int, json_t **)
*/
TMH_PARSE_JNC_RET_TYPED_JSON,
/**
* Return a `struct GNUNET_CRYPTO_rsa_PublicKey` which was
* encoded as variable-size base32crockford encoded data.
*/
TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY,
/**
* Return a `struct GNUNET_CRYPTO_rsa_Signature` which was
* encoded as variable-size base32crockford encoded data.
*/
TMH_PARSE_JNC_RET_RSA_SIGNATURE,
/**
* Return a `struct TALER_Amount` which was
* encoded within its own json object.
*/
TMH_PARSE_JNC_RET_AMOUNT,
/**
* Return a `struct GNUNET_TIME_Absolute` which was
* encoded within its own json object.
* Param: struct GNUNET_TIME_Absolute *
*/
TMH_PARSE_JNC_RET_TIME_ABSOLUTE,
/**
* Return a `uint64_t` which was
* encoded as a JSON integer.
* Param: uint64_t *
*/
TMH_PARSE_JNC_RET_UINT64
};
/**
* Navigate through a JSON tree.
*
* 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 ... navigation specification (see `enum TMH_PARSE_JsonNavigationCommand`)
* @return
* #GNUNET_YES if navigation was successful
* #GNUNET_NO if json is malformed, error response was generated
* #GNUNET_SYSERR on internal error
*/
int
TMH_PARSE_navigate_json (struct MHD_Connection *connection,
const json_t *root,
...);
/**
* @brief Specification for how to parse a JSON field.
*/
struct TMH_PARSE_FieldSpecification
{
/**
* Name of the field. NULL only to terminate array.
*/
const char *field_name;
/**
* Where to store the result. Must have exactly
* @e destination_size bytes, except if @e destination_size is zero.
* NULL to skip assignment (but check presence of the value).
*/
void *destination;
/**
* How big should the result be, 0 for variable size. In
* this case, @e destination must be a "void **", pointing
* to a location that is currently NULL and is to be allocated.
*/
size_t destination_size_in;
/**
* @e destination_size_out will then be set to the size of the
* value that was stored in @e destination (useful for
* variable-size allocations).
*/
size_t *destination_size_out;
/**
* Navigation command to use to extract the value. Note that
* #TMH_PARSE_JNC_RET_DATA or #TMH_PARSE_JNC_RET_DATA_VAR must be used for @e
* destination_size_in and @e destination_size_out to have a
* meaning. #TMH_PARSE_JNC_FIELD and #TMH_PARSE_JNC_INDEX must not be used here!
*/
enum TMH_PARSE_JsonNavigationCommand command;
/**
* JSON type to use, only meaningful in connection with a @e command
* value of #TMH_PARSE_JNC_RET_TYPED_JSON. Typical values are
* #JSON_ARRAY and #JSON_OBJECT.
*/
int type;
};
/**
* Parse JSON object into components based on the given field
* specification.
@ -224,139 +82,36 @@ struct TMH_PARSE_FieldSpecification
* @return
* #GNUNET_YES if navigation was successful (caller is responsible
* for freeing allocated variable-size data using
* #TMH_PARSE_release_data() when done)
* #GNUNET_JSON_parse_free() when done)
* #GNUNET_NO if json is malformed, error response was generated
* #GNUNET_SYSERR on internal error
*/
int
TMH_PARSE_json_data (struct MHD_Connection *connection,
const json_t *root,
struct TMH_PARSE_FieldSpecification *spec);
struct GNUNET_JSON_Specification *spec);
/**
* Release all memory allocated for the variable-size fields in
* the parser specification.
* Parse JSON array into components based on the given field
* specification. Generates error response on parse errors.
*
* @param spec specification to free
* @param connection the connection to send an error response to
* @param root the JSON node to start the navigation at.
* @param[in,out] spec field specification for the parser
* @param ... -1-terminated list of array offsets of type 'int'
* @return
* #GNUNET_YES if navigation was successful (caller is responsible
* for freeing allocated variable-size data using
* #GNUNET_JSON_parse_free() when done)
* #GNUNET_NO if json is malformed, error response was generated
* #GNUNET_SYSERR on internal error
*/
void
TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec);
/**
* Generate line in parser specification for fixed-size value.
*
* @param field name of the field
* @param value where to store the value
*/
#define TMH_PARSE_member_fixed(field,value) { field, value, sizeof (*value), NULL, TMH_PARSE_JNC_RET_DATA, 0 }
/**
* Generate line in parser specification for variable-size value.
*
* @param field name of the field
* @param[out] ptr pointer to initialize
* @param[out] ptr_size size to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_variable (const char *field,
void **ptr,
size_t *ptr_size);
/**
* Generate line in parser specification for 64-bit integer
* given as an integer in JSON.
*
* @param field name of the field
* @param[out] u64 integer to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_uint64 (const char *field,
uint64_t *u64);
/**
* Generate line in parser specification for JSON array value.
*
* @param field name of the field
* @param[out] jsonp address of JSON pointer to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_array (const char *field,
json_t **jsonp);
/**
* Generate line in parser specification for JSON object value.
*
* @param field name of the field
* @param[out] jsonp address of pointer to JSON to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_object (const char *field,
json_t **jsonp);
/**
* Generate line in parser specification for RSA public key.
*
* @param field name of the field
* @param[out] pk key to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_denomination_public_key (const char *field,
struct TALER_DenominationPublicKey *pk);
/**
* Generate line in parser specification for RSA public key.
*
* @param field name of the field
* @param sig the signature to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_denomination_signature (const char *field,
struct TALER_DenominationSignature *sig);
/**
* Generate line in parser specification for an amount.
*
* @param field name of the field
* @param[out] amount a `struct TALER_Amount *` to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_amount (const char *field,
struct TALER_Amount *amount);
/**
* Generate line in parser specification for an absolute time.
*
* @param field name of the field
* @param[out] atime time to initialize
* @return corresponding field spec
*/
struct TMH_PARSE_FieldSpecification
TMH_PARSE_member_time_abs (const char *field,
struct GNUNET_TIME_Absolute *atime);
/**
* Generate line in parser specification indicating the end of the spec.
*/
#define TMH_PARSE_MEMBER_END { NULL, NULL, 0, NULL, TMH_PARSE_JNC_FIELD, 0 }
int
TMH_PARSE_json_array (struct MHD_Connection *connection,
const json_t *root,
struct GNUNET_JSON_Specification *spec,
...);
/**
@ -381,28 +136,4 @@ TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection,
size_t out_size);
/**
* Extraxt variable-size base32crockford encoded data from request.
*
* Queues an error response to the connection if the parameter is missing
* or the encoding is invalid.
*
* @param connection the MHD connection
* @param param_name the name of the parameter with the key
* @param[out] out_data pointer to allocate buffer and store the result
* @param[out] out_size set to the size of the buffer allocated in @a out_data
* @return
* #GNUNET_YES if the the argument is present
* #GNUNET_NO if the argument is absent or malformed
* #GNUNET_SYSERR on internal error (error response could not be sent)
*/
int
TMH_PARSE_mhd_request_var_arg_data (struct MHD_Connection *connection,
const char *param_name,
void **out_data,
size_t *out_size);
#endif /* TALER_EXCHANGE_HTTPD_PARSING_H */

View File

@ -192,13 +192,13 @@ get_coin_public_info (struct MHD_Connection *connection,
struct TALER_DenominationSignature sig;
struct TALER_DenominationPublicKey pk;
struct TALER_Amount amount;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_fixed ("coin_pub", &r_melt_detail->coin_info.coin_pub),
TMH_PARSE_member_denomination_signature ("denom_sig", &sig),
TMH_PARSE_member_denomination_public_key ("denom_pub", &pk),
TMH_PARSE_member_fixed ("confirm_sig", &melt_sig),
TMH_PARSE_member_amount ("value_with_fee", &amount),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("coin_pub", &r_melt_detail->coin_info.coin_pub),
TALER_JSON_spec_denomination_signature ("denom_sig", &sig),
TALER_JSON_spec_denomination_public_key ("denom_pub", &pk),
GNUNET_JSON_spec_fixed_auto ("confirm_sig", &melt_sig),
TALER_JSON_spec_amount ("value_with_fee", &amount),
GNUNET_JSON_spec_end ()
};
ret = TMH_PARSE_json_data (connection,
@ -216,7 +216,7 @@ get_coin_public_info (struct MHD_Connection *connection,
TALER_test_coin_valid (&r_melt_detail->coin_info))
{
GNUNET_break_op (0);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
r_melt_detail->coin_info.denom_sig.rsa_signature = NULL;
r_melt_detail->coin_info.denom_pub.rsa_public_key = NULL;
return (MHD_YES ==
@ -409,12 +409,16 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
{
char *buf;
size_t buf_size;
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_denomination_public_key (NULL,
&denom_pubs[i]),
GNUNET_JSON_spec_end ()
};
res = TMH_PARSE_navigate_json (connection,
new_denoms,
TMH_PARSE_JNC_INDEX, (int) i,
TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY,
&denom_pubs[i].rsa_public_key);
res = TMH_PARSE_json_array (connection,
new_denoms,
spec,
i, -1);
if (GNUNET_OK != res)
{
res = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
@ -436,6 +440,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
/* decode JSON data on coin to melt */
struct TALER_AmountNBO melt_amount;
// FIXME: check json_array_get() return value for NULL!
res = get_coin_public_info (connection,
json_array_get (melt_coins, i),
&coin_melt_details[i]);
@ -482,15 +487,23 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
char *link_enc;
size_t link_enc_size;
struct TALER_EXCHANGEDB_RefreshCommitCoin *rcc = &commit_coin[i][j];
struct GNUNET_JSON_Specification coin_spec[] = {
GNUNET_JSON_spec_varsize (NULL,
(void **) &rcc->coin_ev,
&rcc->coin_ev_size),
GNUNET_JSON_spec_end ()
};
struct GNUNET_JSON_Specification link_spec[] = {
GNUNET_JSON_spec_varsize (NULL,
(void **) &link_enc,
&link_enc_size),
GNUNET_JSON_spec_end ()
};
res = TMH_PARSE_navigate_json (connection,
coin_evs,
TMH_PARSE_JNC_INDEX, (int) i,
TMH_PARSE_JNC_INDEX, (int) j,
TMH_PARSE_JNC_RET_DATA_VAR,
&rcc->coin_ev,
&rcc->coin_ev_size);
res = TMH_PARSE_json_array (connection,
coin_evs,
coin_spec,
i, j, -1);
if (GNUNET_OK != res)
{
GNUNET_break_op (0);
@ -501,13 +514,10 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
GNUNET_CRYPTO_hash_context_read (hash_context,
rcc->coin_ev,
rcc->coin_ev_size);
res = TMH_PARSE_navigate_json (connection,
link_encs,
TMH_PARSE_JNC_INDEX, (int) i,
TMH_PARSE_JNC_INDEX, (int) j,
TMH_PARSE_JNC_RET_DATA_VAR,
&link_enc,
&link_enc_size);
res = TMH_PARSE_json_array (connection,
link_encs,
link_spec,
i, j, -1);
if (GNUNET_OK != res)
{
GNUNET_break_op (0);
@ -520,7 +530,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
GNUNET_CRYPTO_hash_context_read (hash_context,
link_enc,
link_enc_size);
GNUNET_free (link_enc);
GNUNET_JSON_parse_free (link_spec);
}
}
@ -531,27 +541,29 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
for (j = 0; j < num_oldcoins; j++)
{
struct TALER_RefreshCommitLinkP *rcl = &commit_link[i][j];
struct GNUNET_JSON_Specification trans_spec[] = {
GNUNET_JSON_spec_fixed_auto (NULL, &rcl->transfer_pub),
GNUNET_JSON_spec_end ()
};
struct GNUNET_JSON_Specification sec_spec[] = {
GNUNET_JSON_spec_fixed_auto (NULL, &rcl->shared_secret_enc),
GNUNET_JSON_spec_end ()
};
res = TMH_PARSE_navigate_json (connection,
transfer_pubs,
TMH_PARSE_JNC_INDEX, (int) i,
TMH_PARSE_JNC_INDEX, (int) j,
TMH_PARSE_JNC_RET_DATA,
&rcl->transfer_pub,
sizeof (struct TALER_TransferPublicKeyP));
res = TMH_PARSE_json_array (connection,
transfer_pubs,
trans_spec,
i, j, -1);
if (GNUNET_OK != res)
{
GNUNET_break_op (0);
res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
goto cleanup;
}
res = TMH_PARSE_navigate_json (connection,
secret_encs,
TMH_PARSE_JNC_INDEX, (int) i,
TMH_PARSE_JNC_INDEX, (int) j,
TMH_PARSE_JNC_RET_DATA,
&rcl->shared_secret_enc,
sizeof (struct TALER_EncryptedLinkSecretP));
res = TMH_PARSE_json_array (connection,
secret_encs,
sec_spec,
i, j, -1);
if (GNUNET_OK != res)
{
GNUNET_break_op (0);
@ -646,15 +658,16 @@ TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh,
unsigned int num_oldcoins;
unsigned int num_newcoins;
json_t *coin_detail;
json_t *trans_detail;
int res;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_array ("new_denoms", &new_denoms),
TMH_PARSE_member_array ("melt_coins", &melt_coins),
TMH_PARSE_member_array ("coin_evs", &coin_evs),
TMH_PARSE_member_array ("link_encs", &link_encs),
TMH_PARSE_member_array ("transfer_pubs", &transfer_pubs),
TMH_PARSE_member_array ("secret_encs", &secret_encs),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_json ("new_denoms", &new_denoms),
GNUNET_JSON_spec_json ("melt_coins", &melt_coins),
GNUNET_JSON_spec_json ("coin_evs", &coin_evs),
GNUNET_JSON_spec_json ("link_encs", &link_encs),
GNUNET_JSON_spec_json ("transfer_pubs", &transfer_pubs),
GNUNET_JSON_spec_json ("secret_encs", &secret_encs),
GNUNET_JSON_spec_end ()
};
res = TMH_PARSE_post_json (connection,
@ -678,43 +691,36 @@ TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh,
if (TALER_CNC_KAPPA != json_array_size (coin_evs))
{
GNUNET_break_op (0);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_arg_invalid (connection,
"coin_evs");
}
if (TALER_CNC_KAPPA != json_array_size (transfer_pubs))
{
GNUNET_break_op (0);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_arg_invalid (connection,
"transfer_pubs");
}
res = TMH_PARSE_navigate_json (connection,
coin_evs,
TMH_PARSE_JNC_INDEX, (int) 0,
TMH_PARSE_JNC_RET_TYPED_JSON,
JSON_ARRAY, &coin_detail);
if (GNUNET_OK != res)
coin_detail = json_array_get (coin_evs, 0);
if (NULL == coin_detail)
{
// FIXME: generate proper HTTP response!
GNUNET_break_op (0);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
num_newcoins = json_array_size (coin_detail);
json_decref (coin_detail);
res = TMH_PARSE_navigate_json (connection,
transfer_pubs,
TMH_PARSE_JNC_INDEX, (int) 0,
TMH_PARSE_JNC_RET_TYPED_JSON,
JSON_ARRAY, &coin_detail);
if (GNUNET_OK != res)
trans_detail = json_array_get (transfer_pubs, 0);
if (NULL == trans_detail)
{
// FIXME: generate proper HTTP response!
GNUNET_break_op (0);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
num_oldcoins = json_array_size (coin_detail);
json_decref (coin_detail);
num_oldcoins = json_array_size (trans_detail);
res = handle_refresh_melt_json (connection,
new_denoms,
melt_coins,
@ -724,7 +730,7 @@ TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh,
num_newcoins,
coin_evs,
link_encs);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return res;
}
@ -763,15 +769,16 @@ handle_refresh_reveal_json (struct MHD_Connection *connection,
break;
for (j = 0; j < num_oldcoins; j++)
{
struct GNUNET_JSON_Specification tp_spec[] = {
GNUNET_JSON_spec_fixed_auto (NULL, &transfer_privs[i][j]),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK != res)
break;
res = TMH_PARSE_navigate_json (connection,
tp_json,
TMH_PARSE_JNC_INDEX, (int) i,
TMH_PARSE_JNC_INDEX, (int) j,
TMH_PARSE_JNC_RET_DATA,
&transfer_privs[i][j],
sizeof (struct TALER_TransferPrivateKeyP));
res = TMH_PARSE_json_array (connection,
tp_json,
tp_spec,
i, j, -1);
GNUNET_break_op (GNUNET_OK == res);
}
}
@ -817,10 +824,10 @@ TMH_REFRESH_handler_refresh_reveal (struct TMH_RequestHandler *rh,
json_t *reveal_detail;
json_t *root;
json_t *transfer_privs;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_fixed ("session_hash", &session_hash),
TMH_PARSE_member_array ("transfer_privs", &transfer_privs),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("session_hash", &session_hash),
GNUNET_JSON_spec_json ("transfer_privs", &transfer_privs),
GNUNET_JSON_spec_end ()
};
res = TMH_PARSE_post_json (connection,
@ -846,30 +853,25 @@ TMH_REFRESH_handler_refresh_reveal (struct TMH_RequestHandler *rh,
/* Note we do +1 as 1 row (cut-and-choose!) is missing! */
if (TALER_CNC_KAPPA != json_array_size (transfer_privs) + 1)
{
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
GNUNET_break_op (0);
return TMH_RESPONSE_reply_arg_invalid (connection,
"transfer_privs");
}
res = TMH_PARSE_navigate_json (connection,
transfer_privs,
TMH_PARSE_JNC_INDEX, 0,
TMH_PARSE_JNC_RET_TYPED_JSON,
JSON_ARRAY,
&reveal_detail);
if (GNUNET_OK != res)
reveal_detail = json_array_get (transfer_privs, 0);
if (NULL == reveal_detail)
{
TMH_PARSE_release_data (spec);
// FIXME: generate proper HTTP response!
GNUNET_JSON_parse_free (spec);
GNUNET_break_op (0);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
num_oldcoins = json_array_size (reveal_detail);
json_decref (reveal_detail);
res = handle_refresh_reveal_json (connection,
&session_hash,
num_oldcoins,
transfer_privs);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return res;
}

View File

@ -101,17 +101,17 @@ TMH_RESERVE_handler_reserve_withdraw (struct TMH_RequestHandler *rh,
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
struct TMH_KS_StateHandle *ks;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_variable ("coin_ev",
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_varsize ("coin_ev",
(void **) &blinded_msg,
&blinded_msg_len),
TMH_PARSE_member_fixed ("reserve_pub",
GNUNET_JSON_spec_fixed_auto ("reserve_pub",
&wsrd.reserve_pub),
TMH_PARSE_member_fixed ("reserve_sig",
GNUNET_JSON_spec_fixed_auto ("reserve_sig",
&signature),
TMH_PARSE_member_denomination_public_key ("denom_pub",
TALER_JSON_spec_denomination_public_key ("denom_pub",
&denomination_pub),
TMH_PARSE_MEMBER_END
GNUNET_JSON_spec_end ()
};
res = TMH_PARSE_post_json (connection,
@ -135,7 +135,7 @@ TMH_RESERVE_handler_reserve_withdraw (struct TMH_RequestHandler *rh,
TMH_KS_DKU_WITHDRAW);
if (NULL == dki)
{
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
TMH_KS_release (ks);
return TMH_RESPONSE_reply_arg_unknown (connection,
"denom_pub");
@ -169,7 +169,7 @@ TMH_RESERVE_handler_reserve_withdraw (struct TMH_RequestHandler *rh,
&wsrd.reserve_pub.eddsa_pub))
{
TALER_LOG_WARNING ("Client supplied invalid signature for /reserve/withdraw request\n");
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_signature_invalid (connection,
"reserve_sig");
}
@ -179,7 +179,7 @@ TMH_RESERVE_handler_reserve_withdraw (struct TMH_RequestHandler *rh,
blinded_msg,
blinded_msg_len,
&signature);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return res;
}

View File

@ -63,9 +63,9 @@ TMH_TEST_handler_test_base32 (struct TMH_RequestHandler *rh,
void *in_ptr;
size_t in_ptr_size;
struct GNUNET_HashCode hc;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_varsize ("input", &in_ptr, &in_ptr_size),
GNUNET_JSON_spec_end ()
};
res = TMH_PARSE_post_json (connection,
@ -85,7 +85,7 @@ TMH_TEST_handler_test_base32 (struct TMH_RequestHandler *rh,
GNUNET_CRYPTO_hash (in_ptr,
in_ptr_size,
&hc);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
json_decref (json);
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_OK,
@ -126,10 +126,10 @@ TMH_TEST_handler_test_encrypt (struct TMH_RequestHandler *rh,
struct GNUNET_CRYPTO_SymmetricSessionKey skey;
void *in_ptr;
size_t in_ptr_size;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size),
TMH_PARSE_member_fixed ("key_hash", &key),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_varsize ("input", &in_ptr, &in_ptr_size),
GNUNET_JSON_spec_fixed_auto ("key_hash", &key),
GNUNET_JSON_spec_end ()
};
char *out;
@ -168,7 +168,7 @@ TMH_TEST_handler_test_encrypt (struct TMH_RequestHandler *rh,
json = GNUNET_JSON_from_data (out,
in_ptr_size);
GNUNET_free (out);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:o}",
@ -206,9 +206,9 @@ TMH_TEST_handler_test_hkdf (struct TMH_RequestHandler *rh,
struct GNUNET_HashCode hc;
void *in_ptr;
size_t in_ptr_size;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_variable ("input", &in_ptr, &in_ptr_size),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_varsize ("input", &in_ptr, &in_ptr_size),
GNUNET_JSON_spec_end ()
};
res = TMH_PARSE_post_json (connection,
@ -231,7 +231,7 @@ TMH_TEST_handler_test_hkdf (struct TMH_RequestHandler *rh,
in_ptr,
in_ptr_size,
NULL, 0);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
json = GNUNET_JSON_from_data (&hc,
sizeof (struct GNUNET_HashCode));
return TMH_RESPONSE_reply_json_pack (connection,
@ -268,10 +268,10 @@ TMH_TEST_handler_test_ecdhe (struct TMH_RequestHandler *rh,
struct GNUNET_CRYPTO_EcdhePublicKey pub;
struct GNUNET_CRYPTO_EcdhePrivateKey priv;
struct GNUNET_HashCode hc;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_fixed ("ecdhe_pub", &pub),
TMH_PARSE_member_fixed ("ecdhe_priv", &priv),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("ecdhe_pub", &pub),
GNUNET_JSON_spec_fixed_auto ("ecdhe_priv", &priv),
GNUNET_JSON_spec_end ()
};
res = TMH_PARSE_post_json (connection,
@ -294,11 +294,11 @@ TMH_TEST_handler_test_ecdhe (struct TMH_RequestHandler *rh,
&pub,
&hc))
{
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_internal_error (connection,
"Failed to perform ECDH");
}
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:o}",
@ -335,10 +335,10 @@ TMH_TEST_handler_test_eddsa (struct TMH_RequestHandler *rh,
struct GNUNET_CRYPTO_EddsaPublicKey pub;
struct GNUNET_CRYPTO_EddsaSignature sig;
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_fixed ("eddsa_pub", &pub),
TMH_PARSE_member_fixed ("eddsa_sig", &sig),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("eddsa_pub", &pub),
GNUNET_JSON_spec_fixed_auto ("eddsa_sig", &sig),
GNUNET_JSON_spec_end ()
};
struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
@ -365,11 +365,11 @@ TMH_TEST_handler_test_eddsa (struct TMH_RequestHandler *rh,
&sig,
&pub))
{
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_signature_invalid (connection,
"eddsa_sig");
}
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
pk = GNUNET_CRYPTO_eddsa_key_create ();
purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_TEST_EDDSA);
if (GNUNET_OK !=
@ -466,9 +466,9 @@ TMH_TEST_handler_test_rsa_sign (struct TMH_RequestHandler *rh,
struct GNUNET_CRYPTO_rsa_Signature *sig;
void *in_ptr;
size_t in_ptr_size;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_variable ("blind_ev", &in_ptr, &in_ptr_size),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_varsize ("blind_ev", &in_ptr, &in_ptr_size),
GNUNET_JSON_spec_end ()
};
res = TMH_PARSE_post_json (connection,
@ -491,7 +491,7 @@ TMH_TEST_handler_test_rsa_sign (struct TMH_RequestHandler *rh,
if (NULL == rsa_pk)
{
GNUNET_break (0);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_internal_error (connection,
"Failed to create RSA key");
}
@ -501,11 +501,11 @@ TMH_TEST_handler_test_rsa_sign (struct TMH_RequestHandler *rh,
if (NULL == sig)
{
GNUNET_break (0);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_internal_error (connection,
"Failed to RSA-sign");
}
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
res = TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:o}",
@ -542,11 +542,11 @@ TMH_TEST_handler_test_transfer (struct TMH_RequestHandler *rh,
struct TALER_EncryptedLinkSecretP secret_enc;
struct TALER_TransferPrivateKeyP trans_priv;
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_fixed ("secret_enc", &secret_enc),
TMH_PARSE_member_fixed ("trans_priv", &trans_priv),
TMH_PARSE_member_fixed ("coin_pub", &coin_pub),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("secret_enc", &secret_enc),
GNUNET_JSON_spec_fixed_auto ("trans_priv", &trans_priv),
GNUNET_JSON_spec_fixed_auto ("coin_pub", &coin_pub),
GNUNET_JSON_spec_end ()
};
struct TALER_LinkSecretP secret;
@ -571,7 +571,7 @@ TMH_TEST_handler_test_transfer (struct TMH_RequestHandler *rh,
&coin_pub,
&secret))
{
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
return TMH_RESPONSE_reply_internal_error (connection,
"Failed to decrypt secret");
}

View File

@ -121,14 +121,14 @@ TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh,
struct TALER_DepositTrackPS tps;
uint64_t transaction_id;
struct TALER_MerchantSignatureP merchant_sig;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_fixed ("H_wire", &tps.h_wire),
TMH_PARSE_member_fixed ("H_contract", &tps.h_contract),
TMH_PARSE_member_fixed ("coin_pub", &tps.coin_pub),
TMH_PARSE_member_uint64 ("transaction_id", &transaction_id),
TMH_PARSE_member_fixed ("merchant_pub", &tps.merchant),
TMH_PARSE_member_fixed ("merchant_sig", &merchant_sig),
TMH_PARSE_MEMBER_END
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("H_wire", &tps.h_wire),
GNUNET_JSON_spec_fixed_auto ("H_contract", &tps.h_contract),
GNUNET_JSON_spec_fixed_auto ("coin_pub", &tps.coin_pub),
GNUNET_JSON_spec_uint64 ("transaction_id", &transaction_id),
GNUNET_JSON_spec_fixed_auto ("merchant_pub", &tps.merchant),
GNUNET_JSON_spec_fixed_auto ("merchant_sig", &merchant_sig),
GNUNET_JSON_spec_end ()
};
res = TMH_PARSE_post_json (connection,
@ -156,7 +156,7 @@ TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh,
&tps.merchant,
&merchant_sig,
transaction_id);
TMH_PARSE_release_data (spec);
GNUNET_JSON_parse_free (spec);
json_decref (json);
return res;
}

View File

@ -57,6 +57,30 @@ TALER_JSON_spec_amount (const char *name,
struct TALER_Amount *r_amount);
/**
* Generate line in parser specification for denomination public key.
*
* @param field name of the field
* @param[out] pk key to initialize
* @return corresponding field spec
*/
struct GNUNET_JSON_Specification
TALER_JSON_spec_denomination_public_key (const char *field,
struct TALER_DenominationPublicKey *pk);
/**
* Generate line in parser specification for denomination signature.
*
* @param field name of the field
* @param sig the signature to initialize
* @return corresponding field spec
*/
struct GNUNET_JSON_Specification
TALER_JSON_spec_denomination_signature (const char *field,
struct TALER_DenominationSignature *sig);
/**
* Hash a JSON for binary signing.
*

View File

@ -143,4 +143,36 @@ TALER_JSON_spec_amount (const char *name,
}
/**
* Generate line in parser specification for denomination public key.
*
* @param field name of the field
* @param[out] pk key to initialize
* @return corresponding field spec
*/
struct GNUNET_JSON_Specification
TALER_JSON_spec_denomination_public_key (const char *field,
struct TALER_DenominationPublicKey *pk)
{
return GNUNET_JSON_spec_rsa_public_key (field,
&pk->rsa_public_key);
}
/**
* Generate line in parser specification for denomination signature.
*
* @param field name of the field
* @param sig the signature to initialize
* @return corresponding field spec
*/
struct GNUNET_JSON_Specification
TALER_JSON_spec_denomination_signature (const char *field,
struct TALER_DenominationSignature *sig)
{
return GNUNET_JSON_spec_rsa_signature (field,
&sig->rsa_signature);
}
/* end of json/json_helper.c */