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