Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2026 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU Lesser General Public License as published by the Free Software
7 : Foundation; either version 2.1, 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 Lesser General Public License for more details.
12 :
13 : You should have received a copy of the GNU Lesser General Public License along with
14 : TALER; see the file COPYING.LGPL. If not, see
15 : <http://www.gnu.org/licenses/>
16 : */
17 : /**
18 : * @file merchant_api_get-management-instances-new.c
19 : * @brief Implementation of the GET /management/instances request
20 : * @author Christian Grothoff
21 : */
22 : #include "taler/platform.h"
23 : #include <curl/curl.h>
24 : #include <jansson.h>
25 : #include <microhttpd.h> /* just for HTTP status codes */
26 : #include <gnunet/gnunet_util_lib.h>
27 : #include <gnunet/gnunet_curl_lib.h>
28 : #include <taler/merchant/get-management-instances.h>
29 : #include "merchant_api_curl_defaults.h"
30 : #include <taler/taler_json_lib.h>
31 :
32 : /**
33 : * Maximum number of instances permitted.
34 : */
35 : #define MAX_INSTANCES 1024
36 :
37 :
38 : /**
39 : * Handle for a GET /management/instances operation.
40 : */
41 : struct TALER_MERCHANT_GetManagementInstancesHandle
42 : {
43 : /**
44 : * Base URL of the merchant backend.
45 : */
46 : char *base_url;
47 :
48 : /**
49 : * The full URL for this request.
50 : */
51 : char *url;
52 :
53 : /**
54 : * Handle for the request.
55 : */
56 : struct GNUNET_CURL_Job *job;
57 :
58 : /**
59 : * Function to call with the result.
60 : */
61 : TALER_MERCHANT_GetManagementInstancesCallback cb;
62 :
63 : /**
64 : * Closure for @a cb.
65 : */
66 : TALER_MERCHANT_GET_MANAGEMENT_INSTANCES_RESULT_CLOSURE *cb_cls;
67 :
68 : /**
69 : * Reference to the execution context.
70 : */
71 : struct GNUNET_CURL_Context *ctx;
72 : };
73 :
74 :
75 : /**
76 : * Parse instance information from @a ia.
77 : *
78 : * @param ia JSON array (or NULL!) with instance data
79 : * @param[in] igr partially filled response
80 : * @param gimh operation handle
81 : * @return #GNUNET_OK on success
82 : */
83 : static enum GNUNET_GenericReturnValue
84 0 : parse_instances (const json_t *ia,
85 : struct TALER_MERCHANT_GetManagementInstancesResponse *igr,
86 : struct TALER_MERCHANT_GetManagementInstancesHandle *gimh)
87 : {
88 0 : unsigned int iis_len = (unsigned int) json_array_size (ia);
89 :
90 0 : if ( (json_array_size (ia) != (size_t) iis_len) ||
91 : (iis_len > MAX_INSTANCES) )
92 : {
93 0 : GNUNET_break (0);
94 0 : return GNUNET_SYSERR;
95 : }
96 0 : {
97 0 : struct TALER_MERCHANT_GetManagementInstancesInstanceInfo iis[
98 0 : GNUNET_NZL (iis_len)];
99 : size_t index;
100 : json_t *value;
101 :
102 0 : memset (iis,
103 : 0,
104 : sizeof (iis));
105 0 : json_array_foreach (ia, index, value) {
106 0 : struct TALER_MERCHANT_GetManagementInstancesInstanceInfo *ii =
107 : &iis[index];
108 : struct GNUNET_JSON_Specification spec[] = {
109 0 : GNUNET_JSON_spec_string ("name",
110 : &ii->name),
111 0 : GNUNET_JSON_spec_string ("id",
112 : &ii->id),
113 0 : GNUNET_JSON_spec_fixed_auto ("merchant_pub",
114 : &ii->merchant_pub),
115 0 : GNUNET_JSON_spec_array_const ("payment_targets",
116 : &ii->payment_targets),
117 0 : GNUNET_JSON_spec_mark_optional (
118 : GNUNET_JSON_spec_string ("website",
119 : &ii->website),
120 : NULL),
121 0 : GNUNET_JSON_spec_mark_optional (
122 : GNUNET_JSON_spec_string ("logo",
123 : &ii->logo),
124 : NULL),
125 0 : GNUNET_JSON_spec_bool ("deleted",
126 : &ii->deleted),
127 0 : GNUNET_JSON_spec_end ()
128 : };
129 :
130 0 : if (GNUNET_OK !=
131 0 : GNUNET_JSON_parse (value,
132 : spec,
133 : NULL, NULL))
134 : {
135 0 : GNUNET_break_op (0);
136 0 : return GNUNET_SYSERR;
137 : }
138 0 : for (size_t i = 0; i<json_array_size (ii->payment_targets); i++)
139 : {
140 0 : if (! json_is_string (json_array_get (ii->payment_targets,
141 : i)))
142 : {
143 0 : GNUNET_break_op (0);
144 0 : return GNUNET_SYSERR;
145 : }
146 : }
147 : }
148 0 : igr->details.ok.iis_length = iis_len;
149 0 : igr->details.ok.iis = iis;
150 0 : gimh->cb (gimh->cb_cls,
151 : igr);
152 0 : gimh->cb = NULL;
153 : }
154 0 : return GNUNET_OK;
155 : }
156 :
157 :
158 : /**
159 : * Function called when we're done processing the
160 : * HTTP GET /management/instances request.
161 : *
162 : * @param cls the `struct TALER_MERCHANT_GetManagementInstancesHandle`
163 : * @param response_code HTTP response code, 0 on error
164 : * @param response response body, NULL if not in JSON
165 : */
166 : static void
167 0 : handle_get_instances_finished (void *cls,
168 : long response_code,
169 : const void *response)
170 : {
171 0 : struct TALER_MERCHANT_GetManagementInstancesHandle *gimh = cls;
172 0 : const json_t *json = response;
173 0 : struct TALER_MERCHANT_GetManagementInstancesResponse igr = {
174 0 : .hr.http_status = (unsigned int) response_code,
175 : .hr.reply = json
176 : };
177 :
178 0 : gimh->job = NULL;
179 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
180 : "Got /management/instances response with status code %u\n",
181 : (unsigned int) response_code);
182 0 : switch (response_code)
183 : {
184 0 : case MHD_HTTP_OK:
185 : {
186 : const json_t *instances;
187 : struct GNUNET_JSON_Specification spec[] = {
188 0 : GNUNET_JSON_spec_array_const ("instances",
189 : &instances),
190 0 : GNUNET_JSON_spec_end ()
191 : };
192 :
193 0 : if (GNUNET_OK !=
194 0 : GNUNET_JSON_parse (json,
195 : spec,
196 : NULL, NULL))
197 : {
198 0 : igr.hr.http_status = 0;
199 0 : igr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
200 0 : break;
201 : }
202 0 : if (GNUNET_OK ==
203 0 : parse_instances (instances,
204 : &igr,
205 : gimh))
206 : {
207 0 : TALER_MERCHANT_get_management_instances_cancel (gimh);
208 0 : return;
209 : }
210 0 : igr.hr.http_status = 0;
211 0 : igr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
212 0 : break;
213 : }
214 0 : case MHD_HTTP_UNAUTHORIZED:
215 0 : igr.hr.ec = TALER_JSON_get_error_code (json);
216 0 : igr.hr.hint = TALER_JSON_get_error_hint (json);
217 0 : break;
218 0 : default:
219 0 : igr.hr.ec = TALER_JSON_get_error_code (json);
220 0 : igr.hr.hint = TALER_JSON_get_error_hint (json);
221 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
222 : "Unexpected response code %u/%d\n",
223 : (unsigned int) response_code,
224 : (int) igr.hr.ec);
225 0 : break;
226 : }
227 0 : gimh->cb (gimh->cb_cls,
228 : &igr);
229 0 : TALER_MERCHANT_get_management_instances_cancel (gimh);
230 : }
231 :
232 :
233 : struct TALER_MERCHANT_GetManagementInstancesHandle *
234 0 : TALER_MERCHANT_get_management_instances_create (
235 : struct GNUNET_CURL_Context *ctx,
236 : const char *url)
237 : {
238 : struct TALER_MERCHANT_GetManagementInstancesHandle *gimh;
239 :
240 0 : gimh = GNUNET_new (struct TALER_MERCHANT_GetManagementInstancesHandle);
241 0 : gimh->ctx = ctx;
242 0 : gimh->base_url = GNUNET_strdup (url);
243 0 : return gimh;
244 : }
245 :
246 :
247 : enum TALER_ErrorCode
248 0 : TALER_MERCHANT_get_management_instances_start (
249 : struct TALER_MERCHANT_GetManagementInstancesHandle *gimh,
250 : TALER_MERCHANT_GetManagementInstancesCallback cb,
251 : TALER_MERCHANT_GET_MANAGEMENT_INSTANCES_RESULT_CLOSURE *cb_cls)
252 : {
253 : CURL *eh;
254 :
255 0 : gimh->cb = cb;
256 0 : gimh->cb_cls = cb_cls;
257 0 : gimh->url = TALER_url_join (gimh->base_url,
258 : "management/instances",
259 : NULL);
260 0 : if (NULL == gimh->url)
261 0 : return TALER_EC_GENERIC_CONFIGURATION_INVALID;
262 0 : eh = TALER_MERCHANT_curl_easy_get_ (gimh->url);
263 0 : if (NULL == eh)
264 0 : return TALER_EC_GENERIC_CONFIGURATION_INVALID;
265 0 : gimh->job = GNUNET_CURL_job_add (gimh->ctx,
266 : eh,
267 : &handle_get_instances_finished,
268 : gimh);
269 0 : if (NULL == gimh->job)
270 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
271 0 : return TALER_EC_NONE;
272 : }
273 :
274 :
275 : void
276 0 : TALER_MERCHANT_get_management_instances_cancel (
277 : struct TALER_MERCHANT_GetManagementInstancesHandle *gimh)
278 : {
279 0 : if (NULL != gimh->job)
280 : {
281 0 : GNUNET_CURL_job_cancel (gimh->job);
282 0 : gimh->job = NULL;
283 : }
284 0 : GNUNET_free (gimh->url);
285 0 : GNUNET_free (gimh->base_url);
286 0 : GNUNET_free (gimh);
287 0 : }
288 :
289 :
290 : /* end of merchant_api_get-management-instances-new.c */
|