merchant

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

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


      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       GNUNET_free (instance_id);
    121       GNUNET_free (data_source);
    122       return TALER_MHD_reply_with_error (connection,
    123                                          MHD_HTTP_NOT_FOUND,
    124                                          TALER_EC_MERCHANT_GENERIC_REPORT_UNKNOWN,
    125                                          report_id_str);
    126     }
    127     /* Rewrite request: force instance to match report */
    128     mi->rc++;
    129     if (NULL != hc->instance)
    130       TMH_instance_decref (hc->instance);
    131     hc->instance = mi;
    132   }
    133   {
    134     enum GNUNET_GenericReturnValue ret;
    135     bool is_public; /* ignored: access control never applies for reports */
    136     char *q;
    137 
    138     /* This rewrites the request: force request handler to match report! */
    139     q = strchr (data_source,
    140                 '?');
    141     if (NULL != q)
    142     {
    143       /* Terminate URI at '?' for dispatching, parse
    144          query parameters and add them to this connection */
    145       *q = '\0';
    146       for (char *tok = strtok (q + 1,
    147                                "&");
    148            NULL != tok;
    149            tok = strtok (NULL,
    150                          "&"))
    151       {
    152         char *eq;
    153 
    154         eq = strchr (tok,
    155                      '=');
    156         if (NULL == eq)
    157         {
    158           GNUNET_break (MHD_YES ==
    159                         MHD_set_connection_value (connection,
    160                                                   MHD_GET_ARGUMENT_KIND,
    161                                                   tok,
    162                                                   NULL));
    163         }
    164         else
    165         {
    166           *eq = '\0';
    167           GNUNET_break (MHD_YES ==
    168                         MHD_set_connection_value (connection,
    169                                                   MHD_GET_ARGUMENT_KIND,
    170                                                   tok,
    171                                                   eq + 1));
    172         }
    173       }
    174     }
    175 
    176     hc->rh = NULL; /* just to make it clear: current one will NOT remain */
    177     ret = TMH_dispatch_request (hc,
    178                                 data_source,
    179                                 MHD_HTTP_METHOD_GET,
    180                                 0 == strcmp ("admin",
    181                                              instance_id),
    182                                 &is_public);
    183     if (GNUNET_OK != ret)
    184     {
    185       GNUNET_free (instance_id);
    186       GNUNET_free (data_source);
    187       return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
    188     }
    189     GNUNET_break (NULL != hc->rh);
    190   }
    191   GNUNET_free (instance_id);
    192   GNUNET_free (data_source);
    193   /* MHD will call the main handler again, which will now
    194      dispatch into the _new_ handler callback we just installed! */
    195   return MHD_YES;
    196 }