summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2023-06-14 19:20:33 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-06-14 19:20:33 +0000
commit6cf8f2d5174a53f582e61d715edbb88d6e3367cc (patch)
tree78cec0fd8d09c4a6a052461d42f4b2be3af6d396 /web
parentAdding upstream version 1.39.1. (diff)
downloadnetdata-6cf8f2d5174a53f582e61d715edbb88d6e3367cc.tar.xz
netdata-6cf8f2d5174a53f582e61d715edbb88d6e3367cc.zip
Adding upstream version 1.40.0.upstream/1.40.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'web')
-rw-r--r--web/api/formatters/json/json.c26
-rw-r--r--web/api/formatters/rrd2json.h2
-rw-r--r--web/api/netdata-swagger.yaml11
-rw-r--r--web/api/queries/query.c87
-rw-r--r--web/api/queries/query.h1
-rw-r--r--web/api/web_api_v1.c2
-rw-r--r--web/gui/dashboard_info.js21
-rw-r--r--web/server/static/static-threaded.c59
-rw-r--r--web/server/web_client.c142
-rw-r--r--web/server/web_client.h38
-rw-r--r--web/server/web_client_cache.c10
11 files changed, 165 insertions, 234 deletions
diff --git a/web/api/formatters/json/json.c b/web/api/formatters/json/json.c
index d5b8c7570..3a7a23ba1 100644
--- a/web/api/formatters/json/json.c
+++ b/web/api/formatters/json/json.c
@@ -244,12 +244,12 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
//info("RRD2JSON(): %s: END", r->st->id);
}
-
void rrdr2json_v2(RRDR *r, BUFFER *wb) {
QUERY_TARGET *qt = r->internal.qt;
RRDR_OPTIONS options = qt->window.options;
- bool expose_gbc = query_target_aggregatable(qt);
+ bool send_count = query_target_aggregatable(qt);
+ bool send_hidden = send_count && r->vh && query_has_group_by_aggregation_percentage(qt);
buffer_json_member_add_object(wb, "result");
@@ -267,12 +267,17 @@ void rrdr2json_v2(RRDR *r, BUFFER *wb) {
buffer_json_array_close(wb); // labels
buffer_json_member_add_object(wb, "point");
- buffer_json_member_add_uint64(wb, "value", 0);
- buffer_json_member_add_uint64(wb, "arp", 1);
- buffer_json_member_add_uint64(wb, "pa", 2);
- if(expose_gbc)
- buffer_json_member_add_uint64(wb, "count", 3);
- buffer_json_object_close(wb);
+ {
+ size_t point_count = 0;
+ buffer_json_member_add_uint64(wb, "value", point_count++);
+ buffer_json_member_add_uint64(wb, "arp", point_count++);
+ buffer_json_member_add_uint64(wb, "pa", point_count++);
+ if (send_count)
+ buffer_json_member_add_uint64(wb, "count", point_count++);
+ if (send_hidden)
+ buffer_json_member_add_uint64(wb, "hidden", point_count++);
+ }
+ buffer_json_object_close(wb); // point
buffer_json_member_add_array(wb, "data");
if(i) {
@@ -286,6 +291,7 @@ void rrdr2json_v2(RRDR *r, BUFFER *wb) {
// for each line in the array
for (i = start; i != end; i += step) {
NETDATA_DOUBLE *cn = &r->v[ i * r->d ];
+ NETDATA_DOUBLE *ch = send_hidden ? &r->vh[i * r->d ] : NULL;
RRDR_VALUE_FLAGS *co = &r->o[ i * r->d ];
NETDATA_DOUBLE *ar = &r->ar[ i * r->d ];
uint32_t *gbc = &r->gbc [ i * r->d ];
@@ -325,8 +331,10 @@ void rrdr2json_v2(RRDR *r, BUFFER *wb) {
buffer_json_add_array_item_uint64(wb, o);
// add the count
- if(expose_gbc)
+ if(send_count)
buffer_json_add_array_item_uint64(wb, gbc[d]);
+ if(send_hidden)
+ buffer_json_add_array_item_double(wb, ch[d]);
buffer_json_array_close(wb); // point
}
diff --git a/web/api/formatters/rrd2json.h b/web/api/formatters/rrd2json.h
index def26c754..ca3a41aae 100644
--- a/web/api/formatters/rrd2json.h
+++ b/web/api/formatters/rrd2json.h
@@ -87,7 +87,7 @@ int rrdset2value_api_v1(
);
static inline bool rrdr_dimension_should_be_exposed(RRDR_DIMENSION_FLAGS rrdr_dim_flags, RRDR_OPTIONS options) {
- if(unlikely(options & RRDR_OPTION_RETURN_RAW))
+ if(unlikely((options & RRDR_OPTION_RETURN_RAW) && (rrdr_dim_flags & RRDR_DIMENSION_QUERIED)))
return true;
if(unlikely(rrdr_dim_flags & RRDR_DIMENSION_HIDDEN)) return false;
diff --git a/web/api/netdata-swagger.yaml b/web/api/netdata-swagger.yaml
index c25f0b719..b050f3407 100644
--- a/web/api/netdata-swagger.yaml
+++ b/web/api/netdata-swagger.yaml
@@ -241,6 +241,7 @@ paths:
A comma separated list of the groupings required.
All possible values can be combined together, except `selected`. If `selected` is given in the list, all others are ignored.
The order they are placed in the list is currently ignored.
+ This parameter is also accepted as `group_by[0]` and `group_by[1]` when multiple grouping passes are required.
required: false
schema:
type: array
@@ -261,6 +262,7 @@ paths:
in: query
description: |
A comma separated list of the label keys to group by their values. The order of the labels in the list is respected.
+ This parameter is also accepted as `group_by_label[0]` and `group_by_label[1]` when multiple grouping passes are required.
required: false
schema:
type: string
@@ -271,6 +273,7 @@ paths:
description: |
The aggregation function to apply when grouping metrics together.
When option `raw` is given, `average` and `avg` behave like `sum` and the caller is expected to calculate the average.
+ This parameter is also accepted as `aggregation[0]` and `aggregation[1]` when multiple grouping passes are required.
required: false
schema:
type: string
@@ -280,6 +283,7 @@ paths:
- avg
- average
- sum
+ - percentage
default: average
- $ref: '#/components/parameters/scopeNodes'
- $ref: '#/components/parameters/scopeContexts'
@@ -2741,8 +2745,13 @@ components:
type: integer
count:
description: |
- The number of metrics aggregated into this point. This exists only when the option `raw` is given to the query.
+ The number of metrics aggregated into this point.
+ This exists only when the option `raw` is given to the query and the final aggregation point is NOT `percentage`.
type: integer
+ hidden:
+ description: |
+ The sum of the non-selected dimensions aggregated for this group item point.
+ This exists only when the option `raw` is given to the query and the final aggregation method is `percentage`.
data:
type: array
items:
diff --git a/web/api/queries/query.c b/web/api/queries/query.c
index 3770d4770..a0347f6fe 100644
--- a/web/api/queries/query.c
+++ b/web/api/queries/query.c
@@ -883,6 +883,9 @@ RRDR_GROUP_BY_FUNCTION group_by_aggregate_function_parse(const char *s) {
if(strcmp(s, "sum") == 0)
return RRDR_GROUP_BY_FUNCTION_SUM;
+ if(strcmp(s, "percentage") == 0)
+ return RRDR_GROUP_BY_FUNCTION_PERCENTAGE;
+
return RRDR_GROUP_BY_FUNCTION_AVERAGE;
}
@@ -900,6 +903,9 @@ const char *group_by_aggregate_function_to_string(RRDR_GROUP_BY_FUNCTION group_b
case RRDR_GROUP_BY_FUNCTION_SUM:
return "sum";
+
+ case RRDR_GROUP_BY_FUNCTION_PERCENTAGE:
+ return "percentage";
}
}
@@ -2555,9 +2561,9 @@ static void rrd2rrdr_set_timestamps(RRDR *r) {
before_wanted, r->t[points_wanted - 1]);
}
-static void query_group_by_make_dimension_key(BUFFER *key, RRDR_GROUP_BY group_by, size_t group_by_id, QUERY_TARGET *qt, QUERY_NODE *qn, QUERY_CONTEXT *qc, QUERY_INSTANCE *qi, QUERY_DIMENSION *qd __maybe_unused, QUERY_METRIC *qm, bool query_has_percentage_of_instance) {
+static void query_group_by_make_dimension_key(BUFFER *key, RRDR_GROUP_BY group_by, size_t group_by_id, QUERY_TARGET *qt, QUERY_NODE *qn, QUERY_CONTEXT *qc, QUERY_INSTANCE *qi, QUERY_DIMENSION *qd __maybe_unused, QUERY_METRIC *qm, bool query_has_percentage_of_group) {
buffer_flush(key);
- if(unlikely(!query_has_percentage_of_instance && qm->status & RRDR_DIMENSION_HIDDEN)) {
+ if(unlikely(!query_has_percentage_of_group && qm->status & RRDR_DIMENSION_HIDDEN)) {
buffer_strcat(key, "__hidden_dimensions__");
}
else if(unlikely(group_by & RRDR_GROUP_BY_SELECTED)) {
@@ -2599,9 +2605,9 @@ static void query_group_by_make_dimension_key(BUFFER *key, RRDR_GROUP_BY group_b
}
}
-static void query_group_by_make_dimension_id(BUFFER *key, RRDR_GROUP_BY group_by, size_t group_by_id, QUERY_TARGET *qt, QUERY_NODE *qn, QUERY_CONTEXT *qc, QUERY_INSTANCE *qi, QUERY_DIMENSION *qd __maybe_unused, QUERY_METRIC *qm, bool query_has_percentage_of_instance) {
+static void query_group_by_make_dimension_id(BUFFER *key, RRDR_GROUP_BY group_by, size_t group_by_id, QUERY_TARGET *qt, QUERY_NODE *qn, QUERY_CONTEXT *qc, QUERY_INSTANCE *qi, QUERY_DIMENSION *qd __maybe_unused, QUERY_METRIC *qm, bool query_has_percentage_of_group) {
buffer_flush(key);
- if(unlikely(!query_has_percentage_of_instance && qm->status & RRDR_DIMENSION_HIDDEN)) {
+ if(unlikely(!query_has_percentage_of_group && qm->status & RRDR_DIMENSION_HIDDEN)) {
buffer_strcat(key, "__hidden_dimensions__");
}
else if(unlikely(group_by & RRDR_GROUP_BY_SELECTED)) {
@@ -2654,9 +2660,9 @@ static void query_group_by_make_dimension_id(BUFFER *key, RRDR_GROUP_BY group_by
}
}
-static void query_group_by_make_dimension_name(BUFFER *key, RRDR_GROUP_BY group_by, size_t group_by_id, QUERY_TARGET *qt, QUERY_NODE *qn, QUERY_CONTEXT *qc, QUERY_INSTANCE *qi, QUERY_DIMENSION *qd __maybe_unused, QUERY_METRIC *qm, bool query_has_percentage_of_instance) {
+static void query_group_by_make_dimension_name(BUFFER *key, RRDR_GROUP_BY group_by, size_t group_by_id, QUERY_TARGET *qt, QUERY_NODE *qn, QUERY_CONTEXT *qc, QUERY_INSTANCE *qi, QUERY_DIMENSION *qd __maybe_unused, QUERY_METRIC *qm, bool query_has_percentage_of_group) {
buffer_flush(key);
- if(unlikely(!query_has_percentage_of_instance && qm->status & RRDR_DIMENSION_HIDDEN)) {
+ if(unlikely(!query_has_percentage_of_group && qm->status & RRDR_DIMENSION_HIDDEN)) {
buffer_strcat(key, "__hidden_dimensions__");
}
else if(unlikely(group_by & RRDR_GROUP_BY_SELECTED)) {
@@ -2758,16 +2764,16 @@ static RRDR *rrd2rrdr_group_by_initialize(ONEWAYALLOC *owa, QUERY_TARGET *qt) {
}
// make sure there are valid group-by methods
- bool query_has_percentage_of_instance = false;
- for(size_t g = 0; g < MAX_QUERY_GROUP_BY_PASSES - 1 ;g++) {
+ for(size_t g = 0; g < MAX_QUERY_GROUP_BY_PASSES ;g++) {
if(!(qt->request.group_by[g].group_by & SUPPORTED_GROUP_BY_METHODS))
qt->request.group_by[g].group_by = (g == 0) ? RRDR_GROUP_BY_DIMENSION : RRDR_GROUP_BY_NONE;
-
- if(qt->request.group_by[g].group_by & RRDR_GROUP_BY_PERCENTAGE_OF_INSTANCE)
- query_has_percentage_of_instance = true;
}
- // merge all group-by options to upper levels
+ bool query_has_percentage_of_group = query_target_has_percentage_of_group(qt);
+
+ // merge all group-by options to upper levels,
+ // so that the top level has all the groupings of the inner levels,
+ // and each subsequent level has all the groupings of its inner levels.
for(size_t g = 0; g < MAX_QUERY_GROUP_BY_PASSES - 1 ;g++) {
if(qt->request.group_by[g].group_by == RRDR_GROUP_BY_NONE)
continue;
@@ -2815,6 +2821,7 @@ static RRDR *rrd2rrdr_group_by_initialize(ONEWAYALLOC *owa, QUERY_TARGET *qt) {
for(size_t g = 0; g < MAX_QUERY_GROUP_BY_PASSES ;g++) {
RRDR_GROUP_BY group_by = qt->request.group_by[g].group_by;
+ RRDR_GROUP_BY_FUNCTION aggregation_method = qt->request.group_by[g].aggregation;
if(group_by == RRDR_GROUP_BY_NONE)
break;
@@ -2855,7 +2862,7 @@ static RRDR *rrd2rrdr_group_by_initialize(ONEWAYALLOC *owa, QUERY_TARGET *qt) {
// --------------------------------------------------------------------
// generate the group by key
- query_group_by_make_dimension_key(key, group_by, g, qt, qn, qc, qi, qd, qm, query_has_percentage_of_instance);
+ query_group_by_make_dimension_key(key, group_by, g, qt, qn, qc, qi, qd, qm, query_has_percentage_of_group);
// lookup the key in the dictionary
@@ -2869,13 +2876,13 @@ static RRDR *rrd2rrdr_group_by_initialize(ONEWAYALLOC *owa, QUERY_TARGET *qt) {
// ----------------------------------------------------------------
// generate the dimension id
- query_group_by_make_dimension_id(key, group_by, g, qt, qn, qc, qi, qd, qm, query_has_percentage_of_instance);
+ query_group_by_make_dimension_id(key, group_by, g, qt, qn, qc, qi, qd, qm, query_has_percentage_of_group);
entries[pos].id = string_strdupz(buffer_tostring(key));
// ----------------------------------------------------------------
// generate the dimension name
- query_group_by_make_dimension_name(key, group_by, g, qt, qn, qc, qi, qd, qm, query_has_percentage_of_instance);
+ query_group_by_make_dimension_name(key, group_by, g, qt, qn, qc, qi, qd, qm, query_has_percentage_of_group);
entries[pos].name = string_strdupz(buffer_tostring(key));
// add the rest of the info
@@ -2914,9 +2921,9 @@ static RRDR *rrd2rrdr_group_by_initialize(ONEWAYALLOC *owa, QUERY_TARGET *qt) {
// the query target adds to it the non-zero flag
qm->status |= RRDR_DIMENSION_GROUPED;
- if(query_has_percentage_of_instance)
- // when the query has percentage of instance
- // there will be no hidden dimensions in the final query
+ if(query_has_percentage_of_group)
+ // when the query has percentage of group
+ // there will be no hidden dimensions in the final query,
// so we have to remove the hidden flag from all dimensions
entries[pos].od |= qm->status & ~RRDR_DIMENSION_HIDDEN;
else
@@ -2934,12 +2941,10 @@ static RRDR *rrd2rrdr_group_by_initialize(ONEWAYALLOC *owa, QUERY_TARGET *qt) {
qt->id, qt->window.after, qt->window.before, added, qt->window.points);
goto cleanup;
}
-
- bool hidden_dimension_on_percentage_of_instance = hidden_dimensions && (group_by & RRDR_GROUP_BY_PERCENTAGE_OF_INSTANCE);
-
- // prevent double cleanup in case of error
+ // prevent double free at cleanup in case of error
added = 0;
+ // link this RRDR
if(!last_r)
first_r = last_r = r;
else
@@ -2954,7 +2959,7 @@ static RRDR *rrd2rrdr_group_by_initialize(ONEWAYALLOC *owa, QUERY_TARGET *qt) {
r->gbc = onewayalloc_callocz(owa, r->n * r->d, sizeof(*r->gbc));
r->dqp = onewayalloc_callocz(owa, r->d, sizeof(STORAGE_POINT));
- if(hidden_dimension_on_percentage_of_instance)
+ if(hidden_dimensions && ((group_by & RRDR_GROUP_BY_PERCENTAGE_OF_INSTANCE) || (aggregation_method == RRDR_GROUP_BY_FUNCTION_PERCENTAGE)))
// this is where we are going to group the hidden dimensions
r->vh = onewayalloc_mallocz(owa, r->n * r->d * sizeof(*r->vh));
@@ -2987,7 +2992,7 @@ static RRDR *rrd2rrdr_group_by_initialize(ONEWAYALLOC *owa, QUERY_TARGET *qt) {
// initialize partial trimming
r->partial_data_trimming.max_update_every = update_every_max;
r->partial_data_trimming.expected_after =
- (!(qt->window.options & RRDR_OPTION_RETURN_RAW) &&
+ (!query_target_aggregatable(qt) &&
qt->window.before >= qt->window.now - update_every_max) ?
qt->window.before - update_every_max :
qt->window.before;
@@ -3006,7 +3011,7 @@ static RRDR *rrd2rrdr_group_by_initialize(ONEWAYALLOC *owa, QUERY_TARGET *qt) {
co[d] = RRDR_VALUE_EMPTY;
if(vh)
- *vh = NAN;
+ vh[d] = NAN;
}
}
}
@@ -3073,9 +3078,9 @@ static void rrd2rrdr_group_by_add_metric(RRDR *r_dst, size_t d_dst, RRDR *r_tmp,
internal_fatal(!r_dst->dqp, "QUERY: group-by destination is not properly prepared (missing dqp array)");
internal_fatal(!r_dst->gbc, "QUERY: group-by destination is not properly prepared (missing gbc array)");
- bool hidden_dimension_on_percentage_of_instance = (r_tmp->od[d_tmp] & RRDR_DIMENSION_HIDDEN) && r_dst->vh;
+ bool hidden_dimension_on_percentage_of_group = (r_tmp->od[d_tmp] & RRDR_DIMENSION_HIDDEN) && r_dst->vh;
- if(!hidden_dimension_on_percentage_of_instance) {
+ if(!hidden_dimension_on_percentage_of_group) {
r_dst->od[d_dst] |= r_tmp->od[d_tmp];
storage_point_merge_to(r_dst->dqp[d_dst], *query_points);
}
@@ -3092,7 +3097,7 @@ static void rrd2rrdr_group_by_add_metric(RRDR *r_dst, size_t d_dst, RRDR *r_tmp,
continue;
size_t idx_dst = i * r_dst->d + d_dst;
- NETDATA_DOUBLE *cn = (hidden_dimension_on_percentage_of_instance) ? &r_dst->vh[ idx_dst ] : &r_dst->v[ idx_dst ];
+ NETDATA_DOUBLE *cn = (hidden_dimension_on_percentage_of_group) ? &r_dst->vh[ idx_dst ] : &r_dst->v[ idx_dst ];
RRDR_VALUE_FLAGS *co = &r_dst->o[ idx_dst ];
NETDATA_DOUBLE *ar = &r_dst->ar[ idx_dst ];
uint32_t *gbc = &r_dst->gbc[ idx_dst ];
@@ -3101,6 +3106,7 @@ static void rrd2rrdr_group_by_add_metric(RRDR *r_dst, size_t d_dst, RRDR *r_tmp,
default:
case RRDR_GROUP_BY_FUNCTION_AVERAGE:
case RRDR_GROUP_BY_FUNCTION_SUM:
+ case RRDR_GROUP_BY_FUNCTION_PERCENTAGE:
if(isnan(*cn))
*cn = n_tmp;
else
@@ -3118,7 +3124,7 @@ static void rrd2rrdr_group_by_add_metric(RRDR *r_dst, size_t d_dst, RRDR *r_tmp,
break;
}
- if(!hidden_dimension_on_percentage_of_instance) {
+ if(!hidden_dimension_on_percentage_of_group) {
*co &= ~RRDR_VALUE_EMPTY;
*co |= (o_tmp & (RRDR_VALUE_RESET | RRDR_VALUE_PARTIAL));
*ar += ar_tmp;
@@ -3161,10 +3167,13 @@ static void rrdr2rrdr_group_by_partial_trimming(RRDR *r) {
}
}
-static void rrdr2rrdr_group_by_calculate_percentage_of_instance(RRDR *r) {
+static void rrdr2rrdr_group_by_calculate_percentage_of_group(RRDR *r) {
if(!r->vh)
return;
+ if(query_target_aggregatable(r->internal.qt) && query_has_group_by_aggregation_percentage(r->internal.qt))
+ return;
+
for(size_t i = 0; i < r->n ;i++) {
NETDATA_DOUBLE *cn = &r->v[ i * r->d ];
NETDATA_DOUBLE *ch = &r->vh[ i * r->d ];
@@ -3185,7 +3194,10 @@ static void rrdr2rrdr_group_by_calculate_percentage_of_instance(RRDR *r) {
}
}
-static void rrd2rrdr_convert_to_percentage(RRDR *r) {
+static void rrd2rrdr_convert_values_to_percentage_of_total(RRDR *r) {
+ if(!(r->internal.qt->window.options & RRDR_OPTION_PERCENTAGE) || query_target_aggregatable(r->internal.qt))
+ return;
+
size_t global_min_max_values = 0;
NETDATA_DOUBLE global_min = NAN, global_max = NAN;
@@ -3279,19 +3291,17 @@ static void rrd2rrdr_convert_to_percentage(RRDR *r) {
static RRDR *rrd2rrdr_group_by_finalize(RRDR *r_tmp) {
QUERY_TARGET *qt = r_tmp->internal.qt;
- RRDR_OPTIONS options = qt->window.options;
if(!r_tmp->group_by.r) {
// v1 query
- if(options & RRDR_OPTION_PERCENTAGE)
- rrd2rrdr_convert_to_percentage(r_tmp);
+ rrd2rrdr_convert_values_to_percentage_of_total(r_tmp);
return r_tmp;
}
// v2 query
// do the additional passes on RRDRs
RRDR *last_r = r_tmp->group_by.r;
- rrdr2rrdr_group_by_calculate_percentage_of_instance(last_r);
+ rrdr2rrdr_group_by_calculate_percentage_of_group(last_r);
RRDR *r = last_r->group_by.r;
size_t pass = 0;
@@ -3302,7 +3312,7 @@ static RRDR *rrd2rrdr_group_by_finalize(RRDR *r_tmp) {
qt->request.group_by[pass].aggregation,
&last_r->dqp[d], pass);
}
- rrdr2rrdr_group_by_calculate_percentage_of_instance(r);
+ rrdr2rrdr_group_by_calculate_percentage_of_group(r);
last_r = r;
r = last_r->group_by.r;
@@ -3324,7 +3334,7 @@ static RRDR *rrd2rrdr_group_by_finalize(RRDR *r_tmp) {
if(qt->request.group_by[g].group_by != RRDR_GROUP_BY_NONE)
aggregation = qt->request.group_by[g].aggregation;
- if(!(options & RRDR_OPTION_RETURN_RAW) && r->partial_data_trimming.expected_after < qt->window.before)
+ if(!query_target_aggregatable(qt) && r->partial_data_trimming.expected_after < qt->window.before)
rrdr2rrdr_group_by_partial_trimming(r);
// apply averaging, remove RRDR_VALUE_EMPTY, find the non-zero dimensions, min and max
@@ -3416,8 +3426,7 @@ static RRDR *rrd2rrdr_group_by_finalize(RRDR *r_tmp) {
qt->window.options &= ~RRDR_OPTION_NONZERO;
}
- if(options & RRDR_OPTION_PERCENTAGE && !(options & RRDR_OPTION_RETURN_RAW))
- rrd2rrdr_convert_to_percentage(r);
+ rrd2rrdr_convert_values_to_percentage_of_total(r);
// update query instance counts in query host and query context
{
diff --git a/web/api/queries/query.h b/web/api/queries/query.h
index e6fdcfbe4..5eabb6c03 100644
--- a/web/api/queries/query.h
+++ b/web/api/queries/query.h
@@ -85,6 +85,7 @@ typedef enum rrdr_group_by_function {
RRDR_GROUP_BY_FUNCTION_MIN,
RRDR_GROUP_BY_FUNCTION_MAX,
RRDR_GROUP_BY_FUNCTION_SUM,
+ RRDR_GROUP_BY_FUNCTION_PERCENTAGE,
} RRDR_GROUP_BY_FUNCTION;
RRDR_GROUP_BY_FUNCTION group_by_aggregate_function_parse(const char *s);
diff --git a/web/api/web_api_v1.c b/web/api/web_api_v1.c
index 6e23549d4..637329696 100644
--- a/web/api/web_api_v1.c
+++ b/web/api/web_api_v1.c
@@ -354,7 +354,7 @@ inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client
buffer_flush(w->response.data);
w->response.data->content_type = CT_APPLICATION_JSON;
- health_alarm_log2json(host, w->response.data, after, chart);
+ sql_health_alarm_log2json(host, w->response.data, after, chart);
return HTTP_RESP_OK;
}
diff --git a/web/gui/dashboard_info.js b/web/gui/dashboard_info.js
index 3dfbd6166..23574a701 100644
--- a/web/gui/dashboard_info.js
+++ b/web/gui/dashboard_info.js
@@ -883,6 +883,19 @@ netdataDashboard.submenu = {
'When the kernel or an application requests some memory, the buddy allocator provides a page that matches closest the request.'
},
+ 'mem.fragmentation': {
+ info: 'These charts show whether the kernel will compact memory or direct reclaim to satisfy a high-order allocation. '+
+ 'The extfrag/extfrag_index file in debugfs shows what the fragmentation index for each order is in each zone in the system.' +
+ 'Values tending towards 0 imply allocations would fail due to lack of memory, values towards 1000 imply failures are due to ' +
+ 'fragmentation and -1 implies that the allocation will succeed as long as watermarks are met.'
+ },
+
+ 'system.zswap': {
+ info : 'Zswap is a backend for frontswap that takes pages that are in the process of being swapped out and attempts to compress and store them in a ' +
+ 'RAM-based memory pool. This can result in a significant I/O reduction on the swap device and, in the case where decompressing from RAM is faster ' +
+ 'than reading from the swap device, can also improve workload performance.'
+ },
+
'ip.ecn': {
info: '<a href="https://en.wikipedia.org/wiki/Explicit_Congestion_Notification" target="_blank">Explicit Congestion Notification (ECN)</a> '+
'is an extension to the IP and to the TCP that allows end-to-end notification of network congestion without dropping packets. '+
@@ -1522,6 +1535,14 @@ netdataDashboard.context = {
info: '<a href="https://en.wikipedia.org/wiki/Entropy_(computing)" target="_blank">Entropy</a>, is a pool of random numbers (<a href="https://en.wikipedia.org/wiki//dev/random" target="_blank">/dev/random</a>) that is mainly used in cryptography. If the pool of entropy gets empty, processes requiring random numbers may run a lot slower (it depends on the interface each program uses), waiting for the pool to be replenished. Ideally a system with high entropy demands should have a hardware device for that purpose (TPM is one such device). There are also several software-only options you may install, like <code>haveged</code>, although these are generally useful only in servers.'
},
+ 'system.zswap_rejections': {
+ info: '<p>Zswap rejected pages per access.</p>' +
+ '<p><b>CompressPoor</b> - compressed page was too big for the allocator to store. ' +
+ '<b>KmemcacheFail</b> - number of entry metadata that could not be allocated. ' +
+ '<b>AllocFail</b> - allocator could not get memory. ' +
+ '<b>ReclaimFail</b> - memory cannot be reclaimed (pool limit was reached).</p>'
+ },
+
'system.clock_sync_state': {
info:'<p>The system clock synchronization state as provided by the <a href="https://man7.org/linux/man-pages/man2/adjtimex.2.html" target="_blank">ntp_adjtime()</a> system call. '+
'An unsynchronized clock may be the result of synchronization issues by the NTP daemon or a hardware clock fault. '+
diff --git a/web/server/static/static-threaded.c b/web/server/static/static-threaded.c
index 52bb56cd6..4cb3dcd92 100644
--- a/web/server/static/static-threaded.c
+++ b/web/server/static/static-threaded.c
@@ -211,58 +211,32 @@ static void *web_server_add_callback(POLLINFO *pi, short int *events, void *data
}
#ifdef ENABLE_HTTPS
- if ((!web_client_check_unix(w)) && (netdata_ssl_srv_ctx)) {
- if( sock_delnonblock(w->ifd) < 0 ){
- error("Web server cannot remove the non-blocking flag from socket %d",w->ifd);
- }
+ if ((!web_client_check_unix(w)) && (netdata_ssl_web_server_ctx)) {
+ sock_delnonblock(w->ifd);
//Read the first 7 bytes from the message, but the message
//is not removed from the queue, because we are using MSG_PEEK
char test[8];
- if ( recv(w->ifd,test, 7,MSG_PEEK) == 7 ) {
- test[7] = 0x00;
+ if ( recv(w->ifd,test, 7, MSG_PEEK) == 7 ) {
+ test[7] = '\0';
}
else {
- //Case I do not have success to read 7 bytes,
- //this means that the mensage was not completely read, so
- //I cannot identify it yet.
+ // we couldn't read 7 bytes
sock_setnonblock(w->ifd);
goto cleanup;
}
- //The next two ifs are not together because I am reusing SSL structure
- if (!w->ssl.conn)
- {
- w->ssl.conn = SSL_new(netdata_ssl_srv_ctx);
- if ( w->ssl.conn ) {
- SSL_set_accept_state(w->ssl.conn);
- } else {
- error("Failed to create SSL context on socket fd %d.", w->ifd);
- if (test[0] < 0x18){
- WEB_CLIENT_IS_DEAD(w);
- sock_setnonblock(w->ifd);
- goto cleanup;
- }
- }
+ if(test[0] > 0x17) {
+ // no SSL
+ netdata_ssl_close(&w->ssl); // free any previous SSL data
}
-
- if (w->ssl.conn) {
- if (SSL_set_fd(w->ssl.conn, w->ifd) != 1) {
- error("Failed to set the socket to the SSL on socket fd %d.", w->ifd);
- //The client is not set dead, because I received a normal HTTP request
- //instead a Client Hello(HTTPS).
- if ( test[0] < 0x18 ){
- WEB_CLIENT_IS_DEAD(w);
- }
- }
- else{
- w->ssl.flags = security_process_accept(w->ssl.conn, (int)test[0]);
- }
+ else {
+ // SSL
+ if(!netdata_ssl_open(&w->ssl, netdata_ssl_web_server_ctx, w->ifd) || !netdata_ssl_accept(&w->ssl))
+ WEB_CLIENT_IS_DEAD(w);
}
sock_setnonblock(w->ifd);
- } else{
- w->ssl.flags = NETDATA_SSL_NO_HANDSHAKE;
}
#endif
@@ -525,9 +499,15 @@ void *socket_listen_main_static_threaded(void *ptr) {
if(!api_sockets.opened)
fatal("LISTENER: no listen sockets available.");
+ netdata_ssl_validate_certificate = !config_get_boolean(CONFIG_SECTION_WEB, "ssl skip certificate verification", !netdata_ssl_validate_certificate);
+
+ if(!netdata_ssl_validate_certificate_sender)
+ info("SSL: web server will skip SSL certificates verification.");
+
#ifdef ENABLE_HTTPS
- security_start_ssl(NETDATA_SSL_CONTEXT_SERVER);
+ netdata_ssl_initialize_ctx(NETDATA_SSL_WEB_SERVER_CTX);
#endif
+
// 6 threads is the optimal value
// since 6 are the parallel connections browsers will do
// so, if the machine has more CPUs, avoid using resources unnecessarily
@@ -541,6 +521,7 @@ void *socket_listen_main_static_threaded(void *ptr) {
static_threaded_workers_count = config_get_number(CONFIG_SECTION_WEB, "web server threads", def_thread_count);
if (static_threaded_workers_count < 1) static_threaded_workers_count = 1;
+
#ifdef ENABLE_HTTPS
// See https://github.com/netdata/netdata/issues/11081#issuecomment-831998240 for more details
if (OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110) {
diff --git a/web/server/web_client.c b/web/server/web_client.c
index 8bc72e71f..6e3c1225e 100644
--- a/web/server/web_client.c
+++ b/web/server/web_client.c
@@ -8,9 +8,7 @@
int respect_web_browser_do_not_track_policy = 0;
char *web_x_frame_options = NULL;
-#ifdef NETDATA_WITH_ZLIB
int web_enable_gzip = 1, web_gzip_level = 3, web_gzip_strategy = Z_DEFAULT_STRATEGY;
-#endif /* NETDATA_WITH_ZLIB */
inline int web_client_permission_denied(struct web_client *w) {
w->response.data->content_type = CT_TEXT_PLAIN;
@@ -36,11 +34,10 @@ static inline int web_client_crock_socket(struct web_client *w __maybe_unused) {
return 0;
}
-static inline void web_client_enable_wait_from_ssl(struct web_client *w, int bytes) {
- int ssl_err = SSL_get_error(w->ssl.conn, bytes);
- if (ssl_err == SSL_ERROR_WANT_READ)
+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);
- else if (ssl_err == SSL_ERROR_WANT_WRITE)
+ else if (w->ssl.ssl_errno == SSL_ERROR_WANT_WRITE)
web_client_enable_ssl_wait_send(w);
else {
web_client_disable_ssl_wait_receive(w);
@@ -101,15 +98,6 @@ static void web_client_reset_allocations(struct web_client *w, bool free_all) {
freez(w->post_payload);
w->post_payload = NULL;
w->post_payload_size = 0;
-
-#ifdef ENABLE_HTTPS
- if ((!web_client_check_unix(w)) && (netdata_ssl_srv_ctx)) {
- if (w->ssl.conn) {
- SSL_free(w->ssl.conn);
- w->ssl.conn = NULL;
- }
- }
-#endif
}
else {
// the web client is to be re-used
@@ -123,7 +111,6 @@ static void web_client_reset_allocations(struct web_client *w, bool free_all) {
buffer_reset(w->response.data);
// leave w->post_payload
- // leave w->ssl
}
freez(w->server_host);
@@ -142,7 +129,6 @@ static void web_client_reset_allocations(struct web_client *w, bool free_all) {
w->auth_bearer_token = NULL;
// if we had enabled compression, release it
-#ifdef NETDATA_WITH_ZLIB
if(w->response.zinitialized) {
deflateEnd(&w->response.zstream);
w->response.zsent = 0;
@@ -154,7 +140,6 @@ static void web_client_reset_allocations(struct web_client *w, bool free_all) {
w->response.zinitialized = false;
w->flags &= ~WEB_CLIENT_CHUNKED_TRANSFER;
}
-#endif // NETDATA_WITH_ZLIB
}
void web_client_request_done(struct web_client *w) {
@@ -168,9 +153,7 @@ void web_client_request_done(struct web_client *w) {
size_t size = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->response.rlen:w->response.data->len;
size_t sent = size;
-#ifdef NETDATA_WITH_ZLIB
if(likely(w->response.zoutput)) sent = (size_t)w->response.zstream.total_out;
-#endif
// --------------------------------------------------------------------
// global statistics
@@ -444,9 +427,6 @@ int mysendfile(struct web_client *w, char *filename) {
}
#endif
-
-
-#ifdef NETDATA_WITH_ZLIB
void web_client_enable_deflate(struct web_client *w, int gzip) {
if(unlikely(w->response.zinitialized)) {
debug(D_DEFLATE, "%llu: Compression has already be initialized for this client.", w->id);
@@ -492,7 +472,6 @@ void web_client_enable_deflate(struct web_client *w, int gzip) {
debug(D_DEFLATE, "%llu: Initialized compression.", w->id);
}
-#endif // NETDATA_WITH_ZLIB
void buffer_data_options2string(BUFFER *wb, uint32_t options) {
int count = 0;
@@ -730,16 +709,12 @@ const char *web_response_code_to_string(int code) {
static inline char *http_header_parse(struct web_client *w, char *s, int parse_useragent) {
static uint32_t hash_origin = 0, hash_connection = 0, hash_donottrack = 0, hash_useragent = 0,
hash_authorization = 0, hash_host = 0, hash_forwarded_proto = 0, hash_forwarded_host = 0;
-#ifdef NETDATA_WITH_ZLIB
static uint32_t hash_accept_encoding = 0;
-#endif
if(unlikely(!hash_origin)) {
hash_origin = simple_uhash("Origin");
hash_connection = simple_uhash("Connection");
-#ifdef NETDATA_WITH_ZLIB
hash_accept_encoding = simple_uhash("Accept-Encoding");
-#endif
hash_donottrack = simple_uhash("DNT");
hash_useragent = simple_uhash("User-Agent");
hash_authorization = simple_uhash("X-Auth-Token");
@@ -798,7 +773,6 @@ static inline char *http_header_parse(struct web_client *w, char *s, int parse_u
strncpyz(buffer, v, ((size_t)(ve - v) < sizeof(buffer) - 1 ? (size_t)(ve - v) : sizeof(buffer) - 1));
w->server_host = strdupz(buffer);
}
-#ifdef NETDATA_WITH_ZLIB
else if(hash == hash_accept_encoding && !strcasecmp(s, "Accept-Encoding")) {
if(web_enable_gzip) {
if(strcasestr(v, "gzip"))
@@ -809,13 +783,10 @@ static inline char *http_header_parse(struct web_client *w, char *s, int parse_u
// web_client_enable_deflate(w, 0);
}
}
-#endif /* NETDATA_WITH_ZLIB */
-#ifdef ENABLE_HTTPS
else if(hash == hash_forwarded_proto && !strcasecmp(s, "X-Forwarded-Proto")) {
if(strcasestr(v, "https"))
- w->ssl.flags |= NETDATA_SSL_PROXY_HTTPS;
+ w->flags |= WEB_CLIENT_FLAG_PROXY_HTTPS;
}
-#endif
else if(hash == hash_forwarded_host && !strcasecmp(s, "X-Forwarded-Host")) {
char buffer[NI_MAXHOST];
strncpyz(buffer, v, ((size_t)(ve - v) < sizeof(buffer) - 1 ? (size_t)(ve - v) : sizeof(buffer) - 1));
@@ -855,7 +826,7 @@ static inline char *web_client_valid_method(struct web_client *w, char *s) {
s = &s[7];
#ifdef ENABLE_HTTPS
- if (w->ssl.flags && web_client_is_using_ssl_force(w)){
+ if (!SSL_connection(&w->ssl) && web_client_is_using_ssl_force(w)) {
w->header_parse_tries = 0;
w->header_parse_last_size = 0;
web_client_disable_wait_receive(w);
@@ -996,8 +967,8 @@ static inline HTTP_VALIDATION http_request_validate(struct web_client *w) {
*ue = c;
#ifdef ENABLE_HTTPS
- if ( (!web_client_check_unix(w)) && (netdata_ssl_srv_ctx) ) {
- if ((w->ssl.conn) && ((w->ssl.flags & NETDATA_SSL_NO_HANDSHAKE) && (web_client_is_using_ssl_force(w) || web_client_is_using_ssl_default(w)) && (w->mode != WEB_CLIENT_MODE_STREAM)) ) {
+ if ( (!web_client_check_unix(w)) && (netdata_ssl_web_server_ctx) ) {
+ if (!w->ssl.conn && (web_client_is_using_ssl_force(w) || web_client_is_using_ssl_default(w)) && (w->mode != WEB_CLIENT_MODE_STREAM)) {
w->header_parse_tries = 0;
w->header_parse_last_size = 0;
web_client_disable_wait_receive(w);
@@ -1026,16 +997,15 @@ static inline ssize_t web_client_send_data(struct web_client *w,const void *buf,
{
ssize_t bytes;
#ifdef ENABLE_HTTPS
- if ( (!web_client_check_unix(w)) && (netdata_ssl_srv_ctx) ) {
- if ( ( w->ssl.conn ) && ( !w->ssl.flags ) ){
- bytes = netdata_ssl_write(w->ssl.conn, buf, len) ;
- web_client_enable_wait_from_ssl(w, bytes);
- } else {
- bytes = send(w->ofd,buf, len , flags);
+ if ((!web_client_check_unix(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 {
+ else
+ bytes = send(w->ofd,buf, len , flags);
+ } else
bytes = send(w->ofd,buf, len , flags);
- }
#else
bytes = send(w->ofd, buf, len, flags);
#endif
@@ -1172,10 +1142,10 @@ 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_unix(w)) && (netdata_ssl_srv_ctx) ) {
- if ( ( w->ssl.conn ) && ( w->ssl.flags == NETDATA_SSL_HANDSHAKE_COMPLETE ) ) {
- bytes = netdata_ssl_write(w->ssl.conn, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output));
- web_client_enable_wait_from_ssl(w, bytes);
+ if ( (!web_client_check_unix(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));
+ web_client_enable_wait_from_ssl(w);
}
else {
while((bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0)) == -1) {
@@ -1276,11 +1246,11 @@ static inline int web_client_switch_host(RRDHOST *host, struct web_client *w, ch
if(!url) { //no delim found
debug(D_WEB_CLIENT, "%llu: URL doesn't end with / generating redirect.", w->id);
char *protocol, *url_host;
+ protocol = (
#ifdef ENABLE_HTTPS
- protocol = ((w->ssl.conn && !w->ssl.flags) || w->ssl.flags & NETDATA_SSL_PROXY_HTTPS) ? "https" : "http";
-#else
- protocol = "http";
+ SSL_connection(&w->ssl) ||
#endif
+ (w->flags & WEB_CLIENT_FLAG_PROXY_HTTPS)) ? "https" : "http";
url_host = w->forwarded_host;
if(!url_host) {
@@ -1736,7 +1706,6 @@ ssize_t web_client_send_chunk_finalize(struct web_client *w)
return bytes;
}
-#ifdef NETDATA_WITH_ZLIB
ssize_t web_client_send_deflate(struct web_client *w)
{
ssize_t len = 0, t = 0;
@@ -1851,12 +1820,9 @@ ssize_t web_client_send_deflate(struct web_client *w)
return(len);
}
-#endif // NETDATA_WITH_ZLIB
ssize_t web_client_send(struct web_client *w) {
-#ifdef NETDATA_WITH_ZLIB
if(likely(w->response.zoutput)) return web_client_send_deflate(w);
-#endif // NETDATA_WITH_ZLIB
ssize_t bytes;
@@ -1968,11 +1934,12 @@ ssize_t web_client_receive(struct web_client *w)
buffer_need_bytes(w->response.data, NETDATA_WEB_REQUEST_INITIAL_SIZE);
#ifdef ENABLE_HTTPS
- if ( (!web_client_check_unix(w)) && (netdata_ssl_srv_ctx) ) {
- if ( ( w->ssl.conn ) && (!w->ssl.flags)) {
- bytes = netdata_ssl_read(w->ssl.conn, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1));
- web_client_enable_wait_from_ssl(w, bytes);
- }else {
+ if ( (!web_client_check_unix(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));
+ web_client_enable_wait_from_ssl(w);
+ }
+ else {
bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
}
}
@@ -2005,26 +1972,6 @@ ssize_t web_client_receive(struct web_client *w)
}
-int web_client_socket_is_now_used_for_streaming(struct web_client *w) {
- // prevent the web_client from closing the streaming socket
-
- WEB_CLIENT_IS_DEAD(w);
-
- if(web_server_mode == WEB_SERVER_MODE_STATIC_THREADED) {
- web_client_flag_set(w, WEB_CLIENT_FLAG_DONT_CLOSE_SOCKET);
- }
- else {
- if(w->ifd == w->ofd)
- w->ifd = w->ofd = -1;
- else
- w->ifd = -1;
- }
-
- buffer_flush(w->response.data);
-
- return HTTP_RESP_OK;
-}
-
void web_client_decode_path_and_query_string(struct web_client *w, const char *path_and_query_string) {
char buffer[NETDATA_WEB_REQUEST_URL_SIZE + 2];
buffer[0] = '\0';
@@ -2072,25 +2019,6 @@ void web_client_decode_path_and_query_string(struct web_client *w, const char *p
}
}
-#ifdef ENABLE_HTTPS
-void web_client_reuse_ssl(struct web_client *w) {
- if (netdata_ssl_srv_ctx) {
- if (w->ssl.conn) {
- SSL_SESSION *session = SSL_get_session(w->ssl.conn);
- SSL *old = w->ssl.conn;
- w->ssl.conn = SSL_new(netdata_ssl_srv_ctx);
- if (session) {
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_111
- if (SSL_SESSION_is_resumable(session))
-#endif
- SSL_set_session(w->ssl.conn, session);
- }
- SSL_free(old);
- }
- }
-}
-#endif
-
void web_client_zero(struct web_client *w) {
// zero everything about it - but keep the buffers
@@ -2105,8 +2033,7 @@ void web_client_zero(struct web_client *w) {
BUFFER *b6 = w->url_query_string_decoded;
#ifdef ENABLE_HTTPS
- web_client_reuse_ssl(w);
- SSL *ssl = w->ssl.conn;
+ NETDATA_SSL ssl = w->ssl;
#endif
size_t use_count = w->use_count;
@@ -2120,9 +2047,7 @@ void web_client_zero(struct web_client *w) {
w->use_count = use_count;
#ifdef ENABLE_HTTPS
- w->ssl.conn = ssl;
- w->ssl.flags = NETDATA_SSL_START;
- debug(D_WEB_CLIENT_ACCESS,"Reusing SSL structure with (w->ssl = NULL, w->accepted = %u)", w->ssl.flags);
+ w->ssl = ssl;
#endif
// restore the pointers of the buffers
@@ -2136,6 +2061,11 @@ void web_client_zero(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;
@@ -2152,6 +2082,10 @@ 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);
__atomic_sub_fetch(w->statistics.memory_accounting, sizeof(struct web_client), __ATOMIC_RELAXED);
diff --git a/web/server/web_client.h b/web/server/web_client.h
index c61a8b813..4c2b06a70 100644
--- a/web/server/web_client.h
+++ b/web/server/web_client.h
@@ -5,33 +5,7 @@
#include "libnetdata/libnetdata.h"
-#ifdef NETDATA_WITH_ZLIB
extern int web_enable_gzip, web_gzip_level, web_gzip_strategy;
-#endif /* NETDATA_WITH_ZLIB */
-
-// HTTP_CODES 2XX Success
-#define HTTP_RESP_OK 200
-
-// HTTP_CODES 3XX Redirections
-#define HTTP_RESP_MOVED_PERM 301
-#define HTTP_RESP_REDIR_TEMP 307
-#define HTTP_RESP_REDIR_PERM 308
-
-// HTTP_CODES 4XX Client Errors
-#define HTTP_RESP_BAD_REQUEST 400
-#define HTTP_RESP_UNAUTHORIZED 401
-#define HTTP_RESP_FORBIDDEN 403
-#define HTTP_RESP_NOT_FOUND 404
-#define HTTP_RESP_CONFLICT 409
-#define HTTP_RESP_PRECOND_FAIL 412
-#define HTTP_RESP_CONTENT_TOO_LONG 413
-
-// HTTP_CODES 5XX Server Errors
-#define HTTP_RESP_INTERNAL_SERVER_ERROR 500
-#define HTTP_RESP_BACKEND_FETCH_FAILED 503
-#define HTTP_RESP_SERVICE_UNAVAILABLE 503
-#define HTTP_RESP_GATEWAY_TIMEOUT 504
-#define HTTP_RESP_BACKEND_RESPONSE_INVALID 591
#define HTTP_REQ_MAX_HEADER_FETCH_TRIES 100
@@ -78,6 +52,8 @@ typedef enum web_client_flags {
WEB_CLIENT_FLAG_SSL_WAIT_RECEIVE = 1 << 11, // if set, we are waiting more input data from an ssl conn
WEB_CLIENT_FLAG_SSL_WAIT_SEND = 1 << 12, // if set, we have data to send to the client from an ssl conn
+
+ WEB_CLIENT_FLAG_PROXY_HTTPS = 1 << 13, // if set, the client reaches us via an https proxy
} WEB_CLIENT_FLAGS;
#define web_client_flag_check(w, flag) ((w)->flags & (flag))
@@ -145,13 +121,11 @@ struct response {
bool zoutput; // if set to 1, web_client_send() will send compressed data
-#ifdef NETDATA_WITH_ZLIB
bool zinitialized;
z_stream zstream; // zlib stream for sending compressed output to client
size_t zsent; // the compressed bytes we have sent to the client
size_t zhave; // the compressed bytes that we have received from zlib
Bytef zbuffer[NETDATA_WEB_RESPONSE_ZLIB_CHUNK_SIZE]; // temporary buffer for storing compressed output
-#endif /* NETDATA_WITH_ZLIB */
};
struct web_client;
@@ -196,7 +170,7 @@ struct web_client {
size_t pollinfo_filecopy_slot; // POLLINFO slot of the file read
#ifdef ENABLE_HTTPS
- struct netdata_ssl ssl;
+ NETDATA_SSL ssl;
#endif
struct { // A callback to check if the query should be interrupted / stopped
@@ -241,16 +215,10 @@ int mysendfile(struct web_client *w, char *filename);
void web_client_build_http_header(struct web_client *w);
char *strip_control_characters(char *url);
-int web_client_socket_is_now_used_for_streaming(struct web_client *w);
-
void web_client_zero(struct web_client *w);
struct web_client *web_client_create(size_t *statistics_memory_accounting);
void web_client_free(struct web_client *w);
-#ifdef ENABLE_HTTPS
-void web_client_reuse_ssl(struct web_client *w);
-#endif
-
#include "web/api/web_api_v1.h"
#include "web/api/web_api_v2.h"
#include "daemon/common.h"
diff --git a/web/server/web_client_cache.c b/web/server/web_client_cache.c
index b410ba7f9..394bea32b 100644
--- a/web/server/web_client_cache.c
+++ b/web/server/web_client_cache.c
@@ -104,11 +104,6 @@ struct web_client *web_client_get_from_cache(void) {
// allocate it
w = web_client_create(&netdata_buffers_statistics.buffers_web);
-#ifdef ENABLE_HTTPS
- w->ssl.flags = NETDATA_SSL_START;
- debug(D_WEB_CLIENT_ACCESS,"Starting SSL structure with (w->ssl = NULL, w->accepted = %u)", w->ssl.flags);
-#endif
-
netdata_spinlock_lock(&web_clients_cache.used.spinlock);
web_clients_cache.used.allocated++;
}
@@ -127,6 +122,11 @@ struct web_client *web_client_get_from_cache(void) {
}
void web_client_release_to_cache(struct web_client *w) {
+
+#ifdef ENABLE_HTTPS
+ netdata_ssl_close(&w->ssl);
+#endif
+
// unlink it from the used
netdata_spinlock_lock(&web_clients_cache.used.spinlock);
DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(web_clients_cache.used.head, w, cache.prev, cache.next);