diff --git a/src/exchange/taler-exchange-httpd_deposits_get.c b/src/exchange/taler-exchange-httpd_deposits_get.c index ebbb13e08..26c9e2618 100644 --- a/src/exchange/taler-exchange-httpd_deposits_get.c +++ b/src/exchange/taler-exchange-httpd_deposits_get.c @@ -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); } diff --git a/src/exchange/taler-exchange-httpd_kyc-check.c b/src/exchange/taler-exchange-httpd_kyc-check.c index bf4e4dea1..0372573bb 100644 --- a/src/exchange/taler-exchange-httpd_kyc-check.c +++ b/src/exchange/taler-exchange-httpd_kyc-check.c @@ -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) && diff --git a/src/exchange/taler-exchange-httpd_kyc-proof.c b/src/exchange/taler-exchange-httpd_kyc-proof.c index 6d06f0c82..9668ee54c 100644 --- a/src/exchange/taler-exchange-httpd_kyc-proof.c +++ b/src/exchange/taler-exchange-httpd_kyc-proof.c @@ -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, diff --git a/src/exchange/taler-exchange-httpd_purses_delete.c b/src/exchange/taler-exchange-httpd_purses_delete.c index 58cc78250..5bf7c24c9 100644 --- a/src/exchange/taler-exchange-httpd_purses_delete.c +++ b/src/exchange/taler-exchange-httpd_purses_delete.c @@ -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)) diff --git a/src/exchange/taler-exchange-httpd_purses_get.c b/src/exchange/taler-exchange-httpd_purses_get.c index 434798a80..613372357 100644 --- a/src/exchange/taler-exchange-httpd_purses_get.c +++ b/src/exchange/taler-exchange-httpd_purses_get.c @@ -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) ) { diff --git a/src/exchange/taler-exchange-httpd_reserves_get.c b/src/exchange/taler-exchange-httpd_reserves_get.c index 21c0b74aa..3ffbda293 100644 --- a/src/exchange/taler-exchange-httpd_reserves_get.c +++ b/src/exchange/taler-exchange-httpd_reserves_get.c @@ -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)) && diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h index b64231352..e2e8ecb08 100644 --- a/src/include/taler_mhd_lib.h +++ b/src/include/taler_mhd_lib.h @@ -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) /** diff --git a/src/mhd/mhd_parsing.c b/src/mhd/mhd_parsing.c index ee647f4b7..e76450831 100644 --- a/src/mhd/mhd_parsing.c +++ b/src/mhd/mhd_parsing.c @@ -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; }