merchant_api_post-private-donau.c (7523B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2024-2026 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify 6 it under the terms of the GNU Lesser General Public License as 7 published by the Free Software Foundation; either version 2.1, 8 or (at your option) any later version. 9 10 TALER is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General 16 Public License along with TALER; see the file COPYING.LGPL. 17 If not, see <http://www.gnu.org/licenses/> 18 */ 19 /** 20 * @file merchant_api_post-private-donau.c 21 * @brief Implementation of the POST /private/donau request 22 * @author Christian Grothoff 23 */ 24 #include "taler/platform.h" 25 #include <curl/curl.h> 26 #include <jansson.h> 27 #include <microhttpd.h> /* just for HTTP status codes */ 28 #include <gnunet/gnunet_util_lib.h> 29 #include <gnunet/gnunet_curl_lib.h> 30 #include <taler/taler-merchant/post-private-donau.h> 31 #include "merchant_api_curl_defaults.h" 32 #include "merchant_api_common.h" 33 #include <taler/taler_json_lib.h> 34 #include <taler/taler_curl_lib.h> 35 36 37 /** 38 * Handle for a POST /private/donau operation. 39 */ 40 struct TALER_MERCHANT_PostPrivateDonauHandle 41 { 42 /** 43 * Base URL of the merchant backend. 44 */ 45 char *base_url; 46 47 /** 48 * The full URL for this request. 49 */ 50 char *url; 51 52 /** 53 * Handle for the request. 54 */ 55 struct GNUNET_CURL_Job *job; 56 57 /** 58 * Function to call with the result. 59 */ 60 TALER_MERCHANT_PostPrivateDonauCallback cb; 61 62 /** 63 * Closure for @a cb. 64 */ 65 TALER_MERCHANT_POST_PRIVATE_DONAU_RESULT_CLOSURE *cb_cls; 66 67 /** 68 * Reference to the execution context. 69 */ 70 struct GNUNET_CURL_Context *ctx; 71 72 /** 73 * Minor context that holds body and headers. 74 */ 75 struct TALER_CURL_PostContext post_ctx; 76 77 /** 78 * Charity information to register. 79 */ 80 struct TALER_MERCHANT_Charity charity; 81 82 /** 83 * Charity URL (owned copy). 84 */ 85 char *charity_url; 86 }; 87 88 89 /** 90 * Function called when we're done processing the 91 * HTTP POST /private/donau request. 92 * 93 * @param cls the `struct TALER_MERCHANT_PostPrivateDonauHandle` 94 * @param response_code HTTP response code, 0 on error 95 * @param response response body, NULL if not in JSON 96 */ 97 static void 98 handle_post_donau_finished (void *cls, 99 long response_code, 100 const void *response) 101 { 102 struct TALER_MERCHANT_PostPrivateDonauHandle *ppdh = cls; 103 const json_t *json = response; 104 struct TALER_MERCHANT_PostPrivateDonauResponse pdr = { 105 .hr.http_status = (unsigned int) response_code, 106 .hr.reply = json 107 }; 108 109 ppdh->job = NULL; 110 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 111 "POST /private/donau completed with response code %u\n", 112 (unsigned int) response_code); 113 switch (response_code) 114 { 115 case 0: 116 pdr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 117 break; 118 case MHD_HTTP_ACCEPTED: 119 if (GNUNET_OK != 120 TALER_MERCHANT_parse_mfa_challenge_response_ ( 121 json, 122 &pdr.details.accepted)) 123 { 124 GNUNET_break_op (0); 125 pdr.hr.http_status = 0; 126 pdr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 127 } 128 break; 129 case MHD_HTTP_NO_CONTENT: 130 break; 131 case MHD_HTTP_BAD_REQUEST: 132 pdr.hr.ec = TALER_JSON_get_error_code (json); 133 pdr.hr.hint = TALER_JSON_get_error_hint (json); 134 break; 135 case MHD_HTTP_CONFLICT: 136 pdr.hr.ec = TALER_JSON_get_error_code (json); 137 pdr.hr.hint = TALER_JSON_get_error_hint (json); 138 break; 139 case MHD_HTTP_INTERNAL_SERVER_ERROR: 140 pdr.hr.ec = TALER_JSON_get_error_code (json); 141 pdr.hr.hint = TALER_JSON_get_error_hint (json); 142 break; 143 case MHD_HTTP_BAD_GATEWAY: 144 pdr.hr.ec = TALER_JSON_get_error_code (json); 145 pdr.hr.hint = TALER_JSON_get_error_hint (json); 146 break; 147 default: 148 TALER_MERCHANT_parse_error_details_ (json, 149 response_code, 150 &pdr.hr); 151 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 152 "Unexpected response code %u/%d\n", 153 (unsigned int) response_code, 154 (int) pdr.hr.ec); 155 GNUNET_break_op (0); 156 break; 157 } 158 ppdh->cb (ppdh->cb_cls, 159 &pdr); 160 if (MHD_HTTP_ACCEPTED == response_code) 161 TALER_MERCHANT_mfa_challenge_response_free ( 162 &pdr.details.accepted); 163 TALER_MERCHANT_post_private_donau_cancel (ppdh); 164 } 165 166 167 struct TALER_MERCHANT_PostPrivateDonauHandle * 168 TALER_MERCHANT_post_private_donau_create ( 169 struct GNUNET_CURL_Context *ctx, 170 const char *url, 171 const struct TALER_MERCHANT_Charity *charity) 172 { 173 struct TALER_MERCHANT_PostPrivateDonauHandle *ppdh; 174 175 ppdh = GNUNET_new (struct TALER_MERCHANT_PostPrivateDonauHandle); 176 ppdh->ctx = ctx; 177 ppdh->base_url = GNUNET_strdup (url); 178 ppdh->charity_url = GNUNET_strdup (charity->charity_url); 179 ppdh->charity.charity_url = ppdh->charity_url; 180 ppdh->charity.charity_id = charity->charity_id; 181 return ppdh; 182 } 183 184 185 enum GNUNET_GenericReturnValue 186 TALER_MERCHANT_post_private_donau_set_options_ ( 187 struct TALER_MERCHANT_PostPrivateDonauHandle *ppdh, 188 unsigned int num_options, 189 const struct TALER_MERCHANT_PostPrivateDonauOptionValue *options) 190 { 191 for (unsigned int i = 0; i < num_options; i++) 192 { 193 switch (options[i].option) 194 { 195 case TALER_MERCHANT_POST_PRIVATE_DONAU_OPTION_END: 196 return GNUNET_OK; 197 default: 198 GNUNET_break (0); 199 return GNUNET_SYSERR; 200 } 201 } 202 return GNUNET_OK; 203 } 204 205 206 enum TALER_ErrorCode 207 TALER_MERCHANT_post_private_donau_start ( 208 struct TALER_MERCHANT_PostPrivateDonauHandle *ppdh, 209 TALER_MERCHANT_PostPrivateDonauCallback cb, 210 TALER_MERCHANT_POST_PRIVATE_DONAU_RESULT_CLOSURE *cb_cls) 211 { 212 json_t *req_obj; 213 CURL *eh; 214 215 ppdh->cb = cb; 216 ppdh->cb_cls = cb_cls; 217 ppdh->url = TALER_url_join (ppdh->base_url, 218 "private/donau", 219 NULL); 220 if (NULL == ppdh->url) 221 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 222 req_obj = GNUNET_JSON_PACK ( 223 GNUNET_JSON_pack_string ("donau_url", 224 ppdh->charity.charity_url), 225 GNUNET_JSON_pack_uint64 ("charity_id", 226 ppdh->charity.charity_id) 227 ); 228 eh = TALER_MERCHANT_curl_easy_get_ (ppdh->url); 229 if ( (NULL == eh) || 230 (GNUNET_OK != 231 TALER_curl_easy_post (&ppdh->post_ctx, 232 eh, 233 req_obj)) ) 234 { 235 GNUNET_break (0); 236 json_decref (req_obj); 237 if (NULL != eh) 238 curl_easy_cleanup (eh); 239 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 240 } 241 json_decref (req_obj); 242 ppdh->job = GNUNET_CURL_job_add2 (ppdh->ctx, 243 eh, 244 ppdh->post_ctx.headers, 245 &handle_post_donau_finished, 246 ppdh); 247 if (NULL == ppdh->job) 248 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 249 return TALER_EC_NONE; 250 } 251 252 253 void 254 TALER_MERCHANT_post_private_donau_cancel ( 255 struct TALER_MERCHANT_PostPrivateDonauHandle *ppdh) 256 { 257 if (NULL != ppdh->job) 258 { 259 GNUNET_CURL_job_cancel (ppdh->job); 260 ppdh->job = NULL; 261 } 262 TALER_curl_easy_post_finished (&ppdh->post_ctx); 263 GNUNET_free (ppdh->charity_url); 264 GNUNET_free (ppdh->url); 265 GNUNET_free (ppdh->base_url); 266 GNUNET_free (ppdh); 267 } 268 269 270 /* end of merchant_api_post-private-donau.c */