gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] branch master updated: implement /public/poll-payment A


From: gnunet
Subject: [taler-merchant] branch master updated: implement /public/poll-payment API, refactor to avoid code duplication
Date: Sat, 02 Nov 2019 13:40:43 +0100

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

grothoff pushed a commit to branch master
in repository merchant.

The following commit(s) were added to refs/heads/master by this push:
     new ea48d9f  implement /public/poll-payment API, refactor to avoid code 
duplication
ea48d9f is described below

commit ea48d9fc008e34cf954f497db635fe343ba902f0
Author: Christian Grothoff <address@hidden>
AuthorDate: Sat Nov 2 13:40:41 2019 +0100

    implement /public/poll-payment API, refactor to avoid code duplication
---
 src/backend/Makefile.am                            |  21 +-
 src/backend/taler-merchant-httpd.c                 |  81 ++++
 src/backend/taler-merchant-httpd.h                 |  31 +-
 src/backend/taler-merchant-httpd_check-payment.c   | 102 +----
 ...yment.c => taler-merchant-httpd_poll-payment.c} | 462 +++++++++------------
 src/backend/taler-merchant-httpd_poll-payment.h    |  47 +++
 src/backend/taler-merchant-httpd_tip-pickup.c      |   4 +-
 7 files changed, 379 insertions(+), 369 deletions(-)

diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index ec4b204..966d8f4 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -14,26 +14,25 @@ bin_PROGRAMS = \
 
 taler_merchant_httpd_SOURCES = \
   taler-merchant-httpd.c taler-merchant-httpd.h \
-  taler-merchant-httpd_parsing.c taler-merchant-httpd_parsing.h \
-  taler-merchant-httpd_responses.c taler-merchant-httpd_responses.h \
-  taler-merchant-httpd_mhd.c taler-merchant-httpd_mhd.h \
   taler-merchant-httpd_auditors.c taler-merchant-httpd_auditors.h \
+  taler-merchant-httpd_config.c taler-merchant-httpd_config.h \
+  taler-merchant-httpd_check-payment.c taler-merchant-httpd_check-payment.h \
   taler-merchant-httpd_exchanges.c taler-merchant-httpd_exchanges.h \
+  taler-merchant-httpd_history.c taler-merchant-httpd_history.h \
+  taler-merchant-httpd_mhd.c taler-merchant-httpd_mhd.h \
   taler-merchant-httpd_order.c taler-merchant-httpd_order.h \
-  taler-merchant-httpd_proposal.c taler-merchant-httpd_proposal.h \
+  taler-merchant-httpd_parsing.c taler-merchant-httpd_parsing.h \
   taler-merchant-httpd_pay.c taler-merchant-httpd_pay.h \
-  taler-merchant-httpd_history.c taler-merchant-httpd_history.h \
+  taler-merchant-httpd_poll-payment.c taler-merchant-httpd_poll-payment.h \
+  taler-merchant-httpd_proposal.c taler-merchant-httpd_proposal.h \
+  taler-merchant-httpd_refund.c taler-merchant-httpd_refund.h \
+  taler-merchant-httpd_responses.c taler-merchant-httpd_responses.h \
   taler-merchant-httpd_tip-authorize.c taler-merchant-httpd_tip-authorize.h \
   taler-merchant-httpd_tip-pickup.c taler-merchant-httpd_tip-pickup.h \
   taler-merchant-httpd_tip-query.c taler-merchant-httpd_tip-query.h \
   taler-merchant-httpd_tip-reserve-helper.c 
taler-merchant-httpd_tip-reserve-helper.h \
   taler-merchant-httpd_track-transaction.c 
taler-merchant-httpd_track-transaction.h \
-  taler-merchant-httpd_track-transfer.c taler-merchant-httpd_track-transfer.h \
-  taler-merchant-httpd_refund.c taler-merchant-httpd_refund.h \
-  taler-merchant-httpd_check-payment.c taler-merchant-httpd_check-payment.h \
-  taler-merchant-httpd_config.c taler-merchant-httpd_config.h
-
-
+  taler-merchant-httpd_track-transfer.c taler-merchant-httpd_track-transfer.h
 taler_merchant_httpd_LDADD = \
   $(top_builddir)/src/backenddb/libtalermerchantdb.la \
   -ltalerexchange \
diff --git a/src/backend/taler-merchant-httpd.c 
b/src/backend/taler-merchant-httpd.c
index e06e144..8abb444 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -48,6 +48,7 @@
 #include "taler-merchant-httpd_history.h"
 #include "taler-merchant-httpd_refund.h"
 #include "taler-merchant-httpd_check-payment.h"
