summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-11-02 12:13:01 +0100
committerChristian Grothoff <christian@grothoff.org>2019-11-02 12:13:01 +0100
commite8d2cde63cefeba9f6c6dc242a075de48875c9bd (patch)
tree695258d3a56e73ed147ef9e019720adb90db73e7
parentd19a45f960923cecbaabe23407f1d2f0aa244954 (diff)
downloadmerchant-e8d2cde63cefeba9f6c6dc242a075de48875c9bd.tar.gz
merchant-e8d2cde63cefeba9f6c6dc242a075de48875c9bd.tar.bz2
merchant-e8d2cde63cefeba9f6c6dc242a075de48875c9bd.zip
clean up check payment logic
-rw-r--r--src/backend/taler-merchant-httpd_check-payment.c595
-rw-r--r--src/lib/merchant_api_check_payment.c27
2 files changed, 345 insertions, 277 deletions
diff --git a/src/backend/taler-merchant-httpd_check-payment.c b/src/backend/taler-merchant-httpd_check-payment.c
index 74b8c5c1..d9284c21 100644
--- a/src/backend/taler-merchant-httpd_check-payment.c
+++ b/src/backend/taler-merchant-httpd_check-payment.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2017 Taler Systems SA
+ (C) 2017, 2019 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -17,6 +17,7 @@
* @file backend/taler-merchant-httpd_check-payment.c
* @brief implementation of /check-payment handler
* @author Florian Dold
+ * @author Christian Grothoff
*/
#include "platform.h"
#include <string.h>
@@ -38,20 +39,113 @@
/**
+ * Data structure we keep for a check payment request.
+ */
+struct CheckPaymentRequestContext
+{
+ /**
+ * Must be first for #handle_mhd_completion_callback.
+ */
+ struct TM_HandlerContext hc;
+
+ /**
+ * Connection we are processing a request for.
+ */
+ struct MHD_Connection *connection;
+
+ /**
+ * URL where the final contract can be found for this payment.
+ */
+ char *final_contract_url;
+
+ /**
+ * order ID for the payment
+ */
+ const char *order_id;
+
+ /**
+ * Where to get the contract
+ */
+ const char *contract_url;
+
+ /**
+ * session of the client
+ */
+ const char *session_id;
+
+ /**
+ * fulfillment URL of the contract (valid as long as
+ * @e contract_terms is valid).
+ */
+ const char *fulfillment_url;
+
+ /**
+ * At what time does this request expire? If set in the future, we
+ * may wait this long for a payment to arrive before responding.
+ */
+ struct GNUNET_TIME_Absolute long_poll_timeout;
+
+ /**
+ * Contract terms of the payment we are checking. NULL when they
+ * are not (yet) known.
+ */
+ json_t *contract_terms;
+
+ /**
+ * Hash of @e contract_terms, set only once @e contract_terms
+ * is available.
+ */
+ struct GNUNET_HashCode h_contract_terms;
+
+ /**
+ * Total refunds granted for this payment. Only initialized
+ * if @e refunded is set to #GNUNET_YES.
+ */
+ struct TALER_Amount refund_amount;
+
+ /**
+ * Set to #GNUNET_YES if this payment has been refunded and
+ * @e refund_amount is initialized.
+ */
+ int refunded;
+
+ /**
+ * Initially #GNUNET_SYSERR. If we queued a response, set to the
+ * result code (i.e. #MHD_YES or #MHD_NO).
+ */
+ int ret;
+
+};
+
+
+/**
+ * Clean up the session state for a check payment request.
+ *
+ * @param hc must be a `struct CheckPaymentRequestContext *`
+ */
+static void
+cprc_cleanup (struct TM_HandlerContext *hc)
+{
+ struct CheckPaymentRequestContext *cprc = (struct
+ CheckPaymentRequestContext *) hc;
+
+ if (NULL != cprc->contract_terms)
+ json_decref (cprc->contract_terms);
+ GNUNET_free_non_null (cprc->final_contract_url);
+ GNUNET_free (cprc);
+}
+
+
+/**
* Make a taler://pay URI
*
- * @param connection MHD connection to take host and path from
* @param instance_id merchant's instance ID
- * @param order_id order ID to request a payment for
- * @param session_id session ID for the payment or NULL
- * if not a session-bound payment
+ * @param cprc payment request context
* @returns the URI, must be freed with #GNUNET_free
*/
static char *
-make_taler_pay_uri (struct MHD_Connection *connection,
- const char *instance_id,
- const char *order_id,
- const char *session_id)
+make_taler_pay_uri (const char *instance_id,
+ const struct CheckPaymentRequestContext *cprc)
{
const char *host;
const char *forwarded_host;
@@ -60,23 +154,25 @@ make_taler_pay_uri (struct MHD_Connection *connection,
const char *query;
char *result;
- host = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "Host");
- forwarded_host = MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
+ host = MHD_lookup_connection_value (cprc->connection,
+ MHD_HEADER_KIND,
+ "Host");
+ forwarded_host = MHD_lookup_connection_value (cprc->connection,
+ MHD_HEADER_KIND,
"X-Forwarded-Host");
- uri_path = MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
+ uri_path = MHD_lookup_connection_value (cprc->connection,
+ MHD_HEADER_KIND,
"X-Forwarded-Prefix");
if (NULL == uri_path)
uri_path = "-";
-
if (NULL != forwarded_host)
host = forwarded_host;
-
- if (0 == strcmp (instance_id, "default"))
+ if (0 == strcmp (instance_id,
+ "default"))
uri_instance_id = "-";
else
uri_instance_id = instance_id;
-
if (NULL == host)
{
/* Should never happen, at least the host header should be defined */
@@ -84,21 +180,20 @@ make_taler_pay_uri (struct MHD_Connection *connection,
return NULL;
}
- if (GNUNET_YES == TALER_mhd_is_https (connection))
+ if (GNUNET_YES == TALER_mhd_is_https (cprc->connection))
query = "";
else
query = "?insecure=1";
-
- GNUNET_assert (NULL != order_id);
-
+ GNUNET_assert (NULL != cprc->order_id);
GNUNET_assert (0 < GNUNET_asprintf (&result,
"taler://pay/%s/%s/%s/%s%s%s%s",
host,
uri_path,
uri_instance_id,
- order_id,
- (session_id == NULL) ? "" : "/",
- (session_id == NULL) ? "" : session_id,
+ cprc->order_id,
+ (cprc->session_id == NULL) ? "" : "/",
+ (cprc->session_id == NULL) ? "" :
+ cprc->session_id,
query));
return result;
}
@@ -123,50 +218,48 @@ process_refunds_cb (void *cls,
const struct TALER_Amount *refund_amount,
const struct TALER_Amount *refund_fee)
{
- struct TALER_Amount *acc_amount = cls;
+ struct CheckPaymentRequestContext *cprc = cls;
- GNUNET_assert (GNUNET_SYSERR !=
- TALER_amount_add (acc_amount,
- acc_amount,
- refund_amount));
+ if (cprc->refunded)
+ {
+ GNUNET_assert (GNUNET_SYSERR !=
+ TALER_amount_add (&cprc->refund_amount,
+ &cprc->refund_amount,
+ refund_amount));
+ return;
+ }
+ cprc->refund_amount = *refund_amount;
+ cprc->refunded = GNUNET_YES;
}
/**
* The client did not yet pay, send it the payment request.
*
- * @param connection connection to send on
- * @param order_id order ID for the payment
- * @param final_contract_url where to get the contract
- * @param session_id session of the client
- * @param fulfillment_url fulfillment URL of the contract
- * @param h_contract_terms_str hash of the contract terms, stringified
+ * @param cprc check pay request context
* @param mi merchant instance
* @return #MHD_YES on success
*/
static int
-send_pay_request (struct MHD_Connection *connection,
- const char *order_id,
- const char *final_contract_url,
- const char *session_id,
- const char *fulfillment_url,
- const char *h_contract_terms_str,
+send_pay_request (const struct CheckPaymentRequestContext *cprc,
const struct MerchantInstance *mi)
{
int ret;
- int qs;
char *already_paid_order_id = NULL;
char *taler_pay_uri;
/* Check if resource_id has been paid for in the same session
* with another order_id.
*/
- if ( (NULL != session_id) && (NULL != fulfillment_url) )
+ if ( (NULL != cprc->session_id) &&
+ (NULL != cprc->fulfillment_url) )
{
+ enum GNUNET_DB_QueryStatus qs;
+
qs = db->find_session_info (db->cls,
&already_paid_order_id,
- session_id,
- fulfillment_url,
+ cprc->session_id,
+ cprc->fulfillment_url,
&mi->pubkey);
if (qs < 0)
{
@@ -175,60 +268,98 @@ send_pay_request (struct MHD_Connection *connection,
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
/* Always report on hard error as well to enable diagnostics */
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
- return TMH_RESPONSE_reply_internal_error (connection,
+ return TMH_RESPONSE_reply_internal_error (cprc->connection,
TALER_EC_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR,
"db error fetching pay session info");
}
}
-
- taler_pay_uri = make_taler_pay_uri (connection, mi->id, order_id, session_id);
-
- ret = TMH_RESPONSE_reply_json_pack (connection,
+ taler_pay_uri = make_taler_pay_uri (mi->id,
+ cprc);
+ ret = TMH_RESPONSE_reply_json_pack (cprc->connection,
MHD_HTTP_OK,
"{s:s, s:s, s:b, s:s?}",
- "taler_pay_uri",
- taler_pay_uri,
- "contract_url",
- final_contract_url,
- "paid",
- 0,
+ "taler_pay_uri", taler_pay_uri,
+ "contract_url", cprc->final_contract_url,
+ "paid", 0,
"already_paid_order_id",
- already_paid_order_id
- );
- GNUNET_free_non_null (already_paid_order_id);
+ already_paid_order_id);
GNUNET_free (taler_pay_uri);
+ GNUNET_free_non_null (already_paid_order_id);
return ret;
}
/**
+ * Parse the "contract_terms" in @a cprc and set the
+ * "fulfillment_url" and the "h_contract_terms" in @a cprc
+ * accordingly.
+ *
+ * On errors, the response is being queued and the status
+ * code set in @cprc "ret".
+ *
+ * @param cprc[in,out] context to process
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
+ */
+static int
+parse_contract_terms (struct CheckPaymentRequestContext *cprc)
+{
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("fulfillment_url",
+ &cprc->fulfillment_url),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (cprc->contract_terms,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break (0);
+ cprc->ret
+ = TMH_RESPONSE_reply_internal_error (cprc->connection,
+ TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
+ "Merchant database error (contract terms corrupted)");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_JSON_hash (cprc->contract_terms,
+ &cprc->h_contract_terms))
+ {
+ GNUNET_break (0);
+ cprc->ret
+ = TMH_RESPONSE_reply_internal_error (cprc->connection,
+ TALER_EC_CHECK_PAYMENT_FAILED_COMPUTE_PROPOSAL_HASH,
+ "Failed to hash proposal");
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
* Check that we are aware of @a order_id and if so request the payment,
* otherwise generate an error response.
*
- * @param connection where to send the response
* @param mi the merchant's instance
- * @param final_contract_url where to redirect for the contract
- * @param session_id the session_id
- * @param order_id the order to look up
- * @return #MHD_YES on success
+ * @param cprc session state
+ * @return status code to return to MHD for @a connection
*/
static int
-check_order_and_request_payment (struct MHD_Connection *connection,
- struct MerchantInstance *mi,
- const char *final_contract_url,
- const char *session_id,
- const char *order_id)
+check_order_and_request_payment (struct MerchantInstance *mi,
+ struct CheckPaymentRequestContext *cprc)
{
enum GNUNET_DB_QueryStatus qs;
- json_t *contract_terms;
- struct GNUNET_HashCode h_contract_terms;
- char *h_contract_terms_str;
- int ret;
- const char *fulfillment_url;
+ if (NULL != cprc->contract_terms)
+ {
+ /* This should never happen. */
+ GNUNET_break (0);
+ json_decref (cprc->contract_terms);
+ cprc->contract_terms = NULL;
+ }
qs = db->find_order (db->cls,
- &contract_terms,
- order_id,
+ &cprc->contract_terms,
+ cprc->order_id,
&mi->pubkey);
if (0 > qs)
{
@@ -237,55 +368,23 @@ check_order_and_request_payment (struct MHD_Connection *connection,
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
/* Always report on hard error as well to enable diagnostics */
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
- return TMH_RESPONSE_reply_internal_error (connection,
+ return TMH_RESPONSE_reply_internal_error (cprc->connection,
TALER_EC_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR,
"db error fetching order");
}
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
{
- return TMH_RESPONSE_reply_not_found (connection,
+ return TMH_RESPONSE_reply_not_found (cprc->connection,
TALER_EC_CHECK_PAYMENT_ORDER_ID_UNKNOWN,
"unknown order_id");
}
- {
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("fulfillment_url", &fulfillment_url),
- GNUNET_JSON_spec_end ()
- };
- if (GNUNET_OK != GNUNET_JSON_parse (contract_terms, spec, NULL, NULL))
- {
- GNUNET_break (0);
- json_decref (contract_terms);
- return TMH_RESPONSE_reply_internal_error (connection,
- TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
- "Merchant database error (contract terms corrupted)");
- }
- }
if (GNUNET_OK !=
- TALER_JSON_hash (contract_terms,
- &h_contract_terms))
- {
- GNUNET_break (0);
- json_decref (contract_terms);
- return TMH_RESPONSE_reply_internal_error (connection,
- TALER_EC_CHECK_PAYMENT_FAILED_COMPUTE_PROPOSAL_HASH,
- "Failed to hash proposal");
- }
+ parse_contract_terms (cprc))
+ return cprc->ret;
/* Offer was not picked up yet, but we ensured that it exists */
- h_contract_terms_str = GNUNET_STRINGS_data_to_string_alloc (&h_contract_terms,
- sizeof (struct
- GNUNET_HashCode));
- ret = send_pay_request (connection,
- order_id,
- final_contract_url,
- session_id,
- fulfillment_url,
- h_contract_terms_str,
- mi);
- GNUNET_free_non_null (h_contract_terms_str);
- json_decref (contract_terms);
- return ret;
+ return send_pay_request (cprc,
+ mi);
}
@@ -310,131 +409,119 @@ MH_handler_check_payment (struct TMH_RequestHandler *rh,
size_t *upload_data_size,
struct MerchantInstance *mi)
{
- const char *order_id;
- const char *contract_url;
- const char *session_id;
- const char *fulfillment_url;
- char *final_contract_url;
- char *h_contract_terms_str;
+ struct CheckPaymentRequestContext *cprc = *connection_cls;
enum GNUNET_DB_QueryStatus qs;
- json_t *contract_terms;
- struct GNUNET_HashCode h_contract_terms;
- struct TALER_Amount refund_amount;
int ret;
- int refunded;
- order_id = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "order_id");
- if (NULL == order_id)
+ if (NULL == cprc)
{
- /* order_id is required but missing */
- GNUNET_break_op (0);
- return TMH_RESPONSE_reply_bad_request (connection,
- TALER_EC_PARAMETER_MISSING,
- "order_id required");
- }
- contract_url = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "contract_url");
- if (NULL == contract_url)
- {
- final_contract_url = TALER_url_absolute_mhd (connection,
- "/public/proposal",
- "instance", mi->id,
- "order_id", order_id,
- NULL);
- GNUNET_assert (NULL != final_contract_url);
- }
- else
- {
- final_contract_url = GNUNET_strdup (contract_url);
- }
- session_id = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "session_id");
-
- db->preflight (db->cls);
- qs = db->find_contract_terms (db->cls,
- &contract_terms,
- order_id,
- &mi->pubkey);
- if (0 > qs)
- {
- /* single, read-only SQL statements should never cause
- serialization problems */
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
- /* Always report on hard error as well to enable diagnostics */
- GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
- GNUNET_free (final_contract_url);
- return TMH_RESPONSE_reply_internal_error (connection,
- TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
- "db error fetching contract terms");
- }
-
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- {
- /* Check that we're at least aware of the order */
- ret = check_order_and_request_payment (connection,
- mi,
- final_contract_url,
- session_id,
- order_id);
- GNUNET_free (final_contract_url);
- return ret;
- }
-
- GNUNET_assert (NULL != contract_terms);
-
- /* Get the amount and fulfillment_url from the contract. */
- {
- struct TALER_Amount amount;
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_amount ("amount", &amount),
- GNUNET_JSON_spec_string ("fulfillment_url", &fulfillment_url),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK != GNUNET_JSON_parse (contract_terms, spec, NULL, NULL))
+ /* First time here, parse request and check order is known */
+ const char *long_poll_timeout_s;
+
+ cprc = GNUNET_new (struct CheckPaymentRequestContext);
+ cprc->hc.cc = &cprc_cleanup;
+ cprc->ret = GNUNET_SYSERR;
+ cprc->connection = connection;
+ *connection_cls = cprc;
+
+ cprc->order_id = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "order_id");
+ if (NULL == cprc->order_id)
+ {
+ /* order_id is required but missing */
+ GNUNET_break_op (0);
+ return TMH_RESPONSE_reply_bad_request (connection,
+ TALER_EC_PARAMETER_MISSING,
+ "order_id required");
+ }
+ long_poll_timeout_s = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "timeout");
+ if (NULL != long_poll_timeout_s)
+ {
+ unsigned int timeout;
+
+ if (1 != sscanf (long_poll_timeout_s,
+ "%u",
+ &timeout))
+ {
+ GNUNET_break_op (0);
+ return TMH_RESPONSE_reply_bad_request (connection,
+ TALER_EC_PARAMETER_MALFORMED,
+ "timeout must be non-negative number");
+ }
+ cprc->long_poll_timeout
+ = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_SECONDS,
+ timeout));
+ }
+ else
{
- GNUNET_break (0);
- GNUNET_free (final_contract_url);
- json_decref (contract_terms);
+ cprc->long_poll_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
+ }
+ cprc->contract_url = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "contract_url");
+ if (NULL == cprc->contract_url)
+ {
+ cprc->final_contract_url = TALER_url_absolute_mhd (connection,
+ "/public/proposal",
+ "instance", mi->id,
+ "order_id",
+ cprc->order_id,
+ NULL);
+ GNUNET_assert (NULL != cprc->final_contract_url);
+ }
+ else
+ {
+ cprc->final_contract_url = GNUNET_strdup (cprc->contract_url);
+ }
+ cprc->session_id = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "session_id");
+ db->preflight (db->cls);
+ qs = db->find_contract_terms (db->cls,
+ &cprc->contract_terms,
+ cprc->order_id,
+ &mi->pubkey);
+ if (0 > qs)
+ {
+ /* single, read-only SQL statements should never cause
+ serialization problems */
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+ /* Always report on hard error as well to enable diagnostics */
+ GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
return TMH_RESPONSE_reply_internal_error (connection,
TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
- "Merchant database error (contract terms corrupted)");
+ "db error fetching contract terms");
}
- TALER_amount_get_zero (amount.currency, &refund_amount);
- }
- if (GNUNET_OK !=
- TALER_JSON_hash (contract_terms,
- &h_contract_terms))
- {
- GNUNET_break (0);
- json_decref (contract_terms);
- GNUNET_free (final_contract_url);
- return TMH_RESPONSE_reply_internal_error (connection,
- TALER_EC_CHECK_PAYMENT_FAILED_COMPUTE_PROPOSAL_HASH,
- "Failed to hash proposal");
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ /* Check that we're at least aware of the order */
+ return check_order_and_request_payment (mi,
+ cprc);
+ }
+
+ GNUNET_assert (NULL != cprc->contract_terms);
}
- h_contract_terms_str = GNUNET_STRINGS_data_to_string_alloc (&h_contract_terms,
- sizeof (struct
- GNUNET_HashCode));
+ if (GNUNET_OK !=
+ parse_contract_terms (cprc))
+ return cprc->ret;
/* Check if the order has been paid for. */
- if (NULL != session_id)
+ if (NULL != cprc->session_id)
{
/* Check if paid within a session. */
-
char *already_paid_order_id = NULL;
qs = db->find_session_info (db->cls,
&already_paid_order_id,
- session_id,
- fulfillment_url,
+ cprc->session_id,
+ cprc->fulfillment_url,
&mi->pubkey);
if (qs < 0)
{
@@ -449,56 +536,39 @@ MH_handler_check_payment (struct TMH_RequestHandler *rh,
}
else if (0 == qs)
{
- ret = send_pay_request (connection,
- order_id,
- final_contract_url,
- session_id,
- fulfillment_url,
- h_contract_terms_str,
+ ret = send_pay_request (cprc,
mi);
GNUNET_free_non_null (already_paid_order_id);
return ret;
}
GNUNET_break (1 == qs);
- GNUNET_break (0 == strcmp (order_id, already_paid_order_id));
+ GNUNET_break (0 == strcmp (cprc->order_id,
+ already_paid_order_id));
GNUNET_free_non_null (already_paid_order_id);
}
else
{
/* Check if paid regardless of session. */
-
json_t *xcontract_terms = NULL;
qs = db->find_paid_contract_terms_from_hash (db->cls,
&xcontract_terms,
- &h_contract_terms,
+ &cprc->h_contract_terms,
&mi->pubkey);
if (0 > qs)
{
/* Always report on hard error as well to enable diagnostics */
GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
- GNUNET_free_non_null (h_contract_terms_str);
- GNUNET_free (final_contract_url);
- json_decref (contract_terms);
return TMH_RESPONSE_reply_internal_error (connection,
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
"Merchant database error");
}
if (0 == qs)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "not paid yet\n");
- ret = send_pay_request (connection,
- order_id,
- final_contract_url,
- session_id,
- fulfillment_url,
- h_contract_terms_str,
- mi);
- GNUNET_free_non_null (h_contract_terms_str);
- GNUNET_free (final_contract_url);
- json_decref (contract_terms);
- return ret;
-
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "not paid yet\n");
+ return send_pay_request (cprc,
+ mi);
}
GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
GNUNET_assert (NULL != xcontract_terms);
@@ -510,9 +580,9 @@ MH_handler_check_payment (struct TMH_RequestHandler *rh,
{
qs = db->get_refunds_from_contract_terms_hash (db->cls,
&mi->pubkey,
- &h_contract_terms,
+ &cprc->h_contract_terms,
&process_refunds_cb,
- &refund_amount);
+ cprc);
if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
break;
}
@@ -520,26 +590,25 @@ MH_handler_check_payment (struct TMH_RequestHandler *rh,
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Database hard error on refunds_from_contract_terms_hash lookup: %s\n",
- GNUNET_h2s (&h_contract_terms));
- GNUNET_free_non_null (h_contract_terms_str);
- GNUNET_free (final_contract_url);
- json_decref (contract_terms);
+ GNUNET_h2s (&cprc->h_contract_terms));
return TMH_RESPONSE_reply_internal_error (connection,
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
"Merchant database error");
}
- GNUNET_free_non_null (h_contract_terms_str);
-
- refunded = (0 != refund_amount.value) || (0 != refund_amount.fraction);
-
- ret = TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o, s:b, s:b, s:o}",
- "contract_terms", contract_terms,
- "paid", 1,
- "refunded", refunded,
- "refund_amount", TALER_JSON_from_amount (
- &refund_amount));
- GNUNET_free (final_contract_url);
- return ret;
+ if (cprc->refunded)
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o, s:b, s:b, s:o}",
+ "contract_terms", cprc->contract_terms,
+ "paid", 1,
+ "refunded", cprc->refunded,
+ "refund_amount",
+ TALER_JSON_from_amount (
+ &cprc->refund_amount));
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o, s:b, s:b }",
+ "contract_terms", cprc->contract_terms,
+ "paid", 1,
+ "refunded", 0);
}
diff --git a/src/lib/merchant_api_check_payment.c b/src/lib/merchant_api_check_payment.c
index 8a85d26a..35cd44ce 100644
--- a/src/lib/merchant_api_check_payment.c
+++ b/src/lib/merchant_api_check_payment.c
@@ -79,12 +79,10 @@ handle_check_payment_finished (void *cls,
{
struct TALER_MERCHANT_CheckPaymentOperation *cpo = cls;
struct TALER_Amount refund_amount = { 0 };
- int refunded;
const json_t *json = response;
+ const json_t *refunded;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_boolean ("refunded",
- &refunded),
TALER_JSON_spec_amount ("refund_amount",
&refund_amount),
GNUNET_JSON_spec_end ()
@@ -103,7 +101,7 @@ handle_check_payment_finished (void *cls,
json,
GNUNET_SYSERR,
GNUNET_SYSERR,
- &refund_amount,
+ NULL,
NULL);
TALER_MERCHANT_check_payment_cancel (cpo);
return;
@@ -123,7 +121,7 @@ handle_check_payment_finished (void *cls,
json,
GNUNET_SYSERR,
GNUNET_SYSERR,
- &refund_amount,
+ NULL,
NULL);
}
else
@@ -133,17 +131,19 @@ handle_check_payment_finished (void *cls,
json,
GNUNET_NO,
GNUNET_NO,
- &refund_amount,
+ NULL,
taler_pay_uri);
}
TALER_MERCHANT_check_payment_cancel (cpo);
return;
}
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
+ if ( (NULL == (refunded = json_object_get (json, "refunded"))) ||
+ ( (json_true () == refunded) &&
+ (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL)) ) )
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"check payment failed to parse JSON\n");
@@ -153,7 +153,7 @@ handle_check_payment_finished (void *cls,
json,
GNUNET_SYSERR,
GNUNET_SYSERR,
- &refund_amount,
+ NULL,
NULL);
TALER_MERCHANT_check_payment_cancel (cpo);
return;
@@ -163,10 +163,9 @@ handle_check_payment_finished (void *cls,
MHD_HTTP_OK,
json,
GNUNET_YES,
- refunded,
- &refund_amount,
+ (json_true () == refunded),
+ (json_true () == refunded) ? &refund_amount : NULL,
NULL);
- GNUNET_JSON_parse_free (spec);
TALER_MERCHANT_check_payment_cancel (cpo);
}