Merged with the default branch.

This commit is contained in:
Sergey Kandaurov 2022-06-22 18:34:58 +04:00
commit f2bc2e05d0
45 changed files with 1280 additions and 1277 deletions

2
README
View File

@ -15,7 +15,7 @@ Experimental QUIC support for nginx
The code is developed in a separate "quic" branch available
at https://hg.nginx.org/nginx-quic. Currently it is based
on nginx mainline 1.21.x. We merge new nginx releases into
on nginx mainline 1.23.x. We merge new nginx releases into
this branch regularly.
The project code base is under the same BSD license as nginx.

View File

@ -110,7 +110,7 @@ case "$NGX_MACHINE" in
NGX_MACH_CACHE_LINE=64
;;
aarch64 )
aarch64 | arm64)
have=NGX_ALIGNMENT value=16 . auto/define
NGX_MACH_CACHE_LINE=64
;;

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,107 @@
<change_log title="nginx">
<changes ver="1.23.0" date="2022-06-21">
<change>
<para lang="ru">
Изменение во внутреннем API:
теперь строки заголовков представлены связными списками.
</para>
<para lang="en">
Change in internal API:
now header lines are represented as linked lists.
</para>
</change>
<change type="change">
<para lang="ru">
теперь nginx объединяет произвольные строки заголовков с одинаковыми именами
при отправке на FastCGI-, SCGI- и uwsgi-бэкенды,
в методе $r->header_in() модуля ngx_http_perl_module,
и при доступе через переменные "$http_...", "$sent_http_...",
"$sent_trailer_...", "$upstream_http_..." и "$upstream_trailer_...".
</para>
<para lang="en">
now nginx combines arbitrary header lines with identical names
when sending to FastCGI, SCGI, and uwsgi backends,
in the $r->header_in() method of the ngx_http_perl_module,
and during lookup of the "$http_...", "$sent_http_...",
"$sent_trailer_...", "$upstream_http_...", and "$upstream_trailer_..."
variables.
</para>
</change>
<change type="bugfix">
<para lang="ru">
если в заголовке ответа бэкенда было несколько строк "Vary",
при кэшировании nginx учитывал только последнюю из них.
</para>
<para lang="en">
if there were multiple "Vary" header lines in the backend response,
nginx only used the last of them when caching.
</para>
</change>
<change type="bugfix">
<para lang="ru">
если в заголовке ответа бэкенда было несколько строк "WWW-Authenticate"
и использовался перехват ошибок с кодом 401 от бэкенда
или директива auth_request,
nginx пересылал клиенту только первую из этих строк.
</para>
<para lang="en">
if there were multiple "WWW-Authenticate" header lines in the backend response
and errors with code 401 were intercepted
or the "auth_request" directive was used,
nginx only sent the first of the header lines to the client.
</para>
</change>
<change type="change">
<para lang="ru">
уровень логгирования ошибок SSL "application data after close notify"
понижен с уровня crit до info.
</para>
<para lang="en">
the logging level of the "application data after close notify" SSL errors
has been lowered from "crit" to "info".
</para>
</change>
<change type="bugfix">
<para lang="ru">
соединения могли зависать, если nginx был собран на Linux 2.6.17 и новее,
а использовался на системах без поддержки EPOLLRDHUP, в частности, на
системах с эмуляцией epoll;
ошибка появилась в 1.17.5.<br/>
Спасибо Marcus Ball.
</para>
<para lang="en">
connections might hang if nginx was built on Linux 2.6.17 or newer,
but was used on systems without EPOLLRDHUP support, notably with epoll
emulation layers;
the bug had appeared in 1.17.5.<br/>
Thanks to Marcus Ball.
</para>
</change>
<change type="bugfix">
<para lang="ru">
nginx не кэшировал ответ,
если строка заголовка ответа "Expires" запрещала кэширование,
а последующая строка заголовка "Cache-Control" разрешала кэширование.
</para>
<para lang="en">
nginx did not cache the response
if the "Expires" response header line disabled caching,
but following "Cache-Control" header line enabled caching.
</para>
</change>
</changes>
<changes ver="1.21.6" date="2022-01-25">
<change type="bugfix">

View File

@ -6,8 +6,8 @@ TEMP = tmp
CC = cl
OBJS = objs.msvc8
OPENSSL = openssl-1.1.1m
ZLIB = zlib-1.2.11
OPENSSL = openssl-1.1.1p
ZLIB = zlib-1.2.12
PCRE = pcre2-10.39
@ -15,12 +15,6 @@ release: export
mv $(TEMP)/$(NGINX)/auto/configure $(TEMP)/$(NGINX)
# delete incomplete sources
rm $(TEMP)/$(NGINX)/src/event/ngx_event_acceptex.c
rm $(TEMP)/$(NGINX)/src/event/ngx_event_connectex.c
rm $(TEMP)/$(NGINX)/src/event/modules/ngx_iocp_module.*
rm -r $(TEMP)/$(NGINX)/src/os/win32
mv $(TEMP)/$(NGINX)/docs/text/LICENSE $(TEMP)/$(NGINX)
mv $(TEMP)/$(NGINX)/docs/text/README $(TEMP)/$(NGINX)
mv $(TEMP)/$(NGINX)/docs/html $(TEMP)/$(NGINX)

View File

@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
#define nginx_version 1021007
#define NGINX_VERSION "1.21.7"
#define nginx_version 1023000
#define NGINX_VERSION "1.23.0"
#define NGINX_VER "nginx/" NGINX_VERSION
#ifdef NGX_BUILD

View File

@ -89,12 +89,15 @@ typedef struct {
} ngx_hash_keys_arrays_t;
typedef struct {
typedef struct ngx_table_elt_s ngx_table_elt_t;
struct ngx_table_elt_s {
ngx_uint_t hash;
ngx_str_t key;
ngx_str_t value;
u_char *lowcase_key;
} ngx_table_elt_t;
ngx_table_elt_t *next;
};
void *ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len);

View File

@ -1389,6 +1389,7 @@ ngx_resolver_send_tcp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec,
rec->tcp->data = rec;
rec->tcp->write->handler = ngx_resolver_tcp_write;
rec->tcp->write->cancelable = 1;
rec->tcp->read->handler = ngx_resolver_tcp_read;
rec->tcp->read->resolver = 1;

View File

@ -339,6 +339,7 @@ ngx_http_auth_basic_set_realm(ngx_http_request_t *r, ngx_str_t *realm)
*p = '"';
r->headers_out.www_authenticate->hash = 1;
r->headers_out.www_authenticate->next = NULL;
ngx_str_set(&r->headers_out.www_authenticate->key, "WWW-Authenticate");
r->headers_out.www_authenticate->value.data = basic;
r->headers_out.www_authenticate->value.len = len;

View File

@ -101,7 +101,7 @@ ngx_module_t ngx_http_auth_request_module = {
static ngx_int_t
ngx_http_auth_request_handler(ngx_http_request_t *r)
{
ngx_table_elt_t *h, *ho;
ngx_table_elt_t *h, *ho, **ph;
ngx_http_request_t *sr;
ngx_http_post_subrequest_t *ps;
ngx_http_auth_request_ctx_t *ctx;
@ -147,15 +147,21 @@ ngx_http_auth_request_handler(ngx_http_request_t *r)
h = sr->upstream->headers_in.www_authenticate;
}
if (h) {
ph = &r->headers_out.www_authenticate;
while (h) {
ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) {
return NGX_ERROR;
}
*ho = *h;
ho->next = NULL;
r->headers_out.www_authenticate = ho;
*ph = ho;
ph = &ho->next;
h = h->next;
}
return ctx->status;

View File

@ -1082,6 +1082,7 @@ ngx_http_dav_location(ngx_http_request_t *r)
}
r->headers_out.location->hash = 1;
r->headers_out.location->next = NULL;
ngx_str_set(&r->headers_out.location->key, "Location");
escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_URI);

View File

