On Sat, Nov 23, 2013 at 12:15:28PM +1030, SplitIce wrote: > Attached is the patch, > > This is the first time I have created a variable or really done anything > inside the http request processing flow so feel free to let me know if > there is a better way to do something or if I have any edge cases. > > This patch provides a $upstream_connecting variable which contains the IP > address and port of the upstream being connected. If there is no upstream, > it will return "-" my understanding is this may happen if the upstream is > DNS resolved (untested). There may be a better way of doing this? > > This should be used in a config like the following - > map $upstream_connecting $test { > ~^93\.184\.216\.119\: 192.168.2.40; > ~^192\.168\.2\.([0-9]+)\: 192.168.2.40; > } > > proxy_bind $test;
I took a different approach. I've made "local" a peer's method, so the computation of the local address is delayed until it's actually needed. By that time, the peer address is already known. I've also patched "map" so it creates non-cacheable variables. This way, $upstream_peer_addr can be mapped into the local address: map $upstream_peer_addr $bind_addr { 127.0.0.1:8001 127.0.0.1; 127.0.0.1:8002 127.0.0.1; [::1]:8003 ::1; } server { ... location / { proxy_pass ...; proxy_bind $bind_addr; ... } } diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -17,6 +17,7 @@ ngx_event_connect_peer(ngx_peer_connecti int rc; ngx_int_t event; ngx_err_t err; + ngx_addr_t *local; ngx_uint_t level; ngx_socket_t s; ngx_event_t *rev, *wev; @@ -67,9 +68,13 @@ ngx_event_connect_peer(ngx_peer_connecti } if (pc->local) { - if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) { + local = pc->local(pc, pc->data); + + if (local != NULL + && bind(s, local->sockaddr, local->socklen) == -1) + { ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno, - "bind(%V) failed", &pc->local->name); + "bind(%V) failed", &local->name); goto failed; } diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -25,6 +25,8 @@ typedef ngx_int_t (*ngx_event_get_peer_p void *data); typedef void (*ngx_event_free_peer_pt)(ngx_peer_connection_t *pc, void *data, ngx_uint_t state); +typedef ngx_addr_t *(*ngx_event_get_local_pt)(ngx_peer_connection_t *pc, + void *data); #if (NGX_SSL) typedef ngx_int_t (*ngx_event_set_peer_session_pt)(ngx_peer_connection_t *pc, @@ -45,6 +47,7 @@ struct ngx_peer_connection_s { ngx_event_get_peer_pt get; ngx_event_free_peer_pt free; + ngx_event_get_local_pt local; void *data; #if (NGX_SSL) @@ -56,8 +59,6 @@ struct ngx_peer_connection_s { ngx_atomic_t *lock; #endif - ngx_addr_t *local; - int rcvbuf; ngx_log_t *log; diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c --- a/src/http/modules/ngx_http_map_module.c +++ b/src/http/modules/ngx_http_map_module.c @@ -477,7 +477,7 @@ ngx_http_map(ngx_conf_t *cf, ngx_command } var->valid = 1; - var->no_cacheable = 0; + var->no_cacheable = 1; var->not_found = 0; vp = ngx_array_push(&ctx->values_hash[key]); diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -31,6 +31,7 @@ typedef struct { ngx_event_get_peer_pt original_get_peer; ngx_event_free_peer_pt original_free_peer; + ngx_event_get_local_pt original_get_local; #if (NGX_HTTP_SSL) ngx_event_set_peer_session_pt original_set_session; @@ -63,6 +64,9 @@ static void ngx_http_upstream_keepalive_ static void ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev); static void ngx_http_upstream_keepalive_close(ngx_connection_t *c); +static ngx_addr_t *ngx_http_upstream_get_keepalive_local( + ngx_peer_connection_t *pc, void *data); + #if (NGX_HTTP_SSL) static ngx_int_t ngx_http_upstream_keepalive_set_session( @@ -189,10 +193,12 @@ ngx_http_upstream_init_keepalive_peer(ng kp->data = r->upstream->peer.data; kp->original_get_peer = r->upstream->peer.get; kp->original_free_peer = r->upstream->peer.free; + kp->original_get_local = r->upstream->peer.local; r->upstream->peer.data = kp; r->upstream->peer.get = ngx_http_upstream_get_keepalive_peer; r->upstream->peer.free = ngx_http_upstream_free_keepalive_peer; + r->upstream->peer.local = ngx_http_upstream_get_keepalive_local; #if (NGX_HTTP_SSL) kp->original_set_session = r->upstream->peer.set_session; @@ -430,6 +436,16 @@ ngx_http_upstream_keepalive_close(ngx_co } +static ngx_addr_t * +ngx_http_upstream_get_keepalive_local(ngx_peer_connection_t *pc, + void *data) +{ + ngx_http_upstream_keepalive_peer_data_t *kp = data; + + return kp->original_get_local(pc, kp->data); +} + + #if (NGX_HTTP_SSL) static ngx_int_t diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -141,14 +141,13 @@ static ngx_int_t ngx_http_upstream_respo ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_upstream_response_length_variable( ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_upstream_peer_addr_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy); static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static ngx_addr_t *ngx_http_upstream_get_local(ngx_http_request_t *r, - ngx_http_upstream_local_t *local); - static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf); static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf); @@ -366,6 +365,10 @@ static ngx_http_variable_t ngx_http_ups #endif + { ngx_string("upstream_peer_addr"), NULL, + ngx_http_upstream_peer_addr_variable, 0, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -534,8 +537,6 @@ ngx_http_upstream_init_request(ngx_http_ return; } - u->peer.local = ngx_http_upstream_get_local(r, u->conf->local); - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); u->output.alignment = clcf->directio_alignment; @@ -4509,6 +4510,25 @@ ngx_http_upstream_response_length_variab } +static ngx_int_t +ngx_http_upstream_peer_addr_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + if (r->upstream == NULL || r->upstream->peer.name == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->len = r->upstream->peer.name->len; + v->data = r->upstream->peer.name->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -5022,53 +5042,6 @@ ngx_http_upstream_bind_set_slot(ngx_conf } -static ngx_addr_t * -ngx_http_upstream_get_local(ngx_http_request_t *r, - ngx_http_upstream_local_t *local) -{ - ngx_int_t rc; - ngx_str_t val; - ngx_addr_t *addr; - - if (local == NULL) { - return NULL; - } - - if (local->value == NULL) { - return local->addr; - } - - if (ngx_http_complex_value(r, local->value, &val) != NGX_OK) { - return NULL; - } - - if (val.len == 0) { - return NULL; - } - - addr = ngx_palloc(r->pool, sizeof(ngx_addr_t)); - if (addr == NULL) { - return NULL; - } - - rc = ngx_parse_addr(r->pool, addr, val.data, val.len); - - switch (rc) { - case NGX_OK: - addr->name = val; - return addr; - - case NGX_DECLINED: - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "invalid local address \"%V\"", &val); - /* fall through */ - - default: - return NULL; - } -} - - char * ngx_http_upstream_param_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -22,6 +22,9 @@ static void ngx_http_upstream_empty_save #endif +static ngx_addr_t *ngx_http_upstream_get_local(ngx_peer_connection_t *pc, + void *data); + ngx_int_t ngx_http_upstream_init_round_robin(ngx_conf_t *cf, @@ -246,6 +249,8 @@ ngx_http_upstream_init_round_robin_peer( } } + rrp->request = r; + r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer; r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer; r->upstream->peer.tries = rrp->peers->number; @@ -255,6 +260,7 @@ ngx_http_upstream_init_round_robin_peer( r->upstream->peer.save_session = ngx_http_upstream_save_round_robin_peer_session; #endif + r->upstream->peer.local = ngx_http_upstream_get_local; return NGX_OK; } @@ -679,3 +685,56 @@ ngx_http_upstream_empty_save_session(ngx } #endif + + +static ngx_addr_t * +ngx_http_upstream_get_local(ngx_peer_connection_t *pc, void *data) +{ + ngx_http_upstream_rr_peer_data_t *rrp = data; + + ngx_int_t rc; + ngx_str_t val; + ngx_addr_t *addr; + ngx_http_request_t *r; + ngx_http_upstream_local_t *local; + + r = rrp->request; + local = r->upstream->conf->local; + + if (local == NULL) { + return NULL; + } + + if (local->value == NULL) { + return local->addr; + } + + if (ngx_http_complex_value(r, local->value, &val) != NGX_OK) { + return NULL; + } + + if (val.len == 0) { + return NULL; + } + + addr = ngx_palloc(r->pool, sizeof(ngx_addr_t)); + if (addr == NULL) { + return NULL; + } + + rc = ngx_parse_addr(r->pool, addr, val.data, val.len); + + switch (rc) { + case NGX_OK: + addr->name = val; + return addr; + + case NGX_DECLINED: + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid local address \"%V\"", &val); + /* fall through */ + + default: + return NULL; + } +} diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h --- a/src/http/ngx_http_upstream_round_robin.h +++ b/src/http/ngx_http_upstream_round_robin.h @@ -63,6 +63,7 @@ typedef struct { ngx_uint_t current; uintptr_t *tried; uintptr_t data; + ngx_http_request_t *request; } ngx_http_upstream_rr_peer_data_t; _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel