merchant_api_post_order_refund.c (6881B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-2023 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Lesser General Public License as published by the Free Software 7 Foundation; either version 2.1, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 12 13 You should have received a copy of the GNU Lesser General Public License along with 14 TALER; see the file COPYING.LGPL. If not, see 15 <http://www.gnu.org/licenses/> 16 */ 17 /** 18 * @file merchant_api_post_order_refund.c 19 * @brief Implementation of the POST /orders/ID/refund request 20 * @author Christian Grothoff 21 * @author Marcello Stanisci 22 */ 23 #include "platform.h" 24 #include <curl/curl.h> 25 #include <jansson.h> 26 #include <microhttpd.h> /* just for HTTP status codes */ 27 #include <gnunet/gnunet_util_lib.h> 28 #include <gnunet/gnunet_curl_lib.h> 29 #include "taler_merchant_service.h" 30 #include "merchant_api_curl_defaults.h" 31 #include "merchant_api_common.h" 32 #include <taler/taler_json_lib.h> 33 #include <taler/taler_signatures.h> 34 #include <taler/taler_curl_lib.h> 35 36 37 /** 38 * Handle for a POST /orders/ID/refund operation. 39 */ 40 struct TALER_MERCHANT_OrderRefundHandle 41 { 42 /** 43 * Complete URL where the backend offers /refund 44 */ 45 char *url; 46 47 /** 48 * Minor context that holds body and headers. 49 */ 50 struct TALER_CURL_PostContext post_ctx; 51 52 /** 53 * The CURL context to connect to the backend 54 */ 55 struct GNUNET_CURL_Context *ctx; 56 57 /** 58 * The callback to pass the backend response to 59 */ 60 TALER_MERCHANT_RefundCallback cb; 61 62 /** 63 * Clasure to pass to the callback 64 */ 65 void *cb_cls; 66 67 /** 68 * Handle for the request 69 */ 70 struct GNUNET_CURL_Job *job; 71 }; 72 73 74 /** 75 * Callback to process POST /orders/ID/refund response 76 * 77 * @param cls the `struct TALER_MERCHANT_OrderRefundHandle` 78 * @param response_code HTTP response code, 0 on error 79 * @param response response body, NULL if not JSON 80 */ 81 static void 82 handle_refund_finished (void *cls, 83 long response_code, 84 const void *response) 85 { 86 struct TALER_MERCHANT_OrderRefundHandle *orh = cls; 87 const json_t *json = response; 88 struct TALER_MERCHANT_RefundResponse rr = { 89 .hr.http_status = (unsigned int) response_code, 90 .hr.reply = json 91 }; 92 93 orh->job = NULL; 94 switch (response_code) 95 { 96 case 0: 97 rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 98 break; 99 case MHD_HTTP_OK: 100 { 101 struct GNUNET_JSON_Specification spec[] = { 102 GNUNET_JSON_spec_string ( 103 "taler_refund_uri", 104 &rr.details.ok.taler_refund_uri), 105 GNUNET_JSON_spec_fixed_auto ( 106 "h_contract", 107 &rr.details.ok.h_contract), 108 GNUNET_JSON_spec_end () 109 }; 110 111 if (GNUNET_OK != 112 GNUNET_JSON_parse (json, 113 spec, 114 NULL, NULL)) 115 { 116 GNUNET_break_op (0); 117 rr.hr.http_status = 0; 118 rr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 119 break; 120 } 121 break; 122 } 123 case MHD_HTTP_UNAUTHORIZED: 124 rr.hr.ec = TALER_JSON_get_error_code (json); 125 rr.hr.hint = TALER_JSON_get_error_hint (json); 126 /* Nothing really to verify, merchant says we need to authenticate. */ 127 break; 128 case MHD_HTTP_FORBIDDEN: 129 rr.hr.ec = TALER_JSON_get_error_code (json); 130 rr.hr.hint = TALER_JSON_get_error_hint (json); 131 /* Nothing really to verify, merchant says we need to authenticate. */ 132 break; 133 case MHD_HTTP_NOT_FOUND: 134 /* order unknown (or not paid) */ 135 rr.hr.ec = TALER_JSON_get_error_code (json); 136 rr.hr.hint = TALER_JSON_get_error_hint (json); 137 break; 138 case MHD_HTTP_CONFLICT: 139 /* amount not acceptable */ 140 rr.hr.ec = TALER_JSON_get_error_code (json); 141 rr.hr.hint = TALER_JSON_get_error_hint (json); 142 break; 143 case MHD_HTTP_GONE: 144 /* too late, wire deadline is past */ 145 rr.hr.ec = TALER_JSON_get_error_code (json); 146 rr.hr.hint = TALER_JSON_get_error_hint (json); 147 break; 148 default: 149 GNUNET_break_op (0); /* unexpected status code */ 150 TALER_MERCHANT_parse_error_details_ (json, 151 response_code, 152 &rr.hr); 153 break; 154 } 155 orh->cb (orh->cb_cls, 156 &rr); 157 TALER_MERCHANT_post_order_refund_cancel (orh); 158 } 159 160 161 void 162 TALER_MERCHANT_post_order_refund_cancel ( 163 struct TALER_MERCHANT_OrderRefundHandle *orh) 164 { 165 if (NULL != orh->job) 166 { 167 GNUNET_CURL_job_cancel (orh->job); 168 orh->job = NULL; 169 } 170 TALER_curl_easy_post_finished (&orh->post_ctx); 171 GNUNET_free (orh->url); 172 GNUNET_free (orh); 173 } 174 175 176 struct TALER_MERCHANT_OrderRefundHandle * 177 TALER_MERCHANT_post_order_refund (struct GNUNET_CURL_Context *ctx, 178 const char *backend_url, 179 const char *order_id, 180 const struct TALER_Amount *refund, 181 const char *reason, 182 TALER_MERCHANT_RefundCallback cb, 183 void *cb_cls) 184 { 185 struct TALER_MERCHANT_OrderRefundHandle *orh; 186 json_t *req; 187 CURL *eh; 188 189 orh = GNUNET_new (struct TALER_MERCHANT_OrderRefundHandle); 190 orh->ctx = ctx; 191 orh->cb = cb; 192 orh->cb_cls = cb_cls; 193 { 194 char *path; 195 196 GNUNET_asprintf (&path, 197 "private/orders/%s/refund", 198 order_id); 199 orh->url = TALER_url_join (backend_url, 200 path, 201 NULL); 202 GNUNET_free (path); 203 } 204 if (NULL == orh->url) 205 { 206 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 207 "Could not construct request URL.\n"); 208 GNUNET_free (orh); 209 return NULL; 210 } 211 req = GNUNET_JSON_PACK ( 212 TALER_JSON_pack_amount ("refund", 213 refund), 214 GNUNET_JSON_pack_string ("reason", 215 reason)); 216 GNUNET_assert (NULL != req); 217 eh = TALER_MERCHANT_curl_easy_get_ (orh->url); 218 if (GNUNET_OK != 219 TALER_curl_easy_post (&orh->post_ctx, 220 eh, 221 req)) 222 { 223 GNUNET_break (0); 224 curl_easy_cleanup (eh); 225 json_decref (req); 226 GNUNET_free (orh->url); 227 GNUNET_free (orh); 228 return NULL; 229 } 230 json_decref (req); 231 orh->job = GNUNET_CURL_job_add2 (ctx, 232 eh, 233 orh->post_ctx.headers, 234 &handle_refund_finished, 235 orh); 236 if (NULL == orh->job) 237 { 238 GNUNET_free (orh->url); 239 GNUNET_free (orh); 240 return NULL; 241 } 242 return orh; 243 } 244 245 246 /* end of merchant_api_post_order_refund.c */