Reworked multi headers to use linked lists.

Multi headers are now using linked lists instead of arrays.  Notably,
the following fields were changed: r->headers_in.cookies (renamed
to r->headers_in.cookie), r->headers_in.x_forwarded_for,
r->headers_out.cache_control, r->headers_out.link, u->headers_in.cache_control
u->headers_in.cookies (renamed to u->headers_in.set_cookie).

The r->headers_in.cookies and u->headers_in.cookies fields were renamed
to r->headers_in.cookie and u->headers_in.set_cookie to match header names.

The ngx_http_parse_multi_header_lines() and ngx_http_parse_set_cookie_lines()
functions were changed accordingly.

With this change, multi headers are now essentially equivalent to normal
headers, and following changes will further make them equivalent.
This commit is contained in:
Maxim Dounin 2022-05-30 21:25:33 +03:00
parent 7dc6f4e25d
commit 3aef1d693f
17 changed files with 175 additions and 245 deletions

View File

@ -327,15 +327,15 @@ static ngx_int_t
ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx, ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx,
ngx_addr_t *addr) ngx_addr_t *addr)
{ {
ngx_array_t *xfwd; ngx_table_elt_t *xfwd;
if (ngx_http_geo_real_addr(r, ctx, addr) != NGX_OK) { if (ngx_http_geo_real_addr(r, ctx, addr) != NGX_OK) {
return NGX_ERROR; return NGX_ERROR;
} }
xfwd = &r->headers_in.x_forwarded_for; xfwd = r->headers_in.x_forwarded_for;
if (xfwd->nelts > 0 && ctx->proxies != NULL) { if (xfwd != NULL && ctx->proxies != NULL) {
(void) ngx_http_get_forwarded_addr(r, addr, xfwd, NULL, (void) ngx_http_get_forwarded_addr(r, addr, xfwd, NULL,
ctx->proxies, ctx->proxy_recursive); ctx->proxies, ctx->proxy_recursive);
} }

View File

@ -240,16 +240,16 @@ static u_long
ngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf) ngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
{ {
ngx_addr_t addr; ngx_addr_t addr;
ngx_array_t *xfwd; ngx_table_elt_t *xfwd;
struct sockaddr_in *sin; struct sockaddr_in *sin;
addr.sockaddr = r->connection->sockaddr; addr.sockaddr = r->connection->sockaddr;
addr.socklen = r->connection->socklen; addr.socklen = r->connection->socklen;
/* addr.name = r->connection->addr_text; */ /* addr.name = r->connection->addr_text; */
xfwd = &r->headers_in.x_forwarded_for; xfwd = r->headers_in.x_forwarded_for;
if (xfwd->nelts > 0 && gcf->proxies != NULL) { if (xfwd != NULL && gcf->proxies != NULL) {
(void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL, (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL,
gcf->proxies, gcf->proxy_recursive); gcf->proxies, gcf->proxy_recursive);
} }
@ -292,7 +292,7 @@ static geoipv6_t
ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf) ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
{ {
ngx_addr_t addr; ngx_addr_t addr;
ngx_array_t *xfwd; ngx_table_elt_t *xfwd;
in_addr_t addr4; in_addr_t addr4;
struct in6_addr addr6; struct in6_addr addr6;
struct sockaddr_in *sin; struct sockaddr_in *sin;
@ -302,9 +302,9 @@ ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
addr.socklen = r->connection->socklen; addr.socklen = r->connection->socklen;
/* addr.name = r->connection->addr_text; */ /* addr.name = r->connection->addr_text; */
xfwd = &r->headers_in.x_forwarded_for; xfwd = r->headers_in.x_forwarded_for;
if (xfwd->nelts > 0 && gcf->proxies != NULL) { if (xfwd != NULL && gcf->proxies != NULL) {
(void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL, (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL,
gcf->proxies, gcf->proxy_recursive); gcf->proxies, gcf->proxy_recursive);
} }

View File

@ -329,8 +329,7 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf)
time_t now, expires_time, max_age; time_t now, expires_time, max_age;
ngx_str_t value; ngx_str_t value;
ngx_int_t rc; ngx_int_t rc;
ngx_uint_t i; ngx_table_elt_t *e, *cc;
ngx_table_elt_t *e, *cc, **ccp;
ngx_http_expires_t expires; ngx_http_expires_t expires;
expires = conf->expires; expires = conf->expires;
@ -371,38 +370,28 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf)
len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT"); len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT");
e->value.len = len - 1; e->value.len = len - 1;
ccp = r->headers_out.cache_control.elts; cc = r->headers_out.cache_control;
if (ccp == NULL) { if (cc == NULL) {
if (ngx_array_init(&r->headers_out.cache_control, r->pool,
1, sizeof(ngx_table_elt_t *))
!= NGX_OK)
{
return NGX_ERROR;
}
cc = ngx_list_push(&r->headers_out.headers); cc = ngx_list_push(&r->headers_out.headers);
if (cc == NULL) { if (cc == NULL) {
return NGX_ERROR; return NGX_ERROR;
} }
r->headers_out.cache_control = cc;
cc->next = NULL;
cc->hash = 1; cc->hash = 1;
ngx_str_set(&cc->key, "Cache-Control"); ngx_str_set(&cc->key, "Cache-Control");
ccp = ngx_array_push(&r->headers_out.cache_control);
if (ccp == NULL) {
return NGX_ERROR;
}
*ccp = cc;
} else { } else {
for (i = 1; i < r->headers_out.cache_control.nelts; i++) { for (cc = cc->next; cc; cc = cc->next) {
ccp[i]->hash = 0; cc->hash = 0;
} }
cc = ccp[0]; cc = r->headers_out.cache_control;
cc->next = NULL;
} }
if (expires == NGX_HTTP_EXPIRES_EPOCH) { if (expires == NGX_HTTP_EXPIRES_EPOCH) {
@ -564,22 +553,12 @@ static ngx_int_t
ngx_http_add_multi_header_lines(ngx_http_request_t *r, ngx_http_add_multi_header_lines(ngx_http_request_t *r,
ngx_http_header_val_t *hv, ngx_str_t *value) ngx_http_header_val_t *hv, ngx_str_t *value)
{ {
ngx_array_t *pa;
ngx_table_elt_t *h, **ph; ngx_table_elt_t *h, **ph;
if (value->len == 0) { if (value->len == 0) {
return NGX_OK; return NGX_OK;
} }
pa = (ngx_array_t *) ((char *) &r->headers_out + hv->offset);
if (pa->elts == NULL) {
if (ngx_array_init(pa, r->pool, 1, sizeof(ngx_table_elt_t *)) != NGX_OK)
{
return NGX_ERROR;
}
}
h = ngx_list_push(&r->headers_out.headers); h = ngx_list_push(&r->headers_out.headers);
if (h == NULL) { if (h == NULL) {
return NGX_ERROR; return NGX_ERROR;
@ -589,12 +568,12 @@ ngx_http_add_multi_header_lines(ngx_http_request_t *r,
h->key = hv->key; h->key = hv->key;
h->value = *value; h->value = *value;
ph = ngx_array_push(pa); ph = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset);
if (ph == NULL) {
return NGX_ERROR; while (*ph) { ph = &(*ph)->next; }
}
*ph = h; *ph = h;
h->next = NULL;
return NGX_OK; return NGX_OK;
} }

View File

@ -2559,22 +2559,20 @@ static ngx_int_t
ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data) ngx_http_variable_value_t *v, uintptr_t data)
{ {
size_t len; size_t len;
u_char *p; u_char *p;
ngx_uint_t i, n; ngx_table_elt_t *h, *xfwd;
ngx_table_elt_t **h;
v->valid = 1; v->valid = 1;
v->no_cacheable = 0; v->no_cacheable = 0;
v->not_found = 0; v->not_found = 0;
n = r->headers_in.x_forwarded_for.nelts; xfwd = r->headers_in.x_forwarded_for;
h = r->headers_in.x_forwarded_for.elts;
len = 0; len = 0;
for (i = 0; i < n; i++) { for (h = xfwd; h; h = h->next) {
len += h[i]->value.len + sizeof(", ") - 1; len += h->value.len + sizeof(", ") - 1;
} }
if (len == 0) { if (len == 0) {
@ -2593,8 +2591,8 @@ ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
v->len = len; v->len = len;
v->data = p; v->data = p;
for (i = 0; i < n; i++) { for (h = xfwd; h; h = h->next) {
p = ngx_copy(p, h[i]->value.data, h[i]->value.len); p = ngx_copy(p, h->value.data, h->value.len);
*p++ = ','; *p++ = ' '; *p++ = ','; *p++ = ' ';
} }

View File

@ -134,9 +134,8 @@ ngx_http_realip_handler(ngx_http_request_t *r)
ngx_str_t *value; ngx_str_t *value;
ngx_uint_t i, hash; ngx_uint_t i, hash;
ngx_addr_t addr; ngx_addr_t addr;
ngx_array_t *xfwd;
ngx_list_part_t *part; ngx_list_part_t *part;
ngx_table_elt_t *header; ngx_table_elt_t *header, *xfwd;
ngx_connection_t *c; ngx_connection_t *c;
ngx_http_realip_ctx_t *ctx; ngx_http_realip_ctx_t *ctx;
ngx_http_realip_loc_conf_t *rlcf; ngx_http_realip_loc_conf_t *rlcf;
@ -168,9 +167,9 @@ ngx_http_realip_handler(ngx_http_request_t *r)
case NGX_HTTP_REALIP_XFWD: case NGX_HTTP_REALIP_XFWD:
xfwd = &r->headers_in.x_forwarded_for; xfwd = r->headers_in.x_forwarded_for;
if (xfwd->elts == NULL) { if (xfwd == NULL) {
return NGX_DECLINED; return NGX_DECLINED;
} }

View File

@ -319,10 +319,9 @@ ngx_http_userid_set_variable(ngx_http_request_t *r,
static ngx_http_userid_ctx_t * static ngx_http_userid_ctx_t *
ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf) ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf)
{ {
ngx_int_t n; ngx_str_t src, dst;
ngx_str_t src, dst; ngx_table_elt_t *cookie;
ngx_table_elt_t **cookies; ngx_http_userid_ctx_t *ctx;
ngx_http_userid_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module);
@ -339,9 +338,9 @@ ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf)
ngx_http_set_ctx(r, ctx, ngx_http_userid_filter_module); ngx_http_set_ctx(r, ctx, ngx_http_userid_filter_module);
} }
n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name, cookie = ngx_http_parse_multi_header_lines(r, r->headers_in.cookie,
&ctx->cookie); &conf->name, &ctx->cookie);
if (n == NGX_DECLINED) { if (cookie == NULL) {
return ctx; return ctx;
} }
@ -349,10 +348,9 @@ ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf)
"uid cookie: \"%V\"", &ctx->cookie); "uid cookie: \"%V\"", &ctx->cookie);
if (ctx->cookie.len < 22) { if (ctx->cookie.len < 22) {
cookies = r->headers_in.cookies.elts;
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"client sent too short userid cookie \"%V\"", "client sent too short userid cookie \"%V\"",
&cookies[n]->value); &cookie->value);
return ctx; return ctx;
} }
@ -370,10 +368,9 @@ ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf)
dst.data = (u_char *) ctx->uid_got; dst.data = (u_char *) ctx->uid_got;
if (ngx_decode_base64(&dst, &src) == NGX_ERROR) { if (ngx_decode_base64(&dst, &src) == NGX_ERROR) {
cookies = r->headers_in.cookies.elts;
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"client sent invalid userid cookie \"%V\"", "client sent invalid userid cookie \"%V\"",
&cookies[n]->value); &cookie->value);
return ctx; return ctx;
} }