+#include "taler-merchant-httpd_poll-payment.h"
 #include "taler-merchant-httpd_config.h"
 
 /**
@@ -168,6 +169,11 @@ struct GNUNET_CONTAINER_Heap *resume_timeout_heap;
  */
 struct GNUNET_CONTAINER_MultiHashMap *payment_trigger_map;
 
+/**
+ * Task responsible for timeouts in the #resume_timeout_heap.
+ */
+struct GNUNET_SCHEDULER_Task *resume_timeout_task;
+
 
 /**
  * Return #GNUNET_YES if given a valid correlation ID and
@@ -276,6 +282,73 @@ TMH_compute_pay_key (const char *order_id,
 }
 
 
+/**
+ * Create a taler://pay/ URI for the given @a con and @a order_id
+ * and @a session_id and @a instance_id.
+ *
+ * @param con HTTP connection
+ * @param order_id the order id
+ * @param session_id session, may be NULL
+ * @param instance_id instance, may be "default"
+ * @return corresponding taler://pay/ URI, or NULL on missing "host"
+ */
+char *
+TMH_make_taler_pay_uri (struct MHD_Connection *con,
+                        const char *order_id,
+                        const char *session_id,
+                        const char *instance_id)
+{
+  const char *host;
+  const char *forwarded_host;
+  const char *uri_path;
+  const char *uri_instance_id;
+  const char *query;
+  char *result;
+
+  host = MHD_lookup_connection_value (con,
+                                      MHD_HEADER_KIND,
+                                      "Host");
+  forwarded_host = MHD_lookup_connection_value (con,
+                                                MHD_HEADER_KIND,
+                                                "X-Forwarded-Host");
+
+  uri_path = MHD_lookup_connection_value (con,
+                                          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"))
+    uri_instance_id = "-";
+  else
+    uri_instance_id = instance_id;
+  if (NULL == host)
+  {
+    /* Should never happen, at least the host header should be defined */
+    GNUNET_break (0);
+    return NULL;
+  }
+
+  if (GNUNET_YES == TALER_mhd_is_https (con))
+    query = "";
+  else
+    query = "?insecure=1";
+  GNUNET_assert (NULL != 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,
+                                      (NULL == session_id) ? "" : "/",
+                                      (NULL == session_id) ? "" : session_id,
+                                      query));
+  return result;
+}
+
+
 /**
  * Shutdown task (magically invoked when the application is being
  * quit)
@@ -311,6 +384,11 @@ do_shutdown (void *cls)
     GNUNET_CONTAINER_heap_destroy (resume_timeout_heap);
     resume_timeout_heap = NULL;
   }
+  if (NULL != resume_timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (resume_timeout_task);
+    resume_timeout_task = NULL;
+  }
   if (NULL != mhd)
   {
     MHD_stop_daemon (mhd);
@@ -1196,6 +1274,9 @@ url_handler (void *cls,
     { "/check-payment", MHD_HTTP_METHOD_GET, "text/plain",
       NULL, 0,
       &MH_handler_check_payment, MHD_HTTP_OK},
+    { "/public/poll-payment", MHD_HTTP_METHOD_GET, "text/plain",
+      NULL, 0,
+      &MH_handler_poll_payment, MHD_HTTP_OK},
     { "/config", MHD_HTTP_METHOD_GET, "text/plain",
       NULL, 0,
       &MH_handler_config, MHD_HTTP_OK},
diff --git a/src/backend/taler-merchant-httpd.h 
b/src/backend/taler-merchant-httpd.h
index bc53bbc..53dedcb 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -276,15 +276,21 @@ struct TMH_SuspendedConnection
    */
   struct MHD_Connection *con;
 
+  /**
+   * Associated heap node.
+   */
+  struct GNUNET_CONTAINER_HeapNode *hn;
+
   /**
    * Key of this entry in the #payment_trigger_map
    */
   struct GNUNET_HashCode key;
 
   /**
-   * Associated heap node.
+   * 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_CONTAINER_HeapNode *hn;
+  struct GNUNET_TIME_Absolute long_poll_timeout;
 
 };
 
@@ -319,6 +325,11 @@ extern unsigned long long default_wire_fee_amortization;
  */
 extern struct GNUNET_CONTAINER_Heap *resume_timeout_heap;
 
