LCOV - code coverage report
Current view: top level - backend - taler-merchant-httpd_dispatcher.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 67.8 % 143 97
Test Date: 2025-12-29 21:26:17 Functions: 83.3 % 6 5

            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              : }
        

Generated by: LCOV version 2.0-1