View File

@ -302,7 +302,7 @@ header_in(r, key)
if (hh) { if (hh) {
if (hh->offset == offsetof(ngx_http_headers_in_t, cookies)) { if (hh->offset == offsetof(ngx_http_headers_in_t, cookie)) {
sep = ';'; sep = ';';
goto multi; goto multi;
} }
@ -327,17 +327,13 @@ header_in(r, key)
/* Cookie, X-Forwarded-For */ /* Cookie, X-Forwarded-For */
a = (ngx_array_t *) ((char *) &r->headers_in + hh->offset); ph = (ngx_table_elt_t **) ((char *) &r->headers_in + hh->offset);
n = a->nelts; if (*ph == NULL) {
if (n == 0) {
XSRETURN_UNDEF; XSRETURN_UNDEF;
} }
ph = a->elts; if ((*ph)->next == NULL) {
if (n == 1) {
ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len); ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len);
goto done; goto done;
@ -345,8 +341,8 @@ header_in(r, key)
size = - (ssize_t) (sizeof("; ") - 1); size = - (ssize_t) (sizeof("; ") - 1);
for (i = 0; i < n; i++) { for (h = *ph; h; h = h->next) {
size += ph[i]->value.len + sizeof("; ") - 1; size += h->value.len + sizeof("; ") - 1;
} }
value = ngx_pnalloc(r->pool, size); value = ngx_pnalloc(r->pool, size);
@ -357,10 +353,10 @@ header_in(r, key)
p = value; p = value;
for (i = 0; /* void */ ; i++) { for (h = *ph; h; h = h->next) {
p = ngx_copy(p, ph[i]->value.data, ph[i]->value.len); p = ngx_copy(p, h->value.data, h->value.len);
if (i == n - 1) { if (h->next == NULL) {
break; break;
} }

View File

@ -103,10 +103,10 @@ ngx_int_t ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
ngx_str_t *args, ngx_uint_t *flags); ngx_str_t *args, ngx_uint_t *flags);
ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
ngx_uint_t allow_underscores); ngx_uint_t allow_underscores);
ngx_int_t ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_table_elt_t *ngx_http_parse_multi_header_lines(ngx_http_request_t *r,
ngx_str_t *name, ngx_str_t *value); ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value);
ngx_int_t ngx_http_parse_set_cookie_lines(ngx_array_t *headers, ngx_table_elt_t *ngx_http_parse_set_cookie_lines(ngx_http_request_t *r,
ngx_str_t *name, ngx_str_t *value); ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value);
ngx_int_t ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_int_t ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len,
ngx_str_t *value); ngx_str_t *value);
void ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, void ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri,

