merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

merchant_api_get-private-fountains.c (7921B)


      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 Lesser 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   TALER is distributed in the hope that it will be useful,
     11   but WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU Lesser General Public License for more details.
     14 
     15   You should have received a copy of the GNU Lesser General
     16   Public License along with TALER; see the file COPYING.LGPL.
     17   If not, see <http://www.gnu.org/licenses/>
     18 */
     19 /**
     20  * @file src/lib/merchant_api_get-private-fountains.c
     21  * @brief Implementation of the GET /private/fountains request
     22  * @author Bohdan Potuzhnyi
     23  */
     24 #include "platform.h"
     25 #include <curl/curl.h>
     26 #include <jansson.h>
     27 #include <microhttpd.h> /* just for HTTP status codes */
     28 #include <gnunet/gnunet_util_lib.h>
     29 #include <gnunet/gnunet_curl_lib.h>
     30 #include <taler/merchant/get-private-fountains.h>
     31 #include "merchant_api_curl_defaults.h"
     32 #include "merchant_api_common.h"
     33 #include <taler/taler_json_lib.h>
     34 #include <taler/taler_curl_lib.h>
     35 
     36 
     37 /**
     38  * Handle for a GET /private/fountains operation.
     39  */
     40 struct TALER_MERCHANT_GetPrivateFountainsHandle
     41 {
     42   /**
     43    * Base URL of the merchant backend.
     44    */
     45   char *base_url;
     46 
     47   /**
     48    * The full URL for this request.
     49    */
     50   char *url;
     51 
     52   /**
     53    * Handle for the request.
     54    */
     55   struct GNUNET_CURL_Job *job;
     56 
     57   /**
     58    * Function to call with the result.
     59    */
     60   TALER_MERCHANT_GetPrivateFountainsCallback cb;
     61 
     62   /**
     63    * Closure for @a cb.
     64    */
     65   TALER_MERCHANT_GET_PRIVATE_FOUNTAINS_RESULT_CLOSURE *cb_cls;
     66 
     67   /**
     68    * Reference to the execution context.
     69    */
     70   struct GNUNET_CURL_Context *ctx;
     71 };
     72 
     73 
     74 /**
     75  * Parse the "fountains" array and invoke the callback.
     76  *
     77  * @param gpfh operation handle
     78  * @param[in,out] gfr response to complete and pass to the callback
     79  */
     80 static void
     81 handle_ok (struct TALER_MERCHANT_GetPrivateFountainsHandle *gpfh,
     82            struct TALER_MERCHANT_GetPrivateFountainsResponse *gfr)
     83 {
     84   const json_t *jfountains;
     85   struct GNUNET_JSON_Specification spec[] = {
     86     GNUNET_JSON_spec_array_const ("fountains",
     87                                   &jfountains),
     88     GNUNET_JSON_spec_end ()
     89   };
     90 
     91   if (GNUNET_OK !=
     92       GNUNET_JSON_parse (gfr->hr.reply,
     93                          spec,
     94                          NULL,
     95                          NULL))
     96   {
     97     GNUNET_break_op (0);
     98     gfr->hr.http_status = 0;
     99     gfr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
    100     gpfh->cb (gpfh->cb_cls,
    101               gfr);
    102     return;
    103   }
    104   /* This endpoint is not paginated, so bound allocation bytes rather than
    105      imposing the much smaller limit used for grants within one fountain.
    106      Check before narrowing the count or multiplying it by the entry size. */
    107   if (json_array_size (jfountains) >=
    108       GNUNET_MAX_MALLOC_CHECKED / sizeof (struct TALER_MERCHANT_FountainEntry))
    109   {
    110     gfr->hr.http_status = 0;
    111     gfr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
    112     gpfh->cb (gpfh->cb_cls,
    113               gfr);
    114     return;
    115   }
    116   {
    117     unsigned int len = (unsigned int) json_array_size (jfountains);
    118     struct TALER_MERCHANT_FountainEntry *fountains
    119       = GNUNET_new_array (GNUNET_NZL (len),
    120                           struct TALER_MERCHANT_FountainEntry);
    121     size_t idx;
    122     json_t *jf;
    123 
    124     json_array_foreach ((json_t *) jfountains, idx, jf)
    125     {
    126       struct TALER_MERCHANT_FountainEntry *fe = &fountains[idx];
    127       struct GNUNET_JSON_Specification ispec[] = {
    128         GNUNET_JSON_spec_string ("fountain_id",
    129                                  &fe->fountain_id),
    130         GNUNET_JSON_spec_string ("description",
    131                                  &fe->description),
    132         GNUNET_JSON_spec_end ()
    133       };
    134 
    135       if (GNUNET_OK !=
    136           GNUNET_JSON_parse (jf,
    137                              ispec,
    138                              NULL,
    139                              NULL))
    140       {
    141         GNUNET_break_op (0);
    142         gfr->hr.http_status = 0;
    143         gfr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
    144         GNUNET_free (fountains);
    145         gpfh->cb (gpfh->cb_cls,
    146                   gfr);
    147         return;
    148       }
    149     }
    150     gfr->details.ok.fountains = fountains;
    151     gfr->details.ok.fountains_len = len;
    152     gpfh->cb (gpfh->cb_cls,
    153               gfr);
    154     GNUNET_free (fountains);
    155   }
    156 }
    157 
    158 
    159 /**
    160  * Function called when we're done processing the
    161  * HTTP GET /private/fountains request.
    162  *
    163  * @param cls the `struct TALER_MERCHANT_GetPrivateFountainsHandle`
    164  * @param response_code HTTP response code, 0 on error
    165  * @param response response body, NULL if not in JSON
    166  */
    167 static void
    168 handle_get_fountains_finished (void *cls,
    169                                long response_code,
    170                                const void *response)
    171 {
    172   struct TALER_MERCHANT_GetPrivateFountainsHandle *gpfh = cls;
    173   const json_t *json = response;
    174   struct TALER_MERCHANT_GetPrivateFountainsResponse gfr = {
    175     .hr.http_status = (unsigned int) response_code,
    176     .hr.reply = json
    177   };
    178 
    179   gpfh->job = NULL;
    180   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    181               "GET /private/fountains completed with response code %u\n",
    182               (unsigned int) response_code);
    183   switch (response_code)
    184   {
    185   case 0:
    186     gfr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    187     break;
    188   case MHD_HTTP_OK:
    189     handle_ok (gpfh,
    190                &gfr);
    191     TALER_MERCHANT_get_private_fountains_cancel (gpfh);
    192     return;
    193   case MHD_HTTP_UNAUTHORIZED:
    194   case MHD_HTTP_FORBIDDEN:
    195   case MHD_HTTP_NOT_FOUND:
    196   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    197     gfr.hr.ec = TALER_JSON_get_error_code (json);
    198     gfr.hr.hint = TALER_JSON_get_error_hint (json);
    199     break;
    200   default:
    201     TALER_MERCHANT_parse_error_details_ (json,
    202                                          response_code,
    203                                          &gfr.hr);
    204     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    205                 "Unexpected response code %u/%d\n",
    206                 (unsigned int) response_code,
    207                 (int) gfr.hr.ec);
    208     GNUNET_break_op (0);
    209     break;
    210   }
    211   gpfh->cb (gpfh->cb_cls,
    212             &gfr);
    213   TALER_MERCHANT_get_private_fountains_cancel (gpfh);
    214 }
    215 
    216 
    217 struct TALER_MERCHANT_GetPrivateFountainsHandle *
    218 TALER_MERCHANT_get_private_fountains_create (
    219   struct GNUNET_CURL_Context *ctx,
    220   const char *url)
    221 {
    222   struct TALER_MERCHANT_GetPrivateFountainsHandle *gpfh;
    223 
    224   gpfh = GNUNET_new (struct TALER_MERCHANT_GetPrivateFountainsHandle);
    225   gpfh->ctx = ctx;
    226   gpfh->base_url = GNUNET_strdup (url);
    227   return gpfh;
    228 }
    229 
    230 
    231 enum TALER_ErrorCode
    232 TALER_MERCHANT_get_private_fountains_start (
    233   struct TALER_MERCHANT_GetPrivateFountainsHandle *gpfh,
    234   TALER_MERCHANT_GetPrivateFountainsCallback cb,
    235   TALER_MERCHANT_GET_PRIVATE_FOUNTAINS_RESULT_CLOSURE *cb_cls)
    236 {
    237   CURL *eh;
    238 
    239   gpfh->cb = cb;
    240   gpfh->cb_cls = cb_cls;
    241   gpfh->url = TALER_url_join (gpfh->base_url,
    242                               "private/fountains",
    243                               NULL);
    244   if (NULL == gpfh->url)
    245     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    246   eh = TALER_MERCHANT_curl_easy_get_ (gpfh->url);
    247   if (NULL == eh)
    248   {
    249     GNUNET_break (0);
    250     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    251   }
    252   gpfh->job = GNUNET_CURL_job_add (gpfh->ctx,
    253                                    eh,
    254                                    &handle_get_fountains_finished,
    255                                    gpfh);
    256   if (NULL == gpfh->job)
    257     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    258   return TALER_EC_NONE;
    259 }
    260 
    261 
    262 void
    263 TALER_MERCHANT_get_private_fountains_cancel (
    264   struct TALER_MERCHANT_GetPrivateFountainsHandle *gpfh)
    265 {
    266   if (NULL != gpfh->job)
    267   {
    268     GNUNET_CURL_job_cancel (gpfh->job);
    269     gpfh->job = NULL;
    270   }
    271   GNUNET_free (gpfh->url);
    272   GNUNET_free (gpfh->base_url);
    273   GNUNET_free (gpfh);
    274 }
    275 
    276 
    277 /* end of merchant_api_get-private-fountains.c */