summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2021-07-23 17:07:51 +0200
committerChristian Grothoff <christian@grothoff.org>2021-07-23 17:07:51 +0200
commit590bb2c6d181bd703ff4b1c528662898f28eab79 (patch)
tree1f16f3f5eef85ea7438c11d32dfafb83c3f0ef21 /src
parentd5b2b639dab3074307bbfdbd58627bb3253163ab (diff)
downloadmerchant-590bb2c6d181bd703ff4b1c528662898f28eab79.tar.gz
merchant-590bb2c6d181bd703ff4b1c528662898f28eab79.tar.bz2
merchant-590bb2c6d181bd703ff4b1c528662898f28eab79.zip
-misc backend changes from workshop
Diffstat (limited to 'src')
-rw-r--r--src/backend/taler-merchant-httpd.c1
-rw-r--r--src/backend/taler-merchant-httpd_get-orders-ID.c313
-rw-r--r--src/backend/taler-merchant-httpd_get-orders-ID.h7
-rw-r--r--src/backend/taler-merchant-httpd_private-get-orders-ID.c11
4 files changed, 194 insertions, 138 deletions
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index 277f7480..ac223a5b 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -703,6 +703,7 @@ do_shutdown (void *cls)
TMH_force_rc_resume ();
TMH_force_post_transfers_resume ();
TMH_force_tip_pickup_resume ();
+ TMH_force_wallet_get_order_resume ();
TMH_force_wallet_refund_order_resume ();
if (NULL != mhd_task)
{
diff --git a/src/backend/taler-merchant-httpd_get-orders-ID.c b/src/backend/taler-merchant-httpd_get-orders-ID.c
index 110333fc..b061ff43 100644
--- a/src/backend/taler-merchant-httpd_get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_get-orders-ID.c
@@ -119,7 +119,8 @@ struct GetOrderData
enum TALER_ErrorCode ec;
/**
- * Did we suspend @a connection?
+ * Did we suspend @a connection and are thus in
+ * the #god_head DLL?
*/
bool suspended;
@@ -161,9 +162,6 @@ static struct GetOrderData *god_head;
static struct GetOrderData *god_tail;
-/**
- * Force resuming all suspended order lookups, needed during shutdown.
- */
void
TMH_force_wallet_get_order_resume (void)
{
@@ -192,6 +190,11 @@ suspend_god (struct GetOrderData *god)
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Suspending GET /orders/%s\n",
god->order_id);
+ GNUNET_assert (! god->suspended);
+ god->suspended = true;
+ GNUNET_CONTAINER_DLL_insert (god_head,
+ god_tail,
+ god);
TMH_long_poll_suspend (god->order_id,
god->session_id,
god->fulfillment_url,
@@ -231,7 +234,6 @@ make_taler_refund_uri (const char *merchant_base_url,
return NULL;
}
GNUNET_assert (NULL != order_id);
-
GNUNET_buffer_write_str (&buf,
"taler");
if (0 == strcasecmp ("http",
@@ -275,23 +277,25 @@ TMH_make_order_status_url (struct MHD_Connection *con,
host = MHD_lookup_connection_value (con,
MHD_HEADER_KIND,
- "Host");
+ MHD_HTTP_HEADER_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 != forwarded_host)
host = forwarded_host;
-
if (NULL == host)
{
GNUNET_break (0);
return NULL;
}
-
+ if (NULL != strchr (host, '/'))
+ {
+ GNUNET_break_op (0);
+ return NULL;
+ }
GNUNET_assert (NULL != instance_id);
GNUNET_assert (NULL != order_id);
@@ -301,7 +305,6 @@ TMH_make_order_status_url (struct MHD_Connection *con,
else
GNUNET_buffer_write_str (&buf,
"https://");
-
GNUNET_buffer_write_str (&buf,
host);
if (NULL != uri_path)
@@ -322,6 +325,7 @@ TMH_make_order_status_url (struct MHD_Connection *con,
if ((NULL != claim_token) &&
(GNUNET_NO == GNUNET_is_zero (claim_token)))
{
+ /* 'token=' for human readability */
GNUNET_buffer_write_str (&buf,
"?token=");
GNUNET_buffer_write_data_encoded (&buf,
@@ -374,26 +378,27 @@ TMH_make_taler_pay_uri (struct MHD_Connection *con,
host = MHD_lookup_connection_value (con,
MHD_HEADER_KIND,
- "Host");
+ MHD_HTTP_HEADER_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 != forwarded_host)
host = forwarded_host;
-
if (NULL == host)
{
GNUNET_break (0);
return NULL;
}
-
+ if (NULL != strchr (host, '/'))
+ {
+ GNUNET_break_op (0);
+ return NULL;
+ }
GNUNET_assert (NULL != instance_id);
GNUNET_assert (NULL != order_id);
-
GNUNET_buffer_write_str (&buf,
"taler");
if (GNUNET_NO == TALER_mhd_is_https (con))
@@ -421,6 +426,8 @@ TMH_make_taler_pay_uri (struct MHD_Connection *con,
if ((NULL != claim_token) &&
(GNUNET_NO == GNUNET_is_zero (claim_token)))
{
+ /* Just 'c=' because this goes into QR
+ codes, so this is more compact. */
GNUNET_buffer_write_str (&buf,
"?c=");
GNUNET_buffer_write_data_encoded (&buf,
@@ -437,10 +444,10 @@ TMH_make_taler_pay_uri (struct MHD_Connection *con,
* preferred language of the HTTP client.
*
* @param god order to extract summary from
- * @return NULL if no summary was provided in the contract
+ * @return dummy error message summary if no summary was provided in the contract
*/
static const char *
-get_order_summary (struct GetOrderData *god)
+get_order_summary (const struct GetOrderData *god)
{
const char *language_pattern;
const char *ret;
@@ -455,8 +462,10 @@ get_order_summary (struct GetOrderData *god)
"summary"));
if (NULL == ret)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "No order summary found!\n");
+ /* Upon order creation (and insertion into the database), the presence
+ of a summary should have been checked. So if we get here, someone
+ did something fishy to our database... */
+ GNUNET_break (0);
ret = "<bug: no summary>";
}
return ret;
@@ -483,8 +492,7 @@ send_pay_request (struct GetOrderData *god,
remaining = GNUNET_TIME_absolute_get_remaining (god->sc.long_poll_timeout);
if ( (0 != remaining.rel_value_us) &&
- ( (NULL == already_paid_order_id) ||
- (NULL == god->fulfillment_url) ) )
+ (NULL == already_paid_order_id) )
{
/* long polling: do not queue a response, suspend connection instead */
suspend_god (god);
@@ -507,19 +515,28 @@ send_pay_request (struct GetOrderData *god,
god->hc->instance->settings.id,
&god->claim_token,
NULL);
+ if ( (NULL == taler_pay_uri) ||
+ (NULL == order_status_url) )
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (taler_pay_uri);
+ GNUNET_free (order_status_url);
+ return TALER_MHD_reply_with_error (god->sc.con,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED,
+ "host");
+ }
if (god->generate_html)
{
- char *qr;
-
- if ( (NULL != already_paid_order_id) &&
- (NULL != god->fulfillment_url) )
+ if (NULL != already_paid_order_id)
{
struct MHD_Response *reply;
- MHD_RESULT ret;
+ GNUNET_assert (NULL != god->fulfillment_url);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Redirecting to already paid order %s\n",
- already_paid_order_id);
+ "Redirecting to already paid order %s via fulfillment URL %s\n",
+ already_paid_order_id,
+ god->fulfillment_url);
reply = MHD_create_response_from_buffer (0,
NULL,
MHD_RESPMEM_PERSISTENT);
@@ -532,50 +549,61 @@ send_pay_request (struct GetOrderData *god,
MHD_add_response_header (reply,
MHD_HTTP_HEADER_LOCATION,
god->fulfillment_url));
- ret = MHD_queue_response (god->sc.con,
- MHD_HTTP_FOUND,
- reply);
- MHD_destroy_response (reply);
- return ret;
- }
+ {
+ MHD_RESULT ret;
- qr = TMH_create_qrcode (taler_pay_uri);
- if (NULL == qr)
- {
- GNUNET_break (0);
- return MHD_NO;
+ ret = MHD_queue_response (god->sc.con,
+ MHD_HTTP_FOUND,
+ reply);
+ MHD_destroy_response (reply);
+ return ret;
+ }
}
+
{
- enum GNUNET_GenericReturnValue res;
- json_t *context;
+ char *qr;
- context = json_pack ("{s:s, s:s, s:s, s:s}",
- "taler_pay_uri",
- taler_pay_uri,
- "order_status_url",
- order_status_url,
- "taler_pay_qrcode_svg",
- qr,
- "order_summary",
- get_order_summary (god));
- GNUNET_assert (NULL != context);
- res = TMH_return_from_template (god->sc.con,
- MHD_HTTP_PAYMENT_REQUIRED,
- "request_payment",
- god->hc->instance->settings.id,
- taler_pay_uri,
- context);
- if (GNUNET_SYSERR == res)
+ qr = TMH_create_qrcode (taler_pay_uri);
+ if (NULL == qr)
{
GNUNET_break (0);
- ret = MHD_NO;
+ return MHD_NO;
}
- ret = MHD_YES;
- json_decref (context);
+ {
+ enum GNUNET_GenericReturnValue res;
+ json_t *context;
+
+ context = json_pack ("{s:s, s:s, s:s, s:s}",
+ "taler_pay_uri",
+ taler_pay_uri,
+ "order_status_url",
+ order_status_url,
+ "taler_pay_qrcode_svg",
+ qr,
+ "order_summary",
+ get_order_summary (god));
+ GNUNET_assert (NULL != context);
+ res = TMH_return_from_template (god->sc.con,
+ MHD_HTTP_PAYMENT_REQUIRED,
+ "request_payment",
+ god->hc->instance->settings.id,
+ taler_pay_uri,
+ context);
+ if (GNUNET_SYSERR == res)
+ {
+ GNUNET_break (0);
+ ret = MHD_NO;
+ }
+ else
+ {
+ ret = MHD_YES;
+ }
+ json_decref (context);
+ }
+ GNUNET_free (qr);
}
- GNUNET_free (qr);
}
- else
+ else /* end of 'generate HTML' */
{
ret = TALER_MHD_reply_json_pack (god->sc.con,
MHD_HTTP_PAYMENT_REQUIRED,
@@ -586,7 +614,6 @@ send_pay_request (struct GetOrderData *god,
god->fulfillment_url,
"already_paid_order_id",
already_paid_order_id);
-
}
GNUNET_free (taler_pay_uri);
GNUNET_free (order_status_url);
@@ -626,6 +653,7 @@ process_refunds_cb (void *cls,
TALER_amount2s (refund_amount),
TALER_B2S (coin_pub),
reason);
+ god->refund_available |= pending;
if (god->refunded)
{
GNUNET_assert (0 <=
@@ -636,7 +664,6 @@ process_refunds_cb (void *cls,
}
god->refund_amount = *refund_amount;
god->refunded = true;
- god->refund_available |= pending;
}
@@ -794,6 +821,14 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
}
} /* end of first-time initialization / sanity checks */
+ if (god->suspended)
+ {
+ god->suspended = false;
+ GNUNET_CONTAINER_DLL_remove (god_head,
+ god_tail,
+ god);
+ }
+
/* Convert order_id to h_contract_terms */
TMH_db->preflight (TMH_db->cls);
if (NULL == god->contract_terms)
@@ -1006,7 +1041,14 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
if ( (NULL != god->session_id) &&
(NULL != god->fulfillment_url) )
{
- /* Check if paid within a session. */
+ /* Check if client paid for this fulfillment article
+ already within this session, but using a different
+ order ID. If so, redirect the client to the order
+ it already paid. Allows, for example, the case
+ where a mobile phone pays for a browser's session,
+ where the mobile phone has a different order
+ ID (because it purchased the article earlier)
+ than the one that the browser is waiting for. */
char *already_paid_order_id = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1045,7 +1087,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
GNUNET_free (already_paid_order_id);
return ret;
}
- GNUNET_break (1 == qs);
+ GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
GNUNET_free (already_paid_order_id);
}
@@ -1066,7 +1108,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
- "order status");
+ "lookup_order_status");
}
GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
if (! paid)
@@ -1095,7 +1137,7 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
- "refunds, detailed");
+ "lookup_refunds_detailed");
}
if ( ((god->sc.awaiting_refund) &&
@@ -1126,99 +1168,94 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh,
}
/* All operations done, build final response */
+ if (god->generate_html)
{
- if (god->generate_html)
+ enum GNUNET_GenericReturnValue res;
+
+ if (god->refund_available)
{
- enum GNUNET_GenericReturnValue res;
+ char *qr;
+ char *uri;
- if (god->refund_available)
+ GNUNET_assert (NULL != god->contract_terms);
+ uri = make_taler_refund_uri (merchant_base_url,
+ order_id);
+ if (NULL == uri)
{
- char *qr;
- char *uri;
-
- GNUNET_assert (NULL != god->contract_terms);
- uri = make_taler_refund_uri (merchant_base_url,
- order_id);
- if (NULL == uri)
- {
- GNUNET_break (0);
- return TALER_MHD_reply_with_error (god->sc.con,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_ALLOCATION_FAILURE,
- "refund URI");
- }
- qr = TMH_create_qrcode (uri);
- if (NULL == qr)
- {
- GNUNET_break (0);
- GNUNET_free (uri);
- return TALER_MHD_reply_with_error (god->sc.con,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_ALLOCATION_FAILURE,
- "qr code");
- }
- {
- json_t *context;
-
- context = json_pack ("{s:s, s:s, s:s, s:s}",
- "order_summary",
- get_order_summary (god),
- "refund_amount",
- TALER_amount2s (&god->refund_amount),
- "taler_refund_uri",
- uri,
- "taler_refund_qrcode_svg",
- qr);
- GNUNET_assert (NULL != context);
- res = TMH_return_from_template (god->sc.con,
- MHD_HTTP_OK,
- "offer_refund",
- hc->instance->settings.id,
- uri,
- context);
- json_decref (context);
- }
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (god->sc.con,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_ALLOCATION_FAILURE,
+ "refund URI");
+ }
+ qr = TMH_create_qrcode (uri);
+ if (NULL == qr)
+ {
+ GNUNET_break (0);
GNUNET_free (uri);
- GNUNET_free (qr);
+ return TALER_MHD_reply_with_error (god->sc.con,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_ALLOCATION_FAILURE,
+ "qr code");
}
- else
{
json_t *context;
- context = json_pack ("{s:O, s:s, s:s}",
- "contract_terms",
- god->contract_terms,
+ context = json_pack ("{s:s, s:s, s:s, s:s}",
"order_summary",
get_order_summary (god),
"refund_amount",
- TALER_amount2s (&god->refund_amount));
+ TALER_amount2s (&god->refund_amount),
+ "taler_refund_uri",
+ uri,
+ "taler_refund_qrcode_svg",
+ qr);
GNUNET_assert (NULL != context);
res = TMH_return_from_template (god->sc.con,
MHD_HTTP_OK,
- "show_order_details",
+ "offer_refund",
hc->instance->settings.id,
- NULL,
+ uri,
context);
json_decref (context);
}
- if (GNUNET_SYSERR == res)
- {
- GNUNET_break (0);
- return MHD_NO;
- }
- return MHD_YES;
+ GNUNET_free (uri);
+ GNUNET_free (qr);
}
else
{
- return TALER_MHD_reply_json_pack (
- connection,
- MHD_HTTP_OK,
- "{s:b, s:b, s:o}",
- "refunded", god->refunded,
- "refund_pending", god->refund_available,
- "refund_amount", TALER_JSON_from_amount (&god->refund_amount));
+ json_t *context;
+
+ context = json_pack ("{s:O, s:s, s:s}",
+ "contract_terms",
+ god->contract_terms,
+ "order_summary",
+ get_order_summary (god),
+ "refund_amount",
+ TALER_amount2s (&god->refund_amount));
+ GNUNET_assert (NULL != context);
+ res = TMH_return_from_template (god->sc.con,
+ MHD_HTTP_OK,
+ "show_order_details",
+ hc->instance->settings.id,
+ NULL,
+ context);
+ json_decref (context);
+ }
+ if (GNUNET_SYSERR == res)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
}
+ return MHD_YES;
}
+ return TALER_MHD_reply_json_pack (
+ connection,
+ MHD_HTTP_OK,
+ "{s:b, s:b, s:o}",
+ "refunded", god->refunded,
+ "refund_pending", god->refund_available,
+ "refund_amount", TALER_JSON_from_amount (&god->refund_amount));
}
diff --git a/src/backend/taler-merchant-httpd_get-orders-ID.h b/src/backend/taler-merchant-httpd_get-orders-ID.h
index b75e794f..67dd2a1a 100644
--- a/src/backend/taler-merchant-httpd_get-orders-ID.h
+++ b/src/backend/taler-merchant-httpd_get-orders-ID.h
@@ -25,6 +25,13 @@
/**
+ * Force resuming all suspended order lookups, needed during shutdown.
+ */
+void
+TMH_force_wallet_get_order_resume (void);
+
+
+/**
* Create a taler://pay/ URI for the given @a con and @a order_id
* and @a session_id and @a instance_id.
*
diff --git a/src/backend/taler-merchant-httpd_private-get-orders-ID.c b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
index ed276b42..bf5e2f65 100644
--- a/src/backend/taler-merchant-httpd_private-get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
@@ -1045,6 +1045,17 @@ TMH_private_get_orders_ID (const struct TMH_RequestHandler *rh,
hc->instance->settings.id,
&claim_token,
NULL);
+ if ( (NULL == taler_pay_uri) ||
+ (NULL == order_status_url) )
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (taler_pay_uri);
+ GNUNET_free (order_status_url);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED,
+ "host");
+ }
ret = TALER_MHD_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:s, s:s, s:s, s:s, s:s"