Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions src/ngx_http_vhost_traffic_status_display_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@
#endif


#if (nginx_version > 1027003) && defined(NGX_HTTP_UPSTREAM_MODIFY) && !defined(NGX_HTTP_UPSTREAM_CHECK)
static u_char *
ngx_http_vhost_traffic_status_display_ug_host(
ngx_http_request_t *r,
ngx_str_t host,
ngx_rbtree_node_t *node,
ngx_rbtree_node_t *sentinel,
ngx_http_upstream_rr_peers_t *peers,
u_char *buf);
#endif

u_char *
ngx_http_vhost_traffic_status_display_set_main(ngx_http_request_t *r,
u_char *buf)
Expand Down Expand Up @@ -633,6 +644,50 @@ ngx_http_vhost_traffic_status_display_set_upstream_group(ngx_http_request_t *r,

zone = 1;

#if (nginx_version > 1027003) && defined(NGX_HTTP_UPSTREAM_MODIFY) && !defined(NGX_HTTP_UPSTREAM_CHECK)
if (uscf->flags & NGX_HTTP_UPSTREAM_MODIFY) {
peers = uscf->peer.data;
buf = ngx_http_vhost_traffic_status_display_ug_host(r, uscf->host, ctx->rbtree->root, ctx->rbtree->sentinel, peers, buf);
} else {
for (peers = uscf->peer.data; peers; peers = peers->next) {
ngx_http_upstream_rr_peers_rlock(peers);
for (peer = peers->peer; peer; peer = peer->next) {
p = ngx_cpymem(p, uscf->host.data, uscf->host.len);
*p++ = NGX_HTTP_VHOST_TRAFFIC_STATUS_KEY_SEPARATOR;
p = ngx_cpymem(p, peer->name.data, peer->name.len);

dst.len = uscf->host.len + sizeof("@") - 1 + peer->name.len;

rc = ngx_http_vhost_traffic_status_node_generate_key(r->pool, &key, &dst, type);
if (rc != NGX_OK) {
ngx_http_upstream_rr_peers_unlock(peers);
return buf;
}

hash = ngx_crc32_short(key.data, key.len);
node = ngx_http_vhost_traffic_status_node_lookup(ctx->rbtree, &key, hash);

usn.weight = peer->weight;
usn.max_fails = peer->max_fails;
usn.fail_timeout = peer->fail_timeout;
usn.backup = 0;
usn.down = (peer->fails >= peer->max_fails || peer->down);
usn.name = peer->name;

if (node != NULL) {
vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color;
buf = ngx_http_vhost_traffic_status_display_set_upstream_node(r, buf, &usn, vtsn);
} else {
buf = ngx_http_vhost_traffic_status_display_set_upstream_node(r, buf, &usn, NULL);
}
p = dst.data;
}
ngx_http_upstream_rr_peers_unlock(peers);
}
}
goto last;
Copy link
Preview

Copilot AI Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using goto statements can make code harder to follow. Consider restructuring the logic to avoid the goto by using early returns or restructuring the conditional blocks.

Copilot uses AI. Check for mistakes.

#endif

peers = uscf->peer.data;

ngx_http_upstream_rr_peers_rlock(peers);
Expand Down Expand Up @@ -744,6 +799,9 @@ ngx_http_vhost_traffic_status_display_set_upstream_group(ngx_http_request_t *r,
}
}

