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