merchant_api_get-private-templates.c (7396B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2022-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-private-templates-new.c 19 * @brief Implementation of the GET /private/templates 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-private-templates.h> 29 #include "merchant_api_curl_defaults.h" 30 #include <taler/taler_json_lib.h> 31 32 33 /** 34 * Maximum number of templates we return. 35 */ 36 #define MAX_TEMPLATES 1024 37 38 39 /** 40 * Handle for a GET /private/templates operation. 41 */ 42 struct TALER_MERCHANT_GetPrivateTemplatesHandle 43 { 44 /** 45 * Base URL of the merchant backend. 46 */ 47 char *base_url; 48 49 /** 50 * The full URL for this request. 51 */ 52 char *url; 53 54 /** 55 * Handle for the request. 56 */ 57 struct GNUNET_CURL_Job *job; 58 59 /** 60 * Function to call with the result. 61 */ 62 TALER_MERCHANT_GetPrivateTemplatesCallback cb; 63 64 /** 65 * Closure for @a cb. 66 */ 67 TALER_MERCHANT_GET_PRIVATE_TEMPLATES_RESULT_CLOSURE *cb_cls; 68 69 /** 70 * Reference to the execution context. 71 */ 72 struct GNUNET_CURL_Context *ctx; 73 }; 74 75 76 /** 77 * Parse template information from @a ia. 78 * 79 * @param ia JSON array (or NULL!) with template data 80 * @param[in] tgr partially filled response 81 * @param gpth operation handle 82 * @return #GNUNET_OK on success 83 */ 84 static enum GNUNET_GenericReturnValue 85 parse_templates (const json_t *ia, 86 struct TALER_MERCHANT_GetPrivateTemplatesResponse *tgr, 87 struct TALER_MERCHANT_GetPrivateTemplatesHandle *gpth) 88 { 89 unsigned int tmpl_len = (unsigned int) json_array_size (ia); 90 91 if ( (json_array_size (ia) != (size_t) tmpl_len) || 92 (tmpl_len > MAX_TEMPLATES) ) 93 { 94 GNUNET_break (0); 95 return GNUNET_SYSERR; 96 } 97 { 98 struct TALER_MERCHANT_GetPrivateTemplatesTemplateEntry tmpl[ 99 GNUNET_NZL (tmpl_len)]; 100 size_t index; 101 json_t *value; 102 103 json_array_foreach (ia, index, value) { 104 struct TALER_MERCHANT_GetPrivateTemplatesTemplateEntry *ie = 105 &tmpl[index]; 106 struct GNUNET_JSON_Specification spec[] = { 107 GNUNET_JSON_spec_string ("template_id", 108 &ie->template_id), 109 GNUNET_JSON_spec_string ("template_description", 110 &ie->template_description), 111 GNUNET_JSON_spec_end () 112 }; 113 114 if (GNUNET_OK != 115 GNUNET_JSON_parse (value, 116 spec, 117 NULL, NULL)) 118 { 119 GNUNET_break_op (0); 120 return GNUNET_SYSERR; 121 } 122 } 123 tgr->details.ok.templates_length = tmpl_len; 124 tgr->details.ok.templates = tmpl; 125 gpth->cb (gpth->cb_cls, 126 tgr); 127 gpth->cb = NULL; 128 } 129 return GNUNET_OK; 130 } 131 132 133 /** 134 * Function called when we're done processing the 135 * HTTP GET /private/templates request. 136 * 137 * @param cls the `struct TALER_MERCHANT_GetPrivateTemplatesHandle` 138 * @param response_code HTTP response code, 0 on error 139 * @param response response body, NULL if not in JSON 140 */ 141 static void 142 handle_get_templates_finished (void *cls, 143 long response_code, 144 const void *response) 145 { 146 struct TALER_MERCHANT_GetPrivateTemplatesHandle *gpth = cls; 147 const json_t *json = response; 148 struct TALER_MERCHANT_GetPrivateTemplatesResponse tgr = { 149 .hr.http_status = (unsigned int) response_code, 150 .hr.reply = json 151 }; 152 153 gpth->job = NULL; 154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 155 "Got /private/templates response with status code %u\n", 156 (unsigned int) response_code); 157 switch (response_code) 158 { 159 case MHD_HTTP_OK: 160 { 161 const json_t *templates; 162 struct GNUNET_JSON_Specification spec[] = { 163 GNUNET_JSON_spec_array_const ("templates", 164 &templates), 165 GNUNET_JSON_spec_end () 166 }; 167 168 if (GNUNET_OK != 169 GNUNET_JSON_parse (json, 170 spec, 171 NULL, NULL)) 172 { 173 tgr.hr.http_status = 0; 174 tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 175 break; 176 } 177 if (GNUNET_OK == 178 parse_templates (templates, 179 &tgr, 180 gpth)) 181 { 182 TALER_MERCHANT_get_private_templates_cancel (gpth); 183 return; 184 } 185 tgr.hr.http_status = 0; 186 tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 187 break; 188 } 189 case MHD_HTTP_UNAUTHORIZED: 190 tgr.hr.ec = TALER_JSON_get_error_code (json); 191 tgr.hr.hint = TALER_JSON_get_error_hint (json); 192 break; 193 default: 194 tgr.hr.ec = TALER_JSON_get_error_code (json); 195 tgr.hr.hint = TALER_JSON_get_error_hint (json); 196 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 197 "Unexpected response code %u/%d\n", 198 (unsigned int) response_code, 199 (int) tgr.hr.ec); 200 break; 201 } 202 gpth->cb (gpth->cb_cls, 203 &tgr); 204 TALER_MERCHANT_get_private_templates_cancel (gpth); 205 } 206 207 208 struct TALER_MERCHANT_GetPrivateTemplatesHandle * 209 TALER_MERCHANT_get_private_templates_create ( 210 struct GNUNET_CURL_Context *ctx, 211 const char *url) 212 { 213 struct TALER_MERCHANT_GetPrivateTemplatesHandle *gpth; 214 215 gpth = GNUNET_new (struct TALER_MERCHANT_GetPrivateTemplatesHandle); 216 gpth->ctx = ctx; 217 gpth->base_url = GNUNET_strdup (url); 218 return gpth; 219 } 220 221 222 enum TALER_ErrorCode 223 TALER_MERCHANT_get_private_templates_start ( 224 struct TALER_MERCHANT_GetPrivateTemplatesHandle *gpth, 225 TALER_MERCHANT_GetPrivateTemplatesCallback cb, 226 TALER_MERCHANT_GET_PRIVATE_TEMPLATES_RESULT_CLOSURE *cb_cls) 227 { 228 CURL *eh; 229 230 gpth->cb = cb; 231 gpth->cb_cls = cb_cls; 232 gpth->url = TALER_url_join (gpth->base_url, 233 "private/templates", 234 NULL); 235 if (NULL == gpth->url) 236 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 237 eh = TALER_MERCHANT_curl_easy_get_ (gpth->url); 238 if (NULL == eh) 239 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 240 gpth->job = GNUNET_CURL_job_add (gpth->ctx, 241 eh, 242 &handle_get_templates_finished, 243 gpth); 244 if (NULL == gpth->job) 245 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 246 return TALER_EC_NONE; 247 } 248 249 250 void 251 TALER_MERCHANT_get_private_templates_cancel ( 252 struct TALER_MERCHANT_GetPrivateTemplatesHandle *gpth) 253 { 254 if (NULL != gpth->job) 255 { 256 GNUNET_CURL_job_cancel (gpth->job); 257 gpth->job = NULL; 258 } 259 GNUNET_free (gpth->url); 260 GNUNET_free (gpth->base_url); 261 GNUNET_free (gpth); 262 } 263 264 265 /* end of merchant_api_get-private-templates-new.c */