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 }