merchant_api_get-private-transfers.c (9793B)
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_get-private-transfers.c 19 * @brief Implementation of the GET /transfers request of the merchant's HTTP API 20 * @author Marcello Stanisci 21 * @author Christian Grothoff 22 */ 23 #include "taler/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/taler_merchant_service.h" 30 #include "merchant_api_common.h" 31 #include "merchant_api_curl_defaults.h" 32 #include <taler/taler_json_lib.h> 33 #include <taler/taler_signatures.h> 34 35 36 /** 37 * @brief A Handle for tracking wire transfers. 38 */ 39 struct TALER_MERCHANT_GetTransfersHandle 40 { 41 42 /** 43 * The url for this request. 44 */ 45 char *url; 46 47 /** 48 * Handle for the request. 49 */ 50 struct GNUNET_CURL_Job *job; 51 52 /** 53 * Function to call with the result. 54 */ 55 TALER_MERCHANT_GetTransfersCallback cb; 56 57 /** 58 * Closure for @a cb. 59 */ 60 void *cb_cls; 61 62 /** 63 * Reference to the execution context. 64 */ 65 struct GNUNET_CURL_Context *ctx; 66 }; 67 68 69 /** 70 * Function called when we're done processing the 71 * HTTP GET /transfers request. 72 * 73 * @param cls the `struct TALER_MERCHANT_GetTransfersHandle` 74 * @param response_code HTTP response code, 0 on error 75 * @param response response body, NULL if not in JSON 76 */ 77 static void 78 handle_transfers_get_finished (void *cls, 79 long response_code, 80 const void *response) 81 { 82 struct TALER_MERCHANT_GetTransfersHandle *gth = cls; 83 const json_t *json = response; 84 struct TALER_MERCHANT_GetTransfersResponse gtr = { 85 .hr.http_status = (unsigned int) response_code, 86 .hr.reply = json 87 }; 88 89 gth->job = NULL; 90 switch (response_code) 91 { 92 case 0: 93 gtr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 94 break; 95 case MHD_HTTP_OK: 96 { 97 const json_t *transfers; 98 struct GNUNET_JSON_Specification spec[] = { 99 GNUNET_JSON_spec_array_const ("transfers", 100 &transfers), 101 GNUNET_JSON_spec_end () 102 }; 103 104 if (GNUNET_OK != 105 GNUNET_JSON_parse (json, 106 spec, 107 NULL, NULL)) 108 { 109 GNUNET_break_op (0); 110 gtr.hr.http_status = 0; 111 gtr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 112 break; 113 } 114 115 { 116 size_t tds_length; 117 struct TALER_MERCHANT_TransferData *tds; 118 json_t *transfer; 119 size_t i; 120 bool ok; 121 122 tds_length = json_array_size (transfers); 123 tds = GNUNET_new_array (tds_length, 124 struct TALER_MERCHANT_TransferData); 125 ok = true; 126 json_array_foreach (transfers, i, transfer) { 127 struct TALER_MERCHANT_TransferData *td = &tds[i]; 128 struct GNUNET_JSON_Specification ispec[] = { 129 TALER_JSON_spec_amount_any ("credit_amount", 130 &td->credit_amount), 131 GNUNET_JSON_spec_fixed_auto ("wtid", 132 &td->wtid), 133 TALER_JSON_spec_full_payto_uri ("payto_uri", 134 &td->payto_uri), 135 TALER_JSON_spec_web_url ("exchange_url", 136 &td->exchange_url), 137 GNUNET_JSON_spec_uint64 ("transfer_serial_id", 138 &td->credit_serial), 139 GNUNET_JSON_spec_mark_optional ( 140 GNUNET_JSON_spec_timestamp ("execution_time", 141 &td->execution_time), 142 NULL), 143 GNUNET_JSON_spec_bool ("expected", 144 &td->expected), 145 GNUNET_JSON_spec_end () 146 }; 147 148 if (GNUNET_OK != 149 GNUNET_JSON_parse (transfer, 150 ispec, 151 NULL, NULL)) 152 { 153 GNUNET_break_op (0); 154 ok = false; 155 break; 156 } 157 } 158 159 if (! ok) 160 { 161 GNUNET_break_op (0); 162 GNUNET_free (tds); 163 gtr.hr.http_status = 0; 164 gtr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 165 break; 166 } 167 gtr.details.ok.transfers = tds; 168 gtr.details.ok.transfers_length = tds_length; 169 gth->cb (gth->cb_cls, 170 >r); 171 GNUNET_free (tds); 172 TALER_MERCHANT_transfers_get_cancel (gth); 173 return; 174 } 175 } 176 case MHD_HTTP_UNAUTHORIZED: 177 gtr.hr.ec = TALER_JSON_get_error_code (json); 178 gtr.hr.hint = TALER_JSON_get_error_hint (json); 179 /* Nothing really to verify, merchant says we need to authenticate. */ 180 break; 181 case MHD_HTTP_NOT_FOUND: 182 /* Nothing really to verify, this should never 183 happen, we should pass the JSON reply to the application */ 184 gtr.hr.ec = TALER_JSON_get_error_code (json); 185 gtr.hr.hint = TALER_JSON_get_error_hint (json); 186 break; 187 case MHD_HTTP_INTERNAL_SERVER_ERROR: 188 /* Server had an internal issue; we should retry, but this API 189 leaves this to the application */ 190 gtr.hr.ec = TALER_JSON_get_error_code (json); 191 gtr.hr.hint = TALER_JSON_get_error_hint (json); 192 break; 193 default: 194 /* unexpected response code */ 195 GNUNET_break_op (0); 196 TALER_MERCHANT_parse_error_details_ (json, 197 response_code, 198 >r.hr); 199 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 200 "Unexpected response code %u/%d\n", 201 (unsigned int) response_code, 202 (int) gtr.hr.ec); 203 gtr.hr.http_status = 0; 204 break; 205 } 206 gth->cb (gth->cb_cls, 207 >r); 208 TALER_MERCHANT_transfers_get_cancel (gth); 209 } 210 211 212 struct TALER_MERCHANT_GetTransfersHandle * 213 TALER_MERCHANT_transfers_get ( 214 struct GNUNET_CURL_Context *ctx, 215 const char *backend_url, 216 struct TALER_FullPayto payto_uri, 217 const struct GNUNET_TIME_Timestamp before, 218 const struct GNUNET_TIME_Timestamp after, 219 int64_t limit, 220 uint64_t offset, 221 enum TALER_EXCHANGE_YesNoAll expected, 222 TALER_MERCHANT_GetTransfersCallback cb, 223 void *cb_cls) 224 { 225 struct TALER_MERCHANT_GetTransfersHandle *gth; 226 CURL *eh; 227 const char *expected_s = NULL; 228 char limit_s[30]; 229 char offset_s[30]; 230 char before_s[30]; 231 char after_s[30]; 232 233 gth = GNUNET_new (struct TALER_MERCHANT_GetTransfersHandle); 234 gth->ctx = ctx; 235 gth->cb = cb; 236 gth->cb_cls = cb_cls; 237 expected_s = TALER_yna_to_string (expected); 238 GNUNET_snprintf (limit_s, 239 sizeof (limit_s), 240 "%lld", 241 (long long) limit); 242 GNUNET_snprintf (offset_s, 243 sizeof (offset_s), 244 "%lld", 245 (unsigned long long) offset); 246 GNUNET_snprintf (before_s, 247 sizeof (before_s), 248 "%llu", 249 (unsigned long long) GNUNET_TIME_timestamp_to_s (before)); 250 GNUNET_snprintf (after_s, 251 sizeof (after_s), 252 "%llu", 253 (unsigned long long) GNUNET_TIME_timestamp_to_s (after)); 254 { 255 char *enc_payto = TALER_urlencode (payto_uri.full_payto); 256 257 gth->url = TALER_url_join (backend_url, 258 "private/transfers", 259 "payto_uri", 260 enc_payto, 261 "expected", 262 (TALER_EXCHANGE_YNA_ALL != expected) 263 ? expected_s 264 : NULL, 265 "limit", 266 0 != limit 267 ? limit_s 268 : NULL, 269 "offset", 270 ((0 != offset) && (UINT64_MAX != offset)) 271 ? offset_s 272 : NULL, 273 "before", 274 GNUNET_TIME_absolute_is_never (before.abs_time) 275 ? NULL 276 : before_s, 277 "after", 278 GNUNET_TIME_absolute_is_zero (after.abs_time) 279 ? NULL 280 : after_s, 281 NULL); 282 GNUNET_free (enc_payto); 283 } 284 if (NULL == gth->url) 285 { 286 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 287 "Could not construct request URL.\n"); 288 GNUNET_free (gth); 289 return NULL; 290 } 291 eh = TALER_MERCHANT_curl_easy_get_ (gth->url); 292 gth->job = GNUNET_CURL_job_add (ctx, 293 eh, 294 &handle_transfers_get_finished, 295 gth); 296 return gth; 297 } 298 299 300 void 301 TALER_MERCHANT_transfers_get_cancel ( 302 struct TALER_MERCHANT_GetTransfersHandle *gth) 303 { 304 if (NULL != gth->job) 305 { 306 GNUNET_CURL_job_cancel (gth->job); 307 gth->job = NULL; 308 } 309 GNUNET_free (gth->url); 310 GNUNET_free (gth); 311 } 312 313 314 /* end of merchant_api_get_transfers.c */