donau_api_charity_post.c (6704B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2024 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it 6 under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 TALER is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public 16 License along with TALER; see the file COPYING. If not, see 17 <http://www.gnu.org/licenses/> 18 */ 19 20 /** 21 * @file lib/donau_api_charity_post.c 22 * @brief Implementation of the "handle" component of the donau's HTTP API 23 * @author Lukas Matyja 24 */ 25 #include <gnunet/gnunet_curl_lib.h> 26 #include <taler/taler_json_lib.h> 27 #include <taler/taler_curl_lib.h> 28 #include "donau_service.h" 29 #include "donau_api_curl_defaults.h" 30 #include "donau_json_lib.h" 31 32 33 /** 34 * Handle for a POST /charities request. 35 */ 36 struct DONAU_CharityPostHandle 37 { 38 /** 39 * The url for the /charities request. 40 */ 41 char *url; 42 43 /** 44 * Minor context that holds body and headers. 45 */ 46 struct TALER_CURL_PostContext post_ctx; 47 48 /** 49 * Entry for this request with the `struct GNUNET_CURL_Context`. 50 */ 51 struct GNUNET_CURL_Job *job; 52 53 /** 54 * Function to call with the result. 55 */ 56 DONAU_PostCharityResponseCallback cb; 57 58 /** 59 * Closure to pass to @e cb. 60 */ 61 void *cb_cls; 62 63 /** 64 * Reference to the execution context. 65 */ 66 struct GNUNET_CURL_Context *ctx; 67 68 }; 69 70 /** 71 * Function called when we're done processing the 72 * HTTP POST /charities request. 73 * 74 * @param cls the `struct KeysRequest` 75 * @param response_code HTTP response code, 0 on error 76 * @param resp_obj parsed JSON result, NULL on error 77 */ 78 static void 79 handle_charity_post_finished (void *cls, 80 long response_code, 81 const void *resp_obj) 82 { 83 struct DONAU_CharityPostHandle *cph = cls; 84 const json_t *j = resp_obj; 85 86 struct DONAU_PostCharityResponse pcresp = { 87 .hr.reply = j, 88 .hr.http_status = (unsigned int) response_code 89 }; 90 91 cph->job = NULL; 92 switch (response_code) 93 { 94 case MHD_HTTP_CREATED: 95 { 96 struct GNUNET_JSON_Specification spec[] = { 97 GNUNET_JSON_spec_uint64 ("charity_id", 98 &pcresp.details.ok.charity_id), 99 GNUNET_JSON_spec_end () 100 }; 101 102 if (GNUNET_OK != 103 GNUNET_JSON_parse (j, 104 spec, 105 NULL, 106 NULL)) 107 { 108 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 109 "Could not parse response from charity POST\n"); 110 GNUNET_break_op (0); 111 pcresp.hr.http_status = 0; 112 pcresp.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; 113 } 114 } 115 break; 116 case MHD_HTTP_FORBIDDEN: 117 pcresp.hr.ec = TALER_JSON_get_error_code (j); 118 pcresp.hr.hint = TALER_JSON_get_error_hint (j); 119 break; 120 case MHD_HTTP_NOT_FOUND: 121 pcresp.hr.ec = TALER_JSON_get_error_code (j); 122 pcresp.hr.hint = TALER_JSON_get_error_hint (j); 123 break; 124 case MHD_HTTP_CONFLICT: 125 pcresp.hr.ec = TALER_JSON_get_error_code (j); 126 pcresp.hr.hint = TALER_JSON_get_error_hint (j); 127 break; 128 default: 129 /* unexpected response code */ 130 GNUNET_break_op (0); 131 pcresp.hr.ec = TALER_JSON_get_error_code (j); 132 pcresp.hr.hint = TALER_JSON_get_error_hint (j); 133 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 134 "Unexpected response code %u/%d for POST %s\n", 135 (unsigned int) response_code, 136 (int) pcresp.hr.ec, 137 cph->url); 138 break; 139 } 140 if (NULL != cph->cb) 141 { 142 cph->cb (cph->cb_cls, 143 &pcresp); 144 cph->cb = NULL; 145 } 146 DONAU_charity_post_cancel (cph); 147 } 148 149 150 struct DONAU_CharityPostHandle * 151 DONAU_charity_post ( 152 struct GNUNET_CURL_Context *ctx, 153 const char *url, 154 const char *charity_name, 155 const char *charity_url, 156 const struct TALER_Amount *max_per_year, 157 const struct DONAU_CharityPublicKeyP *charity_pub, 158 const struct DONAU_BearerToken *bearer, 159 DONAU_PostCharityResponseCallback cb, 160 void *cb_cls) 161 { 162 struct DONAU_CharityPostHandle *cph; 163 CURL *eh; 164 json_t *body; 165 166 TALER_LOG_DEBUG ("Connecting to the donau (%s)\n", 167 url); 168 cph = GNUNET_new (struct DONAU_CharityPostHandle); 169 cph->cb = cb; 170 cph->cb_cls = cb_cls; 171 cph->ctx = ctx; 172 cph->url = TALER_url_join (url, 173 "charities", 174 NULL); 175 if (NULL == cph->url) 176 { 177 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 178 "Could not construct request URL.\n"); 179 GNUNET_free (cph); 180 return NULL; 181 } 182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 183 "POST a charity with URL `%s'.\n", 184 cph->url); 185 body = GNUNET_JSON_PACK ( 186 GNUNET_JSON_pack_data_auto ("charity_pub", 187 charity_pub), 188 GNUNET_JSON_pack_string ("charity_url", 189 charity_url), 190 GNUNET_JSON_pack_string ("charity_name", 191 charity_name), 192 TALER_JSON_pack_amount ("max_per_year", 193 max_per_year)); 194 eh = DONAU_curl_easy_get_ (cph->url); 195 if ( (NULL == eh) || 196 (GNUNET_OK != 197 TALER_curl_easy_post (&cph->post_ctx, 198 eh, 199 body)) ) 200 { 201 GNUNET_break (0); 202 if (NULL != eh) 203 curl_easy_cleanup (eh); 204 json_decref (body); 205 GNUNET_free (cph->url); 206 GNUNET_free (cph); 207 return NULL; 208 } 209 json_decref (body); 210 cph->job = GNUNET_CURL_job_add2 (ctx, 211 eh, 212 cph->post_ctx.headers, 213 &handle_charity_post_finished, 214 cph); 215 GNUNET_assert (NULL != cph->job); 216 if (NULL != bearer) 217 { 218 struct curl_slist *auth; 219 char *hdr; 220 221 GNUNET_asprintf (&hdr, 222 "%s: Bearer %s", 223 MHD_HTTP_HEADER_AUTHORIZATION, 224 bearer->token); 225 auth = curl_slist_append (NULL, 226 hdr); 227 GNUNET_free (hdr); 228 GNUNET_CURL_extend_headers (cph->job, 229 auth); 230 curl_slist_free_all (auth); 231 } 232 return cph; 233 } 234 235 236 void 237 DONAU_charity_post_cancel ( 238 struct DONAU_CharityPostHandle *cph) 239 { 240 if (NULL != cph->job) 241 { 242 GNUNET_CURL_job_cancel (cph->job); 243 cph->job = NULL; 244 } 245 TALER_curl_easy_post_finished (&cph->post_ctx); 246 GNUNET_free (cph->url); 247 GNUNET_free (cph); 248 }