sync_api_block_list.c (5844B)
1 /* 2 This file is part of TALER 3 Copyright (C) 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 General Public License as 7 published by the Free Software Foundation; either version 3, or 8 (at your 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 * @file lib/sync_api_block_list.c 21 * @brief Implementation of the block list GET 22 * @author Iván Ávalos 23 */ 24 #include "platform.h" 25 #include <curl/curl.h> 26 #include <jansson.h> 27 #include <microhttpd.h> 28 #include <gnunet/gnunet_util_lib.h> 29 #include <gnunet/gnunet_curl_lib.h> 30 #include <gnunet/gnunet_json_lib.h> 31 #include <taler/taler_json_lib.h> 32 #include <taler/taler_curl_lib.h> 33 #include <sync/sync_service.h> 34 #include <sync/sync_util.h> 35 #include "sync_api_curl_defaults.h" 36 37 38 /** 39 * Handle for a block list operation. 40 */ 41 struct SYNC_BlockListOperation 42 { 43 44 /** 45 * The url for this request. 46 */ 47 char *url; 48 49 /** 50 * Handle for the request. 51 */ 52 struct GNUNET_CURL_Job *job; 53 54 /** 55 * Reference to the execution context. 56 */ 57 struct GNUNET_CURL_Context *ctx; 58 59 /** 60 * Function to call with the result. 61 */ 62 SYNC_BlockListCallback cb; 63 64 /** 65 * Closure for @e cb. 66 */ 67 void *cb_cls; 68 69 }; 70 71 72 /** 73 * Function called when we're done processing the 74 * GET /backups/$KEY/blocks request. 75 * 76 * @param cls the `struct SYNC_BlockListOperation *` 77 * @param response_code HTTP response code, 0 on error 78 * @param response response body as parsed JSON, or NULL 79 */ 80 static void 81 handle_block_list_finished (void *cls, 82 long response_code, 83 const void *response) 84 { 85 struct SYNC_BlockListOperation *op = cls; 86 const json_t *json = response; 87 struct SYNC_BlockListDetails ld = { 88 .http_status = (unsigned int) response_code, 89 .ec = TALER_EC_INVALID 90 }; 91 92 op->job = NULL; 93 switch (response_code) 94 { 95 case 0: 96 break; 97 case MHD_HTTP_OK: 98 if (NULL != json) 99 { 100 unsigned int idx; 101 json_t *entry; 102 103 ld.ec = TALER_EC_NONE; 104 ld.num_entries = json_array_size (json); 105 ld.entries = GNUNET_new_array (ld.num_entries, 106 struct SYNC_BlockListEntry); 107 json_array_foreach (json, idx, entry) 108 { 109 struct SYNC_BlockListEntry *e = &ld.entries[idx]; 110 111 if (GNUNET_OK != 112 SYNC_block_entry_parse (entry, 113 e)) 114 { 115 GNUNET_break_op (0); 116 ld.ec = TALER_EC_GENERIC_PARAMETER_MALFORMED; 117 break; 118 } 119 } 120 } 121 else 122 { 123 ld.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 124 } 125 break; 126 case MHD_HTTP_BAD_REQUEST: 127 case MHD_HTTP_NOT_FOUND: 128 case MHD_HTTP_PAYMENT_REQUIRED: 129 case MHD_HTTP_INTERNAL_SERVER_ERROR: 130 default: 131 if ( (response_code >= 400) && 132 (response_code < 500) ) 133 ld.ec = (NULL != json) 134 ? TALER_JSON_get_error_code (json) 135 : TALER_EC_GENERIC_PARAMETER_MALFORMED; 136 else if (response_code >= 500) 137 ld.ec = (NULL != json) 138 ? TALER_JSON_get_error_code (json) 139 : TALER_EC_GENERIC_INVALID_RESPONSE; 140 break; 141 } 142 if (NULL != op->cb) 143 { 144 op->cb (op->cb_cls, 145 &ld); 146 op->cb = NULL; 147 } 148 if (NULL != ld.entries) 149 { 150 for (unsigned int i = 0; i < ld.num_entries; i++) 151 SYNC_block_entry_clear (&ld.entries[i]); 152 GNUNET_free (ld.entries); 153 } 154 SYNC_block_list_cancel (op); 155 } 156 157 158 struct SYNC_BlockListOperation * 159 SYNC_block_list (struct GNUNET_CURL_Context *ctx, 160 const char *base_url, 161 const struct SYNC_AccountPublicKeyP *pub, 162 int16_t limit, 163 const struct SYNC_BlockNonce *start_nonce, 164 SYNC_BlockListCallback cb, 165 void *cb_cls) 166 { 167 struct SYNC_BlockListOperation *op; 168 CURL *eh; 169 char *pub_s; 170 char *nonce_s = NULL; 171 char *path; 172 char *limit_s; 173 char *url; 174 175 pub_s = GNUNET_STRINGS_data_to_string_alloc (pub, 176 sizeof (*pub)); 177 GNUNET_asprintf (&path, 178 "backups/%s/blocks", 179 pub_s); 180 GNUNET_free (pub_s); 181 GNUNET_asprintf (&limit_s, 182 "%d", 183 (int) limit); 184 if (NULL != start_nonce) 185 nonce_s = GNUNET_STRINGS_data_to_string_alloc ( 186 start_nonce, 187 sizeof (*start_nonce)); 188 url = TALER_url_join (base_url, 189 path, 190 "limit", 191 limit_s, 192 "start_nonce", 193 nonce_s, 194 NULL); 195 GNUNET_free (nonce_s); 196 GNUNET_free (limit_s); 197 GNUNET_free (path); 198 if (NULL == url) 199 { 200 GNUNET_break (0); 201 return NULL; 202 } 203 204 op = GNUNET_new (struct SYNC_BlockListOperation); 205 op->ctx = ctx; 206 op->cb = cb; 207 op->cb_cls = cb_cls; 208 op->url = url; 209 210 eh = SYNC_curl_easy_get_ (op->url); 211 if (NULL == eh) 212 { 213 GNUNET_break (0); 214 GNUNET_free (op->url); 215 GNUNET_free (op); 216 return NULL; 217 } 218 219 op->job = GNUNET_CURL_job_add2 (ctx, 220 eh, 221 NULL, 222 &handle_block_list_finished, 223 op); 224 return op; 225 } 226 227 228 void 229 SYNC_block_list_cancel (struct SYNC_BlockListOperation *op) 230 { 231 if (NULL != op->job) 232 { 233 GNUNET_CURL_job_cancel (op->job); 234 op->job = NULL; 235 } 236 GNUNET_free (op->url); 237 GNUNET_free (op); 238 }