diff options
Diffstat (limited to 'src/lib/merchant_api_merchant_get_order.c')
-rw-r--r-- | src/lib/merchant_api_merchant_get_order.c | 483 |
1 files changed, 222 insertions, 261 deletions
diff --git a/src/lib/merchant_api_merchant_get_order.c b/src/lib/merchant_api_merchant_get_order.c index 167e46be..3bd4003b 100644 --- a/src/lib/merchant_api_merchant_get_order.c +++ b/src/lib/merchant_api_merchant_get_order.c @@ -34,6 +34,17 @@ /** + * Maximum number of refund details we return. + */ +#define MAX_REFUND_DETAILS 1024 + +/** + * Maximum number of wire details we return. + */ +#define MAX_WIRE_DETAILS 1024 + + +/** * @brief A GET /private/orders/$ORDER handle */ struct TALER_MERCHANT_OrderMerchantGetHandle @@ -72,47 +83,48 @@ struct TALER_MERCHANT_OrderMerchantGetHandle * the response and call the callback. * * @param omgh handle for the request - * @param[in,out] hr HTTP response we got + * @param[in,out] osr HTTP response we got */ static void handle_unpaid (struct TALER_MERCHANT_OrderMerchantGetHandle *omgh, - struct TALER_MERCHANT_HttpResponse *hr) + struct TALER_MERCHANT_OrderStatusResponse *osr) { - struct TALER_MERCHANT_OrderStatusResponse osr = { - .status = TALER_MERCHANT_OSC_UNPAID - }; struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount_any ("total_amount", - &osr.details.unpaid.contract_amount), + TALER_JSON_spec_amount_any ( + "total_amount", + &osr->details.ok.details.unpaid.contract_amount), GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("already_paid_order_id", - &osr.details.unpaid.already_paid_order_id), + GNUNET_JSON_spec_string ( + "already_paid_order_id", + &osr->details.ok.details.unpaid.already_paid_order_id), NULL), - GNUNET_JSON_spec_string ("taler_pay_uri", - &osr.details.unpaid.taler_pay_uri), - GNUNET_JSON_spec_string ("summary", - &osr.details.unpaid.summary), - GNUNET_JSON_spec_timestamp ("creation_time", - &osr.details.unpaid.creation_time), + GNUNET_JSON_spec_string ( + "taler_pay_uri", + &osr->details.ok.details.unpaid.taler_pay_uri), + GNUNET_JSON_spec_string ( + "summary", + &osr->details.ok.details.unpaid.summary), + GNUNET_JSON_spec_timestamp ( + "creation_time", + &osr->details.ok.details.unpaid.creation_time), GNUNET_JSON_spec_end () }; if (GNUNET_OK != - GNUNET_JSON_parse (hr->reply, + GNUNET_JSON_parse (osr->hr.reply, spec, NULL, NULL)) { GNUNET_break_op (0); - hr->http_status = 0; - hr->ec = TALER_EC_GENERIC_REPLY_MALFORMED; + osr->hr.http_status = 0; + osr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; omgh->cb (omgh->cb_cls, - hr, - NULL); + osr); return; } + osr->details.ok.status = TALER_MERCHANT_OSC_UNPAID; omgh->cb (omgh->cb_cls, - hr, - &osr); + osr); } @@ -122,38 +134,34 @@ handle_unpaid (struct TALER_MERCHANT_OrderMerchantGetHandle *omgh, * paid. Parse the response and call the callback. * * @param omgh handle for the request - * @param[in,out] hr HTTP response we got + * @param[in,out] osr HTTP response we got */ static void handle_claimed (struct TALER_MERCHANT_OrderMerchantGetHandle *omgh, - struct TALER_MERCHANT_HttpResponse *hr) + struct TALER_MERCHANT_OrderStatusResponse *osr) { - struct TALER_MERCHANT_OrderStatusResponse osr = { - .status = TALER_MERCHANT_OSC_CLAIMED - }; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_json ("contract_terms", - (json_t **) &osr.details.claimed.contract_terms), + GNUNET_JSON_spec_object_const ( + "contract_terms", + &osr->details.ok.details.claimed.contract_terms), GNUNET_JSON_spec_end () }; if (GNUNET_OK != - GNUNET_JSON_parse (hr->reply, + GNUNET_JSON_parse (osr->hr.reply, spec, NULL, NULL)) { GNUNET_break_op (0); - hr->http_status = 0; - hr->ec = TALER_EC_GENERIC_REPLY_MALFORMED; + osr->hr.http_status = 0; + osr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; omgh->cb (omgh->cb_cls, - hr, - NULL); + osr); return; } + osr->details.ok.status = TALER_MERCHANT_OSC_CLAIMED; omgh->cb (omgh->cb_cls, - hr, - &osr); - GNUNET_JSON_parse_free (spec); + osr); } @@ -163,200 +171,158 @@ handle_claimed (struct TALER_MERCHANT_OrderMerchantGetHandle *omgh, * the response and call the callback. * * @param omgh handle for the request - * @param[in,out] hr HTTP response we got + * @param[in,out] osr HTTP response we got */ static void handle_paid (struct TALER_MERCHANT_OrderMerchantGetHandle *omgh, - struct TALER_MERCHANT_HttpResponse *hr) + struct TALER_MERCHANT_OrderStatusResponse *osr) { - uint32_t ec32; uint32_t hc32; - json_t *wire_details; - json_t *wire_reports; - json_t *refund_details; - struct TALER_MERCHANT_OrderStatusResponse osr = { - .status = TALER_MERCHANT_OSC_PAID - }; + const json_t *wire_details; + const json_t *refund_details; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_bool ("refunded", - &osr.details.paid.refunded), + &osr->details.ok.details.paid.refunded), GNUNET_JSON_spec_bool ("refund_pending", - &osr.details.paid.refund_pending), + &osr->details.ok.details.paid.refund_pending), GNUNET_JSON_spec_bool ("wired", - &osr.details.paid.wired), + &osr->details.ok.details.paid.wired), TALER_JSON_spec_amount_any ("deposit_total", - &osr.details.paid.deposit_total), - GNUNET_JSON_spec_uint32 ("exchange_code", - &ec32), + &osr->details.ok.details.paid.deposit_total), + TALER_JSON_spec_ec ("exchange_code", + &osr->details.ok.details.paid.exchange_ec), GNUNET_JSON_spec_uint32 ("exchange_http_status", &hc32), TALER_JSON_spec_amount_any ("refund_amount", - &osr.details.paid.refund_amount), - GNUNET_JSON_spec_json ("contract_terms", - (json_t **) &osr.details.paid.contract_terms), - GNUNET_JSON_spec_json ("wire_details", - &wire_details), - GNUNET_JSON_spec_json ("wire_reports", - &wire_reports), - GNUNET_JSON_spec_json ("refund_details", - &refund_details), + &osr->details.ok.details.paid.refund_amount), + GNUNET_JSON_spec_object_const ( + "contract_terms", + &osr->details.ok.details.paid.contract_terms), + GNUNET_JSON_spec_array_const ("wire_details", + &wire_details), + GNUNET_JSON_spec_array_const ("refund_details", + &refund_details), + /* Only available since **v14** */ + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_timestamp ("last_payment", + &osr->details.ok.details.paid.last_payment), + NULL), GNUNET_JSON_spec_end () }; if (GNUNET_OK != - GNUNET_JSON_parse (hr->reply, + GNUNET_JSON_parse (osr->hr.reply, spec, NULL, NULL)) { GNUNET_break_op (0); - hr->http_status = 0; - hr->ec = TALER_EC_GENERIC_REPLY_MALFORMED; + osr->hr.http_status = 0; + osr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; omgh->cb (omgh->cb_cls, - hr, - NULL); + osr); return; } - if (! (json_is_array (wire_details) && - json_is_array (wire_reports) && - json_is_array (refund_details) && - json_is_object (osr.details.paid.contract_terms)) ) - { - GNUNET_break_op (0); - hr->http_status = 0; - hr->ec = TALER_EC_GENERIC_REPLY_MALFORMED; - omgh->cb (omgh->cb_cls, - hr, - NULL); - GNUNET_JSON_parse_free (spec); - return; - } - osr.details.paid.exchange_ec = (enum TALER_ErrorCode) ec32; - osr.details.paid.exchange_hc = (unsigned int) hc32; + osr->details.ok.status = TALER_MERCHANT_OSC_PAID; + + osr->details.ok.details.paid.exchange_hc = (unsigned int) hc32; { - unsigned int wts_len = json_array_size (wire_details); - unsigned int wrs_len = json_array_size (wire_reports); - unsigned int ref_len = json_array_size (refund_details); - struct TALER_MERCHANT_WireTransfer wts[wts_len]; - struct TALER_MERCHANT_WireReport wrs[wrs_len]; - struct TALER_MERCHANT_RefundOrderDetail ref[ref_len]; - - for (unsigned int i = 0; i<wts_len; i++) + unsigned int wts_len = (unsigned int) json_array_size (wire_details); + unsigned int ref_len = (unsigned int) json_array_size (refund_details); + + if ( (json_array_size (wire_details) != (size_t) wts_len) || + (wts_len > MAX_WIRE_DETAILS) ) { - struct TALER_MERCHANT_WireTransfer *wt = &wts[i]; - const json_t *w = json_array_get (wire_details, - i); - struct GNUNET_JSON_Specification ispec[] = { - GNUNET_JSON_spec_string ("exchange_url", - &wt->exchange_url), - GNUNET_JSON_spec_fixed_auto ("wtid", - &wt->wtid), - GNUNET_JSON_spec_timestamp ("execution_time", - &wt->execution_time), - TALER_JSON_spec_amount_any ("amount", - &wt->total_amount), - GNUNET_JSON_spec_bool ("confirmed", - &wt->confirmed), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (w, - ispec, - NULL, NULL)) - { - GNUNET_break_op (0); - hr->http_status = 0; - hr->ec = TALER_EC_GENERIC_REPLY_MALFORMED; - omgh->cb (omgh->cb_cls, - hr, - NULL); - GNUNET_JSON_parse_free (spec); - return; - } + GNUNET_break (0); + osr->hr.http_status = 0; + osr->hr.ec = TALER_EC_GENERIC_ALLOCATION_FAILURE; + omgh->cb (omgh->cb_cls, + osr); + return; + } + if ( (json_array_size (refund_details) != (size_t) ref_len) || + (ref_len > MAX_REFUND_DETAILS) ) + { + GNUNET_break (0); + osr->hr.http_status = 0; + osr->hr.ec = TALER_EC_GENERIC_ALLOCATION_FAILURE; + omgh->cb (omgh->cb_cls, + osr); + return; } - - for (unsigned int i = 0; i<wrs_len; i++) { - struct TALER_MERCHANT_WireReport *wr = &wrs[i]; - const json_t *w = json_array_get (wire_reports, i); - uint32_t c32; - uint32_t eec32; - uint32_t ehs32; - struct GNUNET_JSON_Specification ispec[] = { - GNUNET_JSON_spec_uint32 ("code", - &c32), - GNUNET_JSON_spec_string ("hint", - &wr->hint), - GNUNET_JSON_spec_uint32 ("exchange_code", - &eec32), - GNUNET_JSON_spec_uint32 ("exchange_http_status", - &ehs32), - GNUNET_JSON_spec_fixed_auto ("coin_pub", - &wr->coin_pub), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (w, - ispec, - NULL, NULL)) + struct TALER_MERCHANT_WireTransfer wts[GNUNET_NZL (wts_len)]; + struct TALER_MERCHANT_RefundOrderDetail ref[GNUNET_NZL (ref_len)]; + + for (unsigned int i = 0; i<wts_len; i++) { - GNUNET_break_op (0); - hr->http_status = 0; - hr->ec = TALER_EC_GENERIC_REPLY_MALFORMED; - omgh->cb (omgh->cb_cls, - hr, - NULL); - GNUNET_JSON_parse_free (spec); - return; + struct TALER_MERCHANT_WireTransfer *wt = &wts[i]; + const json_t *w = json_array_get (wire_details, + i); + struct GNUNET_JSON_Specification ispec[] = { + TALER_JSON_spec_web_url ("exchange_url", + &wt->exchange_url), + GNUNET_JSON_spec_fixed_auto ("wtid", + &wt->wtid), + GNUNET_JSON_spec_timestamp ("execution_time", + &wt->execution_time), + TALER_JSON_spec_amount_any ("amount", + &wt->total_amount), + GNUNET_JSON_spec_bool ("confirmed", + &wt->confirmed), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (w, + ispec, + NULL, NULL)) + { + GNUNET_break_op (0); + osr->hr.http_status = 0; + osr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + omgh->cb (omgh->cb_cls, + osr); + return; + } } - wr->code = (enum TALER_ErrorCode) c32; - wr->hr.ec = (enum TALER_ErrorCode) eec32; - wr->hr.http_status = (unsigned int) ehs32; - } - for (unsigned int i = 0; i<ref_len; i++) - { - struct TALER_MERCHANT_RefundOrderDetail *ro = &ref[i]; - const json_t *w = json_array_get (refund_details, - i); - struct GNUNET_JSON_Specification ispec[] = { - TALER_JSON_spec_amount_any ("amount", - &ro->refund_amount), - GNUNET_JSON_spec_string ("reason", - &ro->reason), - GNUNET_JSON_spec_timestamp ("timestamp", - &ro->refund_time), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (w, - ispec, - NULL, NULL)) + for (unsigned int i = 0; i<ref_len; i++) { - GNUNET_break_op (0); - hr->http_status = 0; - hr->ec = TALER_EC_GENERIC_REPLY_MALFORMED; - omgh->cb (omgh->cb_cls, - hr, - NULL); - GNUNET_JSON_parse_free (spec); - return; + struct TALER_MERCHANT_RefundOrderDetail *ro = &ref[i]; + const json_t *w = json_array_get (refund_details, + i); + struct GNUNET_JSON_Specification ispec[] = { + TALER_JSON_spec_amount_any ("amount", + &ro->refund_amount), + GNUNET_JSON_spec_string ("reason", + &ro->reason), + GNUNET_JSON_spec_timestamp ("timestamp", + &ro->refund_time), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (w, + ispec, + NULL, NULL)) + { + GNUNET_break_op (0); + osr->hr.http_status = 0; + osr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + omgh->cb (omgh->cb_cls, + osr); + return; + } } - } - osr.details.paid.wts = wts; - osr.details.paid.wts_len = wts_len; - osr.details.paid.wrs = wrs; - osr.details.paid.wrs_len = wrs_len; - osr.details.paid.refunds = ref; - osr.details.paid.refunds_len = ref_len; - omgh->cb (omgh->cb_cls, - hr, - &osr); + osr->details.ok.details.paid.wts = wts; + osr->details.ok.details.paid.wts_len = wts_len; + osr->details.ok.details.paid.refunds = ref; + osr->details.ok.details.paid.refunds_len = ref_len; + omgh->cb (omgh->cb_cls, + osr); + } } - GNUNET_JSON_parse_free (spec); } @@ -376,9 +342,9 @@ handle_merchant_order_get_finished (void *cls, struct TALER_MERCHANT_OrderMerchantGetHandle *omgh = cls; const json_t *json = response; const char *order_status; - struct TALER_MERCHANT_HttpResponse hr = { - .http_status = (unsigned int) response_code, - .reply = json + struct TALER_MERCHANT_OrderStatusResponse osr = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json }; omgh->job = NULL; @@ -387,106 +353,106 @@ handle_merchant_order_get_finished (void *cls, case MHD_HTTP_OK: /* see below */ break; + case MHD_HTTP_ACCEPTED: + /* see below */ + omgh->cb (omgh->cb_cls, + &osr); + TALER_MERCHANT_merchant_order_get_cancel (omgh); + return; case MHD_HTTP_UNAUTHORIZED: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); - /* Nothing really to verify, merchant says we need to authenticate. */ - break; + osr.hr.ec = TALER_JSON_get_error_code (json); + osr.hr.hint = TALER_JSON_get_error_hint (json); + omgh->cb (omgh->cb_cls, + &osr); + TALER_MERCHANT_merchant_order_get_cancel (omgh); + return; case MHD_HTTP_NOT_FOUND: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + osr.hr.ec = TALER_JSON_get_error_code (json); + osr.hr.hint = TALER_JSON_get_error_hint (json); omgh->cb (omgh->cb_cls, - &hr, - NULL); + &osr); TALER_MERCHANT_merchant_order_get_cancel (omgh); return; case MHD_HTTP_GATEWAY_TIMEOUT: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + osr.hr.ec = TALER_JSON_get_error_code (json); + osr.hr.hint = TALER_JSON_get_error_hint (json); omgh->cb (omgh->cb_cls, - &hr, - NULL); + &osr); TALER_MERCHANT_merchant_order_get_cancel (omgh); return; default: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + osr.hr.ec = TALER_JSON_get_error_code (json); + osr.hr.hint = TALER_JSON_get_error_hint (json); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Polling payment failed with HTTP status code %u/%d\n", (unsigned int) response_code, - (int) hr.ec); + (int) osr.hr.ec); GNUNET_break_op (0); omgh->cb (omgh->cb_cls, - &hr, - NULL); + &osr); TALER_MERCHANT_merchant_order_get_cancel (omgh); return; } - order_status = json_string_value (json_object_get (json, "order_status")); + order_status = json_string_value (json_object_get (json, + "order_status")); if (NULL == order_status) { GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + osr.hr.http_status = 0; + osr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; omgh->cb (omgh->cb_cls, - &hr, - NULL); + &osr); TALER_MERCHANT_merchant_order_get_cancel (omgh); return; } - if (0 == strcmp ("paid", order_status)) + if (0 == strcmp ("paid", + order_status)) { handle_paid (omgh, - &hr); + &osr); } - else if (0 == strcmp ("claimed", order_status)) + else if (0 == strcmp ("claimed", + order_status)) { handle_claimed (omgh, - &hr); + &osr); } - else if (0 == strcmp ("unpaid", order_status)) + else if (0 == strcmp ("unpaid", + order_status)) { handle_unpaid (omgh, - &hr); + &osr); } else { GNUNET_break_op (0); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + osr.hr.http_status = 0; + osr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; omgh->cb (omgh->cb_cls, - &hr, - NULL); + &osr); } TALER_MERCHANT_merchant_order_get_cancel (omgh); } struct TALER_MERCHANT_OrderMerchantGetHandle * -TALER_MERCHANT_merchant_order_get (struct GNUNET_CURL_Context *ctx, - const char *backend_url, - const char *order_id, - const char *session_id, - bool transfer, - struct GNUNET_TIME_Relative timeout, - TALER_MERCHANT_OrderMerchantGetCallback cb, - void *cb_cls) +TALER_MERCHANT_merchant_order_get ( + struct GNUNET_CURL_Context *ctx, + const char *backend_url, + const char *order_id, + const char *session_id, + struct GNUNET_TIME_Relative timeout, + TALER_MERCHANT_OrderMerchantGetCallback cb, + void *cb_cls) { struct TALER_MERCHANT_OrderMerchantGetHandle *omgh; - unsigned long long tms; - long tlong; - - tms = (unsigned long long) (timeout.rel_value_us - / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us); - /* set curl timeout to *our* long poll timeout plus one minute - (for network latency and processing delays) */ - tlong = (long) (GNUNET_TIME_relative_add (timeout, - GNUNET_TIME_UNIT_MINUTES). - rel_value_us - / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us); + unsigned int tms; + + tms = (unsigned int) (timeout.rel_value_us + / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us); omgh = GNUNET_new (struct TALER_MERCHANT_OrderMerchantGetHandle); omgh->ctx = ctx; omgh->cb = cb; @@ -497,7 +463,7 @@ TALER_MERCHANT_merchant_order_get (struct GNUNET_CURL_Context *ctx, GNUNET_snprintf (timeout_ms, sizeof (timeout_ms), - "%llu", + "%u", tms); GNUNET_asprintf (&path, "private/orders/%s", @@ -505,7 +471,6 @@ TALER_MERCHANT_merchant_order_get (struct GNUNET_CURL_Context *ctx, omgh->url = TALER_url_join (backend_url, path, "session_id", session_id, - "transfer", transfer ? "YES" : "NO", "timeout_ms", (0 != tms) ? timeout_ms : NULL, NULL); GNUNET_free (path); @@ -529,16 +494,12 @@ TALER_MERCHANT_merchant_order_get (struct GNUNET_CURL_Context *ctx, GNUNET_free (omgh); return NULL; } - if (CURLE_OK != - curl_easy_setopt (eh, - CURLOPT_TIMEOUT_MS, - tlong)) + if (0 != tms) { - GNUNET_break (0); - curl_easy_cleanup (eh); - GNUNET_free (omgh->url); - GNUNET_free (omgh); - return NULL; + GNUNET_break (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_TIMEOUT_MS, + (long) (tms + 100L))); } GNUNET_log (GNUNET_ERROR_TYPE_INFO, |