diff options
author | Christian Grothoff <christian@grothoff.org> | 2020-05-04 00:25:27 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2020-05-04 00:25:27 +0200 |
commit | e138cd0e5adff973cf1f065e3fd5588f4bd33ddc (patch) | |
tree | 8621e100caa867fcf64708ead7b11f7b1d892485 | |
parent | 2a5388a263a2edb63dee7865d9da2d9b6db65f6e (diff) | |
download | merchant-e138cd0e5adff973cf1f065e3fd5588f4bd33ddc.tar.gz merchant-e138cd0e5adff973cf1f065e3fd5588f4bd33ddc.tar.bz2 merchant-e138cd0e5adff973cf1f065e3fd5588f4bd33ddc.zip |
starting with get-orders-ID logic
-rw-r--r-- | src/backend/taler-merchant-httpd_get-orders-ID-2.c | 582 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_get-orders-ID-2.h | 47 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_get-orders-ID.c | 723 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_get-orders-ID.h | 28 |
4 files changed, 542 insertions, 838 deletions
diff --git a/src/backend/taler-merchant-httpd_get-orders-ID-2.c b/src/backend/taler-merchant-httpd_get-orders-ID-2.c deleted file mode 100644 index 6ca4fcce..00000000 --- a/src/backend/taler-merchant-httpd_get-orders-ID-2.c +++ /dev/null @@ -1,582 +0,0 @@ -/* - This file is part of TALER - (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 - 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.c - * @brief implementation of /public/poll-payment handler - * @author Florian Dold - * @author Christian Grothoff - */ -#include "platform.h" -#include <string.h> -#include <microhttpd.h> -#include <jansson.h> -#include <taler/taler_json_lib.h> -#include <taler/taler_signatures.h> -#include "taler-merchant-httpd.h" -#include "taler-merchant-httpd_mhd.h" -#include "taler-merchant-httpd_exchanges.h" -#include "taler-merchant-httpd_poll-payment.h" - -/** - * Maximum number of retries for database operations. - */ -#define MAX_RETRIES 5 - - -/** - * Data structure we keep for a check payment request. - */ -struct PollPaymentRequestContext -{ - /** - * Must be first for #handle_mhd_completion_callback. - */ - struct TM_HandlerContext hc; - - /** - * Entry in the #resume_timeout_heap for this check payment, if we are - * suspended. - */ - struct TMH_SuspendedConnection sc; - - /** - * Which merchant instance is this for? - */ - struct MerchantInstance *mi; - - /** - * 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; - - /** - * fulfillment URL of the contract (valid as long as - * @e contract_terms is valid). - */ - const char *fulfillment_url; - - /** - * session of the client - */ - const char *session_id; - - /** - * 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; - - /** - * Minimum refund amount the client would like to poll for. - * Only initialized if - * @e awaiting_refund is set to #GNUNET_YES. - */ - struct TALER_Amount min_refund; - - /** - * Set to #GNUNET_YES if this payment has been refunded and - * @e refund_amount is initialized. - */ - int refunded; - - /** - * Set to #GNUNET_YES if this client is waiting for a refund. - */ - int awaiting_refund; - - /** - * Initially #GNUNET_SYSERR. If we queued a response, set to the - * result code (i.e. #MHD_YES or #MHD_NO). FIXME: fix type! - */ - int ret; - -}; - - -/** - * Clean up the session state for a check payment request. - * - * @param hc must be a `struct PollPaymentRequestContext *` - */ -static void -pprc_cleanup (struct TM_HandlerContext *hc) -{ - struct PollPaymentRequestContext *pprc - = (struct PollPaymentRequestContext *) hc; - - if (NULL != pprc->contract_terms) - json_decref (pprc->contract_terms); - GNUNET_free_non_null (pprc->final_contract_url); - GNUNET_free (pprc); -} - - -/** - * Function called with information about a refund. - * It is responsible for summing up the refund amount. - * - * @param cls closure - * @param coin_pub public coin from which the refund comes from - * @param exchange_url URL of the exchange that issued @a coin_pub - * @param rtransaction_id identificator of the refund - * @param reason human-readable explanation of the refund - * @param refund_amount refund amount which is being taken from @a coin_pub - * @param refund_fee cost of this refund operation - */ -static void -process_refunds_cb (void *cls, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const char *exchange_url, - uint64_t rtransaction_id, - const char *reason, - const struct TALER_Amount *refund_amount, - const struct TALER_Amount *refund_fee) -{ - struct PollPaymentRequestContext *pprc = cls; - - if (pprc->refunded) - { - GNUNET_assert (0 <= - TALER_amount_add (&pprc->refund_amount, - &pprc->refund_amount, - refund_amount)); - return; - } - pprc->refund_amount = *refund_amount; - pprc->refunded = GNUNET_YES; -} - - -/** - * Suspend this @a pprc until the trigger is satisfied. - * - * @param ppr - */ -static void -suspend_pprc (struct PollPaymentRequestContext *pprc) -{ - TMH_compute_pay_key (pprc->order_id, - &pprc->mi->pubkey, - &pprc->sc.key); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Suspending /poll-payment on key %s\n", - GNUNET_h2s (&pprc->sc.key)); - TMH_long_poll_suspend (&pprc->sc, - (pprc->awaiting_refund) - ? &pprc->min_refund - : NULL); -} - - -/** - * The client did not yet pay, send it the payment request. - * - * @param pprc check pay request context - * @return #MHD_YES on success - */ -static MHD_RESULT -send_pay_request (struct PollPaymentRequestContext *pprc) -{ - MHD_RESULT ret; - char *already_paid_order_id = NULL; - char *taler_pay_uri; - struct GNUNET_TIME_Relative remaining; - - remaining = GNUNET_TIME_absolute_get_remaining (pprc->sc.long_poll_timeout); - if (0 != remaining.rel_value_us) - { - /* long polling: do not queue a response, suspend connection instead */ - suspend_pprc (pprc); - return MHD_YES; - } - - /* Check if resource_id has been paid for in the same session - * with another order_id. - */ - 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, - pprc->session_id, - pprc->fulfillment_url, - &pprc->mi->pubkey); - if (qs < 0) - { - /* 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 TALER_MHD_reply_with_error (pprc->sc.con, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR, - "db error fetching pay session info"); - } - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Sending payment request in /poll-payment\n"); - taler_pay_uri = TMH_make_taler_pay_uri (pprc->sc.con, - pprc->order_id, - pprc->session_id, - pprc->mi->id); - ret = TALER_MHD_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", pprc->final_contract_url, - "paid", 0, - "already_paid_order_id", - already_paid_order_id); - GNUNET_free (taler_pay_uri); - GNUNET_free_non_null (already_paid_order_id); - return ret; -} - - -/** - * Manages a /public/poll-payment call, checking the status - * of a payment and, if necessary, constructing the URL - * for a payment redirect URL. - * - * @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 - */ -MHD_RESULT -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 PollPaymentRequestContext *pprc = *connection_cls; - enum GNUNET_DB_QueryStatus qs; - MHD_RESULT ret; - - if (NULL == pprc) - { - /* First time here, parse request and check order is known */ - const char *long_poll_timeout_s; - const char *cts; - const char *min_refund; - - pprc = GNUNET_new (struct PollPaymentRequestContext); - pprc->hc.cc = &pprc_cleanup; - pprc->ret = GNUNET_SYSERR; - pprc->sc.con = connection; - pprc->mi = mi; - *connection_cls = pprc; - - pprc->order_id = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "order_id"); - if (NULL == pprc->order_id) - { - /* order_id is required but missing */ - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - 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 TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - 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 TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_PARAMETER_MALFORMED, - "h_contract malformed"); - } - 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 TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_PARAMETER_MALFORMED, - "timeout must be non-negative number"); - } - pprc->sc.long_poll_timeout - = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply ( - GNUNET_TIME_UNIT_SECONDS, - timeout)); - } - else - { - pprc->sc.long_poll_timeout = GNUNET_TIME_UNIT_ZERO_ABS; - } - - min_refund = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "refund"); - if (NULL != min_refund) - { - if ( (GNUNET_OK != - TALER_string_to_amount (min_refund, - &pprc->min_refund)) || - (0 != strcasecmp (pprc->min_refund.currency, - TMH_currency) ) ) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_PARAMETER_MALFORMED, - "invalid amount given for refund argument"); - } - pprc->awaiting_refund = GNUNET_YES; - } - - pprc->contract_url = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "contract_url"); - if (NULL == pprc->contract_url) - { - pprc->final_contract_url = TALER_url_absolute_mhd (connection, - "/public/proposal", - "instance", mi->id, - "order_id", - pprc->order_id, - NULL); - GNUNET_assert (NULL != pprc->final_contract_url); - } - else - { - pprc->final_contract_url = GNUNET_strdup (pprc->contract_url); - } - 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_from_hash (db->cls, - &pprc->contract_terms, - &pprc->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); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR, - "Merchant database error"); - } - if (0 == qs) - { - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - 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); - - { - 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 TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR, - "Merchant database error (contract terms corrupted)"); - } - } - } /* end of first-time initialization / sanity checks */ - - db->preflight (db->cls); - - /* Check if the order has been paid for. */ - 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, - pprc->session_id, - pprc->fulfillment_url, - &mi->pubkey); - if (qs < 0) - { - /* 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 TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR, - "db error fetching pay session info"); - } - else if (0 == qs) - { - ret = send_pay_request (pprc); - GNUNET_free_non_null (already_paid_order_id); - return ret; - } - GNUNET_break (1 == qs); - GNUNET_break (0 == strcmp (pprc->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, - &pprc->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); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR, - "Merchant database error"); - } - if (0 == qs) - { - return send_pay_request (pprc); - } - GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs); - GNUNET_assert (NULL != xcontract_terms); - json_decref (xcontract_terms); - } - - /* Accumulate refunds, if any. */ - for (unsigned int i = 0; i<MAX_RETRIES; i++) - { - pprc->refunded = GNUNET_NO; - qs = db->get_refunds_from_contract_terms_hash (db->cls, - &mi->pubkey, - &pprc->h_contract_terms, - &process_refunds_cb, - pprc); - if (GNUNET_DB_STATUS_SOFT_ERROR != qs) - break; - } - if (0 > qs) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Database hard error on refunds_from_contract_terms_hash lookup: %s\n", - GNUNET_h2s (&pprc->h_contract_terms)); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR, - "Merchant database error"); - } - if ( (pprc->awaiting_refund) && - ( (! pprc->refunded) || - (1 != TALER_amount_cmp (&pprc->refund_amount, - &pprc->min_refund)) ) ) - { - /* Client is waiting for a refund larger than what we have, suspend - until timeout */ - struct GNUNET_TIME_Relative remaining; - - remaining = GNUNET_TIME_absolute_get_remaining (pprc->sc.long_poll_timeout); - if (0 != remaining.rel_value_us) - { - /* yes, indeed suspend */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Awaiting refund exceeding %s\n", - TALER_amount2s (&pprc->min_refund)); - suspend_pprc (pprc); - return MHD_YES; - } - } - - if (pprc->refunded) - return TALER_MHD_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:b, s:b, s:o}", - "paid", 1, - "refunded", pprc->refunded, - "refund_amount", - TALER_JSON_from_amount ( - &pprc->refund_amount)); - return TALER_MHD_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:b, s:b }", - "paid", 1, - "refunded", 0); -} diff --git a/src/backend/taler-merchant-httpd_get-orders-ID-2.h b/src/backend/taler-merchant-httpd_get-orders-ID-2.h deleted file mode 100644 index ac13c4a3..00000000 --- a/src/backend/taler-merchant-httpd_get-orders-ID-2.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - 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 - */ -MHD_RESULT -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_get-orders-ID.c b/src/backend/taler-merchant-httpd_get-orders-ID.c index e86e4e4b..ba0d3544 100644 --- a/src/backend/taler-merchant-httpd_get-orders-ID.c +++ b/src/backend/taler-merchant-httpd_get-orders-ID.c @@ -14,9 +14,10 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ /** - * @file backend/taler-merchant-httpd_refund_lookup.c - * @brief refund handling logic + * @file backend/taler-merchant-httpd_get-orders-ID.c + * @brief implementation of GET /orders/$ID * @author Marcello Stanisci + * @author Christian Grothoff */ #include "platform.h" #include <jansson.h> @@ -59,9 +60,9 @@ struct CoinRefund struct TALER_EXCHANGE_RefundHandle *rh; /** - * PRD this operation is part of. + * Request this operation is part of. */ - struct ProcessRefundData *prd; + struct GetOrderData *god; /** * URL of the exchange for this @e coin_pub. @@ -119,15 +120,10 @@ struct CoinRefund /** - * Closure for #process_refunds_cb. + * Context for the operation. */ -struct ProcessRefundData +struct GetOrderData { - /** - * Must be first for #handle_mhd_completion_callback() cleanup - * logic to work. - */ - struct TM_HandlerContext hc; /** * Hashed version of contract terms. @@ -137,106 +133,186 @@ struct ProcessRefundData /** * DLL of (suspended) requests. */ - struct ProcessRefundData *next; + struct GetOrderData *next; /** * DLL of (suspended) requests. */ - struct ProcessRefundData *prev; + struct GetOrderData *prev; /** - * Head of DLL of coin refunds for this request. + * Context of the request. */ - struct CoinRefund *cr_head; + struct TMH_HandlerContext *hc; /** - * Tail of DLL of coin refunds for this request. + * Did we suspend @a connection? */ - struct CoinRefund *cr_tail; + int suspended; /** - * Both public and private key are needed by the callback + * Return code: #TALER_EC_NONE if successful. */ - const struct MerchantInstance *merchant; + enum TALER_ErrorCode ec; /** - * Connection we are handling. + * Entry in the #resume_timeout_heap for this check payment, if we are + * suspended. */ - struct MHD_Connection *connection; + struct TMH_SuspendedConnection sc; /** - * Did we suspend @a connection? + * Which merchant instance is this for? */ - int suspended; + struct MerchantInstance *mi; /** - * Return code: #TALER_EC_NONE if successful. + * URL where the final contract can be found for this payment. */ - enum TALER_ErrorCode ec; + char *final_contract_url; + + /** + * order ID for the payment + */ + const char *order_id; + + /** + * Where to get the contract + */ + const char *contract_url; + + /** + * fulfillment URL of the contract (valid as long as + * @e contract_terms is valid). + */ + const char *fulfillment_url; + + /** + * session of the client + */ + const char *session_id; + + /** + * 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 true. + */ + struct TALER_Amount refund_amount; + + /** + * Set to true if this payment has been refunded and + * @e refund_amount is initialized. + */ + bool refunded; + + /** + * Initially #GNUNET_SYSERR. If we queued a response, set to the + * result code (i.e. #MHD_YES or #MHD_NO). FIXME: fix type! + */ + int ret; + + }; /** * HEad of DLL of (suspended) requests. */ -static struct ProcessRefundData *prd_head; +static struct GetOrderData *prd_head; /** * Tail of DLL of (suspended) requests. */ -static struct ProcessRefundData *prd_tail; +static struct GetOrderData *prd_tail; + + +/** + * Force resuming all suspended order lookups, needed during shutdown. + */ +void +TMH_force_wallet_get_order_resume (void) +{ + struct GetOrderData *god; + + while (NULL != (god = god_head)) + { + GNUNET_CONTAINER_DLL_remove (god_head, + god_tail, + god); + GNUNET_assert (god->suspended); + god->suspended = GNUNET_NO; + MHD_resume_connection (god->connection); + } +} /** - * Clean up memory in @a cls, the connection was closed. + * The client did not yet pay, send it the payment request. * - * @param cls a `struct ProcessRefundData` to clean up. + * @param god check pay request context + * @return #MHD_YES on success */ -static void -cleanup_prd (struct TM_HandlerContext *cls) +static MHD_RESULT +send_pay_request (struct GetOrderData *god, + const char *already_paid_order_id) { - struct ProcessRefundData *prd = (struct ProcessRefundData *) cls; - struct CoinRefund *cr; + MHD_RESULT ret; + char *taler_pay_uri; + struct GNUNET_TIME_Relative remaining; - while (NULL != (cr = prd->cr_head)) + remaining = GNUNET_TIME_absolute_get_remaining (god->sc.long_poll_timeout); + if (0 != remaining.rel_value_us) { - GNUNET_CONTAINER_DLL_remove (prd->cr_head, - prd->cr_tail, - cr); - if (NULL != cr->fo) - { - TMH_EXCHANGES_find_exchange_cancel (cr->fo); - cr->fo = NULL; - } - if (NULL != cr->rh) - { - TALER_EXCHANGE_refund_cancel (cr->rh); - cr->rh = NULL; - } - if (NULL != cr->exchange_reply) - { - json_decref (cr->exchange_reply); - cr->exchange_reply = NULL; - } - GNUNET_free (cr->exchange_url); - GNUNET_free (cr); + /* long polling: do not queue a response, suspend connection instead */ + suspend_god (god); + return MHD_YES; } - GNUNET_free (prd); + + /* Check if resource_id has been paid for in the same session + * with another order_id. + */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Sending payment request in /poll-payment\n"); + taler_pay_uri = TMH_make_taler_pay_uri (god->sc.con, + god->order_id, + god->session_id, + god->mi->id); + ret = TALER_MHD_reply_json_pack (god->sc.con, + MHD_HTTP_OK, + "{s:s, s:s, s:b, s:s?}", + "taler_pay_uri", taler_pay_uri, + "contract_url", god->final_contract_url, + "paid", 0, + "already_paid_order_id", + already_paid_order_id); + GNUNET_free (taler_pay_uri); + return ret; } /** - * Check if @a prd has sub-activities still pending. + * Check if @a god has sub-activities still pending. * - * @param prd request to check + * @param god request to check * @return #GNUNET_YES if activities are still pending */ static int -prd_pending (struct ProcessRefundData *prd) +god_pending (struct GetOrderData *god) { int pending = GNUNET_NO; - for (struct CoinRefund *cr = prd->cr_head; + for (struct CoinRefund *cr = god->cr_head; NULL != cr; cr = cr->next) { @@ -252,21 +328,21 @@ prd_pending (struct ProcessRefundData *prd) /** - * Check if @a prd is ready to be resumed, and if so, do it. + * Check if @a god is ready to be resumed, and if so, do it. * - * @param prd refund request to be possibly ready + * @param god refund request to be possibly ready */ static void -check_resume_prd (struct ProcessRefundData *prd) +check_resume_god (struct GetOrderData *god) { - if (prd_pending (prd)) + if (god_pending (god)) return; - GNUNET_CONTAINER_DLL_remove (prd_head, - prd_tail, - prd); - GNUNET_assert (prd->suspended); - prd->suspended = GNUNET_NO; - MHD_resume_connection (prd->connection); + GNUNET_CONTAINER_DLL_remove (god_head, + god_tail, + god); + GNUNET_assert (god->suspended); + god->suspended = GNUNET_NO; + MHD_resume_connection (god->connection); TMH_trigger_daemon (); } @@ -306,8 +382,8 @@ refund_cb (void *cls, cr->exchange_pub = *exchange_pub; cr->exchange_sig = *exchange_sig; qs = db->put_refund_proof (db->cls, - &cr->prd->merchant->pubkey, - &cr->prd->h_contract_terms, + &cr->god->merchant->pubkey, + &cr->god->h_contract_terms, &cr->coin_pub, cr->rtransaction_id, exchange_pub, @@ -321,7 +397,7 @@ refund_cb (void *cls, qs); } } - check_resume_prd (cr->prd); + check_resume_god (cr->god); } @@ -350,10 +426,10 @@ exchange_found_cb (void *cls, cr->rh = TALER_EXCHANGE_refund (eh, &cr->refund_amount, &cr->refund_fee, - &cr->prd->h_contract_terms, + &cr->god->h_contract_terms, &cr->coin_pub, cr->rtransaction_id, - &cr->prd->merchant->privkey, + &cr->god->merchant->privkey, &refund_cb, cr); return; @@ -361,7 +437,7 @@ exchange_found_cb (void *cls, cr->exchange_status = hr->http_status; cr->exchange_code = hr->ec; cr->exchange_reply = json_incref ((json_t*) hr->reply); - check_resume_prd (cr->prd); + check_resume_god (cr->god); } @@ -386,7 +462,7 @@ process_refunds_cb (void *cls, const struct TALER_Amount *refund_amount, const struct TALER_Amount *refund_fee) { - struct ProcessRefundData *prd = cls; + struct GetOrderData *god = cls; struct CoinRefund *cr; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -396,83 +472,230 @@ process_refunds_cb (void *cls, reason); cr = GNUNET_new (struct CoinRefund); cr->exchange_url = GNUNET_strdup (exchange_url); - cr->prd = prd; + cr->god = god; cr->coin_pub = *coin_pub; cr->rtransaction_id = rtransaction_id; cr->refund_amount = *refund_amount; cr->refund_fee = *refund_fee; - GNUNET_CONTAINER_DLL_insert (prd->cr_head, - prd->cr_tail, + GNUNET_CONTAINER_DLL_insert (god->cr_head, + god->cr_tail, cr); + if (god->refunded) + { + GNUNET_assert (0 <= + TALER_amount_add (&god->refund_amount, + &god->refund_amount, + refund_amount)); + return; + } + god->refund_amount = *refund_amount; + god->refunded = true; } /** - * Force resuming all suspended refund lookups, needed during shutdown. + * Suspend this @a god until the trigger is satisfied. + * + * @param ppr */ -void -MH_force_refund_resume (void) +static void +suspend_god (struct GetOrderData *god) { - struct ProcessRefundData *prd; + TMH_compute_pay_key (god->order_id, + &god->mi->pubkey, + &god->sc.key); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Suspending /poll-payment on key %s\n", + GNUNET_h2s (&god->sc.key)); + TMH_long_poll_suspend (&god->sc, + (god->sc.awaiting_refund) + ? &god->sc.refund_expected + : NULL); +} - while (NULL != (prd = prd_head)) + +/** + * Clean up the session state for a GET /orders/$ID request. + * + * @param cls must be a `struct GetOrderData *` + */ +static void +god_cleanup (void *cls) +{ + struct GetOrderData *god = cls; + + while (NULL != (cr = god->cr_head)) { - GNUNET_CONTAINER_DLL_remove (prd_head, - prd_tail, - prd); - GNUNET_assert (prd->suspended); - prd->suspended = GNUNET_NO; - MHD_resume_connection (prd->connection); + GNUNET_CONTAINER_DLL_remove (god->cr_head, + god->cr_tail, + cr); + if (NULL != cr->fo) + { + TMH_EXCHANGES_find_exchange_cancel (cr->fo); + cr->fo = NULL; + } + if (NULL != cr->rh) + { + TALER_EXCHANGE_refund_cancel (cr->rh); + cr->rh = NULL; + } + if (NULL != cr->exchange_reply) + { + json_decref (cr->exchange_reply); + cr->exchange_reply = NULL; + } + GNUNET_free (cr->exchange_url); + GNUNET_free (cr); } + + if (NULL != god->contract_terms) + json_decref (god->contract_terms); + GNUNET_free_non_null (god->final_contract_url); + GNUNET_free (god); } /** - * Return refund situation about a contract. + * Handle a GET "/orders/$ID" request. * * @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 + * @param[in,out] hc context with further information about the request * @return MHD result code */ MHD_RESULT -MH_handler_refund_lookup (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size, - struct MerchantInstance *mi) +TMH_get_orders_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) { - struct ProcessRefundData *prd; - const char *order_id; - json_t *contract_terms; + struct GetOrderData *god = hc->ctx; + const char *order_id = hc->infix; enum GNUNET_DB_QueryStatus qs; - prd = *connection_cls; - if (NULL == prd) + if (NULL == god) { - order_id = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "order_id"); - if (NULL == order_id) + god = GNUNET_new (struct GetOrderData); + hc->ctx = god; + god->hc.cc = &god_cleanup; + god->sc.con = connection; + god->ec = TALER_EC_NONE; + god->connection = connection; + god->hc = hc; + god->ret = GNUNET_SYSERR; + { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_PARAMETER_MISSING, - "order_id"); + const char *cts; + + 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 TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_PARAMETER_MISSING, + "h_contract required"); + } + if (GNUNET_OK != + GNUNET_CRYPTO_hash_from_string (cts, + &god->h_contract_terms)) + { + /* cts has wrong encoding */ + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_PARAMETER_MALFORMED, + "h_contract malformed"); + } + } + + { + const char *long_poll_timeout_s; + + 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 TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_PARAMETER_MALFORMED, + "timeout must be non-negative number"); + } + god->sc.long_poll_timeout + = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_SECONDS, + timeout)); + } + else + { + god->sc.long_poll_timeout = GNUNET_TIME_UNIT_ZERO_ABS; + } } + { + const char *min_refund; + + min_refund = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "refund"); + if (NULL != min_refund) + { + if ( (GNUNET_OK != + TALER_string_to_amount (min_refund, + &god->sc.refund_expected)) || + (0 != strcasecmp (god->sc.refund_expected.currency, + TMH_currency) ) ) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_PARAMETER_MALFORMED, + "invalid amount given for refund argument"); + } + god->sc.awaiting_refund = true; + } + } + + // FIXME: what is this about again??? + god->contract_url = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "contract_url"); + if (NULL == god->contract_url) + { + // FIXME: this can't be right anymore... + god->final_contract_url = TALER_url_absolute_mhd (connection, + "/public/proposal", + "instance", mi->id, + "order_id", + god->order_id, + NULL); + GNUNET_assert (NULL != god->final_contract_url); + } + else + { + god->final_contract_url = GNUNET_strdup (god->contract_url); + } + + god->session_id = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "session_id"); + /* Convert order id to h_contract_terms */ - contract_terms = NULL; db->preflight (db->cls); qs = db->find_contract_terms (db->cls, - &contract_terms, + hc->instance->settings.id, order_id, - &mi->pubkey); + &god->contract_terms); if (0 > qs) { /* single, read-only SQL statements should never cause @@ -483,9 +706,8 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh, return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_REFUND_LOOKUP_DB_ERROR, - "database error looking up order_id from merchant_contract_terms table"); + "database error looking up contract"); } - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -493,108 +715,210 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh, order_id); return TALER_MHD_reply_with_error (connection, MHD_HTTP_NOT_FOUND, - TALER_EC_REFUND_ORDER_ID_UNKNOWN, + TALER_EC_ORDER_ID_UNKNOWN, "order_id not found in database"); } - prd = GNUNET_new (struct ProcessRefundData); - if (GNUNET_OK != - TALER_JSON_hash (contract_terms, - &prd->h_contract_terms)) + /* Check client provided the right hash code of the contract terms */ + { + struct GNUNET_HashCode h; + + if (GNUNET_OK != + TALER_JSON_hash (god->contract_terms, + &h)) + { + GNUNET_break (0); + GNUNET_free (god); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_INTERNAL_LOGIC_ERROR, + "Could not hash contract terms"); + } + if (0 != + GNUNET_memcmp (&h, + &god->h_contract_terms)) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_WRONG_CONTRACT, + "Contract hash does not match order"); + } + } + + { + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("fulfillment_url", + &god->fulfillment_url), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (god->contract_terms, + spec, + NULL, NULL)) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_CHECK_PAYMENT_DB_FETCH_CONTRACT_TERMS_ERROR, + "Merchant database error (contract terms corrupted)"); + } + } + } /* end of first-time initialization / sanity checks */ + + if ( (NULL != god->session_id) && + (NULL != god->fulfillment_url) ) + { + /* Check if paid within a session. */ + char *already_paid_order_id = NULL; + + qs = db->find_session_info (db->cls, + &already_paid_order_id, + god->session_id, + god->fulfillment_url, + &mi->pubkey); + if (qs < 0) { - GNUNET_break (0); - json_decref (contract_terms); - GNUNET_free (prd); + /* 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 TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_INTERNAL_LOGIC_ERROR, - "Could not hash contract terms"); + TALER_EC_CHECK_PAYMENT_DB_FETCH_ORDER_ERROR, + "db error fetching pay session info"); } - json_decref (contract_terms); - prd->hc.cc = &cleanup_prd; - prd->merchant = mi; - prd->ec = TALER_EC_NONE; - prd->connection = connection; - *connection_cls = prd; - - for (unsigned int i = 0; i<MAX_RETRIES; i++) + else if (0 == qs) { - qs = db->get_refunds_from_contract_terms_hash (db->cls, - &mi->pubkey, - &prd->h_contract_terms, - &process_refunds_cb, - prd); - if (GNUNET_DB_STATUS_SOFT_ERROR != qs) - break; + ret = send_pay_request (god, + already_paid_order_id); + 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_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, + &god->h_contract_terms, + &mi->pubkey); if (0 > qs) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Database hard error on refunds_from_contract_terms_hash lookup: %s\n", - GNUNET_h2s (&prd->h_contract_terms)); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_REFUND_LOOKUP_DB_ERROR, - "Failed to lookup refunds for contract"); + TALER_EC_PAY_DB_FETCH_TRANSACTION_ERROR, + "Merchant database error"); + } + if (0 == qs) + { + return send_pay_request (god, + NULL); } + GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs); + GNUNET_assert (NULL != xcontract_terms); + json_decref (xcontract_terms); + } - /* Now launch exchange interactions, unless we already have the - response in the database! */ - for (struct CoinRefund *cr = prd->cr_head; - NULL != cr; - cr = cr->next) + + for (unsigned int i = 0; i<MAX_RETRIES; i++) + { + qs = db->get_refunds_from_contract_terms_hash (db->cls, + hc->instance->settings.id, + &god->h_contract_terms, + &process_refunds_cb, + god); + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + break; + } + if (0 > qs) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFUND_LOOKUP_DB_ERROR, + "Failed to lookup refunds for contract"); + } + + /* Now launch exchange interactions, unless we already have the + response in the database! */ + for (struct CoinRefund *cr = god->cr_head; + NULL != cr; + cr = cr->next) + { + enum GNUNET_DB_QueryStatus qs; + + qs = db->get_refund_proof (db->cls, + &cr->god->merchant->pubkey, + &cr->god->h_contract_terms, + &cr->coin_pub, + cr->rtransaction_id, + &cr->exchange_pub, + &cr->exchange_sig); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { - enum GNUNET_DB_QueryStatus qs; - - qs = db->get_refund_proof (db->cls, - &cr->prd->merchant->pubkey, - &cr->prd->h_contract_terms, - &cr->coin_pub, - cr->rtransaction_id, - &cr->exchange_pub, - &cr->exchange_sig); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) - { - /* We need to talk to the exchange */ - cr->fo = TMH_EXCHANGES_find_exchange (cr->exchange_url, - NULL, - GNUNET_NO, - &exchange_found_cb, - cr); - } + /* We need to talk to the exchange */ + cr->fo = TMH_EXCHANGES_find_exchange (cr->exchange_url, + NULL, + GNUNET_NO, + &exchange_found_cb, + cr); } } + if ( (god->awaiting_refund) && + ( (! god->refunded) || + (1 != TALER_amount_cmp (&god->refund_amount, + &god->min_refund)) ) ) + { + /* Client is waiting for a refund larger than what we have, suspend + until timeout */ + struct GNUNET_TIME_Relative remaining; + + remaining = GNUNET_TIME_absolute_get_remaining (god->sc.long_poll_timeout); + if (0 != remaining.rel_value_us) + { + /* yes, indeed suspend */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Awaiting refund exceeding %s\n", + TALER_amount2s (&god->min_refund)); + suspend_god (god); + return MHD_YES; + } + } + + /* Check if there are still exchange operations pending */ - if (GNUNET_YES == prd_pending (prd)) + if (GNUNET_YES == god_pending (god)) { - if (! prd->suspended) + if (! god->suspended) { - prd->suspended = GNUNET_YES; + god->suspended = GNUNET_YES; MHD_suspend_connection (connection); - GNUNET_CONTAINER_DLL_insert (prd_head, - prd_tail, - prd); + GNUNET_CONTAINER_DLL_insert (god_head, + god_tail, + god); } return MHD_YES; /* we're still talking to the exchange */ } /* All operations done, build final response */ - if (NULL == prd->cr_head) - { - /* There ARE no refunds scheduled, bitch */ - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_REFUND_LOOKUP_NO_REFUND, - "This contract is not currently eligible for refunds"); - } - { json_t *ra; ra = json_array (); GNUNET_assert (NULL != ra); - for (struct CoinRefund *cr = prd->cr_head; + for (struct CoinRefund *cr = god->cr_head; NULL != cr; cr = cr->next) { @@ -637,6 +961,23 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh, GNUNET_JSON_from_data_auto (&cr->exchange_sig) ))); } + + if (god->refunded) + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:b, s:b, s:o}", + "paid", 1, + "refunded", god->refunded, + "refund_amount", + TALER_JSON_from_amount ( + &god->refund_amount)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:b, s:b }", + "paid", 1, + "refunded", 0); + + return TALER_MHD_reply_json_pack ( connection, MHD_HTTP_OK, @@ -646,9 +987,9 @@ MH_handler_refund_lookup (struct TMH_RequestHandler *rh, "merchant_pub", GNUNET_JSON_from_data_auto (&mi->pubkey), "h_contract_terms", - GNUNET_JSON_from_data_auto (&prd->h_contract_terms)); + GNUNET_JSON_from_data_auto (&god->h_contract_terms)); } } -/* end of taler-merchant-httpd_refund_lookup.c */ +/* end of taler-merchant-httpd_get-orders-ID.c */ diff --git a/src/backend/taler-merchant-httpd_get-orders-ID.h b/src/backend/taler-merchant-httpd_get-orders-ID.h index 24495daf..3aa157da 100644 --- a/src/backend/taler-merchant-httpd_get-orders-ID.h +++ b/src/backend/taler-merchant-httpd_get-orders-ID.h @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2014, 2015, 2016, 2017 Taler Systems SA + (C) 2014, 2015, 2016, 2017, 2020 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -13,36 +13,28 @@ 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_refund_lookup.h - * @brief + * @file backend/taler-merchant-httpd_get-orders-ID.h + * @brief implementation of GET /orders/$ID * @author Marcello Stanisci */ - -#ifndef TALER_MERCHANT_HTTPD_REFUND_LOOKUP_H -#define TALER_MERCHANT_HTTPD_REFUND_LOOKUP_H +#ifndef TALER_MERCHANT_HTTPD_GET_ORDERS_ID_H +#define TALER_MERCHANT_HTTPD_GET_ORDERS_ID_H #include <microhttpd.h> #include "taler-merchant-httpd.h" /** - * Return refund situation about a contract. + * Handle a GET "/orders/$ID" request. * * @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 + * @param[in,out] hc context with further information about the request * @return MHD result code */ MHD_RESULT -MH_handler_refund_lookup (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size, - struct MerchantInstance *mi); +TMH_get_orders_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); #endif |