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:
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! */