changeset 250:fbf2b2f66c9f NGINX_0_4_10

nginx 0.4.10 *) Feature: the POP3 proxy supports the APOP command. *) Bugfix: if the select, poll or /dev/poll methods were used, then while waiting authentication server response the IMAP/POP3 proxy hogged CPU. *) Bugfix: a segmentation fault might occur if the $server_addr variable was used in the "map" directive. *) Bugfix: the ngx_http_flv_module did not support the byte ranges for full responses; bug appeared in 0.4.7. *) Bugfix: nginx could not be built on Debian amd64; bug appeared in 0.4.9.
author Igor Sysoev <http://sysoev.ru>
date Mon, 23 Oct 2006 00:00:00 +0400
parents 7a34085272cb
children 16ffa8ae5759
files CHANGES CHANGES.ru auto/sources src/core/nginx.c src/core/nginx.h src/core/ngx_config.h src/core/ngx_core.h src/core/ngx_crc.h src/core/ngx_crc32.c src/core/ngx_crc32.h src/core/ngx_file.c src/core/ngx_string.c src/http/modules/ngx_http_charset_filter_module.c src/http/modules/ngx_http_flv_module.c src/http/modules/ngx_http_map_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/ngx_http_userid_filter_module.c src/http/modules/perl/nginx.pm src/http/ngx_http_parse.c src/http/ngx_http_upstream.c src/http/ngx_http_variables.c src/imap/ngx_imap.h src/imap/ngx_imap_auth_http_module.c src/imap/ngx_imap_core_module.c src/imap/ngx_imap_handler.c src/imap/ngx_imap_parse.c src/os/unix/ngx_posix_init.c
diffstat 27 files changed, 510 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,22 @@
 
+Changes with nginx 0.4.10                                        23 Oct 2006
+
+    *) Feature: the IMAP/POP3 proxy supports the APOP command.
+
+    *) Bugfix: if the select, poll or /dev/poll methods were used, then 
+       while waiting authentication server response the IMAP/POP3 proxy 
+       hogged CPU.
+
+    *) Bugfix: a segmentation fault might occur if the $server_addr 
+       variable was used in the "map" directive.
+
+    *) Bugfix: the ngx_http_flv_module did not support the byte ranges for 
+       full responses; bug appeared in 0.4.7.
+
+    *) Bugfix: nginx could not be built on Debian amd64; bug appeared in 
+       0.4.9.
+
+
 Changes with nginx 0.4.9                                         13 Oct 2006
 
     *) Feature: the "set" parameter in the "include" SSI command.
@@ -1576,7 +1594,7 @@ Changes with nginx 0.1.29               
 
 Changes with nginx 0.1.28                                        08 Apr 2005
 
-    *) Bugfix: nginx hogs CPU while proxing the huge files.
+    *) Bugfix: nginx hogs CPU while proxying the huge files.
 
     *) Bugfix: nginx could not be built by gcc 4.0 on Linux.
 
@@ -1687,7 +1705,7 @@ Changes with nginx 0.1.23               
 Changes with nginx 0.1.22                                        22 Feb 2005
 
     *) Bugfix: the ngx_http_stub_status_module showed incorrect handled 
-       connections statistics if the proxing or FastCGI server were used.
+       connections statistics if the proxying or FastCGI server were used.
 
     *) Bugfix: the installation paths were incorrectly quoted on Linux and 
        Solaris; bug appeared in 0.1.21.
@@ -2051,7 +2069,7 @@ Changes with nginx 0.1.1                
 
     *) Feature: the setproctitle() emulation for Linux and Solaris.
 
-    *) Bugfix: the "Location" header rewrite bug fixed while the proxing.
+    *) Bugfix: the "Location" header rewrite bug fixed while the proxying.
 
     *) Bugfix: the ngx_http_chunked_module module may get caught in an 
        endless loop.
@@ -2059,7 +2077,7 @@ Changes with nginx 0.1.1                
     *) Bugfix: the /dev/poll module bugs fixed.
 
     *) Bugfix: the responses were corrupted when the temporary files were 
