nginx-0.3.36-RELEASE import

*) Feature: the ngx_http_addition_filter_module.

    *) Feature: the "proxy_pass" and "fastcgi_pass" directives may be used
       inside the "if" block.

    *) Feature: the "proxy_ignore_client_abort" and
       "fastcgi_ignore_client_abort" directives.

    *) Feature: the "$request_completion" variable.

    *) Feature: the ngx_http_perl_module supports the $r->request_method
       and $r->remote_addr.

    *) Feature: the ngx_http_ssi_module supports the "elif" command.

    *) Bugfix: the "\/" string in the expression of the "if" command of the
       ngx_http_ssi_module was treated incorrectly.

    *) Bugfix: in the regular expressions in the "if" command of the
       ngx_http_ssi_module.

    *) Bugfix: if the relative path was specified in the
       "client_body_temp_path", "proxy_temp_path", "fastcgi_temp_path", and
       "perl_modules" directives, then the directory was used relatively to
       a current path but not to a server prefix.
This commit is contained in:
Igor Sysoev 2006-04-05 13:40:54 +00:00
parent 7d4551b196
commit d17850e685
29 changed files with 575 additions and 4573 deletions

View file

@ -78,6 +78,7 @@ fi
# ngx_http_postpone_filter
# ngx_http_charset_filter
# ngx_http_ssi_filter
# ngx_http_addition_filter
# ngx_http_userid_filter
# ngx_http_headers_filter
# ngx_http_copy_filter
@ -114,6 +115,11 @@ if [ $HTTP_SSI = YES ]; then
HTTP_SRCS="$HTTP_SRCS $HTTP_SSI_SRCS"
fi
if [ $HTTP_ADDITION = YES ]; then
HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_ADDITION_FILTER_MODULE"
HTTP_SRCS="$HTTP_SRCS $HTTP_ADDITION_SRCS"
fi
if [ $HTTP_USERID = YES ]; then
HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_USERID_FILTER_MODULE"
HTTP_SRCS="$HTTP_SRCS $HTTP_USERID_SRCS"

View file

@ -52,6 +52,7 @@ HTTP_SSL=NO
HTTP_SSI=YES
HTTP_POSTPONE=NO
HTTP_REALIP=NO
HTTP_ADDITION=NO
HTTP_ACCESS=YES
HTTP_AUTH_BASIC=YES
HTTP_USERID=YES
@ -139,6 +140,7 @@ do
--with-http_ssl_module) HTTP_SSL=YES ;;
--with-http_realip_module) HTTP_REALIP=YES ;;
--with-http_addition_module) HTTP_ADDITION=YES ;;
--without-http_charset_module) HTTP_CHARSET=NO ;;
--without-http_gzip_module) HTTP_GZIP=NO ;;
--without-http_ssi_module) HTTP_SSI=NO ;;

View file

@ -59,7 +59,7 @@ fi
# sendfile()
CC_AUX_FLAGS="-D_GNU_SOURCE"
CC_AUX_FLAGS="$CC_AUX_FLAGS -D_GNU_SOURCE"
ngx_feature="sendfile()"
ngx_feature_name="NGX_HAVE_SENDFILE"
ngx_feature_run=yes
@ -79,7 +79,7 @@ fi
# sendfile64()
CC_AUX_FLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64"
CC_AUX_FLAGS="$CC_AUX_FLAGS -D_FILE_OFFSET_BITS=64"
ngx_feature="sendfile64()"
ngx_feature_name="NGX_HAVE_SENDFILE64"
ngx_feature_run=yes

View file

@ -319,6 +319,10 @@ HTTP_REALIP_MODULE=ngx_http_realip_module
HTTP_REALIP_SRCS=src/http/modules/ngx_http_realip_module.c
HTTP_ADDITION_FILTER_MODULE=ngx_http_addition_filter_module
HTTP_ADDITION_SRCS=src/http/modules/ngx_http_addition_filter_module.c
HTTP_ACCESS_MODULE=ngx_http_access_module
HTTP_ACCESS_SRCS=src/http/modules/ngx_http_access_module.c

View file

@ -9,6 +9,102 @@
<title lang="en">nginx changelog</title>
<changes ver="0.3.36" date="05.04.2006">
<change type="feature">
<para lang="ru">
ÍÏÄÕÌØ ngx_http_addition_filter_module.
</para>
<para lang="en">
the ngx_http_addition_filter_module.
</para>
</change>
<change type="feature">
<para lang="ru">
ÄÉÒÅËÔÉ×Ù proxy_pass É fastcgi_pass ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ×ÎÕÔÒÉ ÂÌÏËÁ if.
</para>
<para lang="en">
the "proxy_pass" and "fastcgi_pass" directives may be used inside
the "if" block.
</para>
</change>
<change type="feature">
<para lang="ru">
ÄÉÒÅËÔÉ×Ù proxy_ignore_client_abort É fastcgi_ignore_client_abort.
</para>
<para lang="en">
the "proxy_ignore_client_abort" and "fastcgi_ignore_client_abort" directives.
</para>
</change>
<change type="feature">
<para lang="ru">
ÐÅÒÅÍÅÎÎÁÑ $request_completion.
</para>
<para lang="en">
the "$request_completion" variable.
</para>
</change>
<change type="feature">
<para lang="ru">
ÍÏÄÕÌØ ngx_http_perl_module ÐÏÄÄÅÒÖÉ×ÁÅÔ ÍÅÔÏÄÙ $r->request_method É
$r->remote_addr.
</para>
<para lang="en">
the ngx_http_perl_module supports the $r->request_method and $r->remote_addr.
</para>
</change>
<change type="feature">
<para lang="ru">
ÍÏÄÕÌØ ngx_http_ssi_module ÐÏÄÄÅÒÖÉ×ÁÅÔ ËÏÍÁÎÄÕ elif.
</para>
<para lang="en">
the ngx_http_ssi_module supports the "elif" command.
</para>
</change>
<change type="bugfix">
<para lang="ru">
ÓÔÒÏËÁ "\/" × ÎÁÞÁÌÅ ×ÙÒÁÖÅÎÉÑ ËÏÍÁÎÄÙ if ÍÏÄÕÌÑ ngx_http_ssi_module
×ÏÓÐÒÉÎÉÍÁÌÁÓØ ÎÅ×ÅÒÎÏ.
</para>
<para lang="en">
the "\/" string in the expression of the "if" command of the
ngx_http_ssi_module was treated incorrectly.
</para>
</change>
<change type="bugfix">
<para lang="ru">
× ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÒÅÇÕÌÑÒÎÙÈ ×ÙÒÁÖÅÎÉÑÈ × ËÏÍÁÎÄÅ if ÍÏÄÕÌÑ ngx_http_ssi_module.
</para>
<para lang="en">
in the regular expressions in the "if" command of the ngx_http_ssi_module.
</para>
</change>
<change type="bugfix">
<para lang="ru">
ÐÒÉ ÚÁÄÁÎÉÉ ÏÔÎÏÓÉÔÅÌØÎÏÇÏ ÐÕÔÉ × ÄÉÒÅËÔÉ×ÁÈ
client_body_temp_path, proxy_temp_path, fastcgi_temp_path É perl_modules
ÉÓÐÏÌØÚÏ×ÁÌÓÑ ËÁÔÁÌÏÇ ÏÔÎÏÓÉÔÅÌØÎÏ ÔÅËÕÝÅÇÏ ËÁÔÁÌÏÇÁ, Á ÎÅ ÏÔÎÏÓÉÔÅÌØÎÏ
ÐÒÅÆÉËÓÁ ÓÅÒ×ÅÒÁ.
</para>
<para lang="en">
if the relative path was specified in the "client_body_temp_path",
"proxy_temp_path", "fastcgi_temp_path", and "perl_modules" directives,
then the directory was used relatively to a current path but not
to a server prefix.
</para>
</change>
</changes>
<changes ver="0.3.35" date="22.03.2006">
<change type="bugfix">
@ -64,7 +160,7 @@ the "http_503" parameter of the "proxy_next_upstream" or
<change type="bugfix">
<para lang="ru">
ngx_http_perl_module не работал со встроенным в конфигурацинный файл кодом,
ngx_http_perl_module ÎÅ ÒÁÂÏÔÁÌ ÓÏ ×ÓÔÒÏÅÎÎÙÍ × ËÏÎÆÉÇÕÒÁÃÉÏÎÎÙÊ ÆÁÊÌ ËÏÄÏÍ,
ÅÓÌÉ ÏÎ ÎÅ ÎÁÞÉÎÁÌÓÑ ÓÒÁÚÕ ÖÅ Ó "sub".
</para>
<para lang="en">

