more shared logic for argument/header parsing

This commit is contained in:
Christian Grothoff 2023-05-04 14:42:06 +02:00
parent 0b8752bb1b
commit 4c1a2c0307
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
8 changed files with 380 additions and 220 deletions

View File

@ -64,6 +64,12 @@ struct DepositWtidContext
*/
struct TALER_WireTransferIdentifierRawP wtid;
/**
* Signature by the merchant.
*/
struct TALER_MerchantSignatureP merchant_sig;
/**
* Set by #handle_wtid data to the coin's contribution to the wire transfer.
*/
@ -275,89 +281,103 @@ handle_track_transaction_request (
}
/**
* Function called to clean up a context.
*
* @param rc request context with data to clean up
*/
static void
dwc_cleaner (struct TEH_RequestContext *rc)
{
struct DepositWtidContext *ctx = rc->rh_ctx;
GNUNET_free (ctx);
}
MHD_RESULT
TEH_handler_deposits_get (struct TEH_RequestContext *rc,
const char *const args[4])
{
enum GNUNET_GenericReturnValue res;
struct TALER_MerchantSignatureP merchant_sig;
struct DepositWtidContext ctx;
struct DepositWtidContext *ctx = rc->rh_ctx;
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[0],
strlen (args[0]),
&ctx.h_wire,
sizeof (ctx.h_wire)))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_H_WIRE,
args[0]);
}
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[1],
strlen (args[1]),
&ctx.merchant,
sizeof (ctx.merchant)))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_MERCHANT_PUB,
args[1]);
}
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[2],
strlen (args[2]),
&ctx.h_contract_terms,
sizeof (ctx.h_contract_terms)))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_H_CONTRACT_TERMS,
args[2]);
}
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[3],
strlen (args[3]),
&ctx.coin_pub,
sizeof (ctx.coin_pub)))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_COIN_PUB,
args[3]);
}
res = TALER_MHD_parse_request_arg_data (rc->connection,
"merchant_sig",
&merchant_sig,
sizeof (merchant_sig));
if (GNUNET_SYSERR == res)
return MHD_NO; /* internal error */
if (GNUNET_NO == res)
return MHD_YES; /* parse error */
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
if (NULL == ctx)
{
ctx = GNUNET_new (struct DepositWtidContext);
rc->rh_ctx = ctx;
rc->rh_cleaner = &dwc_cleaner;
if (GNUNET_OK !=
TALER_merchant_deposit_verify (&ctx.merchant,
&ctx.coin_pub,
&ctx.h_contract_terms,
&ctx.h_wire,
&merchant_sig))
GNUNET_STRINGS_string_to_data (args[0],
strlen (args[0]),
&ctx->h_wire,
sizeof (ctx->h_wire)))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_EXCHANGE_DEPOSITS_GET_MERCHANT_SIGNATURE_INVALID,
NULL);
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_H_WIRE,
args[0]);
}
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[1],
strlen (args[1]),
&ctx->merchant,
sizeof (ctx->merchant)))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_MERCHANT_PUB,
args[1]);
}
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[2],
strlen (args[2]),
&ctx->h_contract_terms,
sizeof (ctx->h_contract_terms)))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_H_CONTRACT_TERMS,
args[2]);
}
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[3],
strlen (args[3]),
&ctx->coin_pub,
sizeof (ctx->coin_pub)))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_COIN_PUB,
args[3]);
}
TALER_MHD_parse_request_arg_auto_t (rc->connection,
"merchant_sig",
&ctx->merchant_sig);
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
{
if (GNUNET_OK !=
TALER_merchant_deposit_verify (&ctx->merchant,
&ctx->coin_pub,
&ctx->h_contract_terms,
&ctx->h_wire,
&ctx->merchant_sig))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_EXCHANGE_DEPOSITS_GET_MERCHANT_SIGNATURE_INVALID,
NULL);
}
}
}
return handle_track_transaction_request (rc->connection,
&ctx);
ctx);
}

View File