@ -835,14 +835,14 @@ static ngx_int_t
ngx_http_fastcgi_create_request(ngx_http_request_t *r)
{
off_t file_pos;
u_char ch, *pos, *lowcase_key;
u_char ch, sep, *pos, *lowcase_key;
size_t size, len, key_len, val_len, padding,
allocated;
ngx_uint_t i, n, next, hash, skip_empty, header_params;
ngx_buf_t *b;
ngx_chain_t *cl, *body;
ngx_list_part_t *part;
ngx_table_elt_t *header, **ignored;
ngx_table_elt_t *header, *hn, **ignored;
ngx_http_upstream_t *u;
ngx_http_script_code_pt code;
ngx_http_script_engine_t e, le;
@ -900,7 +900,11 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
allocated = 0;
lowcase_key = NULL;
if (params->number) {
if (ngx_http_link_multi_headers(r) != NGX_OK) {
return NGX_ERROR;
}
if (params->number || r->headers_in.multi) {
n = 0;
part = &r->headers_in.headers.part;
@ -930,6 +934,12 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
i = 0;
}
for (n = 0; n < header_params; n++) {
if (&header[i] == ignored[n]) {
goto next_length;
}
}
if (params->number) {
if (allocated < header[i].key.len) {
allocated = header[i].key.len + 16;
@ -959,15 +969,23 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
ignored[header_params++] = &header[i];
continue;
}
n += sizeof("HTTP_") - 1;
} else {
n = sizeof("HTTP_") - 1 + header[i].key.len;
}
len += ((n > 127) ? 4 : 1) + ((header[i].value.len > 127) ? 4 : 1)
+ n + header[i].value.len;
key_len = sizeof("HTTP_") - 1 + header[i].key.len;
val_len = header[i].value.len;
for (hn = header[i].next; hn; hn = hn->next) {
val_len += hn->value.len + 2;
ignored[header_params++] = hn;
}
len += ((key_len > 127) ? 4 : 1) + key_len
+ ((val_len > 127) ? 4 : 1) + val_len;
next_length:
continue;
}
}
@ -1109,7 +1127,7 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
for (n = 0; n < header_params; n++) {
if (&header[i] == ignored[n]) {
goto next;
goto next_value;
}
}
@ -1125,6 +1143,11 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
}
val_len = header[i].value.len;
for (hn = header[i].next; hn; hn = hn->next) {
val_len += hn->value.len + 2;
}
if (val_len > 127) {
*b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
*b->last++ = (u_char) ((val_len >> 16) & 0xff);
@ -1150,13 +1173,34 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
*b->last++ = ch;
}
b->last = ngx_copy(b->last, header[i].value.data, val_len);
b->last = ngx_copy(b->last, header[i].value.data,
header[i].value.len);
if (header[i].next) {
if (header[i].key.len == sizeof("Cookie") - 1
&& ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie",
sizeof("Cookie") - 1)
== 0)
{
sep = ';';
} else {
sep = ',';
}
for (hn = header[i].next; hn; hn = hn->next) {
*b->last++ = sep;
*b->last++ = ' ';
b->last = ngx_copy(b->last, hn->value.data, hn->value.len);
}
}
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"fastcgi param: \"%*s: %*s\"",
key_len, b->last - (key_len + val_len),
val_len, b->last - val_len);
next:
next_value:
continue;
}
@ -1963,8 +2007,12 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r)
hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
h->lowcase_key, h->key.len);
if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
return NGX_ERROR;
if (hh) {
rc = hh->handler(r, h, hh->offset);
if (rc != NGX_OK) {
return rc;
}
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,

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_addr_t *addr)
{
ngx_array_t *xfwd;
ngx_table_elt_t *xfwd;
if (ngx_http_geo_real_addr(r, ctx, addr) != NGX_OK) {
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,
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_addr_t addr;
ngx_array_t *xfwd;
ngx_table_elt_t *xfwd;
struct sockaddr_in *sin;
addr.sockaddr = r->connection->sockaddr;
addr.socklen = r->connection->socklen;
/* 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,
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_addr_t addr;
ngx_array_t *xfwd;
ngx_table_elt_t *xfwd;
in_addr_t addr4;
struct in6_addr addr6;
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.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,
gcf->proxies, gcf->proxy_recursive);
}

View File

@ -1891,8 +1891,12 @@ ngx_http_grpc_process_header(ngx_http_request_t *r)
hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
h->lowcase_key, h->key.len);
if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
return NGX_ERROR;
if (hh) {
rc = hh->handler(r, h, hh->offset);
if (rc != NGX_OK) {
return rc;
}
}
continue;
@ -4902,8 +4906,9 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf)
return NGX_ERROR;
}
if (glcf->upstream.ssl_certificate) {
if (glcf->upstream.ssl_certificate
&& glcf->upstream.ssl_certificate->value.len)
{
if (glcf->upstream.ssl_certificate_key == NULL) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no \"grpc_ssl_certificate_key\" is defined "

View File

@ -280,6 +280,7 @@ ngx_http_gzip_header_filter(ngx_http_request_t *r)
}
h->hash = 1;
h->next = NULL;
ngx_str_set(&h->key, "Content-Encoding");
ngx_str_set(&h->value, "gzip");
r->headers_out.content_encoding = h;

View File

@ -242,6 +242,7 @@ ngx_http_gzip_static_handler(ngx_http_request_t *r)
}
h->hash = 1;
h->next = NULL;
ngx_str_set(&h->key, "Content-Encoding");
ngx_str_set(&h->value, "gzip");
r->headers_out.content_encoding = h;

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;
ngx_str_t value;
ngx_int_t rc;
ngx_uint_t i;
ngx_table_elt_t *e, *cc, **ccp;
ngx_table_elt_t *e, *cc;
ngx_http_expires_t expires;
expires = conf->expires;
@ -363,6 +362,7 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf)
}
r->headers_out.expires = e;
e->next = NULL;
e->hash = 1;
ngx_str_set(&e->key, "Expires");
@ -371,38 +371,29 @@ 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");
e->value.len = len - 1;
ccp = r->headers_out.cache_control.elts;
cc = r->headers_out.cache_control;
if (ccp == NULL) {
if (ngx_array_init(&r->headers_out.cache_control, r->pool,
1, sizeof(ngx_table_elt_t *))
!= NGX_OK)
{
return NGX_ERROR;
}
if (cc == NULL) {
cc = ngx_list_push(&r->headers_out.headers);
if (cc == NULL) {
e->hash = 0;
return NGX_ERROR;
}
r->headers_out.cache_control = cc;
cc->next = NULL;
cc->hash = 1;
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 {
for (i = 1; i < r->headers_out.cache_control.nelts; i++) {
ccp[i]->hash = 0;
for (cc = cc->next; cc; cc = cc->next) {
cc->hash = 0;
}
cc = ccp[0];
cc = r->headers_out.cache_control;
cc->next = NULL;
}
if (expires == NGX_HTTP_EXPIRES_EPOCH) {
@ -420,6 +411,8 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf)
e->value.data = ngx_pnalloc(r->pool, len);
if (e->value.data == NULL) {
e->hash = 0;
cc->hash = 0;
return NGX_ERROR;
}
@ -457,6 +450,7 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf)
cc->value.data = ngx_pnalloc(r->pool,
sizeof("max-age=") + NGX_TIME_T_LEN + 1);
if (cc->value.data == NULL) {
cc->hash = 0;
return NGX_ERROR;
}
@ -564,22 +558,12 @@ static ngx_int_t
ngx_http_add_multi_header_lines(ngx_http_request_t *r,
ngx_http_header_val_t *hv, ngx_str_t *value)
{
ngx_array_t *pa;
ngx_table_elt_t *h, **ph;
if (value->len == 0) {
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);
if (h == NULL) {
return NGX_ERROR;
@ -589,12 +573,12 @@ ngx_http_add_multi_header_lines(ngx_http_request_t *r,
h->key = hv->key;
h->value = *value;
ph = ngx_array_push(pa);
if (ph == NULL) {
return NGX_ERROR;
}
ph = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset);
while (*ph) { ph = &(*ph)->next; }
*ph = h;
h->next = NULL;
return NGX_OK;
}
@ -642,6 +626,7 @@ ngx_http_set_response_header(ngx_http_request_t *r, ngx_http_header_val_t *hv,
}
*old = h;
h->next = NULL;
}
h->hash = 1;

View File

@ -401,6 +401,7 @@ found:
}
h->hash = 1;
h->next = NULL;
ngx_str_set(&h->key, "Content-Encoding");
ngx_str_set(&h->value, "gzip");
r->headers_out.content_encoding = h;

View File

@ -2331,7 +2331,7 @@ ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4,
}
start_sample += count;
start_time -= count * duration;
start_time -= (uint64_t) count * duration;
entries--;
entry++;
}

View File

@ -1930,8 +1930,12 @@ ngx_http_proxy_process_header(ngx_http_request_t *r)
hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
h->lowcase_key, h->key.len);
if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
return NGX_ERROR;
if (hh) {
rc = hh->handler(r, h, hh->offset);
if (rc != NGX_OK) {
return rc;
}
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@ -1965,6 +1969,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r)
ngx_str_set(&h->key, "Server");
ngx_str_null(&h->value);
h->lowcase_key = (u_char *) "server";
h->next = NULL;
}
if (r->upstream->headers_in.date == NULL) {
@ -1978,6 +1983,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r)
ngx_str_set(&h->key, "Date");
ngx_str_null(&h->value);
h->lowcase_key = (u_char *) "date";
h->next = NULL;
}
/* clear content length if response is chunked */
@ -2559,22 +2565,20 @@ static ngx_int_t
ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
size_t len;
u_char *p;
ngx_uint_t i, n;
ngx_table_elt_t **h;
size_t len;
u_char *p;
ngx_table_elt_t *h, *xfwd;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
n = r->headers_in.x_forwarded_for.nelts;
h = r->headers_in.x_forwarded_for.elts;
xfwd = r->headers_in.x_forwarded_for;
len = 0;
for (i = 0; i < n; i++) {
len += h[i]->value.len + sizeof(", ") - 1;
for (h = xfwd; h; h = h->next) {
len += h->value.len + sizeof(", ") - 1;
}
if (len == 0) {
@ -2593,8 +2597,8 @@ ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
v->len = len;
v->data = p;
for (i = 0; i < n; i++) {
p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
for (h = xfwd; h; h = h->next) {
p = ngx_copy(p, h->value.data, h->value.len);
*p++ = ','; *p++ = ' ';
}
@ -4951,8 +4955,9 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
return NGX_ERROR;
}
if (plcf->upstream.ssl_certificate) {
if (plcf->upstream.ssl_certificate
&& plcf->upstream.ssl_certificate->value.len)
{
if (plcf->upstream.ssl_certificate_key == NULL) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no \"proxy_ssl_certificate_key\" is defined "

View File

@ -258,6 +258,7 @@ next_filter:
}
r->headers_out.accept_ranges->hash = 1;
r->headers_out.accept_ranges->next = NULL;
ngx_str_set(&r->headers_out.accept_ranges->key, "Accept-Ranges");
ngx_str_set(&r->headers_out.accept_ranges->value, "bytes");
@ -427,6 +428,7 @@ ngx_http_range_singlepart_header(ngx_http_request_t *r,
r->headers_out.content_range = content_range;
content_range->hash = 1;
content_range->next = NULL;
ngx_str_set(&content_range->key, "Content-Range");
content_range->value.data = ngx_pnalloc(r->pool,
@ -599,6 +601,7 @@ ngx_http_range_not_satisfiable(ngx_http_request_t *r)
r->headers_out.content_range = content_range;
content_range->hash = 1;
content_range->next = NULL;
ngx_str_set(&content_range->key, "Content-Range");
content_range->value.data = ngx_pnalloc(r->pool,

View File

@ -134,9 +134,8 @@ ngx_http_realip_handler(ngx_http_request_t *r)
ngx_str_t *value;
ngx_uint_t i, hash;
ngx_addr_t addr;
ngx_array_t *xfwd;
ngx_list_part_t *part;
ngx_table_elt_t *header;
ngx_table_elt_t *header, *xfwd;
ngx_connection_t *c;
ngx_http_realip_ctx_t *ctx;
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:
xfwd = &r->headers_in.x_forwarded_for;
xfwd = r->headers_in.x_forwarded_for;
if (xfwd->elts == NULL) {
if (xfwd == NULL) {
return NGX_DECLINED;
}

View File

@ -633,14 +633,14 @@ static ngx_int_t
ngx_http_scgi_create_request(ngx_http_request_t *r)
{
off_t content_length_n;
u_char ch, *key, *val, *lowcase_key;
u_char ch, sep, *key, *val, *lowcase_key;
size_t len, key_len, val_len, allocated;
ngx_buf_t *b;
ngx_str_t content_length;
ngx_uint_t i, n, hash, skip_empty, header_params;
ngx_chain_t *cl, *body;
ngx_list_part_t *part;
ngx_table_elt_t *header, **ignored;
ngx_table_elt_t *header, *hn, **ignored;
ngx_http_scgi_params_t *params;
ngx_http_script_code_pt code;
ngx_http_script_engine_t e, le;
@ -707,7 +707,11 @@ ngx_http_scgi_create_request(ngx_http_request_t *r)
allocated = 0;
lowcase_key = NULL;
if (params->number) {
if (ngx_http_link_multi_headers(r) != NGX_OK) {
return NGX_ERROR;
}
if (params->number || r->headers_in.multi) {
n = 0;
part = &r->headers_in.headers.part;
@ -737,6 +741,12 @@ ngx_http_scgi_create_request(ngx_http_request_t *r)
i = 0;
}
for (n = 0; n < header_params; n++) {
if (&header[i] == ignored[n]) {
goto next_length;
}
}
if (params->number) {
if (allocated < header[i].key.len) {
allocated = header[i].key.len + 16;
@ -770,6 +780,15 @@ ngx_http_scgi_create_request(ngx_http_request_t *r)
len += sizeof("HTTP_") - 1 + header[i].key.len + 1
+ header[i].value.len + 1;
for (hn = header[i].next; hn; hn = hn->next) {
len += hn->value.len + 2;
ignored[header_params++] = hn;
}
next_length:
continue;
}
}
@ -869,7 +888,7 @@ ngx_http_scgi_create_request(ngx_http_request_t *r)
for (n = 0; n < header_params; n++) {
if (&header[i] == ignored[n]) {
goto next;
goto next_value;
}
}
@ -893,12 +912,33 @@ ngx_http_scgi_create_request(ngx_http_request_t *r)
val = b->last;
b->last = ngx_copy(val, header[i].value.data, header[i].value.len);
if (header[i].next) {
if (header[i].key.len == sizeof("Cookie") - 1
&& ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie",
sizeof("Cookie") - 1)
== 0)
{
sep = ';';
} else {
sep = ',';
}
for (hn = header[i].next; hn; hn = hn->next) {
*b->last++ = sep;
*b->last++ = ' ';
b->last = ngx_copy(b->last, hn->value.data, hn->value.len);
}
}
*b->last++ = (u_char) 0;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"scgi param: \"%s: %s\"", key, val);
next:
next_value:
continue;
}
@ -1074,8 +1114,12 @@ ngx_http_scgi_process_header(ngx_http_request_t *r)
hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
h->lowcase_key, h->key.len);
if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
return NGX_ERROR;
if (hh) {
rc = hh->handler(r, h, hh->offset);
if (rc != NGX_OK) {
return rc;
}
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,

View File

@ -195,6 +195,7 @@ ngx_http_static_handler(ngx_http_request_t *r)
}
r->headers_out.location->hash = 1;
r->headers_out.location->next = NULL;
ngx_str_set(&r->headers_out.location->key, "Location");
r->headers_out.location->value.len = len;
r->headers_out.location->value.data = location;

View File

@ -319,10 +319,9 @@ ngx_http_userid_set_variable(ngx_http_request_t *r,
static ngx_http_userid_ctx_t *
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_table_elt_t **cookies;
ngx_http_userid_ctx_t *ctx;
ngx_str_t src, dst;
ngx_table_elt_t *cookie;
ngx_http_userid_ctx_t *ctx;
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);
}
n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name,
&ctx->cookie);
if (n == NGX_DECLINED) {
cookie = ngx_http_parse_multi_header_lines(r, r->headers_in.cookie,
&conf->name, &ctx->cookie);
if (cookie == NULL) {
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);
if (ctx->cookie.len < 22) {
cookies = r->headers_in.cookies.elts;
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"client sent too short userid cookie \"%V\"",
&cookies[n]->value);
&cookie->value);
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;
if (ngx_decode_base64(&dst, &src) == NGX_ERROR) {
cookies = r->headers_in.cookies.elts;
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"client sent invalid userid cookie \"%V\"",
&cookies[n]->value);
&cookie->value);
return ctx;
}

View File

@ -845,13 +845,13 @@ ngx_http_uwsgi_create_key(ngx_http_request_t *r)
static ngx_int_t
ngx_http_uwsgi_create_request(ngx_http_request_t *r)
{
u_char ch, *lowcase_key;
u_char ch, sep, *lowcase_key;
size_t key_len, val_len, len, allocated;
ngx_uint_t i, n, hash, skip_empty, header_params;
ngx_buf_t *b;
ngx_chain_t *cl, *body;
ngx_list_part_t *part;
ngx_table_elt_t *header, **ignored;
ngx_table_elt_t *header, *hn, **ignored;
ngx_http_uwsgi_params_t *params;
ngx_http_script_code_pt code;
ngx_http_script_engine_t e, le;
@ -905,7 +905,11 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r)
allocated = 0;
lowcase_key = NULL;
if (params->number) {
if (ngx_http_link_multi_headers(r) != NGX_OK) {
return NGX_ERROR;
}
if (params->number || r->headers_in.multi) {
n = 0;
part = &r->headers_in.headers.part;
@ -935,6 +939,12 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r)
i = 0;
}
for (n = 0; n < header_params; n++) {
if (&header[i] == ignored[n]) {
goto next_length;
}
}
if (params->number) {
if (allocated < header[i].key.len) {
allocated = header[i].key.len + 16;
@ -968,6 +978,15 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r)
len += 2 + sizeof("HTTP_") - 1 + header[i].key.len
+ 2 + header[i].value.len;
for (hn = header[i].next; hn; hn = hn->next) {
len += hn->value.len + 2;
ignored[header_params++] = hn;
}
next_length:
continue;
}
}
@ -1086,7 +1105,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r)
for (n = 0; n < header_params; n++) {
if (&header[i] == ignored[n]) {
goto next;
goto next_value;
}
}
@ -1109,15 +1128,41 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r)
}
val_len = header[i].value.len;
for (hn = header[i].next; hn; hn = hn->next) {
val_len += hn->value.len + 2;
}
*b->last++ = (u_char) (val_len & 0xff);
*b->last++ = (u_char) ((val_len >> 8) & 0xff);
b->last = ngx_copy(b->last, header[i].value.data, val_len);
b->last = ngx_copy(b->last, header[i].value.data,
header[i].value.len);
if (header[i].next) {
if (header[i].key.len == sizeof("Cookie") - 1
&& ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie",
sizeof("Cookie") - 1)
== 0)
{
sep = ';';
} else {
sep = ',';
}
for (hn = header[i].next; hn; hn = hn->next) {
*b->last++ = sep;
*b->last++ = ' ';
b->last = ngx_copy(b->last, hn->value.data, hn->value.len);
}
}
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"uwsgi param: \"%*s: %*s\"",
key_len, b->last - (key_len + 2 + val_len),
val_len, b->last - val_len);
next:
next_value:
continue;
}
@ -1295,8 +1340,12 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r)
hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
h->lowcase_key, h->key.len);
if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
return NGX_ERROR;
if (hh) {
rc = hh->handler(r, h, hh->offset);
if (rc != NGX_OK) {
return rc;
}
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@ -2438,8 +2487,9 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf)
return NGX_ERROR;
}
if (uwcf->upstream.ssl_certificate) {
if (uwcf->upstream.ssl_certificate
&& uwcf->upstream.ssl_certificate->value.len)
{
if (uwcf->upstream.ssl_certificate_key == NULL) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no \"uwsgi_ssl_certificate_key\" is defined "

View File

@ -269,10 +269,9 @@ header_in(r, key)
u_char *p, *lowcase_key, *value, sep;
STRLEN len;
ssize_t size;
ngx_uint_t i, n, hash;
ngx_array_t *a;
ngx_uint_t i, hash;
ngx_list_part_t *part;
ngx_table_elt_t *h, **ph;
ngx_table_elt_t *h, *header, **ph;
ngx_http_header_t *hh;
ngx_http_core_main_conf_t *cmcf;
@ -302,78 +301,23 @@ header_in(r, key)
if (hh) {
if (hh->offset == offsetof(ngx_http_headers_in_t, cookies)) {
if (hh->offset == offsetof(ngx_http_headers_in_t, cookie)) {
sep = ';';
goto multi;
}
#if (NGX_HTTP_X_FORWARDED_FOR)
if (hh->offset == offsetof(ngx_http_headers_in_t, x_forwarded_for)) {
} else {
sep = ',';
goto multi;
}
#endif
ph = (ngx_table_elt_t **) ((char *) &r->headers_in + hh->offset);
if (*ph) {
ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len);
goto done;
}
XSRETURN_UNDEF;
multi:
/* Cookie, X-Forwarded-For */
a = (ngx_array_t *) ((char *) &r->headers_in + hh->offset);
n = a->nelts;
if (n == 0) {
XSRETURN_UNDEF;
}
ph = a->elts;
if (n == 1) {
ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len);
goto done;
}
size = - (ssize_t) (sizeof("; ") - 1);
for (i = 0; i < n; i++) {
size += ph[i]->value.len + sizeof("; ") - 1;
}
value = ngx_pnalloc(r->pool, size);
if (value == NULL) {
ctx->error = 1;
croak("ngx_pnalloc() failed");
}
p = value;
for (i = 0; /* void */ ; i++) {
p = ngx_copy(p, ph[i]->value.data, ph[i]->value.len);
if (i == n - 1) {
break;
}
*p++ = sep; *p++ = ' ';
}
ngx_http_perl_set_targ(value, size);
goto done;
goto found;
}
/* iterate over all headers */
sep = ',';
ph = &header;
part = &r->headers_in.headers.part;
h = part->elts;
@ -395,12 +339,49 @@ header_in(r, key)
continue;
}
ngx_http_perl_set_targ(h[i].value.data, h[i].value.len);
*ph = &h[i];
ph = &h[i].next;
}
*ph = NULL;
ph = &header;
found:
if (*ph == NULL) {
XSRETURN_UNDEF;
}
if ((*ph)->next == NULL) {
ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len);
goto done;
}
XSRETURN_UNDEF;
size = - (ssize_t) (sizeof("; ") - 1);
for (h = *ph; h; h = h->next) {
size += h->value.len + sizeof("; ") - 1;
}
value = ngx_pnalloc(r->pool, size);
if (value == NULL) {
ctx->error = 1;
croak("ngx_pnalloc() failed");
}
p = value;
for (h = *ph; h; h = h->next) {
p = ngx_copy(p, h->value.data, h->value.len);
if (h->next == NULL) {
break;
}
*p++ = sep; *p++ = ' ';
}
ngx_http_perl_set_targ(value, size);
done:
@ -591,6 +572,7 @@ header_out(r, key, value)
}
header->hash = 1;
header->next = NULL;
if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) {
header->hash = 0;

View File

@ -108,10 +108,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_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
ngx_uint_t allow_underscores);
ngx_int_t ngx_http_parse_multi_header_lines(ngx_array_t *headers,
ngx_str_t *name, ngx_str_t *value);
ngx_int_t ngx_http_parse_set_cookie_lines(ngx_array_t *headers,
ngx_str_t *name, ngx_str_t *value);
ngx_table_elt_t *ngx_http_parse_multi_header_lines(ngx_http_request_t *r,
ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value);
ngx_table_elt_t *ngx_http_parse_set_cookie_lines(ngx_http_request_t *r,
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_str_t *value);
void ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri,

