merchant

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

taler-merchant-httpd_post-reports-REPORT_ID.c (6384B)


      1 /*
      2   This file is part of TALER
      3   (C) 2025 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, 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 Affero General Public License for more
     12   details.
     13 
     14   You should have received a copy of the GNU Affero General Public License
     15   along with TALER; see the file COPYING.  If not, see
     16   <http://www.gnu.org/licenses/>
     17 */
     18 /**
     19  * @file taler-merchant-httpd_post-reports-REPORT_ID.c
     20  * @brief implementation of POST /reports/$REPORT_ID
     21  * @author Christian Grothoff
     22  */
     23 #include "taler/platform.h"
     24 #include "taler-merchant-httpd_dispatcher.h"
     25 #include "taler-merchant-httpd_post-reports-REPORT_ID.h"
     26 #include <taler/taler_json_lib.h>
     27 
     28 
     29 MHD_RESULT
     30 TMH_post_reports_ID (
     31   const struct TMH_RequestHandler *rh,
     32   struct MHD_Connection *connection,
     33   struct TMH_HandlerContext *hc)
     34 {
     35   const char *report_id_str = hc->infix;
     36   unsigned long long report_id;
     37   const char *mime_type;
     38   struct TALER_MERCHANT_ReportToken report_token;
     39   struct GNUNET_JSON_Specification spec[] = {
     40     GNUNET_JSON_spec_fixed_auto ("report_token",
     41                                  &report_token),
     42     GNUNET_JSON_spec_end ()
     43   };
     44   enum GNUNET_DB_QueryStatus qs;
     45   char *instance_id;
     46   char *data_source;
     47 
     48   {
     49     char dummy;
     50 
     51     if (1 != sscanf (report_id_str,
     52                      "%llu%c",
     53                      &report_id,
     54                      &dummy))
     55     {
     56       GNUNET_break_op (0);
     57       return TALER_MHD_reply_with_error (connection,
     58                                          MHD_HTTP_BAD_REQUEST,
     59                                          TALER_EC_GENERIC_PARAMETER_MALFORMED,
     60                                          "report_id");
     61     }
     62   }
     63 
     64   {
     65     enum GNUNET_GenericReturnValue res;
     66 
     67     res = TALER_MHD_parse_json_data (connection,
     68                                      hc->request_body,
     69                                      spec);
     70     if (GNUNET_OK != res)
     71     {
     72       GNUNET_break_op (0);
     73       return (GNUNET_NO == res)
     74         ? MHD_YES
     75         : MHD_NO;
     76     }
     77   }
     78 
     79   mime_type = MHD_lookup_connection_value (connection,
     80                                            MHD_HEADER_KIND,
     81                                            MHD_HTTP_HEADER_ACCEPT);
     82   if (NULL == mime_type)
     83     mime_type = "application/json";
     84   qs = TMH_db->check_report (TMH_db->cls,
     85                              report_id,
     86                              &report_token,
     87                              mime_type,
     88                              &instance_id,
     89                              &data_source);
     90   if (qs < 0)
     91   {
     92     GNUNET_break (0);
     93     return TALER_MHD_reply_with_error (connection,
     94                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     95                                        TALER_EC_GENERIC_DB_FETCH_FAILED,
     96                                        "check_report");
     97   }
     98   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
     99   {
    100     return TALER_MHD_reply_with_error (connection,
    101                                        MHD_HTTP_NOT_FOUND,
    102                                        TALER_EC_MERCHANT_GENERIC_REPORT_UNKNOWN,
    103                                        report_id_str);
    104   }
    105 
    106   {
    107     struct TMH_MerchantInstance *mi;
    108 
    109     mi = TMH_lookup_instance (instance_id);
    110     if (NULL == mi)
    111     {
    112       /* Strange, we found the report but the instance of the
    113          report is not known. This should basically be impossible
    114          modulo maybe some transactional issue where the
    115          instance was created, the report added *and* triggered
    116          before this process was able to process the notification
    117          about the new instance. Wild. */
    118       GNUNET_break (0);
    119       return TALER_MHD_reply_with_error (connection,
    120                                          MHD_HTTP_NOT_FOUND,
    121                                          TALER_EC_MERCHANT_GENERIC_REPORT_UNKNOWN,
    122                                          report_id_str);
    123     }
    124     /* Rewrite request: force instance to match report */
    125     mi->rc++;
    126     if (NULL != hc->instance)
    127       TMH_instance_decref (hc->instance);
    128     hc->instance = mi;
    129   }
    130   {
    131     enum GNUNET_GenericReturnValue ret;
    132     bool is_public; /* ignored: access control never applies for reports */
    133     char *q;
    134 
    135     /* This rewrites the request: force request handler to match report! */
    136     q = strchr (data_source,
    137                 '?');
    138     if (NULL != q)
    139     {
    140       /* Terminate URI at '?' for dispatching, parse
    141          query parameters and add them to this connection */
    142       *q = '\0';
    143       for (char *tok = strtok (q + 1,
    144                                "&");
    145            NULL != tok;
    146            tok = strtok (NULL,
    147                          "&"))
    148       {
    149         char *eq;
    150 
    151         eq = strchr (tok,
    152                      '=');
    153         if (NULL == eq)
    154         {
    155           GNUNET_break (MHD_YES ==
    156                         MHD_set_connection_value (connection,
    157                                                   MHD_GET_ARGUMENT_KIND,
    158                                                   tok,
    159                                                   NULL));
    160         }
    161         else
    162         {
    163           *eq = '\0';
    164           GNUNET_break (MHD_YES ==
    165                         MHD_set_connection_value (connection,
    166                                                   MHD_GET_ARGUMENT_KIND,
    167                                                   tok,
    168                                                   eq + 1));
    169         }
    170       }
    171     }
    172 
    173     hc->rh = NULL; /* just to make it clear: current one will NOT remain */
    174     ret = TMH_dispatch_request (hc,
    175                                 data_source,
    176                                 MHD_HTTP_METHOD_GET,
    177                                 0 == strcmp ("admin",
    178                                              instance_id),
    179                                 &is_public);
    180     if (GNUNET_OK != ret)
    181       return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
    182     GNUNET_break (NULL != hc->rh);
    183   }
    184   GNUNET_free (instance_id);
    185   GNUNET_free (data_source);
    186   /* MHD will call the main handler again, which will now
    187      dispatch into the _new_ handler callback we just installed! */
    188   return MHD_YES;
    189 }