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