merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit f02036b3cb59135c5df2fda57627e42f344b5a96
parent 964478942eb1c85114d88e6298f8a8e8759c0ded
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu, 20 Oct 2016 15:09:13 +0200

add 'code' with error code details to merchant backend error responses (#4497)

Diffstat:
Msrc/backend/taler-merchant-httpd_contract.c | 30++++++++++++++++++------------
Msrc/backend/taler-merchant-httpd_history.c | 16++++++++++------
Msrc/backend/taler-merchant-httpd_parsing.c | 11+++++++++--
Msrc/backend/taler-merchant-httpd_pay.c | 74++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/backend/taler-merchant-httpd_responses.c | 72+++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/backend/taler-merchant-httpd_responses.h | 28++++++++++++++++++++++++----
Msrc/backend/taler-merchant-httpd_track-transaction.c | 33+++++++++++++++++++++------------
Msrc/backend/taler-merchant-httpd_track-transfer.c | 21+++++++++++++--------
8 files changed, 196 insertions(+), 89 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_contract.c b/src/backend/taler-merchant-httpd_contract.c @@ -114,9 +114,11 @@ json_parse_cleanup (struct TM_HandlerContext *hc) GNUNET_free (jpc); } + extern struct MerchantInstance * get_instance (struct json_t *json); + /** * Manage a contract request. In practical terms, it adds the fields * 'exchanges', 'merchant_pub', and 'H_wire' to the contract 'proposition' @@ -190,13 +192,14 @@ MH_handler_contract (struct TMH_RequestHandler *rh, if ((GNUNET_NO == res) || (NULL == root)) return MHD_YES; - jcontract = json_object_get (root, "contract"); - + jcontract = json_object_get (root, + "contract"); if (NULL == jcontract) { json_decref (root); - return TMH_RESPONSE_reply_external_error (connection, - "contract request malformed"); + return TMH_RESPONSE_reply_arg_missing (connection, + TALER_EC_PARAMETER_MISSING, + "contract"); } /* extract fields we need to sign separately */ res = TMH_PARSE_json_data (connection, @@ -210,29 +213,32 @@ MH_handler_contract (struct TMH_RequestHandler *rh, if (GNUNET_SYSERR == res) { json_decref (root); - return TMH_RESPONSE_reply_external_error (connection, - "contract request malformed"); + return TMH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_PARAMETER_MALFORMED, + "contract"); } /* check contract is well-formed */ if (GNUNET_OK != check_products (products)) { GNUNET_JSON_parse_free (spec); json_decref (root); - return TMH_RESPONSE_reply_external_error (connection, - "products in contract request malformed"); + return TMH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_PARAMETER_MALFORMED, + "contract:products"); } mi = get_instance (jcontract); if (NULL == mi) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Not able to find the specified receiver\n"); + "Not able to find the specified instance\n"); json_decref (root); - return TMH_RESPONSE_reply_external_error (connection, - "Unknown receiver given"); + return TMH_RESPONSE_reply_not_found (connection, + TALER_EC_CONTRACT_INSTANCE_UNKNOWN, + "Unknown instance given"); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Signing contract on behalf of receiver '%s'\n", + "Signing contract on behalf of instance '%s'\n", mi->id); /* add fields to the contract that the backend should provide */ json_object_set (jcontract, diff --git a/src/backend/taler-merchant-httpd_history.c b/src/backend/taler-merchant-httpd_history.c @@ -96,23 +96,27 @@ MH_handler_history (struct TMH_RequestHandler *rh, "date"); if (NULL == str) - return TMH_RESPONSE_reply_bad_request (connection, - "date argument missing"); + return TMH_RESPONSE_reply_arg_missing (connection, + TALER_EC_PARAMETER_MISSING, + "date"); if (1 != sscanf (str, "%llu", &seconds)) - return TMH_RESPONSE_reply_bad_request (connection, - "date argument must be a timestamp"); + return TMH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_PARAMETER_MALFORMED, + "date"); date.abs_value_us = seconds * 1000LL * 1000LL; if (date.abs_value_us / 1000LL / 1000LL != seconds) return TMH_RESPONSE_reply_bad_request (connection, + TALER_EC_HISTORY_TIMESTAMP_OVERFLOW, "Timestamp overflowed"); ret = db->find_transactions_by_date (db->cls, date, history_cb, response); if (GNUNET_SYSERR == ret) - return TMH_RESPONSE_reply_internal_error (connection, - "db error to get history"); + return TMH_RESPONSE_reply_internal_error (connection, + TALER_EC_HISTORY_DB_FETCH_ERROR, + "db error to get history"); return TMH_RESPONSE_reply_json (connection, response, MHD_HTTP_OK); diff --git a/src/backend/taler-merchant-httpd_parsing.c b/src/backend/taler-merchant-httpd_parsing.c @@ -27,6 +27,8 @@ #include "taler-merchant-httpd_parsing.h" #include "taler-merchant-httpd_responses.h" +/* FIXME: de-duplicate code with taler-exchange-httpd_parsing.c + and taler-exchange-httpd_response.c */ /** * Initial size for POST request buffer. @@ -209,6 +211,7 @@ TMH_PARSE_post_json (struct MHD_Connection *connection, GNUNET_free (r); return (MHD_NO == TMH_RESPONSE_reply_internal_error (connection, + TALER_EC_PARSER_OUT_OF_MEMORY, "out of memory")) ? GNUNET_SYSERR : GNUNET_NO; } @@ -337,7 +340,9 @@ TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, if (NULL == str) { return (MHD_NO == - TMH_RESPONSE_reply_arg_missing (connection, param_name)) + TMH_RESPONSE_reply_arg_missing (connection, + TALER_EC_PARAMETER_MISSING, + param_name)) ? GNUNET_SYSERR : GNUNET_NO; } if (GNUNET_OK != @@ -346,7 +351,9 @@ TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, out_data, out_size)) return (MHD_NO == - TMH_RESPONSE_reply_arg_invalid (connection, param_name)) + TMH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_PARAMETER_MALFORMED, + param_name)) ? GNUNET_SYSERR : GNUNET_NO; return GNUNET_OK; } diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c @@ -364,8 +364,10 @@ deposit_cb (void *cls, /* FIXME: any useful information we can include? */ resume_pay_with_response (pc, MHD_HTTP_SERVICE_UNAVAILABLE, - TMH_RESPONSE_make_json_pack ("{s:s, s:s}", + TMH_RESPONSE_make_json_pack ("{s:s, s:I, s:I, s:s}", "error", "exchange failed", + "code", (json_int_t) TALER_EC_PAY_EXCHANGE_FAILED, + "exchange-http-status", (json_int_t) http_status, "hint", "The exchange provided an unexpected response")); } else @@ -402,7 +404,8 @@ deposit_cb (void *cls, /* Forward error including 'proof' for the body */ resume_pay_with_response (pc, MHD_HTTP_INTERNAL_SERVER_ERROR, - TMH_RESPONSE_make_internal_error ("Merchant database error")); + TMH_RESPONSE_make_internal_error (TALER_EC_PAY_DB_STORE_PAY_ERROR, + "Merchant database error")); return; } @@ -512,7 +515,8 @@ process_pay_with_exchange (void *cls, GNUNET_break_op (0); resume_pay_with_response (pc, MHD_HTTP_PRECONDITION_FAILED, - TMH_RESPONSE_make_external_error ("exchange not supported")); + TMH_RESPONSE_make_external_error (TALER_EC_PAY_EXCHANGE_REJECTED, + "exchange not supported")); return; } pc->mh = mh; @@ -523,7 +527,8 @@ process_pay_with_exchange (void *cls, GNUNET_break (0); resume_pay_with_response (pc, MHD_HTTP_INTERNAL_SERVER_ERROR, - TMH_RESPONSE_make_internal_error ("no keys")); + TMH_RESPONSE_make_internal_error (TALER_EC_PAY_EXCHANGE_KEYS_FAILURE, + "no keys")); return; } @@ -542,8 +547,9 @@ process_pay_with_exchange (void *cls, GNUNET_break_op (0); resume_pay_with_response (pc, MHD_HTTP_BAD_REQUEST, - TMH_RESPONSE_make_json_pack ("{s:s, s:o, s:o}", + TMH_RESPONSE_make_json_pack ("{s:s, s:I, s:o, s:o}", "error", "denomination not found", + "code", TALER_EC_PAY_DENOMINATION_KEY_NOT_FOUND, "denom_pub", GNUNET_JSON_from_rsa_public_key (dc->denom.rsa_public_key), "exchange_keys", TALER_EXCHANGE_get_keys_raw (mh))); denom_enc = denomination_to_string_alloc (&dc->denom); @@ -563,8 +569,9 @@ process_pay_with_exchange (void *cls, GNUNET_break_op (0); resume_pay_with_response (pc, MHD_HTTP_BAD_REQUEST, - TMH_RESPONSE_make_json_pack ("{s:s, s:o}", + TMH_RESPONSE_make_json_pack ("{s:s, s:I, s:o}", "error", "invalid denomination", + "code", (json_int_t) TALER_EC_PAY_DENOMINATION_KEY_AUDITOR_FAILURE, "denom_pub", GNUNET_JSON_from_rsa_public_key (dc->denom.rsa_public_key))); denom_enc = denomination_to_string_alloc (&dc->denom); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -594,7 +601,8 @@ process_pay_with_exchange (void *cls, /* Overflow in these amounts? Very strange. */ resume_pay_with_response (pc, MHD_HTTP_BAD_REQUEST, - TMH_RESPONSE_make_internal_error ("Overflow adding up amounts")); + TMH_RESPONSE_make_internal_error (TALER_EC_PAY_AMOUNT_OVERFLOW, + "Overflow adding up amounts")); return; } } @@ -606,8 +614,9 @@ process_pay_with_exchange (void *cls, /* fee higher than residual coin value, makes no sense. */ resume_pay_with_response (pc, MHD_HTTP_BAD_REQUEST, - TMH_RESPONSE_make_json_pack ("{s:s, s:o, s:o}", + TMH_RESPONSE_make_json_pack ("{s:s, s:I, s:o, s:o}", "hint", "fee higher than coin value", + "code", (json_int_t) TALER_EC_PAY_FEES_EXCEED_PAYMENT, "f" /* FIXME */, TALER_JSON_from_amount (&dc->amount_with_fee), "fee_deposit", TALER_JSON_from_amount (&denom_details->fee_deposit))); return; @@ -636,7 +645,8 @@ process_pay_with_exchange (void *cls, GNUNET_break (0); resume_pay_with_response (pc, MHD_HTTP_INTERNAL_SERVER_ERROR, - TMH_RESPONSE_make_internal_error ("overflow")); + TMH_RESPONSE_make_internal_error (TALER_EC_PAY_AMOUNT_OVERFLOW, + "overflow")); return; } /* check if total payment sufficies */ @@ -646,7 +656,8 @@ process_pay_with_exchange (void *cls, GNUNET_break_op (0); resume_pay_with_response (pc, MHD_HTTP_NOT_ACCEPTABLE, - TMH_RESPONSE_make_external_error ("insufficient funds (including excessive exchange fees to be covered by customer)")); + TMH_RESPONSE_make_external_error (TALER_EC_PAY_PAYMENT_INSUFFICIENT_DUE_TO_FEES, + "insufficient funds (including excessive exchange fees to be covered by customer)")); return; } } @@ -659,7 +670,8 @@ process_pay_with_exchange (void *cls, GNUNET_break_op (0); resume_pay_with_response (pc, MHD_HTTP_NOT_ACCEPTABLE, - TMH_RESPONSE_make_external_error ("insufficient funds")); + TMH_RESPONSE_make_external_error (TALER_EC_PAY_PAYMENT_INSUFFICIENT, + "insufficient funds")); return; } } @@ -703,8 +715,10 @@ process_pay_with_exchange (void *cls, GNUNET_break_op (0); resume_pay_with_response (pc, MHD_HTTP_UNAUTHORIZED, - TMH_RESPONSE_make_json_pack ("{s:s, s:i}", + TMH_RESPONSE_make_json_pack ("{s:s, s:I, s:i}", "hint", "Coin signature invalid.", + "code", (json_int_t) TALER_EC_PAY_COIN_SIGNATURE_INVALID, + "coin_idx", i)); return; } @@ -735,7 +749,8 @@ handle_pay_timeout (void *cls) resume_pay_with_response (pc, MHD_HTTP_SERVICE_UNAVAILABLE, - TMH_RESPONSE_make_internal_error ("exchange not reachable")); + TMH_RESPONSE_make_internal_error (TALER_EC_PAY_EXCHANGE_TIMEOUT, + "exchange not reachable")); } @@ -906,6 +921,7 @@ MH_handler_pay (struct TMH_RequestHandler *rh, { GNUNET_break (0); return TMH_RESPONSE_reply_external_error (connection, + TALER_EC_JSON_INVALID, "failed to parse JSON body"); } if ((GNUNET_NO == res) || (NULL == root)) @@ -951,15 +967,17 @@ MH_handler_pay (struct TMH_RequestHandler *rh, if (NULL == pc->mi) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Not able to find the specified receiver\n"); + "Not able to find the specified instance\n"); json_decref (root); - return TMH_RESPONSE_reply_external_error (connection, - "Unknown receiver given"); + return TMH_RESPONSE_reply_not_found (connection, + TALER_EC_PAY_INSTANCE_UNKNOWN, + "Unknown instance given"); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "The receiver for this deposit is '%s', whose bank details are '%s'\n", pc->mi->id, - json_dumps (pc->mi->j_wire, JSON_COMPACT)); + json_dumps (pc->mi->j_wire, + JSON_COMPACT)); pc->chosen_exchange = GNUNET_strdup (chosen_exchange); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsed JSON for /pay.\n"); @@ -982,6 +1000,7 @@ MH_handler_pay (struct TMH_RequestHandler *rh, GNUNET_JSON_parse_free (spec); json_decref (root); return TMH_RESPONSE_reply_external_error (connection, + TALER_EC_PAY_MERCHANT_SIGNATURE_INVALID, "invalid merchant signature supplied"); } @@ -991,8 +1010,9 @@ MH_handler_pay (struct TMH_RequestHandler *rh, if (NULL == json_object_get (root, "wire_transfer_deadline")) { - pc->wire_transfer_deadline = GNUNET_TIME_absolute_add (pc->timestamp, - wire_transfer_delay); + pc->wire_transfer_deadline + = GNUNET_TIME_absolute_add (pc->timestamp, + wire_transfer_delay); if (pc->wire_transfer_deadline.abs_value_us < pc->refund_deadline.abs_value_us) { /* Refund value very large, delay wire transfer accordingly */ @@ -1023,6 +1043,7 @@ MH_handler_pay (struct TMH_RequestHandler *rh, GNUNET_JSON_parse_free (spec); json_decref (root); return TMH_RESPONSE_reply_external_error (connection, + TALER_EC_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE, "refund deadline after wire transfer deadline"); } } @@ -1033,8 +1054,9 @@ MH_handler_pay (struct TMH_RequestHandler *rh, { GNUNET_JSON_parse_free (spec); json_decref (root); - return TMH_RESPONSE_reply_external_error (connection, - "no coins given"); + return TMH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_PAY_COINS_ARRAY_EMPTY, + "coins"); } /* note: 1 coin = 1 deposit confirmation expected */ pc->dc = GNUNET_new_array (pc->coins_cnt, @@ -1093,6 +1115,7 @@ MH_handler_pay (struct TMH_RequestHandler *rh, GNUNET_break (0); json_decref (root); return TMH_RESPONSE_reply_internal_error (connection, + TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR, "Merchant database error"); } if (0 == pc->pending) @@ -1123,14 +1146,16 @@ MH_handler_pay (struct TMH_RequestHandler *rh, GNUNET_break (0); json_decref (root); return TMH_RESPONSE_reply_internal_error (connection, + TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR, "Merchant database error"); } if (GNUNET_SYSERR == pc->transaction_exits) { GNUNET_break (0); json_decref (root); - return TMH_RESPONSE_reply_internal_error (connection, - "Transaction ID reused with different transaction details"); + return TMH_RESPONSE_reply_external_error (connection, + TALER_EC_PAY_DB_TRANSACTION_ID_CONFLICT, + "Transaction ID reused with different transaction details"); } if (GNUNET_NO == pc->transaction_exits) { @@ -1148,7 +1173,8 @@ MH_handler_pay (struct TMH_RequestHandler *rh, GNUNET_break (0); json_decref (root); return TMH_RESPONSE_reply_internal_error (connection, - "Merchant database error"); + TALER_EC_PAY_DB_STORE_TRANSACTION_ERROR, + "Merchant database error"); } } diff --git a/src/backend/taler-merchant-httpd_responses.c b/src/backend/taler-merchant-httpd_responses.c @@ -42,9 +42,11 @@ TMH_RESPONSE_make_json (const json_t *json) struct MHD_Response *resp; char *json_str; - json_str = json_dumps (json, JSON_INDENT(2)); + json_str = json_dumps (json, + JSON_INDENT(2)); GNUNET_assert (NULL != json_str); - resp = MHD_create_response_from_buffer (strlen (json_str), json_str, + resp = MHD_create_response_from_buffer (strlen (json_str), + json_str, MHD_RESPMEM_MUST_FREE); if (NULL == resp) { @@ -103,7 +105,10 @@ TMH_RESPONSE_make_json_pack (const char *fmt, json_error_t jerror; va_start (argp, fmt); - json = json_vpack_ex (&jerror, 0, fmt, argp); + json = json_vpack_ex (&jerror, + 0, + fmt, + argp); va_end (argp); if (NULL == json) { @@ -142,7 +147,10 @@ TMH_RESPONSE_reply_json_pack (struct MHD_Connection *connection, json_error_t jerror; va_start (argp, fmt); - json = json_vpack_ex (&jerror, 0, fmt, argp); + json = json_vpack_ex (&jerror, + 0, + fmt, + argp); va_end (argp); if (NULL == json) { @@ -164,14 +172,17 @@ TMH_RESPONSE_reply_json_pack (struct MHD_Connection *connection, /** * Create a response indicating an internal error. * + * @param ec error code to return * @param hint hint about the internal error's nature * @return a MHD response object */ struct MHD_Response * -TMH_RESPONSE_make_internal_error (const char *hint) +TMH_RESPONSE_make_internal_error (enum TALER_ErrorCode ec, + const char *hint) { - return TMH_RESPONSE_make_json_pack ("{s:s, s:s}", + return TMH_RESPONSE_make_json_pack ("{s:s, s:I, s:s}", "error", "internal error", + "code", (json_int_t) ec, "hint", hint); } @@ -180,17 +191,20 @@ TMH_RESPONSE_make_internal_error (const char *hint) * Send a response indicating an internal error. * * @param connection the MHD connection to use + * @param ec error code to return * @param hint hint about the internal error's nature * @return a MHD result code */ int TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *hint) { return TMH_RESPONSE_reply_json_pack (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, - "{s:s, s:s}", + "{s:s, s:I, s:s}", "error", "internal error", + "code", (json_int_t) ec, "hint", hint); } @@ -232,8 +246,7 @@ TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection) return TMH_RESPONSE_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, "{s:s}", - "error", - "invalid json"); + "error", "invalid json"); } @@ -242,18 +255,20 @@ TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection) * needed for the reply. * * @param connection the MHD connection to use + * @param ec error code to return * @param object name of the object we did not find * @return a MHD result code */ int TMH_RESPONSE_reply_not_found (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *object) { return TMH_RESPONSE_reply_json_pack (connection, MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", - object); + "{s:I, s:s}", + "code", (json_int_t) ec, + "error", object); } @@ -261,18 +276,20 @@ TMH_RESPONSE_reply_not_found (struct MHD_Connection *connection, * Send a response indicating that the request was malformed. * * @param connection the MHD connection to use + * @param ec error code to return * @param issue description of what was wrong with the request * @return a MHD result code */ int TMH_RESPONSE_reply_bad_request (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *issue) { return TMH_RESPONSE_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", - issue); + "{s:I, s:s}", + "code", (json_int_t) ec, + "error", issue); } @@ -297,17 +314,20 @@ TMH_RESPONSE_add_global_headers (struct MHD_Response *response) * Send a response indicating an external error. * * @param connection the MHD connection to use + * @param ec error code to return * @param hint hint about the error's nature * @return a MHD result code */ int TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *hint) { return TMH_RESPONSE_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{s:s, s:s}", + "{s:s, s:I, s:s}", "error", "client error", + "code", (json_int_t) ec, "hint", hint); } @@ -315,32 +335,39 @@ TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection, /** * Create a response indicating an external error. * + * @param ec error code to return * @param hint hint about the internal error's nature * @return a MHD response object */ struct MHD_Response * -TMH_RESPONSE_make_external_error (const char *hint) +TMH_RESPONSE_make_external_error (enum TALER_ErrorCode ec, + const char *hint) { - return TMH_RESPONSE_make_json_pack ("{s:s, s:s}", + return TMH_RESPONSE_make_json_pack ("{s:s, s:I, s:s}", "error", "client error", + "code", (json_int_t) ec, "hint", hint); } + /** * Send a response indicating a missing argument. * * @param connection the MHD connection to use + * @param ec error code to return * @param param_name the parameter that is missing * @return a MHD result code */ int TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *param_name) { return TMH_RESPONSE_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{ s:s, s:s}", + "{ s:s, s:I, s:s}", "error", "missing parameter", + "code", (json_int_t) ec, "parameter", param_name); } @@ -349,17 +376,20 @@ TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, * Send a response indicating an invalid argument. * * @param connection the MHD connection to use + * @param ec error code to return * @param param_name the parameter that is invalid * @return a MHD result code */ int TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, - const char *param_name) + enum TALER_ErrorCode ec, + const char *param_name) { return TMH_RESPONSE_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{s:s, s:s}", + "{s:s, s:I, s:s}", "error", "invalid parameter", + "code", (json_int_t) ec, "parameter", param_name); } diff --git a/src/backend/taler-merchant-httpd_responses.h b/src/backend/taler-merchant-httpd_responses.h @@ -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 @@ -30,6 +30,7 @@ #include <microhttpd.h> #include <pthread.h> /* just need some structs, not the actual API */ +#include <taler/taler_error_codes.h> #include "taler_merchant_service.h" /** @@ -112,11 +113,13 @@ TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection); * needed for the reply. * * @param connection the MHD connection to use + * @param ec error code to return * @param object name of the object we did not find * @return a MHD result code */ int TMH_RESPONSE_reply_not_found (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *object); @@ -124,11 +127,13 @@ TMH_RESPONSE_reply_not_found (struct MHD_Connection *connection, * Send a response indicating that the request was malformed. * * @param connection the MHD connection to use + * @param ec error code to return * @param issue description of what was wrong with the request * @return a MHD result code */ int TMH_RESPONSE_reply_bad_request (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *issue); @@ -136,44 +141,52 @@ TMH_RESPONSE_reply_bad_request (struct MHD_Connection *connection, * Send a response indicating an internal error. * * @param connection the MHD connection to use + * @param ec error code to return * @param hint hint about the internal error's nature * @return a MHD result code */ int TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *hint); /** * Create a response indicating an internal error. * + * @param ec error code to return * @param hint hint about the internal error's nature * @return a MHD response object */ struct MHD_Response * -TMH_RESPONSE_make_internal_error (const char *hint); - +TMH_RESPONSE_make_internal_error (enum TALER_ErrorCode ec, + const char *hint); + /** * Send a response indicating an external error. * * @param connection the MHD connection to use + * @param ec error code to return * @param hint hint about the error's nature * @return a MHD result code */ int TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *hint); /** * Create a response indicating an external error. * + * @param ec error code to return * @param hint hint about the internal error's nature * @return a MHD response object */ struct MHD_Response * -TMH_RESPONSE_make_external_error (const char *hint); +TMH_RESPONSE_make_external_error (enum TALER_ErrorCode ec, + const char *hint); /** @@ -196,25 +209,32 @@ TMH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection); void TMH_RESPONSE_add_global_headers (struct MHD_Response *response); + /** * Send a response indicating a missing argument. * * @param connection the MHD connection to use + * @param ec error code to return * @param param_name the parameter that is missing * @return a MHD result code */ int TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *param_name); + /** * Send a response indicating an invalid argument. * * @param connection the MHD connection to use + * @param ec error code to return * @param param_name the parameter that is invalid * @return a MHD result code */ int TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, + enum TALER_ErrorCode ec, const char *param_name); + #endif diff --git a/src/backend/taler-merchant-httpd_track-transaction.c b/src/backend/taler-merchant-httpd_track-transaction.c @@ -688,7 +688,8 @@ handle_track_transaction_timeout (void *cls) } resume_track_transaction_with_response (tctx, MHD_HTTP_SERVICE_UNAVAILABLE, - TMH_RESPONSE_make_internal_error ("exchange not reachable")); + TMH_RESPONSE_make_internal_error (TALER_EC_PAY_EXCHANGE_TIMEOUT, + "exchange not reachable")); } @@ -872,11 +873,12 @@ MH_handler_track_transaction (struct TMH_RequestHandler *rh, MHD_GET_ARGUMENT_KIND, "id"); if (NULL == str) - return TMH_RESPONSE_reply_bad_request (connection, - "id argument missing"); + return TMH_RESPONSE_reply_arg_missing (connection, + TALER_EC_PARAMETER_MISSING, + "id"); receiver = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, - "receiver"); + "receiver" /* FIXME: rename to 'instance' */); if (NULL == receiver) receiver = "default"; GNUNET_CRYPTO_hash (receiver, @@ -885,14 +887,16 @@ MH_handler_track_transaction (struct TMH_RequestHandler *rh, tctx->mi = GNUNET_CONTAINER_multihashmap_get (by_id_map, &h_receiver); if (NULL == tctx->mi) - return TMH_RESPONSE_reply_bad_request (connection, - "unknown receiver"); + return TMH_RESPONSE_reply_not_found (connection, + TALER_EC_TRACK_TRANSACTION_INSTANCE_UNKNOWN, + "unknown instance"); if (1 != sscanf (str, "%llu", &transaction_id)) - return TMH_RESPONSE_reply_bad_request (connection, - "id argument must be a number"); + return TMH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_PARAMETER_MALFORMED, + "id"); ret = db->find_transaction (db->cls, transaction_id, @@ -902,6 +906,7 @@ MH_handler_track_transaction (struct TMH_RequestHandler *rh, if (GNUNET_NO == ret) { return TMH_RESPONSE_reply_not_found (connection, + TALER_EC_TRACK_TRANSACTION_TRANSACTION_UNKNOWN, "id"); } if ( (GNUNET_SYSERR == ret) || @@ -910,6 +915,7 @@ MH_handler_track_transaction (struct TMH_RequestHandler *rh, { GNUNET_break (0); return TMH_RESPONSE_reply_internal_error (connection, + TALER_EC_TRACK_TRANSACTION_DB_FETCH_TRANSACTION_ERROR, "Database error"); } ret = db->find_payments (db->cls, @@ -921,11 +927,13 @@ MH_handler_track_transaction (struct TMH_RequestHandler *rh, { GNUNET_break (0); return TMH_RESPONSE_reply_internal_error (connection, - "Database error"); + TALER_EC_TRACK_TRANSACTION_DB_FETCH_PAYMENT_ERROR, + "Database error"); } if (GNUNET_NO == ret) { return TMH_RESPONSE_reply_not_found (connection, + TALER_EC_TRACK_TRANSACTION_DB_NO_DEPOSITS_ERROR, "deposits"); } *connection_cls = tctx; @@ -937,9 +945,10 @@ MH_handler_track_transaction (struct TMH_RequestHandler *rh, &process_track_transaction_with_exchange, tctx); - tctx->timeout_task = GNUNET_SCHEDULER_add_delayed (TRACK_TIMEOUT, - &handle_track_transaction_timeout, - tctx); + tctx->timeout_task + = GNUNET_SCHEDULER_add_delayed (TRACK_TIMEOUT, + &handle_track_transaction_timeout, + tctx); return MHD_YES; } diff --git a/src/backend/taler-merchant-httpd_track-transfer.c b/src/backend/taler-merchant-httpd_track-transfer.c @@ -452,7 +452,8 @@ handle_track_transfer_timeout (void *cls) } resume_track_transfer_with_response (rctx, MHD_HTTP_SERVICE_UNAVAILABLE, - TMH_RESPONSE_make_internal_error ("exchange not reachable")); + TMH_RESPONSE_make_internal_error (TALER_EC_TRACK_TRANSFER_EXCHANGE_TIMEOUT, + "exchange not reachable")); } @@ -549,33 +550,37 @@ MH_handler_track_transfer (struct TMH_RequestHandler *rh, MHD_GET_ARGUMENT_KIND, "exchange"); if (NULL == uri) - return TMH_RESPONSE_reply_bad_request (connection, - "exchange argument missing"); + return TMH_RESPONSE_reply_arg_missing (connection, + TALER_EC_PARAMETER_MISSING, + "exchange"); rctx->uri = GNUNET_strdup (uri); receiver_str = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, - "receiver"); + "receiver" /* FIXME: instance */); if (NULL == receiver_str) receiver_str = "default"; rctx->mi = TMH_lookup_instance (receiver_str); if (NULL == rctx->mi) return TMH_RESPONSE_reply_not_found (connection, + TALER_EC_TRACK_TRANSFER_INSTANCE_UNKNOWN, "instance unknown"); str = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "wtid"); if (NULL == str) - return TMH_RESPONSE_reply_bad_request (connection, - "wtid argument missing"); + return TMH_RESPONSE_reply_arg_missing (connection, + TALER_EC_PARAMETER_MISSING, + "wtid"); if (GNUNET_OK != GNUNET_STRINGS_string_to_data (str, strlen (str), &rctx->wtid, sizeof (rctx->wtid))) { - return TMH_RESPONSE_reply_bad_request (connection, - "wtid argument malformed"); + return TMH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_PARAMETER_MALFORMED, + "wtid"); } /* Check if reply is already in database! */