nginx provides flexible way to manipulate headers, you can do this by directive or by lua, here we only say directive, headers can be request header or response header, that means nginx gives you the way to manipulate request header before sending to upstream and response header before sending to client. nginx supports
add a header
update existing header
delete a header
request header related directive before sending to upstream
proxy_set_header
response header related directives before sending to client
add_header
proxy_ignore_headers
proxy_hide_header
proxy_pass_header
Header building
For proxy header sent to upstream, it depends on three parts.
request sent(header in request itself) lowest priority
default behavior for some proxy headers
user setting by directive(proxy_set_header) highest priority
First check user setting, if has, use that value, otherwise, use default behavior for some proxy headers, if not header has no default behavior, just pass it to upstream.
For response header sent to client, it depends on two parts.
ignore/hide
user setting by directive(add_header) highest priority
First check user setting, if has, use that value, otherwise not send to client if ignored or hidden.
Data Structure
proxy header(most headers from client) sent to upstream
typedefstruct { /* as proxy headers value can have variable, so need to compile it, then saved at values(handler) * hash is the hash table for proxy header name */ ngx_array_t *flushes; ngx_array_t *lengths; ngx_array_t *values; ngx_hash_t hash; } ngx_http_proxy_headers_t;
/* headers(used runtime sent to backend) are merged result from two parts * default proxy header : ngx_http_proxy_headers * header set by proxy_set_header directive : headers_source(high priority) */ ngx_http_proxy_headers_t headers;
/* headers set by proxy_set_header directive, user defines * proxy_set_header supports using variable as value like this: * proxy_set_header Host $http_host; */ ngx_array_t *headers_source; // ngx_keyval_t array };
/* * default proxy headers(overwrite such header if client sends it as well) * these headers will be sent/removed when sending request to backend * * like { ngx_string("TE"), ngx_string("")} means remove such header * when sending request to backend, even client sends it. * * these can be overwritten by proxy_set_header * because we merge these two parts during conf * but proxy_set_header has higher priority */ staticngx_keyval_t ngx_http_proxy_headers[] = { { ngx_string("Host"), ngx_string("$proxy_host") }, /* if no set default Connection header is set with Connection: close when send request to upstream */ { ngx_string("Connection"), ngx_string("close") }, { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") }, { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") }, { ngx_string("TE"), ngx_string("") }, { ngx_string("Keep-Alive"), ngx_string("") }, { ngx_string("Expect"), ngx_string("") }, { ngx_string("Upgrade"), ngx_string("") }, { ngx_null_string, ngx_null_string } };
response header sent to client(hide or ignore some headers)
// response header sent to client(hide or ignore some headers) typedefstruct { /* ignore header bit for supported ignore header, user can only ignore these headers * you can ignore processing these response headers(limit scope) from backend * no set var etc * ngx_conf_bitmask_t ngx_http_upstream_ignore_headers_masks[] = { * { ngx_string("X-Accel-Redirect"), NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT }, * { ngx_string("X-Accel-Expires"), NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES }, * { ngx_string("X-Accel-Limit-Rate"), NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE }, * { ngx_string("X-Accel-Buffering"), NGX_HTTP_UPSTREAM_IGN_XA_BUFFERING }, * { ngx_string("X-Accel-Charset"), NGX_HTTP_UPSTREAM_IGN_XA_CHARSET }, * { ngx_string("Expires"), NGX_HTTP_UPSTREAM_IGN_EXPIRES }, * { ngx_string("Cache-Control"), NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL }, * { ngx_string("Set-Cookie"), NGX_HTTP_UPSTREAM_IGN_SET_COOKIE }, * { ngx_string("Vary"), NGX_HTTP_UPSTREAM_IGN_VARY }, * { ngx_null_string, 0 } * }; * by default, no header is ignored */ ngx_uint_t ignore_headers;
/* hide_headers for quick searching */ ngx_hash_t hide_headers_hash;
/* by default nginx will hide some headers when send response to client * these headers like Server, you can also add more hide header by proxy_hide_header * * if you don't hide some default headers you can use * proxy_pass_header to exclude them from hide_headers */
/* both ignore and hiding headers are not processed, so you can't get that header value by ngx.header.xx * but ignore header has limit group, only support some headers * hide header can hide any header, that's the difference / ngx_array_t *hide_headers; ngx_array_t *pass_headers; } ngx_http_upstream_conf_t; static ngx_str_t ngx_http_proxy_hide_headers[] = { /* by default, we did NOT send these to client, but you can use proxy_pass_header to exclude a header * let nginx sends it to client */ ngx_string("Date"), // exception: Date means NOT use Date header from backend, but use nginx cache time, still send Date to client!!! ngx_string("Server"), ngx_string("X-Pad"), ngx_string("X-Accel-Expires"), ngx_string("X-Accel-Redirect"), ngx_string("X-Accel-Limit-Rate"), ngx_string("X-Accel-Buffering"), ngx_string("X-Accel-Charset"), ngx_null_string };
typedefstruct { // set by add_header directive(user setting response header) ngx_array_t *headers; } ngx_http_headers_conf_t;
// build r->headers_in from request header staticvoidngx_http_process_request_headers(ngx_event_t *rev);
//build header sent to upstream(backend), create a temp buffer to hold all header copied from r->headers_in staticngx_int_tngx_http_proxy_create_request(ngx_http_request_t *r); // build header sent to client(set r->headers_out) when parsed all response headers staticngx_int_tngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u);
// header filter to add/update/remove(manipulate r->headers_out) response header staticngx_int_tngx_http_headers_filter(ngx_http_request_t *r); // last header filter based on r->headers_out create a temp buffer to hold all header copied from r->headers_out, then send it out staticngx_int_tngx_http_header_filter(ngx_http_request_t *r)