View file

@ -8,7 +8,7 @@
#define _NGINX_H_INCLUDED_
#define NGINX_VER "nginx/0.3.35"
#define NGINX_VER "nginx/0.3.36"
#define NGINX_VAR "NGINX"
#define NGX_OLDPID_EXT ".oldbin"

View file

@ -63,6 +63,7 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
char *rv;
ngx_fd_t fd;
ngx_int_t rc;
ngx_buf_t *b;
ngx_uint_t block;
ngx_conf_file_t *prev;
@ -95,11 +96,23 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
ngx_fd_info_n " \"%s\" failed", filename->data);
}
cf->conf_file->buffer = ngx_create_temp_buf(cf->pool, ngx_pagesize);
if (cf->conf_file->buffer == NULL) {
b = ngx_calloc_buf(cf->pool);
if (b == NULL) {
return NGX_CONF_ERROR;
}
cf->conf_file->buffer = b;
b->start = ngx_alloc(ngx_pagesize, cf->log);
if (b->start == NULL) {
return NGX_CONF_ERROR;
}
b->pos = b->start;
b->last = b->start;
b->end = b->last + ngx_pagesize;
b->temporary = 1;
cf->conf_file->file.fd = fd;
cf->conf_file->file.name.len = filename->len;
cf->conf_file->file.name.data = filename->data;
@ -183,7 +196,7 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
if (filename) {
ngx_pfree(cf->pool, cf->conf_file->buffer->start);
ngx_free(cf->conf_file->buffer->start);
cf->conf_file = prev;

View file

@ -211,8 +211,8 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
char *p = conf;
ssize_t level;
ngx_uint_t i, n;
ngx_str_t *value;
ngx_uint_t i, n;
ngx_path_t *path, **slot;
slot = (ngx_path_t **) (p + cmd->offset);
@ -229,6 +229,11 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
value = cf->args->elts;
path->name = value[1];
if (ngx_conf_full_name(cf->cycle, &path->name) == NGX_ERROR) {
return NULL;
}
path->len = 0;
path->cleaner = (ngx_gc_handler_pt) cmd->post;
path->conf_file = cf->conf_file->file.name.data;

View file

@ -86,7 +86,7 @@ ngx_palloc(ngx_pool_t *pool, size_t size)
{
u_char *m;
ngx_pool_t *p, *n;
ngx_pool_large_t *large, *last;
ngx_pool_large_t *large;
if (size <= (size_t) NGX_MAX_ALLOC_FROM_POOL
&& size <= (size_t) (pool->end - (u_char *) pool)
@ -134,34 +134,6 @@ ngx_palloc(ngx_pool_t *pool, size_t size)
return m;
}
/* allocate a large block */
large = NULL;
last = NULL;
if (pool->large) {
for (last = pool->large; /* void */ ; last = last->next) {
if (last->alloc == NULL) {
large = last;
last = NULL;
break;
}
if (last->next == NULL) {
break;
}
}
}
if (large == NULL) {
large = ngx_palloc(pool, sizeof(ngx_pool_large_t));
if (large == NULL) {
return NULL;
}
large->next = NULL;
}
#if 0
p = ngx_memalign(ngx_pagesize, size, pool->log);
if (p == NULL) {
@ -174,14 +146,14 @@ ngx_palloc(ngx_pool_t *pool, size_t size)
}
#endif
if (pool->large == NULL) {
pool->large = large;
} else if (last) {
last->next = large;
large = ngx_palloc(pool, sizeof(ngx_pool_large_t));
if (large == NULL) {
return NULL;
}
large->alloc = p;
large->next = pool->large;
pool->large = large;
return p;
}

View file

@ -0,0 +1,228 @@
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
typedef struct {
ngx_str_t before_body;
ngx_str_t after_body;
} ngx_http_addition_conf_t;
typedef struct {
unsigned before_body_sent:1;
unsigned after_body_sent:1;
} ngx_http_addition_ctx_t;
static ngx_int_t ngx_http_addition_filter_init(ngx_cycle_t *cycle);
static void *ngx_http_addition_create_conf(ngx_conf_t *cf);
static char *ngx_http_addition_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
static ngx_command_t ngx_http_addition_commands[] = {
{ ngx_string("add_before_body"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_addition_conf_t, before_body),
NULL },
{ ngx_string("add_after_body"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_addition_conf_t, after_body),
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_addition_filter_module_ctx = {
NULL, /* preconfiguration */
NULL, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_addition_create_conf, /* create location configuration */
ngx_http_addition_merge_conf /* merge location configuration */
};
ngx_module_t ngx_http_addition_filter_module = {
NGX_MODULE_V1,
&ngx_http_addition_filter_module_ctx, /* module context */
ngx_http_addition_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
ngx_http_addition_filter_init, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static ngx_int_t
ngx_http_addition_header_filter(ngx_http_request_t *r)
{
ngx_http_addition_ctx_t *ctx;
ngx_http_addition_conf_t *conf;
if (r->headers_out.status != NGX_HTTP_OK || r != r->main) {
return ngx_http_next_header_filter(r);
}
if (ngx_strncasecmp(r->headers_out.content_type.data, "text/html",
sizeof("text/html") - 1)
!= 0)
{
return ngx_http_next_header_filter(r);
}
conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module);
if (conf->before_body.len == 0 && conf->after_body.len == 0) {
return ngx_http_next_header_filter(r);
}
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_addition_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_addition_filter_module);
ngx_http_clear_content_length(r);
ngx_http_clear_accept_ranges(r);
return ngx_http_next_header_filter(r);
}
static ngx_int_t
ngx_http_addition_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_int_t rc;
ngx_uint_t last;
ngx_chain_t *cl;
ngx_http_addition_ctx_t *ctx;
ngx_http_addition_conf_t *conf;
if (in == NULL || r->header_only) {
return ngx_http_next_body_filter(r, in);
}
ctx = ngx_http_get_module_ctx(r, ngx_http_addition_filter_module);
if (ctx == NULL) {
return ngx_http_next_body_filter(r, in);
}
conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module);
if (!ctx->before_body_sent) {
ctx->before_body_sent = 1;
if (conf->before_body.len) {
if (ngx_http_subrequest(r, &conf->before_body, NULL, 0) != NGX_OK) {
return NGX_ERROR;
}
}
}
last = 0;
for (cl = in; cl; cl = cl->next) {
if (cl->buf->last_buf) {
cl->buf->last_buf = 0;
last = 1;
}
}
rc = ngx_http_next_body_filter(r, in);
if (rc == NGX_ERROR
|| !last
|| ctx->after_body_sent
|| conf->after_body.len == 0)
{
return rc;
}
if (ngx_http_subrequest(r, &conf->after_body, NULL, 0) != NGX_OK) {
return NGX_ERROR;
}
ctx->after_body_sent = 1;
return ngx_http_send_special(r, NGX_HTTP_LAST);
}
static ngx_int_t
ngx_http_addition_filter_init(ngx_cycle_t *cycle)
{
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_addition_header_filter;
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_addition_body_filter;
return NGX_OK;
}
static void *
ngx_http_addition_create_conf(ngx_conf_t *cf)
{
ngx_http_addition_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_addition_conf_t));
if (conf == NULL) {
return NGX_CONF_ERROR;
}
/*
* set by ngx_pcalloc():
*
* conf->before_body.len = 0;
* conf->before_body.date = NULL;
* conf->after_body.len = 0;
* conf->after_body.date = NULL;
*/
return conf;
}
static char *
ngx_http_addition_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_addition_conf_t *prev = parent;
ngx_http_addition_conf_t *conf = child;
ngx_conf_merge_str_value(conf->before_body, prev->before_body, "");
ngx_conf_merge_str_value(conf->after_body, prev->after_body, "");
return NGX_CONF_OK;
}