View File

@ -2024,8 +2024,7 @@ ngx_http_gzip_ok(ngx_http_request_t *r)
{ {
time_t date, expires; time_t date, expires;
ngx_uint_t p; ngx_uint_t p;
ngx_array_t *cc; ngx_table_elt_t *e, *d, *ae, *cc;
ngx_table_elt_t *e, *d, *ae;
ngx_http_core_loc_conf_t *clcf; ngx_http_core_loc_conf_t *clcf;
r->gzip_tested = 1; r->gzip_tested = 1;
@ -2118,30 +2117,30 @@ ngx_http_gzip_ok(ngx_http_request_t *r)
return NGX_DECLINED; return NGX_DECLINED;
} }
cc = &r->headers_out.cache_control; cc = r->headers_out.cache_control;
if (cc->elts) { if (cc) {
if ((p & NGX_HTTP_GZIP_PROXIED_NO_CACHE) if ((p & NGX_HTTP_GZIP_PROXIED_NO_CACHE)
&& ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_cache, && ngx_http_parse_multi_header_lines(r, cc, &ngx_http_gzip_no_cache,
NULL) NULL)
>= 0) != NULL)
{ {
goto ok; goto ok;
} }
if ((p & NGX_HTTP_GZIP_PROXIED_NO_STORE) if ((p & NGX_HTTP_GZIP_PROXIED_NO_STORE)
&& ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_store, && ngx_http_parse_multi_header_lines(r, cc, &ngx_http_gzip_no_store,
NULL) NULL)
>= 0) != NULL)
{ {
goto ok; goto ok;
} }
if ((p & NGX_HTTP_GZIP_PROXIED_PRIVATE) if ((p & NGX_HTTP_GZIP_PROXIED_PRIVATE)
&& ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_private, && ngx_http_parse_multi_header_lines(r, cc, &ngx_http_gzip_private,
NULL) NULL)
>= 0) != NULL)
{ {
goto ok; goto ok;
} }
@ -2712,12 +2711,12 @@ ngx_http_set_disable_symlinks(ngx_http_request_t *r,
ngx_int_t ngx_int_t
ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr, ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr,
ngx_array_t *headers, ngx_str_t *value, ngx_array_t *proxies, ngx_table_elt_t *headers, ngx_str_t *value, ngx_array_t *proxies,
int recursive) int recursive)
{ {
ngx_int_t rc; ngx_int_t rc;
ngx_uint_t i, found; ngx_uint_t found;
ngx_table_elt_t **h; ngx_table_elt_t *h, *next;
if (headers == NULL) { if (headers == NULL) {
return ngx_http_get_forwarded_addr_internal(r, addr, value->data, return ngx_http_get_forwarded_addr_internal(r, addr, value->data,
@ -2725,16 +2724,23 @@ ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr,
recursive); recursive);
} }
i = headers->nelts; /* revert headers order */
h = headers->elts;
for (h = headers, headers = NULL; h; h = next) {
next = h->next;
h->next = headers;
headers = h;
}
/* iterate over all headers in reverse order */
rc = NGX_DECLINED; rc = NGX_DECLINED;
found = 0; found = 0;
while (i-- > 0) { for (h = headers; h; h = h->next) {
rc = ngx_http_get_forwarded_addr_internal(r, addr, h[i]->value.data, rc = ngx_http_get_forwarded_addr_internal(r, addr, h->value.data,
h[i]->value.len, proxies, h->value.len, proxies,
recursive); recursive);
if (!recursive) { if (!recursive) {
@ -2753,6 +2759,14 @@ ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr,
found = 1; found = 1;
} }
/* restore headers order */
for (h = headers, headers = NULL; h; h = next) {
next = h->next;
h->next = headers;
headers = h;
}
return rc; return rc;
} }

View File

@ -529,7 +529,7 @@ ngx_int_t ngx_http_set_disable_symlinks(ngx_http_request_t *r,
ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of); ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of);
ngx_int_t ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr, ngx_int_t ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr,
ngx_array_t *headers, ngx_str_t *value, ngx_array_t *proxies, ngx_table_elt_t *headers, ngx_str_t *value, ngx_array_t *proxies,
int recursive); int recursive);
ngx_int_t ngx_http_link_multi_headers(ngx_http_request_t *r); ngx_int_t ngx_http_link_multi_headers(ngx_http_request_t *r);

