merchant_api_patch_instance.c (7972B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2020 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_patch_instance.c 21 * @brief Implementation of the PATCH /instances/$ID 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_kyclogic_lib.h> 35 #include <taler/taler_curl_lib.h> 36 37 38 /** 39 * Handle for a PATCH /instances/$ID operation. 40 */ 41 struct TALER_MERCHANT_InstancePatchHandle 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_InstancePatchCallback 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 PATCH /instances/$ID request. 80 * 81 * @param cls the `struct TALER_MERCHANT_InstancePatchHandle` 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_patch_instance_finished (void *cls, 87 long response_code, 88 const void *response) 89 { 90 struct TALER_MERCHANT_InstancePatchHandle *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 "PATCH /instances/$ID 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 break; 112 case MHD_HTTP_UNAUTHORIZED: 113 hr.ec = TALER_JSON_get_error_code (json); 114 hr.hint = TALER_JSON_get_error_hint (json); 115 /* Nothing really to verify, merchant says we need to authenticate. */ 116 break; 117 case MHD_HTTP_FORBIDDEN: 118 hr.ec = TALER_JSON_get_error_code (json); 119 hr.hint = TALER_JSON_get_error_hint (json); 120 /* Nothing really to verify, merchant says we tried to abort the payment 121 * after it was successful. We should pass the JSON reply to the 122 * application */ 123 break; 124 case MHD_HTTP_NOT_FOUND: 125 hr.ec = TALER_JSON_get_error_code (json); 126 hr.hint = TALER_JSON_get_error_hint (json); 127 break; 128 case MHD_HTTP_CONFLICT: 129 hr.ec = TALER_JSON_get_error_code (json); 130 hr.hint = TALER_JSON_get_error_hint (json); 131 break; 132 case MHD_HTTP_INTERNAL_SERVER_ERROR: 133 hr.ec = TALER_JSON_get_error_code (json); 134 hr.hint = TALER_JSON_get_error_hint (json); 135 /* Server had an internal issue; we should retry, 136 but this API leaves this to the application */ 137 break; 138 default: 139 TALER_MERCHANT_parse_error_details_ (json, 140 response_code, 141 &hr); 142 /* unexpected response code */ 143 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 144 "Unexpected response code %u/%d\n", 145 (unsigned int) response_code, 146 (int) hr.ec); 147 GNUNET_break_op (0); 148 break; 149 } 150 iph->cb (iph->cb_cls, 151 &hr); 152 TALER_MERCHANT_instance_patch_cancel (iph); 153 } 154 155 156 struct TALER_MERCHANT_InstancePatchHandle * 157 TALER_MERCHANT_instance_patch ( 158 struct GNUNET_CURL_Context *ctx, 159 const char *backend_url, 160 const char *instance_id, 161 const char *name, 162 const json_t *address, 163 const json_t *jurisdiction, 164 bool use_stefan, 165 struct GNUNET_TIME_Relative default_wire_transfer_delay, 166 struct GNUNET_TIME_Relative default_pay_delay, 167 struct GNUNET_TIME_Relative default_refund_delay, 168 TALER_MERCHANT_InstancePatchCallback cb, 169 void *cb_cls) 170 { 171 struct TALER_MERCHANT_InstancePatchHandle *iph; 172 json_t *req_obj; 173 174 req_obj = GNUNET_JSON_PACK ( 175 GNUNET_JSON_pack_string ("name", 176 name), 177 GNUNET_JSON_pack_object_incref ("address", 178 (json_t *) address), 179 GNUNET_JSON_pack_object_incref ("jurisdiction", 180 (json_t *) jurisdiction), 181 GNUNET_JSON_pack_bool ("use_stefan", 182 use_stefan), 183 GNUNET_JSON_pack_time_rel ("default_wire_transfer_delay", 184 default_wire_transfer_delay), 185 GNUNET_JSON_pack_time_rel ("default_pay_delay", 186 default_pay_delay), 187 GNUNET_JSON_pack_time_rel ("default_refund_delay", 188 default_refund_delay), 189 /* FIXME: add eventually to arguments when we transform the API... */ 190 GNUNET_JSON_pack_time_rounder_interval ( 191 "default_wire_transfer_rounding_interval", 192 GNUNET_TIME_RI_NONE) 193 ); 194 iph = GNUNET_new (struct TALER_MERCHANT_InstancePatchHandle); 195 iph->ctx = ctx; 196 iph->cb = cb; 197 iph->cb_cls = cb_cls; 198 if (NULL != instance_id) 199 { 200 char *path; 201 202 GNUNET_asprintf (&path, 203 "management/instances/%s", 204 instance_id); 205 iph->url = TALER_url_join (backend_url, 206 path, 207 NULL); 208 GNUNET_free (path); 209 } 210 else 211 { 212 /* backend_url is already identifying the instance */ 213 iph->url = TALER_url_join (backend_url, 214 "private", 215 NULL); 216 } 217 if (NULL == iph->url) 218 { 219 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 220 "Could not construct request URL.\n"); 221 json_decref (req_obj); 222 GNUNET_free (iph); 223 return NULL; 224 } 225 { 226 CURL *eh; 227 228 eh = TALER_MERCHANT_curl_easy_get_ (iph->url); 229 if (GNUNET_OK != 230 TALER_curl_easy_post (&iph->post_ctx, 231 eh, 232 req_obj)) 233 { 234 GNUNET_break (0); 235 curl_easy_cleanup (eh); 236 json_decref (req_obj); 237 GNUNET_free (iph->url); 238 GNUNET_free (iph); 239 return NULL; 240 } 241 json_decref (req_obj); 242 GNUNET_assert (CURLE_OK == 243 curl_easy_setopt (eh, 244 CURLOPT_CUSTOMREQUEST, 245 MHD_HTTP_METHOD_PATCH)); 246 iph->job = GNUNET_CURL_job_add2 (ctx, 247 eh, 248 iph->post_ctx.headers, 249 &handle_patch_instance_finished, 250 iph); 251 } 252 return iph; 253 } 254 255 256 void 257 TALER_MERCHANT_instance_patch_cancel ( 258 struct TALER_MERCHANT_InstancePatchHandle *iph) 259 { 260 if (NULL != iph->job) 261 { 262 GNUNET_CURL_job_cancel (iph->job); 263 iph->job = NULL; 264 } 265 TALER_curl_easy_post_finished (&iph->post_ctx); 266 GNUNET_free (iph->url); 267 GNUNET_free (iph); 268 } 269 270 271 /* end of merchant_api_patch_instance.c */