#if (nginx_version > 1027003) && defined(NGX_HTTP_UPSTREAM_MODIFY) && !defined(NGX_HTTP_UPSTREAM_CHECK)
last:
#endif
if (s == buf) {
buf = o;

Expand Down Expand Up @@ -970,4 +1028,59 @@ ngx_http_vhost_traffic_status_display_set(ngx_http_request_t *r,
return buf;
}

#if (nginx_version > 1027003) && defined(NGX_HTTP_UPSTREAM_MODIFY) && !defined(NGX_HTTP_UPSTREAM_CHECK)
static u_char *
ngx_http_vhost_traffic_status_display_ug_host(
ngx_http_request_t *r,
ngx_str_t host,
ngx_rbtree_node_t *node,
ngx_rbtree_node_t *sentinel,
ngx_http_upstream_rr_peers_t *peers,
u_char *buf)
{
ngx_int_t rc;
ngx_http_upstream_server_t usn;
ngx_http_upstream_rr_peer_t *peer;
ngx_http_upstream_rr_peers_t *base_peers;
ngx_http_vhost_traffic_status_node_t *vtsn;

base_peers = peers;
if (node != sentinel) {
vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color;
if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG) {
if (vtsn->len >= NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_KEY_LEN + host.len) {
rc = ngx_memn2cmp(host.data, vtsn->data + NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_PREFIX_LEN, host.len, (size_t) host.len);
if (rc == 0) {
usn.name.data = vtsn->data + NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_PREFIX_LEN + host.len + 1;
usn.name.len = vtsn->len - host.len - NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_KEY_LEN;
usn.weight = 0;
usn.max_fails = 0;
usn.fail_timeout = 0;
usn.backup = 0;
usn.down = 0;
while (peers != NULL) {
Copy link
Preview

Copilot AI Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nested loop structure with peers traversal inside the tree traversal could lead to O(n²) complexity. Consider optimizing by caching peer lookups or restructuring the algorithm.

Copilot uses AI. Check for mistakes.

ngx_http_upstream_rr_peers_rlock(peers);
for (peer = peers->peer; peer; peer = peer->next) {
rc = ngx_memn2cmp(peer->name.data, usn.name.data, peer->name.len, (size_t) usn.name.len);
if (rc == 0) {
usn.weight = peer->weight;
usn.max_fails = peer->max_fails;
usn.fail_timeout = peer->fail_timeout;
usn.backup = 0;
usn.down = (peer->fails >= peer->max_fails || peer->down);
}
}
Comment on lines +1064 to +1072
Copy link
Preview

Copilot AI Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The memory comparison uses different lengths (peer->name.len vs usn.name.len) which could lead to incorrect matches when one name is a prefix of another. Both lengths should be equal for a valid match.

Suggested change
rc = ngx_memn2cmp(peer->name.data, usn.name.data, peer->name.len, (size_t) usn.name.len);
if (rc == 0) {
usn.weight = peer->weight;
usn.max_fails = peer->max_fails;
usn.fail_timeout = peer->fail_timeout;
usn.backup = 0;
usn.down = (peer->fails >= peer->max_fails || peer->down);
}
}
if (peer->name.len == usn.name.len) {
rc = ngx_memn2cmp(peer->name.data, usn.name.data, peer->name.len, (size_t) usn.name.len);
if (rc == 0) {
usn.weight = peer->weight;
usn.max_fails = peer->max_fails;
usn.fail_timeout = peer->fail_timeout;
usn.backup = 0;
usn.down = (peer->fails >= peer->max_fails || peer->down);
}
} // End of length check

Copilot uses AI. Check for mistakes.

ngx_http_upstream_rr_peers_unlock(peers);
peers = peers->next;
}
buf = ngx_http_vhost_traffic_status_display_set_upstream_node(r, buf, &usn, vtsn);
}
}
}
buf = ngx_http_vhost_traffic_status_display_ug_host(r, host, node->left, sentinel, base_peers, buf);
buf = ngx_http_vhost_traffic_status_display_ug_host(r, host, node->right, sentinel, base_peers, buf);
}
return buf;
}
#endif
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
3 changes: 3 additions & 0 deletions src/ngx_http_vhost_traffic_status_display_json.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@
"},"

#if (NGX_HTTP_CACHE)
Copy link
Preview

Copilot AI Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magic number 3 should be documented or replaced with a more descriptive calculation to explain what this prefix length represents.

Suggested change
#if (NGX_HTTP_CACHE)
#if (NGX_HTTP_CACHE)
// The prefix length for upstream traffic status keys. This value is derived
// from the fixed format of upstream keys, which use a 3-character prefix.

Copilot uses AI. Check for mistakes.

#define NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_PREFIX_LEN 3
#define NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_KEY_LEN 4

Comment on lines +184 to +185
Copy link
Preview

Copilot AI Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magic number 4 should be documented or replaced with a more descriptive calculation to explain what this key length represents.

Suggested change
#define NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_KEY_LEN 4
// The length of the upstream key used in traffic status calculations.
#define NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_KEY_LENGTH 4

Copilot uses AI. Check for mistakes.

#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CACHE_S "\"cacheZones\":{"
#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CACHE "\"%V\":{" \
"\"maxSize\":%uA," \
Expand Down