-       used while the proxing.
+       used while the proxying.
 
     *) Bugfix: the unescaped requests were passed to the backend.
 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,22 @@
 
+Изменения в nginx 0.4.10                                          23.10.2006
+
+    *) Добавление: IMAP/POP3 прокси поддерживает APOP.
+
+    *) Исправление: при использовании методов select, poll и /dev/poll во 
+       время ожидания ответа от сервера аутентификации IMAP/POP3 прокси 
+       нагружал процессор.
+
+    *) Исправление: при использовании переменной $server_addr в директиве 
+       map мог произойти segmentation fault.
+
+    *) Исправление: модуль ngx_http_flv_module не поддерживал byte ranges 
+       для полных ответов; ошибка появилась в 0.4.7.
+
+    *) Исправление: nginx не собирался на Debian amd64; ошибка появилась в 
+       0.4.9.
+
+
 Изменения в nginx 0.4.9                                           13.10.2006
 
     *) Добавление: параметр set в команде SSI include.
--- a/auto/sources
+++ b/auto/sources
@@ -20,6 +20,7 @@ CORE_DEPS="src/core/nginx.h \
            src/core/ngx_inet.h \
            src/core/ngx_file.h \
            src/core/ngx_crc.h \
+           src/core/ngx_crc32.h \
            src/core/ngx_rbtree.h \
            src/core/ngx_radix_tree.h \
            src/core/ngx_times.h \
@@ -42,6 +43,7 @@ CORE_SRCS="src/core/nginx.c \
            src/core/ngx_parse.c \
            src/core/ngx_inet.c \
            src/core/ngx_file.c \
+           src/core/ngx_crc32.c \
            src/core/ngx_rbtree.c \
            src/core/ngx_radix_tree.c \
            src/core/ngx_times.c \
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -283,6 +283,10 @@ main(int argc, char *const *argv)
 
     ngx_os_status(cycle->log);
 
+    if (ngx_crc32_init(cycle->pool) != NGX_OK) {
+        return 1;
+    }
+
     ngx_cycle = cycle;
 
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.4.9"
+#define NGINX_VERSION      "0.4.10"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -49,6 +49,8 @@
 #define ngx_signal_helper(n)     SIG##n
 #define ngx_signal_value(n)      ngx_signal_helper(n)
 
