web_server.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #define WEB_SERVER_INTERNALS 1
  3. #include "web_server.h"
  4. // this file includes 3 web servers:
  5. //
  6. // 1. single-threaded, based on select()
  7. // 2. multi-threaded, based on poll() that spawns threads to handle the requests, based on select()
  8. // 3. static-threaded, based on poll() using a fixed number of threads (configured at netdata.conf)
  9. WEB_SERVER_MODE web_server_mode = WEB_SERVER_MODE_STATIC_THREADED;
  10. // --------------------------------------------------------------------------------------
  11. WEB_SERVER_MODE web_server_mode_id(const char *mode) {
  12. if(!strcmp(mode, "none"))
  13. return WEB_SERVER_MODE_NONE;
  14. else if(!strcmp(mode, "single") || !strcmp(mode, "single-threaded"))
  15. return WEB_SERVER_MODE_SINGLE_THREADED;
  16. else if(!strcmp(mode, "static") || !strcmp(mode, "static-threaded"))
  17. return WEB_SERVER_MODE_STATIC_THREADED;
  18. else // if(!strcmp(mode, "multi") || !strcmp(mode, "multi-threaded"))
  19. return WEB_SERVER_MODE_MULTI_THREADED;
  20. }
  21. const char *web_server_mode_name(WEB_SERVER_MODE id) {
  22. switch(id) {
  23. case WEB_SERVER_MODE_NONE:
  24. return "none";
  25. case WEB_SERVER_MODE_SINGLE_THREADED:
  26. return "single-threaded";
  27. case WEB_SERVER_MODE_STATIC_THREADED:
  28. return "static-threaded";
  29. default:
  30. case WEB_SERVER_MODE_MULTI_THREADED:
  31. return "multi-threaded";
  32. }
  33. }
  34. // --------------------------------------------------------------------------------------
  35. // API sockets
  36. LISTEN_SOCKETS api_sockets = {
  37. .config = &netdata_config,
  38. .config_section = CONFIG_SECTION_WEB,
  39. .default_bind_to = "*",
  40. .default_port = API_LISTEN_PORT,
  41. .backlog = API_LISTEN_BACKLOG
  42. };
  43. int api_listen_sockets_setup(void) {
  44. int socks = listen_sockets_setup(&api_sockets);
  45. if(!socks)
  46. fatal("LISTENER: Cannot listen on any API socket. Exiting...");
  47. return socks;
  48. }
  49. // --------------------------------------------------------------------------------------
  50. // access lists
  51. SIMPLE_PATTERN *web_allow_connections_from = NULL;
  52. SIMPLE_PATTERN *web_allow_streaming_from = NULL;
  53. SIMPLE_PATTERN *web_allow_netdataconf_from = NULL;
  54. // WEB_CLIENT_ACL
  55. SIMPLE_PATTERN *web_allow_dashboard_from = NULL;
  56. SIMPLE_PATTERN *web_allow_registry_from = NULL;
  57. SIMPLE_PATTERN *web_allow_badges_from = NULL;
  58. void web_client_update_acl_matches(struct web_client *w) {
  59. w->acl = WEB_CLIENT_ACL_NONE;
  60. if(!web_allow_dashboard_from || simple_pattern_matches(web_allow_dashboard_from, w->client_ip))
  61. w->acl |= WEB_CLIENT_ACL_DASHBOARD;
  62. if(!web_allow_registry_from || simple_pattern_matches(web_allow_registry_from, w->client_ip))
  63. w->acl |= WEB_CLIENT_ACL_REGISTRY;
  64. if(!web_allow_badges_from || simple_pattern_matches(web_allow_badges_from, w->client_ip))
  65. w->acl |= WEB_CLIENT_ACL_BADGE;
  66. }
  67. // --------------------------------------------------------------------------------------
  68. void web_server_log_connection(struct web_client *w, const char *msg) {
  69. log_access("%llu: %d '[%s]:%s' '%s'", w->id, gettid(), w->client_ip, w->client_port, msg);
  70. }
  71. // --------------------------------------------------------------------------------------
  72. void web_client_initialize_connection(struct web_client *w) {
  73. int flag = 1;
  74. if(unlikely(web_client_check_tcp(w) && setsockopt(w->ifd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0))
  75. debug(D_WEB_CLIENT, "%llu: failed to enable TCP_NODELAY on socket fd %d.", w->id, w->ifd);
  76. flag = 1;
  77. if(unlikely(setsockopt(w->ifd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)) != 0))
  78. debug(D_WEB_CLIENT, "%llu: failed to enable SO_KEEPALIVE on socket fd %d.", w->id, w->ifd);
  79. web_client_update_acl_matches(w);
  80. w->origin[0] = '*'; w->origin[1] = '\0';
  81. w->cookie1[0] = '\0'; w->cookie2[0] = '\0';
  82. freez(w->user_agent); w->user_agent = NULL;
  83. web_client_enable_wait_receive(w);
  84. web_server_log_connection(w, "CONNECTED");
  85. web_client_cache_verify(0);
  86. }
  87. struct web_client *web_client_create_on_listenfd(int listener) {
  88. struct web_client *w;
  89. w = web_client_get_from_cache_or_allocate();
  90. w->ifd = w->ofd = accept_socket(listener, SOCK_NONBLOCK, w->client_ip, sizeof(w->client_ip), w->client_port, sizeof(w->client_port), web_allow_connections_from);
  91. if(unlikely(!*w->client_ip)) strcpy(w->client_ip, "-");
  92. if(unlikely(!*w->client_port)) strcpy(w->client_port, "-");
  93. if (w->ifd == -1) {
  94. if(errno == EPERM)
  95. web_server_log_connection(w, "ACCESS DENIED");
  96. else {
  97. web_server_log_connection(w, "CONNECTION FAILED");
  98. error("%llu: Failed to accept new incoming connection.", w->id);
  99. }
  100. web_client_release(w);
  101. return NULL;
  102. }
  103. web_client_initialize_connection(w);
  104. return(w);
  105. }