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