merchant_api_post_tokenfamilies.c (8060B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2020-2024 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_tokenfamilies.c 21 * @brief Implementation of the POST /tokenfamilies request 22 * of the merchant's HTTP API 23 * @author Christian Blättler 24 */ 25 #include "platform.h" 26 #include <curl/curl.h> 27 #include <gnunet/gnunet_json_lib.h> 28 #include <gnunet/gnunet_time_lib.h> 29 #include <jansson.h> 30 #include <microhttpd.h> /* just for HTTP status codes */ 31 #include <gnunet/gnunet_util_lib.h> 32 #include "taler_merchant_service.h" 33 #include "merchant_api_curl_defaults.h" 34 #include "merchant_api_common.h" 35 #include <taler/taler_json_lib.h> 36 #include <taler/taler_curl_lib.h> 37 38 39 /** 40 * Handle for a POST /tokenfamilies operation. 41 */ 42 struct TALER_MERCHANT_TokenFamiliesPostHandle 43 { 44 45 /** 46 * The url for this request. 47 */ 48 char *url; 49 50 /** 51 * Handle for the request. 52 */ 53 struct GNUNET_CURL_Job *job; 54 55 /** 56 * Function to call with the result. 57 */ 58 TALER_MERCHANT_TokenFamiliesPostCallback cb; 59 60 /** 61 * Closure for @a cb. 62 */ 63 void *cb_cls; 64 65 /** 66 * Reference to the execution context. 67 */ 68 struct GNUNET_CURL_Context *ctx; 69 70 /** 71 * Minor context that holds body and headers. 72 */ 73 struct TALER_CURL_PostContext post_ctx; 74 75 }; 76 77 /** 78 * Function called when we're done processing the 79 * HTTP POST /tokenfamilies request. 80 * 81 * @param cls the `struct TALER_MERCHANT_TokenFamiliesPostHandle` 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_token_families_finished (void *cls, 87 long response_code, 88 const void *response) 89 { 90 struct TALER_MERCHANT_TokenFamiliesPostHandle *handle = 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 handle->job = NULL; 98 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 99 "POST /tokenfamilies 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 handle->cb (handle->cb_cls, 157 &hr); 158 TALER_MERCHANT_token_families_post_cancel (handle); 159 } 160 161 162 struct TALER_MERCHANT_TokenFamiliesPostHandle * 163 TALER_MERCHANT_token_families_post ( 164 struct GNUNET_CURL_Context *ctx, 165 const char *backend_url, 166 const char *slug, 167 const char *name, 168 const char *description, 169 const json_t *description_i18n, 170 const json_t *extra_data, 171 struct GNUNET_TIME_Timestamp valid_after, 172 struct GNUNET_TIME_Timestamp valid_before, 173 struct GNUNET_TIME_Relative duration, 174 struct GNUNET_TIME_Relative validity_granularity, 175 struct GNUNET_TIME_Relative start_offset, 176 const char *kind, 177 TALER_MERCHANT_TokenFamiliesPostCallback cb, 178 void *cb_cls) 179 { 180 struct TALER_MERCHANT_TokenFamiliesPostHandle *handle; 181 json_t *req_obj; 182 183 req_obj = GNUNET_JSON_PACK ( 184 GNUNET_JSON_pack_string ("slug", 185 slug), 186 GNUNET_JSON_pack_string ("name", 187 name), 188 GNUNET_JSON_pack_string ("description", 189 description), 190 GNUNET_JSON_pack_allow_null ( 191 GNUNET_JSON_pack_object_incref ("description_i18n", 192 (json_t *) description_i18n)), 193 GNUNET_JSON_pack_allow_null ( 194 GNUNET_JSON_pack_object_incref ("extra_data", 195 (json_t *) extra_data)), 196 GNUNET_JSON_pack_allow_null ( 197 GNUNET_JSON_pack_timestamp ("valid_after", 198 valid_after)), 199 GNUNET_JSON_pack_timestamp ("valid_before", 200 valid_before), 201 GNUNET_JSON_pack_time_rel ("duration", 202 duration), 203 GNUNET_JSON_pack_time_rel ("validity_granularity", 204 validity_granularity), 205 GNUNET_JSON_pack_time_rel ("start_offset", 206 start_offset), 207 GNUNET_JSON_pack_string ("kind", 208 kind)); 209 handle = GNUNET_new (struct TALER_MERCHANT_TokenFamiliesPostHandle); 210 handle->ctx = ctx; 211 handle->cb = cb; 212 handle->cb_cls = cb_cls; 213 handle->url = TALER_url_join (backend_url, 214 "private/tokenfamilies", 215 NULL); 216 if (NULL == handle->url) 217 { 218 219 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 220 "Could not construct request URL.\n"); 221 json_decref (req_obj); 222 GNUNET_free (handle); 223 return NULL; 224 } 225 { 226 CURL *eh; 227 228 eh = TALER_MERCHANT_curl_easy_get_ (handle->url); 229 GNUNET_assert (GNUNET_OK == 230 TALER_curl_easy_post (&handle->post_ctx, 231 eh, 232 req_obj)); 233 json_decref (req_obj); 234 handle->job = GNUNET_CURL_job_add2 (ctx, 235 eh, 236 handle->post_ctx.headers, 237 &handle_post_token_families_finished, 238 handle); 239 GNUNET_assert (NULL != handle->job); 240 } 241 return handle; 242 } 243 244 245 void 246 TALER_MERCHANT_token_families_post_cancel ( 247 struct TALER_MERCHANT_TokenFamiliesPostHandle *pph) 248 { 249 if (NULL != pph->job) 250 { 251 GNUNET_CURL_job_cancel (pph->job); 252 pph->job = NULL; 253 } 254 TALER_curl_easy_post_finished (&pph->post_ctx); 255 GNUNET_free (pph->url); 256 GNUNET_free (pph); 257 }