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