View File

@ -1960,27 +1960,24 @@ unsafe:
} }
ngx_int_t ngx_table_elt_t *
ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name, ngx_http_parse_multi_header_lines(ngx_http_request_t *r,
ngx_str_t *value) ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value)
{ {
ngx_uint_t i; u_char *start, *last, *end, ch;
u_char *start, *last, *end, ch; ngx_table_elt_t *h;
ngx_table_elt_t **h;
h = headers->elts; for (h = headers; h; h = h->next) {
for (i = 0; i < headers->nelts; i++) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"parse header: \"%V: %V\"", &h->key, &h->value);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0, if (name->len > h->value.len) {
"parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
if (name->len > h[i]->value.len) {
continue; continue;
} }
start = h[i]->value.data; start = h->value.data;
end = h[i]->value.data + h[i]->value.len; end = h->value.data + h->value.len;
while (start < end) { while (start < end) {
@ -1994,7 +1991,7 @@ ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
if (value == NULL) { if (value == NULL) {
if (start == end || *start == ',') { if (start == end || *start == ',') {
return i; return h;
} }
goto skip; goto skip;
@ -2014,7 +2011,7 @@ ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
value->len = last - start; value->len = last - start;
value->data = start; value->data = start;
return i; return h;
skip: skip:
@ -2029,31 +2026,28 @@ ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
} }
} }
return NGX_DECLINED; return NULL;
} }
ngx_int_t ngx_table_elt_t *
ngx_http_parse_set_cookie_lines(ngx_array_t *headers, ngx_str_t *name, ngx_http_parse_set_cookie_lines(ngx_http_request_t *r,
ngx_str_t *value) ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value)
{ {
ngx_uint_t i; u_char *start, *last, *end;
u_char *start, *last, *end; ngx_table_elt_t *h;
ngx_table_elt_t **h;
h = headers->elts; for (h = headers; h; h = h->next) {
for (i = 0; i < headers->nelts; i++) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"parse header: \"%V: %V\"", &h->key, &h->value);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0, if (name->len >= h->value.len) {
"parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
if (name->len >= h[i]->value.len) {
continue; continue;
} }
start = h[i]->value.data; start = h->value.data;
end = h[i]->value.data + h[i]->value.len; end = h->value.data + h->value.len;
if (ngx_strncasecmp(start, name->data, name->len) != 0) { if (ngx_strncasecmp(start, name->data, name->len) != 0) {
continue; continue;
@ -2077,10 +2071,10 @@ ngx_http_parse_set_cookie_lines(ngx_array_t *headers, ngx_str_t *name,
value->len = last - start; value->len = last - start;
value->data = start; value->data = start;
return i; return h;
} }
return NGX_DECLINED; return NULL;
} }

View File

@ -196,7 +196,7 @@ ngx_http_header_t ngx_http_headers_in[] = {
ngx_http_process_header_line }, ngx_http_process_header_line },
#endif #endif
{ ngx_string("Cookie"), offsetof(ngx_http_headers_in_t, cookies), { ngx_string("Cookie"), offsetof(ngx_http_headers_in_t, cookie),
ngx_http_process_multi_header_lines }, ngx_http_process_multi_header_lines },
{ ngx_null_string, 0, NULL } { ngx_null_string, 0, NULL }
@ -1744,6 +1744,7 @@ ngx_http_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
if (*ph == NULL) { if (*ph == NULL) {
*ph = h; *ph = h;
h->next = NULL;
} }
return NGX_OK; return NGX_OK;
@ -1760,6 +1761,7 @@ ngx_http_process_unique_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
if (*ph == NULL) { if (*ph == NULL) {
*ph = h; *ph = h;
h->next = NULL;
return NGX_OK; return NGX_OK;
} }
@ -1792,6 +1794,7 @@ ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h,
} }
r->headers_in.host = h; r->headers_in.host = h;
h->next = NULL;
host = h->value; host = h->value;
@ -1853,6 +1856,7 @@ ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h,
} }
r->headers_in.user_agent = h; r->headers_in.user_agent = h;
h->next = NULL;
/* check some widespread browsers while the header is in CPU cache */ /* check some widespread browsers while the header is in CPU cache */
@ -1919,27 +1923,15 @@ static ngx_int_t
ngx_http_process_multi_header_lines(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_http_process_multi_header_lines(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset) ngx_uint_t offset)
{ {
ngx_array_t *headers;
ngx_table_elt_t **ph; ngx_table_elt_t **ph;
headers = (ngx_array_t *) ((char *) &r->headers_in + offset); ph = (ngx_table_elt_t **) ((char *) &r->headers_in + offset);
if (headers->elts == NULL) { while (*ph) { ph = &(*ph)->next; }
if (ngx_array_init(headers, r->pool, 1, sizeof(ngx_table_elt_t *))
!= NGX_OK)
{
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_ERROR;
}
}
ph = ngx_array_push(headers);
if (ph == NULL) {
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_ERROR;
}
*ph = h; *ph = h;
h->next = NULL;
return NGX_OK; return NGX_OK;
} }

