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 }