From 9648b91ac1768e6a1777349dffaab9cc5cf6c13b Mon Sep 17 00:00:00 2001 From: Hanada Date: Mon, 27 Apr 2026 10:38:50 +0800 Subject: [PATCH] Stream: the $upstream_status variable. Keeps status code of upstream server. The status code reflects only the status of the upstream, not the code in the upstream response. Status codes of several responses are separated by commas like addresses in the $upstream_addr variable. If a server cannot be selected, the variable keeps the 502 status code. --- src/stream/ngx_stream_proxy_module.c | 6 +++ src/stream/ngx_stream_upstream.c | 58 ++++++++++++++++++++++++++++ src/stream/ngx_stream_upstream.h | 1 + 3 files changed, 65 insertions(+) diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index c358c8647..5c0413f20 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -2198,6 +2198,8 @@ ngx_stream_proxy_next_upstream(ngx_stream_session_t *s) pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + u->state->status = NGX_STREAM_BAD_GATEWAY; + timeout = pscf->next_upstream_timeout; if (u->peer.tries == 0 @@ -2260,6 +2262,10 @@ ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_uint_t rc) u->state->response_time = ngx_current_msec - u->start_time; } + if (u->state->status == 0) { + u->state->status = rc; + } + if (pc) { u->state->bytes_received = u->received; u->state->bytes_sent = pc->sent; diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c index 006672cdf..319d4534d 100644 --- a/src/stream/ngx_stream_upstream.c +++ b/src/stream/ngx_stream_upstream.c @@ -13,6 +13,8 @@ static ngx_int_t ngx_stream_upstream_add_variables(ngx_conf_t *cf); static ngx_int_t ngx_stream_upstream_addr_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_upstream_status_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_upstream_response_time_variable( ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_upstream_bytes_variable(ngx_stream_session_t *s, @@ -103,6 +105,10 @@ static ngx_stream_variable_t ngx_stream_upstream_vars[] = { ngx_stream_upstream_addr_variable, 0, NGX_STREAM_VAR_NOCACHEABLE, 0 }, + { ngx_string("upstream_status"), NULL, + ngx_stream_upstream_status_variable, 0, + NGX_STREAM_VAR_NOCACHEABLE, 0 }, + { ngx_string("upstream_bytes_sent"), NULL, ngx_stream_upstream_bytes_variable, 0, NGX_STREAM_VAR_NOCACHEABLE, 0 }, @@ -203,6 +209,58 @@ ngx_stream_upstream_addr_variable(ngx_stream_session_t *s, } +static ngx_int_t +ngx_stream_upstream_status_variable(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + size_t len; + ngx_uint_t i; + ngx_stream_upstream_state_t *state; + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + if (s->upstream_states == NULL || s->upstream_states->nelts == 0) { + v->not_found = 1; + return NGX_OK; + } + + len = s->upstream_states->nelts * (3 + 2); + + p = ngx_pnalloc(s->connection->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + v->data = p; + + i = 0; + state = s->upstream_states->elts; + + for ( ;; ) { + if (state[i].status) { + p = ngx_sprintf(p, "%ui", state[i].status); + + } else { + *p++ = '-'; + } + + if (++i == s->upstream_states->nelts) { + break; + } + + *p++ = ','; + *p++ = ' '; + } + + v->len = p - v->data; + + return NGX_OK; +} + + static ngx_int_t ngx_stream_upstream_bytes_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index c581aa0be..2a9b99382 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -93,6 +93,7 @@ struct ngx_stream_upstream_srv_conf_s { typedef struct { + ngx_uint_t status; ngx_msec_t response_time; ngx_msec_t connect_time; ngx_msec_t first_byte_time;