merchant

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

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


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