+/**
+ * Task responsible for timeouts in the #resume_timeout_heap.
+ */
+extern struct GNUNET_SCHEDULER_Task *resume_timeout_task;
+
 /**
  * Hash map from H(order_id,merchant_pub) to `struct TMH_SuspendedConnection`
  * entries to resume when a payment is made for the given order.
@@ -397,4 +408,20 @@ TMH_compute_pay_key (const char *order_id,
                      struct GNUNET_HashCode *key);
 
 
+/**
+ * Create a taler://pay/ URI for the given @a con and @a order_id
+ * and @a session_id and @a instance_id.
+ *
+ * @param con HTTP connection
+ * @param order_id the order id
+ * @param session_id session, may be NULL
+ * @param instance_id instance, may be "default"
+ * @return corresponding taler://pay/ URI, or NULL on missing "host"
+ */
+char *
+TMH_make_taler_pay_uri (struct MHD_Connection *con,
+                        const char *order_id,
+                        const char *session_id,
+                        const char *instance_id);
+
 #endif
diff --git a/src/backend/taler-merchant-httpd_check-payment.c 
b/src/backend/taler-merchant-httpd_check-payment.c
index ac73a90..fad3fdc 100644
--- a/src/backend/taler-merchant-httpd_check-payment.c
+++ b/src/backend/taler-merchant-httpd_check-payment.c
@@ -48,9 +48,6 @@ struct CheckPaymentRequestContext
    */
   struct TM_HandlerContext hc;
 
-  /**
-   * Connection we are processing a request for.
-   */
   struct MHD_Connection *connection;
 
   /**
@@ -84,12 +81,6 @@ struct CheckPaymentRequestContext
    */
   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.
@@ -141,67 +132,6 @@ cprc_cleanup (struct TM_HandlerContext *hc)
 }
 
 
-/**
- * Make a taler://pay URI
- *
- * @param cprc payment request context
- * @returns the URI, must be freed with #GNUNET_free
- */
-static char *
-make_taler_pay_uri (const struct CheckPaymentRequestContext *cprc)
-{
-  const char *host;
-  const char *forwarded_host;
-  const char *uri_path;
-  const char *uri_instance_id;
-  const char *query;
-  char *result;
-
-  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 (cprc->connection,
-                                          MHD_HEADER_KIND,
-                                          "X-Forwarded-Prefix");
-  if (NULL == uri_path)
-    uri_path = "-";
-  if (NULL != forwarded_host)
-    host = forwarded_host;
-  if (0 == strcmp (cprc->mi->id,
-                   "default"))
-    uri_instance_id = "-";
-  else
-    uri_instance_id = cprc->mi->id;
-  if (NULL == host)
-  {
-    /* Should never happen, at least the host header should be defined */
-    GNUNET_break (0);
-    return NULL;
-  }
-
-  if (GNUNET_YES == TALER_mhd_is_https (cprc->connection))
-    query = "";
-  else
-    query = "?insecure=1";
-  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,
-                                      cprc->order_id,
-                                      (cprc->session_id == NULL) ? "" : "/",
-                                      (cprc->session_id == NULL) ? "" :
-                                      cprc->session_id,
-                                      query));
-  return result;
-}
-
-
 /**
  * Function called with information about a refund.
  * It is responsible for summing up the refund amount.
@@ -274,7 +204,10 @@ send_pay_request (const struct CheckPaymentRequestContext 
*cprc)
                                                 "db error fetching pay session 
info");
     }
   }
-  taler_pay_uri = make_taler_pay_uri (cprc);
+  taler_pay_uri = TMH_make_taler_pay_uri (cprc->connection,
+                                          cprc->order_id,
+                                          cprc->session_id,
+                                          cprc->mi->id);
   ret = TMH_RESPONSE_reply_json_pack (cprc->connection,
                                       MHD_HTTP_OK,
                                       "{s:s, s:s, s:b, s:s?}",
@@ -413,8 +346,6 @@ MH_handler_check_payment (struct TMH_RequestHandler *rh,
   if (NULL == cprc)
   {
     /* 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;
@@ -433,31 +364,6 @@ MH_handler_check_payment (struct TMH_RequestHandler *rh,
                                              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
-    {
-      cprc->long_poll_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
-    }
     cprc->contract_url = MHD_lookup_connection_value (connection,
                                                       MHD_GET_ARGUMENT_KIND,
                                                       "contract_url");
diff --git a/src/backend/taler-merchant-httpd_check-payment.c 
b/src/backend/taler-merchant-httpd_poll-payment.c
similarity index 53%
copy from src/backend/taler-merchant-httpd_check-payment.c
copy to src/backend/taler-merchant-httpd_poll-payment.c
index ac73a90..945a356 100644
--- a/src/backend/taler-merchant-httpd_check-payment.c
+++ b/src/backend/taler-merchant-httpd_poll-payment.c
@@ -14,8 +14,8 @@
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
 /**
- * @file backend/taler-merchant-httpd_check-payment.c
- * @brief implementation of /check-payment handler
+ * @file backend/taler-merchant-httpd_poll-payment.c
+ * @brief implementation of /public/poll-payment handler
  * @author Florian Dold
  * @author Christian Grothoff
  */