View file

@ -23,7 +23,7 @@ static ngx_http_module_t ngx_http_chunked_filter_module_ctx = {
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL, /* merge location configuration */
NULL /* merge location configuration */
};

View file

@ -170,7 +170,7 @@ static ngx_conf_bitmask_t ngx_http_fastcgi_next_upstream_masks[] = {
static ngx_command_t ngx_http_fastcgi_commands[] = {
{ ngx_string("fastcgi_pass"),
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
ngx_http_fastcgi_pass,
NGX_HTTP_LOC_CONF_OFFSET,
0,
@ -183,6 +183,13 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
offsetof(ngx_http_fastcgi_loc_conf_t, index),
NULL },
{ ngx_string("fastcgi_ignore_client_abort"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_client_abort),
NULL },
{ ngx_string("fastcgi_connect_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
@ -1470,6 +1477,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
*/
conf->upstream.buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
@ -1520,6 +1528,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->upstream.buffering,
prev->upstream.buffering, 1);
ngx_conf_merge_value(conf->upstream.ignore_client_abort,
prev->upstream.ignore_client_abort, 0);
ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
prev->upstream.connect_timeout, 60000);
@ -1670,6 +1681,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->peers == NULL) {
conf->peers = prev->peers;
conf->upstream.schema = prev->upstream.schema;
}
if (conf->params_source == NULL) {

View file

@ -517,6 +517,8 @@ ngx_http_memcached_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cyclic_temp_file = 0;
/* the hardcoded values */
conf->upstream.buffering = 0;
conf->upstream.ignore_client_abort = 0;
conf->upstream.send_lowat = 0;
conf->upstream.bufs.num = 0;
conf->upstream.busy_buffers_size = 0;

View file

@ -130,7 +130,7 @@ static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = {
static ngx_command_t ngx_http_proxy_commands[] = {
{ ngx_string("proxy_pass"),
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
ngx_http_proxy_pass,
NGX_HTTP_LOC_CONF_OFFSET,
0,
@ -150,6 +150,13 @@ static ngx_command_t ngx_http_proxy_commands[] = {
offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
NULL },
{ ngx_string("proxy_ignore_client_abort"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
NULL },
{ ngx_string("proxy_connect_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
@ -1415,6 +1422,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
*/
conf->upstream.buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
@ -1468,6 +1476,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->upstream.buffering,
prev->upstream.buffering, 1);
ngx_conf_merge_value(conf->upstream.ignore_client_abort,
prev->upstream.ignore_client_abort, 0);
ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
prev->upstream.connect_timeout, 60000);
@ -1654,6 +1665,10 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->peers == NULL) {
conf->peers = prev->peers;
conf->host_header = prev->host_header;
conf->port_text = prev->port_text;
conf->upstream.schema = prev->upstream.schema;
}
@ -2057,11 +2072,12 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#if (NGX_PCRE)
if (clcf->regex) {
if (clcf->regex || clcf->noname) {
if (plcf->upstream.uri.len) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"proxy_pass\" may not have URI part in "
"location given by regular expression");
"location given by regular expression or "
"inside the \"if\" statement");
return NGX_CONF_ERROR;
}

View file

@ -13,6 +13,7 @@
#define NGX_HTTP_SSI_DATE_LEN 2048
#define NGX_HTTP_SSI_ADD_PREFIX 1
#define NGX_HTTP_SSI_ADD_ZERO 2
typedef struct {
@ -247,8 +248,12 @@ static ngx_http_ssi_command_t ngx_http_ssi_commands[] = {
{ ngx_string("set"), ngx_http_ssi_set, ngx_http_ssi_set_params, 0, 0 },
{ ngx_string("if"), ngx_http_ssi_if, ngx_http_ssi_if_params, 0, 0 },
{ ngx_string("else"), ngx_http_ssi_else, ngx_http_ssi_no_params, 1, 0 },
{ ngx_string("endif"), ngx_http_ssi_endif, ngx_http_ssi_no_params, 1, 0 },
{ ngx_string("elif"), ngx_http_ssi_if, ngx_http_ssi_if_params,
NGX_HTTP_SSI_COND_IF, 0 },
{ ngx_string("else"), ngx_http_ssi_else, ngx_http_ssi_no_params,
NGX_HTTP_SSI_COND_IF, 0 },
{ ngx_string("endif"), ngx_http_ssi_endif, ngx_http_ssi_no_params,
NGX_HTTP_SSI_COND_ELSE, 0 },
{ ngx_null_string, NULL, NULL, 0, 0 }
};
@ -523,7 +528,17 @@ ngx_http_ssi_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
continue;
}
if (!ctx->output && !cmd->conditional) {
if (cmd->conditional
&& (ctx->conditional == 0
|| ctx->conditional > cmd->conditional))
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"invalid context of SSI command: \"%V\"",
&ctx->command);
goto ssi_error;
}
if (!ctx->output && cmd->conditional == 0) {
continue;
}
@ -926,6 +941,7 @@ ngx_http_ssi_parse(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx)
ctx->key = ngx_hash(ctx->key, ch);
ctx->params.nelts = 0;
state = ssi_command_state;
break;
}
@ -1565,7 +1581,7 @@ ngx_http_ssi_evaluate_string(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
}
}
p = ngx_palloc(r->pool, len);
p = ngx_palloc(r->pool, len + ((flags & NGX_HTTP_SSI_ADD_ZERO) ? 1 : 0));
if (p == NULL) {
return NGX_ERROR;
}
@ -1809,13 +1825,26 @@ ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
u_char *p, *last;
ngx_str_t *expr, left, right;
ngx_int_t rc;
ngx_uint_t negative, noregex;
ngx_uint_t negative, noregex, flags;
#if (NGX_PCRE)
ngx_str_t err;
ngx_regex_t *regex;
u_char errstr[NGX_MAX_CONF_ERRSTR];
#endif
if (ctx->command.len == 2) {
if (ctx->conditional) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"the \"if\" command inside the \"if\" command");
return NGX_HTTP_SSI_ERROR;
}
}
if (ctx->output_chosen) {
ctx->output = 0;
return NGX_OK;
}
expr = params[NGX_HTTP_SSI_IF_EXPR];
left.data = expr->data;
@ -1857,11 +1886,14 @@ ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
if (p == last) {
if (left.len) {
ctx->output = 1;
ctx->output_chosen = 1;
} else {
ctx->output = 0;
}
ctx->conditional = NGX_HTTP_SSI_COND_IF;
return NGX_OK;
}
@ -1887,11 +1919,17 @@ ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
}
noregex = 0;
flags = NGX_HTTP_SSI_ADD_ZERO;
last--;
p++;
} else {
noregex = 1;
flags = 0;
if (p < last - 1 && p[0] == '\\' && p[1] == '/') {
p++;
}
}
right.len = last - p;
@ -1900,7 +1938,7 @@ ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"right: \"%V\"", &right);
if (ngx_http_ssi_evaluate_string(r, ctx, &right, 0) != NGX_OK) {
if (ngx_http_ssi_evaluate_string(r, ctx, &right, flags) != NGX_OK) {
return NGX_HTTP_SSI_ERROR;
}
@ -1948,11 +1986,14 @@ ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
if ((rc == 0 && !negative) || (rc != 0 && negative)) {
ctx->output = 1;
ctx->output_chosen = 1;
} else {
ctx->output = 0;
}
ctx->conditional = NGX_HTTP_SSI_COND_IF;
return NGX_OK;
invalid_expression:
@ -1968,7 +2009,13 @@ static ngx_int_t
ngx_http_ssi_else(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
ngx_str_t **params)
{
ctx->output = !ctx->output;
if (ctx->output_chosen) {
ctx->output = 0;
} else {
ctx->output = 1;
}
ctx->conditional = NGX_HTTP_SSI_COND_ELSE;
return NGX_OK;
}
@ -1979,6 +2026,8 @@ ngx_http_ssi_endif(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
ngx_str_t **params)
{
ctx->output = 1;
ctx->output_chosen = 0;
ctx->conditional = 0;
return NGX_OK;
}

View file

@ -20,6 +20,10 @@
#define NGX_HTTP_SSI_PARAMS_N 4
#define NGX_HTTP_SSI_COND_IF 1
#define NGX_HTTP_SSI_COND_ELSE 2
typedef struct {
ngx_hash_t hash;
ngx_hash_keys_arrays_t commands;
@ -54,7 +58,9 @@ typedef struct {
ngx_array_t variables;
ngx_uint_t output; /* unsigned output:1; */
unsigned conditional:2;
unsigned output:1;
unsigned output_chosen:1;
void *value_buf;
ngx_str_t timefmt;
@ -80,7 +86,7 @@ typedef struct {
ngx_http_ssi_command_pt handler;
ngx_http_ssi_param_t *params;
unsigned conditional:1;
unsigned conditional:2;
unsigned flush:1;
} ngx_http_ssi_command_t;

View file

@ -177,6 +177,35 @@ args(r, ...)
RETVAL
char *
request_method(r)
nginx r
CODE:
RETVAL = ngx_palloc(r->pool, r->method_name.len + 1);
if (RETVAL == NULL) {
XSRETURN_UNDEF;
}
ngx_cpystrn((u_char *) RETVAL, r->method_name.data, r->method_name.len + 1);
OUTPUT:
RETVAL
char *
remote_addr(r)
nginx r
CODE:
RETVAL = (char *) r->connection->addr_text.data;
OUTPUT:
RETVAL
char *
header_in(r, key)
nginx r

View file

@ -39,6 +39,7 @@ static ngx_int_t ngx_http_perl_ssi(ngx_http_request_t *r,
ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params);
#endif
static void ngx_http_perl_handle_request(ngx_http_request_t *r);
static ngx_int_t
ngx_http_perl_get_interpreter(ngx_http_perl_main_conf_t *pmcf,
PerlInterpreter **perl, ngx_log_t *log);
@ -174,23 +175,39 @@ ngx_http_perl_xs_init(pTHX)
static ngx_int_t
ngx_http_perl_handler(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_str_t uri, args;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_loc_conf_t *plcf;
ngx_http_perl_main_conf_t *pmcf;
ngx_int_t rc;
/* TODO: Win32 */
if (r->zero_in_uri) {
return NGX_HTTP_NOT_FOUND;
}
rc = ngx_http_read_client_request_body(r, ngx_http_perl_handle_request);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
return rc;
}
return NGX_DONE;
}
static void
ngx_http_perl_handle_request(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_str_t uri, args;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_loc_conf_t *plcf;
ngx_http_perl_main_conf_t *pmcf;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler");
/* mod_perl's content handler assumes that content type was already set */
if (ngx_http_set_content_type(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
@ -198,7 +215,8 @@ ngx_http_perl_handler(ngx_http_request_t *r)
if (ctx == NULL) {
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
@ -209,7 +227,8 @@ ngx_http_perl_handler(ngx_http_request_t *r)
rc = ngx_http_perl_get_interpreter(pmcf, &ctx->perl, r->connection->log);
if (rc != NGX_OK) {
return rc;
ngx_http_finalize_request(r, rc);
return;
}
{
@ -235,20 +254,24 @@ ngx_http_perl_handler(ngx_http_request_t *r)
if (ctx->redirect_uri.len) {
uri = ctx->redirect_uri;
args = ctx->redirect_args;
} else {
uri.len = 0;
}
ctx->filename = NULL;
ctx->redirect_uri.len = 0;
if (uri.len) {
return ngx_http_internal_redirect(r, &uri, &args);
ngx_http_internal_redirect(r, &uri, &args);
return;
}
if (rc == NGX_OK || rc == NGX_HTTP_OK) {
return ngx_http_send_special(r, NGX_HTTP_LAST);
ngx_http_send_special(r, NGX_HTTP_LAST);
}
return rc;
ngx_http_finalize_request(r, rc);
}
@ -448,6 +471,10 @@ ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf)
}
#endif
if (ngx_conf_full_name(cf->cycle, &pmcf->modules) != NGX_OK) {
return NGX_CONF_ERROR;
}
PERL_SYS_INIT(&ngx_argc, &ngx_argv);
pmcf->perl = ngx_http_perl_create_interpreter(pmcf, cf->log);

View file

@ -1,628 +0,0 @@
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <ngx_http_proxy_handler.h>
static int ngx_http_proxy_process_cached_response(ngx_http_proxy_ctx_t *p,
int rc);
static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p);
static void ngx_http_proxy_cache_look_complete_request(ngx_http_proxy_ctx_t *p);
int ngx_http_proxy_get_cached_response(ngx_http_proxy_ctx_t *p)
{
char *last;
ngx_http_request_t *r;
ngx_http_proxy_cache_t *c;
ngx_http_proxy_upstream_conf_t *u;
r = p->request;
if (!(c = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_cache_t)))) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
p->cache = c;
c->ctx.file.fd = NGX_INVALID_FILE;
c->ctx.file.log = r->connection->log;
c->ctx.path = p->lcf->cache_path;
u = p->lcf->upstream;
c->ctx.key.len = u->url.len + r->uri.len - u->location->len + r->args.len;
if (!(c->ctx.key.data = ngx_palloc(r->pool, c->ctx.key.len + 1))) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
last = ngx_cpymem(c->ctx.key.data, u->url.data, u->url.len);
last = ngx_cpymem(last, r->uri.data + u->location->len,
r->uri.len - u->location->len);
if (r->args.len > 0) {
*(last++) = '?';
last = ngx_cpymem(last, r->args.data, r->args.len);
}
*last = '\0';
p->header_in = ngx_create_temp_hunk(r->pool, p->lcf->header_buffer_size);
if (p->header_in == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
p->header_in->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
c->ctx.buf = p->header_in;
c->ctx.log = r->connection->log;
return ngx_http_proxy_process_cached_response(p,
ngx_http_cache_get_file(r, &c->ctx));
}
static int ngx_http_proxy_process_cached_response(ngx_http_proxy_ctx_t *p,
int rc)
{
if (rc == NGX_OK) {
p->state->cache_state = NGX_HTTP_PROXY_CACHE_HIT;
p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
if (ngx_http_proxy_process_cached_header(p) == NGX_ERROR) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
p->valid_header_in = 1;
return ngx_http_proxy_send_cached_response(p);
}
if (rc == NGX_HTTP_CACHE_STALE) {
p->state->cache_state = NGX_HTTP_PROXY_CACHE_EXPR;
} else if (rc == NGX_HTTP_CACHE_AGED) {
p->state->cache_state = NGX_HTTP_PROXY_CACHE_AGED;
}
if (rc == NGX_HTTP_CACHE_STALE || rc == NGX_HTTP_CACHE_AGED) {
p->state->expired = ngx_time() - p->cache->ctx.expires;
p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
if (ngx_http_proxy_process_cached_header(p) == NGX_ERROR) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
p->header_in->last = p->header_in->pos;
p->stale = 1;
p->valid_header_in = 1;
} else if (rc == NGX_DECLINED) {
p->state->cache_state = NGX_HTTP_PROXY_CACHE_MISS;
p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
p->header_in->last = p->header_in->pos;
}
if (p->lcf->busy_lock) {
p->try_busy_lock = 1;
p->header_in->pos = p->header_in->start;
p->header_in->last = p->header_in->start;
p->busy_lock.time = 0;
p->busy_lock.event = p->request->connection->read;
p->busy_lock.event_handler = ngx_http_proxy_busy_lock_handler;
p->busy_lock.md5 = p->cache->ctx.md5;
ngx_http_proxy_cache_busy_lock(p);
return NGX_DONE;
}
return ngx_http_proxy_request_upstream(p);
}
static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p)
{
int rc, i;
ngx_table_elt_t *h;
ngx_http_request_t *r;
ngx_http_proxy_cache_t *c;
rc = ngx_http_proxy_parse_status_line(p);
c = p->cache;
r = p->request;
if (rc == NGX_AGAIN) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"\"proxy_header_buffer_size\" "
"is too small to read header from \"%s\"",
c->ctx.file.name.data);
return NGX_ERROR;
}
if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"no valid HTTP/1.0 header in \"%s\"",
c->ctx.file.name.data);
return NGX_ERROR;
}
/* rc == NGX_OK */
c->status = p->status;
c->status_line.len = p->status_end - p->status_start;
c->status_line.data = ngx_palloc(r->pool, c->status_line.len + 1);
if (c->status_line.data == NULL) {
return NGX_ERROR;
}
/* reset for the possible parsing the upstream header */
p->status = 0;
p->status_count = 0;
ngx_cpystrn(c->status_line.data, p->status_start, c->status_line.len + 1);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http cache status %ui \"%V\"",
c->status, &c->status_line);
/* TODO: ngx_init_table */
c->headers_in.headers = ngx_create_table(r->pool, 20);
for ( ;; ) {
rc = ngx_http_parse_header_line(r, p->header_in);
if (rc == NGX_OK) {
/* a header line has been parsed successfully */
h = ngx_http_add_header(&c->headers_in, ngx_http_proxy_headers_in);
if (h == NULL) {
return NGX_ERROR;
}
h->key.len = r->header_name_end - r->header_name_start;
h->value.len = r->header_end - r->header_start;
h->key.data = ngx_palloc(r->pool,
h->key.len + 1 + h->value.len + 1);
if (h->key.data == NULL) {
return NGX_ERROR;
}
h->value.data = h->key.data + h->key.len + 1;
ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
for (i = 0; ngx_http_proxy_headers_in[i].name.len != 0; i++) {
if (ngx_http_proxy_headers_in[i].name.len != h->key.len) {
continue;
}
if (ngx_strcasecmp(ngx_http_proxy_headers_in[i].name.data,
h->key.data) == 0)
{
*((ngx_table_elt_t **) ((char *) &c->headers_in
+ ngx_http_proxy_headers_in[i].offset)) = h;
break;
}
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http cache header: \"%V: %V\"", &h->key, &h->value);
continue;
} else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
/* a whole header has been parsed successfully */
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http cache header done");
c->ctx.file_start = p->header_in->pos - p->header_in->start;
return NGX_OK;
} else if (rc == NGX_HTTP_PARSE_INVALID_HEADER) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"invalid header in \"%s\"",
c->ctx.file.name.data);
return NGX_ERROR;
}
/* rc == NGX_AGAIN || rc == NGX_HTTP_PARSE_TOO_LONG_HEADER */
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"\"proxy_header_buffer_size\" "
"is too small to read header from \"%s\"",
c->ctx.file.name.data);
return NGX_ERROR;
}
}
void ngx_http_proxy_cache_busy_lock(ngx_http_proxy_ctx_t *p)
{
int rc, ft_type;
rc = ngx_http_busy_lock_cachable(p->lcf->busy_lock, &p->busy_lock,
p->try_busy_lock);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
"http cache busy lock cachable: %d", rc);
if (rc == NGX_OK) {
if (p->try_busy_lock) {
p->busy_locked = 1;
p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
p->header_in->last = p->header_in->pos;
ngx_http_proxy_request_upstream(p);
return;
}
ngx_http_proxy_cache_look_complete_request(p);
return;
}
p->try_busy_lock = 0;
if (p->cache->ctx.file.fd != NGX_INVALID_FILE
&& !p->cache->ctx.file.info_valid)
{
if (ngx_fd_info(p->cache->ctx.file.fd, &p->cache->ctx.file.info)
== NGX_FILE_ERROR)
{
ngx_log_error(NGX_LOG_CRIT, p->request->connection->log, ngx_errno,
ngx_fd_info_n " \"%s\" failed",
p->cache->ctx.file.name.data);
ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
p->cache->ctx.file.info_valid = 1;
}
if (rc == NGX_AGAIN) {
if ((ngx_event_flags & (NGX_USE_CLEAR_EVENT|NGX_USE_KQUEUE_EVENT))
&& !p->request->connection->write->active)
{
/*
* kqueue allows to detect when client closes prematurely
* connection
*/
p->request->connection->write->event_handler =
ngx_http_proxy_check_broken_connection;
if (ngx_add_event(p->request->connection->write, NGX_WRITE_EVENT,
NGX_CLEAR_EVENT) == NGX_ERROR)
{
ngx_http_proxy_finalize_request(p,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
}
return;
}
ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
if (rc == NGX_DONE) {
ft_type = NGX_HTTP_PROXY_FT_BUSY_LOCK;
} else {
/* rc == NGX_ERROR */
ft_type = NGX_HTTP_PROXY_FT_MAX_WAITING;
}
if (p->stale && (p->lcf->use_stale & ft_type)) {
ngx_http_proxy_finalize_request(p,
ngx_http_proxy_send_cached_response(p));
return;
}
p->state->status = NGX_HTTP_SERVICE_UNAVAILABLE;
ngx_http_proxy_finalize_request(p, NGX_HTTP_SERVICE_UNAVAILABLE);
}
static void ngx_http_proxy_cache_look_complete_request(ngx_http_proxy_ctx_t *p)
{
int rc;
ngx_http_cache_ctx_t *ctx;
if (!(ctx = ngx_pcalloc(p->request->pool, sizeof(ngx_http_cache_ctx_t)))) {
ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
*ctx = p->cache->ctx;
rc = ngx_http_cache_open_file(ctx, ngx_file_uniq(&p->cache->ctx.file.info));
if (rc == NGX_DECLINED || rc == NGX_HTTP_CACHE_THE_SAME) {
p->try_busy_lock = 1;
p->busy_lock.time = 0;
ngx_http_proxy_cache_busy_lock(p);
return;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
"http cache old fd:%d, new fd:%d",
p->cache->ctx.file.fd, ctx->file.fd);
if (p->cache->ctx.file.fd != NGX_INVALID_FILE) {
if (ngx_close_file(p->cache->ctx.file.fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, p->request->connection->log, ngx_errno,
ngx_close_file_n " \"%s\" failed",
p->cache->ctx.file.name.data);
}
}
p->cache->ctx = *ctx;
p->status = 0;
p->status_count = 0;
ngx_http_proxy_finalize_request(p,
ngx_http_proxy_process_cached_response(p, rc));
}
int ngx_http_proxy_send_cached_response(ngx_http_proxy_ctx_t *p)
{
int rc, len, i;
off_t rest;
ngx_hunk_t *h0, *h1;
ngx_chain_t out[2];
ngx_http_request_t *r;
r = p->request;
r->headers_out.status = p->cache->status;
#if 0
r->headers_out.content_length_n = -1;
r->headers_out.content_length = NULL;
#endif
/* copy an cached header to r->headers_out */
if (ngx_http_proxy_copy_header(p, &p->cache->headers_in) == NGX_ERROR) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
/* we need to allocate all before the header would be sent */
len = p->header_in->end - (p->header_in->start + p->cache->ctx.file_start);
h0 = NULL;
h1 = NULL;
if (len) {
if (!((h0 = ngx_calloc_hunk(r->pool)))) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (!((h0->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t))))) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
}
if (len < p->cache->ctx.length) {
if (!((h1 = ngx_calloc_hunk(r->pool)))) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (!((h1->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t))))) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
}
rc = ngx_http_send_header(r);
/* NEEDED ??? */ p->header_sent = 1;
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
rest = p->cache->ctx.length;
if (len) {
if (p->valid_header_in) {
h0->pos = p->header_in->start + p->cache->ctx.file_start;
if (len > p->cache->ctx.length) {
h0->last = h0->pos + p->cache->ctx.length;
} else {
h0->last = p->header_in->end;
}
h0->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
}
h0->type |= NGX_HUNK_FILE;
h0->file_pos = p->cache->ctx.file_start;
h0->file->fd = p->cache->ctx.file.fd;
h0->file->log = r->connection->log;
if (len > p->cache->ctx.length) {
h0->file_last = h0->file_pos + p->cache->ctx.length;
rest = 0;
} else {
h0->file_last = h0->file_pos + len;
rest -= len;
}
out[0].hunk = h0;
out[0].next = &out[1];
i = 0;
} else {
i = -1;
}
if (rest) {
h1->file_pos = p->cache->ctx.file_start + len;
h1->file_last = h1->file_pos + rest;
h1->type = NGX_HUNK_FILE;
h1->file->fd = p->cache->ctx.file.fd;
h1->file->log = r->connection->log;
out[++i].hunk = h1;
}
out[i].next = NULL;
if (!r->main) {
out[i].hunk->type |= NGX_HUNK_LAST;
}
r->file.fd = p->cache->ctx.file.fd;
return ngx_http_output_filter(r, out);
}
int ngx_http_proxy_is_cachable(ngx_http_proxy_ctx_t *p)
{
time_t date, last_modified, expires, t;
ngx_http_proxy_headers_in_t *h;
switch (p->upstream->status) {
case NGX_HTTP_OK:
case NGX_HTTP_MOVED_PERMANENTLY:
case NGX_HTTP_MOVED_TEMPORARILY:
break;
#if 0
case NGX_HTTP_NOT_MODIFIED:
return 1;
#endif
default:
return 0;
}
h = &p->upstream->headers_in;
date = NGX_ERROR;
if (h->date) {
date = ngx_http_parse_time(h->date->value.data, h->date->value.len);
}
if (date == NGX_ERROR) {
date = ngx_time();
}
p->cache->ctx.date = date;
last_modified = NGX_ERROR;
if (h->last_modified) {
last_modified = ngx_http_parse_time(h->last_modified->value.data,
h->last_modified->value.len);
p->cache->ctx.last_modified = last_modified;
}
if (h->x_accel_expires) {
expires = ngx_atoi(h->x_accel_expires->value.data,
h->x_accel_expires->value.len);
if (expires != NGX_ERROR) {
p->state->reason = NGX_HTTP_PROXY_CACHE_XAE;
p->state->expires = expires;
p->cache->ctx.expires = date + expires;
return (expires > 0);
}
}
if (!p->lcf->ignore_expires) {
/* TODO: Cache-Control: no-cache, max-age= */
if (h->expires) {
expires = ngx_http_parse_time(h->expires->value.data,
h->expires->value.len);
if (expires != NGX_ERROR) {
p->state->reason = NGX_HTTP_PROXY_CACHE_EXP;
p->state->expires = expires - date;
p->cache->ctx.expires = expires;
return (date < expires);
}
}
}
if (p->upstream->status == NGX_HTTP_MOVED_PERMANENTLY) {
p->state->reason = NGX_HTTP_PROXY_CACHE_MVD;
p->state->expires = /* STUB: 1 hour */ 60 * 60;
p->cache->ctx.expires = /* STUB: 1 hour */ 60 * 60;
return 1;
}
if (p->upstream->status == NGX_HTTP_MOVED_TEMPORARILY) {
return 1;
}
if (last_modified != NGX_ERROR && p->lcf->lm_factor > 0) {
/* FIXME: time_t == int_64_t, we can use fpu */
p->state->reason = NGX_HTTP_PROXY_CACHE_LMF;
t = (time_t)
((((int64_t) (date - last_modified)) * p->lcf->lm_factor) / 100);
p->state->expires = t;
p->cache->ctx.expires = ngx_time() + t;
return 1;
}
if (p->lcf->default_expires > 0) {
p->state->reason = NGX_HTTP_PROXY_CACHE_PDE;
p->state->expires = p->lcf->default_expires;
p->cache->ctx.expires = ngx_time() + p->lcf->default_expires;
return 1;
}
return 0;
}
int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p)
{
ngx_event_pipe_t *ep;
if (p->cache == NULL) {
return NGX_OK;
}
ep = p->upstream->event_pipe;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
"http cache update len: %O:%O",
p->cache->ctx.length, ep->read_length);
if (p->cache->ctx.length == -1) {
/* TODO: test rc */
ngx_write_file(&ep->temp_file->file,
(char *) &ep->read_length, sizeof(off_t),
offsetof(ngx_http_cache_header_t, length));
}
return ngx_http_cache_update_file(p->request, &p->cache->ctx,
&ep->temp_file->file.name);
}

