taler-merchant-httpd_dispatcher.c (51964B)
1 /* 2 This file is part of TALER 3 (C) 2014-2025 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file taler-merchant-httpd_dispatcher.c 18 * @brief map requested URL and method to the respective request handler 19 * @author Christian Grothoff 20 */ 21 #include "taler/platform.h" 22 #include "taler-merchant-httpd_get-config.h" 23 #include "taler-merchant-httpd_get-exchanges.h" 24 #include "taler-merchant-httpd_dispatcher.h" 25 #include "taler-merchant-httpd_get-orders-ORDER_ID.h" 26 #include "taler-merchant-httpd_get-sessions-SESSION_ID.h" 27 #include "taler-merchant-httpd_get-products-IMAGE_HASH-image.h" 28 #include "taler-merchant-httpd_get-templates-TEMPLATE_ID.h" 29 #include "taler-merchant-httpd_mhd.h" 30 #include "taler-merchant-httpd_delete-private-accounts-H_WIRE.h" 31 #include "taler-merchant-httpd_delete-private-categories-CATEGORY_ID.h" 32 #include "taler-merchant-httpd_delete-private-units-UNIT.h" 33 #include "taler-merchant-httpd_delete-management-instances-INSTANCE.h" 34 #include "taler-merchant-httpd_delete-private-tokens-SERIAL.h" 35 #include "taler-merchant-httpd_delete-private-products-PRODUCT_ID.h" 36 #include "taler-merchant-httpd_delete-private-orders-ORDER_ID.h" 37 #include "taler-merchant-httpd_delete-private-otp-devices-DEVICE_ID.h" 38 #include "taler-merchant-httpd_delete-private-templates-TEMPLATE_ID.h" 39 #include "taler-merchant-httpd_delete-private-tokenfamilies-TOKEN_FAMILY_SLUG.h" 40 #include "taler-merchant-httpd_delete-private-transfers-TID.h" 41 #include "taler-merchant-httpd_delete-private-webhooks-WEBHOOK_ID.h" 42 #include "taler-merchant-httpd_get-private-accounts.h" 43 #include "taler-merchant-httpd_get-private-accounts-H_WIRE.h" 44 #include "taler-merchant-httpd_get-private-categories.h" 45 #include "taler-merchant-httpd_get-private-categories-CATEGORY_ID.h" 46 #include "taler-merchant-httpd_get-private-units.h" 47 #include "taler-merchant-httpd_get-private-units-UNIT.h" 48 #include "taler-merchant-httpd_get-private-incoming.h" 49 #include "taler-merchant-httpd_get-private-incoming-ID.h" 50 #include "taler-merchant-httpd_get-management-instances.h" 51 #include "taler-merchant-httpd_get-management-instances-INSTANCE.h" 52 #include "taler-merchant-httpd_get-private-kyc.h" 53 #include "taler-merchant-httpd_get-private-tokens.h" 54 #include "taler-merchant-httpd_get-private-pos.h" 55 #include "taler-merchant-httpd_get-private-products.h" 56 #include "taler-merchant-httpd_get-private-products-PRODUCT_ID.h" 57 #include "taler-merchant-httpd_get-private-orders.h" 58 #include "taler-merchant-httpd_get-private-orders-ORDER_ID.h" 59 #include "taler-merchant-httpd_get-private-otp-devices.h" 60 #include "taler-merchant-httpd_get-private-otp-devices-DEVICE_ID.h" 61 #include "taler-merchant-httpd_get-private-statistics-amount-SLUG.h" 62 #include "taler-merchant-httpd_get-private-statistics-counter-SLUG.h" 63 #include "taler-merchant-httpd_get-private-statistics-report-transactions.h" 64 #include "taler-merchant-httpd_get-private-templates.h" 65 #include "taler-merchant-httpd_get-private-templates-TEMPLATE_ID.h" 66 #include "taler-merchant-httpd_get-private-tokenfamilies.h" 67 #include "taler-merchant-httpd_get-private-tokenfamilies-TOKEN_FAMILY_SLUG.h" 68 #include "taler-merchant-httpd_get-private-transfers.h" 69 #include "taler-merchant-httpd_get-private-webhooks.h" 70 #include "taler-merchant-httpd_get-private-webhooks-WEBHOOK_ID.h" 71 #include "taler-merchant-httpd_patch-private-accounts-H_WIRE.h" 72 #include "taler-merchant-httpd_patch-private-categories-CATEGORY_ID.h" 73 #include "taler-merchant-httpd_patch-private-units-UNIT.h" 74 #include "taler-merchant-httpd_patch-management-instances-INSTANCE.h" 75 #include "taler-merchant-httpd_patch-private-orders-ORDER_ID-forget.h" 76 #include "taler-merchant-httpd_patch-private-otp-devices-DEVICE_ID.h" 77 #include "taler-merchant-httpd_patch-private-products-PRODUCT_ID.h" 78 #include "taler-merchant-httpd_patch-private-templates-TEMPLATE_ID.h" 79 #include "taler-merchant-httpd_patch-private-tokenfamilies-TOKEN_FAMILY_SLUG.h" 80 #include "taler-merchant-httpd_patch-private-webhooks-WEBHOOK_ID.h" 81 #include "taler-merchant-httpd_post-private-accounts.h" 82 #include "taler-merchant-httpd_post-private-categories.h" 83 #include "taler-merchant-httpd_post-private-units.h" 84 #include "taler-merchant-httpd_post-management-instances.h" 85 #include "taler-merchant-httpd_post-management-instances-INSTANCE-auth.h" 86 #include "taler-merchant-httpd_post-private-token.h" 87 #include "taler-merchant-httpd_post-private-otp-devices.h" 88 #include "taler-merchant-httpd_post-private-orders.h" 89 #include "taler-merchant-httpd_post-private-orders-ORDER_ID-refund.h" 90 #include "taler-merchant-httpd_post-private-products.h" 91 #include "taler-merchant-httpd_post-private-products-PRODUCT_ID-lock.h" 92 #include "taler-merchant-httpd_post-private-templates.h" 93 #include "taler-merchant-httpd_post-private-tokenfamilies.h" 94 #include "taler-merchant-httpd_post-private-transfers.h" 95 #include "taler-merchant-httpd_post-private-webhooks.h" 96 #include "taler-merchant-httpd_post-challenge-ID.h" 97 #include "taler-merchant-httpd_post-challenge-ID-confirm.h" 98 #include "taler-merchant-httpd_post-orders-ORDER_ID-abort.h" 99 #include "taler-merchant-httpd_post-orders-ORDER_ID-claim.h" 100 #include "taler-merchant-httpd_post-orders-ORDER_ID-paid.h" 101 #include "taler-merchant-httpd_post-orders-ORDER_ID-pay.h" 102 #include "taler-merchant-httpd_post-orders-ORDER_ID-unclaim.h" 103 #include "taler-merchant-httpd_post-templates-TEMPLATE_ID.h" 104 #include "taler-merchant-httpd_post-orders-ORDER_ID-refund.h" 105 #include "taler-merchant-httpd_get-webui.h" 106 #include "taler-merchant-httpd_statics.h" 107 #include "taler-merchant-httpd_get-terms.h" 108 #include "taler-merchant-httpd_post-reports-REPORT_ID.h" 109 #include "taler-merchant-httpd_delete-private-reports-REPORT_ID.h" 110 #include "taler-merchant-httpd_get-private-reports-REPORT_ID.h" 111 #include "taler-merchant-httpd_get-private-reports.h" 112 #include "taler-merchant-httpd_patch-private-reports-REPORT_ID.h" 113 #include "taler-merchant-httpd_post-private-reports.h" 114 #include "taler-merchant-httpd_delete-private-pots-POT_ID.h" 115 #include "taler-merchant-httpd_get-private-pots-POT_ID.h" 116 #include "taler-merchant-httpd_get-private-pots.h" 117 #include "taler-merchant-httpd_patch-private-pots-POT_ID.h" 118 #include "taler-merchant-httpd_post-private-pots.h" 119 #include "taler-merchant-httpd_get-private-groups.h" 120 #include "taler-merchant-httpd_post-private-groups.h" 121 #include "taler-merchant-httpd_patch-private-groups-GROUP_ID.h" 122 #include "taler-merchant-httpd_delete-private-groups-GROUP_ID.h" 123 124 #ifdef HAVE_DONAU_DONAU_SERVICE_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 #endif 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 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 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 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 /* PATCH /accounts/$H_WIRE: */ 809 { 810 .url_prefix = "/accounts/", 811 .method = MHD_HTTP_METHOD_PATCH, 812 .permission = "accounts-write", 813 .handler = &TMH_private_patch_accounts_ID, 814 .have_id_segment = true, 815 /* allow account details of up to 8 kb, that should be plenty */ 816 .max_upload = 1024 * 8 817 }, 818 /* GET /accounts: */ 819 { 820 .url_prefix = "/accounts", 821 .permission = "accounts-read", 822 .method = MHD_HTTP_METHOD_GET, 823 .handler = &TMH_private_get_accounts 824 }, 825 /* GET /accounts/$H_WIRE: */ 826 { 827 .url_prefix = "/accounts/", 828 .permission = "accounts-read", 829 .method = MHD_HTTP_METHOD_GET, 830 .have_id_segment = true, 831 .handler = &TMH_private_get_accounts_ID 832 }, 833 /* DELETE /accounts/$H_WIRE: */ 834 { 835 .url_prefix = "/accounts/", 836 .permission = "accounts-write", 837 .method = MHD_HTTP_METHOD_DELETE, 838 .handler = &TMH_private_delete_account_ID, 839 .have_id_segment = true 840 }, 841 /* GET /tokens: */ 842 { 843 .url_prefix = "/tokens", 844 .permission = "tokens-read", 845 .method = MHD_HTTP_METHOD_GET, 846 .handler = &TMH_private_get_instances_ID_tokens, 847 }, 848 /* POST /token: */ 849 { 850 .url_prefix = "/token", 851 .permission = "token-refresh", 852 .method = MHD_HTTP_METHOD_POST, 853 .handler = &TMH_private_post_instances_ID_token, 854 /* Body should be tiny. */ 855 .max_upload = 1024 856 }, 857 /* DELETE /tokens/$SERIAL: */ 858 { 859 .url_prefix = "/tokens/", 860 .permission = "tokens-write", 861 .method = MHD_HTTP_METHOD_DELETE, 862 .handler = &TMH_private_delete_instances_ID_token_SERIAL, 863 .have_id_segment = true 864 }, 865 /* DELETE /token: */ 866 { 867 .url_prefix = "/token", 868 .method = MHD_HTTP_METHOD_DELETE, 869 .handler = &TMH_private_delete_instances_ID_token, 870 }, 871 /* GET /tokenfamilies: */ 872 { 873 .url_prefix = "/tokenfamilies", 874 .permission = "tokenfamilies-read", 875 .method = MHD_HTTP_METHOD_GET, 876 .handler = &TMH_private_get_tokenfamilies 877 }, 878 /* POST /tokenfamilies: */ 879 { 880 .url_prefix = "/tokenfamilies", 881 .permission = "tokenfamilies-write", 882 .method = MHD_HTTP_METHOD_POST, 883 .handler = &TMH_private_post_token_families 884 }, 885 /* GET /tokenfamilies/$SLUG/: */ 886 { 887 .url_prefix = "/tokenfamilies/", 888 .method = MHD_HTTP_METHOD_GET, 889 .permission = "tokenfamilies-read", 890 .have_id_segment = true, 891 .handler = &TMH_private_get_tokenfamilies_SLUG 892 }, 893 /* DELETE /tokenfamilies/$SLUG/: */ 894 { 895 .url_prefix = "/tokenfamilies/", 896 .method = MHD_HTTP_METHOD_DELETE, 897 .permission = "tokenfamilies-write", 898 .have_id_segment = true, 899 .handler = &TMH_private_delete_token_families_SLUG 900 }, 901 /* PATCH /tokenfamilies/$SLUG/: */ 902 { 903 .url_prefix = "/tokenfamilies/", 904 .method = MHD_HTTP_METHOD_PATCH, 905 .permission = "tokenfamilies-write", 906 .have_id_segment = true, 907 .handler = &TMH_private_patch_token_family_SLUG, 908 }, 909 910 /* Reports endpoints */ 911 { 912 .url_prefix = "/reports", 913 .method = MHD_HTTP_METHOD_GET, 914 .permission = "reports-read", 915 .handler = &TMH_private_get_reports, 916 }, 917 { 918 .url_prefix = "/reports", 919 .method = MHD_HTTP_METHOD_POST, 920 .permission = "reports-write", 921 .handler = &TMH_private_post_reports, 922 }, 923 { 924 .url_prefix = "/reports/", 925 .method = MHD_HTTP_METHOD_GET, 926 .handler = &TMH_private_get_report, 927 .permission = "reports-read", 928 .have_id_segment = true, 929 }, 930 { 931 .url_prefix = "/reports/", 932 .method = MHD_HTTP_METHOD_PATCH, 933 .handler = &TMH_private_patch_report, 934 .permission = "reports-write", 935 .have_id_segment = true, 936 }, 937 { 938 .url_prefix = "/reports/", 939 .method = MHD_HTTP_METHOD_DELETE, 940 .handler = &TMH_private_delete_report, 941 .permission = "reports-write", 942 .have_id_segment = true, 943 }, 944 945 /* Groups endpoints */ 946 { 947 .url_prefix = "/groups", 948 .method = MHD_HTTP_METHOD_GET, 949 .permission = "groups-read", 950 .handler = &TMH_private_get_groups, 951 }, 952 { 953 .url_prefix = "/groups", 954 .method = MHD_HTTP_METHOD_POST, 955 .permission = "groups-write", 956 .handler = &TMH_private_post_groups, 957 }, 958 { 959 .url_prefix = "/groups/", 960 .method = MHD_HTTP_METHOD_PATCH, 961 .handler = &TMH_private_patch_group, 962 .permission = "groups-write", 963 .have_id_segment = true, 964 }, 965 { 966 .url_prefix = "/groups/", 967 .method = MHD_HTTP_METHOD_DELETE, 968 .handler = &TMH_private_delete_group, 969 .permission = "groups-write", 970 .have_id_segment = true, 971 }, 972 973 /* Money pots endpoints */ 974 { 975 .url_prefix = "/pots", 976 .method = MHD_HTTP_METHOD_GET, 977 .handler = &TMH_private_get_pots, 978 .permission = "pots-read", 979 }, 980 { 981 .url_prefix = "/pots", 982 .method = MHD_HTTP_METHOD_POST, 983 .handler = &TMH_private_post_pots, 984 .permission = "pots-write" 985 }, 986 { 987 .url_prefix = "/pots/", 988 .method = MHD_HTTP_METHOD_GET, 989 .handler = &TMH_private_get_pot, 990 .have_id_segment = true, 991 .permission = "pots-read", 992 }, 993 { 994 .url_prefix = "/pots/", 995 .method = MHD_HTTP_METHOD_PATCH, 996 .handler = &TMH_private_patch_pot, 997 .have_id_segment = true, 998 .permission = "pots-write" 999 }, 1000 { 1001 .url_prefix = "/pots/", 1002 .method = MHD_HTTP_METHOD_DELETE, 1003 .handler = &TMH_private_delete_pot, 1004 .have_id_segment = true, 1005 .permission = "pots-write" 1006 }, 1007 1008 1009 #ifdef HAVE_DONAU_DONAU_SERVICE_H 1010 /* GET /donau */ 1011 { 1012 .url_prefix = "/donau", 1013 .method = MHD_HTTP_METHOD_GET, 1014 .handler = &TMH_private_get_donau_instances 1015 }, 1016 /* POST /donau */ 1017 { 1018 .url_prefix = "/donau", 1019 .method = MHD_HTTP_METHOD_POST, 1020 .handler = &TMH_private_post_donau_instance 1021 }, 1022 /* DELETE /donau/$charity-id */ 1023 { 1024 .url_prefix = "/donau/", 1025 .method = MHD_HTTP_METHOD_DELETE, 1026 .have_id_segment = true, 1027 .handler = &TMH_private_delete_donau_instance_ID 1028 }, 1029 #endif 1030 /* GET /statistics-counter/$SLUG: */ 1031 { 1032 .url_prefix = "/statistics-counter/", 1033 .method = MHD_HTTP_METHOD_GET, 1034 .permission = "statistics-read", 1035 .have_id_segment = true, 1036 .handler = &TMH_private_get_statistics_counter_SLUG, 1037 }, 1038 /* GET /statistics-amount/$SLUG: */ 1039 { 1040 .url_prefix = "/statistics-amount/", 1041 .method = MHD_HTTP_METHOD_GET, 1042 .permission = "statistics-read", 1043 .have_id_segment = true, 1044 .handler = &TMH_private_get_statistics_amount_SLUG, 1045 }, 1046 /* GET /statistics-report/transactions: */ 1047 { 1048 .url_prefix = "/statistics-report/", 1049 .url_suffix = "transactions", 1050 .method = MHD_HTTP_METHOD_GET, 1051 .permission = "statistics-read", 1052 .handler = &TMH_private_get_statistics_report_transactions, 1053 }, 1054 { 1055 .url_prefix = NULL 1056 } 1057 }; 1058 static struct TMH_RequestHandler public_handlers[] = { 1059 { 1060 /* for "admin" instance, it does not even 1061 have to exist before we give the WebUI */ 1062 .url_prefix = "/", 1063 .method = MHD_HTTP_METHOD_GET, 1064 .mime_type = "text/html", 1065 .skip_instance = true, 1066 .default_only = true, 1067 .handler = &spa_redirect, 1068 .response_code = MHD_HTTP_FOUND 1069 }, 1070 { 1071 .url_prefix = "/config", 1072 .method = MHD_HTTP_METHOD_GET, 1073 .skip_instance = true, 1074 .default_only = true, 1075 .handler = &MH_handler_config 1076 }, 1077 { 1078 .url_prefix = "/exchanges", 1079 .method = MHD_HTTP_METHOD_GET, 1080 .skip_instance = true, 1081 .default_only = true, 1082 .handler = &MH_handler_exchanges 1083 }, 1084 { 1085 /* for "normal" instance,s they must exist 1086 before we give the WebUI */ 1087 .url_prefix = "/", 1088 .method = MHD_HTTP_METHOD_GET, 1089 .mime_type = "text/html", 1090 .handler = &spa_redirect, 1091 .response_code = MHD_HTTP_FOUND 1092 }, 1093 { 1094 .url_prefix = "/webui/", 1095 .method = MHD_HTTP_METHOD_GET, 1096 .mime_type = "text/html", 1097 .skip_instance = true, 1098 .have_id_segment = true, 1099 .handler = &TMH_return_spa, 1100 .response_code = MHD_HTTP_OK 1101 }, 1102 { 1103 .url_prefix = "/agpl", 1104 .method = MHD_HTTP_METHOD_GET, 1105 .skip_instance = true, 1106 .handler = &TMH_MHD_handler_agpl_redirect 1107 }, 1108 { 1109 .url_prefix = "/agpl", 1110 .method = MHD_HTTP_METHOD_GET, 1111 .skip_instance = true, 1112 .handler = &TMH_MHD_handler_agpl_redirect 1113 }, 1114 { 1115 .url_prefix = "/terms", 1116 .method = MHD_HTTP_METHOD_GET, 1117 .skip_instance = true, 1118 .handler = &TMH_handler_terms 1119 }, 1120 { 1121 .url_prefix = "/privacy", 1122 .method = MHD_HTTP_METHOD_GET, 1123 .skip_instance = true, 1124 .handler = &TMH_handler_privacy 1125 }, 1126 /* Also serve the same /config per instance */ 1127 { 1128 .url_prefix = "/config", 1129 .method = MHD_HTTP_METHOD_GET, 1130 .handler = &MH_handler_config 1131 }, 1132 /* POST /orders/$ID/abort: */ 1133 { 1134 .url_prefix = "/orders/", 1135 .have_id_segment = true, 1136 .url_suffix = "abort", 1137 .method = MHD_HTTP_METHOD_POST, 1138 .handler = &TMH_post_orders_ID_abort, 1139 /* wallet may give us many coins to sign, allow 1 MB of upload 1140 to set a conservative bound for sane wallets */ 1141 .max_upload = 1024 * 1024 1142 }, 1143 /* POST /orders/$ID/claim: */ 1144 { 1145 .url_prefix = "/orders/", 1146 .have_id_segment = true, 1147 .url_suffix = "claim", 1148 .method = MHD_HTTP_METHOD_POST, 1149 .handler = &TMH_post_orders_ID_claim, 1150 /* the body should be pretty small, allow 1 MB of upload 1151 to set a conservative bound for sane wallets */ 1152 .max_upload = 1024 * 1024 1153 }, 1154 /* POST /orders/$ID/unclaim: */ 1155 { 1156 .url_prefix = "/orders/", 1157 .have_id_segment = true, 1158 .url_suffix = "unclaim", 1159 .method = MHD_HTTP_METHOD_POST, 1160 .handler = &TMH_post_orders_ID_unclaim, 1161 /* the body should be very small */ 1162 .max_upload = 1024 1163 }, 1164 /* POST /orders/$ID/pay: */ 1165 { 1166 .url_prefix = "/orders/", 1167 .have_id_segment = true, 1168 .url_suffix = "pay", 1169 .method = MHD_HTTP_METHOD_POST, 1170 .handler = &TMH_post_orders_ID_pay, 1171 /* wallet may give us many coins to sign, allow 1 MB of upload 1172 to set a conservative bound for sane wallets */ 1173 .max_upload = 1024 * 1024 1174 }, 1175 /* POST /orders/$ID/paid: */ 1176 { 1177 .url_prefix = "/orders/", 1178 .have_id_segment = true, 1179 .allow_deleted_instance = true, 1180 .url_suffix = "paid", 1181 .method = MHD_HTTP_METHOD_POST, 1182 .handler = &TMH_post_orders_ID_paid, 1183 /* the body should be pretty small, allow 1 MB of upload 1184 to set a conservative bound for sane wallets */ 1185 .max_upload = 1024 * 1024 1186 }, 1187 /* POST /orders/$ID/refund: */ 1188 { 1189 .url_prefix = "/orders/", 1190 .have_id_segment = true, 1191 .allow_deleted_instance = true, 1192 .url_suffix = "refund", 1193 .method = MHD_HTTP_METHOD_POST, 1194 .handler = &TMH_post_orders_ID_refund, 1195 /* the body should be pretty small, allow 1 MB of upload 1196 to set a conservative bound for sane wallets */ 1197 .max_upload = 1024 * 1024 1198 }, 1199 /* GET /orders/$ID: */ 1200 { 1201 .url_prefix = "/orders/", 1202 .method = MHD_HTTP_METHOD_GET, 1203 .allow_deleted_instance = true, 1204 .have_id_segment = true, 1205 .handler = &TMH_get_orders_ID 1206 }, 1207 /* GET /sessions/$ID: */ 1208 { 1209 .url_prefix = "/sessions/", 1210 .method = MHD_HTTP_METHOD_GET, 1211 .allow_deleted_instance = true, 1212 .have_id_segment = true, 1213 .handler = &TMH_get_sessions_ID 1214 }, 1215 /* GET /static/ *: */ 1216 { 1217 .url_prefix = "/static/", 1218 .method = MHD_HTTP_METHOD_GET, 1219 .have_id_segment = true, 1220 .handler = &TMH_return_static 1221 }, 1222 /* POST /reports/$ID/ */ 1223 { 1224 .url_prefix = "/reports/", 1225 .method = MHD_HTTP_METHOD_POST, 1226 .have_id_segment = true, 1227 .handler = &TMH_post_reports_ID, 1228 }, 1229 /* GET /templates/$ID/: */ 1230 { 1231 .url_prefix = "/templates/", 1232 .method = MHD_HTTP_METHOD_GET, 1233 .have_id_segment = true, 1234 .handler = &TMH_get_templates_ID 1235 }, 1236 /* GET /products/$HASH/image: */ 1237 { 1238 .url_prefix = "/products/", 1239 .method = MHD_HTTP_METHOD_GET, 1240 .have_id_segment = true, 1241 .allow_deleted_instance = true, 1242 .url_suffix = "image", 1243 .handler = &TMH_get_products_image 1244 }, 1245 /* POST /templates/$ID: */ 1246 { 1247 .url_prefix = "/templates/", 1248 .method = MHD_HTTP_METHOD_POST, 1249 .have_id_segment = true, 1250 .handler = &TMH_post_using_templates_ID, 1251 .max_upload = 1024 * 1024 1252 }, 1253 /* POST /challenge/$ID: */ 1254 { 1255 .url_prefix = "/challenge/", 1256 .method = MHD_HTTP_METHOD_POST, 1257 .have_id_segment = true, 1258 .handler = &TMH_post_challenge_ID, 1259 .max_upload = 1024 1260 }, 1261 /* POST /challenge/$ID/confirm: */ 1262 { 1263 .url_prefix = "/challenge/", 1264 .method = MHD_HTTP_METHOD_POST, 1265 .have_id_segment = true, 1266 .url_suffix = "confirm", 1267 .handler = &TMH_post_challenge_ID_confirm, 1268 .max_upload = 1024 1269 }, 1270 /* POST /instances */ 1271 { 1272 .url_prefix = "/instances", 1273 .method = MHD_HTTP_METHOD_POST, 1274 .skip_instance = true, 1275 .default_only = true, 1276 .handler = &TMH_public_post_instances, 1277 /* allow instance data of up to 8 MB, that should be plenty; 1278 note that exceeding #GNUNET_MAX_MALLOC_CHECKED (40 MB) 1279 would require further changes to the allocation logic 1280 in the code... */ 1281 .max_upload = 1024 * 1024 * 8 1282 }, 1283 /* POST /forgot-password: */ 1284 { 1285 .url_prefix = "/forgot-password", 1286 .method = MHD_HTTP_METHOD_POST, 1287 .handler = &TMH_public_post_instances_ID_auth, 1288 /* Body should be pretty small. */ 1289 .max_upload = 1024 * 1024 1290 }, 1291 1292 { 1293 .url_prefix = "*", 1294 .method = MHD_HTTP_METHOD_OPTIONS, 1295 .handler = &handle_server_options 1296 }, 1297 { 1298 .url_prefix = NULL 1299 } 1300 }; 1301 const char *management_prefix = "/management/"; 1302 const char *private_prefix = "/private/"; 1303 const char *url = *urlp; 1304 struct TMH_RequestHandler *handlers; 1305 1306 *is_public = false; /* ensure safe default */ 1307 if ( (0 == strncmp (url, 1308 management_prefix, 1309 strlen (management_prefix))) ) 1310 { 1311 handlers = management_handlers; 1312 *urlp = url + strlen (management_prefix) - 1; 1313 } 1314 else if ( (0 == strncmp (url, 1315 private_prefix, 1316 strlen (private_prefix))) || 1317 (0 == strcmp (url, 1318 "/private")) ) 1319 { 1320 handlers = private_handlers; 1321 if (0 == strcmp (url, 1322 "/private")) 1323 *urlp = "/"; 1324 else 1325 *urlp = url + strlen (private_prefix) - 1; 1326 } 1327 else 1328 { 1329 handlers = public_handlers; 1330 *is_public = true; 1331 } 1332 return handlers; 1333 } 1334 1335 1336 /** 1337 * Checks if the @a rh matches the given (parsed) URL. 1338 * 1339 * @param rh handler to compare against 1340 * @param url the main URL (without "/private/" prefix, if any) 1341 * @param prefix_strlen length of the prefix, i.e. 8 for '/orders/' or 7 for '/config' 1342 * @param infix_url infix text, i.e. "$ORDER_ID". 1343 * @param infix_strlen length of the string in @a infix_url 1344 * @param suffix_url suffix, i.e. "/refund", including the "/" 1345 * @param suffix_strlen number of characters in @a suffix_url 1346 * @return true if @a rh matches this request 1347 */ 1348 static bool 1349 prefix_match (const struct TMH_RequestHandler *rh, 1350 const char *url, 1351 size_t prefix_strlen, 1352 const char *infix_url, 1353 size_t infix_strlen, 1354 const char *suffix_url, 1355 size_t suffix_strlen) 1356 { 1357 if ( (prefix_strlen != strlen (rh->url_prefix)) || 1358 (0 != memcmp (url, 1359 rh->url_prefix, 1360 prefix_strlen)) ) 1361 return false; 1362 if (! rh->have_id_segment) 1363 { 1364 /* Require /$PREFIX/$SUFFIX or /$PREFIX */ 1365 if (NULL != suffix_url) 1366 return false; /* too many segments to match */ 1367 if ( (NULL == infix_url) /* either or */ 1368 ^ (NULL == rh->url_suffix) ) 1369 return false; /* suffix existence mismatch */ 1370 /* If /$PREFIX/$SUFFIX, check $SUFFIX matches */ 1371 if ( (NULL != infix_url) && 1372 ( (infix_strlen != strlen (rh->url_suffix)) || 1373 (0 != memcmp (infix_url, 1374 rh->url_suffix, 1375 infix_strlen)) ) ) 1376 return false; /* cannot use infix as suffix: content mismatch */ 1377 } 1378 else 1379 { 1380 /* Require /$PREFIX/$ID or /$PREFIX/$ID/$SUFFIX */ 1381 if (NULL == infix_url) 1382 return false; /* infix existence mismatch */ 1383 if ( ( (NULL == suffix_url) 1384 ^ (NULL == rh->url_suffix) ) ) 1385 return false; /* suffix existence mismatch */ 1386 if ( (NULL != suffix_url) && 1387 ( (suffix_strlen != strlen (rh->url_suffix)) || 1388 (0 != memcmp (suffix_url, 1389 rh->url_suffix, 1390 suffix_strlen)) ) ) 1391 return false; /* suffix content mismatch */ 1392 } 1393 return true; 1394 } 1395 1396 1397 /** 1398 * Identify the handler of the request from the @a url and @a method 1399 * 1400 * @param[in,out] hc handler context to update with applicable handler 1401 * @param handlers array of handlers to consider 1402 * @param url URL to match against the handlers 1403 * @param method HTTP access method to consider 1404 * @param use_admin set to true if we are using the admin instance 1405 * @return #GNUNET_OK on success, 1406 * #GNUNET_NO if an error was queued (return #MHD_YES) 1407 * #GNUNET_SYSERR to close the connection (return #MHD_NO) 1408 */ 1409 static enum GNUNET_GenericReturnValue 1410 identify_handler (struct TMH_HandlerContext *hc, 1411 const struct TMH_RequestHandler *handlers, 1412 const char *url, 1413 const char *method, 1414 bool use_admin) 1415 { 1416 size_t prefix_strlen; /* i.e. 8 for "/orders/", or 7 for "/config" */ 1417 const char *infix_url = NULL; /* i.e. "$ORDER_ID", no '/'-es */ 1418 size_t infix_strlen = 0; /* number of characters in infix_url */ 1419 const char *suffix_url = NULL; /* i.e. "refund", excludes '/' at the beginning */ 1420 size_t suffix_strlen = 0; /* number of characters in suffix_url */ 1421 1422 if (0 == strcasecmp (method, 1423 MHD_HTTP_METHOD_HEAD)) 1424 method = MHD_HTTP_METHOD_GET; /* MHD will deal with the rest */ 1425 if (0 == strcmp (url, 1426 "")) 1427 url = "/"; /* code below does not like empty string */ 1428 1429 /* parse the URL into the three different components */ 1430 { 1431 const char *slash; 1432 1433 slash = strchr (&url[1], '/'); 1434 if (NULL == slash) 1435 { 1436 /* the prefix was everything */ 1437 prefix_strlen = strlen (url); 1438 } 1439 else 1440 { 1441 prefix_strlen = slash - url + 1; /* includes both '/'-es if present! */ 1442 infix_url = slash + 1; 1443 slash = strchr (infix_url, '/'); 1444 if (NULL == slash) 1445 { 1446 /* the infix was the rest */ 1447 infix_strlen = strlen (infix_url); 1448 } 1449 else 1450 { 1451 infix_strlen = slash - infix_url; /* excludes both '/'-es */ 1452 suffix_url = slash + 1; /* skip the '/' */ 1453 suffix_strlen = strlen (suffix_url); 1454 } 1455 hc->infix = GNUNET_strndup (infix_url, 1456 infix_strlen); 1457 } 1458 } 1459 1460 /* find matching handler */ 1461 { 1462 bool url_found = false; 1463 1464 for (unsigned int i = 0; NULL != handlers[i].url_prefix; i++) 1465 { 1466 const struct TMH_RequestHandler *rh = &handlers[i]; 1467 1468 if (rh->default_only && (! use_admin)) 1469 continue; 1470 if (! prefix_match (rh, 1471 url, 1472 prefix_strlen, 1473 infix_url, 1474 infix_strlen, 1475 suffix_url, 1476 suffix_strlen)) 1477 continue; 1478 url_found = true; 1479 if (0 == strcasecmp (method, 1480 MHD_HTTP_METHOD_OPTIONS)) 1481 { 1482 return (MHD_YES == 1483 TALER_MHD_reply_cors_preflight (hc->connection)) 1484 ? GNUNET_NO 1485 : GNUNET_SYSERR; 1486 } 1487 if ( (rh->method != NULL) && 1488 (0 != strcasecmp (method, 1489 rh->method)) ) 1490 continue; 1491 hc->rh = rh; 1492 break; 1493 } 1494 /* Handle HTTP 405: METHOD NOT ALLOWED case */ 1495 if ( (NULL == hc->rh) && 1496 (url_found) ) 1497 { 1498 struct MHD_Response *reply; 1499 MHD_RESULT ret; 1500 char *allowed = NULL; 1501 1502 GNUNET_break_op (0); 1503 /* compute 'Allowed:' header (required by HTTP spec for 405 replies) */ 1504 for (unsigned int i = 0; NULL != handlers[i].url_prefix; i++) 1505 { 1506 const struct TMH_RequestHandler *rh = &handlers[i]; 1507 1508 if (rh->default_only && (! use_admin)) 1509 continue; 1510 if (! prefix_match (rh, 1511 url, 1512 prefix_strlen, 1513 infix_url, 1514 infix_strlen, 1515 suffix_url, 1516 suffix_strlen)) 1517 continue; 1518 if (NULL == allowed) 1519 { 1520 allowed = GNUNET_strdup (rh->method); 1521 } 1522 else 1523 { 1524 char *tmp; 1525 1526 GNUNET_asprintf (&tmp, 1527 "%s, %s", 1528 allowed, 1529 rh->method); 1530 GNUNET_free (allowed); 1531 allowed = tmp; 1532 } 1533 if (0 == strcasecmp (rh->method, 1534 MHD_HTTP_METHOD_GET)) 1535 { 1536 char *tmp; 1537 1538 GNUNET_asprintf (&tmp, 1539 "%s, %s", 1540 allowed, 1541 MHD_HTTP_METHOD_HEAD); 1542 GNUNET_free (allowed); 1543 allowed = tmp; 1544 } 1545 } 1546 reply = TALER_MHD_make_error (TALER_EC_GENERIC_METHOD_INVALID, 1547 method); 1548 GNUNET_break (MHD_YES == 1549 MHD_add_response_header (reply, 1550 MHD_HTTP_HEADER_ALLOW, 1551 allowed)); 1552 GNUNET_free (allowed); 1553 ret = MHD_queue_response (hc->connection, 1554 MHD_HTTP_METHOD_NOT_ALLOWED, 1555 reply); 1556 MHD_destroy_response (reply); 1557 return (MHD_YES == ret) 1558 ? GNUNET_NO 1559 : GNUNET_SYSERR; 1560 } 1561 if (NULL == hc->rh) 1562 { 1563 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1564 "Endpoint `%s' not known\n", 1565 hc->url); 1566 return (MHD_YES == 1567 TALER_MHD_reply_with_error (hc->connection, 1568 MHD_HTTP_NOT_FOUND, 1569 TALER_EC_GENERIC_ENDPOINT_UNKNOWN, 1570 hc->url)) 1571 ? GNUNET_NO 1572 : GNUNET_SYSERR; 1573 } 1574 } 1575 return GNUNET_OK; 1576 } 1577 1578 1579 enum GNUNET_GenericReturnValue 1580 TMH_dispatch_request (struct TMH_HandlerContext *hc, 1581 const char *url, 1582 const char *method, 1583 bool use_admin, 1584 bool *is_public) 1585 { 1586 const struct TMH_RequestHandler *handlers; 1587 1588 *is_public = false; 1589 handlers = determine_handler_group (&url, 1590 is_public); 1591 return identify_handler (hc, 1592 handlers, 1593 url, 1594 method, 1595 use_admin); 1596 }