@ -520,34 +520,8 @@ TEH_handler_kyc_check (
"usertype");
}
{
const char *ts;
ts = MHD_lookup_connection_value (rc->connection,
MHD_GET_ARGUMENT_KIND,
"timeout_ms");
if (NULL != ts)
{
char dummy;
unsigned long long tms;
if (1 !=
sscanf (ts,
"%llu%c",
&tms,
&dummy))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"timeout_ms");
}
kyp->timeout = GNUNET_TIME_relative_to_absolute (
GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
tms));
}
}
TALER_MHD_parse_request_timeout (rc->connection,
&kyp->timeout);
}
if ( (NULL == kyp->eh) &&

View File

@ -297,7 +297,6 @@ TEH_handler_kyc_proof (
{
struct KycProofContext *kpc = rc->rh_ctx;
const char *provider_section_or_logic = args[0];
const char *h_payto;
if (NULL == kpc)
{
@ -310,33 +309,13 @@ TEH_handler_kyc_proof (
TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
"'/kyc-proof/$PROVIDER_SECTION?state=$H_PAYTO' required");
}
h_payto = MHD_lookup_connection_value (rc->connection,
MHD_GET_ARGUMENT_KIND,
"state");
if (NULL == h_payto)
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MISSING,
"h_payto");
}
kpc = GNUNET_new (struct KycProofContext);
kpc->rc = rc;
rc->rh_ctx = kpc;
rc->rh_cleaner = &clean_kpc;
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (h_payto,
strlen (h_payto),
&kpc->h_payto,
sizeof (kpc->h_payto)))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"h_payto");
}
TALER_MHD_parse_request_arg_auto_t (rc->connection,
"state",
&kpc->h_payto);
if (GNUNET_OK !=
TALER_KYCLOGIC_lookup_logic (provider_section_or_logic,
&kpc->logic,

View File

@ -57,29 +57,9 @@ TEH_handler_purses_delete (
TALER_EC_EXCHANGE_GENERIC_PURSE_PUB_MALFORMED,
args[0]);
}
{
const char *sig;
sig = MHD_lookup_connection_value (connection,
MHD_HEADER_KIND,
"Taler-Purse-Signature");
if ( (NULL == sig) ||
(GNUNET_OK !=
GNUNET_STRINGS_string_to_data (sig,
strlen (sig),
&purse_sig,
sizeof (purse_sig))) )
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
(NULL == sig)
? TALER_EC_GENERIC_PARAMETER_MISSING
: TALER_EC_GENERIC_PARAMETER_MALFORMED,
"Taler-Purse-Signature");
}
}
TALER_MHD_parse_request_header_auto_t (connection,
"Taler-Purse-Signature",
&purse_sig);
if (GNUNET_OK !=
TALER_wallet_purse_delete_verify (&purse_pub,
&purse_sig))

View File