View File

@ -212,7 +212,7 @@ typedef struct {
ngx_table_elt_t *keep_alive; ngx_table_elt_t *keep_alive;
#if (NGX_HTTP_X_FORWARDED_FOR) #if (NGX_HTTP_X_FORWARDED_FOR)
ngx_array_t x_forwarded_for; ngx_table_elt_t *x_forwarded_for;
#endif #endif
#if (NGX_HTTP_REALIP) #if (NGX_HTTP_REALIP)
@ -231,11 +231,11 @@ typedef struct {
ngx_table_elt_t *date; ngx_table_elt_t *date;
#endif #endif
ngx_table_elt_t *cookie;
ngx_str_t user; ngx_str_t user;
ngx_str_t passwd; ngx_str_t passwd;
ngx_array_t cookies;
ngx_str_t server; ngx_str_t server;
off_t content_length_n; off_t content_length_n;
time_t keep_alive_n; time_t keep_alive_n;
@ -274,6 +274,9 @@ typedef struct {
ngx_table_elt_t *expires; ngx_table_elt_t *expires;
ngx_table_elt_t *etag; ngx_table_elt_t *etag;
ngx_table_elt_t *cache_control;
ngx_table_elt_t *link;
ngx_str_t *override_charset; ngx_str_t *override_charset;
size_t content_type_len; size_t content_type_len;
@ -282,9 +285,6 @@ typedef struct {
u_char *content_type_lowcase; u_char *content_type_lowcase;
ngx_uint_t content_type_hash; ngx_uint_t content_type_hash;
ngx_array_t cache_control;
ngx_array_t link;
off_t content_length_n; off_t content_length_n;
off_t content_offset; off_t content_offset;
time_t date_time; time_t date_time;

View File

@ -246,7 +246,7 @@ static ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
{ ngx_string("Set-Cookie"), { ngx_string("Set-Cookie"),
ngx_http_upstream_process_set_cookie, ngx_http_upstream_process_set_cookie,
offsetof(ngx_http_upstream_headers_in_t, cookies), offsetof(ngx_http_upstream_headers_in_t, set_cookie),
ngx_http_upstream_rewrite_set_cookie, 0, 1 }, ngx_http_upstream_rewrite_set_cookie, 0, 1 },
{ ngx_string("Content-Disposition"), { ngx_string("Content-Disposition"),
@ -4666,26 +4666,16 @@ static ngx_int_t
ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset) ngx_uint_t offset)
{ {
ngx_array_t *pa;
ngx_table_elt_t **ph; ngx_table_elt_t **ph;
ngx_http_upstream_t *u; ngx_http_upstream_t *u;
u = r->upstream; u = r->upstream;
pa = &u->headers_in.cookies; ph = &u->headers_in.set_cookie;
if (pa->elts == NULL) { while (*ph) { ph = &(*ph)->next; }
if (ngx_array_init(pa, r->pool, 1, sizeof(ngx_table_elt_t *)) != NGX_OK)
{
return NGX_ERROR;
}
}
ph = ngx_array_push(pa);
if (ph == NULL) {
return NGX_ERROR;
}
*ph = h; *ph = h;
h->next = NULL;
#if (NGX_HTTP_CACHE) #if (NGX_HTTP_CACHE)
if (!(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)) { if (!(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)) {
@ -4701,26 +4691,16 @@ static ngx_int_t
ngx_http_upstream_process_cache_control(ngx_http_request_t *r, ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset) ngx_table_elt_t *h, ngx_uint_t offset)
{ {
ngx_array_t *pa;
ngx_table_elt_t **ph; ngx_table_elt_t **ph;
ngx_http_upstream_t *u; ngx_http_upstream_t *u;
u = r->upstream; u = r->upstream;
pa = &u->headers_in.cache_control; ph = &u->headers_in.cache_control;
if (pa->elts == NULL) { while (*ph) { ph = &(*ph)->next; }
if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
{
return NGX_ERROR;
}
}
ph = ngx_array_push(pa);
if (ph == NULL) {
return NGX_ERROR;
}
*ph = h; *ph = h;
h->next = NULL;
#if (NGX_HTTP_CACHE) #if (NGX_HTTP_CACHE)
{ {
@ -5103,18 +5083,8 @@ static ngx_int_t
ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r, ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset) ngx_table_elt_t *h, ngx_uint_t offset)
{ {
ngx_array_t *pa;
ngx_table_elt_t *ho, **ph; ngx_table_elt_t *ho, **ph;
pa = (ngx_array_t *) ((char *) &r->headers_out + offset);
if (pa->elts == NULL) {
if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
{
return NGX_ERROR;
}
}
ho = ngx_list_push(&r->headers_out.headers); ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) { if (ho == NULL) {
return NGX_ERROR; return NGX_ERROR;
@ -5122,12 +5092,12 @@ ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
*ho = *h; *ho = *h;
ph = ngx_array_push(pa); ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
if (ph == NULL) {
return NGX_ERROR; while (*ph) { ph = &(*ph)->next; }
}
*ph = ho; *ph = ho;
ho->next = NULL;
return NGX_OK; return NGX_OK;
} }
@ -5740,9 +5710,9 @@ ngx_http_upstream_cookie_variable(ngx_http_request_t *r,
s.len = name->len - (sizeof("upstream_cookie_") - 1); s.len = name->len - (sizeof("upstream_cookie_") - 1);
s.data = name->data + sizeof("upstream_cookie_") - 1; s.data = name->data + sizeof("upstream_cookie_") - 1;
if (ngx_http_parse_set_cookie_lines(&r->upstream->headers_in.cookies, if (ngx_http_parse_set_cookie_lines(r, r->upstream->headers_in.set_cookie,
&s, &cookie) &s, &cookie)
== NGX_DECLINED) == NULL)
{ {
v->not_found = 1; v->not_found = 1;
return NGX_OK; return NGX_OK;

View File

@ -289,8 +289,8 @@ typedef struct {
ngx_table_elt_t *content_encoding; ngx_table_elt_t *content_encoding;
#endif #endif
ngx_array_t cache_control; ngx_table_elt_t *cache_control;
ngx_array_t cookies; ngx_table_elt_t *set_cookie;
off_t content_length_n; off_t content_length_n;
time_t last_modified_time; time_t last_modified_time;

View File

@ -183,7 +183,7 @@ static ngx_http_variable_t ngx_http_core_variables[] = {
#endif #endif
{ ngx_string("http_cookie"), NULL, ngx_http_variable_cookies, { ngx_string("http_cookie"), NULL, ngx_http_variable_cookies,
offsetof(ngx_http_request_t, headers_in.cookies), 0, 0 }, offsetof(ngx_http_request_t, headers_in.cookie), 0, 0 },
{ ngx_string("content_length"), NULL, ngx_http_variable_content_length, { ngx_string("content_length"), NULL, ngx_http_variable_content_length,
0, 0, 0 }, 0, 0, 0 },
@ -846,26 +846,21 @@ static ngx_int_t
ngx_http_variable_headers_internal(ngx_http_request_t *r, ngx_http_variable_headers_internal(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data, u_char sep) ngx_http_variable_value_t *v, uintptr_t data, u_char sep)
{ {
size_t len; size_t len;
u_char *p, *end; u_char *p;
ngx_uint_t i, n; ngx_table_elt_t *h, *th;
ngx_array_t *a;
ngx_table_elt_t **h;
a = (ngx_array_t *) ((char *) r + data); h = *(ngx_table_elt_t **) ((char *) r + data);
n = a->nelts;
h = a->elts;
len = 0; len = 0;
for (i = 0; i < n; i++) { for (th = h; th; th = th->next) {
if (h[i]->hash == 0) { if (th->hash == 0) {
continue; continue;
} }
len += h[i]->value.len + 2; len += th->value.len + 2;
} }
if (len == 0) { if (len == 0) {
@ -879,9 +874,9 @@ ngx_http_variable_headers_internal(ngx_http_request_t *r,
v->no_cacheable = 0; v->no_cacheable = 0;
v->not_found = 0; v->not_found = 0;
if (n == 1) { if (h->next == NULL) {
v->len = (*h)->value.len; v->len = h->value.len;
v->data = (*h)->value.data; v->data = h->value.data;
return NGX_OK; return NGX_OK;
} }
@ -894,17 +889,15 @@ ngx_http_variable_headers_internal(ngx_http_request_t *r,
v->len = len; v->len = len;
v->data = p; v->data = p;
end = p + len; for (th = h; th; th = th->next) {
for (i = 0; /* void */ ; i++) { if (th->hash == 0) {
if (h[i]->hash == 0) {
continue; continue;
} }
p = ngx_copy(p, h[i]->value.data, h[i]->value.len); p = ngx_copy(p, th->value.data, th->value.len);
if (p == end) { if (th->next == NULL) {
break; break;
} }
@ -1102,8 +1095,8 @@ ngx_http_variable_cookie(ngx_http_request_t *r, ngx_http_variable_value_t *v,
s.len = name->len - (sizeof("cookie_") - 1); s.len = name->len - (sizeof("cookie_") - 1);
s.data = name->data + sizeof("cookie_") - 1; s.data = name->data + sizeof("cookie_") - 1;
if (ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &s, &cookie) if (ngx_http_parse_multi_header_lines(r, r->headers_in.cookie, &s, &cookie)
== NGX_DECLINED) == NULL)
{ {
v->not_found = 1; v->not_found = 1;
return NGX_OK; return NGX_OK;

View File

@ -674,14 +674,14 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
static ngx_int_t static ngx_int_t
ngx_http_v2_push_resources(ngx_http_request_t *r) ngx_http_v2_push_resources(ngx_http_request_t *r)
{ {
u_char *start, *end, *last; u_char *start, *end, *last;
ngx_int_t rc; ngx_int_t rc;
ngx_str_t path; ngx_str_t path;
ngx_uint_t i, push; ngx_uint_t i, push;
ngx_table_elt_t **h; ngx_table_elt_t *h;
ngx_http_v2_loc_conf_t *h2lcf; ngx_http_v2_loc_conf_t *h2lcf;
ngx_http_complex_value_t *pushes; ngx_http_complex_value_t *pushes;
ngx_str_t binary[NGX_HTTP_V2_PUSH_HEADERS]; ngx_str_t binary[NGX_HTTP_V2_PUSH_HEADERS];
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http2 push resources"); "http2 push resources");
@ -725,15 +725,13 @@ ngx_http_v2_push_resources(ngx_http_request_t *r)
return NGX_OK; return NGX_OK;
} }
h = r->headers_out.link.elts; for (h = r->headers_out.link; h; h = h->next) {
for (i = 0; i < r->headers_out.link.nelts; i++) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http2 parse link: \"%V\"", &h[i]->value); "http2 parse link: \"%V\"", &h->value);
start = h[i]->value.data; start = h->value.data;
end = h[i]->value.data + h[i]->value.len; end = h->value.data + h->value.len;
next_link: next_link: