donau_api_charity_post.c (6623B)
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 } 112 } 113 break; 114 case MHD_HTTP_FORBIDDEN: 115 pcresp.hr.ec = TALER_JSON_get_error_code (j); 116 pcresp.hr.hint = TALER_JSON_get_error_hint (j); 117 break; 118 case MHD_HTTP_NOT_FOUND: 119 pcresp.hr.ec = TALER_JSON_get_error_code (j); 120 pcresp.hr.hint = TALER_JSON_get_error_hint (j); 121 break; 122 case MHD_HTTP_CONFLICT: 123 pcresp.hr.ec = TALER_JSON_get_error_code (j); 124 pcresp.hr.hint = TALER_JSON_get_error_hint (j); 125 break; 126 default: 127 /* unexpected response code */ 128 GNUNET_break_op (0); 129 pcresp.hr.ec = TALER_JSON_get_error_code (j); 130 pcresp.hr.hint = TALER_JSON_get_error_hint (j); 131 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 132 "Unexpected response code %u/%d for POST %s\n", 133 (unsigned int) response_code, 134 (int) pcresp.hr.ec, 135 cph->url); 136 break; 137 } 138 if (NULL != cph->cb) 139 { 140 cph->cb (cph->cb_cls, 141 &pcresp); 142 cph->cb = NULL; 143 } 144 DONAU_charity_post_cancel (cph); 145 } 146 147 148 struct DONAU_CharityPostHandle * 149 DONAU_charity_post ( 150 struct GNUNET_CURL_Context *ctx, 151 const char *url, 152 const char *charity_name, 153 const char *charity_url, 154 const struct TALER_Amount *max_per_year, 155 const struct DONAU_CharityPublicKeyP *charity_pub, 156 const struct DONAU_BearerToken *bearer, 157 DONAU_PostCharityResponseCallback cb, 158 void *cb_cls) 159 { 160 struct DONAU_CharityPostHandle *cph; 161 CURL *eh; 162 json_t *body; 163 164 TALER_LOG_DEBUG ("Connecting to the donau (%s)\n", 165 url); 166 cph = GNUNET_new (struct DONAU_CharityPostHandle); 167 cph->url = GNUNET_strdup (url); 168 cph->cb = cb; 169 cph->cb_cls = cb_cls; 170 cph->ctx = ctx; 171 cph->url = TALER_url_join (url, 172 "charities", 173 NULL); 174 if (NULL == cph->url) 175 { 176 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 177 "Could not construct request URL.\n"); 178 GNUNET_free (cph); 179 return NULL; 180 } 181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 182 "POST a charity with URL `%s'.\n", 183 cph->url); 184 body = GNUNET_JSON_PACK ( 185 GNUNET_JSON_pack_data_auto ("charity_pub", 186 charity_pub), 187 GNUNET_JSON_pack_string ("charity_url", 188 charity_url), 189 GNUNET_JSON_pack_string ("charity_name", 190 charity_name), 191 TALER_JSON_pack_amount ("max_per_year", 192 max_per_year)); 193 eh = DONAU_curl_easy_get_ (cph->url); 194 if ( (NULL == eh) || 195 (GNUNET_OK != 196 TALER_curl_easy_post (&cph->post_ctx, 197 eh, 198 body)) ) 199 { 200 GNUNET_break (0); 201 if (NULL != eh) 202 curl_easy_cleanup (eh); 203 json_decref (body); 204 GNUNET_free (cph->url); 205 return NULL; 206 } 207 json_decref (body); 208 cph->job = GNUNET_CURL_job_add2 (ctx, 209 eh, 210 cph->post_ctx.headers, 211 &handle_charity_post_finished, 212 cph); 213 GNUNET_assert (NULL != cph->job); 214 if (NULL != bearer) 215 { 216 struct curl_slist *auth; 217 char *hdr; 218 219 GNUNET_asprintf (&hdr, 220 "%s: Bearer %s", 221 MHD_HTTP_HEADER_AUTHORIZATION, 222 bearer->token); 223 auth = curl_slist_append (NULL, 224 hdr); 225 GNUNET_free (hdr); 226 GNUNET_CURL_extend_headers (cph->job, 227 auth); 228 curl_slist_free_all (auth); 229 } 230 return cph; 231 } 232 233 234 void 235 DONAU_charity_post_cancel ( 236 struct DONAU_CharityPostHandle *cph) 237 { 238 if (NULL != cph->job) 239 { 240 GNUNET_CURL_job_cancel (cph->job); 241 cph->job = NULL; 242 } 243 TALER_curl_easy_post_finished (&cph->post_ctx); 244 GNUNET_free (cph->url); 245 GNUNET_free (cph); 246 }