@ -243,36 +243,8 @@ TEH_handler_purses_get (struct TEH_RequestContext *rc,
args[1]);
}
{
const char *long_poll_timeout_ms;
long_poll_timeout_ms
= MHD_lookup_connection_value (rc->connection,
MHD_GET_ARGUMENT_KIND,
"timeout_ms");
if (NULL != long_poll_timeout_ms)
{
unsigned int timeout_ms;
char dummy;
struct GNUNET_TIME_Relative timeout;
if (1 != sscanf (long_poll_timeout_ms,
"%u%c",
&timeout_ms,
&dummy))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"timeout_ms (must be non-negative number)");
}
timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
timeout_ms);
gc->timeout = GNUNET_TIME_relative_to_absolute (timeout);
}
}
TALER_MHD_parse_request_timeout (rc->connection,
&gc->timeout);
if ( (GNUNET_TIME_absolute_is_future (gc->timeout)) &&
(NULL == gc->eh) )
{

View File

@ -178,9 +178,6 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc,
if (NULL == rp)
{
struct GNUNET_TIME_Relative timeout
= GNUNET_TIME_UNIT_ZERO;
rp = GNUNET_new (struct ReservePoller);
rp->connection = rc->connection;
rp->rc = rc;
@ -201,34 +198,8 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc,
TALER_EC_GENERIC_RESERVE_PUB_MALFORMED,
args[0]);
}
{
const char *long_poll_timeout_ms;
long_poll_timeout_ms
= MHD_lookup_connection_value (rc->connection,
MHD_GET_ARGUMENT_KIND,
"timeout_ms");
if (NULL != long_poll_timeout_ms)
{
unsigned int timeout_ms;
char dummy;
if (1 != sscanf (long_poll_timeout_ms,
"%u%c",
&timeout_ms,
&dummy))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"timeout_ms (must be non-negative number)");
}
timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
timeout_ms);
}
}
rp->timeout = GNUNET_TIME_relative_to_absolute (timeout);
TALER_MHD_parse_request_timeout (rc->connection,
&rp->timeout);
}
if ( (GNUNET_TIME_absolute_is_future (rp->timeout)) &&

View File

@ -437,7 +437,47 @@ TALER_MHD_parse_json_array (struct MHD_Connection *connection,
/**
* Extract fixed-size base32crockford encoded data from request.
* Extract optional "timeout_ms" argument from request.
*
* @param connection the MHD connection
* @param[out] expiration set to #GNUNET_TIME_UNIT_ZERO_ABS if there was no timeout,
* the current time plus the value given under "timeout_ms" otherwise
* @return #GNUNET_OK on success, #GNUNET_NO if an
* error was returned on @a connection (caller should return #MHD_YES) and
* #GNUNET_SYSERR if we failed to return an error (caller should return #MHD_NO)
*/
enum GNUNET_GenericReturnValue
TALER_MHD_parse_request_arg_timeout (struct MHD_Connection *connection,
struct GNUNET_TIME_Absolute *expiration);
/**
* Extract optional "timeout_ms" argument from request.
* Macro that *returns* #MHD_YES/#MHD_NO if the "timeout_ms"
* argument existed but failed to parse.
*
* @param connection the MHD connection
* @param[out] expiration set to #GNUNET_TIME_UNIT_ZERO_ABS if there was no timeout,
* the current time plus the value given under "timeout_ms" otherwise
*/
#define TALER_MHD_parse_request_timeout(connection,expiration) \
do { \
switch (TALER_MHD_parse_request_arg_timeout (connection, \
expiration)) \
{ \
case GNUNET_SYSERR: \
GNUNET_break (0); \
return MHD_NO; \
case GNUNET_NO: \
GNUNET_break_op (0); \
case GNUNET_OK: \
break; \
} \
} while (0)
/**
* Extract fixed-size base32crockford encoded data from request argument.
*
* Queues an error response to the connection if the parameter is missing or
* invalid.
@ -446,16 +486,152 @@ TALER_MHD_parse_json_array (struct MHD_Connection *connection,
* @param param_name the name of the parameter with the key
* @param[out] out_data pointer to store the result
* @param out_size expected size of @a out_data
* @param[out] present set to true if argument was found
* @return
* #GNUNET_YES if the the argument is present
* #GNUNET_NO if the argument is absent or malformed
* #GNUNET_NO if the argument is malformed
* #GNUNET_SYSERR on internal error (error response could not be sent)
*/
enum GNUNET_GenericReturnValue
TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection,
const char *param_name,
void *out_data,
size_t out_size);
size_t out_size,
bool *present);
/**
* Extract fixed-size base32crockford encoded data from request header.
*
* Queues an error response to the connection if the parameter is missing or
* invalid.
*
* @param connection the MHD connection
* @param header_name the name of the HTTP header with the value
* @param[out] out_data pointer to store the result
* @param out_size expected size of @a out_data
* @param[out] present set to true if argument was found
* @return
* #GNUNET_YES if the the argument is present
* #GNUNET_NO if the argument is malformed
* #GNUNET_SYSERR on internal error (error response could not be sent)
*/
enum GNUNET_GenericReturnValue
TALER_MHD_parse_request_header_data (struct MHD_Connection *connection,
const char *header_name,
void *out_data,
size_t out_size,
bool *present);
/**
* Extract fixed-size base32crockford encoded data from request.
*
* @param connection the MHD connection
* @param name the name of the parameter with the key
* @param[out] out_data pointer to store the result, type must determine size
* @param[in,out] required pass true to require presence of this argument; if 'false'
* set to true if the argument was found
* @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)
*/
#define TALER_MHD_parse_request_arg_auto(connection,name,val,required) \
do { \
bool p; \
switch (TALER_MHD_parse_request_arg_data (connection, name, \
val, sizeof (*val), &p)) \
{ \
case GNUNET_SYSERR: \
GNUNET_break (0); \
return MHD_NO; \
case GNUNET_NO: \
GNUNET_break_op (0); \
return MHD_YES; \
case GNUNET_OK: \
if (required & (! p)) \
return TALER_MHD_reply_with_error ( \
connection, \
MHD_HTTP_BAD_REQUEST, \
TALER_EC_GENERIC_PARAMETER_MISSING, \
name); \
required = p; \
break; \
} \
} while (0)
/**
* Extract required fixed-size base32crockford encoded data from request.
*
* @param connection the MHD connection
* @param name the name of the parameter with the key
* @param[out] out_data pointer to store the result, type must determine size
* @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)
*/
#define TALER_MHD_parse_request_arg_auto_t(connection,name,val) \
do { \
bool b = true; \
TALER_MHD_parse_request_arg_auto (connection,name,val,b); \
} while (0)
/**
* Extract fixed-size base32crockford encoded data from request.
*
* @param connection the MHD connection
* @param name the name of the header with the key
* @param[out] out_data pointer to store the result, type must determine size
* @param[in,out] required pass true to require presence of this argument; if 'false'
* set to true if the argument was found
* @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)
*/
#define TALER_MHD_parse_request_header_auto(connection,name,val,required) \
do { \
bool p; \
switch (TALER_MHD_parse_request_header_data (connection, name, \
val, sizeof (*val), &p)) \
{ \
case GNUNET_SYSERR: \
GNUNET_break (0); \
return MHD_NO; \
case GNUNET_NO: \
GNUNET_break_op (0); \
return MHD_YES; \
case GNUNET_OK: \
if (required & (! p)) \
return TALER_MHD_reply_with_error ( \
connection, \
MHD_HTTP_BAD_REQUEST, \
TALER_EC_GENERIC_PARAMETER_MISSING, \
name); \
required = p; \
break; \
} \
} while (0)
/**
* Extract required fixed-size base32crockford encoded data from request.
*
* @param connection the MHD connection
* @param name the name of the header with the key
* @param[out] out_data pointer to store the result, type must determine size
* @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)
*/
#define TALER_MHD_parse_request_header_auto_t(connection,name,val) \
do { \
bool b = true; \
TALER_MHD_parse_request_header_auto (connection,name,val,b); \
} while (0)
/**

View File

@ -86,25 +86,40 @@ TALER_MHD_parse_post_cleanup_callback (void *con_cls)
}
enum GNUNET_GenericReturnValue
TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection,
const char *param_name,
void *out_data,
size_t out_size)
/**
* Extract fixed-size base32crockford encoded data from request.
*
* 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 HTTP key with the value
* @param kind whether to extract from header, argument or footer
* @param[out] out_data pointer to store the result
* @param out_size expected size of @a out_data
* @param[out] present set to true if argument was found
* @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)
*/
static enum GNUNET_GenericReturnValue
parse_request_data (struct MHD_Connection *connection,
const char *param_name,
enum MHD_ValueKind kind,
void *out_data,
size_t out_size,
bool *present)
{
const char *str;
str = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
kind,
param_name);
if (NULL == str)
{
return (MHD_NO ==
TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MISSING,
param_name))
? GNUNET_SYSERR : GNUNET_NO;
*present = false;
return GNUNET_OK;
}
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (str,
@ -117,6 +132,79 @@ TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
param_name))
? GNUNET_SYSERR : GNUNET_NO;
*present = true;
return GNUNET_OK;
}
enum GNUNET_GenericReturnValue
TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection,
const char *param_name,
void *out_data,
size_t out_size,
bool *present)
{
return parse_request_data (connection,
param_name,
MHD_GET_ARGUMENT_KIND,
out_data,
out_size,
present);
}
enum GNUNET_GenericReturnValue
TALER_MHD_parse_request_header_data (struct MHD_Connection *connection,
const char *header_name,
void *out_data,
size_t out_size,
bool *present)
{
return parse_request_data (connection,
header_name,
MHD_HEADER_KIND,
out_data,
out_size,
present);
}
enum GNUNET_GenericReturnValue
TALER_MHD_parse_request_arg_timeout (struct MHD_Connection *connection,
struct GNUNET_TIME_Absolute *expiration)
{
const char *ts;
char dummy;
unsigned long long tms;
ts = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"timeout_ms");
if (NULL == ts)
{
*expiration = GNUNET_TIME_UNIT_ZERO_ABS;
return GNUNET_OK;
}
if (1 !=
sscanf (ts,
"%llu%c",
&tms,
&dummy))
{
MHD_RESULT mret;
GNUNET_break_op (0);
mret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"timeout_ms");
return (MHD_YES == mret)
? GNUNET_NO
: GNUNET_SYSERR;
}
*expiration = GNUNET_TIME_relative_to_absolute (
GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
tms));
return GNUNET_OK;
}