merchant_api_get_templates.c (6746B)
1 /* 2 This file is part of TALER 3 Copyright (C) 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 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_templates.c 19 * @brief Implementation of the GET /templates request of the merchant's HTTP API 20 * @author Priscilla HUANG 21 */ 22 #include "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_merchant_service.h" 29 #include "merchant_api_curl_defaults.h" 30 #include <taler/taler_json_lib.h> 31 #include <taler/taler_signatures.h> 32 33 34 /** 35 * Maximum number of templates we return. 36 */ 37 #define MAX_TEMPLATES 1024 38 39 40 /** 41 * Handle for a GET /templates operation. 42 */ 43 struct TALER_MERCHANT_TemplatesGetHandle 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_TemplatesGetCallback 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 72 73 /** 74 * Parse template information from @a ia. 75 * 76 * @param ia JSON array (or NULL!) with template data 77 * @param[in] tgr partially filled response 78 * @param tgh operation handle 79 * @return #GNUNET_OK on success 80 */ 81 static enum GNUNET_GenericReturnValue 82 parse_templates (const json_t *ia, 83 struct TALER_MERCHANT_TemplatesGetResponse *tgr, 84 struct TALER_MERCHANT_TemplatesGetHandle *tgh) 85 { 86 unsigned int tmpl_len = (unsigned int) json_array_size (ia); 87 88 if ( (json_array_size (ia) != (size_t) tmpl_len) || 89 (tmpl_len > MAX_TEMPLATES) ) 90 { 91 GNUNET_break (0); 92 return GNUNET_SYSERR; 93 } 94 { 95 struct TALER_MERCHANT_TemplateEntry tmpl[GNUNET_NZL (tmpl_len)]; 96 size_t index; 97 json_t *value; 98 99 json_array_foreach (ia, index, value) { 100 struct TALER_MERCHANT_TemplateEntry *ie = &tmpl[index]; 101 struct GNUNET_JSON_Specification spec[] = { 102 GNUNET_JSON_spec_string ("template_id", 103 &ie->template_id), 104 GNUNET_JSON_spec_end () 105 }; 106 107 if (GNUNET_OK != 108 GNUNET_JSON_parse (value, 109 spec, 110 NULL, NULL)) 111 { 112 GNUNET_break_op (0); 113 return GNUNET_SYSERR; 114 } 115 } 116 tgr->details.ok.templates_length = tmpl_len; 117 tgr->details.ok.templates = tmpl; 118 tgh->cb (tgh->cb_cls, 119 tgr); 120 tgh->cb = NULL; /* just to be sure */ 121 } 122 return GNUNET_OK; 123 } 124 125 126 /** 127 * Function called when we're done processing the 128 * HTTP /templates request. 129 * 130 * @param cls the `struct TALER_MERCHANT_TemplatesGetHandle` 131 * @param response_code HTTP response code, 0 on error 132 * @param response response body, NULL if not in JSON 133 */ 134 static void 135 handle_get_templates_finished (void *cls, 136 long response_code, 137 const void *response) 138 { 139 struct TALER_MERCHANT_TemplatesGetHandle *tgh = cls; 140 const json_t *json = response; 141 struct TALER_MERCHANT_TemplatesGetResponse tgr = { 142 .hr.http_status = (unsigned int) response_code, 143 .hr.reply = json 144 }; 145 146 tgh->job = NULL; 147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 148 "Got /templates response with status code %u\n", 149 (unsigned int) response_code); 150 switch (response_code) 151 { 152 case MHD_HTTP_OK: 153 { 154 const json_t *templates; 155 struct GNUNET_JSON_Specification spec[] = { 156 GNUNET_JSON_spec_array_const ("templates", 157 &templates), 158 GNUNET_JSON_spec_end () 159 }; 160 161 if (GNUNET_OK != 162 GNUNET_JSON_parse (json, 163 spec, 164 NULL, NULL)) 165 { 166 tgr.hr.http_status = 0; 167 tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 168 break; 169 } 170 if (GNUNET_OK == 171 parse_templates (templates, 172 &tgr, 173 tgh)) 174 { 175 TALER_MERCHANT_templates_get_cancel (tgh); 176 return; 177 } 178 tgr.hr.http_status = 0; 179 tgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 180 break; 181 } 182 case MHD_HTTP_UNAUTHORIZED: 183 tgr.hr.ec = TALER_JSON_get_error_code (json); 184 tgr.hr.hint = TALER_JSON_get_error_hint (json); 185 /* Nothing really to verify, merchant says we need to authenticate. */ 186 break; 187 default: 188 /* unexpected response code */ 189 tgr.hr.ec = TALER_JSON_get_error_code (json); 190 tgr.hr.hint = TALER_JSON_get_error_hint (json); 191 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 192 "Unexpected response code %u/%d\n", 193 (unsigned int) response_code, 194 (int) tgr.hr.ec); 195 break; 196 } 197 tgh->cb (tgh->cb_cls, 198 &tgr); 199 TALER_MERCHANT_templates_get_cancel (tgh); 200 } 201 202 203 struct TALER_MERCHANT_TemplatesGetHandle * 204 TALER_MERCHANT_templates_get ( 205 struct GNUNET_CURL_Context *ctx, 206 const char *backend_url, 207 TALER_MERCHANT_TemplatesGetCallback cb, 208 void *cb_cls) 209 { 210 struct TALER_MERCHANT_TemplatesGetHandle *tgh; 211 CURL *eh; 212 213 tgh = GNUNET_new (struct TALER_MERCHANT_TemplatesGetHandle); 214 tgh->ctx = ctx; 215 tgh->cb = cb; 216 tgh->cb_cls = cb_cls; 217 tgh->url = TALER_url_join (backend_url, 218 "private/templates", 219 NULL); 220 if (NULL == tgh->url) 221 { 222 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 223 "Could not construct request URL.\n"); 224 GNUNET_free (tgh); 225 return NULL; 226 } 227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 228 "Requesting URL '%s'\n", 229 tgh->url); 230 eh = TALER_MERCHANT_curl_easy_get_ (tgh->url); 231 tgh->job = GNUNET_CURL_job_add (ctx, 232 eh, 233 &handle_get_templates_finished, 234 tgh); 235 return tgh; 236 } 237 238 239 void 240 TALER_MERCHANT_templates_get_cancel ( 241 struct TALER_MERCHANT_TemplatesGetHandle *tgh) 242 { 243 if (NULL != tgh->job) 244 GNUNET_CURL_job_cancel (tgh->job); 245 GNUNET_free (tgh->url); 246 GNUNET_free (tgh); 247 }