+#define ngx_random               random
+
 /* TODO: #ifndef */
 #define NGX_SHUTDOWN_SIGNAL      QUIT
 #define NGX_TERMINATE_SIGNAL     TERM
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -57,6 +57,7 @@ typedef void (*ngx_connection_handler_pt
 #include <ngx_file.h>
 #include <ngx_files.h>
 #include <ngx_crc.h>
+#include <ngx_crc32.h>
 #if (NGX_PCRE)
 #include <ngx_regex.h>
 #endif
--- a/src/core/ngx_crc.h
+++ b/src/core/ngx_crc.h
@@ -8,10 +8,14 @@
 #define _NGX_CRC_H_INCLUDED_
 
 
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
 /* 32-bit crc16 */
 
 static ngx_inline uint32_t
-ngx_crc(char *data, size_t len)
+ngx_crc(u_char *data, size_t len)
 {
     uint32_t  sum;
 
new file mode 100644
--- /dev/null
+++ b/src/core/ngx_crc32.c
@@ -0,0 +1,128 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * The code and lookup tables are based on the algorithm
+ * described at http://www.w3.org/TR/PNG/
+ *
+ * The 256 element lookup table takes 1024 bytes, and it may be completely
+ * cached after processing about 30-60 bytes.  So for short messages
+ * we use the 16 element lookup table that takes only 64 bytes and align it
+ * to CPU cache line size.  Of course, the small table adds code inside
+ * CRC32 cycle, but cache misses overhead is bigger than overhead of
+ * the additional code.  For example, ngx_crc32_short() of 16 byte message
+ * takes half as much CPU clocks than ngx_crc32_long().
+ */
+
+
+static uint32_t  ngx_crc32_table16[] = {
+    0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+    0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+    0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+    0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+};
+
+
+uint32_t  ngx_crc32_table256[] = {
+    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+    0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+    0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+    0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+    0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+    0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+    0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+    0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+    0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+    0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+    0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+    0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+    0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+    0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+    0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+    0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+    0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+    0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+
+uint32_t *ngx_crc32_table_short = ngx_crc32_table16;
+
+
+ngx_int_t
+ngx_crc32_init(ngx_pool_t *pool)
+{
+    void  *p;
+
+    if (((uintptr_t) ngx_crc32_table_short
+          & ~((uintptr_t) ngx_cacheline_size - 1))
+        == (uintptr_t) ngx_crc32_table_short)
+    {
+        return NGX_OK;
+    }
+
+    p = ngx_palloc(pool, 16 * sizeof(uint32_t) + ngx_cacheline_size);
+    if (p == NULL) {
+        return NGX_ERROR;
+    }
+
+    p = ngx_align_ptr(p, ngx_cacheline_size);
+
+    ngx_memcpy(p, ngx_crc32_table16, 16 * sizeof(uint32_t));
+
+    ngx_crc32_table_short = p;
+
+    return NGX_OK;
+}
new file mode 100644
--- /dev/null
+++ b/src/core/ngx_crc32.h
@@ -0,0 +1,55 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_CRC32_H_INCLUDED_
+#define _NGX_CRC32_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+extern uint32_t  *ngx_crc32_table_short;
+extern uint32_t   ngx_crc32_table256[];
+
+
+static ngx_inline uint32_t
+ngx_crc32_short(u_char *p, size_t len)
+{
+    u_char    c;
+    uint32_t  crc;
+
+    crc = 0xffffffff;
+
+    while (len--) {
+        c = *p++;
+        crc = ngx_crc32_table_short[(crc ^ (c & 0xf)) & 0xf] ^ (crc >> 4);
+        crc = ngx_crc32_table_short[(crc ^ (c >> 4)) & 0xf] ^ (crc >> 4);
+    }
+
+    return crc ^ 0xffffffff;
+}
+
+
+static ngx_inline uint32_t
+ngx_crc32_long(u_char *p, size_t len)
+{
+    uint32_t  crc;
+
+    crc = 0xffffffff;
+
+    while (len--) {
+        crc = ngx_crc32_table256[(crc ^ *p++) & 0xff] ^ (crc >> 8);
+    }
+
+    return crc ^ 0xffffffff;
+}
+
+
+ngx_int_t ngx_crc32_init(ngx_pool_t *pool);
+
+
+#endif /* _NGX_CRC32_H_INCLUDED_ */
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -9,7 +9,7 @@
 
 
 static ngx_atomic_uint_t  ngx_temp_number;
-static ngx_atomic_uint_t  ngx_random;
+static ngx_atomic_uint_t  ngx_random_number;
 
 
 ssize_t
@@ -216,7 +216,7 @@ void
 ngx_init_temp_number(void)
 {
     ngx_temp_number = 0;
-    ngx_random = 123456;
+    ngx_random_number = 123456;
 }
 
 
@@ -224,7 +224,7 @@ ngx_atomic_uint_t
 ngx_next_temp_number(ngx_uint_t collision)
 {
     if (collision) {
-        ngx_temp_number += ngx_random;
+        ngx_temp_number += ngx_random_number;
     }
 
     return ngx_temp_number++;
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -593,7 +593,7 @@ ngx_atotm(u_char *line, size_t n)
 ngx_int_t
 ngx_hextoi(u_char *line, size_t n)
 {
-    u_char     ch;
+    u_char     c, ch;
     ngx_int_t  value;
 
     if (n == 0) {
@@ -608,13 +608,10 @@ ngx_hextoi(u_char *line, size_t n)
             continue;
         }
 
-        if (ch >= 'A' && ch <= 'F') {
-            value = value * 16 + (ch - 'A' + 10);
-            continue;
-        }
+        c = (u_char) (ch | 0x20);
 
-        if (ch >= 'a' && ch <= 'f') {
-            value = value * 16 + (ch - 'a' + 10);
+        if (c >= 'a' && c <= 'f') {
+            value = value * 16 + (c - 'a' + 10);
             continue;
         }
 
--- a/src/http/modules/ngx_http_charset_filter_module.c
+++ b/src/http/modules/ngx_http_charset_filter_module.c
@@ -250,6 +250,10 @@ ngx_http_charset_header_filter(ngx_http_
                 vv = ngx_http_get_indexed_variable(r,
                                                charset - NGX_HTTP_CHARSET_VAR);
 
+                if (vv == NULL || vv->not_found) {
+                    return NGX_ERROR;
+                }
+
                 charset = ngx_http_charset_get_charset(charsets, n,
                                                        (ngx_str_t *) vv);
             }
@@ -293,6 +297,10 @@ ngx_http_charset_header_filter(ngx_http_
             vv = ngx_http_get_indexed_variable(r,
                                         source_charset - NGX_HTTP_CHARSET_VAR);
 
+            if (vv == NULL || vv->not_found) {
+                return NGX_ERROR;
+            }
+
             source_charset = ngx_http_charset_get_charset(charsets, n,
                                                           (ngx_str_t *) vv);
         }
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -214,8 +214,12 @@ ngx_http_flv_handler(ngx_http_request_t 
 
         out[0].buf = b;
         out[0].next = &out[1];
+
+    } else {
+        r->allow_ranges = 1;
     }
 
+
     b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
     if (b == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
--- a/src/http/modules/ngx_http_map_module.c
+++ b/src/http/modules/ngx_http_map_module.c
@@ -115,6 +115,11 @@ ngx_http_map_variable(ngx_http_request_t
 
     vv = ngx_http_get_flushed_variable(r, map->index);
 
+    if (vv == NULL || vv->not_found) {
+        *v = *map->default_value;
+        return NGX_OK;
+    }
+
     len = vv->len;
 
     if (len && map->hostnames && vv->data[len - 1] == '.') {
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -1554,7 +1554,7 @@ ngx_http_ssi_get_variable(ngx_http_reque
             if (part->next == NULL) {
                 break;
             }
-  
+
             part = part->next;
             var = part->elts;
             i = 0;
@@ -1843,7 +1843,7 @@ ngx_http_ssi_include(ngx_http_request_t 
     ngx_str_t                   *uri, *file, *wait, *set, *stub, args;
     ngx_buf_t                   *b;
     ngx_uint_t                   flags, i;
-    ngx_chain_t                 *cl, *tl, **ll;
+    ngx_chain_t                 *cl, *tl, **ll, *out;
     ngx_http_request_t          *sr;
     ngx_http_ssi_var_t          *var;
     ngx_http_ssi_ctx_t          *mctx;
@@ -1947,7 +1947,7 @@ ngx_http_ssi_include(ngx_http_request_t 
 
         if (bl[i].count++) {
 
-            ll = (ngx_chain_t **) &psr->data;
+            ll = &out;
 
             for (tl = bl[i].bufs; tl; tl = tl->next) {
 
@@ -1979,6 +1979,8 @@ ngx_http_ssi_include(ngx_http_request_t 
                 ll = &cl->next;
             }
 
+            psr->data = out;
+
         } else {
             psr->data = bl[i].bufs;
         }
--- a/src/http/modules/ngx_http_userid_filter_module.c
+++ b/src/http/modules/ngx_http_userid_filter_module.c
@@ -348,10 +348,12 @@ ngx_http_userid_set_uid(ngx_http_request
                 if (r->in_addr == 0) {
                     slen = sizeof(struct sockaddr_in);
                     if (getsockname(r->connection->fd,
-                                    (struct sockaddr *) &sin, &slen) == -1)
+                                    (struct sockaddr *) &sin, &slen)
+                        == -1)
                     {
-                        ngx_log_error(NGX_LOG_CRIT, r->connection->log,
-                                      ngx_socket_errno, "getsockname() failed");
+                        ngx_connection_error(r->connection, ngx_socket_errno,
+                                             "getsockname() failed");
+                        return NGX_ERROR;
                     }
 
                     r->in_addr = sin.sin_addr.s_addr;
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -17,7 +17,7 @@ our @EXPORT = qw(
     HTTP_SERVER_ERROR
 );
 
-our $VERSION = '0.4.9';
+our $VERSION = '0.4.10';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -537,6 +537,8 @@ ngx_http_parse_header_line(ngx_http_requ
         sw_header_almost_done
     } state;
 
+    /* the last '\0' is not needed because string is zero terminated */
+
     static u_char  lowcase[] =
         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
         "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0"
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1167,7 +1167,7 @@ ngx_http_upstream_process_header(ngx_eve
 
             if (hh && hh->redirect) {
                 if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
-                    ngx_http_finalize_request(r, 
+                    ngx_http_finalize_request(r,
                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
                     return;
                 }
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -749,8 +749,7 @@ ngx_http_variable_server_addr(ngx_http_r
     if (r->in_addr == 0) {
         len = sizeof(struct sockaddr_in);
         if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) {
-            ngx_log_error(NGX_LOG_CRIT, c->log,
-                          ngx_socket_errno, "getsockname() failed");
+            ngx_connection_error(c, ngx_socket_errno, "getsockname() failed");
             return NGX_ERROR;
         }
 
--- a/src/imap/ngx_imap.h
+++ b/src/imap/ngx_imap.h
@@ -87,6 +87,10 @@ typedef struct {
     ngx_str_t               imap_starttls_capability;
     ngx_str_t               imap_starttls_only_capability;
 
+    ngx_str_t               server_name;
+
+    ngx_uint_t              auth_methods;
+
     ngx_array_t             pop3_capabilities;
     ngx_array_t             imap_capabilities;
 
@@ -149,10 +153,12 @@ typedef struct {
     unsigned                backslash:1;
     unsigned                no_sync_literal:1;
     unsigned                starttls:1;
+    unsigned                auth_method:1;
 
     ngx_str_t               login;
     ngx_str_t               passwd;
 
+    ngx_str_t               salt;
     ngx_str_t               tag;
     ngx_str_t               tagged_line;
 
@@ -179,29 +185,37 @@ typedef struct {
 } ngx_imap_log_ctx_t;
 
 
-#define NGX_POP3_USER       1
-#define NGX_POP3_PASS       2
-#define NGX_POP3_CAPA       3
-#define NGX_POP3_QUIT       4
-#define NGX_POP3_NOOP       5
-#define NGX_POP3_STLS       6
-#define NGX_POP3_APOP       7
-#define NGX_POP3_STAT       8
-#define NGX_POP3_LIST       9
-#define NGX_POP3_RETR       10
-#define NGX_POP3_DELE       11
-#define NGX_POP3_RSET       12
-#define NGX_POP3_TOP        13
-#define NGX_POP3_UIDL       14
+#define NGX_POP3_USER        1
+#define NGX_POP3_PASS        2
+#define NGX_POP3_CAPA        3
+#define NGX_POP3_QUIT        4
+#define NGX_POP3_NOOP        5
+#define NGX_POP3_STLS        6
+#define NGX_POP3_APOP        7
+#define NGX_POP3_STAT        8
+#define NGX_POP3_LIST        9
+#define NGX_POP3_RETR        10
+#define NGX_POP3_DELE        11
+#define NGX_POP3_RSET        12
+#define NGX_POP3_TOP         13
+#define NGX_POP3_UIDL        14
 
 
-#define NGX_IMAP_LOGIN      1
-#define NGX_IMAP_LOGOUT     2
-#define NGX_IMAP_CAPABILITY 3
-#define NGX_IMAP_NOOP       4
-#define NGX_IMAP_STARTTLS   5
+#define NGX_IMAP_LOGIN       1
+#define NGX_IMAP_LOGOUT      2
+#define NGX_IMAP_CAPABILITY  3
+#define NGX_IMAP_NOOP        4
+#define NGX_IMAP_STARTTLS    5
+
+#define NGX_IMAP_NEXT        6
 
-#define NGX_IMAP_NEXT       6
+
+#define NGX_IMAP_AUTH_PLAIN  0
+#define NGX_IMAP_AUTH_APOP   1
+
+
+#define NGX_IMAP_AUTH_PLAIN_ENABLED  0x0002
+#define NGX_IMAP_AUTH_APOP_ENABLED   0x0004
 
 
 #define NGX_IMAP_PARSE_INVALID_COMMAND  20
--- a/src/imap/ngx_imap_auth_http_module.c
+++ b/src/imap/ngx_imap_auth_http_module.c
@@ -131,7 +131,10 @@ ngx_module_t  ngx_imap_auth_http_module 
 };
 
 
-static char *ngx_imap_auth_http_protocol[] = { "pop3", "imap" };
+static char       *ngx_imap_auth_http_protocol[] = { "pop3", "imap" };
+static ngx_str_t   ngx_imap_auth_http_method[] = {
+    ngx_string("plain"), ngx_string("apop")
+};
 
 
 void
@@ -250,6 +253,12 @@ ngx_imap_auth_http_write_handler(ngx_eve
                 ngx_del_timer(wev);
             }
 
+            if (ngx_handle_write_event(wev, 0) == NGX_ERROR) {
+                ngx_close_connection(ctx->peer.connection);
+                ngx_destroy_pool(ctx->pool);
+                ngx_imap_session_internal_server_error(s);
+            }
+
             return;
         }
     }
@@ -552,6 +561,25 @@ ngx_imap_auth_http_process_headers(ngx_i
                 continue;
             }
 
+            if (len == sizeof("Auth-Pass") - 1
+                && ngx_strncasecmp(ctx->header_name_start, "Auth-Pass",
+                                   sizeof("Auth-Pass") - 1) == 0)
+            {
+                s->passwd.len = ctx->header_end - ctx->header_start;
+
+                s->passwd.data = ngx_palloc(s->connection->pool, s->passwd.len);
+                if (s->passwd.data == NULL) {
+                    ngx_close_connection(ctx->peer.connection);
+                    ngx_destroy_pool(ctx->pool);
+                    ngx_imap_session_internal_server_error(s);
+                    return;
+                }
+
+                ngx_memcpy(s->passwd.data, ctx->header_start, s->passwd.len);
+
+                continue;
+            }
+
             if (len == sizeof("Auth-Wait") - 1
                 && ngx_strncasecmp(ctx->header_name_start, "Auth-Wait",
                                    sizeof("Auth-Wait") - 1) == 0)
@@ -608,6 +636,15 @@ ngx_imap_auth_http_process_headers(ngx_i
                 return;
             }
 
+            if (s->passwd.data == NULL) {
+                ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
+                              "auth http server %V did not send password",
+                              &ctx->peer.peers->peer[0].name);
+                ngx_destroy_pool(ctx->pool);
+                ngx_imap_session_internal_server_error(s);
+                return;
+            }
+
             peers = ngx_pcalloc(s->connection->pool, sizeof(ngx_peers_t));
             if (peers == NULL) {
                 ngx_destroy_pool(ctx->pool);
@@ -725,6 +762,8 @@ ngx_imap_auth_sleep_handler(ngx_event_t 
             s->connection->read->handler = ngx_imap_auth_state;
         }
 
+        s->auth_method = NGX_IMAP_AUTH_PLAIN;
+
         c->log->action = "in auth state";
 
         ngx_imap_send(s->connection->write);
@@ -1001,6 +1040,7 @@ ngx_imap_auth_http_create_request(ngx_im
           + sizeof("Auth-Method: plain" CRLF) - 1
           + sizeof("Auth-User: ") - 1 + login.len + sizeof(CRLF) - 1
           + sizeof("Auth-Pass: ") - 1 + passwd.len + sizeof(CRLF) - 1
+          + sizeof("Auth-Salt: ") - 1 + s->salt.len
           + sizeof("Auth-Protocol: imap" CRLF) - 1
           + sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN
                 + sizeof(CRLF) - 1
@@ -1023,8 +1063,12 @@ ngx_imap_auth_http_create_request(ngx_im
                          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-Method: ",
+                         sizeof("Auth-Method: ") - 1);
+    b->last = ngx_cpymem(b->last,
+                         ngx_imap_auth_http_method[s->auth_method].data,
+                         ngx_imap_auth_http_method[s->auth_method].len);
+    *b->last++ = CR; *b->last++ = LF;
 
     b->last = ngx_cpymem(b->last, "Auth-User: ", sizeof("Auth-User: ") - 1);
     b->last = ngx_copy(b->last, login.data, login.len);
@@ -1034,6 +1078,13 @@ ngx_imap_auth_http_create_request(ngx_im
     b->last = ngx_copy(b->last, passwd.data, passwd.len);
     *b->last++ = CR; *b->last++ = LF;
 
+    if (s->salt.len) {
+        b->last = ngx_cpymem(b->last, "Auth-Salt: ", sizeof("Auth-Salt: ") - 1);
+        b->last = ngx_copy(b->last, s->salt.data, s->salt.len);
+
+        s->passwd.data = NULL;
+    }
+
     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],
--- a/src/imap/ngx_imap_core_module.c
+++ b/src/imap/ngx_imap_core_module.c
@@ -45,6 +45,13 @@ static ngx_str_t  ngx_imap_default_capab
 };
 
 
+static ngx_conf_bitmask_t  ngx_imap_auth_methods[] = {
+    { ngx_string("plain"), NGX_IMAP_AUTH_PLAIN_ENABLED },
+    { ngx_string("apop"), NGX_IMAP_AUTH_APOP_ENABLED },
+    { ngx_null_string, 0 }
+};
+
+
 static ngx_command_t  ngx_imap_core_commands[] = {
 
     { ngx_string("server"),
@@ -103,6 +110,20 @@ static ngx_command_t  ngx_imap_core_comm
       offsetof(ngx_imap_core_srv_conf_t, imap_capabilities),
       NULL },
 
+    { ngx_string("server_name"),
+      NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      NGX_IMAP_SRV_CONF_OFFSET,
+      offsetof(ngx_imap_core_srv_conf_t, server_name),
+      NULL },
+
+    { ngx_string("auth"),
+      NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_1MORE,
+      ngx_conf_set_bitmask_slot,
+      NGX_IMAP_SRV_CONF_OFFSET,
+      offsetof(ngx_imap_core_srv_conf_t, auth_methods),
+      &ngx_imap_auth_methods },
+
       ngx_null_command
 };
 
@@ -210,6 +231,30 @@ ngx_imap_core_merge_srv_conf(ngx_conf_t 
     ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0);
 
 
+    ngx_conf_merge_bitmask_value(conf->auth_methods, prev->auth_methods,
+                           (NGX_CONF_BITMASK_SET|NGX_IMAP_AUTH_PLAIN_ENABLED));
+
+
+    ngx_conf_merge_str_value(conf->server_name, prev->server_name, "");
+
+    if (conf->server_name.len == 0) {
+        conf->server_name.data = ngx_palloc(cf->pool, NGX_MAXHOSTNAMELEN);
+        if (conf->server_name.data == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        if (gethostname((char *) conf->server_name.data, NGX_MAXHOSTNAMELEN)
+            == -1)
+        {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
+                               "gethostname() failed");
+            return NGX_CONF_ERROR;
+        }
+
+        conf->server_name.len = ngx_strlen(conf->server_name.data);
+    }
+
+
     if (conf->pop3_capabilities.nelts == 0) {
         conf->pop3_capabilities = prev->pop3_capabilities;
     }
--- a/src/imap/ngx_imap_handler.c
+++ b/src/imap/ngx_imap_handler.c
@@ -233,6 +233,7 @@ ngx_imap_ssl_handshake_handler(ngx_conne
 static void
 ngx_imap_init_session(ngx_connection_t *c)
 {
+    u_char                    *p;
     ngx_imap_session_t        *s;
     ngx_imap_core_srv_conf_t  *cscf;
 
@@ -253,6 +254,35 @@ ngx_imap_init_session(ngx_connection_t *
 
     s->out = greetings[s->protocol];
 
+    if ((cscf->auth_methods & NGX_IMAP_AUTH_APOP_ENABLED)
+        && s->protocol == NGX_IMAP_POP3_PROTOCOL)
+    {
+        s->salt.data = ngx_palloc(c->pool,
+                                 sizeof(" <18446744073709551616.@>" CRLF) - 1
+                                 + NGX_TIME_T_LEN
+                                 + cscf->server_name.len);
+        if (s->salt.data == NULL) {
+            ngx_imap_session_internal_server_error(s);
+            return;
+        }
+
+        s->salt.len = ngx_sprintf(s->salt.data, "<%ul.%T@%V>" CRLF,
+                                  ngx_random(), ngx_time(), &cscf->server_name)
+                     - s->salt.data;
+
+        s->out.data = ngx_palloc(c->pool, greetings[0].len + 1 + s->salt.len);
+        if (s->out.data == NULL) {
+            ngx_imap_session_internal_server_error(s);
+            return;
+        }
+
+        p = ngx_cpymem(s->out.data, greetings[0].data, greetings[0].len - 2);
+        *p++ = ' ';
+        p = ngx_cpymem(p, s->salt.data, s->salt.len);
+
+        s->out.len = p - s->out.data;
+    }
+
     ngx_add_timer(c->read, cscf->timeout);
 
     if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
@@ -726,6 +756,56 @@ ngx_pop3_auth_state(ngx_event_t *rev)
                 text = cscf->pop3_capability.data;
                 break;
 
+            case NGX_POP3_APOP:
+                cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
+
+                if ((cscf->auth_methods & NGX_IMAP_AUTH_APOP_ENABLED)
+                    && 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,
+                                   "pop3 apop: \"%V\" \"%V\"",
+                                   &s->login, &s->passwd);
+
+                    s->auth_method = NGX_IMAP_AUTH_APOP;
+
+                    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;
+
+                } else {
+                    rc = NGX_IMAP_PARSE_INVALID_COMMAND;
+                }
+
+                break;
+
             case NGX_POP3_QUIT:
                 s->quit = 1;
                 break;
@@ -763,8 +843,6 @@ ngx_pop3_auth_state(ngx_event_t *rev)
 
             case NGX_POP3_PASS:
                 if (s->args.nelts == 1) {
-                    /* STUB */ s->imap_state = ngx_pop3_start;
-
                     arg = s->args.elts;
                     s->passwd.len = arg[0].len;
                     s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
--- a/src/imap/ngx_imap_parse.c
+++ b/src/imap/ngx_imap_parse.c
@@ -429,6 +429,10 @@ ngx_int_t ngx_pop3_parse_command(ngx_ima
                     {
                         s->command = NGX_POP3_PASS;
 
+                    } else if (c0 == 'A' && c1 == 'P' && c2 == 'O' && c3 == 'P')
+                    {
+                        s->command = NGX_POP3_APOP;
+
                     } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T')
                     {
                         s->command = NGX_POP3_QUIT;
@@ -496,12 +500,20 @@ ngx_int_t ngx_pop3_parse_command(ngx_ima
         case sw_argument:
             switch (ch) {
 
-         /*
-          * the space should be considered part of the at username
-          * or password, but not of argument in other commands
-          *
-          * case ' ':
-          */
+            case ' ':
+
+                /*
+                 * the space should be considered as part of the at username
+                 * or password, but not of argument in other commands
+                 */
+
+                if (s->command == NGX_POP3_USER
+                    || s->command == NGX_POP3_PASS)
+                {
+                    break;
+                }
+
+                /* fall through */
 
             case CR:
             case LF:
--- a/src/os/unix/ngx_posix_init.c
+++ b/src/os/unix/ngx_posix_init.c
@@ -61,6 +61,8 @@ ngx_os_init(ngx_log_t *log)
     ngx_inherited_nonblocking = 0;
 #endif
 
+    srandom(ngx_time());
+
     return NGX_OK;
 }