mirror of
https://github.com/nginx/nginx.git
synced 2025-02-25 18:55:26 -06:00
nginx-0.1.38-RELEASE import
*) Feature: the "limit_rate" directive is supported in in proxy and FastCGI mode. *) Feature: the "X-Accel-Limit-Rate" response header line is supported in proxy and FastCGI mode. *) Feature: the "break" directive. *) Feature: the "log_not_found" directive. *) Bugfix: the response status code was not changed when request was redirected by the ""X-Accel-Redirect" header line. *) Bugfix: the variables set by the "set" directive could not be used in SSI. *) Bugfix: the segmentation fault may occurred if the SSI page has more than one remote subrequest. *) Bugfix: nginx treated the backend response as invalid if the status line in the header was transferred in two packets; the bug had appeared in 0.1.29. *) Feature: the "ssi_types" directive. *) Feature: the "autoindex_exact_size" directive. *) Bugfix: the ngx_http_autoindex_module did not support the long file names in UTF-8. *) Feature: the IMAP/POP3 proxy.
This commit is contained in:
parent
549c6c6449
commit
5192b3651f
@ -37,7 +37,7 @@ http {
|
||||
|
||||
# deny access to .htaccess files
|
||||
#
|
||||
#location ~ \.ht {
|
||||
#location ~ /\.ht {
|
||||
# deny all;
|
||||
#}
|
||||
}
|
||||
|
@ -9,6 +9,129 @@
|
||||
<title lang="en">nginx changelog</title>
|
||||
|
||||
|
||||
<changes ver="0.1.38" date="08.07.2005">
|
||||
|
||||
<change type="feature">
|
||||
<para lang="ru">
|
||||
ÄÉÒÅËÔÉ×Á limit_rate ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ × ÒÅÖÉÍÅ ÐÒÏËÓÉ É FastCGI.
|
||||
</para>
|
||||
<para lang="en">
|
||||
the "limit_rate" directive is supported in in proxy and FastCGI mode.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="feature">
|
||||
<para lang="ru">
|
||||
× ÒÅÖÉÍÅ ÐÒÏËÓÉ É FastCGI ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ ÓÔÒÏËÁ ÚÁÇÏÌÏ×ËÁ "X-Accel-Limit-Rate"
|
||||
× ÏÔ×ÅÔÅ ÂÜËÅÎÄÁ.
|
||||
</para>
|
||||
<para lang="en">
|
||||
the "X-Accel-Limit-Rate" response header line is supported in proxy and FastCGI
|
||||
mode.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="feature">
|
||||
<para lang="ru">
|
||||
ÄÉÒÅËÔÉ×Á break.
|
||||
</para>
|
||||
<para lang="en">
|
||||
the "break" directive.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="feature">
|
||||
<para lang="ru">
|
||||
ÄÉÒÅËÔÉ×Á log_not_found.
|
||||
</para>
|
||||
<para lang="en">
|
||||
the "log_not_found" directive.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="bugfix">
|
||||
<para lang="ru">
|
||||
ÐÒÉ ÐÅÒÅÎÁÐÒÁ×ÌÅÎÉÉ ÚÁÐÒÏÓÁ Ó ÐÏÍÏÝØÀ ÓÔÒÏËÉ ÚÁÇÏÌÏ×ËÁ "X-Accel-Redirect"
|
||||
ÎÅ ÉÚÍÅÎÑÌÓÑ ËÏÄ ÏÔ×ÅÔÁ.
|
||||
</para>
|
||||
<para lang="en">
|
||||
the response status code was not changed when request was redirected
|
||||
by the ""X-Accel-Redirect" header line.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="bugfix">
|
||||
<para lang="ru">
|
||||
ÐÅÒÅÍÅÎÎÙÅ, ÕÓÔÁÎÏ×ÌÅÎÎÙÅ ÄÉÒÅËÔÉ×ÏÊ set ÎÅ ÍÏÇÌÉ ÉÓÐÏÌØÚÏ×ÁÔØÓÑ × SSI.
|
||||
</para>
|
||||
<para lang="en">
|
||||
the variables set by the "set" directive could not be used in SSI.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="bugfix">
|
||||
<para lang="ru">
|
||||
ÐÒÉ ×ËÌÀÞÅÎÉÉ × SSI ÂÏÌÅÅ ÏÄÎÏÇÏ ÕÄÁÌ£ÎÎÏÇÏ ÐÏÄÚÁÐÒÏÓÁ
|
||||
ÍÏÇ ÐÒÏÉÚÏÊÔÉ segmentation fault.
|
||||
</para>
|
||||
<para lang="en">
|
||||
the segmentation fault may occurred if the SSI page has more than one
|
||||
remote subrequest.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="bugfix">
|
||||
<para lang="ru">
|
||||
ÅÓÌÉ ÓÔÁÔÕÓÎÁÑ ÓÔÒÏËÁ × ÏÔ×ÅÔÅ ÂÜËÅÎÄÁ ÐÅÒÅÄÁ×ÁÌÁÓØ × Ä×ÕÈ ÐÁËÅÔÁÈ, ÔÏ
|
||||
nginx ÓÞÉÔÁÌ ÏÔ×ÅÔ ÎÅ×ÅÒÎÙÍ;
|
||||
ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.1.29.
|
||||
</para>
|
||||
<para lang="en">
|
||||
nginx treated the backend response as invalid if the status line in the
|
||||
header was transferred in two packets;
|
||||
bug appeared in 0.1.29.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="feature">
|
||||
<para lang="ru">
|
||||
ÄÉÒÅËÔÉ×Á ssi_types.
|
||||
</para>
|
||||
<para lang="en">
|
||||
the "ssi_types" directive.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="feature">
|
||||
<para lang="ru">
|
||||
ÄÉÒÅËÔÉ×Á autoindex_exact_size.
|
||||
</para>
|
||||
<para lang="en">
|
||||
the "autoindex_exact_size" directive.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="bugfix">
|
||||
<para lang="ru">
|
||||
ÍÏÄÕÌØ ngx_http_autoindex_module ÎÅ ÐÏÄÄÅÒÖÉ×ÁÌ ÄÌÉÎÎÙÅ ÉÍÅÎÁ ÆÁÊÌÏ× × UTF-8.
|
||||
</para>
|
||||
<para lang="en">
|
||||
the ngx_http_autoindex_module did not support the long file names in UTF-8.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="feature">
|
||||
<para lang="ru">
|
||||
IMAP/POP3 ÐÒÏËÓÉ.
|
||||
</para>
|
||||
<para lang="en">
|
||||
the IMAP/POP3 proxy.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
</changes>
|
||||
|
||||
|
||||
<changes ver="0.1.37" date="23.06.2005">
|
||||
|
||||
<change type="change">
|
||||
@ -316,7 +439,7 @@ expressions.
|
||||
|
||||
<change type="feature">
|
||||
<para lang="ru">
|
||||
в режиме прокси и FastCGI поддерживается строка заголовка X-Accel-Redirect
|
||||
× ÒÅÖÉÍÅ ÐÒÏËÓÉ É FastCGI ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ ÓÔÒÏËÁ ÚÁÇÏÌÏ×ËÁ "X-Accel-Redirect"
|
||||
× ÏÔ×ÅÔÅ ÂÜËÅÎÄÁ.
|
||||
</para>
|
||||
<para lang="en">
|
||||
|
@ -8,7 +8,7 @@
|
||||
#define _NGINX_H_INCLUDED_
|
||||
|
||||
|
||||
#define NGINX_VER "nginx/0.1.37"
|
||||
#define NGINX_VER "nginx/0.1.38"
|
||||
|
||||
#define NGINX_VAR "NGINX"
|
||||
#define NGX_NEWPID_EXT ".newbin"
|
||||
|
@ -128,6 +128,7 @@ struct ngx_connection_s {
|
||||
unsigned single_connection:1;
|
||||
unsigned unexpected_eof:1;
|
||||
unsigned timedout:1;
|
||||
unsigned closed:1;
|
||||
|
||||
unsigned sendfile:1;
|
||||
unsigned sndlowat:1;
|
||||
|
@ -15,7 +15,7 @@ ngx_create_pool(size_t size, ngx_log_t *log)
|
||||
|
||||
p = ngx_alloc(size, log);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p->last = (u_char *) p + sizeof(ngx_pool_t);
|
||||
|
@ -753,20 +753,62 @@ ngx_utf_length(ngx_str_t *utf)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c < 0xC0) {
|
||||
/* invalid utf */
|
||||
return utf->len;
|
||||
if (c >= 0xc0) {
|
||||
for (c <<= 1; c & 0x80; c <<= 1) {
|
||||
i++;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for (c <<= 1; c & 0x80; c <<= 1) {
|
||||
i++;
|
||||
}
|
||||
/* invalid utf */
|
||||
|
||||
return utf->len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
u_char *
|
||||
ngx_utf_cpystrn(u_char *dst, u_char *src, size_t n)
|
||||
{
|
||||
u_char c;
|
||||
|
||||
if (n == 0) {
|
||||
return dst;
|
||||
}
|
||||
|
||||
for ( /* void */ ; --n; dst++, src++) {
|
||||
|
||||
c = *src;
|
||||
*dst = c;
|
||||
|
||||
if (c < 0x80) {
|
||||
if (*dst != '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
if (c >= 0xc0) {
|
||||
for (c <<= 1; c & 0x80; c <<= 1) {
|
||||
*++dst = *++src;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* invalid utf */
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
uintptr_t
|
||||
ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
|
||||
{
|
||||
|
@ -97,6 +97,8 @@ void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src);
|
||||
ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src);
|
||||
|
||||
size_t ngx_utf_length(ngx_str_t *utf);
|
||||
u_char * ngx_utf_cpystrn(u_char *dst, u_char *src, size_t n);
|
||||
|
||||
|
||||
#define NGX_ESCAPE_URI 0
|
||||
#define NGX_ESCAPE_ARGS 1
|
||||
|
@ -761,7 +761,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t *cycle)
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
|
||||
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
||||
"rt signal queue overflow recovered");
|
||||
|
||||
overflow = 0;
|
||||
|
@ -182,7 +182,8 @@ static ngx_int_t ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
|
||||
|
||||
} else if (!p->cachable
|
||||
&& p->downstream->data == p->output_ctx
|
||||
&& p->downstream->write->ready)
|
||||
&& p->downstream->write->ready
|
||||
&& !p->downstream->write->delayed)
|
||||
{
|
||||
/*
|
||||
* if the bufs are not needed to be saved in a cache and
|
||||
@ -461,7 +462,8 @@ static ngx_int_t ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
|
||||
}
|
||||
|
||||
if (p->downstream->data != p->output_ctx
|
||||
|| !p->downstream->write->ready)
|
||||
|| !p->downstream->write->ready
|
||||
|| p->downstream->write->delayed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
ngx_flag_t enable;
|
||||
ngx_flag_t localtime;
|
||||
ngx_flag_t exact_size;
|
||||
} ngx_http_autoindex_loc_conf_t;
|
||||
|
||||
|
||||
@ -67,6 +68,13 @@ static ngx_command_t ngx_http_autoindex_commands[] = {
|
||||
offsetof(ngx_http_autoindex_loc_conf_t, localtime),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("autoindex_exact_size"),
|
||||
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_autoindex_loc_conf_t, exact_size),
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
@ -117,10 +125,11 @@ static u_char tail[] =
|
||||
static ngx_int_t
|
||||
ngx_http_autoindex_handler(ngx_http_request_t *r)
|
||||
{
|
||||
u_char *last;
|
||||
size_t len;
|
||||
u_char *last, scale;
|
||||
off_t length;
|
||||
size_t len, copy;
|
||||
ngx_tm_t tm;
|
||||
ngx_int_t rc;
|
||||
ngx_int_t rc, size;
|
||||
ngx_uint_t i, level;
|
||||
ngx_err_t err;
|
||||
ngx_buf_t *b;
|
||||
@ -351,7 +360,7 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
|
||||
+ NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof(">") - 2
|
||||
+ sizeof("</a>") - 1
|
||||
+ sizeof(" 28-Sep-1970 12:00 ") - 1
|
||||
+ 19
|
||||
+ 20
|
||||
+ 2;
|
||||
}
|
||||
|
||||
@ -396,14 +405,27 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
|
||||
*b->last++ = '"';
|
||||
*b->last++ = '>';
|
||||
|
||||
b->last = ngx_cpystrn(b->last, entry[i].name.data,
|
||||
NGX_HTTP_AUTOINDEX_NAME_LEN + 1);
|
||||
|
||||
len = entry[i].utf_len;
|
||||
|
||||
if (len) {
|
||||
if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
|
||||
copy = NGX_HTTP_AUTOINDEX_NAME_LEN - 3 + 1;
|
||||
|
||||
} else {
|
||||
copy = NGX_HTTP_AUTOINDEX_NAME_LEN + 1;
|
||||
}
|
||||
|
||||
b->last = ngx_utf_cpystrn(b->last, entry[i].name.data, copy);
|
||||
last = b->last;
|
||||
|
||||
} else {
|
||||
b->last = ngx_cpystrn(b->last, entry[i].name.data,
|
||||
NGX_HTTP_AUTOINDEX_NAME_LEN + 1);
|
||||
last = b->last - 3;
|
||||
}
|
||||
|
||||
if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
|
||||
b->last = ngx_cpymem(b->last - 3, "..></a>",
|
||||
sizeof("..></a>") - 1);
|
||||
b->last = ngx_cpymem(last, "..></a>", sizeof("..></a>") - 1);
|
||||
|
||||
} else {
|
||||
if (entry[i].dir && NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) {
|
||||
@ -427,12 +449,55 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
|
||||
tm.ngx_tm_hour,
|
||||
tm.ngx_tm_min);
|
||||
|
||||
if (entry[i].dir) {
|
||||
b->last = ngx_cpymem(b->last, " -",
|
||||
sizeof(" -") - 1);
|
||||
if (alcf->exact_size) {
|
||||
if (entry[i].dir) {
|
||||
b->last = ngx_cpymem(b->last, " -",
|
||||
sizeof(" -") - 1);
|
||||
} else {
|
||||
b->last = ngx_sprintf(b->last, "%19O", entry[i].size);
|
||||
}
|
||||
|
||||
} else {
|
||||
b->last = ngx_sprintf(b->last, "%19O", entry[i].size);
|
||||
if (entry[i].dir) {
|
||||
b->last = ngx_cpymem(b->last, " -", sizeof(" -") - 1);
|
||||
|
||||
} else {
|
||||
length = entry[i].size;
|
||||
|
||||
if (length > 1024 * 1024 * 1024 - 1) {
|
||||
size = (ngx_int_t) (length / (1024 * 1024 * 1024));
|
||||
if ((length % (1024 * 1024 * 1024))
|
||||
> (1024 * 1024 * 1024 / 2 - 1))
|
||||
{
|
||||
size++;
|
||||
}
|
||||
scale = 'G';
|
||||
|
||||
} else if (length > 1024 * 1024 - 1) {
|
||||
size = (ngx_int_t) (length / (1024 * 1024));
|
||||
if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) {
|
||||
size++;
|
||||
}
|
||||
scale = 'M';
|
||||
|
||||
} else if (length > 9999) {
|
||||
size = (ngx_int_t) (length / 1024);
|
||||
if (length % 1024 > 511) {
|
||||
size++;
|
||||
}
|
||||
scale = 'K';
|
||||
|
||||
} else {
|
||||
size = (ngx_int_t) length;
|
||||
scale = ' ';
|
||||
}
|
||||
|
||||
b->last = ngx_sprintf(b->last, "%6i", size);
|
||||
|
||||
if (scale != ' ') {
|
||||
*b->last++ = scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*b->last++ = CR;
|
||||
@ -559,6 +624,7 @@ ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf)
|
||||
|
||||
conf->enable = NGX_CONF_UNSET;
|
||||
conf->localtime = NGX_CONF_UNSET;
|
||||
conf->exact_size = NGX_CONF_UNSET;
|
||||
|
||||
return conf;
|
||||
}
|
||||
@ -572,6 +638,7 @@ ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
|
||||
ngx_conf_merge_value(conf->enable, prev->enable, 0);
|
||||
ngx_conf_merge_value(conf->localtime, prev->localtime, 0);
|
||||
ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1);
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ typedef struct {
|
||||
ngx_flag_t enable;
|
||||
ngx_flag_t no_buffer;
|
||||
|
||||
ngx_array_t *types; /* array of ngx_http_gzip_type_t */
|
||||
ngx_array_t *types; /* array of ngx_str_t */
|
||||
|
||||
ngx_bufs_t bufs;
|
||||
|
||||
@ -29,12 +29,6 @@ typedef struct {
|
||||
} ngx_http_gzip_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
ngx_uint_t enable;
|
||||
} ngx_http_gzip_type_t;
|
||||
|
||||
|
||||
#define NGX_HTTP_GZIP_PROXIED_OFF 0x0002
|
||||
#define NGX_HTTP_GZIP_PROXIED_EXPIRED 0x0004
|
||||
#define NGX_HTTP_GZIP_PROXIED_NO_CACHE 0x0008
|
||||
@ -91,20 +85,18 @@ static ngx_int_t ngx_http_gzip_filter_init(ngx_cycle_t *cycle);
|
||||
static void *ngx_http_gzip_create_conf(ngx_conf_t *cf);
|
||||
static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf,
|
||||
void *parent, void *child);
|
||||
static char *ngx_http_gzip_set_types(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
static char *ngx_http_gzip_types(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_http_gzip_set_window(ngx_conf_t *cf, void *post, void *data);
|
||||
static char *ngx_http_gzip_set_hash(ngx_conf_t *cf, void *post, void *data);
|
||||
static char *ngx_http_gzip_window(ngx_conf_t *cf, void *post, void *data);
|
||||
static char *ngx_http_gzip_hash(ngx_conf_t *cf, void *post, void *data);
|
||||
|
||||
|
||||
static ngx_conf_num_bounds_t ngx_http_gzip_comp_level_bounds = {
|
||||
ngx_conf_check_num_bounds, 1, 9
|
||||
};
|
||||
|
||||
static ngx_conf_post_handler_pt ngx_http_gzip_set_window_p =
|
||||
ngx_http_gzip_set_window;
|
||||
static ngx_conf_post_handler_pt ngx_http_gzip_set_hash_p =
|
||||
ngx_http_gzip_set_hash;
|
||||
static ngx_conf_post_handler_pt ngx_http_gzip_window_p = ngx_http_gzip_window;
|
||||
static ngx_conf_post_handler_pt ngx_http_gzip_hash_p = ngx_http_gzip_hash;
|
||||
|
||||
|
||||
|
||||
@ -148,7 +140,7 @@ static ngx_command_t ngx_http_gzip_filter_commands[] = {
|
||||
|
||||
{ ngx_string("gzip_types"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
|
||||
ngx_http_gzip_set_types,
|
||||
ngx_http_gzip_types,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
@ -165,14 +157,14 @@ static ngx_command_t ngx_http_gzip_filter_commands[] = {
|
||||
ngx_conf_set_size_slot,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
offsetof(ngx_http_gzip_conf_t, wbits),
|
||||
&ngx_http_gzip_set_window_p },
|
||||
&ngx_http_gzip_window_p },
|
||||
|
||||
{ ngx_string("gzip_hash"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_size_slot,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
offsetof(ngx_http_gzip_conf_t, memlevel),
|
||||
&ngx_http_gzip_set_hash_p },
|
||||
&ngx_http_gzip_hash_p },
|
||||
|
||||
{ ngx_string("gzip_no_buffer"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
|
||||
@ -270,10 +262,10 @@ static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
|
||||
static ngx_int_t
|
||||
ngx_http_gzip_header_filter(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_uint_t i, found;
|
||||
ngx_str_t *type;
|
||||
ngx_uint_t i;
|
||||
ngx_http_gzip_ctx_t *ctx;
|
||||
ngx_http_gzip_conf_t *conf;
|
||||
ngx_http_gzip_type_t *type;
|
||||
|
||||
conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
|
||||
|
||||
@ -297,24 +289,21 @@ ngx_http_gzip_header_filter(ngx_http_request_t *r)
|
||||
}
|
||||
|
||||
|
||||
found = 0;
|
||||
type = conf->types->elts;
|
||||
|
||||
for (i = 0; i < conf->types->nelts; i++) {
|
||||
if (r->headers_out.content_type.len >= type[i].name.len
|
||||
if (r->headers_out.content_type.len >= type[i].len
|
||||
&& ngx_strncasecmp(r->headers_out.content_type.data,
|
||||
type[i].name.data, type[i].name.len) == 0)
|
||||
type[i].data, type[i].len) == 0)
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
return ngx_http_next_header_filter(r);
|
||||
|
||||
|
||||
found:
|
||||
|
||||
if (r->headers_in.via) {
|
||||
if (conf->proxied & NGX_HTTP_GZIP_PROXIED_OFF) {
|
||||
return ngx_http_next_header_filter(r);
|
||||
@ -1031,7 +1020,7 @@ ngx_http_gzip_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
ngx_http_gzip_conf_t *prev = parent;
|
||||
ngx_http_gzip_conf_t *conf = child;
|
||||
|
||||
ngx_http_gzip_type_t *type;
|
||||
ngx_str_t *type;
|
||||
|
||||
ngx_conf_merge_value(conf->enable, prev->enable, 0);
|
||||
|
||||
@ -1051,8 +1040,7 @@ ngx_http_gzip_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
|
||||
if (conf->types == NULL) {
|
||||
if (prev->types == NULL) {
|
||||
conf->types = ngx_array_create(cf->pool, 1,
|
||||
sizeof(ngx_http_gzip_type_t));
|
||||
conf->types = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t));
|
||||
if (conf->types == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
@ -1062,9 +1050,8 @@ ngx_http_gzip_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
type->name.len = sizeof("text/html") - 1;
|
||||
type->name.data = (u_char *) "text/html";
|
||||
type->enable = 1;
|
||||
type->len = sizeof("text/html") - 1;
|
||||
type->data = (u_char *) "text/html";
|
||||
|
||||
} else {
|
||||
conf->types = prev->types;
|
||||
@ -1076,17 +1063,15 @@ ngx_http_gzip_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_gzip_set_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
ngx_http_gzip_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_gzip_conf_t *gcf = conf;
|
||||
|
||||
ngx_str_t *value;
|
||||
ngx_uint_t i;
|
||||
ngx_http_gzip_type_t *type;
|
||||
ngx_str_t *value, *type;
|
||||
ngx_uint_t i;
|
||||
|
||||
if (gcf->types == NULL) {
|
||||
gcf->types = ngx_array_create(cf->pool, 4,
|
||||
sizeof(ngx_http_gzip_type_t));
|
||||
gcf->types = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
|
||||
if (gcf->types == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
@ -1096,9 +1081,8 @@ ngx_http_gzip_set_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
type->name.len = sizeof("text/html") - 1;
|
||||
type->name.data = (u_char *) "text/html";
|
||||
type->enable = 1;
|
||||
type->len = sizeof("text/html") - 1;
|
||||
type->data = (u_char *) "text/html";
|
||||
}
|
||||
|
||||
value = cf->args->elts;
|
||||
@ -1114,14 +1098,14 @@ ngx_http_gzip_set_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
type->name.len = value[i].len;
|
||||
type->len = value[i].len;
|
||||
|
||||
type->name.data = ngx_palloc(cf->pool, type->name.len + 1);
|
||||
if (type->name.data == NULL) {
|
||||
type->data = ngx_palloc(cf->pool, type->len + 1);
|
||||
if (type->data == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
ngx_cpystrn(type->name.data, value[i].data, type->name.len + 1);
|
||||
ngx_cpystrn(type->data, value[i].data, type->len + 1);
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
@ -1129,7 +1113,7 @@ ngx_http_gzip_set_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_gzip_set_window(ngx_conf_t *cf, void *post, void *data)
|
||||
ngx_http_gzip_window(ngx_conf_t *cf, void *post, void *data)
|
||||
{
|
||||
int *np = data;
|
||||
|
||||
@ -1153,7 +1137,7 @@ ngx_http_gzip_set_window(ngx_conf_t *cf, void *post, void *data)
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_gzip_set_hash(ngx_conf_t *cf, void *post, void *data)
|
||||
ngx_http_gzip_hash(ngx_conf_t *cf, void *post, void *data)
|
||||
{
|
||||
int *np = data;
|
||||
|
||||
|
@ -914,7 +914,7 @@ ngx_http_proxy_parse_status_line(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p)
|
||||
}
|
||||
break;
|
||||
|
||||
/* end of request line */
|
||||
/* end of status line */
|
||||
case sw_almost_done:
|
||||
p->status_end = pos - 1;
|
||||
switch (ch) {
|
||||
@ -926,7 +926,7 @@ ngx_http_proxy_parse_status_line(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p)
|
||||
}
|
||||
}
|
||||
|
||||
u->header_in.pos = pos + 1;
|
||||
u->header_in.pos = pos;
|
||||
r->state = state;
|
||||
|
||||
return NGX_AGAIN;
|
||||
@ -1803,7 +1803,7 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
}
|
||||
|
||||
for (i = 0; i < plcf->peers->number; i++) {
|
||||
plcf->peers->peer[i].uri_separator = ":";
|
||||
plcf->peers->peer[i].uri_separator = "";
|
||||
}
|
||||
|
||||
plcf->host_header = inet_upstream.host_header;
|
||||
|
@ -36,6 +36,8 @@ static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle);
|
||||
static char *ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
static char *ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char * ngx_http_rewrite_if_condition(ngx_conf_t *cf,
|
||||
@ -66,6 +68,14 @@ static ngx_command_t ngx_http_rewrite_commands[] = {
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("break"),
|
||||
NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|
||||
|NGX_CONF_NOARGS,
|
||||
ngx_http_rewrite_break,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("if"),
|
||||
NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE,
|
||||
ngx_http_rewrite_if,
|
||||
@ -600,6 +610,24 @@ ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_rewrite_loc_conf_t *lcf = conf;
|
||||
|
||||
ngx_http_script_code_pt *code;
|
||||
|
||||
code = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(uintptr_t));
|
||||
if (code == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
*code = ngx_http_script_break_code;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
|
@ -24,6 +24,8 @@ typedef struct {
|
||||
ngx_flag_t silent_errors;
|
||||
ngx_flag_t ignore_recycled_buffers;
|
||||
|
||||
ngx_array_t *types; /* array of ngx_str_t */
|
||||
|
||||
size_t min_file_chunk;
|
||||
size_t value_len;
|
||||
} ngx_http_ssi_conf_t;
|
||||
@ -127,6 +129,8 @@ static ngx_int_t ngx_http_ssi_endif(ngx_http_request_t *r,
|
||||
static ngx_http_variable_value_t *
|
||||
ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, uintptr_t gmt);
|
||||
|
||||
static char *ngx_http_ssi_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
|
||||
static ngx_int_t ngx_http_ssi_add_variables(ngx_conf_t *cf);
|
||||
static void *ngx_http_ssi_create_conf(ngx_conf_t *cf);
|
||||
static char *ngx_http_ssi_merge_conf(ngx_conf_t *cf,
|
||||
@ -164,6 +168,13 @@ static ngx_command_t ngx_http_ssi_filter_commands[] = {
|
||||
offsetof(ngx_http_ssi_conf_t, min_file_chunk),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("ssi_types"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
|
||||
ngx_http_ssi_types,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
@ -201,7 +212,7 @@ static ngx_int_t (*ngx_http_next_body_filter) (ngx_http_request_t *r,
|
||||
|
||||
static u_char ngx_http_ssi_string[] = "<!--";
|
||||
static u_char ngx_http_ssi_error_string[] =
|
||||
"[an error occurred while processing the directive]";
|
||||
"[an error occurred while processing the directive]";
|
||||
|
||||
static ngx_str_t ngx_http_ssi_none = ngx_string("(none)");
|
||||
|
||||
@ -280,25 +291,35 @@ static ngx_http_variable_t ngx_http_ssi_vars[] = {
|
||||
static ngx_int_t
|
||||
ngx_http_ssi_header_filter(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_str_t *type;
|
||||
ngx_http_ssi_ctx_t *ctx;
|
||||
ngx_http_ssi_conf_t *conf;
|
||||
|
||||
conf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module);
|
||||
|
||||
if (!conf->enable) {
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
/* TODO: "text/html" -> custom types */
|
||||
|
||||
if (r->headers_out.content_type.len == 0
|
||||
|| ngx_strncasecmp(r->headers_out.content_type.data, "text/html", 5)
|
||||
!= 0)
|
||||
if (!conf->enable
|
||||
|| r->headers_out.content_type.len == 0)
|
||||
{
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
|
||||
type = conf->types->elts;
|
||||
for (i = 0; i < conf->types->nelts; i++) {
|
||||
if (r->headers_out.content_type.len >= type[i].len
|
||||
&& ngx_strncasecmp(r->headers_out.content_type.data,
|
||||
type[i].data, type[i].len) == 0)
|
||||
{
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
return ngx_http_next_header_filter(r);
|
||||
|
||||
|
||||
found:
|
||||
|
||||
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_ssi_ctx_t));
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
@ -1632,6 +1653,56 @@ ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, uintptr_t gmt)
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_ssi_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_ssi_conf_t *scf = conf;
|
||||
|
||||
ngx_str_t *value, *type;
|
||||
ngx_uint_t i;
|
||||
|
||||
if (scf->types == NULL) {
|
||||
scf->types = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
|
||||
if (scf->types == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
type = ngx_array_push(scf->types);
|
||||
if (type == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
type->len = sizeof("text/html") - 1;
|
||||
type->data = (u_char *) "text/html";
|
||||
}
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
for (i = 1; i < cf->args->nelts; i++) {
|
||||
|
||||
if (ngx_strcmp(value[i].data, "text/html") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
type = ngx_array_push(scf->types);
|
||||
if (type == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
type->len = value[i].len;
|
||||
|
||||
type->data = ngx_palloc(cf->pool, type->len + 1);
|
||||
if (type->data == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
ngx_cpystrn(type->data, value[i].data, type->len + 1);
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_ssi_add_variables(ngx_conf_t *cf)
|
||||
{
|
||||
@ -1661,6 +1732,12 @@ ngx_http_ssi_create_conf(ngx_conf_t *cf)
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* set by ngx_pcalloc():
|
||||
*
|
||||
* conf->types = NULL;
|
||||
*/
|
||||
|
||||
conf->enable = NGX_CONF_UNSET;
|
||||
conf->silent_errors = NGX_CONF_UNSET;
|
||||
conf->ignore_recycled_buffers = NGX_CONF_UNSET;
|
||||
@ -1678,6 +1755,8 @@ ngx_http_ssi_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
ngx_http_ssi_conf_t *prev = parent;
|
||||
ngx_http_ssi_conf_t *conf = child;
|
||||
|
||||
ngx_str_t *type;
|
||||
|
||||
ngx_conf_merge_value(conf->enable, prev->enable, 0);
|
||||
ngx_conf_merge_value(conf->silent_errors, prev->silent_errors, 0);
|
||||
ngx_conf_merge_value(conf->ignore_recycled_buffers,
|
||||
@ -1686,6 +1765,26 @@ ngx_http_ssi_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
ngx_conf_merge_size_value(conf->min_file_chunk, prev->min_file_chunk, 1024);
|
||||
ngx_conf_merge_size_value(conf->value_len, prev->value_len, 256);
|
||||
|
||||
if (conf->types == NULL) {
|
||||
if (prev->types == NULL) {
|
||||
conf->types = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t));
|
||||
if (conf->types == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
type = ngx_array_push(conf->types);
|
||||
if (type == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
type->len = sizeof("text/html") - 1;
|
||||
type->data = (u_char *) "text/html";
|
||||
|
||||
} else {
|
||||
conf->types = prev->types;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
@ -210,8 +210,10 @@ ngx_http_static_handler(ngx_http_request_t *r)
|
||||
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_error(level, log, err,
|
||||
ngx_open_file_n " \"%s\" failed", name.data);
|
||||
if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
|
||||
ngx_log_error(level, log, err,
|
||||
ngx_open_file_n " \"%s\" failed", name.data);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -68,13 +68,17 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
ngx_output_chain_ctx_t *ctx;
|
||||
ngx_http_copy_filter_conf_t *conf;
|
||||
|
||||
if (r->connection->write->error) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"copy filter: \"%V\"", &r->uri);
|
||||
|
||||
if (r->connection->closed) {
|
||||
rc = ngx_http_next_filter(r, in);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"copy closed filter: %i \"%V\"", rc, &r->uri);
|
||||
return rc;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
|
@ -326,6 +326,13 @@ static ngx_command_t ngx_http_core_commands[] = {
|
||||
offsetof(ngx_http_core_loc_conf_t, msie_padding),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("log_not_found"),
|
||||
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_core_loc_conf_t, log_not_found),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("error_page"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|
||||
|NGX_CONF_2MORE,
|
||||
@ -633,6 +640,8 @@ ngx_http_find_location_config(ngx_http_request_t *r)
|
||||
return NGX_HTTP_MOVED_PERMANENTLY;
|
||||
}
|
||||
|
||||
r->limit_rate = clcf->limit_rate;
|
||||
|
||||
if (clcf->handler) {
|
||||
r->content_handler = clcf->handler;
|
||||
}
|
||||
@ -862,10 +871,6 @@ ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
|
||||
if (r->connection->write->error) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http output filter \"%V\"", &r->uri);
|
||||
|
||||
@ -873,7 +878,7 @@ ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
/* NGX_ERROR may be returned by any filter */
|
||||
r->connection->write->error = 1;
|
||||
r->connection->closed = 1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -1727,6 +1732,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
|
||||
lcf->reset_timedout_connection = NGX_CONF_UNSET;
|
||||
lcf->port_in_redirect = NGX_CONF_UNSET;
|
||||
lcf->msie_padding = NGX_CONF_UNSET;
|
||||
lcf->log_not_found = NGX_CONF_UNSET;
|
||||
|
||||
return lcf;
|
||||
}
|
||||
@ -1841,6 +1847,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf,
|
||||
prev->reset_timedout_connection, 0);
|
||||
ngx_conf_merge_value(conf->port_in_redirect, prev->port_in_redirect, 1);
|
||||
ngx_conf_merge_value(conf->msie_padding, prev->msie_padding, 1);
|
||||
ngx_conf_merge_value(conf->log_not_found, prev->log_not_found, 1);
|
||||
|
||||
if (conf->open_files == NULL) {
|
||||
conf->open_files = prev->open_files;
|
||||
|
@ -224,6 +224,7 @@ struct ngx_http_core_loc_conf_s {
|
||||
ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */
|
||||
ngx_flag_t port_in_redirect; /* port_in_redirect */
|
||||
ngx_flag_t msie_padding; /* msie_padding */
|
||||
ngx_flag_t log_not_found; /* log_not_found */
|
||||
|
||||
ngx_array_t *error_pages; /* error_page */
|
||||
|
||||
|
@ -48,13 +48,18 @@ ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
ngx_http_request_t *mr;
|
||||
ngx_http_postponed_request_t *pr, **ppr;
|
||||
|
||||
if (r->connection->write->error) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http postpone filter \"%V\" %p", &r->uri, in);
|
||||
|
||||
if (r->connection->closed) {
|
||||
|
||||
if (r->postponed) {
|
||||
r->postponed = r->postponed->next;
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (r != r->connection->data || (r->postponed && in)) {
|
||||
|
||||
if (r->postponed) {
|
||||
@ -112,7 +117,7 @@ ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
/* NGX_ERROR may be returned by any filter */
|
||||
r->connection->write->error = 1;
|
||||
r->connection->closed = 1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -90,11 +90,6 @@ ngx_http_header_t ngx_http_headers_in[] = {
|
||||
{ ngx_string("Range"), offsetof(ngx_http_headers_in_t, range),
|
||||
ngx_http_process_header_line },
|
||||
|
||||
#if 0
|
||||
{ ngx_string("If-Range"), offsetof(ngx_http_headers_in_t, if_range),
|
||||
ngx_http_process_header_line },
|
||||
#endif
|
||||
|
||||
#if (NGX_HTTP_GZIP)
|
||||
{ ngx_string("Accept-Encoding"),
|
||||
offsetof(ngx_http_headers_in_t, accept_encoding),
|
||||
@ -1441,6 +1436,8 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||
r->done = 1;
|
||||
|
||||
if (r != r->connection->data) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http finalize non-active request: \"%V\"", &r->uri);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1448,12 +1445,18 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||
|
||||
pr = r->parent;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http parent request: \"%V\"", &pr->uri);
|
||||
|
||||
if (rc != NGX_AGAIN) {
|
||||
pr->connection->data = pr;
|
||||
}
|
||||
|
||||
if (pr->postponed) {
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http request: \"%V\" has postponed", &pr->uri);
|
||||
|
||||
if (rc != NGX_AGAIN && pr->postponed->request == r) {
|
||||
pr->postponed = pr->postponed->next;
|
||||
|
||||
@ -1462,9 +1465,13 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http request: \"%V\" still has postponed",
|
||||
&pr->uri);
|
||||
|
||||
if (pr->done) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http wake request: \"%V\"", &pr->uri);
|
||||
"http wake parent request: \"%V\"", &pr->uri);
|
||||
|
||||
pr->write_event_handler(pr);
|
||||
}
|
||||
@ -1483,7 +1490,7 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||
ngx_del_timer(r->connection->write);
|
||||
}
|
||||
|
||||
if (rc == NGX_HTTP_CLIENT_CLOSED_REQUEST || r->closed) {
|
||||
if (r->connection->closed) {
|
||||
ngx_http_close_request(r, 0);
|
||||
ngx_http_close_connection(r->connection);
|
||||
return;
|
||||
@ -1492,13 +1499,15 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||
ngx_http_finalize_request(r, ngx_http_special_response_handler(r, rc));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (rc == NGX_ERROR) {
|
||||
if (rc == NGX_ERROR || r->connection->closed) {
|
||||
ngx_http_close_request(r, 0);
|
||||
ngx_http_close_connection(r->connection);
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (rc == NGX_AGAIN || r->out) {
|
||||
if (rc == NGX_AGAIN || r->out) {
|
||||
(void) ngx_http_set_write_handler(r);
|
||||
return;
|
||||
}
|
||||
@ -1553,6 +1562,10 @@ ngx_http_set_write_handler(ngx_http_request_t *r)
|
||||
|
||||
r->write_event_handler = ngx_http_writer;
|
||||
|
||||
if (r->connection->closed) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
wev = r->connection->write;
|
||||
|
||||
if (wev->ready && wev->delayed) {
|
||||
@ -1673,6 +1686,9 @@ static ngx_int_t
|
||||
ngx_http_postponed_handler(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
#if 0
|
||||
ngx_http_request_t *mr;
|
||||
#endif
|
||||
ngx_http_postponed_request_t *pr;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
@ -1687,20 +1703,16 @@ ngx_http_postponed_handler(ngx_http_request_t *r)
|
||||
rc = ngx_http_output_filter(r, NULL);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http postponed output filter: %d", rc);
|
||||
"http postponed output filter: %d", rc);
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
/* NGX_ERROR may be returned by any filter */
|
||||
r->connection->write->error = 1;
|
||||
|
||||
ngx_http_finalize_request(r, rc);
|
||||
|
||||
return NGX_DONE;
|
||||
}
|
||||
/*
|
||||
* we treat NGX_ERROR as NGX_OK, because we need to complete
|
||||
* all postponed requests
|
||||
*/
|
||||
|
||||
pr = r->postponed;
|
||||
|
||||
@ -1713,7 +1725,7 @@ ngx_http_postponed_handler(ngx_http_request_t *r)
|
||||
r->connection->data = r;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http postponed request \"%V\"", &r->uri);
|
||||
"http wake child request \"%V\"", &r->uri);
|
||||
|
||||
r->write_event_handler(r);
|
||||
|
||||
@ -1833,7 +1845,7 @@ ngx_http_read_discarded_body(ngx_http_request_t *r)
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
|
||||
r->closed = 1;
|
||||
r->connection->closed = 1;
|
||||
|
||||
/*
|
||||
* if a client request body is discarded then we already set
|
||||
|
@ -310,6 +310,8 @@ struct ngx_http_request_s {
|
||||
|
||||
ngx_http_variable_value_t **variables;
|
||||
|
||||
size_t limit_rate;
|
||||
|
||||
/* used to learn the Apache compatible response length without a header */
|
||||
size_t header_size;
|
||||
|
||||
@ -361,7 +363,6 @@ struct ngx_http_request_s {
|
||||
unsigned keepalive:1;
|
||||
unsigned lingering_close:1;
|
||||
unsigned internal:1;
|
||||
unsigned closed:1;
|
||||
unsigned done:1;
|
||||
unsigned utf8:1;
|
||||
|
||||
|
@ -236,7 +236,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
|
||||
}
|
||||
|
||||
if (n == 0 || n == NGX_ERROR) {
|
||||
r->closed = 1;
|
||||
c->closed = 1;
|
||||
return NGX_HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
|
@ -558,6 +558,7 @@ ngx_http_script_regex_start_code(ngx_http_script_engine_t *e)
|
||||
|
||||
if (code->break_cycle) {
|
||||
r->valid_location = 0;
|
||||
r->uri_changed = 0;
|
||||
|
||||
} else {
|
||||
r->uri_changed = 1;
|
||||
@ -712,6 +713,15 @@ ngx_http_script_return_code(ngx_http_script_engine_t *e)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_script_break_code(ngx_http_script_engine_t *e)
|
||||
{
|
||||
e->request->uri_changed = 0;
|
||||
|
||||
e->ip = ngx_http_script_exit;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_script_if_code(ngx_http_script_engine_t *e)
|
||||
{
|
||||
|
@ -166,6 +166,7 @@ void ngx_http_script_regex_start_code(ngx_http_script_engine_t *e);
|
||||
void ngx_http_script_regex_end_code(ngx_http_script_engine_t *e);
|
||||
#endif
|
||||
void ngx_http_script_return_code(ngx_http_script_engine_t *e);
|
||||
void ngx_http_script_break_code(ngx_http_script_engine_t *e);
|
||||
void ngx_http_script_if_code(ngx_http_script_engine_t *e);
|
||||
void ngx_http_script_complex_value_code(ngx_http_script_engine_t *e);
|
||||
void ngx_http_script_value_code(ngx_http_script_engine_t *e);
|
||||
|
@ -244,6 +244,9 @@ ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error)
|
||||
ngx_http_err_page_t *err_page;
|
||||
ngx_http_core_loc_conf_t *clcf;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http special response: %d, \"%V\"", error, &r->uri);
|
||||
|
||||
rc = ngx_http_discard_body(r);
|
||||
|
||||
if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) {
|
||||
|
@ -39,6 +39,8 @@ static ngx_int_t
|
||||
ngx_table_elt_t *h, ngx_uint_t offset);
|
||||
static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r,
|
||||
ngx_table_elt_t *h, ngx_uint_t offset);
|
||||
static ngx_int_t ngx_http_upstream_process_limit_rate(ngx_http_request_t *r,
|
||||
ngx_table_elt_t *h, ngx_uint_t offset);
|
||||
static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r,
|
||||
ngx_table_elt_t *h, ngx_uint_t offset);
|
||||
static ngx_int_t
|
||||
@ -143,6 +145,10 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
|
||||
offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect),
|
||||
ngx_http_upstream_ignore_header_line, 0, 0 },
|
||||
|
||||
{ ngx_string("X-Accel-Limit-Rate"),
|
||||
ngx_http_upstream_process_limit_rate, 0,
|
||||
ngx_http_upstream_ignore_header_line, 0, 0 },
|
||||
|
||||
#if (NGX_HTTP_GZIP)
|
||||
{ ngx_string("Content-Encoding"),
|
||||
ngx_http_upstream_process_header_line,
|
||||
@ -299,12 +305,19 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
|
||||
ngx_connection_t *c;
|
||||
ngx_http_upstream_t *u;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
|
||||
"http upstream check client, write event:%d", ev->write);
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
|
||||
"http upstream check client, write event:%d, \"%V\"",
|
||||
ev->write, &r->uri);
|
||||
|
||||
c = r->connection;
|
||||
u = r->upstream;
|
||||
|
||||
if (c->closed) {
|
||||
ngx_http_upstream_finalize_request(r, u,
|
||||
NGX_HTTP_CLIENT_CLOSED_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
if (u->peer.connection == NULL) {
|
||||
return;
|
||||
}
|
||||
@ -318,6 +331,7 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
|
||||
}
|
||||
|
||||
ev->eof = 1;
|
||||
c->closed = 1;
|
||||
|
||||
if (ev->kq_errno) {
|
||||
ev->error = 1;
|
||||
@ -325,9 +339,8 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
|
||||
|
||||
if (!u->cachable && u->peer.connection) {
|
||||
ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
|
||||
"kevent() reported that client closed "
|
||||
"prematurely connection, "
|
||||
"so upstream connection is closed too");
|
||||
"kevent() reported that client closed prematurely "
|
||||
"connection, so upstream connection is closed too");
|
||||
ngx_http_upstream_finalize_request(r, u,
|
||||
NGX_HTTP_CLIENT_CLOSED_REQUEST);
|
||||
return;
|
||||
@ -374,6 +387,7 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
|
||||
}
|
||||
|
||||
ev->eof = 1;
|
||||
c->closed = 1;
|
||||
|
||||
if (n == -1) {
|
||||
if (err == NGX_EAGAIN) {
|
||||
@ -924,6 +938,8 @@ ngx_http_upstream_process_header(ngx_event_t *rev)
|
||||
}
|
||||
}
|
||||
|
||||
r->headers_out.status_line.len = 0;
|
||||
|
||||
ngx_http_internal_redirect(r,
|
||||
&r->upstream->headers_in.x_accel_redirect->value,
|
||||
NULL);
|
||||
@ -1155,9 +1171,33 @@ ngx_http_upstream_process_body(ngx_event_t *ev)
|
||||
|
||||
if (ev->timedout) {
|
||||
if (ev->write) {
|
||||
p->downstream_error = 1;
|
||||
ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
|
||||
"client timed out");
|
||||
if (ev->delayed) {
|
||||
|
||||
ev->timedout = 0;
|
||||
ev->delayed = 0;
|
||||
|
||||
if (!ev->ready) {
|
||||
ngx_add_timer(ev, p->send_timeout);
|
||||
|
||||
if (ngx_handle_write_event(ev, p->send_lowat) == NGX_ERROR)
|
||||
{
|
||||
ngx_http_upstream_finalize_request(r, u, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_event_pipe(p, ev->write) == NGX_ABORT) {
|
||||
ngx_http_upstream_finalize_request(r, u, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
p->downstream_error = 1;
|
||||
ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
|
||||
"client timed out");
|
||||
}
|
||||
|
||||
} else {
|
||||
p->upstream_error = 1;
|
||||
@ -1166,6 +1206,17 @@ ngx_http_upstream_process_body(ngx_event_t *ev)
|
||||
}
|
||||
|
||||
} else {
|
||||
if (ev->write && ev->delayed) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
"http downstream delayed");
|
||||
|
||||
if (ngx_handle_write_event(ev, p->send_lowat) == NGX_ERROR) {
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_event_pipe(p, ev->write) == NGX_ABORT) {
|
||||
ngx_http_upstream_finalize_request(r, u, 0);
|
||||
return;
|
||||
@ -1281,6 +1332,7 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
|
||||
}
|
||||
|
||||
if (r->connection->write->eof) {
|
||||
r->connection->closed = 1;
|
||||
ngx_http_upstream_finalize_request(r, u,
|
||||
NGX_HTTP_CLIENT_CLOSED_REQUEST);
|
||||
return;
|
||||
@ -1431,6 +1483,24 @@ ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h,
|
||||
ngx_uint_t offset)
|
||||
{
|
||||
ngx_int_t n;
|
||||
|
||||
r->upstream->headers_in.x_accel_limit_rate = h;
|
||||
|
||||
n = ngx_atoi(h->value.data, h->value.len);
|
||||
|
||||
if (n != NGX_ERROR) {
|
||||
r->limit_rate = (size_t) n;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
|
||||
ngx_uint_t offset)
|
||||
|
@ -48,6 +48,7 @@ typedef struct {
|
||||
ngx_msec_t connect_timeout;
|
||||
ngx_msec_t send_timeout;
|
||||
ngx_msec_t read_timeout;
|
||||
ngx_msec_t timeout;
|
||||
|
||||
size_t send_lowat;
|
||||
size_t header_buffer_size;
|
||||
@ -103,6 +104,7 @@ typedef struct {
|
||||
ngx_table_elt_t *etag;
|
||||
ngx_table_elt_t *x_accel_expires;
|
||||
ngx_table_elt_t *x_accel_redirect;
|
||||
ngx_table_elt_t *x_accel_limit_rate;
|
||||
|
||||
ngx_table_elt_t *content_type;
|
||||
ngx_table_elt_t *content_length;
|
||||
@ -120,8 +122,6 @@ typedef struct {
|
||||
|
||||
|
||||
struct ngx_http_upstream_s {
|
||||
ngx_http_request_t *request;
|
||||
|
||||
ngx_peer_connection_t peer;
|
||||
|
||||
ngx_event_pipe_t pipe;
|
||||
@ -146,6 +146,8 @@ struct ngx_http_upstream_s {
|
||||
ngx_int_t (*rewrite_redirect)(ngx_http_request_t *r,
|
||||
ngx_table_elt_t *h, size_t prefix);
|
||||
|
||||
ngx_msec_t timeout;
|
||||
|
||||
ngx_uint_t method;
|
||||
|
||||
ngx_http_log_handler_pt saved_log_handler;
|
||||
|
@ -706,7 +706,9 @@ ngx_http_variables_init_vars(ngx_conf_t *cf)
|
||||
{
|
||||
v[i].handler = av[n].handler;
|
||||
v[i].data = av[n].data;
|
||||
v[i].flags = av[n].flags | NGX_HTTP_VAR_INDEXED;
|
||||
|
||||
av[n].flags |= NGX_HTTP_VAR_INDEXED;
|
||||
v[i].flags = av[n].flags;
|
||||
|
||||
goto next;
|
||||
}
|
||||
|
@ -47,6 +47,12 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
ngx_connection_t *c;
|
||||
ngx_http_core_loc_conf_t *clcf;
|
||||
|
||||
c = r->connection;
|
||||
|
||||
if (c->closed) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
size = 0;
|
||||
flush = 0;
|
||||
last = 0;
|
||||
@ -151,8 +157,6 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
|
||||
*ll = NULL;
|
||||
|
||||
c = r->connection;
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
"http write filter: l:%d f:%d s:%O", last, flush, size);
|
||||
|
||||
@ -197,19 +201,20 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
|
||||
sent = c->sent;
|
||||
|
||||
chain = c->send_chain(c, r->out, clcf->limit_rate);
|
||||
chain = c->send_chain(c, r->out, r->limit_rate);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
"http write filter %p", chain);
|
||||
|
||||
if (clcf->limit_rate) {
|
||||
if (r->limit_rate) {
|
||||
sent = c->sent - sent;
|
||||
c->write->delayed = 1;
|
||||
ngx_add_timer(r->connection->write,
|
||||
(ngx_msec_t) (sent * 1000 / clcf->limit_rate));
|
||||
(ngx_msec_t) (sent * 1000 / r->limit_rate));
|
||||
}
|
||||
|
||||
if (chain == NGX_CHAIN_ERROR) {
|
||||
c->closed = 1;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,12 @@ typedef struct {
|
||||
|
||||
ngx_uint_t protocol;
|
||||
|
||||
ngx_buf_t *pop3_capability;
|
||||
ngx_buf_t *imap_capability;
|
||||
|
||||
ngx_array_t pop3_capabilities;
|
||||
ngx_array_t imap_capabilities;
|
||||
|
||||
/* server ctx */
|
||||
ngx_imap_conf_ctx_t *ctx;
|
||||
} ngx_imap_core_srv_conf_t;
|
||||
@ -51,11 +57,20 @@ typedef struct {
|
||||
|
||||
|
||||
typedef enum {
|
||||
ngx_pop3_start = 0,
|
||||
ngx_pop3_user
|
||||
ngx_imap_start = 0,
|
||||
ngx_imap_login,
|
||||
ngx_imap_user,
|
||||
ngx_imap_passwd,
|
||||
} ngx_imap_state_e;
|
||||
|
||||
|
||||
typedef enum {
|
||||
ngx_pop3_start = 0,
|
||||
ngx_pop3_user,
|
||||
ngx_pop3_passwd
|
||||
} ngx_po3_state_e;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_peer_connection_t upstream;
|
||||
ngx_buf_t *buffer;
|
||||
@ -68,6 +83,7 @@ typedef struct {
|
||||
ngx_connection_t *connection;
|
||||
|
||||
ngx_buf_t *buffer;
|
||||
ngx_str_t out;
|
||||
|
||||
void **ctx;
|
||||
void **main_conf;
|
||||
@ -75,39 +91,55 @@ typedef struct {
|
||||
|
||||
ngx_imap_proxy_ctx_t *proxy;
|
||||
|
||||
ngx_imap_state_e imap_state;
|
||||
ngx_uint_t imap_state;
|
||||
|
||||
unsigned protocol:1;
|
||||
unsigned quoted:1;
|
||||
|
||||
ngx_str_t login;
|
||||
ngx_str_t passwd;
|
||||
|
||||
ngx_str_t tag;
|
||||
|
||||
ngx_uint_t command;
|
||||
ngx_array_t args;
|
||||
|
||||
ngx_uint_t login_attempt;
|
||||
|
||||
/* used to parse IMAP/POP3 command */
|
||||
|
||||
ngx_uint_t state;
|
||||
u_char *cmd_start;
|
||||
u_char *arg_start;
|
||||
u_char *arg_end;
|
||||
ngx_uint_t literal_len;
|
||||
} ngx_imap_session_t;
|
||||
|
||||
|
||||
#define NGX_POP3_USER 1
|
||||
#define NGX_POP3_PASS 2
|
||||
#define NGX_POP3_APOP 3
|
||||
#define NGX_POP3_STAT 4
|
||||
#define NGX_POP3_LIST 5
|
||||
#define NGX_POP3_RETR 6
|
||||
#define NGX_POP3_DELE 7
|
||||
#define NGX_POP3_NOOP 8
|
||||
#define NGX_POP3_RSET 9
|
||||
#define NGX_POP3_TOP 10
|
||||
#define NGX_POP3_UIDL 11
|
||||
#define NGX_POP3_QUIT 12
|
||||
#define NGX_POP3_CAPA 3
|
||||
#define NGX_POP3_QUIT 4
|
||||
#define NGX_POP3_NOOP 5
|
||||
#define NGX_POP3_APOP 6
|
||||
#define NGX_POP3_STAT 7
|
||||
#define NGX_POP3_LIST 8
|
||||
#define NGX_POP3_RETR 9
|
||||
#define NGX_POP3_DELE 10
|
||||
#define NGX_POP3_RSET 11
|
||||
#define NGX_POP3_TOP 12
|
||||
#define NGX_POP3_UIDL 13
|
||||
|
||||
|
||||
#define NGX_IMAP_PARSE_INVALID_COMMAND 10
|
||||
#define NGX_IMAP_LOGIN 1
|
||||
#define NGX_IMAP_LOGOUT 2
|
||||
#define NGX_IMAP_CAPABILITY 3
|
||||
#define NGX_IMAP_NOOP 4
|
||||
|
||||
#define NGX_IMAP_NEXT 5
|
||||
|
||||
|
||||
#define NGX_IMAP_PARSE_INVALID_COMMAND 20
|
||||
|
||||
|
||||
#define NGX_IMAP_PROXY_INVALID 10
|
||||
@ -135,9 +167,12 @@ typedef struct {
|
||||
|
||||
|
||||
void ngx_imap_init_connection(ngx_connection_t *c);
|
||||
void ngx_imap_auth_state(ngx_event_t *rev);
|
||||
void ngx_pop3_auth_state(ngx_event_t *rev);
|
||||
void ngx_imap_close_connection(ngx_connection_t *c);
|
||||
void ngx_imap_session_internal_server_error(ngx_imap_session_t *s);
|
||||
|
||||
ngx_int_t ngx_imap_parse_command(ngx_imap_session_t *s);
|
||||
ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s);
|
||||
|
||||
|
||||
|
@ -12,24 +12,54 @@
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_peers_t *peers;
|
||||
ngx_peers_t *peers;
|
||||
|
||||
ngx_msec_t timeout;
|
||||
ngx_msec_t timeout;
|
||||
|
||||
ngx_str_t host_header;
|
||||
ngx_str_t uri;
|
||||
ngx_str_t host_header;
|
||||
ngx_str_t uri;
|
||||
} ngx_imap_auth_http_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_buf_t *request;
|
||||
ngx_buf_t *response;
|
||||
ngx_peer_connection_t peer;
|
||||
} ngx_imap_auth_http_ctx_t;
|
||||
typedef struct ngx_imap_auth_http_ctx_s ngx_imap_auth_http_ctx_t;
|
||||
|
||||
typedef void (*ngx_imap_auth_http_handler_pt)(ngx_imap_session_t *s,
|
||||
ngx_imap_auth_http_ctx_t *ctx);
|
||||
|
||||
struct ngx_imap_auth_http_ctx_s {
|
||||
ngx_buf_t *request;
|
||||
ngx_buf_t *response;
|
||||
ngx_peer_connection_t peer;
|
||||
|
||||
ngx_imap_auth_http_handler_pt handler;
|
||||
|
||||
ngx_uint_t state;
|
||||
ngx_uint_t hash; /* no needed ? */
|
||||
|
||||
u_char *header_name_start;
|
||||
u_char *header_name_end;
|
||||
u_char *header_start;
|
||||
u_char *header_end;
|
||||
|
||||
ngx_str_t addr;
|
||||
ngx_str_t port;
|
||||
ngx_str_t err;
|
||||
|
||||
ngx_msec_t sleep;
|
||||
|
||||
ngx_peers_t *peers;
|
||||
};
|
||||
|
||||
|
||||
static void ngx_imap_auth_http_write_handler(ngx_event_t *wev);
|
||||
static void ngx_imap_auth_http_read_handler(ngx_event_t *rev);
|
||||
static void ngx_imap_auth_http_ignore_status_line(ngx_imap_session_t *s,
|
||||
ngx_imap_auth_http_ctx_t *ctx);
|
||||
static void ngx_imap_auth_http_process_headers(ngx_imap_session_t *s,
|
||||
ngx_imap_auth_http_ctx_t *ctx);
|
||||
static void ngx_imap_auth_sleep_handler(ngx_event_t *rev);
|
||||
static ngx_int_t ngx_imap_auth_http_parse_header_line(ngx_imap_session_t *s,
|
||||
ngx_imap_auth_http_ctx_t *ctx);
|
||||
static void ngx_imap_auth_http_block_read(ngx_event_t *rev);
|
||||
static void ngx_imap_auth_http_dummy_handler(ngx_event_t *ev);
|
||||
static ngx_buf_t *ngx_imap_auth_http_create_request(ngx_imap_session_t *s,
|
||||
@ -124,6 +154,8 @@ ngx_imap_auth_http_init(ngx_imap_session_t *s)
|
||||
ctx->peer.connection->read->handler = ngx_imap_auth_http_read_handler;
|
||||
ctx->peer.connection->write->handler = ngx_imap_auth_http_write_handler;
|
||||
|
||||
ctx->handler = ngx_imap_auth_http_ignore_status_line;
|
||||
|
||||
if (rc == NGX_OK) {
|
||||
ngx_imap_auth_http_write_handler(ctx->peer.connection->write);
|
||||
return;
|
||||
@ -194,7 +226,6 @@ static void
|
||||
ngx_imap_auth_http_read_handler(ngx_event_t *rev)
|
||||
{
|
||||
ssize_t n, size;
|
||||
ngx_peers_t *peers;
|
||||
ngx_connection_t *c;
|
||||
ngx_imap_session_t *s;
|
||||
ngx_imap_auth_http_ctx_t *ctx;
|
||||
@ -224,24 +255,604 @@ ngx_imap_auth_http_read_handler(ngx_event_t *rev)
|
||||
}
|
||||
}
|
||||
|
||||
size = ctx->response->last - ctx->response->pos;
|
||||
size = ctx->response->end - ctx->response->last;
|
||||
|
||||
n = ngx_recv(c, ctx->response->pos, size);
|
||||
|
||||
if (n == NGX_ERROR || n == 0) {
|
||||
ngx_close_connection(ctx->peer.connection);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
if (n > 0) {
|
||||
ctx->response->last += n;
|
||||
|
||||
ctx->handler(s, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (n == NGX_AGAIN) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_close_connection(ctx->peer.connection);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_imap_auth_http_ignore_status_line(ngx_imap_session_t *s,
|
||||
ngx_imap_auth_http_ctx_t *ctx)
|
||||
{
|
||||
u_char *p, ch;
|
||||
enum {
|
||||
sw_start = 0,
|
||||
sw_H,
|
||||
sw_HT,
|
||||
sw_HTT,
|
||||
sw_HTTP,
|
||||
sw_skip,
|
||||
sw_almost_done
|
||||
} state;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
|
||||
"imap auth http process status line");
|
||||
|
||||
state = ctx->state;
|
||||
|
||||
for (p = ctx->response->pos; p < ctx->response->last; p++) {
|
||||
ch = *p;
|
||||
|
||||
switch (state) {
|
||||
|
||||
/* "HTTP/" */
|
||||
case sw_start:
|
||||
if (ch == 'H') {
|
||||
state = sw_H;
|
||||
break;
|
||||
}
|
||||
goto next;
|
||||
|
||||
case sw_H:
|
||||
if (ch == 'T') {
|
||||
state = sw_HT;
|
||||
break;
|
||||
}
|
||||
goto next;
|
||||
|
||||
case sw_HT:
|
||||
if (ch == 'T') {
|
||||
state = sw_HTT;
|
||||
break;
|
||||
}
|
||||
goto next;
|
||||
|
||||
case sw_HTT:
|
||||
if (ch == 'P') {
|
||||
state = sw_HTTP;
|
||||
break;
|
||||
}
|
||||
goto next;
|
||||
|
||||
case sw_HTTP:
|
||||
if (ch == '/') {
|
||||
state = sw_skip;
|
||||
break;
|
||||
}
|
||||
goto next;
|
||||
|
||||
/* any text until end of line */
|
||||
case sw_skip:
|
||||
switch (ch) {
|
||||
case CR:
|
||||
state = sw_almost_done;
|
||||
|
||||
break;
|
||||
case LF:
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
|
||||
/* end of status line */
|
||||
case sw_almost_done:
|
||||
if (ch == LF) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
||||
"auth http server sent invalid response");
|
||||
ngx_close_connection(ctx->peer.connection);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->response->pos = p;
|
||||
ctx->state = state;
|
||||
|
||||
return;
|
||||
|
||||
next:
|
||||
|
||||
p = ctx->response->start - 1;
|
||||
|
||||
done:
|
||||
|
||||
ctx->response->pos = p + 1;
|
||||
ctx->state = 0;
|
||||
ctx->handler = ngx_imap_auth_http_process_headers;
|
||||
ctx->handler(s, ctx);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_imap_auth_http_process_headers(ngx_imap_session_t *s,
|
||||
ngx_imap_auth_http_ctx_t *ctx)
|
||||
{
|
||||
u_char *p;
|
||||
size_t len, size;
|
||||
ngx_int_t rc, port, n;
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
peers = NULL;
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
|
||||
"imap auth http process headers");
|
||||
|
||||
ngx_imap_proxy_init(s, peers);
|
||||
for ( ;; ) {
|
||||
rc = ngx_imap_auth_http_parse_header_line(s, ctx);
|
||||
|
||||
if (rc == NGX_OK) {
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
{
|
||||
ngx_str_t key, value;
|
||||
|
||||
key.len = ctx->header_name_end - ctx->header_name_start;
|
||||
key.data = ctx->header_name_start;
|
||||
value.len = ctx->header_end - ctx->header_start;
|
||||
value.data = ctx->header_start;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
|
||||
"auth http header: \"%V: %V\"",
|
||||
&key, &value);
|
||||
}
|
||||
#endif
|
||||
|
||||
len = ctx->header_name_end - ctx->header_name_start;
|
||||
|
||||
if (len == sizeof("Auth-Status") - 1
|
||||
&& ngx_strncasecmp(ctx->header_name_start, "Auth-Status",
|
||||
sizeof("Auth-Status") - 1) == 0)
|
||||
{
|
||||
len = ctx->header_end - ctx->header_start;
|
||||
|
||||
if (len == 2
|
||||
&& ctx->header_start[0] == 'O'
|
||||
&& ctx->header_start[1] == 'K')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
|
||||
size = sizeof("-ERR") - 1 + len + sizeof(CRLF) - 1;
|
||||
|
||||
} else {
|
||||
size = s->tag.len + sizeof("NO") - 1 + len
|
||||
+ sizeof(CRLF) - 1;
|
||||
}
|
||||
|
||||
p = ngx_pcalloc(s->connection->pool, size);
|
||||
if (p == NULL) {
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->err.data = p;
|
||||
|
||||
if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
|
||||
*p++ = '-'; *p++ = 'E'; *p++ = 'R'; *p++ = 'R';
|
||||
|
||||
} else {
|
||||
p = ngx_cpymem(p, s->tag.data, s->tag.len);
|
||||
*p++ = 'N'; *p++ = 'O';
|
||||
}
|
||||
|
||||
*p++ = ' ';
|
||||
p = ngx_cpymem(p, ctx->header_start, len);
|
||||
*p++ = CR; *p++ = LF;
|
||||
|
||||
ctx->err.len = p - ctx->err.data;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len == sizeof("Auth-Server") - 1
|
||||
&& ngx_strncasecmp(ctx->header_name_start, "Auth-Server",
|
||||
sizeof("Auth-Server") - 1) == 0)
|
||||
{
|
||||
ctx->addr.len = ctx->header_end - ctx->header_start;
|
||||
ctx->addr.data = ctx->header_start;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len == sizeof("Auth-Port") - 1
|
||||
&& ngx_strncasecmp(ctx->header_name_start, "Auth-Port",
|
||||
sizeof("Auth-Port") - 1) == 0)
|
||||
{
|
||||
ctx->port.len = ctx->header_end - ctx->header_start;
|
||||
ctx->port.data = ctx->header_start;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len == sizeof("Auth-User") - 1
|
||||
&& ngx_strncasecmp(ctx->header_name_start, "Auth-User",
|
||||
sizeof("Auth-User") - 1) == 0)
|
||||
{
|
||||
s->login.len = ctx->header_end - ctx->header_start;
|
||||
s->login.data = ctx->header_start;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len == sizeof("Auth-Wait") - 1
|
||||
&& ngx_strncasecmp(ctx->header_name_start, "Auth-Wait",
|
||||
sizeof("Auth-Wait") - 1) == 0)
|
||||
{
|
||||
n = ngx_atoi(ctx->header_start,
|
||||
ctx->header_end - ctx->header_start);
|
||||
|
||||
if (n != NGX_ERROR) {
|
||||
ctx->sleep = n;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ignore other headers */
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
|
||||
"auth http header done");
|
||||
|
||||
ngx_close_connection(ctx->peer.connection);
|
||||
|
||||
if (ctx->err.len) {
|
||||
(void) ngx_send(s->connection, ctx->err.data, ctx->err.len);
|
||||
|
||||
if (ctx->sleep == 0) {
|
||||
ngx_imap_close_connection(s->connection);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_add_timer(s->connection->read, ctx->sleep * 1000);
|
||||
|
||||
s->connection->read->handler = ngx_imap_auth_sleep_handler;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->addr.len == 0 || ctx->port.len == 0) {
|
||||
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
||||
"auth http server did not send server or port");
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->peers = ngx_pcalloc(s->connection->pool, sizeof(ngx_peers_t));
|
||||
if (ctx->peers == NULL) {
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in));
|
||||
if (sin == NULL) {
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
sin->sin_family = AF_INET;
|
||||
|
||||
port = ngx_atoi(ctx->port.data, ctx->port.len);
|
||||
if (port == NGX_ERROR || port < 1 || port > 65536) {
|
||||
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
||||
"auth http server sent invalid server "
|
||||
"port:\"%V\"", &ctx->port);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
sin->sin_port = htons((in_port_t) port);
|
||||
|
||||
ctx->addr.data[ctx->addr.len] = '\0';
|
||||
sin->sin_addr.s_addr = inet_addr((char *) ctx->addr.data);
|
||||
if (sin->sin_addr.s_addr == INADDR_NONE) {
|
||||
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
||||
"auth http server sent invalid server "
|
||||
"address:\"%V\"", &ctx->addr);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->peers->number = 1;
|
||||
|
||||
ctx->peers->peer[0].sockaddr = (struct sockaddr *) sin;
|
||||
ctx->peers->peer[0].socklen = sizeof(struct sockaddr_in);
|
||||
|
||||
len = ctx->addr.len + 1 + ctx->port.len;
|
||||
|
||||
ctx->peers->peer[0].name.len = len;
|
||||
|
||||
ctx->peers->peer[0].name.data = ngx_palloc(s->connection->pool,
|
||||
len);
|
||||
if (ctx->peers->peer[0].name.data == NULL) {
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
len = ctx->addr.len;
|
||||
|
||||
ngx_memcpy(ctx->peers->peer[0].name.data, ctx->addr.data, len);
|
||||
|
||||
ctx->peers->peer[0].name.data[len++] = ':';
|
||||
|
||||
ngx_memcpy(ctx->peers->peer[0].name.data + len,
|
||||
ctx->port.data, ctx->port.len);
|
||||
|
||||
ctx->peers->peer[0].uri_separator = "";
|
||||
|
||||
ngx_imap_proxy_init(s, ctx->peers);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* rc == NGX_ERROR */
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
||||
"auth http server sent invalid header in response");
|
||||
ngx_close_connection(ctx->peer.connection);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_imap_auth_sleep_handler(ngx_event_t *rev)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
ngx_imap_session_t *s;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap auth sleep handler");
|
||||
|
||||
c = rev->data;
|
||||
s = c->data;
|
||||
|
||||
if (rev->timedout) {
|
||||
|
||||
rev->timedout = 0;
|
||||
|
||||
if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
|
||||
s->imap_state = ngx_pop3_start;
|
||||
s->connection->read->handler = ngx_pop3_auth_state;
|
||||
|
||||
} else {
|
||||
s->imap_state = ngx_imap_start;
|
||||
s->connection->read->handler = ngx_imap_auth_state;
|
||||
}
|
||||
|
||||
if (rev->ready) {
|
||||
s->connection->read->handler(rev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
|
||||
ngx_imap_close_connection(s->connection);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (rev->active) {
|
||||
if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
|
||||
ngx_imap_close_connection(s->connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_imap_auth_http_parse_header_line(ngx_imap_session_t *s,
|
||||
ngx_imap_auth_http_ctx_t *ctx)
|
||||
{
|
||||
u_char c, ch, *p;
|
||||
ngx_uint_t hash;
|
||||
enum {
|
||||
sw_start = 0,
|
||||
sw_name,
|
||||
sw_space_before_value,
|
||||
sw_value,
|
||||
sw_space_after_value,
|
||||
sw_almost_done,
|
||||
sw_header_almost_done
|
||||
} state;
|
||||
|
||||
state = ctx->state;
|
||||
hash = ctx->hash;
|
||||
|
||||
for (p = ctx->response->pos; p < ctx->response->last; p++) {
|
||||
ch = *p;
|
||||
|
||||
switch (state) {
|
||||
|
||||
/* first char */
|
||||
case sw_start:
|
||||
|
||||
switch (ch) {
|
||||
case CR:
|
||||
ctx->header_end = p;
|
||||
state = sw_header_almost_done;
|
||||
break;
|
||||
case LF:
|
||||
ctx->header_end = p;
|
||||
goto header_done;
|
||||
default:
|
||||
state = sw_name;
|
||||
ctx->header_name_start = p;
|
||||
|
||||
c = (u_char) (ch | 0x20);
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
hash = c;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
hash = ch;
|
||||
break;
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
/* header name */
|
||||
case sw_name:
|
||||
c = (u_char) (ch | 0x20);
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
hash += c;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch == ':') {
|
||||
ctx->header_name_end = p;
|
||||
state = sw_space_before_value;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch == '-') {
|
||||
hash += ch;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
hash += ch;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch == CR) {
|
||||
ctx->header_name_end = p;
|
||||
ctx->header_start = p;
|
||||
ctx->header_end = p;
|
||||
state = sw_almost_done;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch == LF) {
|
||||
ctx->header_name_end = p;
|
||||
ctx->header_start = p;
|
||||
ctx->header_end = p;
|
||||
goto done;
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
|
||||
/* space* before header value */
|
||||
case sw_space_before_value:
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
break;
|
||||
case CR:
|
||||
ctx->header_start = p;
|
||||
ctx->header_end = p;
|
||||
state = sw_almost_done;
|
||||
break;
|
||||
case LF:
|
||||
ctx->header_start = p;
|
||||
ctx->header_end = p;
|
||||
goto done;
|
||||
default:
|
||||
ctx->header_start = p;
|
||||
state = sw_value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* header value */
|
||||
case sw_value:
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
ctx->header_end = p;
|
||||
state = sw_space_after_value;
|
||||
break;
|
||||
case CR:
|
||||
ctx->header_end = p;
|
||||
state = sw_almost_done;
|
||||
break;
|
||||
case LF:
|
||||
ctx->header_end = p;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
|
||||
/* space* before end of header line */
|
||||
case sw_space_after_value:
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
break;
|
||||
case CR:
|
||||
state = sw_almost_done;
|
||||
break;
|
||||
case LF:
|
||||
goto done;
|
||||
default:
|
||||
state = sw_value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* end of header line */
|
||||
case sw_almost_done:
|
||||
switch (ch) {
|
||||
case LF:
|
||||
goto done;
|
||||
default:
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* end of header */
|
||||
case sw_header_almost_done:
|
||||
switch (ch) {
|
||||
case LF:
|
||||
goto header_done;
|
||||
default:
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx->response->pos = p;
|
||||
ctx->state = state;
|
||||
ctx->hash = hash;
|
||||
|
||||
return NGX_AGAIN;
|
||||
|
||||
done:
|
||||
|
||||
ctx->response->pos = p + 1;
|
||||
ctx->state = sw_start;
|
||||
ctx->hash = hash;
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
header_done:
|
||||
|
||||
ctx->response->pos = p + 1;
|
||||
ctx->state = sw_start;
|
||||
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
|
||||
@ -288,6 +899,8 @@ ngx_imap_auth_http_create_request(ngx_imap_session_t *s,
|
||||
+ sizeof("Auth-User: ") - 1 + s->login.len + sizeof(CRLF) - 1
|
||||
+ sizeof("Auth-Pass: ") - 1 + s->passwd.len + sizeof(CRLF) - 1
|
||||
+ sizeof("Auth-Protocol: imap" CRLF) - 1
|
||||
+ sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN
|
||||
+ sizeof(CRLF) - 1
|
||||
+ sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
|
||||
+ sizeof(CRLF) - 1
|
||||
+ sizeof(CRLF) - 1;
|
||||
@ -324,6 +937,9 @@ ngx_imap_auth_http_create_request(ngx_imap_session_t *s,
|
||||
sizeof("imap") - 1);
|
||||
*b->last++ = CR; *b->last++ = LF;
|
||||
|
||||
b->last = ngx_sprintf(b->last, "Auth-Login-Attempt: %ui" CRLF,
|
||||
s->login_attempt);
|
||||
|
||||
b->last = ngx_cpymem(b->last, "Client-IP: ", sizeof("Client-IP: ") - 1);
|
||||
b->last = ngx_cpymem(b->last, s->connection->addr_text.data,
|
||||
s->connection->addr_text.len);
|
||||
@ -338,7 +954,7 @@ ngx_imap_auth_http_create_request(ngx_imap_session_t *s,
|
||||
|
||||
l.len = b->last - b->pos;
|
||||
l.data = b->pos;
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, s->connection->log, 0,
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
|
||||
"imap auth http header:\n\"%V\"", &l);
|
||||
}
|
||||
#endif
|
||||
@ -440,7 +1056,7 @@ ngx_imap_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
}
|
||||
|
||||
for (i = 0; i < ahcf->peers->number; i++) {
|
||||
ahcf->peers->peer[i].uri_separator = ":";
|
||||
ahcf->peers->peer[i].uri_separator = "";
|
||||
}
|
||||
|
||||
ahcf->host_header = inet_upstream.host_header;
|
||||
|
@ -18,6 +18,8 @@ static char *ngx_imap_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_imap_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_imap_core_capability(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
|
||||
static ngx_conf_enum_t ngx_imap_core_procotol[] = {
|
||||
@ -27,6 +29,22 @@ static ngx_conf_enum_t ngx_imap_core_procotol[] = {
|
||||
};
|
||||
|
||||
|
||||
static ngx_str_t ngx_pop3_default_capabilities[] = {
|
||||
ngx_string("TOP"),
|
||||
ngx_string("USER"),
|
||||
ngx_string("UIDL"),
|
||||
ngx_null_string
|
||||
};
|
||||
|
||||
|
||||
static ngx_str_t ngx_imap_default_capabilities[] = {
|
||||
ngx_string("IMAP4"),
|
||||
ngx_string("IMAP4rev1"),
|
||||
ngx_string("UIDPLUS"),
|
||||
ngx_null_string
|
||||
};
|
||||
|
||||
|
||||
static ngx_command_t ngx_imap_core_commands[] = {
|
||||
|
||||
{ ngx_string("server"),
|
||||
@ -71,6 +89,20 @@ static ngx_command_t ngx_imap_core_commands[] = {
|
||||
offsetof(ngx_imap_core_srv_conf_t, timeout),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("pop3_capabilities"),
|
||||
NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_1MORE,
|
||||
ngx_imap_core_capability,
|
||||
NGX_IMAP_SRV_CONF_OFFSET,
|
||||
offsetof(ngx_imap_core_srv_conf_t, pop3_capabilities),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("imap_capabilities"),
|
||||
NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_1MORE,
|
||||
ngx_imap_core_capability,
|
||||
NGX_IMAP_SRV_CONF_OFFSET,
|
||||
offsetof(ngx_imap_core_srv_conf_t, imap_capabilities),
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
@ -121,7 +153,7 @@ ngx_imap_core_create_srv_conf(ngx_conf_t *cf)
|
||||
|
||||
cscf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_core_srv_conf_t));
|
||||
if (cscf == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cscf->imap_client_buffer_size = NGX_CONF_UNSET_SIZE;
|
||||
@ -129,6 +161,18 @@ ngx_imap_core_create_srv_conf(ngx_conf_t *cf)
|
||||
cscf->timeout = NGX_CONF_UNSET_MSEC;
|
||||
cscf->protocol = NGX_CONF_UNSET_UINT;
|
||||
|
||||
if (ngx_array_init(&cscf->pop3_capabilities, cf->pool, 4, sizeof(ngx_str_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&cscf->imap_capabilities, cf->pool, 4, sizeof(ngx_str_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cscf;
|
||||
}
|
||||
|
||||
@ -139,6 +183,11 @@ ngx_imap_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
ngx_imap_core_srv_conf_t *prev = parent;
|
||||
ngx_imap_core_srv_conf_t *conf = child;
|
||||
|
||||
size_t size;
|
||||
ngx_buf_t *b;
|
||||
ngx_str_t *c, *d;
|
||||
ngx_uint_t i;
|
||||
|
||||
ngx_conf_merge_size_value(conf->imap_client_buffer_size,
|
||||
prev->imap_client_buffer_size,
|
||||
(size_t) ngx_pagesize);
|
||||
@ -148,6 +197,88 @@ ngx_imap_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
ngx_conf_merge_unsigned_value(conf->protocol, prev->protocol,
|
||||
NGX_IMAP_IMAP_PROTOCOL);
|
||||
|
||||
|
||||
if (conf->pop3_capabilities.nelts == 0) {
|
||||
conf->pop3_capabilities = prev->pop3_capabilities;
|
||||
}
|
||||
|
||||
if (conf->pop3_capabilities.nelts == 0) {
|
||||
|
||||
for (d = ngx_pop3_default_capabilities; d->len; d++) {
|
||||
c = ngx_array_push(&conf->pop3_capabilities);
|
||||
if (c == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
*c = *d;
|
||||
}
|
||||
}
|
||||
|
||||
size = sizeof("+OK Capability list follows" CRLF) - 1
|
||||
+ sizeof("." CRLF) - 1;
|
||||
|
||||
c = conf->pop3_capabilities.elts;
|
||||
for (i = 0; i < conf->pop3_capabilities.nelts; i++) {
|
||||
size += c[i].len + sizeof(CRLF) - 1;
|
||||
}
|
||||
|
||||
b = ngx_create_temp_buf(cf->pool, size);
|
||||
if (b == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
b->last = ngx_cpymem(b->last, "+OK Capability list follows" CRLF,
|
||||
sizeof("+OK Capability list follows" CRLF) - 1);
|
||||
|
||||
for (i = 0; i < conf->pop3_capabilities.nelts; i++) {
|
||||
b->last = ngx_cpymem(b->last, c[i].data, c[i].len);
|
||||
*b->last++ = CR; *b->last++ = LF;
|
||||
}
|
||||
|
||||
*b->last++ = '.'; *b->last++ = CR; *b->last++ = LF;
|
||||
|
||||
conf->pop3_capability = b;
|
||||
|
||||
|
||||
if (conf->imap_capabilities.nelts == 0) {
|
||||
conf->imap_capabilities = prev->imap_capabilities;
|
||||
}
|
||||
|
||||
if (conf->imap_capabilities.nelts == 0) {
|
||||
|
||||
for (d = ngx_imap_default_capabilities; d->len; d++) {
|
||||
c = ngx_array_push(&conf->imap_capabilities);
|
||||
if (c == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
*c = *d;
|
||||
}
|
||||
}
|
||||
|
||||
size = sizeof("* CAPABILITY") - 1 + sizeof(CRLF) - 1;
|
||||
|
||||
c = conf->imap_capabilities.elts;
|
||||
for (i = 0; i < conf->imap_capabilities.nelts; i++) {
|
||||
size += 1 + c[i].len;
|
||||
}
|
||||
|
||||
b = ngx_create_temp_buf(cf->pool, size);
|
||||
if (b == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
b->last = ngx_cpymem(b->last, "* CAPABILITY", sizeof("* CAPABILITY") - 1);
|
||||
|
||||
for (i = 0; i < conf->imap_capabilities.nelts; i++) {
|
||||
*b->last++ = ' ';
|
||||
b->last = ngx_cpymem(b->last, c[i].data, c[i].len);
|
||||
}
|
||||
|
||||
*b->last++ = CR; *b->last++ = LF;
|
||||
|
||||
conf->imap_capability = b;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
@ -296,3 +427,29 @@ ngx_imap_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_imap_core_capability(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
char *p = conf;
|
||||
|
||||
ngx_str_t *c, *value;
|
||||
ngx_uint_t i;
|
||||
ngx_array_t *a;
|
||||
|
||||
a = (ngx_array_t *) (p + cmd->offset);
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
for (i = 1; i < cf->args->nelts; i++) {
|
||||
c = ngx_array_push(a);
|
||||
if (c == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
*c = value[i];
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
@ -8,20 +8,15 @@
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
#include <ngx_imap.h>
|
||||
#include <nginx.h>
|
||||
|
||||
|
||||
static void ngx_imap_init_session(ngx_event_t *rev);
|
||||
|
||||
static void ngx_pop3_auth_state(ngx_event_t *rev);
|
||||
static ngx_int_t ngx_pop3_read_command(ngx_imap_session_t *s);
|
||||
|
||||
static void ngx_imap_auth_state(ngx_event_t *rev);
|
||||
static ngx_int_t ngx_imap_read_command(ngx_imap_session_t *s);
|
||||
|
||||
|
||||
static ngx_str_t greetings[] = {
|
||||
ngx_string("+OK " NGINX_VER " ready" CRLF),
|
||||
ngx_string("* OK " NGINX_VER " ready" CRLF)
|
||||
ngx_string("+OK POP3 ready" CRLF),
|
||||
ngx_string("* OK IMAP ready" CRLF)
|
||||
};
|
||||
|
||||
static ngx_str_t internal_server_errors[] = {
|
||||
@ -32,6 +27,11 @@ static ngx_str_t internal_server_errors[] = {
|
||||
static u_char pop3_ok[] = "+OK" CRLF;
|
||||
static u_char pop3_invalid_command[] = "-ERR invalid command" CRLF;
|
||||
|
||||
static u_char imap_ok[] = "OK" CRLF;
|
||||
static u_char imap_next[] = "+ OK" CRLF;
|
||||
static u_char imap_bye[] = "* BYE" CRLF;
|
||||
static u_char imap_invalid_command[] = "BAD invalid command" CRLF;
|
||||
|
||||
|
||||
void
|
||||
ngx_imap_init_connection(ngx_connection_t *c)
|
||||
@ -87,7 +87,7 @@ ngx_imap_init_session(ngx_event_t *rev)
|
||||
|
||||
s = ngx_pcalloc(c->pool, sizeof(ngx_imap_session_t));
|
||||
if (s == NULL) {
|
||||
ngx_imap_close_connection(c);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ ngx_imap_init_session(ngx_event_t *rev)
|
||||
|
||||
s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_imap_max_module);
|
||||
if (s->ctx == NULL) {
|
||||
ngx_imap_close_connection(c);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ ngx_imap_init_session(ngx_event_t *rev)
|
||||
s->srv_conf = ctx->srv_conf;
|
||||
|
||||
if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) {
|
||||
ngx_imap_close_connection(c);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -115,16 +115,18 @@ ngx_imap_init_session(ngx_event_t *rev)
|
||||
|
||||
if (cscf->protocol == NGX_IMAP_POP3_PROTOCOL) {
|
||||
size = 128;
|
||||
s->imap_state = ngx_pop3_start;
|
||||
c->read->handler = ngx_pop3_auth_state;
|
||||
|
||||
} else {
|
||||
size = cscf->imap_client_buffer_size;
|
||||
s->imap_state = ngx_imap_start;
|
||||
c->read->handler = ngx_imap_auth_state;
|
||||
}
|
||||
|
||||
s->buffer = ngx_create_temp_buf(c->pool, size);
|
||||
if (s->buffer == NULL) {
|
||||
ngx_imap_close_connection(c);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -132,27 +134,194 @@ ngx_imap_init_session(ngx_event_t *rev)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
void
|
||||
ngx_imap_auth_state(ngx_event_t *rev)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
u_char *text, *last, *out, *p;
|
||||
ssize_t size, text_len, last_len;
|
||||
ngx_str_t *arg;
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t quit, tag;
|
||||
ngx_connection_t *c;
|
||||
ngx_imap_session_t *s;
|
||||
ngx_imap_core_srv_conf_t *cscf;
|
||||
|
||||
c = rev->data;
|
||||
s = c->data;
|
||||
|
||||
ngx_imap_close_connection(c);
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth state");
|
||||
|
||||
if (rev->timedout) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
|
||||
ngx_imap_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ngx_imap_read_command(s);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth: %i", rc);
|
||||
|
||||
if (rc == NGX_AGAIN || rc == NGX_ERROR) {
|
||||
return;
|
||||
}
|
||||
|
||||
quit = 0;
|
||||
tag = 1;
|
||||
|
||||
text = NULL;
|
||||
text_len = 0;
|
||||
|
||||
last = imap_ok;
|
||||
last_len = sizeof(imap_ok) - 1;
|
||||
|
||||
if (rc == NGX_OK) {
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth command: %i",
|
||||
s->command);
|
||||
|
||||
switch (s->command) {
|
||||
|
||||
case NGX_IMAP_LOGIN:
|
||||
if (s->args.nelts == 2) {
|
||||
|
||||
arg = s->args.elts;
|
||||
|
||||
s->login.len = arg[0].len;
|
||||
s->login.data = ngx_palloc(c->pool, s->login.len);
|
||||
if (s->login.data == NULL) {
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(s->login.data, arg[0].data, s->login.len);
|
||||
|
||||
s->passwd.len = arg[1].len;
|
||||
s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
|
||||
if (s->passwd.data == NULL) {
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_IMAP, c->log, 0,
|
||||
"imap login:\"%V\" passwd:\"%V\"",
|
||||
&s->login, &s->passwd);
|
||||
|
||||
s->args.nelts = 0;
|
||||
s->buffer->pos = s->buffer->start;
|
||||
s->buffer->last = s->buffer->start;
|
||||
|
||||
if (rev->timer_set) {
|
||||
ngx_del_timer(rev);
|
||||
}
|
||||
|
||||
s->login_attempt++;
|
||||
|
||||
ngx_imap_auth_http_init(s);
|
||||
|
||||
return;
|
||||
|
||||
} else {
|
||||
rc = NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NGX_IMAP_CAPABILITY:
|
||||
cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
|
||||
text = cscf->imap_capability->pos;
|
||||
text_len = cscf->imap_capability->last - cscf->imap_capability->pos;
|
||||
break;
|
||||
|
||||
case NGX_IMAP_LOGOUT:
|
||||
text = imap_bye;
|
||||
text_len = sizeof(imap_bye) - 1;
|
||||
quit = 1;
|
||||
break;
|
||||
|
||||
case NGX_IMAP_NOOP:
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (rc == NGX_IMAP_NEXT) {
|
||||
last = imap_next;
|
||||
last_len = sizeof(imap_next) - 1;
|
||||
tag = 0;
|
||||
}
|
||||
|
||||
if (rc == NGX_IMAP_PARSE_INVALID_COMMAND) {
|
||||
last = imap_invalid_command;
|
||||
last_len = sizeof(imap_invalid_command) - 1;
|
||||
}
|
||||
|
||||
if (tag) {
|
||||
if (s->out.len < text_len + s->tag.len + last_len) {
|
||||
|
||||
s->out.len = text_len + s->tag.len + last_len;
|
||||
s->out.data = ngx_palloc(c->pool, s->out.len);
|
||||
if (s->out.data == NULL) {
|
||||
ngx_imap_close_connection(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
out = s->out.data;
|
||||
p = out;
|
||||
|
||||
if (text) {
|
||||
p = ngx_cpymem(p, text, text_len);
|
||||
}
|
||||
p = ngx_cpymem(p, s->tag.data, s->tag.len);
|
||||
ngx_memcpy(p, last, last_len);
|
||||
|
||||
size = text_len + s->tag.len + last_len;
|
||||
|
||||
} else {
|
||||
out = last;
|
||||
size = last_len;
|
||||
}
|
||||
|
||||
if (ngx_send(c, out, size) < size) {
|
||||
/*
|
||||
* we treat the incomplete sending as NGX_ERROR
|
||||
* because it is very strange here
|
||||
*/
|
||||
ngx_imap_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == NGX_IMAP_NEXT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (quit) {
|
||||
ngx_imap_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
s->args.nelts = 0;
|
||||
s->buffer->pos = s->buffer->start;
|
||||
s->buffer->last = s->buffer->start;
|
||||
s->tag.len = 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
void
|
||||
ngx_pop3_auth_state(ngx_event_t *rev)
|
||||
{
|
||||
u_char *text;
|
||||
ssize_t size;
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t quit;
|
||||
ngx_str_t *arg;
|
||||
ngx_connection_t *c;
|
||||
ngx_imap_session_t *s;
|
||||
u_char *text;
|
||||
ssize_t size;
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t quit;
|
||||
ngx_str_t *arg;
|
||||
ngx_connection_t *c;
|
||||
ngx_imap_session_t *s;
|
||||
ngx_imap_core_srv_conf_t *cscf;
|
||||
|
||||
c = rev->data;
|
||||
s = c->data;
|
||||
@ -165,7 +334,7 @@ ngx_pop3_auth_state(ngx_event_t *rev)
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ngx_pop3_read_command(s);
|
||||
rc = ngx_imap_read_command(s);
|
||||
|
||||
if (rc == NGX_AGAIN || rc == NGX_ERROR) {
|
||||
return;
|
||||
@ -188,16 +357,16 @@ ngx_pop3_auth_state(ngx_event_t *rev)
|
||||
|
||||
arg = s->args.elts;
|
||||
s->login.len = arg[0].len;
|
||||
s->login.data = ngx_palloc(c->pool, s->login.len + 1);
|
||||
s->login.data = ngx_palloc(c->pool, s->login.len);
|
||||
if (s->login.data == NULL) {
|
||||
ngx_imap_close_connection(c);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_cpystrn(s->login.data, arg[0].data, s->login.len + 1);
|
||||
ngx_memcpy(s->login.data, arg[0].data, s->login.len);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
|
||||
"pop3 login: \"%s\"", s->login.data);
|
||||
"pop3 login: \"%V\"", &s->login);
|
||||
|
||||
} else {
|
||||
rc = NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
@ -205,10 +374,19 @@ ngx_pop3_auth_state(ngx_event_t *rev)
|
||||
|
||||
break;
|
||||
|
||||
case NGX_POP3_CAPA:
|
||||
cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
|
||||
text = cscf->pop3_capability->pos;
|
||||
size = cscf->pop3_capability->last - cscf->pop3_capability->pos;
|
||||
break;
|
||||
|
||||
case NGX_POP3_QUIT:
|
||||
quit = 1;
|
||||
break;
|
||||
|
||||
case NGX_POP3_NOOP:
|
||||
break;
|
||||
|
||||
default:
|
||||
s->imap_state = ngx_pop3_start;
|
||||
rc = NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
@ -227,20 +405,25 @@ ngx_pop3_auth_state(ngx_event_t *rev)
|
||||
|
||||
arg = s->args.elts;
|
||||
s->passwd.len = arg[0].len;
|
||||
s->passwd.data = ngx_palloc(c->pool, s->passwd.len + 1);
|
||||
s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
|
||||
if (s->passwd.data == NULL) {
|
||||
ngx_imap_close_connection(c);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_cpystrn(s->passwd.data, arg[0].data, s->passwd.len + 1);
|
||||
ngx_memcpy(s->passwd.data, arg[0].data, s->passwd.len);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
|
||||
"pop3 passwd: \"%s\"", s->passwd.data);
|
||||
"pop3 passwd: \"%V\"", &s->passwd);
|
||||
|
||||
s->args.nelts = 0;
|
||||
s->buffer->pos = s->buffer->start;
|
||||
s->buffer->last = s->buffer->start;
|
||||
|
||||
if (rev->timer_set) {
|
||||
ngx_del_timer(rev);
|
||||
}
|
||||
|
||||
ngx_imap_auth_http_init(s);
|
||||
|
||||
return;
|
||||
@ -251,10 +434,19 @@ ngx_pop3_auth_state(ngx_event_t *rev)
|
||||
|
||||
break;
|
||||
|
||||
case NGX_POP3_CAPA:
|
||||
cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
|
||||
text = cscf->pop3_capability->pos;
|
||||
size = cscf->pop3_capability->last - cscf->pop3_capability->pos;
|
||||
break;
|
||||
|
||||
case NGX_POP3_QUIT:
|
||||
quit = 1;
|
||||
break;
|
||||
|
||||
case NGX_POP3_NOOP:
|
||||
break;
|
||||
|
||||
default:
|
||||
s->imap_state = ngx_pop3_start;
|
||||
rc = NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
@ -262,6 +454,10 @@ ngx_pop3_auth_state(ngx_event_t *rev)
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* suppress warinings */
|
||||
case ngx_pop3_passwd:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,7 +487,7 @@ ngx_pop3_auth_state(ngx_event_t *rev)
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_pop3_read_command(ngx_imap_session_t *s)
|
||||
ngx_imap_read_command(ngx_imap_session_t *s)
|
||||
{
|
||||
ssize_t n;
|
||||
ngx_int_t rc;
|
||||
@ -310,16 +506,23 @@ ngx_pop3_read_command(ngx_imap_session_t *s)
|
||||
|
||||
if (n == NGX_AGAIN) {
|
||||
if (ngx_handle_read_event(s->connection->read, 0) == NGX_ERROR) {
|
||||
ngx_imap_close_connection(s->connection);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
rc = ngx_pop3_parse_command(s);
|
||||
if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
|
||||
rc = ngx_pop3_parse_command(s);
|
||||
} else {
|
||||
rc = ngx_imap_parse_command(s);
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN || rc == NGX_IMAP_PARSE_INVALID_COMMAND) {
|
||||
if (rc == NGX_AGAIN
|
||||
|| rc == NGX_IMAP_NEXT
|
||||
|| rc == NGX_IMAP_PARSE_INVALID_COMMAND)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -332,20 +535,6 @@ ngx_pop3_read_command(ngx_imap_session_t *s)
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
void
|
||||
ngx_imap_close_session(ngx_imap_session_t *s)
|
||||
{
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
|
||||
"close imap session");
|
||||
|
||||
ngx_imap_close_connection(s->connection);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
ngx_imap_session_internal_server_error(ngx_imap_session_t *s)
|
||||
{
|
||||
|
@ -10,64 +10,134 @@
|
||||
#include <ngx_imap.h>
|
||||
|
||||
|
||||
ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
|
||||
ngx_int_t ngx_imap_parse_command(ngx_imap_session_t *s)
|
||||
{
|
||||
u_char ch, *p, *c;
|
||||
ngx_str_t *arg;
|
||||
enum {
|
||||
sw_start = 0,
|
||||
sw_spaces_before_command,
|
||||
sw_command,
|
||||
sw_spaces_before_argument,
|
||||
sw_argument,
|
||||
sw_almost_done,
|
||||
sw_done
|
||||
sw_literal,
|
||||
sw_start_literal_argument,
|
||||
sw_literal_argument,
|
||||
sw_end_literal_argument,
|
||||
sw_almost_done
|
||||
} state;
|
||||
|
||||
state = s->state;
|
||||
p = s->buffer->pos;
|
||||
|
||||
while (p < s->buffer->last && state < sw_done) {
|
||||
ch = *p++;
|
||||
for (p = s->buffer->pos; p < s->buffer->last; p++) {
|
||||
ch = *p;
|
||||
|
||||
switch (state) {
|
||||
|
||||
/* POP3 command */
|
||||
|
||||
/* IMAP tag */
|
||||
case sw_start:
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
s->tag.len = p - s->buffer->start + 1;
|
||||
s->tag.data = s->buffer->start;
|
||||
state = sw_spaces_before_command;
|
||||
break;
|
||||
case CR:
|
||||
s->state = sw_start;
|
||||
return NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
case LF:
|
||||
s->state = sw_start;
|
||||
return NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
}
|
||||
break;
|
||||
|
||||
case sw_spaces_before_command:
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
break;
|
||||
case CR:
|
||||
s->state = sw_start;
|
||||
return NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
case LF:
|
||||
s->state = sw_start;
|
||||
return NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
default:
|
||||
s->cmd_start = p;
|
||||
state = sw_command;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case sw_command:
|
||||
if (ch == ' ' || ch == CR || ch == LF) {
|
||||
c = s->buffer->start;
|
||||
|
||||
if (p - 1 - c == 4) {
|
||||
c = s->cmd_start;
|
||||
|
||||
if (c[0] == 'U' && c[1] == 'S'
|
||||
&& c[2] == 'E' && c[3] == 'R')
|
||||
switch (p - c) {
|
||||
|
||||
case 4:
|
||||
if ((c[0] == 'N' || c[0] == 'n')
|
||||
&& (c[1] == 'O'|| c[1] == 'o')
|
||||
&& (c[2] == 'O'|| c[2] == 'o')
|
||||
&& (c[3] == 'P'|| c[3] == 'p'))
|
||||
{
|
||||
s->command = NGX_POP3_USER;
|
||||
|
||||
} else if (c[0] == 'P' && c[1] == 'A'
|
||||
&& c[2] == 'S' && c[3] == 'S')
|
||||
{
|
||||
s->command = NGX_POP3_PASS;
|
||||
|
||||
} else if (c[0] == 'Q' && c[1] == 'U'
|
||||
&& c[2] == 'I' && c[3] == 'T')
|
||||
{
|
||||
s->command = NGX_POP3_QUIT;
|
||||
|
||||
#if 0
|
||||
} else if (c[0] == 'N' && c[1] == 'O'
|
||||
&& c[2] == 'O' && c[3] == 'P')
|
||||
{
|
||||
s->command = NGX_POP3_NOOP;
|
||||
#endif
|
||||
s->command = NGX_IMAP_NOOP;
|
||||
|
||||
} else {
|
||||
s->state = sw_start;
|
||||
return NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
} else {
|
||||
s->state = sw_start;
|
||||
return NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
case 5:
|
||||
if ((c[0] == 'L'|| c[0] == 'l')
|
||||
&& (c[1] == 'O'|| c[1] == 'o')
|
||||
&& (c[2] == 'G'|| c[2] == 'g')
|
||||
&& (c[3] == 'I'|| c[3] == 'i')
|
||||
&& (c[4] == 'N'|| c[4] == 'n'))
|
||||
{
|
||||
s->command = NGX_IMAP_LOGIN;
|
||||
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
if ((c[0] == 'L'|| c[0] == 'l')
|
||||
&& (c[1] == 'O'|| c[1] == 'o')
|
||||
&& (c[2] == 'G'|| c[2] == 'g')
|
||||
&& (c[3] == 'O'|| c[3] == 'o')
|
||||
&& (c[4] == 'U'|| c[4] == 'u')
|
||||
&& (c[5] == 'T'|| c[5] == 't'))
|
||||
{
|
||||
s->command = NGX_IMAP_LOGOUT;
|
||||
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
case 10:
|
||||
if ((c[0] == 'C'|| c[0] == 'c')
|
||||
&& (c[1] == 'A'|| c[1] == 'a')
|
||||
&& (c[2] == 'P'|| c[2] == 'p')
|
||||
&& (c[3] == 'A'|| c[3] == 'a')
|
||||
&& (c[4] == 'B'|| c[4] == 'b')
|
||||
&& (c[5] == 'I'|| c[5] == 'i')
|
||||
&& (c[6] == 'L'|| c[6] == 'l')
|
||||
&& (c[7] == 'I'|| c[7] == 'i')
|
||||
&& (c[8] == 'T'|| c[8] == 't')
|
||||
&& (c[9] == 'Y'|| c[9] == 'y'))
|
||||
{
|
||||
s->command = NGX_IMAP_CAPABILITY;
|
||||
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
@ -78,45 +148,287 @@ ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
|
||||
state = sw_almost_done;
|
||||
break;
|
||||
case LF:
|
||||
state = sw_done;
|
||||
break;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch < 'A' || ch > 'Z') {
|
||||
s->state = sw_start;
|
||||
return NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* the spaces before the argument */
|
||||
case sw_spaces_before_argument:
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
break;
|
||||
case CR:
|
||||
state = sw_almost_done;
|
||||
s->arg_end = p - 1;
|
||||
s->arg_end = p;
|
||||
break;
|
||||
case LF:
|
||||
state = sw_done;
|
||||
s->arg_end = p - 1;
|
||||
break;
|
||||
default:
|
||||
if (s->args.nelts > 2) {
|
||||
s->state = sw_start;
|
||||
return NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
s->arg_end = p;
|
||||
goto done;
|
||||
case '"':
|
||||
if (s->args.nelts <= 2) {
|
||||
s->quoted = 1;
|
||||
s->arg_start = p + 1;
|
||||
state = sw_argument;
|
||||
break;
|
||||
}
|
||||
goto invalid;
|
||||
case '{':
|
||||
if (s->args.nelts <= 2) {
|
||||
state = sw_literal;
|
||||
break;
|
||||
}
|
||||
goto invalid;
|
||||
default:
|
||||
if (s->args.nelts <= 2) {
|
||||
s->arg_start = p;
|
||||
state = sw_argument;
|
||||
break;
|
||||
}
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
state = sw_argument;
|
||||
s->arg_start = p - 1;
|
||||
case sw_argument:
|
||||
switch (ch) {
|
||||
case '"':
|
||||
if (!s->quoted) {
|
||||
break;
|
||||
}
|
||||
s->quoted = 0;
|
||||
/* fall through */
|
||||
case ' ':
|
||||
case CR:
|
||||
case LF:
|
||||
arg = ngx_array_push(&s->args);
|
||||
if (arg == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
arg->len = p - s->arg_start;
|
||||
arg->data = s->arg_start;
|
||||
s->arg_start = NULL;
|
||||
|
||||
switch (ch) {
|
||||
case '"':
|
||||
case ' ':
|
||||
state = sw_spaces_before_argument;
|
||||
break;
|
||||
case CR:
|
||||
state = sw_almost_done;
|
||||
break;
|
||||
case LF:
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* the argument */
|
||||
case sw_literal:
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
s->literal_len = s->literal_len * 10 + (ch - '0');
|
||||
break;
|
||||
}
|
||||
if (ch == '}') {
|
||||
state = sw_start_literal_argument;
|
||||
break;
|
||||
}
|
||||
goto invalid;
|
||||
|
||||
case sw_start_literal_argument:
|
||||
switch (ch) {
|
||||
case CR:
|
||||
break;
|
||||
case LF:
|
||||
s->buffer->pos = p + 1;
|
||||
s->arg_start = p + 1;
|
||||
s->state = sw_literal_argument;
|
||||
return NGX_IMAP_NEXT;
|
||||
}
|
||||
goto invalid;
|
||||
|
||||
case sw_literal_argument:
|
||||
if (--s->literal_len) {
|
||||
break;
|
||||
}
|
||||
|
||||
arg = ngx_array_push(&s->args);
|
||||
if (arg == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
arg->len = p + 1 - s->arg_start;
|
||||
arg->data = s->arg_start;
|
||||
s->arg_start = NULL;
|
||||
state = sw_end_literal_argument;
|
||||
|
||||
break;
|
||||
|
||||
case sw_end_literal_argument:
|
||||
switch (ch) {
|
||||
case '{':
|
||||
if (s->args.nelts <= 2) {
|
||||
state = sw_literal;
|
||||
break;
|
||||
}
|
||||
goto invalid;
|
||||
case CR:
|
||||
state = sw_almost_done;
|
||||
break;
|
||||
case LF:
|
||||
goto done;
|
||||
default:
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
case sw_almost_done:
|
||||
switch (ch) {
|
||||
case LF:
|
||||
goto done;
|
||||
default:
|
||||
goto invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s->buffer->pos = p;
|
||||
s->state = state;
|
||||
|
||||
return NGX_AGAIN;
|
||||
|
||||
done:
|
||||
|
||||
s->buffer->pos = p + 1;
|
||||
|
||||
if (s->arg_start) {
|
||||
arg = ngx_array_push(&s->args);
|
||||
if (arg == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
arg->len = s->arg_end - s->arg_start;
|
||||
arg->data = s->arg_start;
|
||||
s->arg_start = NULL;
|
||||
s->cmd_start = NULL;
|
||||
s->quoted = 0;
|
||||
s->literal_len = 0;
|
||||
}
|
||||
|
||||
s->state = sw_start;
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
invalid:
|
||||
|
||||
s->state = sw_start;
|
||||
s->quoted = 0;
|
||||
s->literal_len = 0;
|
||||
|
||||
return NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
|
||||
{
|
||||
u_char ch, *p, *c, c0, c1, c2, c3;
|
||||
ngx_str_t *arg;
|
||||
enum {
|
||||
sw_start = 0,
|
||||
sw_spaces_before_argument,
|
||||
sw_argument,
|
||||
sw_almost_done
|
||||
} state;
|
||||
|
||||
state = s->state;
|
||||
|
||||
for (p = s->buffer->pos; p < s->buffer->last; p++) {
|
||||
ch = *p;
|
||||
|
||||
switch (state) {
|
||||
|
||||
/* POP3 command */
|
||||
case sw_start:
|
||||
if (ch == ' ' || ch == CR || ch == LF) {
|
||||
c = s->buffer->start;
|
||||
|
||||
if (p - c == 4) {
|
||||
|
||||
c0 = ngx_toupper(c[0]);
|
||||
c1 = ngx_toupper(c[1]);
|
||||
c2 = ngx_toupper(c[2]);
|
||||
c3 = ngx_toupper(c[3]);
|
||||
|
||||
if (c0 == 'U' && c1 == 'S' && c2 == 'E' && c3 == 'R')
|
||||
{
|
||||
s->command = NGX_POP3_USER;
|
||||
|
||||
} else if (c0 == 'P' && c1 == 'A' && c2 == 'S' && c3 == 'S')
|
||||
{
|
||||
s->command = NGX_POP3_PASS;
|
||||
|
||||
} else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T')
|
||||
{
|
||||
s->command = NGX_POP3_QUIT;
|
||||
|
||||
} else if (c0 == 'C' && c1 == 'A' && c2 == 'P' && c3 == 'A')
|
||||
{
|
||||
s->command = NGX_POP3_CAPA;
|
||||
|
||||
} else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P')
|
||||
{
|
||||
s->command = NGX_POP3_NOOP;
|
||||
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
state = sw_spaces_before_argument;
|
||||
break;
|
||||
case CR:
|
||||
state = sw_almost_done;
|
||||
break;
|
||||
case LF:
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case sw_spaces_before_argument:
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
break;
|
||||
case CR:
|
||||
state = sw_almost_done;
|
||||
s->arg_end = p;
|
||||
break;
|
||||
case LF:
|
||||
s->arg_end = p;
|
||||
goto done;
|
||||
default:
|
||||
if (s->args.nelts <= 2) {
|
||||
state = sw_argument;
|
||||
s->arg_start = p;
|
||||
break;
|
||||
}
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
case sw_argument:
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
@ -126,7 +438,7 @@ ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
|
||||
if (arg == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
arg->len = p - 1 - s->arg_start;
|
||||
arg->len = p - s->arg_start;
|
||||
arg->data = s->arg_start;
|
||||
s->arg_start = NULL;
|
||||
|
||||
@ -138,8 +450,7 @@ ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
|
||||
state = sw_almost_done;
|
||||
break;
|
||||
case LF:
|
||||
state = sw_done;
|
||||
break;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -148,42 +459,42 @@ ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
|
||||
}
|
||||
break;
|
||||
|
||||
/* end of request line */
|
||||
case sw_almost_done:
|
||||
switch (ch) {
|
||||
case LF:
|
||||
state = sw_done;
|
||||
break;
|
||||
goto done;
|
||||
default:
|
||||
s->state = sw_start;
|
||||
return NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
/* suppress warning */
|
||||
case sw_done:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s->buffer->pos = p;
|
||||
s->state = state;
|
||||
|
||||
if (state == sw_done) {
|
||||
if (s->arg_start) {
|
||||
arg = ngx_array_push(&s->args);
|
||||
if (arg == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
arg->len = s->arg_end - s->arg_start;
|
||||
arg->data = s->arg_start;
|
||||
s->arg_start = NULL;
|
||||
return NGX_AGAIN;
|
||||
|
||||
done:
|
||||
|
||||
s->buffer->pos = p + 1;
|
||||
|
||||
if (s->arg_start) {
|
||||
arg = ngx_array_push(&s->args);
|
||||
if (arg == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
s->state = sw_start;
|
||||
return NGX_OK;
|
||||
|
||||
} else {
|
||||
s->state = state;
|
||||
return NGX_AGAIN;
|
||||
arg->len = s->arg_end - s->arg_start;
|
||||
arg->data = s->arg_start;
|
||||
s->arg_start = NULL;
|
||||
}
|
||||
|
||||
s->state = sw_start;
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
invalid:
|
||||
|
||||
s->state = sw_start;
|
||||
|
||||
return NGX_IMAP_PARSE_INVALID_COMMAND;
|
||||
}
|
||||
|
@ -17,16 +17,23 @@ typedef struct {
|
||||
|
||||
|
||||
static void ngx_imap_proxy_block_read(ngx_event_t *rev);
|
||||
static void ngx_imap_proxy_auth_handler(ngx_event_t *rev);
|
||||
static void ngx_imap_proxy_imap_handler(ngx_event_t *rev);
|
||||
static void ngx_imap_proxy_pop3_handler(ngx_event_t *rev);
|
||||
static void ngx_imap_proxy_dummy_handler(ngx_event_t *ev);
|
||||
static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s);
|
||||
static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s,
|
||||
ngx_uint_t what);
|
||||
static void ngx_imap_proxy_handler(ngx_event_t *ev);
|
||||
static void ngx_imap_proxy_internal_server_error(ngx_imap_session_t *s);
|
||||
static void ngx_imap_proxy_close_session(ngx_imap_session_t *s);
|
||||
static void *ngx_imap_proxy_create_conf(ngx_conf_t *cf);
|
||||
static char *ngx_imap_proxy_merge_conf(ngx_conf_t *cf, void *parent,
|
||||
void *child);
|
||||
|
||||
|
||||
#define NGX_IMAP_WAIT_OK 0
|
||||
#define NGX_IMAP_WAIT_NEXT 1
|
||||
|
||||
|
||||
static ngx_command_t ngx_imap_proxy_commands[] = {
|
||||
{ ngx_string("proxy"),
|
||||
NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_FLAG,
|
||||
@ -61,12 +68,13 @@ ngx_module_t ngx_imap_proxy_module = {
|
||||
void
|
||||
ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peers_t *peers)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_imap_proxy_ctx_t *p;
|
||||
ngx_int_t rc;
|
||||
ngx_imap_proxy_ctx_t *p;
|
||||
ngx_imap_core_srv_conf_t *cscf;
|
||||
|
||||
p = ngx_pcalloc(s->connection->pool, sizeof(ngx_imap_proxy_ctx_t));
|
||||
if (p == NULL) {
|
||||
ngx_imap_close_connection(s->connection);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -79,16 +87,27 @@ ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peers_t *peers)
|
||||
rc = ngx_event_connect_peer(&p->upstream);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
ngx_imap_proxy_close_session(s);
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
|
||||
ngx_add_timer(p->upstream.connection->read, cscf->timeout);
|
||||
|
||||
p->upstream.connection->data = s;
|
||||
p->upstream.connection->pool = s->connection->pool;
|
||||
|
||||
s->connection->read->handler = ngx_imap_proxy_block_read;
|
||||
p->upstream.connection->read->handler = ngx_imap_proxy_auth_handler;
|
||||
p->upstream.connection->write->handler = ngx_imap_proxy_dummy_handler;
|
||||
|
||||
if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
|
||||
p->upstream.connection->read->handler = ngx_imap_proxy_pop3_handler;
|
||||
s->imap_state = ngx_pop3_start;
|
||||
|
||||
} else {
|
||||
p->upstream.connection->read->handler = ngx_imap_proxy_imap_handler;
|
||||
s->imap_state = ngx_imap_start;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -110,53 +129,189 @@ ngx_imap_proxy_block_read(ngx_event_t *rev)
|
||||
|
||||
|
||||
static void
|
||||
ngx_imap_proxy_auth_handler(ngx_event_t *rev)
|
||||
ngx_imap_proxy_imap_handler(ngx_event_t *rev)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_int_t rc;
|
||||
ngx_str_t line;
|
||||
ngx_connection_t *c;
|
||||
ngx_imap_session_t *s;
|
||||
u_char *p;
|
||||
ngx_int_t rc;
|
||||
ngx_str_t line;
|
||||
ngx_connection_t *c;
|
||||
ngx_imap_session_t *s;
|
||||
ngx_imap_core_srv_conf_t *cscf;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy auth handler");
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
|
||||
"imap proxy imap auth handler");
|
||||
|
||||
c = rev->data;
|
||||
s = c->data;
|
||||
|
||||
if (rev->timedout) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
|
||||
ngx_imap_proxy_close_session(s);
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
|
||||
"upstream timed out");
|
||||
ngx_imap_proxy_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->proxy->buffer == NULL) {
|
||||
s->proxy->buffer = ngx_create_temp_buf(c->pool, /* STUB */ 4096);
|
||||
cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
|
||||
|
||||
s->proxy->buffer = ngx_create_temp_buf(c->pool,
|
||||
cscf->proxy_buffer_size);
|
||||
if (s->proxy->buffer == NULL) {
|
||||
ngx_imap_proxy_close_session(s);
|
||||
ngx_imap_proxy_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ngx_imap_proxy_read_response(s);
|
||||
rc = ngx_imap_proxy_read_response(s, s->imap_state == ngx_imap_start ?
|
||||
NGX_IMAP_WAIT_OK : NGX_IMAP_WAIT_NEXT);
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
/* TODO: ngx_imap_proxy_finalize_session(s, NGX_IMAP_INTERNAL_ERROR) */
|
||||
ngx_imap_proxy_close_session(s);
|
||||
ngx_imap_proxy_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->imap_state == ngx_pop3_start) {
|
||||
switch (s->imap_state) {
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send user");
|
||||
case ngx_imap_start:
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
|
||||
"imap proxy send login");
|
||||
|
||||
line.len = sizeof("USER ") + s->login.len - 1 + 2;
|
||||
line.len = s->tag.len + sizeof("LOGIN ") - 1
|
||||
+ 1 + NGX_SIZE_T_LEN + 1 + 2;
|
||||
line.data = ngx_palloc(c->pool, line.len);
|
||||
if (line.data == NULL) {
|
||||
ngx_imap_proxy_close_session(s);
|
||||
ngx_imap_proxy_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
line.len = ngx_sprintf(line.data, "%VLOGIN {%uz}" CRLF,
|
||||
&s->tag, s->login.len)
|
||||
- line.data;
|
||||
|
||||
s->imap_state = ngx_imap_login;
|
||||
break;
|
||||
|
||||
case ngx_imap_login:
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send user");
|
||||
|
||||
line.len = s->login.len + 1 + NGX_SIZE_T_LEN + 1 + 2;
|
||||
line.data = ngx_palloc(c->pool, line.len);
|
||||
if (line.data == NULL) {
|
||||
ngx_imap_proxy_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
line.len = ngx_sprintf(line.data, "%V{%uz}" CRLF,
|
||||
&s->login, s->passwd.len)
|
||||
- line.data;
|
||||
|
||||
s->imap_state = ngx_imap_user;
|
||||
break;
|
||||
|
||||
case ngx_imap_user:
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
|
||||
"imap proxy send passwd");
|
||||
|
||||
line.len = s->passwd.len + 2;
|
||||
line.data = ngx_palloc(c->pool, line.len);
|
||||
if (line.data == NULL) {
|
||||
ngx_imap_proxy_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
p = ngx_cpymem(line.data, s->passwd.data, s->passwd.len);
|
||||
*p++ = CR; *p = LF;
|
||||
|
||||
s->imap_state = ngx_imap_passwd;
|
||||
break;
|
||||
|
||||
default:
|
||||
#if (NGX_SUPPRESS_WARN)
|
||||
line.len = 0;
|
||||
line.data = NULL;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) {
|
||||
/*
|
||||
* we treat the incomplete sending as NGX_ERROR
|
||||
* because it is very strange here
|
||||
*/
|
||||
ngx_imap_proxy_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
s->proxy->buffer->pos = s->proxy->buffer->start;
|
||||
s->proxy->buffer->last = s->proxy->buffer->start;
|
||||
|
||||
if (s->imap_state == ngx_imap_passwd) {
|
||||
s->connection->read->handler = ngx_imap_proxy_handler;
|
||||
s->connection->write->handler = ngx_imap_proxy_handler;
|
||||
rev->handler = ngx_imap_proxy_handler;
|
||||
c->write->handler = ngx_imap_proxy_handler;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_imap_proxy_pop3_handler(ngx_event_t *rev)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_int_t rc;
|
||||
ngx_str_t line;
|
||||
ngx_connection_t *c;
|
||||
ngx_imap_session_t *s;
|
||||
ngx_imap_core_srv_conf_t *cscf;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0,
|
||||
"imap proxy pop3 auth handler");
|
||||
|
||||
c = rev->data;
|
||||
s = c->data;
|
||||
|
||||
if (rev->timedout) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
|
||||
"upstream timed out");
|
||||
ngx_imap_proxy_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->proxy->buffer == NULL) {
|
||||
cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
|
||||
|
||||
s->proxy->buffer = ngx_create_temp_buf(c->pool,
|
||||
cscf->proxy_buffer_size);
|
||||
if (s->proxy->buffer == NULL) {
|
||||
ngx_imap_proxy_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ngx_imap_proxy_read_response(s, NGX_IMAP_WAIT_OK);
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
ngx_imap_proxy_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (s->imap_state) {
|
||||
|
||||
case ngx_pop3_start:
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send user");
|
||||
|
||||
line.len = sizeof("USER ") - 1 + s->login.len + 2;
|
||||
line.data = ngx_palloc(c->pool, line.len);
|
||||
if (line.data == NULL) {
|
||||
ngx_imap_proxy_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -164,52 +319,52 @@ ngx_imap_proxy_auth_handler(ngx_event_t *rev)
|
||||
p = ngx_cpymem(p, s->login.data, s->login.len);
|
||||
*p++ = CR; *p = LF;
|
||||
|
||||
if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) {
|
||||
/*
|
||||
* we treat the incomplete sending as NGX_ERROR
|
||||
* because it is very strange here
|
||||
*/
|
||||
ngx_imap_close_connection(c);
|
||||
s->imap_state = ngx_pop3_user;
|
||||
break;
|
||||
|
||||
case ngx_pop3_user:
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send pass");
|
||||
|
||||
line.len = sizeof("PASS ") - 1 + s->passwd.len + 2;
|
||||
line.data = ngx_palloc(c->pool, line.len);
|
||||
if (line.data == NULL) {
|
||||
ngx_imap_proxy_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
s->imap_state = ngx_pop3_user;
|
||||
p = ngx_cpymem(line.data, "PASS ", sizeof("PASS ") - 1);
|
||||
p = ngx_cpymem(p, s->passwd.data, s->passwd.len);
|
||||
*p++ = CR; *p = LF;
|
||||
|
||||
s->proxy->buffer->pos = s->proxy->buffer->start;
|
||||
s->proxy->buffer->last = s->proxy->buffer->start;
|
||||
s->imap_state = ngx_pop3_passwd;
|
||||
break;
|
||||
|
||||
return;
|
||||
default:
|
||||
#if (NGX_SUPPRESS_WARN)
|
||||
line.len = 0;
|
||||
line.data = NULL;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy send pass");
|
||||
|
||||
line.len = sizeof("PASS ") + s->passwd.len - 1 + 2;
|
||||
line.data = ngx_palloc(c->pool, line.len);
|
||||
if (line.data == NULL) {
|
||||
ngx_imap_proxy_close_session(s);
|
||||
return;
|
||||
}
|
||||
|
||||
p = ngx_cpymem(line.data, "PASS ", sizeof("PASS ") - 1);
|
||||
p = ngx_cpymem(p, s->passwd.data, s->passwd.len);
|
||||
*p++ = CR; *p = LF;
|
||||
|
||||
if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) {
|
||||
/*
|
||||
* we treat the incomplete sending as NGX_ERROR
|
||||
* because it is very strange here
|
||||
*/
|
||||
ngx_imap_close_connection(c);
|
||||
ngx_imap_proxy_internal_server_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
s->proxy->buffer->pos = s->proxy->buffer->start;
|
||||
s->proxy->buffer->last = s->proxy->buffer->start;
|
||||
|
||||
s->connection->read->handler = ngx_imap_proxy_handler;
|
||||
s->connection->write->handler = ngx_imap_proxy_handler;
|
||||
rev->handler = ngx_imap_proxy_handler;
|
||||
c->write->handler = ngx_imap_proxy_handler;
|
||||
if (s->imap_state == ngx_pop3_passwd) {
|
||||
s->connection->read->handler = ngx_imap_proxy_handler;
|
||||
s->connection->write->handler = ngx_imap_proxy_handler;
|
||||
rev->handler = ngx_imap_proxy_handler;
|
||||
c->write->handler = ngx_imap_proxy_handler;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -221,7 +376,7 @@ ngx_imap_proxy_dummy_handler(ngx_event_t *ev)
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_imap_proxy_read_response(ngx_imap_session_t *s)
|
||||
ngx_imap_proxy_read_response(ngx_imap_session_t *s, ngx_uint_t what)
|
||||
{
|
||||
u_char *p;
|
||||
ssize_t n;
|
||||
@ -259,17 +414,31 @@ ngx_imap_proxy_read_response(ngx_imap_session_t *s)
|
||||
|
||||
p = b->pos;
|
||||
|
||||
if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') {
|
||||
return NGX_OK;
|
||||
}
|
||||
if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
|
||||
if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (p[0] == '-' && p[1] == 'E' && p[2] == 'R' && p[3] == 'R') {
|
||||
return NGX_IMAP_PROXY_ERROR;
|
||||
if (p[0] == '-' && p[1] == 'E' && p[2] == 'R' && p[3] == 'R') {
|
||||
return NGX_IMAP_PROXY_ERROR;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (what == NGX_IMAP_WAIT_OK) {
|
||||
if (p[0] == '*' && p[1] == ' ' && p[2] == 'O' && p[3] == 'K') {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (p[0] == '+' && p[1] == ' ' && p[2] == 'O' && p[3] == 'K') {
|
||||
return NGX_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*(b->last - 2) = '\0';
|
||||
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
|
||||
"upstream sent invalid greeting line: \"%s\"", p);
|
||||
"upstream sent invalid response: \"%s\"", p);
|
||||
|
||||
return NGX_IMAP_PROXY_INVALID;
|
||||
}
|
||||
@ -396,6 +565,21 @@ ngx_imap_proxy_handler(ngx_event_t *ev)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_imap_proxy_internal_server_error(ngx_imap_session_t *s)
|
||||
{
|
||||
if (s->proxy->upstream.connection) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
|
||||
"close imap proxy connection: %d",
|
||||
s->proxy->upstream.connection->fd);
|
||||
|
||||
ngx_close_connection(s->proxy->upstream.connection);
|
||||
}
|
||||
|
||||
ngx_imap_session_internal_server_error(s);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_imap_proxy_close_session(ngx_imap_session_t *s)
|
||||
{
|
||||
|
@ -88,6 +88,11 @@ extern ssize_t sendfile(int s, int fd, int32_t *offset, size_t size);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NGX_HAVE_GNU_CRYPT_R
|
||||
#define NGX_HAVE_GNU_CRYPT_R 1
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NGX_HAVE_INHERITED_NONBLOCK
|
||||
#define NGX_HAVE_INHERITED_NONBLOCK 0
|
||||
#endif
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#if (NGX_CRYPT)
|
||||
|
||||
#if (NGX_LINUX)
|
||||
#if (NGX_HAVE_GNU_CRYPT_R)
|
||||
|
||||
ngx_int_t
|
||||
ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
|
||||
@ -33,6 +33,8 @@ ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
|
||||
ngx_set_errno(0);
|
||||
|
||||
cd.initialized = 0;
|
||||
/* work around the glibc-2.2.5 bug */
|
||||
cd.current_saltbits = 0;
|
||||
|
||||
value = crypt_r((char *) key, (char *) salt, &cd);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user