$upstream_http_NAME and $sent_http_NAME vars not available in certain scopes
neilstuartcraig
nginx-forum at forum.nginx.org
Wed Mar 30 11:11:45 UTC 2016
Hi all
I am developing a proxy service which uses NGINX to reverse proxy, kind of
CDN-like but very specific to our needs. During this. I have hit an issue
which I *think* is a bug but wanted to ask in case anyone can point to a
solution or some reading I can do. The problem I have is this:
$upstream_http_NAME and $sent_http_NAME variables seem to be
unpopulated/blank at some points in my config when other embedded variables
*are* populated. This is probably best illustrated via an example, so here's
a simplified test case I created:
user nginx;
worker_processes auto;
worker_priority -15;
worker_rlimit_nofile 50000;
events {
# worker_connections benefits from a large value in that it reduces
error counts
worker_connections 20000;
multi_accept on;
}
http {
# for dynamic upstreams
resolver 8.8.8.8;
# Default includes
include /etc/nginx/current/mime.types;
default_type application/octet-stream;
include /etc/nginx/current/proxy.conf;
# Tuning options - these are mainly quite GTM-specific
server_tokens off;
keepalive_requests 1024;
keepalive_timeout 120s 120s;
sendfile on;
tcp_nodelay on;
tcp_nopush on;
client_header_timeout 5s;
open_file_cache max=16384 inactive=600s;
open_file_cache_valid 600s;
open_file_cache_min_uses 0;
open_file_cache_errors on;
output_buffers 64 128k;
# NEW - AIO
aio on;
directio 512;
# For small files and heavy load, this gives ~5-6x greater throughput
(avoids swamping workers with one request)
postpone_output 0;
reset_timedout_connection on;
send_timeout 3s;
sendfile_max_chunk 1m;
large_client_header_buffers 8 8k;
connection_pool_size 4096;
# client_body_buffer_size - Sets buffer size for reading client request
body. In case the request body is larger than the buffer, the whole body or
only its part is written to a temporary file
client_body_buffer_size 8k;
client_header_buffer_size 8k;
# client_max_body_size - Sets the maximum allowed size of the client
request body, specified in the “Content-Length” request header field. If the
size in a request exceeds the configured value, the 413 (Request Entity Too
Large) error is returned to the client
client_max_body_size 8m;
# We need to increase the hash bucket size as the R53 names are long!
server_names_hash_bucket_size 128;
# Same for proxy_headers_hash_max_size and proxy_headers_hash_bucket_size
proxy_headers_hash_max_size 4096;
proxy_headers_hash_bucket_size 1024;
# Logging
# NOTE: $host may need to in fact be $hostname
log_format standard '"$remote_addr" "$time_iso8601" "$request_method"
"$scheme" "$host" "$request_uri" "$server_protocol" "$status" "$bytes_sent"
"$http_referer" "$http_user_agent" "$ssl_protocol" "$ssl_cipher"
"$ssl_server_name" "$ssl_session_reused"';
access_log /var/log/nginx/main-access.log standard;
error_log /var/log/nginx/main-error.log warn;
recursive_error_pages on;
# GeoIP config
# This appears to need an absolute path, despite the docs suggesting it
doesn't.
# Path is defined in bake script so changes to that will break this
# geoip_country /usr/local/GeoIP.dat;
geoip_city /var/lib/GeoIP/GeoLiteCity.dat;
#geoip_proxy 0.0.0.0/0;
#geoip_proxy_recursive on;
# Proxy global configuration
# NOTES:
# proxy_cache_path is an http scope (global) directive
# keys_zone=shared_cache:XXXXm; denotes the amount of RAM to allow for
cache index, 1MB ~7k-8k cached objects - exceeding the number of cached
objects possible due to index size results in LRU invocation
proxy_cache_path /mnt/gtm_cache_data levels=1:2 use_temp_path=on
keys_zone=shared_cache:256m inactive=1440m;
proxy_temp_path /mnt/gtm_cache_temp;
# NGINX recommends HTTP 1.1 for keepalive, proxied conns. (which we use)
proxy_http_version 1.1;
# NGINX recommends clearing the connection request header for keepalive
http 1.1 conns
proxy_set_header Connection "";
# Conditions under which we want to try then next (if there is one)
upstream server in the list & timeouts
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503
http_504;
proxy_next_upstream_timeout 5s;
proxy_next_upstream_tries 3;
ssl_session_cache shared:global_ssl_cache:128m;
ssl_session_timeout 120m;
ssl_session_tickets on;
#ssl_session_ticket_key /etc/nginx/current/tls/session/tkt.key;
# TEST CASE:
# Set up a DNS or hosts file entry to point to your NGINX instance running
this config
# Hit this with URL:
https://<HOSTNAME>/response-headers?Content-Type=text%2Fplain%3B+charset%3DUTF-8&via=1.1%20httpbin3&tester=hello
# To try to check if we can work around the problem below (vars not
existing (?) at time of use/need), we'll try to copy the var via a map
map $upstream_http_via $copy_map_upstream_http_via {
default $upstream_http_via;
}
upstream origin {
server httpbin.org:443 resolve;
}
# Generic/common server for listen port configs
server {
# TMP removing fastopen=None backlog=-1 as the directives don't work!
listen *:80 so_keepalive=120s:30s:20 default_server;
listen *:443 ssl http2 reuseport deferred so_keepalive=120s:30s:20
default_server;
# This cert & key will never actually be used but are needed to allow the
:443 operation - without them the connection will be closed
ssl_certificate /etc/nginx/current/tls/certs/default.crt;
ssl_certificate_key /etc/nginx/current/tls/private/default.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
location / {
# To try to check if we can work around the problem below (vars not
existing (?) at time of use/need), we'll try to copy the var via a set
set $copy_set_upstream_http_via $upstream_http_via;
more_set_headers "SENT_HTTP_VIA: $sent_http_via";
more_set_headers "HTTP_VIA: $http_via";
more_set_headers "UPSTREAM_HTTP_VIA: $upstream_http_via";
# For ref, the upstream is sending e.g. "via: 1.1 string"
# Problem: These do not match, $upstream_http_via appears not to be
populated at this point
# if ( $sent_http_via ~* "^[0-9]\.[0-9]\ .+$" ) {
# if ($upstream_http_via ~* "^[0-9]\.[0-9]\ .+") {
# if ($sent_http_via ~* "^[0-9]\.[0-9]\ .+") {
# if ($upstream_http_via) {
# This does match - for obvious reasons
if ($upstream_http_via ~* ".*") {
# Problem: $upstream_http_via appears not to be populated at this
point...
set $via_comp "$upstream_http_via 1.y BLAH";
more_set_headers "IF_VIA_COMP: Value is $via_comp";
# Just to demo the string concat - we'll use a different embedded var
set $test_comp "$ssl_protocol BLAH";
more_set_headers "IF_TEST_COMP: Value is
$test_comp";
# Does the map-copied var exist?
set $via_comp_copy_map "$copy_map_upstream_http_via 1.y BLAH";
more_set_headers "IF_VIA_COMP_COPY_MAP:
Value is $via_comp_copy_map";
# Does the set-copied var exist?
set $via_comp_copy_set "$copy_set_upstream_http_via 1.y BLAH";
more_set_headers "IF_VIA_COMP_COPY_SET:
Value is $via_comp_copy_set";
# Does a different $upstream_http_X var work? - NO
set $alt_comp "$upstream_http_tester 1.y BLAH";
more_set_headers "IF_ALT_COMP: Value is
$alt_comp";
# ...but $upstream_http_via IS populated at this point
more_set_headers "UPSTREAM_HTTP_VIA_IF: $upstream_http_via";
more_set_headers "HTTP_VIA_IF: $http_via";
more_set_headers "SENT_HTTP_VIA_IF: $sent_http_via";
}
proxy_pass https://origin;
}
# END TEST CASE
}
}
(Sorry, couldn't figure out how to markup the config)
The response headers from a request to this NGIX instance is e.g.:
access-control-allow-credentials:true
access-control-allow-origin:*
content-length:161
content-type:text/plain; charset=UTF-8
date:Wed, 30 Mar 2016 10:31:55 GMT
if_alt_comp:Value is 1.y BLAH
if_test_comp:Value is TLSv1.2 BLAH
if_via_comp:Value is 1.y BLAH
if_via_comp_copy_map:Value is 1.y BLAH
if_via_comp_copy_set:Value is 1.y BLAH
sent_http_via:1.1 httpbin3
sent_http_via_if:1.1 httpbin3
server:nginx
status:200
tester:hello
upstream_http_via:1.1 httpbin3
upstream_http_via_if:1.1 httpbin3
via:1.1 httpbin3
So you can see from the section:
if_alt_comp:Value is 1.y BLAH
if_test_comp:Value is TLSv1.2 BLAH
if_via_comp:Value is 1.y BLAH
if_via_comp_copy_map:Value is 1.y BLAH
if_via_comp_copy_set:Value is 1.y BLAH
That there's a blank space where the value from $upstream_http_via or
$sent_http_via should be.
So my questions are:
Can anyone see something I have done wrong?
Is this expected behaviour (if yes, why? Seems strange some vars behave
differently)
Does anyone have a workaround or solution?
Many thanks in advance if anyone can offer any help.
Cheers
Neil
Posted at Nginx Forum: https://forum.nginx.org/read.php?2,265734,265734#msg-265734
More information about the nginx
mailing list