anastasis_api_policy_meta_lookup.c (7573B)
1 /* 2 This file is part of ANASTASIS 3 Copyright (C) 2022 Anastasis SARL 4 5 ANASTASIS 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 2.1, 8 or (at your option) any later version. 9 10 ANASTASIS 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 ANASTASIS; see the file COPYING.LGPL. If not, 17 see <http://www.gnu.org/licenses/> 18 */ 19 20 /** 21 * @file restclient/anastasis_api_policy_meta_lookup.c 22 * @brief Implementation of the /policy/$POL/meta GET request 23 * @author Christian Grothoff 24 */ 25 #include "platform.h" 26 #include <curl/curl.h> 27 #include <jansson.h> 28 #include <microhttpd.h> /* just for HTTP status codes */ 29 #include "anastasis_service.h" 30 #include "anastasis_api_curl_defaults.h" 31 #include <gnunet/gnunet_json_lib.h> 32 #include <taler/taler_signatures.h> 33 34 35 /** 36 * @brief A Meta Operation Handle 37 */ 38 struct ANASTASIS_PolicyMetaLookupOperation 39 { 40 41 /** 42 * The url for this request, including parameters. 43 */ 44 char *url; 45 46 /** 47 * Handle for the request. 48 */ 49 struct GNUNET_CURL_Job *job; 50 51 /** 52 * Function to call with the result. 53 */ 54 ANASTASIS_PolicyMetaLookupCallback cb; 55 56 /** 57 * Closure for @a cb. 58 */ 59 void *cb_cls; 60 61 /** 62 * Reference to the execution context. 63 */ 64 struct GNUNET_CURL_Context *ctx; 65 66 /** 67 * Public key of the account we are downloading from. 68 */ 69 struct ANASTASIS_CRYPTO_AccountPublicKeyP account_pub; 70 71 /** 72 * Maximum version to fetch. 73 */ 74 uint32_t max_version; 75 76 }; 77 78 79 /** 80 * Process GET /policy/$POL/meta response 81 * 82 * @param cls our `struct ANASTASIS_PolicyMetaLookupOperation *` 83 * @param response_code HTTP status 84 * @param data response body, a `json_t *`, NULL on error 85 */ 86 static void 87 handle_policy_meta_lookup_finished (void *cls, 88 long response_code, 89 const void *response) 90 { 91 struct ANASTASIS_PolicyMetaLookupOperation *plo = cls; 92 const json_t *json = response; 93 struct ANASTASIS_MetaDownloadDetails mdd = { 94 .http_status = response_code, 95 .response = json 96 }; 97 98 plo->job = NULL; 99 switch (response_code) 100 { 101 case 0: 102 /* Hard error */ 103 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 104 "Backend didn't even return from GET /policy\n"); 105 break; 106 case MHD_HTTP_OK: 107 { 108 size_t mlen = json_object_size (json); 109 110 /* put a cap, as we will stack-allocate below and the 111 current service LIMITs the result to 1000 anyway; 112 could theoretically be increased in the future, but 113 then we should not put this onto the stack anymore... */ 114 if (mlen > 10000) 115 { 116 GNUNET_break (0); 117 response_code = 0; 118 break; 119 } 120 { 121 struct ANASTASIS_MetaDataEntry metas[GNUNET_NZL (mlen)]; 122 void *md[GNUNET_NZL (mlen)]; 123 size_t off = 0; 124 const char *label; 125 const json_t *val; 126 127 memset (md, 128 0, 129 sizeof (md)); 130 mdd.details.ok.metas = metas; 131 mdd.details.ok.metas_length = mlen; 132 json_object_foreach ((json_t *) json, 133 label, 134 val) 135 { 136 unsigned int ver; 137 char dummy; 138 struct GNUNET_JSON_Specification spec[] = { 139 GNUNET_JSON_spec_varsize ("meta", 140 &md[off], 141 &metas[off].meta_data_size), 142 GNUNET_JSON_spec_timestamp ("upload_time", 143 &metas[off].server_time), 144 GNUNET_JSON_spec_end () 145 }; 146 147 if (1 != sscanf (label, 148 "%u%c", 149 &ver, 150 &dummy)) 151 { 152 GNUNET_break (0); 153 mdd.http_status = 0; 154 mdd.ec = TALER_EC_GENERIC_REPLY_MALFORMED; 155 break; 156 } 157 if (GNUNET_OK != 158 GNUNET_JSON_parse (val, 159 spec, 160 NULL, NULL)) 161 { 162 GNUNET_break_op (0); 163 mdd.http_status = 0; 164 mdd.ec = TALER_EC_GENERIC_REPLY_MALFORMED; 165 break; 166 } 167 metas[off].version = (uint32_t) ver; 168 metas[off].meta_data = md[off]; 169 off++; 170 } 171 if (off < mlen) 172 { 173 GNUNET_break (0); 174 mdd.http_status = 0; 175 mdd.ec = TALER_EC_GENERIC_REPLY_MALFORMED; 176 for (size_t i = 0; i<off; i++) 177 GNUNET_free (md[i]); 178 break; 179 } 180 plo->cb (plo->cb_cls, 181 &mdd); 182 for (size_t i = 0; i<off; i++) 183 GNUNET_free (md[i]); 184 plo->cb = NULL; 185 } 186 ANASTASIS_policy_meta_lookup_cancel (plo); 187 return; 188 } 189 case MHD_HTTP_BAD_REQUEST: 190 /* This should never happen, either us or the anastasis server is buggy 191 (or API version conflict); just pass JSON reply to the application */ 192 break; 193 case MHD_HTTP_NOT_FOUND: 194 /* Nothing really to verify */ 195 break; 196 case MHD_HTTP_INTERNAL_SERVER_ERROR: 197 /* Server had an internal issue; we should retry, but this API 198 leaves this to the application */ 199 break; 200 default: 201 /* unexpected response code */ 202 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 203 "Unexpected response code %u\n", 204 (unsigned int) response_code); 205 GNUNET_break (0); 206 break; 207 } 208 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 209 "HTTP status for policy meta lookup is %u\n", 210 (unsigned int) response_code); 211 plo->cb (plo->cb_cls, 212 &mdd); 213 plo->cb = NULL; 214 ANASTASIS_policy_meta_lookup_cancel (plo); 215 } 216 217 218 struct ANASTASIS_PolicyMetaLookupOperation * 219 ANASTASIS_policy_meta_lookup ( 220 struct GNUNET_CURL_Context *ctx, 221 const char *backend_url, 222 const struct ANASTASIS_CRYPTO_AccountPublicKeyP *anastasis_pub, 223 uint32_t max_version, 224 ANASTASIS_PolicyMetaLookupCallback cb, 225 void *cb_cls) 226 { 227 struct ANASTASIS_PolicyMetaLookupOperation *plo; 228 CURL *eh; 229 char *path; 230 231 // FIXME: pass 'max_version' in CURL request! 232 GNUNET_assert (NULL != cb); 233 plo = GNUNET_new (struct ANASTASIS_PolicyMetaLookupOperation); 234 plo->account_pub = *anastasis_pub; 235 { 236 char *acc_pub_str; 237 238 acc_pub_str = GNUNET_STRINGS_data_to_string_alloc (anastasis_pub, 239 sizeof (*anastasis_pub)); 240 GNUNET_asprintf (&path, 241 "policy/%s/meta", 242 acc_pub_str); 243 GNUNET_free (acc_pub_str); 244 } 245 plo->url = TALER_url_join (backend_url, 246 path, 247 NULL); 248 GNUNET_free (path); 249 eh = ANASTASIS_curl_easy_get_ (plo->url); 250 GNUNET_assert (NULL != eh); 251 plo->cb = cb; 252 plo->cb_cls = cb_cls; 253 plo->job = GNUNET_CURL_job_add (ctx, 254 eh, 255 &handle_policy_meta_lookup_finished, 256 plo); 257 return plo; 258 } 259 260 261 void 262 ANASTASIS_policy_meta_lookup_cancel ( 263 struct ANASTASIS_PolicyMetaLookupOperation *plo) 264 { 265 if (NULL != plo->job) 266 { 267 GNUNET_CURL_job_cancel (plo->job); 268 plo->job = NULL; 269 } 270 GNUNET_free (plo->url); 271 GNUNET_free (plo); 272 }