gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] 01/02: move lookup order for idempotency check into tra


From: gnunet
Subject: [taler-merchant] 01/02: move lookup order for idempotency check into transaction scope where it belongs
Date: Mon, 18 Mar 2024 23:09:20 +0100

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

grothoff pushed a commit to branch master
in repository merchant.

commit 63c171f49aa4b3d6d412bf50d07a0fae4beab211
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Mon Mar 18 22:14:48 2024 +0100

    move lookup order for idempotency check into transaction scope where it 
belongs
---
 .../taler-merchant-httpd_private-post-orders.c     | 152 ++++++++++++---------
 1 file changed, 88 insertions(+), 64 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c 
b/src/backend/taler-merchant-httpd_private-post-orders.c
index 736da1c2..92d35b78 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -423,6 +423,24 @@ struct OrderContext
      * Which product (by offset) is out of stock, UINT_MAX if all were 
in-stock.
      */
     unsigned int out_of_stock_index;
+
+    /**
+     * Set to a previous claim token *if* @e idempotent
+     * is also true.
+     */
+    struct TALER_ClaimTokenP token;
+
+    /**
+     * Set to true if the order was idempotent and there
+     * was an equivalent one before.
+     */
+    bool idempotent;
+
+    /**
+     * Set to true if the order is in conflict with a
+     * previous order with the same order ID.
+     */
+    bool conflict;
   } execute_order;
 
   struct
@@ -661,6 +679,45 @@ execute_transaction (struct OrderContext *oc)
     GNUNET_break (0);
     return GNUNET_DB_STATUS_HARD_ERROR;
   }
+
+  /* Test if we already have an order with this id */
+  {
+    json_t *contract_terms;
+    struct TALER_MerchantPostDataHashP orig_post;
+
+    qs = TMH_db->lookup_order (TMH_db->cls,
+                               oc->hc->instance->settings.id,
+                               oc->parse_order.order_id,
+                               &oc->execute_order.token,
+                               &orig_post,
+                               &contract_terms);
+    /* If yes, check for idempotency */
+    if (0 > qs)
+    {
+      GNUNET_break (0);
+      TMH_db->rollback (TMH_db->cls);
+      return qs;
+    }
+    if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+    {
+      TMH_db->rollback (TMH_db->cls);
+      json_decref (contract_terms);
+      /* Comparing the contract terms is sufficient because all the other
+         params get added to it at some point. */
+      if (0 == GNUNET_memcmp (&orig_post,
+                              &oc->parse_request.h_post_data))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                    "Order creation idempotent\n");
+        oc->execute_order.idempotent = true;
+        return qs;
+      }
+      GNUNET_break_op (0);
+      oc->execute_order.conflict = true;
+      return qs;
+    }
+  }
+
   /* Setup order */
   qs = TMH_db->insert_order (TMH_db->cls,
                              oc->hc->instance->settings.id,
@@ -757,70 +814,6 @@ execute_order (struct OrderContext *oc)
     &oc->hc->instance->settings;
   enum GNUNET_DB_QueryStatus qs;
 
-  /* Test if we already have an order with this id */
-  /* FIXME: this should be done within the main
-     transaction! */
-  {
-    struct TALER_ClaimTokenP token;
-    json_t *contract_terms;
-    struct TALER_MerchantPostDataHashP orig_post;
-
-    TMH_db->preflight (TMH_db->cls);
-    qs = TMH_db->lookup_order (TMH_db->cls,
-                               oc->hc->instance->settings.id,
-                               oc->parse_order.order_id,
-                               &token,
-                               &orig_post,
-                               &contract_terms);
-    /* If yes, check for idempotency */
-    if (0 > qs)
-    {
-      GNUNET_break (0);
-      TMH_db->rollback (TMH_db->cls);
-      reply_with_error (oc,
-                        MHD_HTTP_INTERNAL_SERVER_ERROR,
-                        TALER_EC_GENERIC_DB_FETCH_FAILED,
-                        "lookup_order");
-      return;
-    }
-    if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
-    {
-      MHD_RESULT ret;
-
-      json_decref (contract_terms);
-      /* Comparing the contract terms is sufficient because all the other
-         params get added to it at some point. */
-      if (0 == GNUNET_memcmp (&orig_post,
-                              &oc->parse_request.h_post_data))
-      {
-        GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                    "Order creation idempotent\n");
-        ret = TALER_MHD_REPLY_JSON_PACK (
-          oc->connection,
-          MHD_HTTP_OK,
-          GNUNET_JSON_pack_string ("order_id",
-                                   oc->parse_order.order_id),
-          GNUNET_JSON_pack_allow_null (
-            GNUNET_JSON_pack_data_varsize (
-              "token",
-              GNUNET_is_zero (&token)
-              ? NULL
-              : &token,
-              sizeof (token))));
-        finalize_order (oc,
-                        ret);
-        return;
-      }
-      /* This request is not idempotent */
-      GNUNET_break_op (0);
-      reply_with_error (
-        oc,
-        MHD_HTTP_CONFLICT,
-        TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ALREADY_EXISTS,
-        oc->parse_order.order_id);
-      return;
-    }
-  }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Executing database transaction to create order '%s' for 
instance '%s'\n",
               oc->parse_order.order_id,
@@ -865,6 +858,37 @@ execute_order (struct OrderContext *oc)
     return;
   }
 
+  /* DB transaction succeeded, check for idempotent */
+  if (oc->execute_order.idempotent)
+  {
+    MHD_RESULT ret;
+
+    ret = TALER_MHD_REPLY_JSON_PACK (
+      oc->connection,
+      MHD_HTTP_OK,
+      GNUNET_JSON_pack_string ("order_id",
+                               oc->parse_order.order_id),
+      GNUNET_JSON_pack_allow_null (
+        GNUNET_JSON_pack_data_varsize (
+          "token",
+          GNUNET_is_zero (&oc->execute_order.token)
+          ? NULL
+          : &oc->execute_order.token,
+          sizeof (oc->execute_order.token))));
+    finalize_order (oc,
+                    ret);
+    return;
+  }
+  if (oc->execute_order.conflict)
+  {
+    reply_with_error (
+      oc,
+      MHD_HTTP_CONFLICT,
+      TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ALREADY_EXISTS,
+      oc->parse_order.order_id);
+    return;
+  }
+
   /* DB transaction succeeded, check for out-of-stock */
   if (oc->execute_order.out_of_stock_index < UINT_MAX)
   {

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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