File diff suppressed because it is too large Load diff

View file

@ -1,275 +0,0 @@
/*
* Copyright (C) Igor Sysoev
*/
#ifndef _NGX_HTTP_PROXY_HANDLER_H_INCLUDED_
#define _NGX_HTTP_PROXY_HANDLER_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_event_connect.h>
#include <ngx_event_pipe.h>
#include <ngx_http.h>
typedef enum {
NGX_HTTP_PROXY_CACHE_PASS = 1,
NGX_HTTP_PROXY_CACHE_BYPASS,
NGX_HTTP_PROXY_CACHE_AUTH,
NGX_HTTP_PROXY_CACHE_PGNC,
NGX_HTTP_PROXY_CACHE_MISS,
NGX_HTTP_PROXY_CACHE_EXPR,
NGX_HTTP_PROXY_CACHE_AGED,
NGX_HTTP_PROXY_CACHE_HIT
} ngx_http_proxy_state_e;
typedef enum {
NGX_HTTP_PROXY_CACHE_BPS = 1,
NGX_HTTP_PROXY_CACHE_XAE,
NGX_HTTP_PROXY_CACHE_CTL,
NGX_HTTP_PROXY_CACHE_EXP,
NGX_HTTP_PROXY_CACHE_MVD,
NGX_HTTP_PROXY_CACHE_LMF,
NGX_HTTP_PROXY_CACHE_PDE
} ngx_http_proxy_reason_e;
typedef struct {
ngx_str_t url;
ngx_str_t host;
ngx_str_t uri;
ngx_str_t host_header;
ngx_str_t port_text;
ngx_str_t *location;
char *uri_separator;
in_port_t port;
unsigned default_port:1;
} ngx_http_proxy_upstream_conf_t;
typedef struct {
size_t send_lowat;
size_t header_buffer_size;
size_t busy_buffers_size;
size_t max_temp_file_size;
size_t temp_file_write_size;
ngx_msec_t connect_timeout;
ngx_msec_t send_timeout;
ngx_msec_t read_timeout;
time_t default_expires;
ngx_int_t lm_factor;
ngx_uint_t next_upstream;
ngx_uint_t use_stale;
ngx_bufs_t bufs;
ngx_flag_t cyclic_temp_file;
ngx_flag_t cache;
ngx_flag_t preserve_host;
ngx_flag_t set_x_url;
ngx_flag_t set_x_real_ip;
ngx_flag_t add_x_forwarded_for;
ngx_flag_t pass_unparsed_uri;
ngx_flag_t pass_server;
ngx_flag_t pass_x_accel_expires;
ngx_flag_t ignore_expires;
ngx_path_t *cache_path;
ngx_path_t *temp_path;
ngx_array_t *x_vars;
ngx_http_busy_lock_t *busy_lock;
ngx_http_proxy_upstream_conf_t *upstream;
ngx_peers_t *peers;
} ngx_http_proxy_loc_conf_t;
/*
* "EXPR/10/5/- 200/EXP/60 4"
* "MISS/-/-/B 503/-/- -"
* "EXPR/10/20/SB HIT/-/- -"
* "EXPR/10/15/NB HIT/-/- -"
*/
typedef struct {
ngx_http_proxy_state_e cache_state;
time_t expired;
time_t bl_time;
ngx_uint_t bl_state;
ngx_uint_t status;
ngx_http_proxy_reason_e reason;
time_t time;
time_t expires;
ngx_str_t *peer;
} ngx_http_proxy_state_t;
typedef struct {
ngx_list_t headers;
#if 0
ngx_table_t headers; /* it must be first field */
#endif
ngx_table_elt_t *date;
ngx_table_elt_t *server;
ngx_table_elt_t *expires;
ngx_table_elt_t *cache_control;
ngx_table_elt_t *etag;
ngx_table_elt_t *x_accel_expires;
ngx_table_elt_t *connection;
ngx_table_elt_t *content_type;
ngx_table_elt_t *content_length;
#if (NGX_HTTP_GZIP)
ngx_table_elt_t *content_encoding;
#endif
ngx_table_elt_t *last_modified;
ngx_table_elt_t *location;
ngx_table_elt_t *accept_ranges;
ngx_table_elt_t *x_pad;
off_t content_length_n;
} ngx_http_proxy_headers_in_t;
typedef struct {
ngx_http_cache_t ctx;
ngx_uint_t status;
ngx_str_t status_line;
ngx_http_proxy_headers_in_t headers_in;
} ngx_http_proxy_cache_t;
typedef struct {
ngx_peer_connection_t peer;
ngx_uint_t status;
ngx_str_t status_line;
ngx_uint_t method;
ngx_output_chain_ctx_t *output_chain_ctx;
ngx_event_pipe_t *event_pipe;
ngx_http_proxy_headers_in_t headers_in;
} ngx_http_proxy_upstream_t;
typedef struct ngx_http_proxy_ctx_s ngx_http_proxy_ctx_t;
struct ngx_http_proxy_ctx_s {
ngx_http_request_t *request;
ngx_http_proxy_loc_conf_t *lcf;
ngx_http_proxy_upstream_t *upstream;
ngx_http_proxy_cache_t *cache;
ngx_buf_t *header_in;
ngx_http_busy_lock_ctx_t busy_lock;
unsigned accel:1;
unsigned cachable:1;
unsigned stale:1;
unsigned try_busy_lock:1;
unsigned busy_locked:1;
unsigned valid_header_in:1;
unsigned request_sent:1;
unsigned header_sent:1;
/* used to parse an upstream HTTP header */
ngx_uint_t status;
u_char *status_start;
u_char *status_end;
ngx_uint_t status_count;
ngx_uint_t parse_state;
ngx_http_proxy_state_t *state;
ngx_array_t states; /* of ngx_http_proxy_state_t */
/*
* we declare "action" as "char *" because the actions are usually
* the static strings and in the "u_char *" case we have to override
* all the time their types
*/
char *action;
ngx_http_log_ctx_t *saved_ctx;
ngx_log_handler_pt saved_handler;
};
typedef struct {
ngx_uint_t connection;
ngx_http_proxy_ctx_t *proxy;
} ngx_http_proxy_log_ctx_t;
#define NGX_HTTP_PROXY_PARSE_NO_HEADER 30
#define NGX_HTTP_PROXY_FT_ERROR 0x02
#define NGX_HTTP_PROXY_FT_TIMEOUT 0x04
#define NGX_HTTP_PROXY_FT_INVALID_HEADER 0x08
#define NGX_HTTP_PROXY_FT_HTTP_500 0x10
#define NGX_HTTP_PROXY_FT_HTTP_404 0x20
#define NGX_HTTP_PROXY_FT_BUSY_LOCK 0x40
#define NGX_HTTP_PROXY_FT_MAX_WAITING 0x80
int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p);
#if (NGX_HTTP_FILE_CACHE)
int ngx_http_proxy_get_cached_response(ngx_http_proxy_ctx_t *p);
int ngx_http_proxy_send_cached_response(ngx_http_proxy_ctx_t *p);
int ngx_http_proxy_is_cachable(ngx_http_proxy_ctx_t *p);
int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p);
void ngx_http_proxy_cache_busy_lock(ngx_http_proxy_ctx_t *p);
#endif
void ngx_http_proxy_rd_check_broken_connection(ngx_http_request_t *r);
void ngx_http_proxy_wr_check_broken_connection(ngx_http_request_t *r);
void ngx_http_proxy_check_broken_connection(ngx_http_request_t *r,
ngx_event_t *ev);
void ngx_http_proxy_busy_lock_handler(ngx_event_t *rev);
void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p);
u_char *ngx_http_proxy_log_error(ngx_log_t *log, u_char *buf, size_t len);
void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc);
void ngx_http_proxy_close_connection(ngx_http_proxy_ctx_t *p);
int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p);
int ngx_http_proxy_copy_header(ngx_http_proxy_ctx_t *p,
ngx_http_proxy_headers_in_t *headers_in);
extern ngx_module_t ngx_http_proxy_module;
extern ngx_http_header0_t ngx_http_proxy_headers_in[];
#endif /* _NGX_HTTP_PROXY_HANDLER_H_INCLUDED_ */

