Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2014-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 General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file taler-merchant-httpd_dispatcher.c
18 : * @brief map requested URL and method to the respective request handler
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include "taler-merchant-httpd_config.h"
23 : #include "taler-merchant-httpd_dispatcher.h"
24 : #include "taler-merchant-httpd_exchanges.h"
25 : #include "taler-merchant-httpd_get-orders-ID.h"
26 : #include "taler-merchant-httpd_get-products-image.h"
27 : #include "taler-merchant-httpd_get-templates-ID.h"
28 : #include "taler-merchant-httpd_mhd.h"
29 : #include "taler-merchant-httpd_private-delete-account-ID.h"
30 : #include "taler-merchant-httpd_private-delete-categories-ID.h"
31 : #include "taler-merchant-httpd_private-delete-units-ID.h"
32 : #include "taler-merchant-httpd_private-delete-instances-ID.h"
33 : #include "taler-merchant-httpd_private-delete-instances-ID-token.h"
34 : #include "taler-merchant-httpd_private-delete-products-ID.h"
35 : #include "taler-merchant-httpd_private-delete-orders-ID.h"
36 : #include "taler-merchant-httpd_private-delete-otp-devices-ID.h"
37 : #include "taler-merchant-httpd_private-delete-templates-ID.h"
38 : #include "taler-merchant-httpd_private-delete-token-families-SLUG.h"
39 : #include "taler-merchant-httpd_private-delete-transfers-ID.h"
40 : #include "taler-merchant-httpd_private-delete-webhooks-ID.h"
41 : #include "taler-merchant-httpd_private-get-accounts.h"
42 : #include "taler-merchant-httpd_private-get-accounts-ID.h"
43 : #include "taler-merchant-httpd_private-get-categories.h"
44 : #include "taler-merchant-httpd_private-get-categories-ID.h"
45 : #include "taler-merchant-httpd_private-get-units.h"
46 : #include "taler-merchant-httpd_private-get-units-ID.h"
47 : #include "taler-merchant-httpd_private-get-incoming.h"
48 : #include "taler-merchant-httpd_private-get-instances.h"
49 : #include "taler-merchant-httpd_private-get-instances-ID.h"
50 : #include "taler-merchant-httpd_private-get-instances-ID-kyc.h"
51 : #include "taler-merchant-httpd_private-get-instances-ID-tokens.h"
52 : #include "taler-merchant-httpd_private-get-pos.h"
53 : #include "taler-merchant-httpd_private-get-products.h"
54 : #include "taler-merchant-httpd_private-get-products-ID.h"
55 : #include "taler-merchant-httpd_private-get-orders.h"
56 : #include "taler-merchant-httpd_private-get-orders-ID.h"
57 : #include "taler-merchant-httpd_private-get-otp-devices.h"
58 : #include "taler-merchant-httpd_private-get-otp-devices-ID.h"
59 : #include "taler-merchant-httpd_private-get-statistics-amount-SLUG.h"
60 : #include "taler-merchant-httpd_private-get-statistics-counter-SLUG.h"
61 : #include "taler-merchant-httpd_private-get-statistics-report-transactions.h"
62 : #include "taler-merchant-httpd_private-get-templates.h"
63 : #include "taler-merchant-httpd_private-get-templates-ID.h"
64 : #include "taler-merchant-httpd_private-get-token-families.h"
65 : #include "taler-merchant-httpd_private-get-token-families-SLUG.h"
66 : #include "taler-merchant-httpd_private-get-transfers.h"
67 : #include "taler-merchant-httpd_private-get-webhooks.h"
68 : #include "taler-merchant-httpd_private-get-webhooks-ID.h"
69 : #include "taler-merchant-httpd_private-patch-accounts-ID.h"
70 : #include "taler-merchant-httpd_private-patch-categories-ID.h"
71 : #include "taler-merchant-httpd_private-patch-units-ID.h"
72 : #include "taler-merchant-httpd_private-patch-instances-ID.h"
73 : #include "taler-merchant-httpd_private-patch-orders-ID-forget.h"
74 : #include "taler-merchant-httpd_private-patch-otp-devices-ID.h"
75 : #include "taler-merchant-httpd_private-patch-products-ID.h"
76 : #include "taler-merchant-httpd_private-patch-templates-ID.h"
77 : #include "taler-merchant-httpd_private-patch-token-families-SLUG.h"
78 : #include "taler-merchant-httpd_private-patch-webhooks-ID.h"
79 : #include "taler-merchant-httpd_private-post-account.h"
80 : #include "taler-merchant-httpd_private-post-categories.h"
81 : #include "taler-merchant-httpd_private-post-units.h"
82 : #include "taler-merchant-httpd_private-post-instances.h"
83 : #include "taler-merchant-httpd_private-post-instances-ID-auth.h"
84 : #include "taler-merchant-httpd_private-post-instances-ID-token.h"
85 : #include "taler-merchant-httpd_private-post-otp-devices.h"
86 : #include "taler-merchant-httpd_private-post-orders.h"
87 : #include "taler-merchant-httpd_private-post-orders-ID-refund.h"
88 : #include "taler-merchant-httpd_private-post-products.h"
89 : #include "taler-merchant-httpd_private-post-products-ID-lock.h"
90 : #include "taler-merchant-httpd_private-post-templates.h"
91 : #include "taler-merchant-httpd_private-post-token-families.h"
92 : #include "taler-merchant-httpd_private-post-transfers.h"
93 : #include "taler-merchant-httpd_private-post-webhooks.h"
94 : #include "taler-merchant-httpd_post-challenge-ID.h"
95 : #include "taler-merchant-httpd_post-challenge-ID-confirm.h"
96 : #include "taler-merchant-httpd_post-orders-ID-abort.h"
97 : #include "taler-merchant-httpd_post-orders-ID-claim.h"
98 : #include "taler-merchant-httpd_post-orders-ID-paid.h"
99 : #include "taler-merchant-httpd_post-orders-ID-pay.h"
100 : #include "taler-merchant-httpd_post-using-templates.h"
101 : #include "taler-merchant-httpd_post-orders-ID-refund.h"
102 : #include "taler-merchant-httpd_spa.h"
103 : #include "taler-merchant-httpd_statics.h"
104 : #include "taler-merchant-httpd_terms.h"
105 : #include "taler-merchant-httpd_post-reports-ID.h"
106 : #include "taler-merchant-httpd_private-delete-report-ID.h"
107 : #include "taler-merchant-httpd_private-get-report-ID.h"
108 : #include "taler-merchant-httpd_private-get-reports.h"
109 : #include "taler-merchant-httpd_private-patch-report-ID.h"
110 : #include "taler-merchant-httpd_private-post-reports.h"
111 : #include "taler-merchant-httpd_private-delete-pot-ID.h"
112 : #include "taler-merchant-httpd_private-get-pot-ID.h"
113 : #include "taler-merchant-httpd_private-get-pots.h"
114 : #include "taler-merchant-httpd_private-patch-pot-ID.h"
115 : #include "taler-merchant-httpd_private-post-pots.h"
116 : #include "taler-merchant-httpd_private-get-groups.h"
117 : #include "taler-merchant-httpd_private-post-groups.h"
118 : #include "taler-merchant-httpd_private-patch-group-ID.h"
119 : #include "taler-merchant-httpd_private-delete-group-ID.h"
120 :
121 : #ifdef HAVE_DONAU_DONAU_SERVICE_H
122 : #include "taler-merchant-httpd_private-get-donau-instances.h"
123 : #include "taler-merchant-httpd_private-post-donau-instance.h"
124 : #include "taler-merchant-httpd_private-delete-donau-instance-ID.h"
125 : #endif
126 :
127 :
128 : /**
129 : * Handle a OPTIONS "*" request.
130 : *
131 : * @param rh context of the handler
132 : * @param connection the MHD connection to handle
133 : * @param[in,out] hc context with further information about the request
134 : * @return MHD result code
135 : */
136 : static MHD_RESULT
137 0 : handle_server_options (const struct TMH_RequestHandler *rh,
138 : struct MHD_Connection *connection,
139 : struct TMH_HandlerContext *hc)
140 : {
141 : (void) rh;
142 : (void) hc;
143 0 : return TALER_MHD_reply_cors_preflight (connection);
144 : }
145 :
146 :
147 : /**
148 : * Generates the response for "/", redirecting the
149 : * client to the "/webui/" from where we serve the SPA.
150 : *
151 : * @param rh request handler
152 : * @param connection MHD connection
153 : * @param hc handler context
154 : * @return MHD result code
155 : */
156 : static MHD_RESULT
157 1 : spa_redirect (const struct TMH_RequestHandler *rh,
158 : struct MHD_Connection *connection,
159 : struct TMH_HandlerContext *hc)
160 : {
161 1 : const char *text = "Redirecting to /webui/";
162 : struct MHD_Response *response;
163 : char *dst;
164 :
165 1 : response = MHD_create_response_from_buffer (strlen (text),
166 : (void *) text,
167 : MHD_RESPMEM_PERSISTENT);
168 1 : if (NULL == response)
169 : {
170 0 : GNUNET_break (0);
171 0 : return MHD_NO;
172 : }
173 1 : TALER_MHD_add_global_headers (response,
174 : true);
175 1 : GNUNET_break (MHD_YES ==
176 : MHD_add_response_header (response,
177 : MHD_HTTP_HEADER_CONTENT_TYPE,
178 : "text/plain"));
179 1 : if ( (NULL == hc->instance) ||
180 1 : (0 == strcmp ("admin",
181 1 : hc->instance->settings.id)) )
182 1 : dst = GNUNET_strdup ("/webui/");
183 : else
184 0 : GNUNET_asprintf (&dst,
185 : "/instances/%s/webui/",
186 0 : hc->instance->settings.id);
187 1 : if (MHD_NO ==
188 1 : MHD_add_response_header (response,
189 : MHD_HTTP_HEADER_LOCATION,
190 : dst))
191 : {
192 0 : GNUNET_break (0);
193 0 : MHD_destroy_response (response);
194 0 : GNUNET_free (dst);
195 0 : return MHD_NO;
196 : }
197 1 : GNUNET_free (dst);
198 :
199 : {
200 : MHD_RESULT ret;
201 :
202 1 : ret = MHD_queue_response (connection,
203 : MHD_HTTP_FOUND,
204 : response);
205 1 : MHD_destroy_response (response);
206 1 : return ret;
207 : }
208 : }
209 :
210 :
211 : /**
212 : * Determine the group of request handlers to call for the
213 : * given URL. Removes a possible prefix from @a purl by advancing
214 : * the pointer.
215 : *
216 : * @param[in,out] urlp pointer to the URL to analyze and update
217 : * @param[out] is_public set to true if these are public handlers
218 : * @return handler group to consider for the given URL
219 : */
220 : static const struct TMH_RequestHandler *
221 749 : determine_handler_group (const char **urlp,
222 : bool *is_public)
223 : {
224 : static struct TMH_RequestHandler management_handlers[] = {
225 : /* GET /instances */
226 : {
227 : .url_prefix = "/instances",
228 : .method = MHD_HTTP_METHOD_GET,
229 : .permission = "instances-write",
230 : .skip_instance = true,
231 : .default_only = true,
232 : .handler = &TMH_private_get_instances
233 : },
234 : /* POST /instances */
235 : {
236 : .url_prefix = "/instances",
237 : .method = MHD_HTTP_METHOD_POST,
238 : .permission = "instances-write",
239 : .skip_instance = true,
240 : .default_only = true,
241 : .handler = &TMH_private_post_instances,
242 : /* allow instance data of up to 8 MB, that should be plenty;
243 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
244 : would require further changes to the allocation logic
245 : in the code... */
246 : .max_upload = 1024 * 1024 * 8
247 : },
248 : /* GET /instances/$ID/ */
249 : {
250 : .url_prefix = "/instances/",
251 : .method = MHD_HTTP_METHOD_GET,
252 : .permission = "instances-write",
253 : .skip_instance = true,
254 : .default_only = true,
255 : .have_id_segment = true,
256 : .handler = &TMH_private_get_instances_default_ID
257 : },
258 : /* DELETE /instances/$ID */
259 : {
260 : .url_prefix = "/instances/",
261 : .method = MHD_HTTP_METHOD_DELETE,
262 : .permission = "instances-write",
263 : .skip_instance = true,
264 : .default_only = true,
265 : .have_id_segment = true,
266 : .handler = &TMH_private_delete_instances_default_ID
267 : },
268 : /* PATCH /instances/$ID */
269 : {
270 : .url_prefix = "/instances/",
271 : .method = MHD_HTTP_METHOD_PATCH,
272 : .permission = "instances-write",
273 : .skip_instance = true,
274 : .default_only = true,
275 : .have_id_segment = true,
276 : .handler = &TMH_private_patch_instances_default_ID,
277 : /* allow instance data of up to 8 MB, that should be plenty;
278 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
279 : would require further changes to the allocation logic
280 : in the code... */
281 : .max_upload = 1024 * 1024 * 8
282 : },
283 : /* POST /auth: */
284 : {
285 : .url_prefix = "/instances/",
286 : .url_suffix = "auth",
287 : .method = MHD_HTTP_METHOD_POST,
288 : .permission = "instances-auth-write",
289 : .skip_instance = true,
290 : .default_only = true,
291 : .have_id_segment = true,
292 : .handler = &TMH_private_post_instances_default_ID_auth,
293 : /* Body should be pretty small. */
294 : .max_upload = 1024 * 1024
295 : },
296 : /* GET /kyc: */
297 : {
298 : .url_prefix = "/instances/",
299 : .url_suffix = "kyc",
300 : .method = MHD_HTTP_METHOD_GET,
301 : .permission = "instances-kyc-read",
302 : .skip_instance = true,
303 : .default_only = true,
304 : .have_id_segment = true,
305 : .handler = &TMH_private_get_instances_default_ID_kyc,
306 : },
307 : {
308 : .url_prefix = NULL
309 : }
310 : };
311 :
312 : static struct TMH_RequestHandler private_handlers[] = {
313 : /* GET /instances/$ID/: */
314 : {
315 : .url_prefix = "/",
316 : .method = MHD_HTTP_METHOD_GET,
317 : .permission = "instances-read",
318 : .handler = &TMH_private_get_instances_ID
319 : },
320 : /* DELETE /instances/$ID/: */
321 : {
322 : .url_prefix = "/",
323 : .method = MHD_HTTP_METHOD_DELETE,
324 : .permission = "instances-write",
325 : .allow_deleted_instance = true,
326 : .handler = &TMH_private_delete_instances_ID
327 : },
328 : /* PATCH /instances/$ID/: */
329 : {
330 : .url_prefix = "/",
331 : .method = MHD_HTTP_METHOD_PATCH,
332 : .handler = &TMH_private_patch_instances_ID,
333 : .permission = "instances-write",
334 : .allow_deleted_instance = true,
335 : /* allow instance data of up to 8 MB, that should be plenty;
336 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
337 : would require further changes to the allocation logic
338 : in the code... */
339 : .max_upload = 1024 * 1024 * 8
340 : },
341 : /* POST /auth: */
342 : {
343 : .url_prefix = "/auth",
344 : .method = MHD_HTTP_METHOD_POST,
345 : .handler = &TMH_private_post_instances_ID_auth,
346 : .permission = "auth-write",
347 : /* Body should be pretty small. */
348 : .max_upload = 1024 * 1024,
349 : },
350 : /* GET /kyc: */
351 : {
352 : .url_prefix = "/kyc",
353 : .method = MHD_HTTP_METHOD_GET,
354 : .permission = "kyc-read",
355 : .handler = &TMH_private_get_instances_ID_kyc,
356 : },
357 : /* GET /pos: */
358 : {
359 : .url_prefix = "/pos",
360 : .method = MHD_HTTP_METHOD_GET,
361 : .permission = "pos-read",
362 : .handler = &TMH_private_get_pos
363 : },
364 : /* GET /categories: */
365 : {
366 : .url_prefix = "/categories",
367 : .method = MHD_HTTP_METHOD_GET,
368 : .permission = "categories-read",
369 : .handler = &TMH_private_get_categories
370 : },
371 : /* POST /categories: */
372 : {
373 : .url_prefix = "/categories",
374 : .method = MHD_HTTP_METHOD_POST,
375 : .permission = "categories-write",
376 : .handler = &TMH_private_post_categories,
377 : /* allow category data of up to 8 kb, that should be plenty */
378 : .max_upload = 1024 * 8
379 : },
380 : /* GET /categories/$ID: */
381 : {
382 : .url_prefix = "/categories/",
383 : .method = MHD_HTTP_METHOD_GET,
384 : .permission = "categories-read",
385 : .have_id_segment = true,
386 : .allow_deleted_instance = true,
387 : .handler = &TMH_private_get_categories_ID
388 : },
389 : /* DELETE /categories/$ID: */
390 : {
391 : .url_prefix = "/categories/",
392 : .method = MHD_HTTP_METHOD_DELETE,
393 : .permission = "categories-write",
394 : .have_id_segment = true,
395 : .allow_deleted_instance = true,
396 : .handler = &TMH_private_delete_categories_ID
397 : },
398 : /* PATCH /categories/$ID/: */
399 : {
400 : .url_prefix = "/categories/",
401 : .method = MHD_HTTP_METHOD_PATCH,
402 : .permission = "categories-write",
403 : .have_id_segment = true,
404 : .allow_deleted_instance = true,
405 : .handler = &TMH_private_patch_categories_ID,
406 : /* allow category data of up to 8 kb, that should be plenty */
407 : .max_upload = 1024 * 8
408 : },
409 : /* GET /units: */
410 : {
411 : .url_prefix = "/units",
412 : .method = MHD_HTTP_METHOD_GET,
413 : .handler = &TMH_private_get_units
414 : },
415 : /* POST /units: */
416 : {
417 : .url_prefix = "/units",
418 : .method = MHD_HTTP_METHOD_POST,
419 : .permission = "units-write",
420 : .handler = &TMH_private_post_units,
421 : .max_upload = 1024 * 8
422 : },
423 : /* GET /units/$UNIT: */
424 : {
425 : .url_prefix = "/units/",
426 : .method = MHD_HTTP_METHOD_GET,
427 : .have_id_segment = true,
428 : .allow_deleted_instance = true,
429 : .handler = &TMH_private_get_units_ID
430 : },
431 : /* DELETE /units/$UNIT: */
432 : {
433 : .url_prefix = "/units/",
434 : .method = MHD_HTTP_METHOD_DELETE,
435 : .permission = "units-write",
436 : .have_id_segment = true,
437 : .allow_deleted_instance = true,
438 : .handler = &TMH_private_delete_units_ID
439 : },
440 : /* PATCH /units/$UNIT: */
441 : {
442 : .url_prefix = "/units/",
443 : .method = MHD_HTTP_METHOD_PATCH,
444 : .permission = "units-write",
445 : .have_id_segment = true,
446 : .allow_deleted_instance = true,
447 : .handler = &TMH_private_patch_units_ID,
448 : .max_upload = 1024 * 8
449 : },
450 : /* GET /products: */
451 : {
452 : .url_prefix = "/products",
453 : .permission = "products-read",
454 : .method = MHD_HTTP_METHOD_GET,
455 : .handler = &TMH_private_get_products
456 : },
457 : /* POST /products: */
458 : {
459 : .url_prefix = "/products",
460 : .method = MHD_HTTP_METHOD_POST,
461 : .permission = "products-write",
462 : .handler = &TMH_private_post_products,
463 : /* allow product data of up to 8 MB, that should be plenty;
464 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
465 : would require further changes to the allocation logic
466 : in the code... */
467 : .max_upload = 1024 * 1024 * 8
468 : },
469 : /* GET /products/$ID: */
470 : {
471 : .url_prefix = "/products/",
472 : .method = MHD_HTTP_METHOD_GET,
473 : .have_id_segment = true,
474 : .permission = "products-read",
475 : .allow_deleted_instance = true,
476 : .handler = &TMH_private_get_products_ID
477 : },
478 : /* DELETE /products/$ID/: */
479 : {
480 : .url_prefix = "/products/",
481 : .method = MHD_HTTP_METHOD_DELETE,
482 : .have_id_segment = true,
483 : .permission = "products-write",
484 : .allow_deleted_instance = true,
485 : .handler = &TMH_private_delete_products_ID
486 : },
487 : /* PATCH /products/$ID/: */
488 : {
489 : .url_prefix = "/products/",
490 : .method = MHD_HTTP_METHOD_PATCH,
491 : .have_id_segment = true,
492 : .allow_deleted_instance = true,
493 : .permission = "products-write",
494 : .handler = &TMH_private_patch_products_ID,
495 : /* allow product data of up to 8 MB, that should be plenty;
496 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
497 : would require further changes to the allocation logic
498 : in the code... */
499 : .max_upload = 1024 * 1024 * 8
500 : },
501 : /* POST /products/$ID/lock: */
502 : {
503 : .url_prefix = "/products/",
504 : .url_suffix = "lock",
505 : .method = MHD_HTTP_METHOD_POST,
506 : .have_id_segment = true,
507 : .permission = "products-lock",
508 : .handler = &TMH_private_post_products_ID_lock,
509 : /* the body should be pretty small, allow 1 MB of upload
510 : to set a conservative bound for sane wallets */
511 : .max_upload = 1024 * 1024
512 : },
513 : /* POST /orders: */
514 : {
515 : .url_prefix = "/orders",
516 : .method = MHD_HTTP_METHOD_POST,
517 : .permission = "orders-write",
518 : .handler = &TMH_private_post_orders,
519 : /* allow contracts of up to 8 MB, that should be plenty;
520 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
521 : would require further changes to the allocation logic
522 : in the code... */
523 : .max_upload = 1024 * 1024 * 8
524 : },
525 : /* GET /orders/$ID: */
526 : {
527 : .url_prefix = "/orders/",
528 : .method = MHD_HTTP_METHOD_GET,
529 : .permission = "orders-read",
530 : .have_id_segment = true,
531 : .allow_deleted_instance = true,
532 : .handler = &TMH_private_get_orders_ID
533 : },
534 : /* GET /orders: */
535 : {
536 : .url_prefix = "/orders",
537 : .method = MHD_HTTP_METHOD_GET,
538 : .permission = "orders-read",
539 : .allow_deleted_instance = true,
540 : .handler = &TMH_private_get_orders
541 : },
542 : /* POST /orders/$ID/refund: */
543 : {
544 : .url_prefix = "/orders/",
545 : .url_suffix = "refund",
546 : .method = MHD_HTTP_METHOD_POST,
547 : .have_id_segment = true,
548 : .permission = "orders-refund",
549 : .handler = &TMH_private_post_orders_ID_refund,
550 : /* the body should be pretty small, allow 1 MB of upload
551 : to set a conservative bound for sane wallets */
552 : .max_upload = 1024 * 1024
553 : },
554 : /* PATCH /orders/$ID/forget: */
555 : {
556 : .url_prefix = "/orders/",
557 : .url_suffix = "forget",
558 : .method = MHD_HTTP_METHOD_PATCH,
559 : .permission = "orders-write",
560 : .have_id_segment = true,
561 : .allow_deleted_instance = true,
562 : .handler = &TMH_private_patch_orders_ID_forget,
563 : /* the body should be pretty small, allow 1 MB of upload
564 : to set a conservative bound for sane wallets */
565 : .max_upload = 1024 * 1024
566 : },
567 : /* DELETE /orders/$ID: */
568 : {
569 : .url_prefix = "/orders/",
570 : .method = MHD_HTTP_METHOD_DELETE,
571 : .permission = "orders-write",
572 : .have_id_segment = true,
573 : .allow_deleted_instance = true,
574 : .handler = &TMH_private_delete_orders_ID
575 : },
576 : /* POST /transfers: */
577 : {
578 : .url_prefix = "/transfers",
579 : .method = MHD_HTTP_METHOD_POST,
580 : .allow_deleted_instance = true,
581 : .handler = &TMH_private_post_transfers,
582 : .permission = "transfers-write",
583 : /* the body should be pretty small, allow 1 MB of upload
584 : to set a conservative bound for sane wallets */
585 : .max_upload = 1024 * 1024
586 : },
587 : /* DELETE /transfers/$ID: */
588 : {
589 : .url_prefix = "/transfers/",
590 : .method = MHD_HTTP_METHOD_DELETE,
591 : .permission = "transfers-write",
592 : .allow_deleted_instance = true,
593 : .handler = &TMH_private_delete_transfers_ID,
594 : .have_id_segment = true,
595 : /* the body should be pretty small, allow 1 MB of upload
596 : to set a conservative bound for sane wallets */
597 : .max_upload = 1024 * 1024
598 : },
599 : /* GET /transfers: */
600 : {
601 : .url_prefix = "/transfers",
602 : .permission = "transfers-read",
603 : .method = MHD_HTTP_METHOD_GET,
604 : .allow_deleted_instance = true,
605 : .handler = &TMH_private_get_transfers
606 : },
607 : /* GET /incoming: */
608 : {
609 : .url_prefix = "/incoming",
610 : .permission = "transfers-read",
611 : .method = MHD_HTTP_METHOD_GET,
612 : .allow_deleted_instance = true,
613 : .handler = &TMH_private_get_incoming
614 : },
615 : /* POST /otp-devices: */
616 : {
617 : .url_prefix = "/otp-devices",
618 : .permission = "otp-devices-write",
619 : .method = MHD_HTTP_METHOD_POST,
620 : .handler = &TMH_private_post_otp_devices
621 : },
622 : /* GET /otp-devices: */
623 : {
624 : .url_prefix = "/otp-devices",
625 : .permission = "opt-devices-read",
626 : .method = MHD_HTTP_METHOD_GET,
627 : .handler = &TMH_private_get_otp_devices
628 : },
629 : /* GET /otp-devices/$ID/: */
630 : {
631 : .url_prefix = "/otp-devices/",
632 : .method = MHD_HTTP_METHOD_GET,
633 : .permission = "otp-devices-read",
634 : .have_id_segment = true,
635 : .handler = &TMH_private_get_otp_devices_ID
636 : },
637 : /* DELETE /otp-devices/$ID/: */
638 : {
639 : .url_prefix = "/otp-devices/",
640 : .method = MHD_HTTP_METHOD_DELETE,
641 : .permission = "otp-devices-write",
642 : .have_id_segment = true,
643 : .handler = &TMH_private_delete_otp_devices_ID
644 : },
645 : /* PATCH /otp-devices/$ID/: */
646 : {
647 : .url_prefix = "/otp-devices/",
648 : .method = MHD_HTTP_METHOD_PATCH,
649 : .permission = "otp-devices-write",
650 : .have_id_segment = true,
651 : .handler = &TMH_private_patch_otp_devices_ID
652 : },
653 : /* POST /templates: */
654 : {
655 : .url_prefix = "/templates",
656 : .method = MHD_HTTP_METHOD_POST,
657 : .permission = "templates-write",
658 : .handler = &TMH_private_post_templates,
659 : /* allow template data of up to 8 MB, that should be plenty;
660 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
661 : would require further changes to the allocation logic
662 : in the code... */
663 : .max_upload = 1024 * 1024 * 8
664 : },
665 : /* GET /templates: */
666 : {
667 : .url_prefix = "/templates",
668 : .permission = "templates-read",
669 : .method = MHD_HTTP_METHOD_GET,
670 : .handler = &TMH_private_get_templates
671 : },
672 : /* GET /templates/$ID/: */
673 : {
674 : .url_prefix = "/templates/",
675 : .method = MHD_HTTP_METHOD_GET,
676 : .permission = "templates-read",
677 : .have_id_segment = true,
678 : .allow_deleted_instance = true,
679 : .handler = &TMH_private_get_templates_ID
680 : },
681 : /* DELETE /templates/$ID/: */
682 : {
683 : .url_prefix = "/templates/",
684 : .method = MHD_HTTP_METHOD_DELETE,
685 : .permission = "templates-write",
686 : .have_id_segment = true,
687 : .allow_deleted_instance = true,
688 : .handler = &TMH_private_delete_templates_ID
689 : },
690 : /* PATCH /templates/$ID/: */
691 : {
692 : .url_prefix = "/templates/",
693 : .method = MHD_HTTP_METHOD_PATCH,
694 : .permission = "templates-write",
695 : .have_id_segment = true,
696 : .allow_deleted_instance = true,
697 : .handler = &TMH_private_patch_templates_ID,
698 : /* allow template data of up to 8 MB, that should be plenty;
699 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
700 : would require further changes to the allocation logic
701 : in the code... */
702 : .max_upload = 1024 * 1024 * 8
703 : },
704 : /* GET /webhooks: */
705 : {
706 : .url_prefix = "/webhooks",
707 : .permission = "webhooks-read",
708 : .method = MHD_HTTP_METHOD_GET,
709 : .handler = &TMH_private_get_webhooks
710 : },
711 : /* POST /webhooks: */
712 : {
713 : .url_prefix = "/webhooks",
714 : .method = MHD_HTTP_METHOD_POST,
715 : .permission = "webhooks-write",
716 : .handler = &TMH_private_post_webhooks,
717 : /* allow webhook data of up to 8 MB, that should be plenty;
718 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
719 : would require further changes to the allocation logic
720 : in the code... */
721 : .max_upload = 1024 * 1024 * 8
722 : },
723 : /* GET /webhooks/$ID/: */
724 : {
725 : .url_prefix = "/webhooks/",
726 : .method = MHD_HTTP_METHOD_GET,
727 : .permission = "webhooks-read",
728 : .have_id_segment = true,
729 : .allow_deleted_instance = true,
730 : .handler = &TMH_private_get_webhooks_ID
731 : },
732 : /* DELETE /webhooks/$ID/: */
733 : {
734 : .url_prefix = "/webhooks/",
735 : .permission = "webhooks-write",
736 : .method = MHD_HTTP_METHOD_DELETE,
737 : .have_id_segment = true,
738 : .allow_deleted_instance = true,
739 : .handler = &TMH_private_delete_webhooks_ID
740 : },
741 : /* PATCH /webhooks/$ID/: */
742 : {
743 : .url_prefix = "/webhooks/",
744 : .method = MHD_HTTP_METHOD_PATCH,
745 : .permission = "webhooks-write",
746 : .have_id_segment = true,
747 : .allow_deleted_instance = true,
748 : .handler = &TMH_private_patch_webhooks_ID,
749 : /* allow webhook data of up to 8 MB, that should be plenty;
750 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
751 : would require further changes to the allocation logic
752 : in the code... */
753 : .max_upload = 1024 * 1024 * 8
754 : },
755 : /* POST /accounts: */
756 : {
757 : .url_prefix = "/accounts",
758 : .method = MHD_HTTP_METHOD_POST,
759 : .permission = "accounts-write",
760 : .handler = &TMH_private_post_account,
761 : /* allow account details of up to 8 kb, that should be plenty */
762 : .max_upload = 1024 * 8
763 : },
764 : /* PATCH /accounts/$H_WIRE: */
765 : {
766 : .url_prefix = "/accounts/",
767 : .method = MHD_HTTP_METHOD_PATCH,
768 : .permission = "accounts-write",
769 : .handler = &TMH_private_patch_accounts_ID,
770 : .have_id_segment = true,
771 : /* allow account details of up to 8 kb, that should be plenty */
772 : .max_upload = 1024 * 8
773 : },
774 : /* GET /accounts: */
775 : {
776 : .url_prefix = "/accounts",
777 : .permission = "accounts-read",
778 : .method = MHD_HTTP_METHOD_GET,
779 : .handler = &TMH_private_get_accounts
780 : },
781 : /* GET /accounts/$H_WIRE: */
782 : {
783 : .url_prefix = "/accounts/",
784 : .permission = "accounts-read",
785 : .method = MHD_HTTP_METHOD_GET,
786 : .have_id_segment = true,
787 : .handler = &TMH_private_get_accounts_ID
788 : },
789 : /* DELETE /accounts/$H_WIRE: */
790 : {
791 : .url_prefix = "/accounts/",
792 : .permission = "accounts-write",
793 : .method = MHD_HTTP_METHOD_DELETE,
794 : .handler = &TMH_private_delete_account_ID,
795 : .have_id_segment = true
796 : },
797 : /* GET /tokens: */
798 : {
799 : .url_prefix = "/tokens",
800 : .permission = "tokens-read",
801 : .method = MHD_HTTP_METHOD_GET,
802 : .handler = &TMH_private_get_instances_ID_tokens,
803 : },
804 : /* POST /token: */
805 : {
806 : .url_prefix = "/token",
807 : .permission = "token-refresh",
808 : .method = MHD_HTTP_METHOD_POST,
809 : .handler = &TMH_private_post_instances_ID_token,
810 : /* Body should be tiny. */
811 : .max_upload = 1024
812 : },
813 : /* DELETE /tokens/$SERIAL: */
814 : {
815 : .url_prefix = "/tokens/",
816 : .permission = "tokens-write",
817 : .method = MHD_HTTP_METHOD_DELETE,
818 : .handler = &TMH_private_delete_instances_ID_token_SERIAL,
819 : .have_id_segment = true
820 : },
821 : /* DELETE /token: */
822 : {
823 : .url_prefix = "/token",
824 : .method = MHD_HTTP_METHOD_DELETE,
825 : .handler = &TMH_private_delete_instances_ID_token,
826 : },
827 : /* GET /tokenfamilies: */
828 : {
829 : .url_prefix = "/tokenfamilies",
830 : .permission = "tokenfamilies-read",
831 : .method = MHD_HTTP_METHOD_GET,
832 : .handler = &TMH_private_get_tokenfamilies
833 : },
834 : /* POST /tokenfamilies: */
835 : {
836 : .url_prefix = "/tokenfamilies",
837 : .permission = "tokenfamilies-write",
838 : .method = MHD_HTTP_METHOD_POST,
839 : .handler = &TMH_private_post_token_families
840 : },
841 : /* GET /tokenfamilies/$SLUG/: */
842 : {
843 : .url_prefix = "/tokenfamilies/",
844 : .method = MHD_HTTP_METHOD_GET,
845 : .permission = "tokenfamilies-read",
846 : .have_id_segment = true,
847 : .handler = &TMH_private_get_tokenfamilies_SLUG
848 : },
849 : /* DELETE /tokenfamilies/$SLUG/: */
850 : {
851 : .url_prefix = "/tokenfamilies/",
852 : .method = MHD_HTTP_METHOD_DELETE,
853 : .permission = "tokenfamilies-write",
854 : .have_id_segment = true,
855 : .handler = &TMH_private_delete_token_families_SLUG
856 : },
857 : /* PATCH /tokenfamilies/$SLUG/: */
858 : {
859 : .url_prefix = "/tokenfamilies/",
860 : .method = MHD_HTTP_METHOD_PATCH,
861 : .permission = "tokenfamilies-write",
862 : .have_id_segment = true,
863 : .handler = &TMH_private_patch_token_family_SLUG,
864 : },
865 : #ifdef HAVE_DONAU_DONAU_SERVICE_H
866 : /* GET /donau */
867 : {
868 : .url_prefix = "/donau",
869 : .method = MHD_HTTP_METHOD_GET,
870 : .handler = &TMH_private_get_donau_instances
871 : },
872 : /* POST /donau */
873 : {
874 : .url_prefix = "/donau",
875 : .method = MHD_HTTP_METHOD_POST,
876 : .handler = &TMH_private_post_donau_instance
877 : },
878 : /* DELETE /donau/$charity-id */
879 : {
880 : .url_prefix = "/donau/",
881 : .method = MHD_HTTP_METHOD_DELETE,
882 : .have_id_segment = true,
883 : .handler = &TMH_private_delete_donau_instance_ID
884 : },
885 : #endif
886 : /* GET /statistics-counter/$SLUG: */
887 : {
888 : .url_prefix = "/statistics-counter/",
889 : .method = MHD_HTTP_METHOD_GET,
890 : .permission = "statistics-read",
891 : .have_id_segment = true,
892 : .handler = &TMH_private_get_statistics_counter_SLUG,
893 : },
894 : /* GET /statistics-amount/$SLUG: */
895 : {
896 : .url_prefix = "/statistics-amount/",
897 : .method = MHD_HTTP_METHOD_GET,
898 : .permission = "statistics-read",
899 : .have_id_segment = true,
900 : .handler = &TMH_private_get_statistics_amount_SLUG,
901 : },
902 : /* GET /statistics-report/transactions: */
903 : {
904 : .url_prefix = "/statistics-report/",
905 : .url_suffix = "transactions",
906 : .method = MHD_HTTP_METHOD_GET,
907 : .permission = "statistics-read",
908 : .handler = &TMH_private_get_statistics_report_transactions,
909 : },
910 : {
911 : .url_prefix = NULL
912 : }
913 : };
914 : static struct TMH_RequestHandler public_handlers[] = {
915 : {
916 : /* for "admin" instance, it does not even
917 : have to exist before we give the WebUI */
918 : .url_prefix = "/",
919 : .method = MHD_HTTP_METHOD_GET,
920 : .mime_type = "text/html",
921 : .skip_instance = true,
922 : .default_only = true,
923 : .handler = &spa_redirect,
924 : .response_code = MHD_HTTP_FOUND
925 : },
926 : {
927 : .url_prefix = "/config",
928 : .method = MHD_HTTP_METHOD_GET,
929 : .skip_instance = true,
930 : .default_only = true,
931 : .handler = &MH_handler_config
932 : },
933 : {
934 : /* for "normal" instance,s they must exist
935 : before we give the WebUI */
936 : .url_prefix = "/",
937 : .method = MHD_HTTP_METHOD_GET,
938 : .mime_type = "text/html",
939 : .handler = &spa_redirect,
940 : .response_code = MHD_HTTP_FOUND
941 : },
942 : {
943 : .url_prefix = "/webui/",
944 : .method = MHD_HTTP_METHOD_GET,
945 : .mime_type = "text/html",
946 : .skip_instance = true,
947 : .have_id_segment = true,
948 : .handler = &TMH_return_spa,
949 : .response_code = MHD_HTTP_OK
950 : },
951 : {
952 : .url_prefix = "/agpl",
953 : .method = MHD_HTTP_METHOD_GET,
954 : .skip_instance = true,
955 : .handler = &TMH_MHD_handler_agpl_redirect
956 : },
957 : {
958 : .url_prefix = "/agpl",
959 : .method = MHD_HTTP_METHOD_GET,
960 : .skip_instance = true,
961 : .handler = &TMH_MHD_handler_agpl_redirect
962 : },
963 : {
964 : .url_prefix = "/terms",
965 : .method = MHD_HTTP_METHOD_GET,
966 : .skip_instance = true,
967 : .handler = &TMH_handler_terms
968 : },
969 : {
970 : .url_prefix = "/privacy",
971 : .method = MHD_HTTP_METHOD_GET,
972 : .skip_instance = true,
973 : .handler = &TMH_handler_privacy
974 : },
975 : /* Also serve the same /config per instance */
976 : {
977 : .url_prefix = "/config",
978 : .method = MHD_HTTP_METHOD_GET,
979 : .handler = &MH_handler_config
980 : },
981 : /* POST /orders/$ID/abort: */
982 : {
983 : .url_prefix = "/orders/",
984 : .have_id_segment = true,
985 : .url_suffix = "abort",
986 : .method = MHD_HTTP_METHOD_POST,
987 : .handler = &TMH_post_orders_ID_abort,
988 : /* wallet may give us many coins to sign, allow 1 MB of upload
989 : to set a conservative bound for sane wallets */
990 : .max_upload = 1024 * 1024
991 : },
992 : /* POST /orders/$ID/claim: */
993 : {
994 : .url_prefix = "/orders/",
995 : .have_id_segment = true,
996 : .url_suffix = "claim",
997 : .method = MHD_HTTP_METHOD_POST,
998 : .handler = &TMH_post_orders_ID_claim,
999 : /* the body should be pretty small, allow 1 MB of upload
1000 : to set a conservative bound for sane wallets */
1001 : .max_upload = 1024 * 1024
1002 : },
1003 : /* POST /orders/$ID/pay: */
1004 : {
1005 : .url_prefix = "/orders/",
1006 : .have_id_segment = true,
1007 : .url_suffix = "pay",
1008 : .method = MHD_HTTP_METHOD_POST,
1009 : .handler = &TMH_post_orders_ID_pay,
1010 : /* wallet may give us many coins to sign, allow 1 MB of upload
1011 : to set a conservative bound for sane wallets */
1012 : .max_upload = 1024 * 1024
1013 : },
1014 : /* POST /orders/$ID/paid: */
1015 : {
1016 : .url_prefix = "/orders/",
1017 : .have_id_segment = true,
1018 : .allow_deleted_instance = true,
1019 : .url_suffix = "paid",
1020 : .method = MHD_HTTP_METHOD_POST,
1021 : .handler = &TMH_post_orders_ID_paid,
1022 : /* the body should be pretty small, allow 1 MB of upload
1023 : to set a conservative bound for sane wallets */
1024 : .max_upload = 1024 * 1024
1025 : },
1026 : /* POST /orders/$ID/refund: */
1027 : {
1028 : .url_prefix = "/orders/",
1029 : .have_id_segment = true,
1030 : .allow_deleted_instance = true,
1031 : .url_suffix = "refund",
1032 : .method = MHD_HTTP_METHOD_POST,
1033 : .handler = &TMH_post_orders_ID_refund,
1034 : /* the body should be pretty small, allow 1 MB of upload
1035 : to set a conservative bound for sane wallets */
1036 : .max_upload = 1024 * 1024
1037 : },
1038 : /* GET /orders/$ID: */
1039 : {
1040 : .url_prefix = "/orders/",
1041 : .method = MHD_HTTP_METHOD_GET,
1042 : .allow_deleted_instance = true,
1043 : .have_id_segment = true,
1044 : .handler = &TMH_get_orders_ID
1045 : },
1046 : /* GET /static/ *: */
1047 : {
1048 : .url_prefix = "/static/",
1049 : .method = MHD_HTTP_METHOD_GET,
1050 : .have_id_segment = true,
1051 : .handler = &TMH_return_static
1052 : },
1053 : /* POST /reports/$ID/ */
1054 : {
1055 : .url_prefix = "/reports",
1056 : .method = MHD_HTTP_METHOD_POST,
1057 : .have_id_segment = true,
1058 : .handler = &TMH_post_reports_ID,
1059 : },
1060 : /* GET /templates/$ID/: */
1061 : {
1062 : .url_prefix = "/templates/",
1063 : .method = MHD_HTTP_METHOD_GET,
1064 : .have_id_segment = true,
1065 : .handler = &TMH_get_templates_ID
1066 : },
1067 : /* GET /products/$HASH/image: */
1068 : {
1069 : .url_prefix = "/products/",
1070 : .method = MHD_HTTP_METHOD_GET,
1071 : .have_id_segment = true,
1072 : .allow_deleted_instance = true,
1073 : .url_suffix = "image",
1074 : .handler = &TMH_get_products_image
1075 : },
1076 : /* POST /templates/$ID: */
1077 : {
1078 : .url_prefix = "/templates/",
1079 : .method = MHD_HTTP_METHOD_POST,
1080 : .have_id_segment = true,
1081 : .handler = &TMH_post_using_templates_ID,
1082 : .max_upload = 1024 * 1024
1083 : },
1084 : /* POST /challenge/$ID: */
1085 : {
1086 : .url_prefix = "/challenge/",
1087 : .method = MHD_HTTP_METHOD_POST,
1088 : .have_id_segment = true,
1089 : .handler = &TMH_post_challenge_ID,
1090 : .max_upload = 1024
1091 : },
1092 : /* POST /challenge/$ID/confirm: */
1093 : {
1094 : .url_prefix = "/challenge/",
1095 : .method = MHD_HTTP_METHOD_POST,
1096 : .have_id_segment = true,
1097 : .url_suffix = "confirm",
1098 : .handler = &TMH_post_challenge_ID_confirm,
1099 : .max_upload = 1024
1100 : },
1101 : /* POST /instances */
1102 : {
1103 : .url_prefix = "/instances",
1104 : .method = MHD_HTTP_METHOD_POST,
1105 : .skip_instance = true,
1106 : .default_only = true,
1107 : .handler = &TMH_public_post_instances,
1108 : /* allow instance data of up to 8 MB, that should be plenty;
1109 : note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB)
1110 : would require further changes to the allocation logic
1111 : in the code... */
1112 : .max_upload = 1024 * 1024 * 8
1113 : },
1114 : /* POST /forgot-password: */
1115 : {
1116 : .url_prefix = "/forgot-password",
1117 : .method = MHD_HTTP_METHOD_POST,
1118 : .handler = &TMH_public_post_instances_ID_auth,
1119 : /* Body should be pretty small. */
1120 : .max_upload = 1024 * 1024
1121 : },
1122 :
1123 : /* Reports endpoints */
1124 : {
1125 : .url_prefix = "reports",
1126 : .method = MHD_HTTP_METHOD_GET,
1127 : .permission = "reports-read",
1128 : .handler = &TMH_private_get_reports,
1129 : },
1130 : {
1131 : .url_prefix = "reports",
1132 : .method = MHD_HTTP_METHOD_POST,
1133 : .permission = "reports-write",
1134 : .handler = &TMH_private_post_reports,
1135 : },
1136 : {
1137 : .url_prefix = "reports",
1138 : .method = MHD_HTTP_METHOD_GET,
1139 : .handler = &TMH_private_get_report,
1140 : .permission = "reports-read",
1141 : .have_id_segment = true,
1142 : },
1143 : {
1144 : .url_prefix = "reports",
1145 : .method = MHD_HTTP_METHOD_PATCH,
1146 : .handler = &TMH_private_patch_report,
1147 : .permission = "reports-write",
1148 : .have_id_segment = true,
1149 : },
1150 : {
1151 : .url_prefix = "reports",
1152 : .method = MHD_HTTP_METHOD_DELETE,
1153 : .handler = &TMH_private_delete_report,
1154 : .permission = "reports-write",
1155 : .have_id_segment = true,
1156 : },
1157 :
1158 : /* Groups endpoints */
1159 : {
1160 : .url_prefix = "groups",
1161 : .method = MHD_HTTP_METHOD_GET,
1162 : .permission = "groups-read",
1163 : .handler = &TMH_private_get_groups,
1164 : },
1165 : {
1166 : .url_prefix = "groups",
1167 : .method = MHD_HTTP_METHOD_POST,
1168 : .permission = "groups-write",
1169 : .handler = &TMH_private_post_groups,
1170 : },
1171 : {
1172 : .url_prefix = "groups",
1173 : .method = MHD_HTTP_METHOD_PATCH,
1174 : .handler = &TMH_private_patch_group,
1175 : .permission = "groups-write",
1176 : .have_id_segment = true,
1177 : },
1178 : {
1179 : .url_prefix = "groups",
1180 : .method = MHD_HTTP_METHOD_DELETE,
1181 : .handler = &TMH_private_delete_group,
1182 : .permission = "groups-write",
1183 : .have_id_segment = true,
1184 : },
1185 :
1186 : /* Money pots endpoints */
1187 : {
1188 : .url_prefix = "pots",
1189 : .method = MHD_HTTP_METHOD_GET,
1190 : .handler = &TMH_private_get_pots,
1191 : .permission = "pots-read",
1192 : },
1193 : {
1194 : .url_prefix = "pots",
1195 : .method = MHD_HTTP_METHOD_POST,
1196 : .handler = &TMH_private_post_pots,
1197 : .permission = "pots-write"
1198 : },
1199 : {
1200 : .url_prefix = "pots",
1201 : .method = MHD_HTTP_METHOD_GET,
1202 : .handler = &TMH_private_get_pot,
1203 : .have_id_segment = true,
1204 : .permission = "pots-read",
1205 : },
1206 : {
1207 : .url_prefix = "pots",
1208 : .method = MHD_HTTP_METHOD_PATCH,
1209 : .handler = &TMH_private_patch_pot,
1210 : .have_id_segment = true,
1211 : .permission = "pots-write"
1212 : },
1213 : {
1214 : .url_prefix = "pots",
1215 : .method = MHD_HTTP_METHOD_DELETE,
1216 : .handler = &TMH_private_delete_pot,
1217 : .have_id_segment = true,
1218 : .permission = "pots-write"
1219 : },
1220 : {
1221 : .url_prefix = "*",
1222 : .method = MHD_HTTP_METHOD_OPTIONS,
1223 : .handler = &handle_server_options
1224 : },
1225 : {
1226 : .url_prefix = NULL
1227 : }
1228 : };
1229 749 : const char *management_prefix = "/management/";
1230 749 : const char *private_prefix = "/private/";
1231 749 : const char *url = *urlp;
1232 : struct TMH_RequestHandler *handlers;
1233 :
1234 749 : *is_public = false; /* ensure safe default */
1235 749 : if ( (0 == strncmp (url,
1236 : management_prefix,
1237 : strlen (management_prefix))) )
1238 : {
1239 64 : handlers = management_handlers;
1240 64 : *urlp = url + strlen (management_prefix) - 1;
1241 : }
1242 685 : else if ( (0 == strncmp (url,
1243 : private_prefix,
1244 212 : strlen (private_prefix))) ||
1245 212 : (0 == strcmp (url,
1246 : "/private")) )
1247 : {
1248 488 : handlers = private_handlers;
1249 976 : if (0 == strcmp (url,
1250 : "/private"))
1251 15 : *urlp = "/";
1252 : else
1253 473 : *urlp = url + strlen (private_prefix) - 1;
1254 : }
1255 : else
1256 : {
1257 197 : handlers = public_handlers;
1258 197 : *is_public = true;
1259 : }
1260 749 : return handlers;
1261 : }
1262 :
1263 :
1264 : /**
1265 : * Checks if the @a rh matches the given (parsed) URL.
1266 : *
1267 : * @param rh handler to compare against
1268 : * @param url the main URL (without "/private/" prefix, if any)
1269 : * @param prefix_strlen length of the prefix, i.e. 8 for '/orders/' or 7 for '/config'
1270 : * @param infix_url infix text, i.e. "$ORDER_ID".
1271 : * @param infix_strlen length of the string in @a infix_url
1272 : * @param suffix_url suffix, i.e. "/refund", including the "/"
1273 : * @param suffix_strlen number of characters in @a suffix_url
1274 : * @return true if @a rh matches this request
1275 : */
1276 : static bool
1277 15812 : prefix_match (const struct TMH_RequestHandler *rh,
1278 : const char *url,
1279 : size_t prefix_strlen,
1280 : const char *infix_url,
1281 : size_t infix_strlen,
1282 : const char *suffix_url,
1283 : size_t suffix_strlen)
1284 : {
1285 15812 : if ( (prefix_strlen != strlen (rh->url_prefix)) ||
1286 2447 : (0 != memcmp (url,
1287 2447 : rh->url_prefix,
1288 : prefix_strlen)) )
1289 14375 : return false;
1290 1437 : if (! rh->have_id_segment)
1291 : {
1292 : /* Require /$PREFIX/$SUFFIX or /$PREFIX */
1293 456 : if (NULL != suffix_url)
1294 0 : return false; /* too many segments to match */
1295 456 : if ( (NULL == infix_url) /* either or */
1296 456 : ^ (NULL == rh->url_suffix) )
1297 0 : return false; /* suffix existence mismatch */
1298 : /* If /$PREFIX/$SUFFIX, check $SUFFIX matches */
1299 456 : if ( (NULL != infix_url) &&
1300 0 : ( (infix_strlen != strlen (rh->url_suffix)) ||
1301 0 : (0 != memcmp (infix_url,
1302 0 : rh->url_suffix,
1303 : infix_strlen)) ) )
1304 0 : return false; /* cannot use infix as suffix: content mismatch */
1305 : }
1306 : else
1307 : {
1308 : /* Require /$PREFIX/$ID or /$PREFIX/$ID/$SUFFIX */
1309 981 : if (NULL == infix_url)
1310 0 : return false; /* infix existence mismatch */
1311 981 : if ( ( (NULL == suffix_url)
1312 981 : ^ (NULL == rh->url_suffix) ) )
1313 253 : return false; /* suffix existence mismatch */
1314 728 : if ( (NULL != suffix_url) &&
1315 363 : ( (suffix_strlen != strlen (rh->url_suffix)) ||
1316 253 : (0 != memcmp (suffix_url,
1317 253 : rh->url_suffix,
1318 : suffix_strlen)) ) )
1319 192 : return false; /* suffix content mismatch */
1320 : }
1321 992 : return true;
1322 : }
1323 :
1324 :
1325 : /**
1326 : * Identify the handler of the request from the @a url and @a method
1327 : *
1328 : * @param[in,out] hc handler context to update with applicable handler
1329 : * @param handlers array of handlers to consider
1330 : * @param url URL to match against the handlers
1331 : * @param method HTTP access method to consider
1332 : * @param use_admin set to true if we are using the admin instance
1333 : * @return #GNUNET_OK on success,
1334 : * #GNUNET_NO if an error was queued (return #MHD_YES)
1335 : * #GNUNET_SYSERR to close the connection (return #MHD_NO)
1336 : */
1337 : static enum GNUNET_GenericReturnValue
1338 749 : identify_handler (struct TMH_HandlerContext *hc,
1339 : const struct TMH_RequestHandler *handlers,
1340 : const char *url,
1341 : const char *method,
1342 : bool use_admin)
1343 : {
1344 : size_t prefix_strlen; /* i.e. 8 for "/orders/", or 7 for "/config" */
1345 749 : const char *infix_url = NULL; /* i.e. "$ORDER_ID", no '/'-es */
1346 749 : size_t infix_strlen = 0; /* number of characters in infix_url */
1347 749 : const char *suffix_url = NULL; /* i.e. "refund", excludes '/' at the beginning */
1348 749 : size_t suffix_strlen = 0; /* number of characters in suffix_url */
1349 :
1350 749 : if (0 == strcasecmp (method,
1351 : MHD_HTTP_METHOD_HEAD))
1352 0 : method = MHD_HTTP_METHOD_GET; /* MHD will deal with the rest */
1353 749 : if (0 == strcmp (url,
1354 : ""))
1355 0 : url = "/"; /* code below does not like empty string */
1356 :
1357 : /* parse the URL into the three different components */
1358 : {
1359 : const char *slash;
1360 :
1361 749 : slash = strchr (&url[1], '/');
1362 749 : if (NULL == slash)
1363 : {
1364 : /* the prefix was everything */
1365 335 : prefix_strlen = strlen (url);
1366 : }
1367 : else
1368 : {
1369 414 : prefix_strlen = slash - url + 1; /* includes both '/'-es if present! */
1370 414 : infix_url = slash + 1;
1371 414 : slash = strchr (infix_url, '/');
1372 414 : if (NULL == slash)
1373 : {
1374 : /* the infix was the rest */
1375 243 : infix_strlen = strlen (infix_url);
1376 : }
1377 : else
1378 : {
1379 171 : infix_strlen = slash - infix_url; /* excludes both '/'-es */
1380 171 : suffix_url = slash + 1; /* skip the '/' */
1381 171 : suffix_strlen = strlen (suffix_url);
1382 : }
1383 414 : hc->infix = GNUNET_strndup (infix_url,
1384 : infix_strlen);
1385 : }
1386 : }
1387 :
1388 : /* find matching handler */
1389 : {
1390 749 : bool url_found = false;
1391 :
1392 15824 : for (unsigned int i = 0; NULL != handlers[i].url_prefix; i++)
1393 : {
1394 15824 : const struct TMH_RequestHandler *rh = &handlers[i];
1395 :
1396 15824 : if (rh->default_only && (! use_admin))
1397 12 : continue;
1398 15812 : if (! prefix_match (rh,
1399 : url,
1400 : prefix_strlen,
1401 : infix_url,
1402 : infix_strlen,
1403 : suffix_url,
1404 : suffix_strlen))
1405 14820 : continue;
1406 992 : url_found = true;
1407 992 : if (0 == strcasecmp (method,
1408 : MHD_HTTP_METHOD_OPTIONS))
1409 : {
1410 : return (MHD_YES ==
1411 1 : TALER_MHD_reply_cors_preflight (hc->connection))
1412 : ? GNUNET_NO
1413 1 : : GNUNET_SYSERR;
1414 : }
1415 991 : if ( (rh->method != NULL) &&
1416 991 : (0 != strcasecmp (method,
1417 991 : rh->method)) )
1418 243 : continue;
1419 748 : hc->rh = rh;
1420 748 : break;
1421 : }
1422 : /* Handle HTTP 405: METHOD NOT ALLOWED case */
1423 748 : if ( (NULL == hc->rh) &&
1424 : (url_found) )
1425 : {
1426 : struct MHD_Response *reply;
1427 : MHD_RESULT ret;
1428 0 : char *allowed = NULL;
1429 :
1430 0 : GNUNET_break_op (0);
1431 : /* compute 'Allowed:' header (required by HTTP spec for 405 replies) */
1432 0 : for (unsigned int i = 0; NULL != handlers[i].url_prefix; i++)
1433 : {
1434 0 : const struct TMH_RequestHandler *rh = &handlers[i];
1435 :
1436 0 : if (rh->default_only && (! use_admin))
1437 0 : continue;
1438 0 : if (! prefix_match (rh,
1439 : url,
1440 : prefix_strlen,
1441 : infix_url,
1442 : infix_strlen,
1443 : suffix_url,
1444 : suffix_strlen))
1445 0 : continue;
1446 0 : if (NULL == allowed)
1447 : {
1448 0 : allowed = GNUNET_strdup (rh->method);
1449 : }
1450 : else
1451 : {
1452 : char *tmp;
1453 :
1454 0 : GNUNET_asprintf (&tmp,
1455 : "%s, %s",
1456 : allowed,
1457 0 : rh->method);
1458 0 : GNUNET_free (allowed);
1459 0 : allowed = tmp;
1460 : }
1461 0 : if (0 == strcasecmp (rh->method,
1462 : MHD_HTTP_METHOD_GET))
1463 : {
1464 : char *tmp;
1465 :
1466 0 : GNUNET_asprintf (&tmp,
1467 : "%s, %s",
1468 : allowed,
1469 : MHD_HTTP_METHOD_HEAD);
1470 0 : GNUNET_free (allowed);
1471 0 : allowed = tmp;
1472 : }
1473 : }
1474 0 : reply = TALER_MHD_make_error (TALER_EC_GENERIC_METHOD_INVALID,
1475 : method);
1476 0 : GNUNET_break (MHD_YES ==
1477 : MHD_add_response_header (reply,
1478 : MHD_HTTP_HEADER_ALLOW,
1479 : allowed));
1480 0 : GNUNET_free (allowed);
1481 0 : ret = MHD_queue_response (hc->connection,
1482 : MHD_HTTP_METHOD_NOT_ALLOWED,
1483 : reply);
1484 0 : MHD_destroy_response (reply);
1485 : return (MHD_YES == ret)
1486 : ? GNUNET_NO
1487 0 : : GNUNET_SYSERR;
1488 : }
1489 748 : if (NULL == hc->rh)
1490 : {
1491 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1492 : "Endpoint `%s' not known\n",
1493 : hc->url);
1494 : return (MHD_YES ==
1495 0 : TALER_MHD_reply_with_error (hc->connection,
1496 : MHD_HTTP_NOT_FOUND,
1497 : TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
1498 : hc->url))
1499 : ? GNUNET_NO
1500 0 : : GNUNET_SYSERR;
1501 : }
1502 : }
1503 748 : return GNUNET_OK;
1504 : }
1505 :
1506 :
1507 : enum GNUNET_GenericReturnValue
1508 749 : TMH_dispatch_request (struct TMH_HandlerContext *hc,
1509 : const char *url,
1510 : const char *method,
1511 : bool use_admin,
1512 : bool *is_public)
1513 : {
1514 : const struct TMH_RequestHandler *handlers;
1515 :
1516 749 : *is_public = false;
1517 749 : handlers = determine_handler_group (&url,
1518 : is_public);
1519 749 : return identify_handler (hc,
1520 : handlers,
1521 : url,
1522 : method,
1523 : use_admin);
1524 : }
|