@@ -30,7 +30,7 @@
 #include "taler-merchant-httpd_parsing.h"
 #include "taler-merchant-httpd_exchanges.h"
 #include "taler-merchant-httpd_responses.h"
-#include "taler-merchant-httpd_check-payment.h"
+#include "taler-merchant-httpd_poll-payment.h"
 
 /**
  * Maximum number of retries for database operations.
@@ -41,7 +41,7 @@
 /**
  * Data structure we keep for a check payment request.
  */
-struct CheckPaymentRequestContext
+struct PollPaymentRequestContext
 {
   /**
    * Must be first for #handle_mhd_completion_callback.
@@ -49,9 +49,10 @@ struct CheckPaymentRequestContext
   struct TM_HandlerContext hc;
 
   /**
-   * Connection we are processing a request for.
+   * Entry in the #resume_timeout_heap for this check payment, if we are
+   * suspended.
    */
-  struct MHD_Connection *connection;
+  struct TMH_SuspendedConnection sc;
 
   /**
    * Which merchant instance is this for?
@@ -73,11 +74,6 @@ struct CheckPaymentRequestContext
    */
   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).
@@ -85,10 +81,9 @@ struct CheckPaymentRequestContext
   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.
+   * session of the client
    */
-  struct GNUNET_TIME_Absolute long_poll_timeout;
+  const char *session_id;
 
   /**
    * Contract terms of the payment we are checking. NULL when they
@@ -126,79 +121,18 @@ struct CheckPaymentRequestContext
 /**
  * Clean up the session state for a check payment request.
  *
- * @param hc must be a `struct CheckPaymentRequestContext *`
+ * @param hc must be a `struct PollPaymentRequestContext *`
  */
 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 cprc payment request context
- * @returns the URI, must be freed with #GNUNET_free
- */
-static char *
-make_taler_pay_uri (const struct CheckPaymentRequestContext *cprc)
+pprc_cleanup (struct TM_HandlerContext *hc)
 {
-  const char *host;
-  const char *forwarded_host;
-  const char *uri_path;
-  const char *uri_instance_id;
-  const char *query;
-  char *result;
-
-  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 (cprc->connection,
-                                          MHD_HEADER_KIND,
-                                          "X-Forwarded-Prefix");
-  if (NULL == uri_path)
-    uri_path = "-";
-  if (NULL != forwarded_host)
-    host = forwarded_host;
-  if (0 == strcmp (cprc->mi->id,
-                   "default"))
-    uri_instance_id = "-";
-  else
-    uri_instance_id = cprc->mi->id;
-  if (NULL == host)
-  {
-    /* Should never happen, at least the host header should be defined */
-    GNUNET_break (0);
-    return NULL;
-  }
+  struct PollPaymentRequestContext *pprc = (struct
+                                            PollPaymentRequestContext *) hc;
 
-  if (GNUNET_YES == TALER_mhd_is_https (cprc->connection))
-    query = "";
-  else
-    query = "?insecure=1";
-  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,
-                                      cprc->order_id,
-                                      (cprc->session_id == NULL) ? "" : "/",
-                                      (cprc->session_id == NULL) ? "" :
-                                      cprc->session_id,
-                                      query));
-  return result;
+  if (NULL != pprc->contract_terms)
+    json_decref (pprc->contract_terms);
+  GNUNET_free_non_null (pprc->final_contract_url);
+  GNUNET_free (pprc);
 }
 
 
@@ -221,47 +155,115 @@ process_refunds_cb (void *cls,
                     const struct TALER_Amount *refund_amount,
                     const struct TALER_Amount *refund_fee)
 {
-  struct CheckPaymentRequestContext *cprc = cls;
+  struct PollPaymentRequestContext *pprc = cls;
 
-  if (cprc->refunded)
+  if (pprc->refunded)
   {
     GNUNET_assert (GNUNET_SYSERR !=
-                   TALER_amount_add (&cprc->refund_amount,
-                                     &cprc->refund_amount,
+                   TALER_amount_add (&pprc->refund_amount,
+                                     &pprc->refund_amount,
                                      refund_amount));
     return;
   }
-  cprc->refund_amount = *refund_amount;
-  cprc->refunded = GNUNET_YES;
+  pprc->refund_amount = *refund_amount;
+  pprc->refunded = GNUNET_YES;
+}
+
+
+/**
+ * Resume processing all suspended connections past timeout.
+ *
+ * @param cls unused
+ */
+static void
+do_resume (void *cls)
+{
+  struct TMH_SuspendedConnection *sc;
+
+  (void) cls;
+  resume_timeout_task = NULL;
+  while (1)
+  {
+    sc = GNUNET_CONTAINER_heap_peek (resume_timeout_heap);
+    if (NULL == sc)
+      return;
+    if  (0 !=
+         GNUNET_TIME_absolute_get_remaining (
+           sc->long_poll_timeout).rel_value_us)
+      break;
+    GNUNET_assert (sc ==
+                   GNUNET_CONTAINER_heap_remove_root (resume_timeout_heap));
+    sc->hn = NULL;
+    GNUNET_assert (GNUNET_YES ==
+                   GNUNET_CONTAINER_multihashmap_remove (payment_trigger_map,
+                                                         &sc->key,
+                                                         sc));
+    MHD_resume_connection (sc->con);
+  }
+  resume_timeout_task = GNUNET_SCHEDULER_add_at (sc->long_poll_timeout,
+                                                 &do_resume,
+                                                 NULL);
 }
 
 
 /**
  * The client did not yet pay, send it the payment request.
  *
- * @param cprc check pay request context
+ * @param pprc check pay request context
  * @return #MHD_YES on success
  */
 static int
-send_pay_request (const struct CheckPaymentRequestContext *cprc)
+send_pay_request (struct PollPaymentRequestContext *pprc)
 {
   int ret;
   char *already_paid_order_id = NULL;
   char *taler_pay_uri;
 
+  if (0 !=
+      GNUNET_TIME_absolute_get_remaining (
+        pprc->sc.long_poll_timeout).rel_value_us)
+  {
+    struct TMH_SuspendedConnection *sc;
+
+    /* long polling: do not queue a response, suspend connection instead */
+    TMH_compute_pay_key (pprc->order_id,
+                         &pprc->mi->pubkey,
+                         &pprc->sc.key);
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_CONTAINER_multihashmap_put (payment_trigger_map,
+                                                      &pprc->sc.key,
+                                                      &pprc->sc,
+                                                      
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
+    pprc->sc.hn = GNUNET_CONTAINER_heap_insert (resume_timeout_heap,
+                                                &pprc->sc,
+                                                pprc->sc.long_poll_timeout.
+                                                abs_value_us);
+    MHD_suspend_connection (pprc->sc.con);
+    if (NULL != resume_timeout_task)
+    {
+      GNUNET_SCHEDULER_cancel (resume_timeout_task);
+      resume_timeout_task = NULL;
+    }
+    sc = GNUNET_CONTAINER_heap_peek (resume_timeout_heap);
+    resume_timeout_task = GNUNET_SCHEDULER_add_at (sc->long_poll_timeout,
+                                                   &do_resume,
+                                                   NULL);
+    return MHD_YES;
+  }
+
   /* Check if resource_id has been paid for in the same session
    * with another order_id.
    */
-  if ( (NULL != cprc->session_id) &&
-       (NULL != cprc->fulfillment_url) )
+  if ( (NULL != pprc->session_id) &&
+       (NULL != pprc->fulfillment_url) )
   {
     enum GNUNET_DB_QueryStatus qs;
 
     qs = db->find_session_info (db->cls,
                                 &already_paid_order_id,
-                                cprc->session_id,
-                                cprc->fulfillment_url,
-                                &cprc->mi->pubkey);
+                                pprc->session_id,
+                                pprc->fulfillment_url,
+                                &pprc->mi->pubkey);
     if (qs < 0)
     {
       /* single, read-only SQL statements should never cause
@@ -269,17 +271,20 @@ send_pay_request (const struct CheckPaymentRequestContext 
*cprc)
       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 (cprc->connection,
+      return TMH_RESPONSE_reply_internal_error (pprc->sc.con,
                                                 
TALER_EC_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR,
                                                 "db error fetching pay session 
info");
     }
   }
-  taler_pay_uri = make_taler_pay_uri (cprc);
-  ret = TMH_RESPONSE_reply_json_pack (cprc->connection,
+  taler_pay_uri = TMH_make_taler_pay_uri (pprc->sc.con,
+                                          pprc->order_id,
+                                          pprc->session_id,
+                                          pprc->mi->id);
+  ret = TMH_RESPONSE_reply_json_pack (pprc->sc.con,
                                       MHD_HTTP_OK,
                                       "{s:s, s:s, s:b, s:s?}",
                                       "taler_pay_uri", taler_pay_uri,
-                                      "contract_url", cprc->final_contract_url,
+                                      "contract_url", pprc->final_contract_url,
                                       "paid", 0,
                                       "already_paid_order_id",
                                       already_paid_order_id);
@@ -290,103 +295,7 @@ send_pay_request (const struct CheckPaymentRequestContext 
*cprc)
 
 
 /**
- * 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 cprc session state
- * @return status code to return to MHD for @a connection
- */
-static int
-check_order_and_request_payment (struct CheckPaymentRequestContext *cprc)
-{
-  enum GNUNET_DB_QueryStatus qs;
-
-  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,
-                       &cprc->contract_terms,
-                       cprc->order_id,
-                       &cprc->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 (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 (cprc->connection,
-                                         
TALER_EC_CHECK_PAYMENT_ORDER_ID_UNKNOWN,
-                                         "unknown order_id");
-  }
-
-  if (GNUNET_OK !=
-      parse_contract_terms (cprc))
-    return cprc->ret;
-  /* Offer was not picked up yet, but we ensured that it exists */
-  return send_pay_request (cprc);
-}
-
-
-/**
- * Manages a /check-payment call, checking the status
+ * Manages a /public/poll-payment call, checking the status
  * of a payment and, if necessary, constructing the URL
  * for a payment redirect URL.
  *
@@ -399,33 +308,34 @@ check_order_and_request_payment (struct 
CheckPaymentRequestContext *cprc)
  * @return MHD result code
  */
 int
-MH_handler_check_payment (struct TMH_RequestHandler *rh,
-                          struct MHD_Connection *connection,
-                          void **connection_cls,
-                          const char *upload_data,
-                          size_t *upload_data_size,
-                          struct MerchantInstance *mi)
+MH_handler_poll_payment (struct TMH_RequestHandler *rh,
+                         struct MHD_Connection *connection,
+                         void **connection_cls,
+                         const char *upload_data,
+                         size_t *upload_data_size,
+                         struct MerchantInstance *mi)
 {
-  struct CheckPaymentRequestContext *cprc = *connection_cls;
+  struct PollPaymentRequestContext *pprc = *connection_cls;
   enum GNUNET_DB_QueryStatus qs;
   int ret;
 
-  if (NULL == cprc)
+  if (NULL == pprc)
   {
     /* First time here, parse request and check order is known */
     const char *long_poll_timeout_s;
+    const char *cts;
 
-    cprc = GNUNET_new (struct CheckPaymentRequestContext);
-    cprc->hc.cc = &cprc_cleanup;
-    cprc->ret = GNUNET_SYSERR;
-    cprc->connection = connection;
-    cprc->mi = mi;
-    *connection_cls = cprc;
+    pprc = GNUNET_new (struct PollPaymentRequestContext);
+    pprc->hc.cc = &pprc_cleanup;
+    pprc->ret = GNUNET_SYSERR;
+    pprc->sc.con = connection;
+    pprc->mi = mi;
+    *connection_cls = pprc;
 
-    cprc->order_id = MHD_lookup_connection_value (connection,
+    pprc->order_id = MHD_lookup_connection_value (connection,
                                                   MHD_GET_ARGUMENT_KIND,
                                                   "order_id");
-    if (NULL == cprc->order_id)
+    if (NULL == pprc->order_id)
     {
       /* order_id is required but missing */
       GNUNET_break_op (0);
@@ -433,6 +343,27 @@ MH_handler_check_payment (struct TMH_RequestHandler *rh,
                                              TALER_EC_PARAMETER_MISSING,
                                              "order_id required");
     }
+    cts = MHD_lookup_connection_value (connection,
+                                       MHD_GET_ARGUMENT_KIND,
+                                       "h_contract");
+    if (NULL == cts)
+    {
+      /* h_contract required but missing */
+      GNUNET_break_op (0);
+      return TMH_RESPONSE_reply_bad_request (connection,
+                                             TALER_EC_PARAMETER_MISSING,
+                                             "h_contract required");
+    }
+    if (GNUNET_OK !=
+        GNUNET_CRYPTO_hash_from_string (cts,
+                                        &pprc->h_contract_terms))
+    {
+      /* cts has wrong encoding */
+      GNUNET_break_op (0);
+      return TMH_RESPONSE_reply_bad_request (connection,
+                                             TALER_EC_PARAMETER_MALFORMED,
+                                             "h_contract malformed");
+    }
     long_poll_timeout_s = MHD_lookup_connection_value (connection,
                                                        MHD_GET_ARGUMENT_KIND,
                                                        "timeout");
@@ -449,76 +380,95 @@ MH_handler_check_payment (struct TMH_RequestHandler *rh,
                                                TALER_EC_PARAMETER_MALFORMED,
                                                "timeout must be non-negative 
number");
       }
-      cprc->long_poll_timeout
+      pprc->sc.long_poll_timeout
         = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (
                                               GNUNET_TIME_UNIT_SECONDS,
                                               timeout));
     }
     else
     {
-      cprc->long_poll_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
+      pprc->sc.long_poll_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
     }
-    cprc->contract_url = MHD_lookup_connection_value (connection,
+    pprc->contract_url = MHD_lookup_connection_value (connection,
                                                       MHD_GET_ARGUMENT_KIND,
                                                       "contract_url");
-    if (NULL == cprc->contract_url)
+    if (NULL == pprc->contract_url)
     {
-      cprc->final_contract_url = TALER_url_absolute_mhd (connection,
+      pprc->final_contract_url = TALER_url_absolute_mhd (connection,
                                                          "/public/proposal",
                                                          "instance", mi->id,
                                                          "order_id",
-                                                         cprc->order_id,
+                                                         pprc->order_id,
                                                          NULL);
-      GNUNET_assert (NULL != cprc->final_contract_url);
+      GNUNET_assert (NULL != pprc->final_contract_url);
     }
     else
     {
-      cprc->final_contract_url = GNUNET_strdup (cprc->contract_url);
+      pprc->final_contract_url = GNUNET_strdup (pprc->contract_url);
     }
-    cprc->session_id = MHD_lookup_connection_value (connection,
+    pprc->session_id = MHD_lookup_connection_value (connection,
                                                     MHD_GET_ARGUMENT_KIND,
                                                     "session_id");
+
+    /* obtain contract terms, indirectly checking that the client's contract
+       terms hash is actually valid and known. */
     db->preflight (db->cls);
-    qs = db->find_contract_terms (db->cls,
-                                  &cprc->contract_terms,
-                                  cprc->order_id,
-                                  &mi->pubkey);
+    qs = db->find_contract_terms_from_hash (db->cls,
+                                            &pprc->contract_terms,
+                                            &pprc->h_contract_terms,
+                                            &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,
-                                                "db error fetching contract 
terms");
+                                                
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
+                                                "Merchant database error");
+    }
+    if (0 == qs)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Contract unknown\n");
+      return TMH_RESPONSE_reply_not_found (connection,
+                                           
TALER_EC_POLL_PAYMENT_CONTRACT_NOT_FOUND,
+                                           "Given order_id doesn't map to any 
proposal");
     }
+    GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
 
-    if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
     {
-      /* Check that we're at least aware of the order */
-      return check_order_and_request_payment (cprc);
+      struct GNUNET_JSON_Specification spec[] = {
+        GNUNET_JSON_spec_string ("fulfillment_url",
+                                 &pprc->fulfillment_url),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (pprc->contract_terms,
+                             spec,
+                             NULL, NULL))
+      {
+        GNUNET_break (0);
+        return TMH_RESPONSE_reply_internal_error (connection,
+                                                  
TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR,
+                                                  "Merchant database error 
(contract terms corrupted)");
+      }
     }
-    GNUNET_assert (NULL != cprc->contract_terms);
 
-    if (GNUNET_OK !=
-        parse_contract_terms (cprc))
-      return cprc->ret;
-  }
+  } /* end of first-time initialization / sanity checks */
+
 
-  GNUNET_assert (NULL != cprc->contract_terms);
+  db->preflight (db->cls);
 
   /* Check if the order has been paid for. */
-  if (NULL != cprc->session_id)
+  if (NULL != pprc->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,
-                                cprc->session_id,
-                                cprc->fulfillment_url,
+                                pprc->session_id,
+                                pprc->fulfillment_url,
                                 &mi->pubkey);
     if (qs < 0)
     {
@@ -533,12 +483,12 @@ MH_handler_check_payment (struct TMH_RequestHandler *rh,
     }
     else if (0 == qs)
     {
-      ret = send_pay_request (cprc);
+      ret = send_pay_request (pprc);
       GNUNET_free_non_null (already_paid_order_id);
       return ret;
     }
     GNUNET_break (1 == qs);
-    GNUNET_break (0 == strcmp (cprc->order_id,
+    GNUNET_break (0 == strcmp (pprc->order_id,
                                already_paid_order_id));
     GNUNET_free_non_null (already_paid_order_id);
   }
@@ -549,7 +499,7 @@ MH_handler_check_payment (struct TMH_RequestHandler *rh,
 
     qs = db->find_paid_contract_terms_from_hash (db->cls,
                                                  &xcontract_terms,
-                                                 &cprc->h_contract_terms,
+                                                 &pprc->h_contract_terms,
                                                  &mi->pubkey);
     if (0 > qs)
     {
@@ -563,7 +513,7 @@ MH_handler_check_payment (struct TMH_RequestHandler *rh,
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "not paid yet\n");
-      return send_pay_request (cprc);
+      return send_pay_request (pprc);
     }
     GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
     GNUNET_assert (NULL != xcontract_terms);
@@ -575,9 +525,9 @@ MH_handler_check_payment (struct TMH_RequestHandler *rh,
   {
     qs = db->get_refunds_from_contract_terms_hash (db->cls,
                                                    &mi->pubkey,
-                                                   &cprc->h_contract_terms,
+                                                   &pprc->h_contract_terms,
                                                    &process_refunds_cb,
-                                                   cprc);
+                                                   pprc);
     if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
       break;
   }
@@ -585,25 +535,23 @@ 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 (&cprc->h_contract_terms));
+                GNUNET_h2s (&pprc->h_contract_terms));
     return TMH_RESPONSE_reply_internal_error (connection,
                                               
TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR,
                                               "Merchant database error");
   }
-  if (cprc->refunded)
+  if (pprc->refunded)
     return TMH_RESPONSE_reply_json_pack (connection,
                                          MHD_HTTP_OK,
-                                         "{s:o, s:b, s:b, s:o}",
-                                         "contract_terms", 
cprc->contract_terms,
+                                         "{s:b, s:b, s:o}",
                                          "paid", 1,
-                                         "refunded", cprc->refunded,
+                                         "refunded", pprc->refunded,
                                          "refund_amount",
                                          TALER_JSON_from_amount (
-                                           &cprc->refund_amount));
+                                           &pprc->refund_amount));
   return TMH_RESPONSE_reply_json_pack (connection,
                                        MHD_HTTP_OK,
-                                       "{s:o, s:b, s:b }",
-                                       "contract_terms", cprc->contract_terms,
+                                       "{s:b, s:b }",
                                        "paid", 1,
                                        "refunded", 0);
 }
diff --git a/src/backend/taler-merchant-httpd_poll-payment.h 
b/src/backend/taler-merchant-httpd_poll-payment.h
new file mode 100644
index 0000000..e9f54c2
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_poll-payment.h
@@ -0,0 +1,47 @@
+/*
+  This file is part of TALER
+  (C) 2017 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
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file backend/taler-merchant-httpd_poll-payment.h
+ * @brief headers for /public/poll-payment handler
+ * @author Christian Grothoff
+ * @author Florian Dold
+ */
+#ifndef TALER_MERCHANT_HTTPD_POLL_PAYMENT_H
+#define TALER_MERCHANT_HTTPD_POLL_PAYMENT_H
+#include <microhttpd.h>
+#include "taler-merchant-httpd.h"
+
+/**
+ * Manages a /public/poll-payment call, checking the status
+ * of a payment.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @param mi merchant backend instance, never NULL
+ * @return MHD result code
+ */
+int
+MH_handler_poll_payment (struct TMH_RequestHandler *rh,
+                         struct MHD_Connection *connection,
+                         void **connection_cls,
+                         const char *upload_data,
+                         size_t *upload_data_size,
+                         struct MerchantInstance *mi);
+
+#endif
diff --git a/src/backend/taler-merchant-httpd_tip-pickup.c 
b/src/backend/taler-merchant-httpd_tip-pickup.c
index bead341..d53596c 100644
--- a/src/backend/taler-merchant-httpd_tip-pickup.c
+++ b/src/backend/taler-merchant-httpd_tip-pickup.c
@@ -649,7 +649,9 @@ MH_handler_tip_pickup_get (struct TMH_RequestHandler *rh,
                                            "tip_id required");
   }
 
-  if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (tip_id_str, &tip_id))
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_hash_from_string (tip_id_str,
+                                      &tip_id))
   {
     /* tip_id has wrong encoding */
     GNUNET_break_op (0);

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



reply via email to

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