merchant_api_get-products-IMAGE_HASH-image.c (5833B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2025-2026 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Lesser General Public License as published by the Free Software 7 Foundation; either version 2.1, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 12 13 You should have received a copy of the GNU Lesser General Public License along with 14 TALER; see the file COPYING.LGPL. If not, see 15 <http://www.gnu.org/licenses/> 16 */ 17 /** 18 * @file merchant_api_get-products-IMAGE_HASH-image-new.c 19 * @brief Implementation of the GET /products/$IMAGE_HASH/image request 20 * @author Christian Grothoff 21 */ 22 #include "taler/platform.h" 23 #include <curl/curl.h> 24 #include <jansson.h> 25 #include <microhttpd.h> /* just for HTTP status codes */ 26 #include <gnunet/gnunet_util_lib.h> 27 #include <gnunet/gnunet_curl_lib.h> 28 #include <taler/taler-merchant/get-products-IMAGE_HASH-image.h> 29 #include "merchant_api_curl_defaults.h" 30 #include <taler/taler_json_lib.h> 31 32 33 /** 34 * Handle for a GET /products/$IMAGE_HASH/image operation. 35 */ 36 struct TALER_MERCHANT_GetProductsImageHandle 37 { 38 /** 39 * Base URL of the merchant backend. 40 */ 41 char *base_url; 42 43 /** 44 * The full URL for this request. 45 */ 46 char *url; 47 48 /** 49 * Handle for the request. 50 */ 51 struct GNUNET_CURL_Job *job; 52 53 /** 54 * Function to call with the result. 55 */ 56 TALER_MERCHANT_GetProductsImageCallback cb; 57 58 /** 59 * Closure for @a cb. 60 */ 61 TALER_MERCHANT_GET_PRODUCTS_IMAGE_RESULT_CLOSURE *cb_cls; 62 63 /** 64 * Reference to the execution context. 65 */ 66 struct GNUNET_CURL_Context *ctx; 67 68 /** 69 * Image hash identifier. 70 */ 71 char *image_hash; 72 }; 73 74 75 /** 76 * Function called when we're done processing the 77 * HTTP GET /products/$IMAGE_HASH/image request. 78 * 79 * @param cls the `struct TALER_MERCHANT_GetProductsImageHandle` 80 * @param response_code HTTP response code, 0 on error 81 * @param response response body, NULL if not in JSON 82 */ 83 static void 84 handle_get_product_image_finished (void *cls, 85 long response_code, 86 const void *response) 87 { 88 struct TALER_MERCHANT_GetProductsImageHandle *gpi = cls; 89 const json_t *json = response; 90 struct TALER_MERCHANT_GetProductsImageResponse pgr = { 91 .hr.http_status = (unsigned int) response_code, 92 .hr.reply = json 93 }; 94 95 gpi->job = NULL; 96 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 97 "Got /products/$IMAGE_HASH/image response with status code %u\n", 98 (unsigned int) response_code); 99 switch (response_code) 100 { 101 case MHD_HTTP_OK: 102 { 103 struct GNUNET_JSON_Specification spec[] = { 104 GNUNET_JSON_spec_string ("image", 105 &pgr.details.ok.image), 106 GNUNET_JSON_spec_end () 107 }; 108 109 if (GNUNET_OK == 110 GNUNET_JSON_parse (json, 111 spec, 112 NULL, NULL)) 113 { 114 gpi->cb (gpi->cb_cls, 115 &pgr); 116 GNUNET_JSON_parse_free (spec); 117 TALER_MERCHANT_get_products_image_cancel (gpi); 118 return; 119 } 120 pgr.hr.http_status = 0; 121 pgr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 122 break; 123 } 124 case MHD_HTTP_NOT_FOUND: 125 case MHD_HTTP_BAD_REQUEST: 126 pgr.hr.ec = TALER_JSON_get_error_code (json); 127 pgr.hr.hint = TALER_JSON_get_error_hint (json); 128 break; 129 default: 130 pgr.hr.ec = TALER_JSON_get_error_code (json); 131 pgr.hr.hint = TALER_JSON_get_error_hint (json); 132 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 133 "Unexpected response code %u/%d\n", 134 (unsigned int) response_code, 135 (int) pgr.hr.ec); 136 break; 137 } 138 gpi->cb (gpi->cb_cls, 139 &pgr); 140 TALER_MERCHANT_get_products_image_cancel (gpi); 141 } 142 143 144 struct TALER_MERCHANT_GetProductsImageHandle * 145 TALER_MERCHANT_get_products_image_create ( 146 struct GNUNET_CURL_Context *ctx, 147 const char *url, 148 const char *image_hash) 149 { 150 struct TALER_MERCHANT_GetProductsImageHandle *gpi; 151 152 gpi = GNUNET_new (struct TALER_MERCHANT_GetProductsImageHandle); 153 gpi->ctx = ctx; 154 gpi->base_url = GNUNET_strdup (url); 155 gpi->image_hash = GNUNET_strdup (image_hash); 156 return gpi; 157 } 158 159 160 enum TALER_ErrorCode 161 TALER_MERCHANT_get_products_image_start ( 162 struct TALER_MERCHANT_GetProductsImageHandle *gpi, 163 TALER_MERCHANT_GetProductsImageCallback cb, 164 TALER_MERCHANT_GET_PRODUCTS_IMAGE_RESULT_CLOSURE *cb_cls) 165 { 166 CURL *eh; 167 168 gpi->cb = cb; 169 gpi->cb_cls = cb_cls; 170 { 171 char *path; 172 173 GNUNET_asprintf (&path, 174 "products/%s/image", 175 gpi->image_hash); 176 gpi->url = TALER_url_join (gpi->base_url, 177 path, 178 NULL); 179 GNUNET_free (path); 180 } 181 if (NULL == gpi->url) 182 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 183 eh = TALER_MERCHANT_curl_easy_get_ (gpi->url); 184 if (NULL == eh) 185 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 186 gpi->job = GNUNET_CURL_job_add (gpi->ctx, 187 eh, 188 &handle_get_product_image_finished, 189 gpi); 190 if (NULL == gpi->job) 191 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 192 return TALER_EC_NONE; 193 } 194 195 196 void 197 TALER_MERCHANT_get_products_image_cancel ( 198 struct TALER_MERCHANT_GetProductsImageHandle *gpi) 199 { 200 if (NULL != gpi->job) 201 { 202 GNUNET_CURL_job_cancel (gpi->job); 203 gpi->job = NULL; 204 } 205 GNUNET_free (gpi->url); 206 GNUNET_free (gpi->base_url); 207 GNUNET_free (gpi->image_hash); 208 GNUNET_free (gpi); 209 } 210 211 212 /* end of merchant_api_get-products-IMAGE_HASH-image-new.c */