View file

@ -1,206 +0,0 @@
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <ngx_http_proxy_handler.h>
static int ngx_http_proxy_rewrite_location_header(ngx_http_proxy_ctx_t *p,
ngx_table_elt_t *loc);
int ngx_http_proxy_copy_header(ngx_http_proxy_ctx_t *p,
ngx_http_proxy_headers_in_t *headers_in)
{
ngx_uint_t i;
ngx_list_part_t *part;
ngx_table_elt_t *ho, *h;
ngx_http_request_t *r;
r = p->request;
part = &headers_in->headers.part;
h = part->elts;
for (i = 0; /* void */; i++) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
h = part->elts;
i = 0;
}
/* ignore some headers */
if (&h[i] == headers_in->connection) {
continue;
}
if (&h[i] == headers_in->x_pad) {
continue;
}
if (p->accel) {
if (&h[i] == headers_in->date
|| &h[i] == headers_in->accept_ranges) {
continue;
}
if (&h[i] == headers_in->x_accel_expires
&& !p->lcf->pass_x_accel_expires)
{
continue;
}
if (&h[i] == headers_in->server && !p->lcf->pass_server) {
continue;
}
if (&h[i] == headers_in->location) {
if (ngx_http_proxy_rewrite_location_header(p, &h[i])
== NGX_ERROR)
{
return NGX_ERROR;
}
continue;
}
}
/* "Content-Type" is handled specially */
if (&h[i] == headers_in->content_type) {
r->headers_out.content_type = &h[i];
r->headers_out.content_type->key.len = 0;
continue;
}
/* copy some header pointers and set up r->headers_out */
ho = ngx_list_push(&r->headers_out.headers);
if (ho == NULL) {
return NGX_ERROR;
}
*ho = h[i];
if (&h[i] == headers_in->expires) {
r->headers_out.expires = ho;
continue;
}
if (&h[i] == headers_in->cache_control) {
r->headers_out.cache_control = ho;
continue;
}
if (&h[i] == headers_in->etag) {
r->headers_out.etag = ho;
continue;
}
#if (NGX_HTTP_GZIP)
if (&h[i] == headers_in->content_encoding) {
r->headers_out.content_encoding = ho;
continue;
}
#endif
if (&h[i] == headers_in->last_modified) {
r->headers_out.last_modified = ho;
/* TODO: update r->headers_out.last_modified_time */
continue;
}
/*
* ngx_http_header_filter() passes the following headers as is
* and does not handle them specially if they are set:
* r->headers_out.server,
* r->headers_out.date,
* r->headers_out.content_length
*/
if (&h[i] == headers_in->server) {
r->headers_out.server = ho;
continue;
}
if (&h[i] == headers_in->date) {
r->headers_out.date = ho;
continue;
}
if (&h[i] == headers_in->content_length) {
r->headers_out.content_length = ho;
r->headers_out.content_length_n = ngx_atoi(ho->value.data,
ho->value.len);
continue;
}
}
return NGX_OK;
}
static int ngx_http_proxy_rewrite_location_header(ngx_http_proxy_ctx_t *p,
ngx_table_elt_t *loc)
{
u_char *last;
ngx_table_elt_t *location;
ngx_http_request_t *r;
ngx_http_proxy_upstream_conf_t *uc;
r = p->request;
uc = p->lcf->upstream;
location = ngx_list_push(&r->headers_out.headers);
if (location == NULL) {
return NGX_ERROR;
}
if (p->lcf->preserve_host
|| uc->url.len > loc->value.len
|| ngx_rstrncmp(loc->value.data, uc->url.data, uc->url.len) != 0)
{
/*
* we do not set r->headers_out.location here to avoid the handling
* the local redirects without a host name by ngx_http_header_filter()
*/
*location = *loc;
return NGX_OK;
}
/* TODO: proxy_reverse */
r->headers_out.location = location;
location->key.len = 0;
location->key.data = NULL;
location->value.len = uc->location->len
+ (loc->value.len - uc->url.len) + 1;
location->value.data = ngx_palloc(r->pool, location->value.len);
if (location->value.data == NULL) {
return NGX_ERROR;
}
last = ngx_cpymem(location->value.data,
uc->location->data, uc->location->len);
ngx_cpystrn(last, loc->value.data + uc->url.len,
loc->value.len - uc->url.len + 1);
return NGX_OK;
}

