merchant

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

merchant_api_patch_instance.c (7972B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2020 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 merchant_api_patch_instance.c
     21  * @brief Implementation of the PATCH /instances/$ID request
     22  *        of the merchant's HTTP API
     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 <gnunet/gnunet_util_lib.h>
     30 #include "taler_merchant_service.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_kyclogic_lib.h>
     35 #include <taler/taler_curl_lib.h>
     36 
     37 
     38 /**
     39  * Handle for a PATCH /instances/$ID operation.
     40  */
     41 struct TALER_MERCHANT_InstancePatchHandle
     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    * Function to call with the result.
     56    */
     57   TALER_MERCHANT_InstancePatchCallback cb;
     58 
     59   /**
     60    * Closure for @a cb.
     61    */
     62   void *cb_cls;
     63 
     64   /**
     65    * Reference to the execution context.
     66    */
     67   struct GNUNET_CURL_Context *ctx;
     68 
     69   /**
     70    * Minor context that holds body and headers.
     71    */
     72   struct TALER_CURL_PostContext post_ctx;
     73 
     74 };
     75 
     76 
     77 /**
     78  * Function called when we're done processing the
     79  * HTTP PATCH /instances/$ID request.
     80  *
     81  * @param cls the `struct TALER_MERCHANT_InstancePatchHandle`
     82  * @param response_code HTTP response code, 0 on error
     83  * @param response response body, NULL if not in JSON
     84  */
     85 static void
     86 handle_patch_instance_finished (void *cls,
     87                                 long response_code,
     88                                 const void *response)
     89 {
     90   struct TALER_MERCHANT_InstancePatchHandle *iph = cls;
     91   const json_t *json = response;
     92   struct TALER_MERCHANT_HttpResponse hr = {
     93     .http_status = (unsigned int) response_code,
     94     .reply = json
     95   };
     96 
     97   iph->job = NULL;
     98   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     99               "PATCH /instances/$ID completed with response code %u\n",
    100               (unsigned int) response_code);
    101   switch (response_code)
    102   {
    103   case 0:
    104     hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    105     break;
    106   case MHD_HTTP_NO_CONTENT:
    107     break;
    108   case MHD_HTTP_BAD_REQUEST:
    109     hr.ec = TALER_JSON_get_error_code (json);
    110     hr.hint = TALER_JSON_get_error_hint (json);
    111     break;
    112   case MHD_HTTP_UNAUTHORIZED:
    113     hr.ec = TALER_JSON_get_error_code (json);
    114     hr.hint = TALER_JSON_get_error_hint (json);
    115     /* Nothing really to verify, merchant says we need to authenticate. */
    116     break;
    117   case MHD_HTTP_FORBIDDEN:
    118     hr.ec = TALER_JSON_get_error_code (json);
    119     hr.hint = TALER_JSON_get_error_hint (json);
    120     /* Nothing really to verify, merchant says we tried to abort the payment
    121      * after it was successful. We should pass the JSON reply to the
    122      * application */
    123     break;
    124   case MHD_HTTP_NOT_FOUND:
    125     hr.ec = TALER_JSON_get_error_code (json);
    126     hr.hint = TALER_JSON_get_error_hint (json);
    127     break;
    128   case MHD_HTTP_CONFLICT:
    129     hr.ec = TALER_JSON_get_error_code (json);
    130     hr.hint = TALER_JSON_get_error_hint (json);
    131     break;
    132   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    133     hr.ec = TALER_JSON_get_error_code (json);
    134     hr.hint = TALER_JSON_get_error_hint (json);
    135     /* Server had an internal issue; we should retry,
    136        but this API leaves this to the application */
    137     break;
    138   default:
    139     TALER_MERCHANT_parse_error_details_ (json,
    140                                          response_code,
    141                                          &hr);
    142     /* unexpected response code */
    143     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    144                 "Unexpected response code %u/%d\n",
    145                 (unsigned int) response_code,
    146                 (int) hr.ec);
    147     GNUNET_break_op (0);
    148     break;
    149   }
    150   iph->cb (iph->cb_cls,
    151            &hr);
    152   TALER_MERCHANT_instance_patch_cancel (iph);
    153 }
    154 
    155 
    156 struct TALER_MERCHANT_InstancePatchHandle *
    157 TALER_MERCHANT_instance_patch (
    158   struct GNUNET_CURL_Context *ctx,
    159   const char *backend_url,
    160   const char *instance_id,
    161   const char *name,
    162   const json_t *address,
    163   const json_t *jurisdiction,
    164   bool use_stefan,
    165   struct GNUNET_TIME_Relative default_wire_transfer_delay,
    166   struct GNUNET_TIME_Relative default_pay_delay,
    167   struct GNUNET_TIME_Relative default_refund_delay,
    168   TALER_MERCHANT_InstancePatchCallback cb,
    169   void *cb_cls)
    170 {
    171   struct TALER_MERCHANT_InstancePatchHandle *iph;
    172   json_t *req_obj;
    173 
    174   req_obj = GNUNET_JSON_PACK (
    175     GNUNET_JSON_pack_string ("name",
    176                              name),
    177     GNUNET_JSON_pack_object_incref ("address",
    178                                     (json_t *) address),
    179     GNUNET_JSON_pack_object_incref ("jurisdiction",
    180                                     (json_t *) jurisdiction),
    181     GNUNET_JSON_pack_bool ("use_stefan",
    182                            use_stefan),
    183     GNUNET_JSON_pack_time_rel ("default_wire_transfer_delay",
    184                                default_wire_transfer_delay),
    185     GNUNET_JSON_pack_time_rel ("default_pay_delay",
    186                                default_pay_delay),
    187     GNUNET_JSON_pack_time_rel ("default_refund_delay",
    188                                default_refund_delay),
    189     /* FIXME: add eventually to arguments when we transform the API... */
    190     GNUNET_JSON_pack_time_rounder_interval (
    191       "default_wire_transfer_rounding_interval",
    192       GNUNET_TIME_RI_NONE)
    193     );
    194   iph = GNUNET_new (struct TALER_MERCHANT_InstancePatchHandle);
    195   iph->ctx = ctx;
    196   iph->cb = cb;
    197   iph->cb_cls = cb_cls;
    198   if (NULL != instance_id)
    199   {
    200     char *path;
    201 
    202     GNUNET_asprintf (&path,
    203                      "management/instances/%s",
    204                      instance_id);
    205     iph->url = TALER_url_join (backend_url,
    206                                path,
    207                                NULL);
    208     GNUNET_free (path);
    209   }
    210   else
    211   {
    212     /* backend_url is already identifying the instance */
    213     iph->url = TALER_url_join (backend_url,
    214                                "private",
    215                                NULL);
    216   }
    217   if (NULL == iph->url)
    218   {
    219     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    220                 "Could not construct request URL.\n");
    221     json_decref (req_obj);
    222     GNUNET_free (iph);
    223     return NULL;
    224   }
    225   {
    226     CURL *eh;
    227 
    228     eh = TALER_MERCHANT_curl_easy_get_ (iph->url);
    229     if (GNUNET_OK !=
    230         TALER_curl_easy_post (&iph->post_ctx,
    231                               eh,
    232                               req_obj))
    233     {
    234       GNUNET_break (0);
    235       curl_easy_cleanup (eh);
    236       json_decref (req_obj);
    237       GNUNET_free (iph->url);
    238       GNUNET_free (iph);
    239       return NULL;
    240     }
    241     json_decref (req_obj);
    242     GNUNET_assert (CURLE_OK ==
    243                    curl_easy_setopt (eh,
    244                                      CURLOPT_CUSTOMREQUEST,
    245                                      MHD_HTTP_METHOD_PATCH));
    246     iph->job = GNUNET_CURL_job_add2 (ctx,
    247                                      eh,
    248                                      iph->post_ctx.headers,
    249                                      &handle_patch_instance_finished,
    250                                      iph);
    251   }
    252   return iph;
    253 }
    254 
    255 
    256 void
    257 TALER_MERCHANT_instance_patch_cancel (
    258   struct TALER_MERCHANT_InstancePatchHandle *iph)
    259 {
    260   if (NULL != iph->job)
    261   {
    262     GNUNET_CURL_job_cancel (iph->job);
    263     iph->job = NULL;
    264   }
    265   TALER_curl_easy_post_finished (&iph->post_ctx);
    266   GNUNET_free (iph->url);
    267   GNUNET_free (iph);
    268 }
    269 
    270 
    271 /* end of merchant_api_patch_instance.c */