merchant_api_post_instances.c (8314B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2020-2023 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify 6 it under the terms of the GNU Lesser General Public License as 7 published by the Free Software Foundation; either version 2.1, 8 or (at your option) any later version. 9 10 TALER is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General 16 Public License along with TALER; see the file COPYING.LGPL. 17 If not, see <http://www.gnu.org/licenses/> 18 */ 19 /** 20 * @file merchant_api_post_instances.c 21 * @brief Implementation of the POST /instances request 22 * of the merchant's HTTP API 23 * @author Christian Grothoff 24 */ 25 #include "platform.h" 26 #include <curl/curl.h> 27 #include <jansson.h> 28 #include <microhttpd.h> /* just for HTTP status codes */ 29 #include <gnunet/gnunet_util_lib.h> 30 #include "taler_merchant_service.h" 31 #include "merchant_api_curl_defaults.h" 32 #include "merchant_api_common.h" 33 #include <taler/taler_json_lib.h> 34 #include <taler/taler_curl_lib.h> 35 #include <taler/taler_kyclogic_lib.h> 36 37 38 /** 39 * Handle for a POST /instances/$ID operation. 40 */ 41 struct TALER_MERCHANT_InstancesPostHandle 42 { 43 44 /** 45 * The url for this request. 46 */ 47 char *url; 48 49 /** 50 * Handle for the request. 51 */ 52 struct GNUNET_CURL_Job *job; 53 54 /** 55 * Function to call with the result. 56 */ 57 TALER_MERCHANT_InstancesPostCallback cb; 58 59 /** 60 * Closure for @a cb. 61 */ 62 void *cb_cls; 63 64 /** 65 * Reference to the execution context. 66 */ 67 struct GNUNET_CURL_Context *ctx; 68 69 /** 70 * Minor context that holds body and headers. 71 */ 72 struct TALER_CURL_PostContext post_ctx; 73 74 }; 75 76 77 /** 78 * Function called when we're done processing the 79 * HTTP POST /instances request. 80 * 81 * @param cls the `struct TALER_MERCHANT_InstancesPostHandle` 82 * @param response_code HTTP response code, 0 on error 83 * @param response response body, NULL if not in JSON 84 */ 85 static void 86 handle_post_instances_finished (void *cls, 87 long response_code, 88 const void *response) 89 { 90 struct TALER_MERCHANT_InstancesPostHandle *iph = cls; 91 const json_t *json = response; 92 struct TALER_MERCHANT_HttpResponse hr = { 93 .http_status = (unsigned int) response_code, 94 .reply = json 95 }; 96 97 iph->job = NULL; 98 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 99 "POST /management/instances completed with response code %u\n", 100 (unsigned int) response_code); 101 switch (response_code) 102 { 103 case 0: 104 hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 105 break; 106 case MHD_HTTP_NO_CONTENT: 107 break; 108 case MHD_HTTP_BAD_REQUEST: 109 hr.ec = TALER_JSON_get_error_code (json); 110 hr.hint = TALER_JSON_get_error_hint (json); 111 /* This should never happen, either us 112 * or the merchant is buggy (or API version conflict); 113 * just pass JSON reply to the application */ 114 break; 115 case MHD_HTTP_UNAUTHORIZED: 116 hr.ec = TALER_JSON_get_error_code (json); 117 hr.hint = TALER_JSON_get_error_hint (json); 118 /* Nothing really to verify, merchant says we need to authenticate. */ 119 break; 120 case MHD_HTTP_FORBIDDEN: 121 hr.ec = TALER_JSON_get_error_code (json); 122 hr.hint = TALER_JSON_get_error_hint (json); 123 /* Nothing really to verify, merchant says we tried to abort the payment 124 * after it was successful. We should pass the JSON reply to the 125 * application */ 126 break; 127 case MHD_HTTP_NOT_FOUND: 128 hr.ec = TALER_JSON_get_error_code (json); 129 hr.hint = TALER_JSON_get_error_hint (json); 130 /* Nothing really to verify, this should never 131 happen, we should pass the JSON reply to the 132 application */ 133 break; 134 case MHD_HTTP_CONFLICT: 135 hr.ec = TALER_JSON_get_error_code (json); 136 hr.hint = TALER_JSON_get_error_hint (json); 137 break; 138 case MHD_HTTP_INTERNAL_SERVER_ERROR: 139 hr.ec = TALER_JSON_get_error_code (json); 140 hr.hint = TALER_JSON_get_error_hint (json); 141 /* Server had an internal issue; we should retry, 142 but this API leaves this to the application */ 143 break; 144 default: 145 TALER_MERCHANT_parse_error_details_ (json, 146 response_code, 147 &hr); 148 /* unexpected response code */ 149 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 150 "Unexpected response code %u/%d\n", 151 (unsigned int) response_code, 152 (int) hr.ec); 153 GNUNET_break_op (0); 154 break; 155 } 156 iph->cb (iph->cb_cls, 157 &hr); 158 TALER_MERCHANT_instances_post_cancel (iph); 159 } 160 161 162 struct TALER_MERCHANT_InstancesPostHandle * 163 TALER_MERCHANT_instances_post ( 164 struct GNUNET_CURL_Context *ctx, 165 const char *backend_url, 166 const char *instance_id, 167 const char *name, 168 const json_t *address, 169 const json_t *jurisdiction, 170 bool use_stefan, 171 struct GNUNET_TIME_Relative default_wire_transfer_delay, 172 struct GNUNET_TIME_Relative default_pay_delay, 173 struct GNUNET_TIME_Relative default_refund_delay, 174 const char *auth_password, 175 TALER_MERCHANT_InstancesPostCallback cb, 176 void *cb_cls) 177 { 178 struct TALER_MERCHANT_InstancesPostHandle *iph; 179 json_t *req_obj; 180 json_t *auth_obj; 181 182 if (NULL != auth_password) 183 { 184 auth_obj = GNUNET_JSON_PACK ( 185 GNUNET_JSON_pack_string ("method", 186 "token"), 187 GNUNET_JSON_pack_string ("password", 188 auth_password)); 189 } 190 else 191 { 192 auth_obj = GNUNET_JSON_PACK ( 193 GNUNET_JSON_pack_string ("method", 194 "external")); 195 } 196 if (NULL == auth_obj) 197 { 198 GNUNET_break (0); 199 return NULL; 200 } 201 req_obj = GNUNET_JSON_PACK ( 202 GNUNET_JSON_pack_string ("id", 203 instance_id), 204 GNUNET_JSON_pack_string ("name", 205 name), 206 GNUNET_JSON_pack_object_incref ("address", 207 (json_t *) address), 208 GNUNET_JSON_pack_object_incref ("jurisdiction", 209 (json_t *) jurisdiction), 210 GNUNET_JSON_pack_bool ("use_stefan", 211 use_stefan), 212 GNUNET_JSON_pack_time_rel ("default_wire_transfer_delay", 213 default_wire_transfer_delay), 214 GNUNET_JSON_pack_time_rel ("default_pay_delay", 215 default_pay_delay), 216 GNUNET_JSON_pack_time_rel ("default_refund_delay", 217 default_refund_delay), 218 /* FIXME: add eventually to arguments when we transform the API... */ 219 GNUNET_JSON_pack_time_rounder_interval ( 220 "default_wire_transfer_rounding_interval", 221 GNUNET_TIME_RI_NONE), 222 GNUNET_JSON_pack_object_steal ("auth", 223 auth_obj)); 224 iph = GNUNET_new (struct TALER_MERCHANT_InstancesPostHandle); 225 iph->ctx = ctx; 226 iph->cb = cb; 227 iph->cb_cls = cb_cls; 228 iph->url = TALER_url_join (backend_url, 229 "management/instances", 230 NULL); 231 if (NULL == iph->url) 232 { 233 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 234 "Could not construct request URL.\n"); 235 json_decref (req_obj); 236 GNUNET_free (iph); 237 return NULL; 238 } 239 { 240 CURL *eh; 241 242 eh = TALER_MERCHANT_curl_easy_get_ (iph->url); 243 if (GNUNET_OK != 244 TALER_curl_easy_post (&iph->post_ctx, 245 eh, 246 req_obj)) 247 { 248 GNUNET_break (0); 249 curl_easy_cleanup (eh); 250 json_decref (req_obj); 251 GNUNET_free (iph); 252 return NULL; 253 } 254 json_decref (req_obj); 255 iph->job = GNUNET_CURL_job_add2 (ctx, 256 eh, 257 iph->post_ctx.headers, 258 &handle_post_instances_finished, 259 iph); 260 } 261 return iph; 262 } 263 264 265 void 266 TALER_MERCHANT_instances_post_cancel ( 267 struct TALER_MERCHANT_InstancesPostHandle *iph) 268 { 269 if (NULL != iph->job) 270 { 271 GNUNET_CURL_job_cancel (iph->job); 272 iph->job = NULL; 273 } 274 TALER_curl_easy_post_finished (&iph->post_ctx); 275 GNUNET_free (iph->url); 276 GNUNET_free (iph); 277 } 278 279 280 /* end of merchant_api_post_instances.c */