View file

@ -1,216 +0,0 @@
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <ngx_http_proxy_handler.h>
int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p)
{
u_char ch;
u_char *pos;
enum {
sw_start = 0,
sw_H,
sw_HT,
sw_HTT,
sw_HTTP,
sw_first_major_digit,
sw_major_digit,
sw_first_minor_digit,
sw_minor_digit,
sw_status,
sw_space_after_status,
sw_status_text,
sw_almost_done,
sw_done
} state;
state = p->parse_state;
pos = p->header_in->pos;
while (pos < p->header_in->last && state < sw_done) {
ch = *pos++;
switch (state) {
/* "HTTP/" */
case sw_start:
switch (ch) {
case 'H':
state = sw_H;
break;
default:
return NGX_HTTP_PROXY_PARSE_NO_HEADER;
}
break;
case sw_H:
switch (ch) {
case 'T':
state = sw_HT;
break;
default:
return NGX_HTTP_PROXY_PARSE_NO_HEADER;
}
break;
case sw_HT:
switch (ch) {
case 'T':
state = sw_HTT;
break;
default:
return NGX_HTTP_PROXY_PARSE_NO_HEADER;
}
break;
case sw_HTT:
switch (ch) {
case 'P':
state = sw_HTTP;
break;
default:
return NGX_HTTP_PROXY_PARSE_NO_HEADER;
}
break;
case sw_HTTP:
switch (ch) {
case '/':
state = sw_first_major_digit;
break;
default:
return NGX_HTTP_PROXY_PARSE_NO_HEADER;
}
break;
/* the first digit of major HTTP version */
case sw_first_major_digit:
if (ch < '1' || ch > '9') {
return NGX_HTTP_PROXY_PARSE_NO_HEADER;
}
state = sw_major_digit;
break;
/* the major HTTP version or dot */
case sw_major_digit:
if (ch == '.') {
state = sw_first_minor_digit;
break;
}
if (ch < '0' || ch > '9') {
return NGX_HTTP_PROXY_PARSE_NO_HEADER;
}
break;
/* the first digit of minor HTTP version */
case sw_first_minor_digit:
if (ch < '0' || ch > '9') {
return NGX_HTTP_PROXY_PARSE_NO_HEADER;
}
state = sw_minor_digit;
break;
/* the minor HTTP version or the end of the request line */
case sw_minor_digit:
if (ch == ' ') {
state = sw_status;
break;
}
if (ch < '0' || ch > '9') {
return NGX_HTTP_PROXY_PARSE_NO_HEADER;
}
break;
/* HTTP status code */
case sw_status:
if (ch < '0' || ch > '9') {
return NGX_HTTP_PROXY_PARSE_NO_HEADER;
}
p->status = p->status * 10 + ch - '0';
if (++p->status_count == 3) {
state = sw_space_after_status;
p->status_start = pos - 3;
}
break;
/* space or end of line */
case sw_space_after_status:
switch (ch) {
case ' ':
state = sw_status_text;
break;
case '.': /* IIS may send 403.1, 403.2, etc */
state = sw_status_text;
break;
case CR:
state = sw_almost_done;
break;
case LF:
state = sw_done;
break;
default:
return NGX_HTTP_PROXY_PARSE_NO_HEADER;
}
break;
/* any text until end of line */
case sw_status_text:
switch (ch) {
case CR:
state = sw_almost_done;
break;
case LF:
state = sw_done;
break;
}
break;
/* end of request line */
case sw_almost_done:
p->status_end = pos - 2;
switch (ch) {
case LF:
state = sw_done;
break;
default:
return NGX_HTTP_PROXY_PARSE_NO_HEADER;
}
break;
/* suppress warning */
case sw_done:
break;
}
}
p->header_in->pos = pos;
if (state == sw_done) {
if (p->status_end == NULL) {
p->status_end = pos - 1;
}
p->parse_state = sw_start;
return NGX_OK;
}
p->parse_state = state;
return NGX_AGAIN;
}

