exchange_api_reserves_get_attestable.c (7610B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-2022 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, 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 General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see 15 <http://www.gnu.org/licenses/> 16 */ 17 /** 18 * @file lib/exchange_api_reserves_get_attestable.c 19 * @brief Implementation of the GET_ATTESTABLE /reserves/$RESERVE_PUB requests 20 * @author Christian Grothoff 21 */ 22 #include "taler/platform.h" 23 #include <jansson.h> 24 #include <microhttpd.h> /* just for HTTP status codes */ 25 #include <gnunet/gnunet_util_lib.h> 26 #include <gnunet/gnunet_json_lib.h> 27 #include <gnunet/gnunet_curl_lib.h> 28 #include "taler/taler_exchange_service.h" 29 #include "taler/taler_json_lib.h" 30 #include "exchange_api_handle.h" 31 #include "taler/taler_signatures.h" 32 #include "exchange_api_curl_defaults.h" 33 34 35 /** 36 * @brief A /reserves/ GET_ATTESTABLE Handle 37 */ 38 struct TALER_EXCHANGE_ReservesGetAttestHandle 39 { 40 41 /** 42 * The url for this request. 43 */ 44 char *url; 45 46 /** 47 * Handle for the request. 48 */ 49 struct GNUNET_CURL_Job *job; 50 51 /** 52 * Function to call with the result. 53 */ 54 TALER_EXCHANGE_ReservesGetAttestCallback cb; 55 56 /** 57 * Public key of the reserve we are querying. 58 */ 59 struct TALER_ReservePublicKeyP reserve_pub; 60 61 /** 62 * Closure for @a cb. 63 */ 64 void *cb_cls; 65 66 }; 67 68 69 /** 70 * We received an #MHD_HTTP_OK status code. Handle the JSON 71 * response. 72 * 73 * @param rgah handle of the request 74 * @param j JSON response 75 * @return #GNUNET_OK on success 76 */ 77 static enum GNUNET_GenericReturnValue 78 handle_reserves_get_attestable_ok ( 79 struct TALER_EXCHANGE_ReservesGetAttestHandle *rgah, 80 const json_t *j) 81 { 82 struct TALER_EXCHANGE_ReserveGetAttestResult rs = { 83 .hr.reply = j, 84 .hr.http_status = MHD_HTTP_OK 85 }; 86 const json_t *details; 87 struct GNUNET_JSON_Specification spec[] = { 88 GNUNET_JSON_spec_array_const ("details", 89 &details), 90 GNUNET_JSON_spec_end () 91 }; 92 93 if (GNUNET_OK != 94 GNUNET_JSON_parse (j, 95 spec, 96 NULL, 97 NULL)) 98 { 99 GNUNET_break_op (0); 100 return GNUNET_SYSERR; 101 } 102 { 103 unsigned int dlen = json_array_size (details); 104 const char *attributes[GNUNET_NZL (dlen)]; 105 106 for (unsigned int i = 0; i<dlen; i++) 107 { 108 json_t *detail = json_array_get (details, 109 i); 110 attributes[i] = json_string_value (detail); 111 if (NULL == attributes[i]) 112 { 113 GNUNET_break_op (0); 114 return GNUNET_SYSERR; 115 } 116 } 117 rs.details.ok.attributes_length = dlen; 118 rs.details.ok.attributes = attributes; 119 rgah->cb (rgah->cb_cls, 120 &rs); 121 rgah->cb = NULL; 122 } 123 return GNUNET_OK; 124 } 125 126 127 /** 128 * Function called when we're done processing the 129 * HTTP GET /reserves-attest/$RID request. 130 * 131 * @param cls the `struct TALER_EXCHANGE_ReservesGetAttestableHandle` 132 * @param response_code HTTP response code, 0 on error 133 * @param response parsed JSON result, NULL on error 134 */ 135 static void 136 handle_reserves_get_attestable_finished (void *cls, 137 long response_code, 138 const void *response) 139 { 140 struct TALER_EXCHANGE_ReservesGetAttestHandle *rgah = cls; 141 const json_t *j = response; 142 struct TALER_EXCHANGE_ReserveGetAttestResult rs = { 143 .hr.reply = j, 144 .hr.http_status = (unsigned int) response_code 145 }; 146 147 rgah->job = NULL; 148 switch (response_code) 149 { 150 case 0: 151 rs.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 152 break; 153 case MHD_HTTP_OK: 154 if (GNUNET_OK != 155 handle_reserves_get_attestable_ok (rgah, 156 j)) 157 { 158 rs.hr.http_status = 0; 159 rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; 160 } 161 break; 162 case MHD_HTTP_BAD_REQUEST: 163 /* This should never happen, either us or the exchange is buggy 164 (or API version conflict); just pass JSON reply to the application */ 165 rs.hr.ec = TALER_JSON_get_error_code (j); 166 rs.hr.hint = TALER_JSON_get_error_hint (j); 167 break; 168 case MHD_HTTP_NOT_FOUND: 169 /* Nothing really to verify, this should never 170 happen, we should pass the JSON reply to the application */ 171 rs.hr.ec = TALER_JSON_get_error_code (j); 172 rs.hr.hint = TALER_JSON_get_error_hint (j); 173 break; 174 case MHD_HTTP_CONFLICT: 175 /* Nothing really to verify, this should never 176 happen, we should pass the JSON reply to the application */ 177 rs.hr.ec = TALER_JSON_get_error_code (j); 178 rs.hr.hint = TALER_JSON_get_error_hint (j); 179 break; 180 case MHD_HTTP_INTERNAL_SERVER_ERROR: 181 /* Server had an internal issue; we should retry, but this API 182 leaves this to the application */ 183 rs.hr.ec = TALER_JSON_get_error_code (j); 184 rs.hr.hint = TALER_JSON_get_error_hint (j); 185 break; 186 default: 187 /* unexpected response code */ 188 GNUNET_break_op (0); 189 rs.hr.ec = TALER_JSON_get_error_code (j); 190 rs.hr.hint = TALER_JSON_get_error_hint (j); 191 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 192 "Unexpected response code %u/%d for reserves get_attestable\n", 193 (unsigned int) response_code, 194 (int) rs.hr.ec); 195 break; 196 } 197 if (NULL != rgah->cb) 198 { 199 rgah->cb (rgah->cb_cls, 200 &rs); 201 rgah->cb = NULL; 202 } 203 TALER_EXCHANGE_reserves_get_attestable_cancel (rgah); 204 } 205 206 207 struct TALER_EXCHANGE_ReservesGetAttestHandle * 208 TALER_EXCHANGE_reserves_get_attestable ( 209 struct GNUNET_CURL_Context *ctx, 210 const char *url, 211 const struct TALER_ReservePublicKeyP *reserve_pub, 212 TALER_EXCHANGE_ReservesGetAttestCallback cb, 213 void *cb_cls) 214 { 215 struct TALER_EXCHANGE_ReservesGetAttestHandle *rgah; 216 CURL *eh; 217 char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32]; 218 219 { 220 char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2]; 221 char *end; 222 223 end = GNUNET_STRINGS_data_to_string ( 224 reserve_pub, 225 sizeof (*reserve_pub), 226 pub_str, 227 sizeof (pub_str)); 228 *end = '\0'; 229 GNUNET_snprintf (arg_str, 230 sizeof (arg_str), 231 "reserves-attest/%s", 232 pub_str); 233 } 234 rgah = GNUNET_new (struct TALER_EXCHANGE_ReservesGetAttestHandle); 235 rgah->cb = cb; 236 rgah->cb_cls = cb_cls; 237 rgah->reserve_pub = *reserve_pub; 238 rgah->url = TALER_url_join (url, 239 arg_str, 240 NULL); 241 if (NULL == rgah->url) 242 { 243 GNUNET_free (rgah); 244 return NULL; 245 } 246 eh = TALER_EXCHANGE_curl_easy_get_ (rgah->url); 247 if (NULL == eh) 248 { 249 GNUNET_break (0); 250 GNUNET_free (rgah->url); 251 GNUNET_free (rgah); 252 return NULL; 253 } 254 rgah->job = GNUNET_CURL_job_add (ctx, 255 eh, 256 &handle_reserves_get_attestable_finished, 257 rgah); 258 return rgah; 259 } 260 261 262 void 263 TALER_EXCHANGE_reserves_get_attestable_cancel ( 264 struct TALER_EXCHANGE_ReservesGetAttestHandle *rgah) 265 { 266 if (NULL != rgah->job) 267 { 268 GNUNET_CURL_job_cancel (rgah->job); 269 rgah->job = NULL; 270 } 271 GNUNET_free (rgah->url); 272 GNUNET_free (rgah); 273 } 274 275 276 /* end of exchange_api_reserves_get_attestable.c */