gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant] 02/02: clean up check payment logic


From: gnunet
Subject: [taler-merchant] 02/02: clean up check payment logic
Date: Sat, 02 Nov 2019 12:13:06 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository merchant.

commit e8d2cde63cefeba9f6c6dc242a075de48875c9bd
Author: Christian Grothoff <address@hidden>
AuthorDate: Sat Nov 2 12:13:01 2019 +0100

    clean up check payment logic
---
 src/backend/taler-merchant-httpd_check-payment.c | 595 +++++++++++++----------
 src/lib/merchant_api_check_payment.c             |  27 +-
 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 74b8c5c..d9284c2 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>
@@ -37,21 +38,114 @@
 #define MAX_RETRIES 5
 
 
+/**
+ * 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 8a85d26..35cd44c 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);
 }
 

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]