File diff suppressed because it is too large Load diff

View file

@ -1503,6 +1503,10 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
return;
}
if (!r->post_action) {
r->request_complete = 1;
}
if (ngx_http_post_action(r) == NGX_OK) {
return;
}
@ -2254,6 +2258,7 @@ ngx_http_post_action(ngx_http_request_t *r)
r->http_version = NGX_HTTP_VERSION_9;
r->header_only = 1;
r->post_action = 1;
ngx_http_internal_redirect(r, &clcf->post_action, NULL);

View file

@ -405,6 +405,8 @@ struct ngx_http_request_s {
unsigned lingering_close:1;
unsigned discard_body:1;
unsigned internal:1;
unsigned post_action:1;
unsigned request_complete:1;
unsigned done:1;
unsigned utf8:1;

View file

@ -277,9 +277,9 @@ ngx_http_upstream_init(ngx_http_request_t *r)
ngx_del_timer(c->read);
}
if (!(r->http_version == NGX_HTTP_VERSION_9 && r->header_only)) {
/* not a post_action */
u = r->upstream;
if (!r->post_action && !u->conf->ignore_client_abort) {
r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
}
@ -296,8 +296,6 @@ ngx_http_upstream_init(ngx_http_request_t *r)
}
}
u = r->upstream;
if (r->request_body) {
u->request_bufs = r->request_body->bufs;
}
@ -1208,10 +1206,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR
|| rc > NGX_OK
/* post_action */
|| (r->http_version == NGX_HTTP_VERSION_9 && r->header_only)) {
if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) {
ngx_http_upstream_finalize_request(r, u, rc);
return;
}
@ -1947,11 +1942,7 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r,
r->connection->log->action = "sending to client";
if (rc == 0
&& r == r->main
/* not a post_action */
&& !(r->http_version == NGX_HTTP_VERSION_9 && r->header_only))
{
if (rc == 0 && r == r->main && !r->post_action) {
rc = ngx_http_send_special(r, NGX_HTTP_LAST);
}

View file

@ -73,6 +73,7 @@ typedef struct {
ngx_flag_t pass_request_headers;
ngx_flag_t pass_request_body;
ngx_flag_t ignore_client_abort;
ngx_flag_t redirect_errors;
ngx_flag_t cyclic_temp_file;

View file

@ -44,6 +44,8 @@ static ngx_int_t ngx_http_variable_remote_user(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_request_completion(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
/*
@ -135,6 +137,9 @@ static ngx_http_variable_t ngx_http_core_variables[] = {
{ ngx_string("body_bytes_sent"), ngx_http_variable_body_bytes_sent,
0, 0, 0 },
{ ngx_string("request_completion"), ngx_http_variable_request_completion,
0, 0, 0 },
{ ngx_null_string, NULL, 0, 0, 0 }
};
@ -798,6 +803,30 @@ ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
}
static ngx_int_t
ngx_http_variable_request_completion(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->request_complete) {
v->len = 2;
v->valid = 1;
v->no_cachable = 0;
v->not_found = 0;
v->data = (u_char *) "OK";
return NGX_OK;
}
v->len = 0;
v->valid = 1;
v->no_cachable = 0;
v->not_found = 0;
v->data = (u_char *) "";
return NGX_OK;
}
ngx_int_t
ngx_http_variables_add_core_vars(ngx_conf_t *cf)
{