merchant_api_get-management-instances.c (8380B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-2026 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-management-instances-new.c 19 * @brief Implementation of the GET /management/instances request 20 * @author Christian Grothoff 21 */ 22 #include "taler/platform.h" 23 #include <curl/curl.h> 24 #include <jansson.h> 25 #include <microhttpd.h> /* just for HTTP status codes */ 26 #include <gnunet/gnunet_util_lib.h> 27 #include <gnunet/gnunet_curl_lib.h> 28 #include <taler/taler-merchant/get-management-instances.h> 29 #include "merchant_api_curl_defaults.h" 30 #include <taler/taler_json_lib.h> 31 32 /** 33 * Maximum number of instances permitted. 34 */ 35 #define MAX_INSTANCES 1024 36 37 38 /** 39 * Handle for a GET /management/instances operation. 40 */ 41 struct TALER_MERCHANT_GetManagementInstancesHandle 42 { 43 /** 44 * Base URL of the merchant backend. 45 */ 46 char *base_url; 47 48 /** 49 * The full URL for this request. 50 */ 51 char *url; 52 53 /** 54 * Handle for the request. 55 */ 56 struct GNUNET_CURL_Job *job; 57 58 /** 59 * Function to call with the result. 60 */ 61 TALER_MERCHANT_GetManagementInstancesCallback cb; 62 63 /** 64 * Closure for @a cb. 65 */ 66 TALER_MERCHANT_GET_MANAGEMENT_INSTANCES_RESULT_CLOSURE *cb_cls; 67 68 /** 69 * Reference to the execution context. 70 */ 71 struct GNUNET_CURL_Context *ctx; 72 }; 73 74 75 /** 76 * Parse instance information from @a ia. 77 * 78 * @param ia JSON array (or NULL!) with instance data 79 * @param[in] igr partially filled response 80 * @param gimh operation handle 81 * @return #GNUNET_OK on success 82 */ 83 static enum GNUNET_GenericReturnValue 84 parse_instances (const json_t *ia, 85 struct TALER_MERCHANT_GetManagementInstancesResponse *igr, 86 struct TALER_MERCHANT_GetManagementInstancesHandle *gimh) 87 { 88 unsigned int iis_len = (unsigned int) json_array_size (ia); 89 90 if ( (json_array_size (ia) != (size_t) iis_len) || 91 (iis_len > MAX_INSTANCES) ) 92 { 93 GNUNET_break (0); 94 return GNUNET_SYSERR; 95 } 96 { 97 struct TALER_MERCHANT_GetManagementInstancesInstanceInfo iis[ 98 GNUNET_NZL (iis_len)]; 99 size_t index; 100 json_t *value; 101 102 memset (iis, 103 0, 104 sizeof (iis)); 105 json_array_foreach (ia, index, value) { 106 struct TALER_MERCHANT_GetManagementInstancesInstanceInfo *ii = 107 &iis[index]; 108 struct GNUNET_JSON_Specification spec[] = { 109 GNUNET_JSON_spec_string ("name", 110 &ii->name), 111 GNUNET_JSON_spec_string ("id", 112 &ii->id), 113 GNUNET_JSON_spec_fixed_auto ("merchant_pub", 114 &ii->merchant_pub), 115 GNUNET_JSON_spec_array_const ("payment_targets", 116 &ii->payment_targets), 117 GNUNET_JSON_spec_mark_optional ( 118 GNUNET_JSON_spec_string ("website", 119 &ii->website), 120 NULL), 121 GNUNET_JSON_spec_mark_optional ( 122 GNUNET_JSON_spec_string ("logo", 123 &ii->logo), 124 NULL), 125 GNUNET_JSON_spec_bool ("deleted", 126 &ii->deleted), 127 GNUNET_JSON_spec_end () 128 }; 129 130 if (GNUNET_OK != 131 GNUNET_JSON_parse (value, 132 spec, 133 NULL, NULL)) 134 { 135 GNUNET_break_op (0); 136 return GNUNET_SYSERR; 137 } 138 for (size_t i = 0; i<json_array_size (ii->payment_targets); i++) 139 { 140 if (! json_is_string (json_array_get (ii->payment_targets, 141 i))) 142 { 143 GNUNET_break_op (0); 144 return GNUNET_SYSERR; 145 } 146 } 147 } 148 igr->details.ok.iis_length = iis_len; 149 igr->details.ok.iis = iis; 150 gimh->cb (gimh->cb_cls, 151 igr); 152 gimh->cb = NULL; 153 } 154 return GNUNET_OK; 155 } 156 157 158 /** 159 * Function called when we're done processing the 160 * HTTP GET /management/instances request. 161 * 162 * @param cls the `struct TALER_MERCHANT_GetManagementInstancesHandle` 163 * @param response_code HTTP response code, 0 on error 164 * @param response response body, NULL if not in JSON 165 */ 166 static void 167 handle_get_instances_finished (void *cls, 168 long response_code, 169 const void *response) 170 { 171 struct TALER_MERCHANT_GetManagementInstancesHandle *gimh = cls; 172 const json_t *json = response; 173 struct TALER_MERCHANT_GetManagementInstancesResponse igr = { 174 .hr.http_status = (unsigned int) response_code, 175 .hr.reply = json 176 }; 177 178 gimh->job = NULL; 179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 180 "Got /management/instances response with status code %u\n", 181 (unsigned int) response_code); 182 switch (response_code) 183 { 184 case MHD_HTTP_OK: 185 { 186 const json_t *instances; 187 struct GNUNET_JSON_Specification spec[] = { 188 GNUNET_JSON_spec_array_const ("instances", 189 &instances), 190 GNUNET_JSON_spec_end () 191 }; 192 193 if (GNUNET_OK != 194 GNUNET_JSON_parse (json, 195 spec, 196 NULL, NULL)) 197 { 198 igr.hr.http_status = 0; 199 igr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 200 break; 201 } 202 if (GNUNET_OK == 203 parse_instances (instances, 204 &igr, 205 gimh)) 206 { 207 TALER_MERCHANT_get_management_instances_cancel (gimh); 208 return; 209 } 210 igr.hr.http_status = 0; 211 igr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 212 break; 213 } 214 case MHD_HTTP_UNAUTHORIZED: 215 igr.hr.ec = TALER_JSON_get_error_code (json); 216 igr.hr.hint = TALER_JSON_get_error_hint (json); 217 break; 218 default: 219 igr.hr.ec = TALER_JSON_get_error_code (json); 220 igr.hr.hint = TALER_JSON_get_error_hint (json); 221 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 222 "Unexpected response code %u/%d\n", 223 (unsigned int) response_code, 224 (int) igr.hr.ec); 225 break; 226 } 227 gimh->cb (gimh->cb_cls, 228 &igr); 229 TALER_MERCHANT_get_management_instances_cancel (gimh); 230 } 231 232 233 struct TALER_MERCHANT_GetManagementInstancesHandle * 234 TALER_MERCHANT_get_management_instances_create ( 235 struct GNUNET_CURL_Context *ctx, 236 const char *url) 237 { 238 struct TALER_MERCHANT_GetManagementInstancesHandle *gimh; 239 240 gimh = GNUNET_new (struct TALER_MERCHANT_GetManagementInstancesHandle); 241 gimh->ctx = ctx; 242 gimh->base_url = GNUNET_strdup (url); 243 return gimh; 244 } 245 246 247 enum TALER_ErrorCode 248 TALER_MERCHANT_get_management_instances_start ( 249 struct TALER_MERCHANT_GetManagementInstancesHandle *gimh, 250 TALER_MERCHANT_GetManagementInstancesCallback cb, 251 TALER_MERCHANT_GET_MANAGEMENT_INSTANCES_RESULT_CLOSURE *cb_cls) 252 { 253 CURL *eh; 254 255 gimh->cb = cb; 256 gimh->cb_cls = cb_cls; 257 gimh->url = TALER_url_join (gimh->base_url, 258 "management/instances", 259 NULL); 260 if (NULL == gimh->url) 261 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 262 eh = TALER_MERCHANT_curl_easy_get_ (gimh->url); 263 if (NULL == eh) 264 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 265 gimh->job = GNUNET_CURL_job_add (gimh->ctx, 266 eh, 267 &handle_get_instances_finished, 268 gimh); 269 if (NULL == gimh->job) 270 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 271 return TALER_EC_NONE; 272 } 273 274 275 void 276 TALER_MERCHANT_get_management_instances_cancel ( 277 struct TALER_MERCHANT_GetManagementInstancesHandle *gimh) 278 { 279 if (NULL != gimh->job) 280 { 281 GNUNET_CURL_job_cancel (gimh->job); 282 gimh->job = NULL; 283 } 284 GNUNET_free (gimh->url); 285 GNUNET_free (gimh->base_url); 286 GNUNET_free (gimh); 287 } 288 289 290 /* end of merchant_api_get-management-instances-new.c */