View File

@ -1007,6 +1007,7 @@ ngx_http_core_find_config_phase(ngx_http_request_t *r,
}
r->headers_out.location->hash = 1;
r->headers_out.location->next = NULL;
ngx_str_set(&r->headers_out.location->key, "Location");
if (r->args.len == 0) {
@ -1087,6 +1088,7 @@ ngx_int_t
ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
{
ngx_int_t rc;
ngx_table_elt_t *h;
ngx_http_core_loc_conf_t *clcf;
if (r != r->main) {
@ -1121,8 +1123,8 @@ ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
if (rc == NGX_OK) {
r->access_code = 0;
if (r->headers_out.www_authenticate) {
r->headers_out.www_authenticate->hash = 0;
for (h = r->headers_out.www_authenticate; h; h = h->next) {
h->hash = 0;
}
r->phase_handler = ph->next;
@ -1687,6 +1689,7 @@ ngx_http_set_etag(ngx_http_request_t *r)
}
etag->hash = 1;
etag->next = NULL;
ngx_str_set(&etag->key, "ETag");
etag->value.data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN + NGX_TIME_T_LEN + 3);
@ -1781,6 +1784,7 @@ ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status,
}
r->headers_out.location->hash = 1;
r->headers_out.location->next = NULL;
ngx_str_set(&r->headers_out.location->key, "Location");
r->headers_out.location->value = val;
@ -2024,8 +2028,7 @@ ngx_http_gzip_ok(ngx_http_request_t *r)
{
time_t date, expires;
ngx_uint_t p;
ngx_array_t *cc;
ngx_table_elt_t *e, *d, *ae;
ngx_table_elt_t *e, *d, *ae, *cc;
ngx_http_core_loc_conf_t *clcf;
r->gzip_tested = 1;
@ -2118,30 +2121,30 @@ ngx_http_gzip_ok(ngx_http_request_t *r)
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)
&& 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)
>= 0)
!= NULL)
{
goto ok;
}
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)
>= 0)
!= NULL)
{
goto ok;
}
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)
>= 0)
!= NULL)
{
goto ok;
}
@ -2712,12 +2715,12 @@ ngx_http_set_disable_symlinks(ngx_http_request_t *r,
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)
{
ngx_int_t rc;
ngx_uint_t i, found;
ngx_table_elt_t **h;
ngx_int_t rc;
ngx_uint_t found;
ngx_table_elt_t *h, *next;
if (headers == NULL) {
return ngx_http_get_forwarded_addr_internal(r, addr, value->data,
@ -2725,16 +2728,23 @@ ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr,
recursive);
}
i = headers->nelts;
h = headers->elts;
/* revert headers order */
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;
found = 0;
while (i-- > 0) {
rc = ngx_http_get_forwarded_addr_internal(r, addr, h[i]->value.data,
h[i]->value.len, proxies,
for (h = headers; h; h = h->next) {
rc = ngx_http_get_forwarded_addr_internal(r, addr, h->value.data,
h->value.len, proxies,
recursive);
if (!recursive) {
@ -2753,6 +2763,14 @@ ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr,
found = 1;
}
/* restore headers order */
for (h = headers, headers = NULL; h; h = next) {
next = h->next;
h->next = headers;
headers = h;
}
return rc;
}
@ -2802,6 +2820,80 @@ ngx_http_get_forwarded_addr_internal(ngx_http_request_t *r, ngx_addr_t *addr,
}
ngx_int_t
ngx_http_link_multi_headers(ngx_http_request_t *r)
{
ngx_uint_t i, j;
ngx_list_part_t *part, *ppart;
ngx_table_elt_t *header, *pheader, **ph;
if (r->headers_in.multi_linked) {
return NGX_OK;
}
r->headers_in.multi_linked = 1;
part = &r->headers_in.headers.part;
header = part->elts;
for (i = 0; /* void */; i++) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
header = part->elts;
i = 0;
}
header[i].next = NULL;
/*
* search for previous headers with the same name;
* if there are any, link to them
*/
ppart = &r->headers_in.headers.part;
pheader = ppart->elts;
for (j = 0; /* void */; j++) {
if (j >= ppart->nelts) {
if (ppart->next == NULL) {
break;
}
ppart = ppart->next;
pheader = ppart->elts;
j = 0;
}
if (part == ppart && i == j) {
break;
}
if (header[i].key.len == pheader[j].key.len
&& ngx_strncasecmp(header[i].key.data, pheader[j].key.data,
header[i].key.len)
== 0)
{
ph = &pheader[j].next;
while (*ph) { ph = &(*ph)->next; }
*ph = &header[i];
r->headers_in.multi = 1;
break;
}
}
}
return NGX_OK;
}
static char *
ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{

View File

@ -533,9 +533,11 @@ 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_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);
ngx_int_t ngx_http_link_multi_headers(ngx_http_request_t *r);
extern ngx_module_t ngx_http_core_module;

View File

@ -1960,27 +1960,24 @@ unsafe:
}
ngx_int_t
ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
ngx_str_t *value)
ngx_table_elt_t *
ngx_http_parse_multi_header_lines(ngx_http_request_t *r,
ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value)
{
ngx_uint_t i;
u_char *start, *last, *end, ch;
ngx_table_elt_t **h;
u_char *start, *last, *end, ch;
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,
"parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
if (name->len > h[i]->value.len) {
if (name->len > h->value.len) {
continue;
}
start = h[i]->value.data;
end = h[i]->value.data + h[i]->value.len;
start = h->value.data;
end = h->value.data + h->value.len;
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 (start == end || *start == ',') {
return i;
return h;
}
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->data = start;
return i;
return h;
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_http_parse_set_cookie_lines(ngx_array_t *headers, ngx_str_t *name,
ngx_str_t *value)
ngx_table_elt_t *
ngx_http_parse_set_cookie_lines(ngx_http_request_t *r,
ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value)
{
ngx_uint_t i;
u_char *start, *last, *end;
ngx_table_elt_t **h;
u_char *start, *last, *end;
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,
"parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
if (name->len >= h[i]->value.len) {
if (name->len >= h->value.len) {
continue;
}
start = h[i]->value.data;
end = h[i]->value.data + h[i]->value.len;
start = h->value.data;
end = h->value.data + h->value.len;
if (ngx_strncasecmp(start, name->data, name->len) != 0) {
continue;
@ -2077,10 +2071,10 @@ ngx_http_parse_set_cookie_lines(ngx_array_t *headers, ngx_str_t *name,
value->len = last - start;
value->data = start;
return i;
return h;
}
return NGX_DECLINED;
return NULL;
}

View File

@ -22,8 +22,6 @@ static ngx_int_t ngx_http_process_header_line(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_process_unique_header_line(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_process_multi_header_lines(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_process_host(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r,
@ -159,7 +157,7 @@ ngx_http_header_t ngx_http_headers_in[] = {
#if (NGX_HTTP_X_FORWARDED_FOR)
{ ngx_string("X-Forwarded-For"),
offsetof(ngx_http_headers_in_t, x_forwarded_for),
ngx_http_process_multi_header_lines },
ngx_http_process_header_line },
#endif
#if (NGX_HTTP_REALIP)
@ -191,8 +189,8 @@ ngx_http_header_t ngx_http_headers_in[] = {
ngx_http_process_header_line },
#endif
{ ngx_string("Cookie"), offsetof(ngx_http_headers_in_t, cookies),
ngx_http_process_multi_header_lines },
{ ngx_string("Cookie"), offsetof(ngx_http_headers_in_t, cookie),
ngx_http_process_header_line },
{ ngx_null_string, 0, NULL }
};
@ -1752,9 +1750,10 @@ ngx_http_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
ph = (ngx_table_elt_t **) ((char *) &r->headers_in + offset);
if (*ph == NULL) {
*ph = h;
}
while (*ph) { ph = &(*ph)->next; }
*ph = h;
h->next = NULL;
return NGX_OK;
}
@ -1770,6 +1769,7 @@ ngx_http_process_unique_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
if (*ph == NULL) {
*ph = h;
h->next = NULL;
return NGX_OK;
}
@ -1802,6 +1802,7 @@ ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h,
}
r->headers_in.host = h;
h->next = NULL;
host = h->value;
@ -1837,6 +1838,10 @@ static ngx_int_t
ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
if (ngx_http_process_header_line(r, h, offset) != NGX_OK) {
return NGX_ERROR;
}
if (ngx_strcasestrn(h->value.data, "close", 5 - 1)) {
r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
@ -1854,12 +1859,10 @@ ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h,
{
u_char *user_agent, *msie;
if (r->headers_in.user_agent) {
return NGX_OK;
if (ngx_http_process_header_line(r, h, offset) != NGX_OK) {
return NGX_ERROR;
}
r->headers_in.user_agent = h;
/* check some widespread browsers while the header is in CPU cache */
user_agent = h->value.data;
@ -1921,35 +1924,6 @@ ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h,
}
static ngx_int_t
ngx_http_process_multi_header_lines(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
ngx_array_t *headers;
ngx_table_elt_t **ph;
headers = (ngx_array_t *) ((char *) &r->headers_in + offset);
if (headers->elts == NULL) {
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;
return NGX_OK;
}
ngx_int_t
ngx_http_process_request_header(ngx_http_request_t *r)
{

View File

@ -213,7 +213,7 @@ typedef struct {
ngx_table_elt_t *keep_alive;
#if (NGX_HTTP_X_FORWARDED_FOR)
ngx_array_t x_forwarded_for;
ngx_table_elt_t *x_forwarded_for;
#endif
#if (NGX_HTTP_REALIP)
@ -232,17 +232,19 @@ typedef struct {
ngx_table_elt_t *date;
#endif
ngx_table_elt_t *cookie;
ngx_str_t user;
ngx_str_t passwd;
ngx_array_t cookies;
ngx_str_t server;
off_t content_length_n;
time_t keep_alive_n;
unsigned connection_type:2;
unsigned chunked:1;
unsigned multi:1;
unsigned multi_linked:1;
unsigned msie:1;
unsigned msie6:1;
unsigned opera:1;
@ -273,6 +275,9 @@ typedef struct {
ngx_table_elt_t *expires;
ngx_table_elt_t *etag;
ngx_table_elt_t *cache_control;
ngx_table_elt_t *link;
ngx_str_t *override_charset;
size_t content_type_len;
@ -281,9 +286,6 @@ typedef struct {
u_char *content_type_lowcase;
ngx_uint_t content_type_hash;
ngx_array_t cache_control;
ngx_array_t link;
off_t content_length_n;
off_t content_offset;
time_t date_time;

View File

@ -1243,6 +1243,7 @@ ngx_http_script_regex_end_code(ngx_http_script_engine_t *e)
}
r->headers_out.location->hash = 1;
r->headers_out.location->next = NULL;
ngx_str_set(&r->headers_out.location->key, "Location");
r->headers_out.location->value = e->buf;

View File

@ -649,6 +649,7 @@ ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page)
}
location->hash = 1;
location->next = NULL;
ngx_str_set(&location->key, "Location");
location->value = uri;

View File

@ -101,6 +101,9 @@ static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t
ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_process_content_length(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_process_last_modified(ngx_http_request_t *r,
@ -147,11 +150,6 @@ static ngx_int_t ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r,
static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
#if (NGX_HTTP_GZIP)
static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
#endif
static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf);
static ngx_int_t ngx_http_upstream_addr_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
@ -231,7 +229,7 @@ static ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
offsetof(ngx_http_headers_out_t, server), 0 },
{ ngx_string("WWW-Authenticate"),
ngx_http_upstream_process_header_line,
ngx_http_upstream_process_multi_header_lines,
offsetof(ngx_http_upstream_headers_in_t, www_authenticate),
ngx_http_upstream_copy_header_line, 0, 0 },
@ -241,12 +239,13 @@ static ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
ngx_http_upstream_rewrite_location, 0, 0 },
{ ngx_string("Refresh"),
ngx_http_upstream_ignore_header_line, 0,
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, refresh),
ngx_http_upstream_rewrite_refresh, 0, 0 },
{ ngx_string("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_string("Content-Disposition"),
@ -264,8 +263,7 @@ static ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
offsetof(ngx_http_headers_out_t, expires), 1 },
{ ngx_string("Accept-Ranges"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, accept_ranges),
ngx_http_upstream_ignore_header_line, 0,
ngx_http_upstream_copy_allow_ranges,
offsetof(ngx_http_headers_out_t, accept_ranges), 1 },
@ -316,12 +314,10 @@ static ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
ngx_http_upstream_process_transfer_encoding, 0,
ngx_http_upstream_ignore_header_line, 0, 0 },
#if (NGX_HTTP_GZIP)
{ ngx_string("Content-Encoding"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, content_encoding),
ngx_http_upstream_copy_content_encoding, 0, 0 },
#endif
ngx_http_upstream_ignore_header_line, 0,
ngx_http_upstream_copy_header_line,
offsetof(ngx_http_headers_out_t, content_encoding), 0 },
{ ngx_null_string, NULL, 0, NULL, 0, 0 }
};
@ -1714,8 +1710,10 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
}
}
if (u->conf->ssl_certificate && (u->conf->ssl_certificate->lengths
|| u->conf->ssl_certificate_key->lengths))
if (u->conf->ssl_certificate
&& u->conf->ssl_certificate->value.len
&& (u->conf->ssl_certificate->lengths
|| u->conf->ssl_certificate_key->lengths))
{
if (ngx_http_upstream_ssl_certificate(r, u, c) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
@ -2671,7 +2669,7 @@ ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
{
ngx_int_t status;
ngx_uint_t i;
ngx_table_elt_t *h;
ngx_table_elt_t *h, *ho, **ph;
ngx_http_err_page_t *err_page;
ngx_http_core_loc_conf_t *clcf;
@ -2700,23 +2698,36 @@ ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
if (status == NGX_HTTP_UNAUTHORIZED
&& u->headers_in.www_authenticate)
{
h = ngx_list_push(&r->headers_out.headers);
h = u->headers_in.www_authenticate;
ph = &r->headers_out.www_authenticate;
if (h == NULL) {
ngx_http_upstream_finalize_request(r, u,
while (h) {
ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_OK;
return NGX_OK;
}
*ho = *h;
ho->next = NULL;
*ph = ho;
ph = &ho->next;
h = h->next;
}
*h = *u->headers_in.www_authenticate;
r->headers_out.www_authenticate = h;
}
#if (NGX_HTTP_CACHE)
if (r->cache) {
if (u->headers_in.no_cache || u->headers_in.expired) {
u->cacheable = 0;
}
if (u->cacheable) {
time_t valid;
@ -2811,6 +2822,10 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
if (u->headers_in.no_cache || u->headers_in.expired) {
u->cacheable = 0;
}
if (u->headers_in.x_accel_redirect
&& !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
{
@ -2831,6 +2846,10 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
i = 0;
}
if (h[i].hash == 0) {
continue;
}
hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
h[i].lowcase_key, h[i].key.len);
@ -2884,6 +2903,10 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
i = 0;
}
if (h[i].hash == 0) {
continue;
}
if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
h[i].lowcase_key, h[i].key.len))
{
@ -4635,10 +4658,36 @@ ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);
if (*ph == NULL) {
*ph = h;
if (*ph) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent duplicate header line: \"%V: %V\", "
"previous value: \"%V: %V\", ignored",
&h->key, &h->value,
&(*ph)->key, &(*ph)->value);
h->hash = 0;
return NGX_OK;
}
*ph = h;
h->next = NULL;
return NGX_OK;
}
static ngx_int_t
ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset)
{
ngx_table_elt_t **ph;
ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);
while (*ph) { ph = &(*ph)->next; }
*ph = h;
h->next = NULL;
return NGX_OK;
}
@ -4659,9 +4708,34 @@ ngx_http_upstream_process_content_length(ngx_http_request_t *r,
u = r->upstream;
if (u->headers_in.content_length) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent duplicate header line: \"%V: %V\", "
"previous value: \"%V: %V\"",
&h->key, &h->value,
&u->headers_in.content_length->key,
&u->headers_in.content_length->value);
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
if (u->headers_in.transfer_encoding) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent \"Content-Length\" and "
"\"Transfer-Encoding\" headers at the same time");
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
h->next = NULL;
u->headers_in.content_length = h;
u->headers_in.content_length_n = ngx_atoof(h->value.data, h->value.len);
if (u->headers_in.content_length_n == NGX_ERROR) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent invalid \"Content-Length\" header: "
"\"%V: %V\"", &h->key, &h->value);
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
return NGX_OK;
}
@ -4674,6 +4748,18 @@ ngx_http_upstream_process_last_modified(ngx_http_request_t *r,
u = r->upstream;
if (u->headers_in.last_modified) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent duplicate header line: \"%V: %V\", "
"previous value: \"%V: %V\", ignored",
&h->key, &h->value,
&u->headers_in.last_modified->key,
&u->headers_in.last_modified->value);
h->hash = 0;
return NGX_OK;
}
h->next = NULL;
u->headers_in.last_modified = h;
u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data,
h->value.len);
@ -4686,26 +4772,16 @@ static ngx_int_t
ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
ngx_array_t *pa;
ngx_table_elt_t **ph;
ngx_http_upstream_t *u;
u = r->upstream;
pa = &u->headers_in.cookies;
ph = &u->headers_in.set_cookie;
if (pa->elts == NULL) {
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;
}
while (*ph) { ph = &(*ph)->next; }
*ph = h;
h->next = NULL;
#if (NGX_HTTP_CACHE)
if (!(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)) {
@ -4721,26 +4797,16 @@ static ngx_int_t
ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset)
{
ngx_array_t *pa;
ngx_table_elt_t **ph;
ngx_http_upstream_t *u;
ngx_table_elt_t **ph;
ngx_http_upstream_t *u;
u = r->upstream;
pa = &u->headers_in.cache_control;
ph = &u->headers_in.cache_control;
if (pa->elts == NULL) {
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;
}
while (*ph) { ph = &(*ph)->next; }
*ph = h;
h->next = NULL;
#if (NGX_HTTP_CACHE)
{
@ -4755,18 +4821,18 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
return NGX_OK;
}
if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) {
return NGX_OK;
}
start = h->value.data;
last = start + h->value.len;
if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) {
goto extensions;
}
if (ngx_strlcasestrn(start, last, (u_char *) "no-cache", 8 - 1) != NULL
|| ngx_strlcasestrn(start, last, (u_char *) "no-store", 8 - 1) != NULL
|| ngx_strlcasestrn(start, last, (u_char *) "private", 7 - 1) != NULL)
{
u->cacheable = 0;
u->headers_in.no_cache = 1;
return NGX_OK;
}
@ -4796,13 +4862,16 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
}
if (n == 0) {
u->cacheable = 0;
u->headers_in.no_cache = 1;
return NGX_OK;
}
r->cache->valid_sec = ngx_time() + n;
u->headers_in.expired = 0;
}
extensions:
p = ngx_strlcasestrn(start, last, (u_char *) "stale-while-revalidate=",
23 - 1);
@ -4862,7 +4931,20 @@ ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_http_upstream_t *u;
u = r->upstream;
if (u->headers_in.expires) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent duplicate header line: \"%V: %V\", "
"previous value: \"%V: %V\", ignored",
&h->key, &h->value,
&u->headers_in.expires->key,
&u->headers_in.expires->value);
h->hash = 0;
return NGX_OK;
}
u->headers_in.expires = h;
h->next = NULL;
#if (NGX_HTTP_CACHE)
{
@ -4883,7 +4965,7 @@ ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h,
expires = ngx_parse_http_time(h->value.data, h->value.len);
if (expires == NGX_ERROR || expires < ngx_time()) {
u->cacheable = 0;
u->headers_in.expired = 1;
return NGX_OK;
}
@ -4902,7 +4984,20 @@ ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
ngx_http_upstream_t *u;
u = r->upstream;
if (u->headers_in.x_accel_expires) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent duplicate header line: \"%V: %V\", "
"previous value: \"%V: %V\", ignored",
&h->key, &h->value,
&u->headers_in.x_accel_expires->key,
&u->headers_in.x_accel_expires->value);
h->hash = 0;
return NGX_OK;
}
u->headers_in.x_accel_expires = h;
h->next = NULL;
#if (NGX_HTTP_CACHE)
{
@ -4934,6 +5029,8 @@ ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
default:
r->cache->valid_sec = ngx_time() + n;
u->headers_in.no_cache = 0;
u->headers_in.expired = 0;
return NGX_OK;
}
}
@ -4945,6 +5042,8 @@ ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
if (n != NGX_ERROR) {
r->cache->valid_sec = n;
u->headers_in.no_cache = 0;
u->headers_in.expired = 0;
}
}
#endif
@ -4961,7 +5060,20 @@ ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_http_upstream_t *u;
u = r->upstream;
if (u->headers_in.x_accel_limit_rate) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent duplicate header line: \"%V: %V\", "
"previous value: \"%V: %V\", ignored",
&h->key, &h->value,
&u->headers_in.x_accel_limit_rate->key,
&u->headers_in.x_accel_limit_rate->value);
h->hash = 0;
return NGX_OK;
}
u->headers_in.x_accel_limit_rate = h;
h->next = NULL;
if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE) {
return NGX_OK;
@ -5020,7 +5132,11 @@ static ngx_int_t
ngx_http_upstream_process_charset(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
if (r->upstream->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_CHARSET) {
ngx_http_upstream_t *u;
u = r->upstream;
if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_CHARSET) {
return NGX_OK;
}
@ -5034,13 +5150,22 @@ static ngx_int_t
ngx_http_upstream_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
r->upstream->headers_in.connection = h;
ngx_table_elt_t **ph;
ngx_http_upstream_t *u;
u = r->upstream;
ph = &u->headers_in.connection;
while (*ph) { ph = &(*ph)->next; }
*ph = h;
h->next = NULL;
if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
(u_char *) "close", 5 - 1)
!= NULL)
{
r->upstream->headers_in.connection_close = 1;
u->headers_in.connection_close = 1;
}
return NGX_OK;
@ -5051,13 +5176,40 @@ static ngx_int_t
ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset)
{
r->upstream->headers_in.transfer_encoding = h;
ngx_http_upstream_t *u;
if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
(u_char *) "chunked", 7 - 1)
!= NULL)
u = r->upstream;
if (u->headers_in.transfer_encoding) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent duplicate header line: \"%V: %V\", "
"previous value: \"%V: %V\"",
&h->key, &h->value,
&u->headers_in.transfer_encoding->key,
&u->headers_in.transfer_encoding->value);
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
if (u->headers_in.content_length) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent \"Content-Length\" and "
"\"Transfer-Encoding\" headers at the same time");
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
u->headers_in.transfer_encoding = h;
h->next = NULL;
if (h->value.len == 7
&& ngx_strncasecmp(h->value.data, (u_char *) "chunked", 7) == 0)
{
r->upstream->headers_in.chunked = 1;
u->headers_in.chunked = 1;
} else {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent unknown \"Transfer-Encoding\": \"%V\"",
&h->value);
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
return NGX_OK;
@ -5068,29 +5220,74 @@ static ngx_int_t
ngx_http_upstream_process_vary(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset)
{
ngx_http_upstream_t *u;
ngx_table_elt_t **ph;
ngx_http_upstream_t *u;
u = r->upstream;
u->headers_in.vary = h;
ph = &u->headers_in.vary;
while (*ph) { ph = &(*ph)->next; }
*ph = h;
h->next = NULL;
#if (NGX_HTTP_CACHE)
{
u_char *p;
size_t len;
ngx_str_t vary;
if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_VARY) {
return NGX_OK;
}
if (r->cache == NULL) {
if (r->cache == NULL || !u->cacheable) {
return NGX_OK;
}
if (h->value.len > NGX_HTTP_CACHE_VARY_LEN
|| (h->value.len == 1 && h->value.data[0] == '*'))
{
if (h->value.len == 1 && h->value.data[0] == '*') {
u->cacheable = 0;
return NGX_OK;
}
if (u->headers_in.vary->next) {
len = 0;
for (h = u->headers_in.vary; h; h = h->next) {
len += h->value.len + 2;
}
len -= 2;
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
return NGX_ERROR;
}
vary.len = len;
vary.data = p;
for (h = u->headers_in.vary; h; h = h->next) {
p = ngx_copy(p, h->value.data, h->value.len);
if (h->next == NULL) {
break;
}
*p++ = ','; *p++ = ' ';
}
} else {
vary = h->value;
}
if (vary.len > NGX_HTTP_CACHE_VARY_LEN) {
u->cacheable = 0;
}
r->cache->vary = h->value;
r->cache->vary = vary;
}
#endif
return NGX_OK;
@ -5113,6 +5310,7 @@ ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
if (offset) {
ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
*ph = ho;
ho->next = NULL;
}
return NGX_OK;
@ -5123,18 +5321,8 @@ static ngx_int_t
ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset)
{
ngx_array_t *pa;
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);
if (ho == NULL) {
return NGX_ERROR;
@ -5142,12 +5330,12 @@ ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
*ho = *h;
ph = ngx_array_push(pa);
if (ph == NULL) {
return NGX_ERROR;
}
ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
while (*ph) { ph = &(*ph)->next; }
*ph = ho;
ho->next = NULL;
return NGX_OK;
}
@ -5217,6 +5405,7 @@ ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h,
}
*ho = *h;
ho->next = NULL;
r->headers_out.last_modified = ho;
r->headers_out.last_modified_time =
@ -5239,6 +5428,7 @@ ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h,
}
*ho = *h;
ho->next = NULL;
if (r->upstream->rewrite_redirect) {
rc = r->upstream->rewrite_redirect(r, ho, 0);
@ -5284,6 +5474,7 @@ ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h,
}
*ho = *h;
ho->next = NULL;
if (r->upstream->rewrite_redirect) {
@ -5329,6 +5520,7 @@ ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
}
*ho = *h;
ho->next = NULL;
if (r->upstream->rewrite_cookie) {
rc = r->upstream->rewrite_cookie(r, ho);
@ -5382,6 +5574,7 @@ ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
}
*ho = *h;
ho->next = NULL;
r->headers_out.accept_ranges = ho;
@ -5389,29 +5582,6 @@ ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
}
#if (NGX_HTTP_GZIP)
static ngx_int_t
ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset)
{
ngx_table_elt_t *ho;
ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) {
return NGX_ERROR;
}
*ho = *h;
r->headers_out.content_encoding = ho;
return NGX_OK;
}
#endif
static ngx_int_t
ngx_http_upstream_add_variables(ngx_conf_t *cf)
{
@ -5723,7 +5893,7 @@ ngx_http_upstream_header_variable(ngx_http_request_t *r,
return NGX_OK;
}
return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
&r->upstream->headers_in.headers.part,
sizeof("upstream_http_") - 1);
}
@ -5738,7 +5908,7 @@ ngx_http_upstream_trailer_variable(ngx_http_request_t *r,
return NGX_OK;
}
return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
&r->upstream->headers_in.trailers.part,
sizeof("upstream_trailer_") - 1);
}
@ -5760,9 +5930,9 @@ ngx_http_upstream_cookie_variable(ngx_http_request_t *r,
s.len = name->len - (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)
== NGX_DECLINED)
== NULL)
{
v->not_found = 1;
return NGX_OK;

View File

@ -280,23 +280,21 @@ typedef struct {
ngx_table_elt_t *last_modified;
ngx_table_elt_t *location;
ngx_table_elt_t *accept_ranges;
ngx_table_elt_t *refresh;
ngx_table_elt_t *www_authenticate;
ngx_table_elt_t *transfer_encoding;
ngx_table_elt_t *vary;
#if (NGX_HTTP_GZIP)
ngx_table_elt_t *content_encoding;
#endif
ngx_array_t cache_control;
ngx_array_t cookies;
ngx_table_elt_t *cache_control;
ngx_table_elt_t *set_cookie;
off_t content_length_n;
time_t last_modified_time;
unsigned connection_close:1;
unsigned chunked:1;
unsigned no_cache:1;
unsigned expired:1;
} ngx_http_upstream_headers_in_t;

View File

@ -27,8 +27,6 @@ static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r,
static ngx_int_t ngx_http_variable_cookies(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_headers(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_headers_internal(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data, u_char sep);
@ -178,12 +176,12 @@ static ngx_http_variable_t ngx_http_core_variables[] = {
#endif
#if (NGX_HTTP_X_FORWARDED_FOR)
{ ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_headers,
{ ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0, 0 },
#endif
{ 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,
0, 0, 0 },
@ -327,10 +325,10 @@ static ngx_http_variable_t ngx_http_core_variables[] = {
{ ngx_string("sent_http_transfer_encoding"), NULL,
ngx_http_variable_sent_transfer_encoding, 0, 0, 0 },
{ ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_headers,
{ ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 },
{ ngx_string("sent_http_link"), NULL, ngx_http_variable_headers,
{ ngx_string("sent_http_link"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_out.link), 0, 0 },
{ ngx_string("limit_rate"), ngx_http_variable_set_limit_rate,
@ -807,22 +805,7 @@ static ngx_int_t
ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
ngx_table_elt_t *h;
h = *(ngx_table_elt_t **) ((char *) r + data);
if (h) {
v->len = h->value.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = h->value.data;
} else {
v->not_found = 1;
}
return NGX_OK;
return ngx_http_variable_headers_internal(r, v, data, ',');
}
@ -834,38 +817,25 @@ ngx_http_variable_cookies(ngx_http_request_t *r,
}
static ngx_int_t
ngx_http_variable_headers(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
return ngx_http_variable_headers_internal(r, v, data, ',');
}
static ngx_int_t
ngx_http_variable_headers_internal(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data, u_char sep)
{
size_t len;
u_char *p, *end;
ngx_uint_t i, n;
ngx_array_t *a;
ngx_table_elt_t **h;
size_t len;
u_char *p;
ngx_table_elt_t *h, *th;
a = (ngx_array_t *) ((char *) r + data);
n = a->nelts;
h = a->elts;
h = *(ngx_table_elt_t **) ((char *) r + data);
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;
}
len += h[i]->value.len + 2;
len += th->value.len + 2;
}
if (len == 0) {
@ -879,9 +849,9 @@ ngx_http_variable_headers_internal(ngx_http_request_t *r,
v->no_cacheable = 0;
v->not_found = 0;
if (n == 1) {
v->len = (*h)->value.len;
v->data = (*h)->value.data;
if (h->next == NULL) {
v->len = h->value.len;
v->data = h->value.data;
return NGX_OK;
}
@ -894,17 +864,15 @@ ngx_http_variable_headers_internal(ngx_http_request_t *r,
v->len = len;
v->data = p;
end = p + len;
for (th = h; th; th = th->next) {
for (i = 0; /* void */ ; i++) {
if (h[i]->hash == 0) {
if (th->hash == 0) {
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;
}
@ -919,7 +887,7 @@ static ngx_int_t
ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
&r->headers_in.headers.part,
sizeof("http_") - 1);
}
@ -929,7 +897,7 @@ static ngx_int_t
ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
&r->headers_out.headers.part,
sizeof("sent_http_") - 1);
}
@ -939,19 +907,26 @@ static ngx_int_t
ngx_http_variable_unknown_trailer_out(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
&r->headers_out.trailers.part,
sizeof("sent_trailer_") - 1);
}
ngx_int_t
ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var,
ngx_http_variable_unknown_header(ngx_http_request_t *r,
ngx_http_variable_value_t *v, ngx_str_t *var,
ngx_list_part_t *part, size_t prefix)
{
u_char ch;
u_char *p, ch;
size_t len;
ngx_uint_t i, n;
ngx_table_elt_t *header;
ngx_table_elt_t *header, *h, **ph;
ph = &h;
#if (NGX_SUPPRESS_WARN)
len = 0;
#endif
header = part->elts;
@ -971,7 +946,11 @@ ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var,
continue;
}
for (n = 0; n + prefix < var->len && n < header[i].key.len; n++) {
if (header[i].key.len != var->len - prefix) {
continue;
}
for (n = 0; n < var->len - prefix; n++) {
ch = header[i].key.data[n];
if (ch >= 'A' && ch <= 'Z') {
@ -986,18 +965,59 @@ ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var,
}
}
if (n + prefix == var->len && n == header[i].key.len) {
v->len = header[i].value.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = header[i].value.data;
return NGX_OK;
if (n != var->len - prefix) {
continue;
}
len += header[i].value.len + 2;
*ph = &header[i];
ph = &header[i].next;
}
v->not_found = 1;
*ph = NULL;
if (h == NULL) {
v->not_found = 1;
return NGX_OK;
}
len -= 2;
if (h->next == NULL) {
v->len = h->value.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = h->value.data;
return NGX_OK;
}
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
return NGX_ERROR;
}
v->len = len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = p;
for ( ;; ) {
p = ngx_copy(p, h->value.data, h->value.len);
if (h->next == NULL) {
break;
}
*p++ = ','; *p++ = ' ';
h = h->next;
}
return NGX_OK;
}
@ -1050,8 +1070,8 @@ ngx_http_variable_cookie(ngx_http_request_t *r, ngx_http_variable_value_t *v,
s.len = name->len - (sizeof("cookie_") - 1);
s.data = name->data + sizeof("cookie_") - 1;
if (ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &s, &cookie)
== NGX_DECLINED)
if (ngx_http_parse_multi_header_lines(r, r->headers_in.cookie, &s, &cookie)
== NULL)
{
v->not_found = 1;
return NGX_OK;
@ -1879,7 +1899,7 @@ ngx_http_variable_sent_location(ngx_http_request_t *r,
ngx_str_set(&name, "sent_http_location");
return ngx_http_variable_unknown_header(v, &name,
return ngx_http_variable_unknown_header(r, v, &name,
&r->headers_out.headers.part,
sizeof("sent_http_") - 1);
}

View File

@ -57,8 +57,9 @@ ngx_http_variable_value_t *ngx_http_get_flushed_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r,
ngx_str_t *name, ngx_uint_t key);
ngx_int_t ngx_http_variable_unknown_header(ngx_http_variable_value_t *v,
ngx_str_t *var, ngx_list_part_t *part, size_t prefix);
ngx_int_t ngx_http_variable_unknown_header(ngx_http_request_t *r,
ngx_http_variable_value_t *v, ngx_str_t *var, ngx_list_part_t *part,
size_t prefix);
#if (NGX_PCRE)

View File

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

View File

@ -609,13 +609,13 @@ ngx_http_v3_header_filter(ngx_http_request_t *r)
static ngx_int_t
ngx_http_v3_push_resources(ngx_http_request_t *r, ngx_chain_t ***out)
{
u_char *start, *end, *last;
ngx_str_t path;
ngx_int_t rc;
ngx_uint_t i, push;
ngx_table_elt_t **h;
ngx_http_v3_loc_conf_t *h3lcf;
ngx_http_complex_value_t *pushes;
u_char *start, *end, *last;
ngx_str_t path;
ngx_int_t rc;
ngx_uint_t i, push;
ngx_table_elt_t *h;
ngx_http_v3_loc_conf_t *h3lcf;
ngx_http_complex_value_t *pushes;
h3lcf = ngx_http_get_module_loc_conf(r, ngx_http_v3_module);
@ -654,15 +654,13 @@ ngx_http_v3_push_resources(ngx_http_request_t *r, ngx_chain_t ***out)
return NGX_OK;
}
h = r->headers_out.link.elts;
for (i = 0; i < r->headers_out.link.nelts; i++) {
for (h = r->headers_out.link; h; h = h->next) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http3 parse link: \"%V\"", &h[i]->value);
"http3 parse link: \"%V\"", &h->value);
start = h[i]->value.data;
end = h[i]->value.data + h[i]->value.len;
start = h->value.data;
end = h->value.data + h->value.len;
next_link:

View File

@ -55,7 +55,9 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit)
#if (NGX_HAVE_EPOLLRDHUP)
if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
&& ngx_use_epoll_rdhup)
{
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"readv: eof:%d, avail:%d",
rev->pending_eof, rev->available);

View File

@ -52,7 +52,9 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size)
#if (NGX_HAVE_EPOLLRDHUP)
if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
&& ngx_use_epoll_rdhup)
{
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"recv: eof:%d, avail:%d",
rev->pending_eof, rev->available);

View File

@ -1069,8 +1069,10 @@ ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s)
}
}
if (pscf->ssl_certificate && (pscf->ssl_certificate->lengths
|| pscf->ssl_certificate_key->lengths))
if (pscf->ssl_certificate
&& pscf->ssl_certificate->value.len
&& (pscf->ssl_certificate->lengths
|| pscf->ssl_certificate_key->lengths))
{
if (ngx_stream_proxy_ssl_certificate(s) != NGX_OK) {
ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
@ -1735,7 +1737,7 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream,
cl->buf->temporary = (n ? 1 : 0);
cl->buf->last_buf = src->read->eof;
cl->buf->flush = 1;
cl->buf->flush = !src->read->eof;
(*packets)++;
*received += n;
@ -2240,8 +2242,9 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf)
return NGX_ERROR;
}
if (pscf->ssl_certificate) {
if (pscf->ssl_certificate
&& pscf->ssl_certificate->value.len)
{
if (pscf->ssl_certificate_key == NULL) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no \"proxy_ssl_certificate_key\" is defined "