diff options
author | Igor Sysoev <igor@sysoev.ru> | 2005-06-07 19:56:31 +0400 |
---|---|---|
committer | Igor Sysoev <igor@sysoev.ru> | 2005-06-07 19:56:31 +0400 |
commit | 7b190b41b0d9885e523f3efd9efcbf94b6abe961 (patch) | |
tree | 4a5e4edda3e4a287a4343e341df38b9c7495ee82 /src/imap | |
parent | 3c8b02a267b310fb0926ee3c63196f976720e113 (diff) |
nginx-0.1.35-RELEASE importrelease-0.1.35
*) Feature: the "working_directory" directive.
*) Feature: the "port_in_redirect" directive.
*) Bugfix: the segmentation fault was occurred if the backend response
header was in several packets; the bug had appeared in 0.1.29.
*) Bugfix: if more than 10 servers were configured or some server did
not use the "listen" directive, then the segmentation fault was
occurred on the start.
*) Bugfix: the segmentation fault might occur if the response was
bigger than the temporary file.
*) Bugfix: nginx returned the 400 response on requests like
"GET http://www.domain.com/uri HTTP/1.0"; the bug had appeared in
0.1.28.
Diffstat (limited to 'src/imap')
-rw-r--r-- | src/imap/ngx_imap.c | 146 | ||||
-rw-r--r-- | src/imap/ngx_imap.h | 81 | ||||
-rw-r--r-- | src/imap/ngx_imap_auth_http_module.c | 421 | ||||
-rw-r--r-- | src/imap/ngx_imap_core_module.c | 297 | ||||
-rw-r--r-- | src/imap/ngx_imap_handler.c | 97 | ||||
-rw-r--r-- | src/imap/ngx_imap_proxy_module.c (renamed from src/imap/ngx_imap_proxy.c) | 133 |
6 files changed, 1081 insertions, 94 deletions
diff --git a/src/imap/ngx_imap.c b/src/imap/ngx_imap.c index 9fc5e2441..aa28b2d6a 100644 --- a/src/imap/ngx_imap.c +++ b/src/imap/ngx_imap.c @@ -13,6 +13,9 @@ static char *ngx_imap_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +ngx_uint_t ngx_imap_max_module; + + static ngx_command_t ngx_imap_commands[] = { { ngx_string("imap"), @@ -43,25 +46,144 @@ ngx_module_t ngx_imap_module = { }; -static char *ngx_imap_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +static char * +ngx_imap_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_listening_t *ls; + char *rv; + ngx_uint_t m, mi, s; + ngx_conf_t pcf; + ngx_imap_module_t *module; + ngx_imap_conf_ctx_t *ctx; + ngx_imap_core_srv_conf_t **cscfp; + ngx_imap_core_main_conf_t *cmcf; + + /* the main imap context */ + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_imap_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + *(ngx_imap_conf_ctx_t **) conf = ctx; + + /* count the number of the http modules and set up their indices */ + + ngx_imap_max_module = 0; + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_IMAP_MODULE) { + continue; + } + + ngx_modules[m]->ctx_index = ngx_imap_max_module++; + } - /* STUB */ - ls = ngx_listening_inet_stream_socket(cf, 0, 8110); - if (ls == NULL) { + /* the imap main_conf context, it is the same in the all imap contexts */ + + ctx->main_conf = ngx_pcalloc(cf->pool, + sizeof(void *) * ngx_imap_max_module); + if (ctx->main_conf == NULL) { return NGX_CONF_ERROR; } - ls->backlog = -1; - ls->addr_ntop = 1; - ls->handler = ngx_imap_init_connection; - ls->pool_size = 16384; - /* ls->post_accept_timeout = 0; */ - ls->log = cf->cycle->new_log; - /* */ + /* + * the imap null srv_conf context, it is used to merge + * the server{}s' srv_conf's + */ + + ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_imap_max_module); + if (ctx->srv_conf == NULL) { + return NGX_CONF_ERROR; + } + + + /* + * create the main_conf's, the null srv_conf's, and the null loc_conf's + * of the all imap modules + */ + + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_IMAP_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + mi = ngx_modules[m]->ctx_index; + + if (module->create_main_conf) { + ctx->main_conf[mi] = module->create_main_conf(cf); + if (ctx->main_conf[mi] == NULL) { + return NGX_CONF_ERROR; + } + } + + if (module->create_srv_conf) { + ctx->srv_conf[mi] = module->create_srv_conf(cf); + if (ctx->srv_conf[mi] == NULL) { + return NGX_CONF_ERROR; + } + } + } + + + /* parse inside the imap{} block */ + + pcf = *cf; + cf->ctx = ctx; + + cf->module_type = NGX_IMAP_MODULE; + cf->cmd_type = NGX_IMAP_MAIN_CONF; + rv = ngx_conf_parse(cf, NULL); + + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + + + /* init imap{} main_conf's, merge the server{}s' srv_conf's */ + + cmcf = ctx->main_conf[ngx_imap_core_module.ctx_index]; + cscfp = cmcf->servers.elts; + + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_IMAP_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + mi = ngx_modules[m]->ctx_index; + + /* init imap{} main_conf's */ + + if (module->init_main_conf) { + rv = module->init_main_conf(cf, ctx->main_conf[mi]); + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + } + + for (s = 0; s < cmcf->servers.nelts; s++) { + + /* merge the server{}s' srv_conf's */ + + if (module->merge_srv_conf) { + rv = module->merge_srv_conf(cf, + ctx->srv_conf[mi], + cscfp[s]->ctx->srv_conf[mi]); + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + } + } + } + + /* imap{}'s cf->ctx was needed while the configuration merging */ + + *cf = pcf; return NGX_CONF_OK; } diff --git a/src/imap/ngx_imap.h b/src/imap/ngx_imap.h index cec709c97..38f449891 100644 --- a/src/imap/ngx_imap.h +++ b/src/imap/ngx_imap.h @@ -15,10 +15,39 @@ typedef struct { - ngx_peer_connection_t upstream; + void **main_conf; + void **srv_conf; +} ngx_imap_conf_ctx_t; - ngx_buf_t *buffer; -} ngx_imap_proxy_ctx_t; + +typedef struct { + ngx_array_t servers; /* ngx_imap_core_srv_conf_t */ +} ngx_imap_core_main_conf_t; + + +#define NGX_IMAP_POP3_PROTOCOL 0 +#define NGX_IMAP_IMAP_PROTOCOL 1 + +typedef struct { + ngx_msec_t timeout; + + size_t imap_client_buffer_size; + size_t proxy_buffer_size; + + ngx_uint_t protocol; + + /* server ctx */ + ngx_imap_conf_ctx_t *ctx; +} ngx_imap_core_srv_conf_t; + + +typedef struct { + void *(*create_main_conf)(ngx_conf_t *cf); + char *(*init_main_conf)(ngx_conf_t *cf, void *conf); + + void *(*create_srv_conf)(ngx_conf_t *cf); + char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); +} ngx_imap_module_t; typedef enum { @@ -28,15 +57,28 @@ typedef enum { typedef struct { + ngx_peer_connection_t upstream; + ngx_buf_t *buffer; +} ngx_imap_proxy_ctx_t; + + +typedef struct { uint32_t signature; /* "IMAP" */ ngx_connection_t *connection; + ngx_buf_t *buffer; - ngx_imap_state_e imap_state; + void **ctx; + void **main_conf; + void **srv_conf; ngx_imap_proxy_ctx_t *proxy; + ngx_imap_state_e imap_state; + + unsigned protocol:1; + ngx_str_t login; ngx_str_t passwd; @@ -74,17 +116,38 @@ typedef struct { #define NGX_IMAP_MODULE 0x50414D49 /* "IMAP" */ -#define NGX_IMAP_SRV_CONF 0x02000000 -#define NGX_IMAP_IMAP_CONF 0x04000000 -#define NGX_IMAP_POP3_CONF 0x08000000 +#define NGX_IMAP_MAIN_CONF 0x02000000 +#define NGX_IMAP_SRV_CONF 0x04000000 + + +#define NGX_IMAP_MAIN_CONF_OFFSET offsetof(ngx_imap_conf_ctx_t, main_conf) +#define NGX_IMAP_SRV_CONF_OFFSET offsetof(ngx_imap_conf_ctx_t, srv_conf) + + +#define ngx_imap_get_module_ctx(s, module) (s)->ctx[module.ctx_index] +#define ngx_imap_set_ctx(s, c, module) s->ctx[module.ctx_index] = c; +#define ngx_imap_delete_ctx(s, module) s->ctx[module.ctx_index] = NULL; + + +#define ngx_imap_get_module_main_conf(s, module) \ + (s)->main_conf[module.ctx_index] +#define ngx_imap_get_module_srv_conf(s, module) (s)->srv_conf[module.ctx_index] void ngx_imap_init_connection(ngx_connection_t *c); void ngx_imap_close_connection(ngx_connection_t *c); -void ngx_imap_proxy_init(ngx_imap_session_t *s); - ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s); +/* STUB */ +void ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peers_t *peers); +void ngx_imap_auth_http_init(ngx_imap_session_t *s); +/**/ + + +extern ngx_uint_t ngx_imap_max_module; +extern ngx_module_t ngx_imap_core_module; + + #endif /* _NGX_IMAP_H_INCLUDED_ */ diff --git a/src/imap/ngx_imap_auth_http_module.c b/src/imap/ngx_imap_auth_http_module.c new file mode 100644 index 000000000..7e6c44b23 --- /dev/null +++ b/src/imap/ngx_imap_auth_http_module.c @@ -0,0 +1,421 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> +#include <ngx_event_connect.h> +#include <ngx_imap.h> + + +typedef struct { + ngx_peers_t *peers; + + ngx_msec_t timeout; + + ngx_str_t host_header; + ngx_str_t uri; +} ngx_imap_auth_http_conf_t; + + +typedef struct { + ngx_buf_t *request; + ngx_peer_connection_t peer; +} ngx_imap_auth_http_ctx_t; + + +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_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, + ngx_imap_auth_http_conf_t *ahcf); + +static void *ngx_imap_auth_http_create_conf(ngx_conf_t *cf); +static char *ngx_imap_auth_http_merge_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_imap_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + + +static ngx_command_t ngx_imap_auth_http_commands[] = { + + { ngx_string("auth_http"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_imap_auth_http, + NGX_IMAP_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("auth_http_timeout"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_auth_http_conf_t, timeout), + NULL }, + + ngx_null_command +}; + + +static ngx_imap_module_t ngx_imap_auth_http_module_ctx = { + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_imap_auth_http_create_conf, /* create server configuration */ + ngx_imap_auth_http_merge_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_imap_auth_http_module = { + NGX_MODULE_V1, + &ngx_imap_auth_http_module_ctx, /* module context */ + ngx_imap_auth_http_commands, /* module directives */ + NGX_IMAP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; + + +static char *ngx_imap_auth_http_protocol[] = { "pop3", "imap" }; + + +void +ngx_imap_auth_http_init(ngx_imap_session_t *s) +{ + ngx_int_t rc; + ngx_imap_auth_http_ctx_t *ctx; + ngx_imap_auth_http_conf_t *ahcf; + + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_imap_auth_http_ctx_t)); + if (ctx == NULL) { + ngx_imap_close_connection(s->connection); + return; + } + + ahcf = ngx_imap_get_module_srv_conf(s, ngx_imap_auth_http_module); + + ctx->request = ngx_imap_auth_http_create_request(s, ahcf); + if (ctx->request == NULL) { + ngx_imap_close_connection(s->connection); + return; + } + + ngx_imap_set_ctx(s, ctx, ngx_imap_auth_http_module); + + ctx->peer.peers = ahcf->peers; + ctx->peer.log = s->connection->log; + ctx->peer.log_error = NGX_ERROR_ERR; + + rc = ngx_event_connect_peer(&ctx->peer); + + if (rc == NGX_ERROR) { + ngx_imap_close_connection(s->connection); + return; + } + + ctx->peer.connection->data = s; + ctx->peer.connection->pool = s->connection->pool; + + s->connection->read->handler = ngx_imap_auth_http_block_read; + ctx->peer.connection->read->handler = ngx_imap_auth_http_read_handler; + ctx->peer.connection->write->handler = ngx_imap_auth_http_write_handler; + + if (rc == NGX_OK) { + ngx_imap_auth_http_write_handler(ctx->peer.connection->write); + return; + } + + ngx_add_timer(ctx->peer.connection->read, ahcf->timeout); + ngx_add_timer(ctx->peer.connection->write, ahcf->timeout); +} + + +static void +ngx_imap_auth_http_write_handler(ngx_event_t *wev) +{ + ssize_t n, size; + ngx_connection_t *c; + ngx_imap_session_t *s; + ngx_imap_auth_http_ctx_t *ctx; + ngx_imap_auth_http_conf_t *ahcf; + + c = wev->data; + s = c->data; + + ctx = ngx_imap_get_module_ctx(s, ngx_imap_auth_http_module); + + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, wev->log, 0, + "imap auth http write handler"); + + if (wev->timedout) { + ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT, + "auth http server timed out"); + ngx_imap_close_connection(ctx->peer.connection); + ngx_imap_close_connection(s->connection); + return; + } + + size = ctx->request->last - ctx->request->pos; + + n = ngx_send(c, ctx->request->pos, size); + + if (n == NGX_ERROR) { + ngx_imap_close_connection(ctx->peer.connection); + ngx_imap_close_connection(s->connection); + return; + } + + if (n > 0) { + ctx->request->pos += n; + + if (n == size) { + wev->handler = ngx_imap_auth_http_dummy_handler; + + if (wev->timer_set) { + ngx_del_timer(wev); + } + + return; + } + } + + if (!wev->timer_set) { + ahcf = ngx_imap_get_module_srv_conf(s, ngx_imap_auth_http_module); + ngx_add_timer(wev, ahcf->timeout); + } +} + + +static void +ngx_imap_auth_http_read_handler(ngx_event_t *rev) +{ + ngx_peers_t *peers; + ngx_connection_t *c; + ngx_imap_session_t *s; +#if 0 + ngx_imap_auth_http_ctx_t *ctx; +#endif + + c = rev->data; + s = c->data; + +#if 0 + ctx = ngx_imap_get_module_ctx(s, ngx_imap_auth_http_module); +#endif + + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, + "imap auth http read handler"); + + peers = NULL; + + ngx_imap_proxy_init(s, peers); +} + + +static void +ngx_imap_auth_http_block_read(ngx_event_t *rev) +{ + ngx_connection_t *c; + ngx_imap_session_t *s; + ngx_imap_auth_http_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, + "imap auth http block read"); + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { + c = rev->data; + s = c->data; + + ctx = ngx_imap_get_module_ctx(s, ngx_imap_auth_http_module); + + ngx_imap_close_connection(ctx->peer.connection); + ngx_imap_close_connection(s->connection); + } +} + + +static void +ngx_imap_auth_http_dummy_handler(ngx_event_t *ev) +{ + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0, + "imap auth http dummy handler"); +} + + +static ngx_buf_t * +ngx_imap_auth_http_create_request(ngx_imap_session_t *s, + ngx_imap_auth_http_conf_t *ahcf) +{ + size_t len; + ngx_buf_t *b; + + len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1 + + sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1 + + sizeof("Auth-Method: plain" CRLF) - 1 + + 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("Client-IP: ") - 1 + s->connection->addr_text.len + + sizeof(CRLF) - 1 + + sizeof(CRLF) - 1; + + b = ngx_create_temp_buf(s->connection->pool, len); + if (b == NULL) { + return NULL; + } + + b->last = ngx_cpymem(b->last, "GET ", sizeof("GET ") - 1); + b->last = ngx_cpymem(b->last, ahcf->uri.data, ahcf->uri.len); + b->last = ngx_cpymem(b->last, " HTTP/1.0" CRLF, + sizeof(" HTTP/1.0" CRLF) - 1); + + b->last = ngx_cpymem(b->last, "Host: ", sizeof("Host: ") - 1); + b->last = ngx_cpymem(b->last, ahcf->host_header.data, + ahcf->host_header.len); + *b->last++ = CR; *b->last++ = LF; + + b->last = ngx_cpymem(b->last, "Auth-Method: plain" CRLF, + sizeof("Auth-Method: plain" CRLF) - 1); + + b->last = ngx_cpymem(b->last, "Auth-User: ", sizeof("Auth-User: ") - 1); + b->last = ngx_cpymem(b->last, s->login.data, s->login.len); + *b->last++ = CR; *b->last++ = LF; + + b->last = ngx_cpymem(b->last, "Auth-Pass: ", sizeof("Auth-Pass: ") - 1); + b->last = ngx_cpymem(b->last, s->passwd.data, s->passwd.len); + *b->last++ = CR; *b->last++ = LF; + + b->last = ngx_cpymem(b->last, "Auth-Protocol: ", + sizeof("Auth-Protocol: ") - 1); + b->last = ngx_cpymem(b->last, ngx_imap_auth_http_protocol[s->protocol], + sizeof("imap") - 1); + *b->last++ = CR; *b->last++ = LF; + + 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); + *b->last++ = CR; *b->last++ = LF; + + /* add "\r\n" at the header end */ + *b->last++ = CR; *b->last++ = LF; + +#if (NGX_DEBUG) + { + ngx_str_t l; + + l.len = b->last - b->pos; + l.data = b->pos; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, s->connection->log, 0, + "imap auth http header:\n\"%V\"", &l); + } +#endif + + return b; +} + + +static void * +ngx_imap_auth_http_create_conf(ngx_conf_t *cf) +{ + ngx_imap_auth_http_conf_t *ahcf; + + ahcf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_auth_http_conf_t)); + if (ahcf == NULL) { + return NGX_CONF_ERROR; + } + + ahcf->timeout = NGX_CONF_UNSET_MSEC; + + return ahcf; +} + + +static char * +ngx_imap_auth_http_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_imap_auth_http_conf_t *prev = parent; + ngx_imap_auth_http_conf_t *conf = child; + + if (conf->peers == NULL) { + conf->peers = prev->peers; + conf->host_header = prev->host_header; + conf->uri = prev->uri; + } + + ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); + + return NGX_CONF_OK; +} + + +static char * +ngx_imap_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_imap_auth_http_conf_t *ahcf = conf; + + ngx_uint_t i; + ngx_str_t *value, *url; + ngx_inet_upstream_t inet_upstream; +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_unix_domain_upstream_t unix_upstream; +#endif + + value = cf->args->elts; + + url = &value[1]; + + if (ngx_strncasecmp(url->data, "unix:", 5) == 0) { + +#if (NGX_HAVE_UNIX_DOMAIN) + + ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); + + unix_upstream.name = *url; + unix_upstream.url = *url; + unix_upstream.uri_part = 1; + + ahcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); + if (ahcf->peers == NULL) { + return NGX_CONF_ERROR; + } + + ahcf->peers->peer[0].uri_separator = ":"; + + ahcf->host_header.len = sizeof("localhost") - 1; + ahcf->host_header.data = (u_char *) "localhost"; + ahcf->uri = unix_upstream.uri; + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the unix domain sockets are not supported " + "on this platform"); + return NGX_CONF_ERROR; + +#endif + + } else { + ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); + + inet_upstream.name = *url; + inet_upstream.url = *url; + inet_upstream.default_port_value = 80; + inet_upstream.uri_part = 1; + + ahcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); + if (ahcf->peers == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 0; i < ahcf->peers->number; i++) { + ahcf->peers->peer[i].uri_separator = ":"; + } + + ahcf->host_header = inet_upstream.host_header; + ahcf->uri = inet_upstream.uri; + } + + return NGX_CONF_OK; +} diff --git a/src/imap/ngx_imap_core_module.c b/src/imap/ngx_imap_core_module.c new file mode 100644 index 000000000..3e775f312 --- /dev/null +++ b/src/imap/ngx_imap_core_module.c @@ -0,0 +1,297 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> +#include <ngx_imap.h> + + +static void *ngx_imap_core_create_main_conf(ngx_conf_t *cf); +static void *ngx_imap_core_create_srv_conf(ngx_conf_t *cf); +static char *ngx_imap_core_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); +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 ngx_conf_enum_t ngx_imap_core_procotol[] = { + { ngx_string("pop3"), NGX_IMAP_POP3_PROTOCOL }, + { ngx_string("imap"), NGX_IMAP_IMAP_PROTOCOL }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_imap_core_commands[] = { + + { ngx_string("server"), + NGX_IMAP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_imap_core_server, + 0, + 0, + NULL }, + + { ngx_string("listen"), + NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_imap_core_listen, + 0, + 0, + NULL }, + + { ngx_string("protocol"), + NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_core_srv_conf_t, protocol), + &ngx_imap_core_procotol }, + + { ngx_string("imap_client_buffer"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_core_srv_conf_t, imap_client_buffer_size), + NULL }, + + { ngx_string("proxy_buffer"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_core_srv_conf_t, proxy_buffer_size), + NULL }, + + { ngx_string("timeout"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_core_srv_conf_t, timeout), + NULL }, + + ngx_null_command +}; + + +static ngx_imap_module_t ngx_imap_core_module_ctx = { + ngx_imap_core_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_imap_core_create_srv_conf, /* create server configuration */ + ngx_imap_core_merge_srv_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_imap_core_module = { + NGX_MODULE_V1, + &ngx_imap_core_module_ctx, /* module context */ + ngx_imap_core_commands, /* module directives */ + NGX_IMAP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; + + +static void * +ngx_imap_core_create_main_conf(ngx_conf_t *cf) +{ + ngx_imap_core_main_conf_t *cmcf; + + cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_core_main_conf_t)); + if (cmcf == NULL) { + return NGX_CONF_ERROR; + } + + if (ngx_array_init(&cmcf->servers, cf->pool, 4, + sizeof(ngx_imap_core_srv_conf_t *)) == NGX_ERROR) + { + return NGX_CONF_ERROR; + } + + return cmcf; +} + + +static void * +ngx_imap_core_create_srv_conf(ngx_conf_t *cf) +{ + ngx_imap_core_srv_conf_t *cscf; + + cscf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_core_srv_conf_t)); + if (cscf == NULL) { + return NGX_CONF_ERROR; + } + + cscf->imap_client_buffer_size = NGX_CONF_UNSET_SIZE; + cscf->proxy_buffer_size = NGX_CONF_UNSET_SIZE; + cscf->timeout = NGX_CONF_UNSET_MSEC; + cscf->protocol = NGX_CONF_UNSET_UINT; + + return cscf; +} + + +static char * +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; + + ngx_conf_merge_size_value(conf->imap_client_buffer_size, + prev->imap_client_buffer_size, + (size_t) ngx_pagesize); + ngx_conf_merge_size_value(conf->proxy_buffer_size, prev->proxy_buffer_size, + (size_t) ngx_pagesize); + ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); + ngx_conf_merge_unsigned_value(conf->protocol, prev->protocol, + NGX_IMAP_IMAP_PROTOCOL); + + return NGX_CONF_OK; +} + + +static char * +ngx_imap_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + void *mconf; + ngx_uint_t m; + ngx_conf_t pcf; + ngx_imap_module_t *module; + ngx_imap_conf_ctx_t *ctx, *imap_ctx; + ngx_imap_core_srv_conf_t *cscf, **cscfp; + ngx_imap_core_main_conf_t *cmcf; + + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_imap_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + imap_ctx = cf->ctx; + ctx->main_conf = imap_ctx->main_conf; + + /* the server{}'s srv_conf */ + + ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_imap_max_module); + if (ctx->srv_conf == NULL) { + return NGX_CONF_ERROR; + } + + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_IMAP_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + + if (module->create_srv_conf) { + mconf = module->create_srv_conf(cf); + if (mconf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf; + } + } + + /* the server configuration context */ + + cscf = ctx->srv_conf[ngx_imap_core_module.ctx_index]; + cscf->ctx = ctx; + + cmcf = ctx->main_conf[ngx_imap_core_module.ctx_index]; + + cscfp = ngx_array_push(&cmcf->servers); + if (cscfp == NULL) { + return NGX_CONF_ERROR; + } + + *cscfp = cscf; + + + /* parse inside server{} */ + + pcf = *cf; + cf->ctx = ctx; + cf->cmd_type = NGX_IMAP_SRV_CONF; + + rv = ngx_conf_parse(cf, NULL); + + *cf = pcf; + + return rv; +} + + +/* AF_INET only */ + +static char * +ngx_imap_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *err; + ngx_str_t *value; + in_addr_t in_addr; + struct hostent *h; + ngx_listening_t *ls; + ngx_inet_upstream_t inet_upstream; + + value = cf->args->elts; + + ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); + + inet_upstream.url = value[1]; + inet_upstream.port_only = 1; + + err = ngx_inet_parse_host_port(&inet_upstream); + + if (err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in \"%V\" of the \"listen\" directive", err); + return NGX_CONF_ERROR; + } + + if (inet_upstream.host.len) { + inet_upstream.host.data[inet_upstream.host.len] = '\0'; + + in_addr = inet_addr((const char *) inet_upstream.host.data); + + if (in_addr == INADDR_NONE) { + h = gethostbyname((const char *) inet_upstream.host.data); + + if (h == NULL || h->h_addr_list[0] == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "can not resolve host \"%s\" " + "in the \"listen\" directive", + inet_upstream.host.data); + return NGX_CONF_ERROR; + } + + in_addr = *(in_addr_t *)(h->h_addr_list[0]); + } + + } else { + in_addr = INADDR_ANY; + } + + + ls = ngx_listening_inet_stream_socket(cf, in_addr, inet_upstream.port); + if (ls == NULL) { + return NGX_CONF_ERROR; + } + + ls->backlog = -1; + ls->addr_ntop = 1; + ls->handler = ngx_imap_init_connection; + ls->pool_size = 256; + + ls->ctx = cf->ctx; + + /* STUB */ + ls->log = cf->cycle->new_log; + /**/ + + return NGX_CONF_OK; +} diff --git a/src/imap/ngx_imap_handler.c b/src/imap/ngx_imap_handler.c index f65db81f3..be2c9d1c5 100644 --- a/src/imap/ngx_imap_handler.c +++ b/src/imap/ngx_imap_handler.c @@ -12,33 +12,39 @@ 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 u_char pop3_greeting[] = "+OK " NGINX_VER " ready" CRLF; -#if 0 -static u_char imap_greeting[] = "* OK " NGINX_VER " ready" CRLF; -#endif -static u_char pop3_ok[] = "+OK" CRLF; -static u_char pop3_invalid_command[] = "-ERR invalid command" CRLF; +static ngx_str_t greetings[] = { + ngx_string("+OK " NGINX_VER " ready" CRLF), + ngx_string("* OK " NGINX_VER " ready" CRLF) +}; +static u_char pop3_ok[] = "+OK" CRLF; +static u_char pop3_invalid_command[] = "-ERR invalid command" CRLF; -void ngx_imap_init_connection(ngx_connection_t *c) + +void +ngx_imap_init_connection(ngx_connection_t *c) { - u_char *greeting; - ssize_t size; + ssize_t size; + ngx_imap_conf_ctx_t *ctx; + ngx_imap_core_srv_conf_t *cscf; - ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, - "imap init connection"); + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap init connection"); c->log_error = NGX_ERROR_INFO; - greeting = pop3_greeting; - size = sizeof(pop3_greeting) - 1; + ctx = c->ctx; + cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module); + + size = greetings[cscf->protocol].len; - if (ngx_send(c, greeting, size) < size) { + if (ngx_send(c, greetings[cscf->protocol].data, size) < size) { /* * we treat the incomplete sending as NGX_ERROR * because it is very strange here @@ -49,7 +55,7 @@ void ngx_imap_init_connection(ngx_connection_t *c) c->read->handler = ngx_imap_init_session; - ngx_add_timer(c->read, /* STUB */ 60000); + ngx_add_timer(c->read, cscf->timeout); if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { ngx_imap_close_connection(c); @@ -57,11 +63,14 @@ void ngx_imap_init_connection(ngx_connection_t *c) } -static void ngx_imap_init_session(ngx_event_t *rev) +static void +ngx_imap_init_session(ngx_event_t *rev) { - size_t size; - ngx_connection_t *c; - ngx_imap_session_t *s; + size_t size; + ngx_connection_t *c; + ngx_imap_session_t *s; + ngx_imap_conf_ctx_t *ctx; + ngx_imap_core_srv_conf_t *cscf; c = rev->data; @@ -80,12 +89,33 @@ static void ngx_imap_init_session(ngx_event_t *rev) c->data = s; s->connection = c; + s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_imap_max_module); + if (s->ctx == NULL) { + ngx_imap_close_connection(c); + return; + } + + ctx = c->ctx; + s->main_conf = ctx->main_conf; + 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); return; } - size = /* STUB: pop3: 128, imap: configurable 4K default */ 128; + cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module); + + s->protocol = cscf->protocol; + + if (cscf->protocol == NGX_IMAP_POP3_PROTOCOL) { + size = 128; + c->read->handler = ngx_pop3_auth_state; + + } else { + size = cscf->imap_client_buffer_size; + c->read->handler = ngx_imap_auth_state; + } s->buffer = ngx_create_temp_buf(c->pool, size); if (s->buffer == NULL) { @@ -93,13 +123,23 @@ static void ngx_imap_init_session(ngx_event_t *rev) return; } - c->read->handler = ngx_pop3_auth_state; + c->read->handler(rev); +} + + +static void +ngx_imap_auth_state(ngx_event_t *rev) +{ + ngx_connection_t *c; + + c = rev->data; - ngx_pop3_auth_state(rev); + ngx_imap_close_connection(c); } -static void ngx_pop3_auth_state(ngx_event_t *rev) +static void +ngx_pop3_auth_state(ngx_event_t *rev) { u_char *text; ssize_t size; @@ -196,7 +236,7 @@ static void ngx_pop3_auth_state(ngx_event_t *rev) s->buffer->pos = s->buffer->start; s->buffer->last = s->buffer->start; - ngx_imap_proxy_init(s); + ngx_imap_auth_http_init(s); return; @@ -245,7 +285,8 @@ static void ngx_pop3_auth_state(ngx_event_t *rev) } -static ngx_int_t ngx_pop3_read_command(ngx_imap_session_t *s) +static ngx_int_t +ngx_pop3_read_command(ngx_imap_session_t *s) { ssize_t n; ngx_int_t rc; @@ -288,7 +329,8 @@ static ngx_int_t ngx_pop3_read_command(ngx_imap_session_t *s) #if 0 -void ngx_imap_close_session(ngx_imap_session_t *s) +void +ngx_imap_close_session(ngx_imap_session_t *s) { ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0, "close imap session"); @@ -299,7 +341,8 @@ void ngx_imap_close_session(ngx_imap_session_t *s) #endif -void ngx_imap_close_connection(ngx_connection_t *c) +void +ngx_imap_close_connection(ngx_connection_t *c) { ngx_pool_t *pool; diff --git a/src/imap/ngx_imap_proxy.c b/src/imap/ngx_imap_proxy_module.c index 2b6e30e3a..b3bedae58 100644 --- a/src/imap/ngx_imap_proxy.c +++ b/src/imap/ngx_imap_proxy_module.c @@ -11,19 +11,57 @@ #include <ngx_imap.h> +typedef struct { + ngx_flag_t enable; +} ngx_imap_proxy_conf_t; + + 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_dummy_handler(ngx_event_t *ev); static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s); static void ngx_imap_proxy_handler(ngx_event_t *ev); 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); + + +static ngx_command_t ngx_imap_proxy_commands[] = { + { ngx_string("proxy"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_proxy_conf_t, enable), + NULL }, + + ngx_null_command +}; + + +static ngx_imap_module_t ngx_imap_proxy_module_ctx = { + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_imap_proxy_create_conf, /* create server configuration */ + ngx_imap_proxy_merge_conf /* merge server configuration */ +}; + +ngx_module_t ngx_imap_proxy_module = { + NGX_MODULE_V1, + &ngx_imap_proxy_module_ctx, /* module context */ + ngx_imap_proxy_commands, /* module directives */ + NGX_IMAP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; -void ngx_imap_proxy_init(ngx_imap_session_t *s) + +void +ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peers_t *peers) { ngx_int_t rc; - ngx_peers_t *peers; - struct sockaddr_in *sin; ngx_imap_proxy_ctx_t *p; p = ngx_pcalloc(s->connection->pool, sizeof(ngx_imap_proxy_ctx_t)); @@ -34,44 +72,10 @@ void ngx_imap_proxy_init(ngx_imap_session_t *s) s->proxy = p; - /**/ - - peers = ngx_pcalloc(s->connection->pool, sizeof(ngx_peers_t)); - if (peers == NULL) { - ngx_imap_close_connection(s->connection); - return; - } - p->upstream.peers = peers; p->upstream.log = s->connection->log; p->upstream.log_error = NGX_ERROR_ERR; - sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in)); - if (sin == NULL) { - ngx_imap_close_connection(s->connection); - return; - } - - peers->peer[0].sockaddr = (struct sockaddr *) sin; - peers->peer[0].socklen = sizeof(struct sockaddr_in); - - sin->sin_port = htons(110); -#if 1 - sin->sin_addr.s_addr = inet_addr("81.19.64.101"); - peers->peer[0].name.len = sizeof("81.19.64.101:110") - 1; - peers->peer[0].name.data = (u_char *) "81.19.64.101:110"; -#else - sin->sin_addr.s_addr = inet_addr("81.19.69.70"); - peers->peer[0].name.len = sizeof("81.19.69.70:110") - 1; - peers->peer[0].name.data = (u_char *) "81.19.69.70:110"; -#endif - - peers->number = 1; - - peers->peer[0].max_fails = 1; - peers->peer[0].fail_timeout = 60; - peers->peer[0].weight = 1; - rc = ngx_event_connect_peer(&p->upstream); if (rc == NGX_ERROR) { @@ -88,7 +92,8 @@ void ngx_imap_proxy_init(ngx_imap_session_t *s) } -static void ngx_imap_proxy_block_read(ngx_event_t *rev) +static void +ngx_imap_proxy_block_read(ngx_event_t *rev) { ngx_connection_t *c; ngx_imap_session_t *s; @@ -104,7 +109,8 @@ 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_auth_handler(ngx_event_t *rev) { u_char *p; ngx_int_t rc; @@ -207,13 +213,15 @@ static void ngx_imap_proxy_auth_handler(ngx_event_t *rev) } -static void ngx_imap_proxy_dummy_handler(ngx_event_t *ev) +static void +ngx_imap_proxy_dummy_handler(ngx_event_t *ev) { ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0, "imap proxy dummy handler"); } -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) { u_char *p; ssize_t n; @@ -267,7 +275,8 @@ static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s) } -static void ngx_imap_proxy_handler(ngx_event_t *ev) +static void +ngx_imap_proxy_handler(ngx_event_t *ev) { size_t size; ssize_t n; @@ -387,12 +396,44 @@ static void ngx_imap_proxy_handler(ngx_event_t *ev) } -static void ngx_imap_proxy_close_session(ngx_imap_session_t *s) +static void +ngx_imap_proxy_close_session(ngx_imap_session_t *s) { - if (ngx_close_socket(s->proxy->upstream.connection->fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, s->connection->log, ngx_socket_errno, - ngx_close_socket_n " failed"); + 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_close_connection(s->connection); } + + +static void * +ngx_imap_proxy_create_conf(ngx_conf_t *cf) +{ + ngx_imap_proxy_conf_t *pcf; + + pcf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_proxy_conf_t)); + if (pcf == NULL) { + return NGX_CONF_ERROR; + } + + pcf->enable = NGX_CONF_UNSET; + + return pcf; +} + + +static char * +ngx_imap_proxy_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_imap_proxy_conf_t *prev = parent; + ngx_imap_proxy_conf_t *conf = child; + + ngx_conf_merge_msec_value(conf->enable, prev->enable, 0); + + return NGX_CONF_OK; +} |