summaryrefslogtreecommitdiffstats
path: root/src/web/server/web_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/web/server/web_client.c')
-rw-r--r--src/web/server/web_client.c166
1 files changed, 66 insertions, 100 deletions
diff --git a/src/web/server/web_client.c b/src/web/server/web_client.c
index ca1c28e7f..8a79b61f0 100644
--- a/src/web/server/web_client.c
+++ b/src/web/server/web_client.c
@@ -6,7 +6,7 @@
// it is used by all netdata web servers
int respect_web_browser_do_not_track_policy = 0;
-char *web_x_frame_options = NULL;
+const char *web_x_frame_options = NULL;
int web_enable_gzip = 1, web_gzip_level = 3, web_gzip_strategy = Z_DEFAULT_STRATEGY;
@@ -33,6 +33,7 @@ void web_client_set_conn_webrtc(struct web_client *w) {
void web_client_reset_permissions(struct web_client *w) {
web_client_flags_clear_auth(w);
w->access = HTTP_ACCESS_NONE;
+ w->user_role = HTTP_USER_ROLE_NONE;
}
void web_client_set_permissions(struct web_client *w, HTTP_ACCESS access, HTTP_USER_ROLE role, WEB_CLIENT_FLAGS auth) {
@@ -97,7 +98,6 @@ static inline int web_client_cork_socket(struct web_client *w __maybe_unused) {
return 0;
}
-#ifdef ENABLE_HTTPS
static inline void web_client_enable_wait_from_ssl(struct web_client *w) {
if (w->ssl.ssl_errno == SSL_ERROR_WANT_READ)
web_client_enable_ssl_wait_receive(w);
@@ -108,7 +108,6 @@ static inline void web_client_enable_wait_from_ssl(struct web_client *w) {
web_client_disable_ssl_wait_send(w);
}
}
-#endif
static inline int web_client_uncork_socket(struct web_client *w __maybe_unused) {
#ifdef TCP_CORK
@@ -211,6 +210,8 @@ static void web_client_reset_allocations(struct web_client *w, bool free_all) {
}
memset(w->transaction, 0, sizeof(w->transaction));
+ memset(&w->auth, 0, sizeof(w->auth));
+
web_client_reset_permissions(w);
web_client_flag_clear(w, WEB_CLIENT_ENCODING_GZIP|WEB_CLIENT_ENCODING_DEFLATE);
web_client_reset_path_flags(w);
@@ -380,12 +381,14 @@ static inline int dashboard_version(struct web_client *w) {
if(!web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_WITH_VERSION))
return -1;
- if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_IS_V0))
- return 0;
- if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_IS_V1))
- return 1;
+ if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_IS_V3))
+ return 3;
if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_IS_V2))
return 2;
+ if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_IS_V1))
+ return 1;
+ if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_IS_V0))
+ return 0;
return -1;
}
@@ -548,7 +551,8 @@ static int mysendfile(struct web_client *w, char *filename) {
w->response.data->date = statbuf.st_mtimespec.tv_sec;
#else
w->response.data->date = statbuf.st_mtim.tv_sec;
-#endif
+#endif
+ w->response.data->expires = now_realtime_sec() + 86400;
buffer_cacheable(w->response.data);
return HTTP_RESP_OK;
@@ -589,7 +593,9 @@ int web_client_api_request(RRDHOST *host, struct web_client *w, char *url_path_f
// get the api version
char *tok = strsep_skip_consecutive_separators(&url_path_fragment, "/");
if(tok && *tok) {
- if(strcmp(tok, "v2") == 0)
+ if(strcmp(tok, "v3") == 0)
+ return web_client_api_request_v3(host, w, url_path_fragment);
+ else if(strcmp(tok, "v2") == 0)
return web_client_api_request_v2(host, w, url_path_fragment);
else if(strcmp(tok, "v1") == 0)
return web_client_api_request_v1(host, w, url_path_fragment);
@@ -644,7 +650,6 @@ static inline char *web_client_valid_method(struct web_client *w, char *s) {
else if(!strncmp(s, "STREAM ", 7)) {
s = &s[7];
-#ifdef ENABLE_HTTPS
if (!SSL_connection(&w->ssl) && http_is_using_ssl_force(w)) {
w->header_parse_tries = 0;
w->header_parse_last_size = 0;
@@ -672,7 +677,6 @@ static inline char *web_client_valid_method(struct web_client *w, char *s) {
netdata_log_error("The server is configured to always use encrypted connections, please enable the SSL on child with hostname '%s'.",hostname);
s = NULL;
}
-#endif
w->mode = HTTP_REQUEST_MODE_STREAM;
}
@@ -704,11 +708,12 @@ HTTP_VALIDATION http_request_validate(struct web_client *w) {
if(last_pos > 4) last_pos -= 4; // allow searching for \r\n\r\n
else last_pos = 0;
- if(w->header_parse_last_size < last_pos)
+ if(w->header_parse_last_size <= last_pos)
last_pos = 0;
- is_it_valid =
- url_is_request_complete_and_extract_payload(s, &s[last_pos], w->header_parse_last_size, &w->payload);
+ is_it_valid = url_is_request_complete_and_extract_payload(s, &s[last_pos],
+ w->header_parse_last_size, &w->payload);
+
if(!is_it_valid) {
if(w->header_parse_tries > HTTP_REQ_MAX_HEADER_FETCH_TRIES) {
netdata_log_info("Disabling slow client after %zu attempts to read the request (%zu bytes received)", w->header_parse_tries, buffer_strlen(w->response.data));
@@ -736,17 +741,6 @@ HTTP_VALIDATION http_request_validate(struct web_client *w) {
return HTTP_VALIDATION_NOT_SUPPORTED;
} else if (!is_it_valid) {
- //Invalid request, we have more data after the end of message
- char *check = strstr((char *)buffer_tostring(w->response.data), "\r\n\r\n");
- if(check) {
- check += 4;
- if (*check) {
- w->header_parse_tries = 0;
- w->header_parse_last_size = 0;
- web_client_disable_wait_receive(w);
- return HTTP_VALIDATION_EXCESS_REQUEST_DATA;
- }
- }
web_client_enable_wait_receive(w);
return HTTP_VALIDATION_INCOMPLETE;
}
@@ -787,7 +781,6 @@ HTTP_VALIDATION http_request_validate(struct web_client *w) {
web_client_decode_path_and_query_string(w, encoded_url);
*ue = c;
-#ifdef ENABLE_HTTPS
if ( (web_client_check_conn_tcp(w)) && (netdata_ssl_web_server_ctx) ) {
if (!w->ssl.conn && (http_is_using_ssl_force(w) || http_is_using_ssl_default(w)) && (w->mode != HTTP_REQUEST_MODE_STREAM)) {
w->header_parse_tries = 0;
@@ -796,7 +789,6 @@ HTTP_VALIDATION http_request_validate(struct web_client *w) {
return HTTP_VALIDATION_REDIRECT;
}
}
-#endif
w->header_parse_tries = 0;
w->header_parse_last_size = 0;
@@ -816,28 +808,28 @@ HTTP_VALIDATION http_request_validate(struct web_client *w) {
static inline ssize_t web_client_send_data(struct web_client *w,const void *buf,size_t len, int flags)
{
- ssize_t bytes;
-#ifdef ENABLE_HTTPS
- if ((web_client_check_conn_tcp(w)) && (netdata_ssl_web_server_ctx)) {
- if (SSL_connection(&w->ssl)) {
- bytes = netdata_ssl_write(&w->ssl, buf, len) ;
- web_client_enable_wait_from_ssl(w);
- }
+ do {
+ errno_clear();
+
+ ssize_t bytes;
+ if ((web_client_check_conn_tcp(w)) && (netdata_ssl_web_server_ctx)) {
+ if (SSL_connection(&w->ssl)) {
+ bytes = netdata_ssl_write(&w->ssl, buf, len);
+ web_client_enable_wait_from_ssl(w);
+ } else
+ bytes = send(w->ofd, buf, len, flags);
+ } else if (web_client_check_conn_tcp(w) || web_client_check_conn_unix(w))
+ bytes = send(w->ofd, buf, len, flags);
else
- bytes = send(w->ofd,buf, len , flags);
- }
- else if(web_client_check_conn_tcp(w) || web_client_check_conn_unix(w))
- bytes = send(w->ofd,buf, len , flags);
- else
- bytes = -999;
-#else
- if(web_client_check_conn_tcp(w) || web_client_check_conn_unix(w))
- bytes = send(w->ofd, buf, len, flags);
- else
- bytes = -999;
-#endif
+ bytes = -999;
- return bytes;
+ if(bytes < 0 && errno == EAGAIN) {
+ tinysleep();
+ continue;
+ }
+
+ return bytes;
+ } while(true);
}
void web_client_build_http_header(struct web_client *w) {
@@ -910,8 +902,8 @@ void web_client_build_http_header(struct web_client *w) {
if(w->mode == HTTP_REQUEST_MODE_OPTIONS) {
buffer_strcat(w->response.header_output,
- "Access-Control-Allow-Methods: GET, OPTIONS\r\n"
- "Access-Control-Allow-Headers: accept, x-requested-with, origin, content-type, cookie, pragma, cache-control, x-auth-token\r\n"
+ "Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n"
+ "Access-Control-Allow-Headers: accept, x-requested-with, origin, content-type, cookie, pragma, cache-control, x-auth-token, x-netdata-auth, x-transaction-id\r\n"
"Access-Control-Max-Age: 1209600\r\n" // 86400 * 14
);
}
@@ -967,7 +959,7 @@ static inline void web_client_send_http_header(struct web_client *w) {
size_t count = 0;
ssize_t bytes;
-#ifdef ENABLE_HTTPS
+
if ( (web_client_check_conn_tcp(w)) && (netdata_ssl_web_server_ctx) ) {
if (SSL_connection(&w->ssl)) {
bytes = netdata_ssl_write(&w->ssl, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output));
@@ -996,20 +988,6 @@ static inline void web_client_send_http_header(struct web_client *w) {
}
else
bytes = -999;
-#else
- if(web_client_check_conn_tcp(w) || web_client_check_conn_unix(w)) {
- while ((bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0)) == -1) {
- count++;
-
- if (count > 100 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
- netdata_log_error("Cannot send HTTP headers to web client.");
- break;
- }
- }
- }
- else
- bytes = -999;
-#endif
if(bytes != (ssize_t) buffer_strlen(w->response.header_output)) {
if(bytes > 0)
@@ -1161,7 +1139,8 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
hash_node = 0,
hash_v0 = 0,
hash_v1 = 0,
- hash_v2 = 0;
+ hash_v2 = 0,
+ hash_v3 = 0;
#ifdef NETDATA_INTERNAL_CHECKS
static uint32_t hash_exit = 0, hash_debug = 0, hash_mirror = 0;
@@ -1175,6 +1154,7 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
hash_v0 = simple_hash("v0");
hash_v1 = simple_hash("v1");
hash_v2 = simple_hash("v2");
+ hash_v3 = simple_hash("v3");
#ifdef NETDATA_INTERNAL_CHECKS
hash_exit = simple_hash("exit");
hash_debug = simple_hash("debug");
@@ -1199,6 +1179,12 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: host switch request ...", w->id);
return web_client_switch_host(host, w, decoded_url_path, hash == hash_node, web_client_process_url);
}
+ else if(unlikely(hash == hash_v3 && strcmp(tok, "v3") == 0)) {
+ if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_WITH_VERSION))
+ return bad_request_multiple_dashboard_versions(w);
+ web_client_flag_set(w, WEB_CLIENT_FLAG_PATH_IS_V3);
+ return web_client_process_url(host, w, decoded_url_path);
+ }
else if(unlikely(hash == hash_v2 && strcmp(tok, "v2") == 0)) {
if(web_client_flag_check(w, WEB_CLIENT_FLAG_PATH_WITH_VERSION))
return bad_request_multiple_dashboard_versions(w);
@@ -1224,7 +1210,7 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: generating netdata.conf ...", w->id);
w->response.data->content_type = CT_TEXT_PLAIN;
buffer_flush(w->response.data);
- config_generate(w->response.data, 0);
+ netdata_conf_generate(w->response.data, 0);
return HTTP_RESP_OK;
}
#ifdef NETDATA_INTERNAL_CHECKS
@@ -1310,11 +1296,7 @@ static bool web_server_log_transport(BUFFER *wb, void *ptr) {
if(!w)
return false;
-#ifdef ENABLE_HTTPS
buffer_strcat(wb, SSL_connection(&w->ssl) ? "https" : "http");
-#else
- buffer_strcat(wb, "http");
-#endif
return true;
}
@@ -1441,7 +1423,7 @@ void web_client_process_request_from_web_server(struct web_client *w) {
buffer_flush(w->url_as_received);
buffer_strcat(w->url_as_received, "too big request");
- netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big (%zu bytes).", w->id, w->response.data->len);
+ netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big (%zu bytes).", w->id, (size_t)w->response.data->len);
size_t len = w->response.data->len;
buffer_flush(w->response.data);
@@ -1457,7 +1439,7 @@ void web_client_process_request_from_web_server(struct web_client *w) {
return;
}
break;
-#ifdef ENABLE_HTTPS
+
case HTTP_VALIDATION_REDIRECT:
{
buffer_flush(w->response.data);
@@ -1473,7 +1455,7 @@ void web_client_process_request_from_web_server(struct web_client *w) {
w->response.code = HTTP_RESP_HTTPS_UPGRADE;
break;
}
-#endif
+
case HTTP_VALIDATION_MALFORMED_URL:
netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: Malformed URL '%s'.", w->id, w->response.data->buffer);
@@ -1481,13 +1463,6 @@ void web_client_process_request_from_web_server(struct web_client *w) {
buffer_strcat(w->response.data, "Malformed URL...\r\n");
w->response.code = HTTP_RESP_BAD_REQUEST;
break;
- case HTTP_VALIDATION_EXCESS_REQUEST_DATA:
- netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: Excess data in request '%s'.", w->id, w->response.data->buffer);
-
- buffer_flush(w->response.data);
- buffer_strcat(w->response.data, "Excess data in request.\r\n");
- w->response.code = HTTP_RESP_BAD_REQUEST;
- break;
case HTTP_VALIDATION_TOO_MANY_READ_RETRIES:
netdata_log_debug(D_WEB_CLIENT_ACCESS, "%llu: Too many retries to read request '%s'.", w->id, w->response.data->buffer);
@@ -1521,14 +1496,18 @@ void web_client_process_request_from_web_server(struct web_client *w) {
break;
case HTTP_REQUEST_MODE_OPTIONS:
- netdata_log_debug(D_WEB_CLIENT, "%llu: Done preparing the OPTIONS response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
+ netdata_log_debug(D_WEB_CLIENT,
+ "%llu: Done preparing the OPTIONS response. Sending data (%zu bytes) to client.",
+ w->id, (size_t)w->response.data->len);
break;
case HTTP_REQUEST_MODE_POST:
case HTTP_REQUEST_MODE_GET:
case HTTP_REQUEST_MODE_PUT:
case HTTP_REQUEST_MODE_DELETE:
- netdata_log_debug(D_WEB_CLIENT, "%llu: Done preparing the response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
+ netdata_log_debug(D_WEB_CLIENT,
+ "%llu: Done preparing the response. Sending data (%zu bytes) to client.",
+ w->id, (size_t)w->response.data->len);
break;
case HTTP_REQUEST_MODE_FILECOPY:
@@ -1635,8 +1614,9 @@ ssize_t web_client_send_deflate(struct web_client *w)
// when using compression,
// w->response.sent is the amount of bytes passed through compression
- netdata_log_debug(D_DEFLATE, "%llu: web_client_send_deflate(): w->response.data->len = %zu, w->response.sent = %zu, w->response.zhave = %zu, w->response.zsent = %zu, w->response.zstream.avail_in = %u, w->response.zstream.avail_out = %u, w->response.zstream.total_in = %lu, w->response.zstream.total_out = %lu.",
- w->id, w->response.data->len, w->response.sent, w->response.zhave, w->response.zsent, w->response.zstream.avail_in, w->response.zstream.avail_out, w->response.zstream.total_in, w->response.zstream.total_out);
+ netdata_log_debug(D_DEFLATE,
+ "%llu: web_client_send_deflate(): w->response.data->len = %zu, w->response.sent = %zu, w->response.zhave = %zu, w->response.zsent = %zu, w->response.zstream.avail_in = %u, w->response.zstream.avail_out = %u, w->response.zstream.total_in = %lu, w->response.zstream.total_out = %lu.",
+ w->id, (size_t)w->response.data->len, w->response.sent, w->response.zhave, w->response.zsent, w->response.zstream.avail_in, w->response.zstream.avail_out, w->response.zstream.total_in, w->response.zstream.total_out);
if(w->response.data->len - w->response.sent == 0 && w->response.zstream.avail_in == 0 && w->response.zhave == w->response.zsent && w->response.zstream.avail_out != 0) {
// there is nothing to send
@@ -1850,14 +1830,14 @@ ssize_t web_client_receive(struct web_client *w)
return web_client_read_file(w);
ssize_t bytes;
- ssize_t left = (ssize_t)(w->response.data->size - w->response.data->len);
// do we have any space for more data?
buffer_need_bytes(w->response.data, NETDATA_WEB_REQUEST_INITIAL_SIZE);
+ ssize_t left = (ssize_t)(w->response.data->size - w->response.data->len);
+
errno_clear();
-#ifdef ENABLE_HTTPS
if ( (web_client_check_conn_tcp(w)) && (netdata_ssl_web_server_ctx) ) {
if (SSL_connection(&w->ssl)) {
bytes = netdata_ssl_read(&w->ssl, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1));
@@ -1872,12 +1852,6 @@ ssize_t web_client_receive(struct web_client *w)
}
else // other connection methods
bytes = -1;
-#else
- if(web_client_check_conn_tcp(w) || web_client_check_conn_unix(w))
- bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
- else
- bytes = -1;
-#endif
if(likely(bytes > 0)) {
w->statistics.received_bytes += bytes;
@@ -1960,9 +1934,7 @@ void web_client_reuse_from_cache(struct web_client *w) {
BUFFER *b6 = w->url_query_string_decoded;
BUFFER *b7 = w->payload;
-#ifdef ENABLE_HTTPS
NETDATA_SSL ssl = w->ssl;
-#endif
size_t use_count = w->use_count;
size_t *statistics_memory_accounting = w->statistics.memory_accounting;
@@ -1974,9 +1946,7 @@ void web_client_reuse_from_cache(struct web_client *w) {
w->statistics.memory_accounting = statistics_memory_accounting;
w->use_count = use_count;
-#ifdef ENABLE_HTTPS
w->ssl = ssl;
-#endif
// restore the pointers of the buffers
w->response.data = b1;
@@ -1991,9 +1961,7 @@ void web_client_reuse_from_cache(struct web_client *w) {
struct web_client *web_client_create(size_t *statistics_memory_accounting) {
struct web_client *w = (struct web_client *)callocz(1, sizeof(struct web_client));
-#ifdef ENABLE_HTTPS
w->ssl = NETDATA_SSL_UNSET_CONNECTION;
-#endif
w->use_count = 1;
w->statistics.memory_accounting = statistics_memory_accounting;
@@ -2011,9 +1979,7 @@ struct web_client *web_client_create(size_t *statistics_memory_accounting) {
}
void web_client_free(struct web_client *w) {
-#ifdef ENABLE_HTTPS
netdata_ssl_close(&w->ssl);
-#endif
web_client_reset_allocations(w, true);