[emerg] 83583#0: unknown directive "server_tokens"

Igor Sysoev is at rambler-co.ru
Fri Nov 2 17:18:07 MSK 2007


On Fri, Nov 02, 2007 at 03:47:37PM +0200, Goncharov Yuri wrote:

> >>Да, да, интересует например ключ backup при указании серверов в секции 
> >>server {upstream}
> >
> >У меня нет уверенности, что backup достаточно стабильна для включения
> >в 0.5.x. Могу сделать в виде патч.
> >
> >
> Очень интересует. Я со своей стороны такой патч протестирую и в случае 
> негативных результатов - сразу же сообщу

patch-0.5.32-33.txt - апгрэйд до 0.5.33
patch-0.5.33-upstream.txt - новый код upstream c backup.


-- 
Игорь Сысоев
http://sysoev.ru
-------------- next part --------------
Index: src/http/ngx_http_request.c
===================================================================
--- src/http/ngx_http_request.c	(revision 857)
+++ src/http/ngx_http_request.c	(revision 935)
@@ -1205,10 +1205,10 @@
 ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
     ngx_uint_t offset)
 {
-    if (ngx_strstr(h->value.data, "close")) {
+    if (ngx_strcasestrn(h->value.data, "close", 5 - 1)) {
         r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
 
-    } else if (ngx_strstr(h->value.data, "keep-alive")) {
+    } else if (ngx_strcasestrn(h->value.data, "keep-alive", 10 - 1)) {
         r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE;
     }
 
@@ -1320,7 +1320,8 @@
     }
 
     if (r->headers_in.transfer_encoding
-        && ngx_strstr(r->headers_in.transfer_encoding->value.data, "chunked"))
+        && ngx_strcasestrn(r->headers_in.transfer_encoding->value.data,
+                           "chunked", 7 - 1))
     {
         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                       "client sent \"Transfer-Encoding: chunked\" header");
@@ -1352,7 +1353,7 @@
 
         user_agent = r->headers_in.user_agent->value.data;
 
-        ua = (u_char *) ngx_strstr(user_agent, "MSIE");
+        ua = ngx_strstrn(user_agent, "MSIE", 4 - 1);
 
         if (ua && ua + 8 < user_agent + r->headers_in.user_agent->value.len) {
 
@@ -1370,7 +1371,7 @@
 #endif
         }
 
-        if (ngx_strstr(user_agent, "Opera")) {
+        if (ngx_strstrn(user_agent, "Opera", 5 - 1)) {
             r->headers_in.opera = 1;
             r->headers_in.msie = 0;
             r->headers_in.msie4 = 0;
@@ -1378,10 +1379,10 @@
 
         if (!r->headers_in.msie && !r->headers_in.opera) {
 
-            if (ngx_strstr(user_agent, "Gecko/")) {
+            if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) {
                 r->headers_in.gecko = 1;
 
-            } else if (ngx_strstr(user_agent, "Konqueror")) {
+            } else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) {
                 r->headers_in.konqueror = 1;
             }
         }
Index: src/http/ngx_http_core_module.c
===================================================================
--- src/http/ngx_http_core_module.c	(revision 857)
+++ src/http/ngx_http_core_module.c	(revision 935)
@@ -877,7 +877,7 @@
 
         if (ngx_http_map_uri_to_path(r, &path, &root, 0) != NULL) {
             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                          "directory index of \"%V\" is forbidden", &path);
+                          "directory index of \"%s\" is forbidden", path.data);
         }
 
         ngx_http_finalize_request(r, NGX_HTTP_FORBIDDEN);
Index: src/http/ngx_http_upstream.c
===================================================================
--- src/http/ngx_http_upstream.c	(revision 857)
+++ src/http/ngx_http_upstream.c	(revision 935)
@@ -2632,7 +2632,7 @@
 
     if (r->upstream->rewrite_redirect) {
 
-        p = (u_char *) ngx_strstr(ho->value.data, "url=");
+        p = ngx_strcasestrn(ho->value.data, "url=", 4 - 1);
 
         if (p) {
             rc = r->upstream->rewrite_redirect(r, ho, p + 4 - ho->value.data);
Index: src/http/modules/ngx_http_gzip_filter_module.c
===================================================================
--- src/http/modules/ngx_http_gzip_filter_module.c	(revision 857)
+++ src/http/modules/ngx_http_gzip_filter_module.c	(revision 935)
@@ -279,7 +279,9 @@
         || r->headers_in.accept_encoding == NULL
         || (r->headers_out.content_length_n != -1
             && r->headers_out.content_length_n < conf->min_length)
-        || ngx_strstr(r->headers_in.accept_encoding->value.data, "gzip") == NULL
+        || ngx_strcasestrn(r->headers_in.accept_encoding->value.data,
+                           "gzip", 4 - 1)
+           == NULL
        )
     {
         return ngx_http_next_header_filter(r);
Index: src/http/modules/ngx_http_empty_gif_module.c
===================================================================
--- src/http/modules/ngx_http_empty_gif_module.c	(revision 857)
+++ src/http/modules/ngx_http_empty_gif_module.c	(revision 935)
@@ -127,6 +127,8 @@
 
     if (r->method == NGX_HTTP_HEAD) {
         r->headers_out.status = NGX_HTTP_OK;
+        r->headers_out.content_length_n = sizeof(ngx_empty_gif);
+        r->headers_out.last_modified_time = 23349600;
 
         return ngx_http_send_header(r);
     }
Index: src/http/modules/ngx_http_ssi_filter_module.c
===================================================================
--- src/http/modules/ngx_http_ssi_filter_module.c	(revision 857)
+++ src/http/modules/ngx_http_ssi_filter_module.c	(revision 935)
@@ -212,6 +212,7 @@
 
 #define  NGX_HTTP_SSI_ECHO_VAR         0
 #define  NGX_HTTP_SSI_ECHO_DEFAULT     1
+#define  NGX_HTTP_SSI_ECHO_ENCODING    2
 
 #define  NGX_HTTP_SSI_CONFIG_ERRMSG    0
 #define  NGX_HTTP_SSI_CONFIG_TIMEFMT   1
@@ -237,6 +238,7 @@
 static ngx_http_ssi_param_t  ngx_http_ssi_echo_params[] = {
     { ngx_string("var"), NGX_HTTP_SSI_ECHO_VAR, 1, 0 },
     { ngx_string("default"), NGX_HTTP_SSI_ECHO_DEFAULT, 0, 0 },
+    { ngx_string("encoding"), NGX_HTTP_SSI_ECHO_ENCODING, 0, 0 },
     { ngx_null_string, 0, 0, 0 }
 };
 
@@ -355,6 +357,7 @@
     ctx->value_len = slcf->value_len;
     ctx->last_out = &ctx->out;
 
+    ctx->encoding = NGX_HTTP_SSI_ENTITY_ENCODING;
     ctx->output = 1;
 
     ctx->params.elts = ctx->params_array;
@@ -2119,10 +2122,12 @@
 ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
     ngx_str_t **params)
 {
+    u_char                     *p;
+    uintptr_t                   len;
     ngx_int_t                   key;
     ngx_uint_t                  i;
     ngx_buf_t                  *b;
-    ngx_str_t                  *var, *value, text;
+    ngx_str_t                  *var, *value, *enc, text;
     ngx_chain_t                *cl;
     ngx_http_variable_value_t  *vv;
 
@@ -2170,6 +2175,69 @@
         }
     }
 
+    enc = params[NGX_HTTP_SSI_ECHO_ENCODING];
+
+    if (enc) {
+        if (enc->len == 4 && ngx_strncmp(enc->data, "none", 4) == 0) {
+
+            ctx->encoding = NGX_HTTP_SSI_NO_ENCODING;
+
+        } else if (enc->len == 3 && ngx_strncmp(enc->data, "url", 3) == 0) {
+
+            ctx->encoding = NGX_HTTP_SSI_URL_ENCODING;
+
+        } else if (enc->len == 6 && ngx_strncmp(enc->data, "entity", 6) == 0) {
+
+            ctx->encoding = NGX_HTTP_SSI_ENTITY_ENCODING;
+
+        } else {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "unknown encoding \"%V\" in the \"echo\" command",
+                          enc);
+        }
+    }
+
+    switch (ctx->encoding) {
+
+    case NGX_HTTP_SSI_NO_ENCODING:
+        break;
+
+    case NGX_HTTP_SSI_URL_ENCODING:
+        len = 2 * ngx_escape_uri(NULL, value->data, value->len,
+                                 NGX_ESCAPE_HTML);
+
+        if (len) {
+            p = ngx_palloc(r->pool, value->len + len);
+            if (p == NULL) {
+                return NGX_HTTP_SSI_ERROR;
+            }
+
+            (void) ngx_escape_uri(p, value->data, value->len, NGX_ESCAPE_HTML);
+
+            value->len += len;
+            value->data = p;
+        }
+
+        break;
+
+    case NGX_HTTP_SSI_ENTITY_ENCODING:
+        len = ngx_escape_html(NULL, value->data, value->len);
+
+        if (len) {
+            p = ngx_palloc(r->pool, value->len + len);
+            if (p == NULL) {
+                return NGX_HTTP_SSI_ERROR;
+            }
+
+            (void) ngx_escape_html(p, value->data, value->len);
+
+            value->len += len;
+            value->data = p;
+        }
+
+        break;
+    }
+
     b = ngx_calloc_buf(r->pool);
     if (b == NULL) {
         return NGX_HTTP_SSI_ERROR;
Index: src/http/modules/ngx_http_memcached_module.c
===================================================================
--- src/http/modules/ngx_http_memcached_module.c	(revision 857)
+++ src/http/modules/ngx_http_memcached_module.c	(revision 935)
@@ -425,16 +425,16 @@
     if (u->length == ctx->rest) {
 
         if (ngx_strncmp(b->last,
-                        ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END
-                                                 - ctx->rest,
-                        bytes) != 0)
+                   ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END - ctx->rest,
+                   ctx->rest)
+            != 0)
         {
             ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
                           "memcached sent invalid trailer");
         }
 
-        u->length -= bytes;
-        ctx->rest -= bytes;
+        u->length = 0;
+        ctx->rest = 0;
 
         return NGX_OK;
     }
@@ -453,7 +453,8 @@
 
     *ll = cl;
 
-    cl->buf->pos = b->last;
+    last = b->last;
+    cl->buf->pos = last;
     b->last += bytes;
     cl->buf->last = b->last;
 
@@ -461,20 +462,19 @@
                    "memcached filter bytes:%z size:%z length:%z rest:%z",
                    bytes, b->last - b->pos, u->length, ctx->rest);
 
-    if (b->last - b->pos <= (ssize_t) (u->length - NGX_HTTP_MEMCACHED_END)) {
+    if (bytes <= (ssize_t) (u->length - NGX_HTTP_MEMCACHED_END)) {
         u->length -= bytes;
         return NGX_OK;
     }
 
+    last += u->length - NGX_HTTP_MEMCACHED_END;
 
-    last = b->pos + u->length - NGX_HTTP_MEMCACHED_END;
-
     if (ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) {
         ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
                       "memcached sent invalid trailer");
     }
 
-    ctx->rest = u->length - (b->last - b->pos);
+    ctx->rest -= b->last - last;
     b->last = last;
     cl->buf->last = last;
     u->length = ctx->rest;
Index: src/http/modules/ngx_http_ssi_filter_module.h
===================================================================
--- src/http/modules/ngx_http_ssi_filter_module.h	(revision 857)
+++ src/http/modules/ngx_http_ssi_filter_module.h	(revision 935)
@@ -13,17 +13,22 @@
 #include <ngx_http.h>
 
 
-#define NGX_HTTP_SSI_MAX_PARAMS     16
+#define NGX_HTTP_SSI_MAX_PARAMS       16
 
-#define NGX_HTTP_SSI_COMMAND_LEN    32
-#define NGX_HTTP_SSI_PARAM_LEN      32
-#define NGX_HTTP_SSI_PARAMS_N       4
+#define NGX_HTTP_SSI_COMMAND_LEN      32
+#define NGX_HTTP_SSI_PARAM_LEN        32
+#define NGX_HTTP_SSI_PARAMS_N         4
 
 
-#define NGX_HTTP_SSI_COND_IF        1
-#define NGX_HTTP_SSI_COND_ELSE      2
+#define NGX_HTTP_SSI_COND_IF          1
+#define NGX_HTTP_SSI_COND_ELSE        2
 
 
+#define NGX_HTTP_SSI_NO_ENCODING      0
+#define NGX_HTTP_SSI_URL_ENCODING     1
+#define NGX_HTTP_SSI_ENTITY_ENCODING  2
+
+
 typedef struct {
     ngx_hash_t                hash;
     ngx_hash_keys_arrays_t    commands;
@@ -60,6 +65,7 @@
     ngx_array_t              *blocks;
 
     unsigned                  conditional:2;
+    unsigned                  encoding:2;
     unsigned                  block:1;
     unsigned                  output:1;
     unsigned                  output_chosen:1;
Index: src/http/modules/ngx_http_flv_module.c
===================================================================
--- src/http/modules/ngx_http_flv_module.c	(revision 857)
+++ src/http/modules/ngx_http_flv_module.c	(revision 935)
@@ -167,7 +167,7 @@
     i = 1;
 
     if (r->args.len) {
-        p = (u_char *) ngx_strstr(r->args.data, "start=");
+        p = (u_char *) ngx_strnstr(r->args.data, "start=", r->args.len);
 
         if (p) {
             p += 6;
Index: src/http/modules/perl/nginx.pm
===================================================================
--- src/http/modules/perl/nginx.pm	(revision 857)
+++ src/http/modules/perl/nginx.pm	(revision 935)
@@ -47,7 +47,7 @@
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.5.32';
+our $VERSION = '0.5.33';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
Index: src/mail/ngx_mail_handler.c
===================================================================
--- src/mail/ngx_mail_handler.c	(revision 857)
+++ src/mail/ngx_mail_handler.c	(revision 935)
@@ -2139,7 +2139,9 @@
         return p;
     }
 
-    p = ngx_snprintf(buf, len, ", server: %V", s->addr_text);
+    p = ngx_snprintf(buf, len, "%s, server: %V",
+                     s->starttls ? " using starttls" : "",
+                     s->addr_text);
     len -= p - buf;
     buf = p;
 
Index: src/core/nginx.h
===================================================================
--- src/core/nginx.h	(revision 857)
+++ src/core/nginx.h	(revision 935)
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.5.32"
+#define NGINX_VERSION      "0.5.33"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
Index: src/core/ngx_string.c
===================================================================
--- src/core/ngx_string.c	(revision 857)
+++ src/core/ngx_string.c	(revision 935)
@@ -442,7 +442,7 @@
 
 
 /*
- * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII string only,
+ * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only,
  * and implement our own ngx_strcasecmp()/ngx_strncasecmp()
  * to avoid libc locale overhead.  Besides, we use the ngx_uint_t's
  * instead of the u_char's, because they are slightly faster.
@@ -503,6 +503,95 @@
 }
 
 
+u_char *
+ngx_strnstr(u_char *s1, char *s2, size_t len)
+{
+    u_char  c1, c2;
+    size_t  n;
+
+    c2 = *(u_char *) s2++;
+
+    n = ngx_strlen(s2);
+
+    do {
+        do {
+            if (len-- == 0) {
+                return NULL;
+            }
+
+            c1 = *s1++;
+
+            if (c1 == 0) {
+                return NULL;
+            }
+
+        } while (c1 != c2);
+
+        if (n > len) {
+            return NULL;
+        }
+
+    } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
+
+    return --s1;
+}
+
+
+/*
+ * ngx_strstrn() and ngx_strcasestrn() are intended to search for static
+ * substring with known length in null-terminated string. The argument n
+ * must be length of the second substring - 1.
+ */
+
+u_char *
+ngx_strstrn(u_char *s1, char *s2, size_t n)
+{
+    u_char  c1, c2;
+
+    c2 = *(u_char *) s2++;
+
+    do {
+        do {
+            c1 = *s1++;
+
+            if (c1 == 0) {
+                return NULL;
+            }
+
+        } while (c1 != c2);
+
+    } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
+
+    return --s1;
+}
+
+
+u_char *
+ngx_strcasestrn(u_char *s1, char *s2, size_t n)
+{
+    ngx_uint_t  c1, c2;
+
+    c2 = (ngx_uint_t) *s2++;
+    c2  = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+
+    do {
+        do {
+            c1 = (ngx_uint_t) *s1++;
+
+            if (c1 == 0) {
+                return NULL;
+            }
+
+            c1  = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+
+        } while (c1 != c2);
+
+    } while (ngx_strncasecmp(s1, (u_char *) s2, n) != 0);
+
+    return --s1;
+}
+
+
 ngx_int_t
 ngx_rstrncmp(u_char *s1, u_char *s2, size_t n)
 {
@@ -1250,6 +1339,67 @@
 }
 
 
+uintptr_t
+ngx_escape_html(u_char *dst, u_char *src, size_t size)
+{
+    u_char      ch;
+    ngx_uint_t  i, len;
+
+    if (dst == NULL) {
+
+        len = 0;
+
+        for (i = 0; i < size; i++) {
+            switch (*src++) {
+
+            case '<':
+                len += sizeof("&lt;") - 2;
+                break; 
+
+            case '>':
+                len += sizeof("&gt;") - 2;
+                break; 
+
+            case '&':
+                len += sizeof("&amp;") - 2;
+                break; 
+
+            default:
+                break;
+            }
+        }
+
+        return (uintptr_t) len;
+    }
+
+    for (i = 0; i < size; i++) {
+        ch = *src++;
+
+        switch (ch) {
+
+        case '<':
+            *dst++ = '&'; *dst++ = 'l'; *dst++ = 't'; *dst++ = ';';
+            break;
+
+        case '>':
+            *dst++ = '&'; *dst++ = 'g'; *dst++ = 't'; *dst++ = ';';
+            break;
+
+        case '&':
+            *dst++ = '&'; *dst++ = 'a'; *dst++ = 'm'; *dst++ = 'p';
+            *dst++ = ';';
+            break;
+
+        default:
+            *dst++ = ch;
+            break;
+        }
+    }
+
+    return (uintptr_t) dst;
+}
+
+
 /* ngx_sort() is implemented as insertion sort because we need stable sort */
 
 void
Index: src/core/ngx_string.h
===================================================================
--- src/core/ngx_string.h	(revision 857)
+++ src/core/ngx_string.h	(revision 935)
@@ -126,6 +126,11 @@
 ngx_int_t ngx_strcasecmp(u_char *s1, u_char *s2);
 ngx_int_t ngx_strncasecmp(u_char *s1, u_char *s2, size_t n);
 
+u_char *ngx_strnstr(u_char *s1, char *s2, size_t n);
+
+u_char *ngx_strstrn(u_char *s1, char *s2, size_t n);
+u_char *ngx_strcasestrn(u_char *s1, char *s2, size_t n);
+
 ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n);
 ngx_int_t ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n);
 ngx_int_t ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2);
@@ -162,8 +167,10 @@
 uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size,
     ngx_uint_t type);
 void ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type);
+uintptr_t ngx_escape_html(u_char *dst, u_char *src, size_t size);
 
 
+
 void ngx_sort(void *base, size_t n, size_t size,
     int (*cmp)(const void *, const void *));
 #define ngx_qsort             qsort
Index: auto/os/solaris
===================================================================
--- auto/os/solaris	(revision 857)
+++ auto/os/solaris	(revision 935)
@@ -9,6 +9,8 @@
 CORE_SRCS="$UNIX_SRCS $SOLARIS_SRCS "
 CORE_LIBS="$CORE_LIBS -lsocket -lnsl -lrt"
 
+NGX_RPATH=YES
+
 # Solaris's make does not support a blank line between target and rules
 ngx_spacer=
 
Index: auto/options
===================================================================
--- auto/options	(revision 857)
+++ auto/options	(revision 935)
@@ -22,6 +22,8 @@
 NGX_LD_OPT=
 CPU=NO
 
+NGX_RPATH=NO
+
 NGX_TEST_BUILD_DEVPOLL=NO
 NGX_TEST_BUILD_EVENTPORT=NO
 NGX_TEST_BUILD_EPOLL=NO
Index: auto/lib/pcre/conf
===================================================================
--- auto/lib/pcre/conf	(revision 857)
+++ auto/lib/pcre/conf	(revision 935)
@@ -77,7 +77,6 @@
             CORE_DEPS="$CORE_DEPS $PCRE/pcre.h"
             LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a"
             CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre.a"
-            #CORE_LIBS="$CORE_LIBS -L $PCRE/.libs -lpcre"
         ;;
 
     esac
@@ -111,7 +110,13 @@
             ngx_feature_run=no
             ngx_feature_incs="#include <pcre.h>"
             ngx_feature_path="/usr/local/include"
-            ngx_feature_libs="-L /usr/local/lib -lpcre"
+
+            if [ $NGX_RPATH = YES ]; then
+                ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lpcre"
+            else
+                ngx_feature_libs="-L/usr/local/lib -lpcre"
+            fi
+
             ngx_feature_test="pcre *re;
                               re = pcre_compile(NULL, 0, NULL, 0, NULL)"
             . auto/feature
@@ -160,7 +165,13 @@
                 ngx_feature_run=no
                 ngx_feature_incs="#include <pcre.h>"
                 ngx_feature_path="/usr/pkg/include"
-                ngx_feature_libs="-L /usr/pkg/lib -lpcre"
+
+                if [ $NGX_RPATH = YES ]; then
+                    ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lpcre"
+                else
+                    ngx_feature_libs="-L/usr/pkg/lib -lpcre"
+                fi
+
                 ngx_feature_test="pcre *re;
                                   re = pcre_compile(NULL, 0, NULL, 0, NULL)"
                 . auto/feature
@@ -185,7 +196,13 @@
                 ngx_feature_run=no
                 ngx_feature_incs="#include <pcre.h>"
                 ngx_feature_path="/opt/local/include"
-                ngx_feature_libs="-L/opt/local/lib -lpcre"
+
+                if [ $NGX_RPATH = YES ]; then
+                    ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lpcre"
+                else
+                    ngx_feature_libs="-L/opt/local/lib -lpcre"
+                fi
+
                 ngx_feature_test="pcre *re;
                                   re = pcre_compile(NULL, 0, NULL, 0, NULL)"
                 . auto/feature
-------------- next part --------------
Index: src/http/ngx_http_upstream_round_robin.c
===================================================================
--- src/http/ngx_http_upstream_round_robin.c	(revision 935)
+++ src/http/ngx_http_upstream_round_robin.c	(working copy)
@@ -9,6 +9,11 @@
 #include <ngx_http.h>
 
 
+static int ngx_http_upstream_cmp_servers(const void *one, const void *two);
+static ngx_uint_t
+ngx_http_upstream_get_peer(ngx_http_upstream_rr_peers_t *peers);
+
+
 ngx_int_t
 ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
     ngx_http_upstream_srv_conf_t *us)
@@ -16,15 +21,20 @@
     ngx_url_t                      u;
     ngx_uint_t                     i, j, n;
     ngx_http_upstream_server_t    *server;
-    ngx_http_upstream_rr_peers_t  *peers;
+    ngx_http_upstream_rr_peers_t  *peers, *backup;
 
     us->peer.init = ngx_http_upstream_init_round_robin_peer;
 
     if (us->servers) {
-        n = 0;
         server = us->servers->elts;
 
+        n = 0;
+
         for (i = 0; i < us->servers->nelts; i++) {
+            if (server[i].backup) {
+                continue;
+            }
+
             n += server[i].naddrs;
         }
 
@@ -34,6 +44,7 @@
             return NGX_ERROR;
         }
 
+        peers->single = (n == 1);
         peers->number = n;
         peers->name = &us->host;
 
@@ -41,20 +52,81 @@
 
         for (i = 0; i < us->servers->nelts; i++) {
             for (j = 0; j < server[i].naddrs; j++) {
+                if (server[i].backup) {
+                    continue;
+                }
+
                 peers->peer[n].sockaddr = server[i].addrs[j].sockaddr;
                 peers->peer[n].socklen = server[i].addrs[j].socklen;
                 peers->peer[n].name = server[i].addrs[j].name;
-                peers->peer[n].weight = server[i].weight;
-                peers->peer[n].current_weight = server[i].weight;
                 peers->peer[n].max_fails = server[i].max_fails;
                 peers->peer[n].fail_timeout = server[i].fail_timeout;
                 peers->peer[n].down = server[i].down;
+                peers->peer[n].weight = server[i].down ? 0 : server[i].weight;
+                peers->peer[n].current_weight = peers->peer[n].weight;
                 n++;
             }
         }
 
         us->peer.data = peers;
 
+        ngx_sort(&peers->peer[0], (size_t) n,
+                 sizeof(ngx_http_upstream_rr_peer_t),
+                 ngx_http_upstream_cmp_servers);
+
+        /* backup servers */
+
+        n = 0;
+
+        for (i = 0; i < us->servers->nelts; i++) {
+            if (!server[i].backup) {
+                continue;
+            }
+
+            n += server[i].naddrs;
+        }
+
+        if (n == 0) {
+            return NGX_OK;
+        }
+
+        backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
+                              + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
+        if (backup == NULL) {
+            return NGX_ERROR;
+        }
+
+        peers->single = 0;
+        backup->single = 0;
+        backup->number = n;
+        backup->name = &us->host;
+
+        n = 0;
+
+        for (i = 0; i < us->servers->nelts; i++) {
+            for (j = 0; j < server[i].naddrs; j++) {
+                if (!server[i].backup) {
+                    continue;
+                }
+
+                backup->peer[n].sockaddr = server[i].addrs[j].sockaddr;
+                backup->peer[n].socklen = server[i].addrs[j].socklen;
+                backup->peer[n].name = server[i].addrs[j].name;
+                backup->peer[n].weight = server[i].weight;
+                backup->peer[n].current_weight = server[i].weight;
+                backup->peer[n].max_fails = server[i].max_fails;
+                backup->peer[n].fail_timeout = server[i].fail_timeout;
+                backup->peer[n].down = server[i].down;
+                n++;
+            }
+        }
+
+        peers->next = backup;
+
+        ngx_sort(&backup->peer[0], (size_t) n,
+                 sizeof(ngx_http_upstream_rr_peer_t),
+                 ngx_http_upstream_cmp_servers);
+
         return NGX_OK;
     }
 
@@ -91,6 +163,7 @@
         return NGX_ERROR;
     }
 
+    peers->single = (n == 1);
     peers->number = n;
     peers->name = &us->host;
 
@@ -109,10 +182,24 @@
 
     us->peer.data = peers;
 
+    /* implicitly defined upstream has no backup servers */
+
     return NGX_OK;
 }
 
 
+static int
+ngx_http_upstream_cmp_servers(const void *one, const void *two)
+{
+    ngx_http_upstream_rr_peer_t  *first, *second;
+
+    first = (ngx_http_upstream_rr_peer_t *) one;
+    second = (ngx_http_upstream_rr_peer_t *) two;
+
+    return (first->weight < second->weight);
+}
+
+
 ngx_int_t
 ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
     ngx_http_upstream_srv_conf_t *us)
@@ -167,11 +254,13 @@
 {
     ngx_http_upstream_rr_peer_data_t  *rrp = data;
 
-    time_t                        now;
-    uintptr_t                     m;
-    ngx_uint_t                    i, n;
-    ngx_connection_t             *c;
-    ngx_http_upstream_rr_peer_t  *peer;
+    time_t                         now;
+    uintptr_t                      m;
+    ngx_int_t                      rc;
+    ngx_uint_t                     i, n;
+    ngx_connection_t              *c;
+    ngx_http_upstream_rr_peer_t   *peer;
+    ngx_http_upstream_rr_peers_t  *peers;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                    "get rr peer, try: %ui", pc->tries);
@@ -203,7 +292,7 @@
     pc->cached = 0;
     pc->connection = NULL;
 
-    if (rrp->peers->number == 1) {
+    if (rrp->peers->single) {
         peer = &rrp->peers->peer[0];
 
     } else {
@@ -214,9 +303,16 @@
 
             /* it's a first try - get a current peer */
 
+            i = pc->tries;
+
             for ( ;; ) {
-                rrp->current = rrp->peers->current;
+                rrp->current = ngx_http_upstream_get_peer(rrp->peers);
 
+                ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+                               "get rr peer, current: %ui %i",
+                               rrp->current,
+                               rrp->peers->peer[rrp->current].current_weight);
+
                 n = rrp->current / (8 * sizeof(uintptr_t));
                 m = (uintptr_t) 1 << rrp->current % (8 * sizeof(uintptr_t));
 
@@ -236,6 +332,8 @@
                             break;
                         }
 
+                        peer->current_weight = 0;
+
                     } else {
                         rrp->tried[n] |= m;
                     }
@@ -243,32 +341,24 @@
                     pc->tries--;
                 }
 
-                rrp->peers->current++;
-
-                if (rrp->peers->current >= rrp->peers->number) {
-                    rrp->peers->current = 0;
+                if (pc->tries == 0) {
+                    goto failed;
                 }
 
-                if (pc->tries) {
-                    continue;
+                if (--i == 0) {
+                    ngx_log_error(NGX_LOG_ALERT, pc->log, 0,
+                                  "round robin upstream stuck on %ui tries",
+                                  pc->tries);
+                    goto failed;
                 }
-
-                goto failed;
             }
 
             peer->current_weight--;
 
-            if (peer->current_weight == 0) {
-                peer->current_weight = peer->weight;
+        } else {
 
-                rrp->peers->current++;
+            i = pc->tries;
 
-                if (rrp->peers->current >= rrp->peers->number) {
-                    rrp->peers->current = 0;
-                }
-            }
-
-        } else {
             for ( ;; ) {
                 n = rrp->current / (8 * sizeof(uintptr_t));
                 m = (uintptr_t) 1 << rrp->current % (8 * sizeof(uintptr_t));
@@ -290,6 +380,8 @@
                             break;
                         }
 
+                        peer->current_weight = 0;
+
                     } else {
                         rrp->tried[n] |= m;
                     }
@@ -303,26 +395,19 @@
                     rrp->current = 0;
                 }
 
-                if (pc->tries) {
-                    continue;
+                if (pc->tries == 0) {
+                    goto failed;
                 }
 
-                goto failed;
+                if (--i == 0) {
+                    ngx_log_error(NGX_LOG_ALERT, pc->log, 0,
+                                  "round robin upstream stuck on %ui tries",
+                                  pc->tries);
+                    goto failed;
+                }
             }
 
             peer->current_weight--;
-
-            if (peer->current_weight == 0) {
-                peer->current_weight = peer->weight;
-
-                if (rrp->current == rrp->peers->current) {
-                    rrp->peers->current++;
-
-                    if (rrp->peers->current >= rrp->peers->number) {
-                        rrp->peers->current = 0;
-                    }
-                }
-            }
         }
 
         rrp->tried[n] |= m;
@@ -334,24 +419,107 @@
 
     /* ngx_unlock_mutex(rrp->peers->mutex); */
 
+    if (pc->tries == 1 && rrp->peers->next) {
+        pc->tries += rrp->peers->next->number;
+
+        n = rrp->peers->next->number / (8 * sizeof(uintptr_t)) + 1;
+        for (i = 0; i < n; i++) {
+             rrp->tried[i] = 0;
+        }
+    }
+
     return NGX_OK;
 
 failed:
 
+    peers = rrp->peers;
+
+    if (peers->next) {
+
+        /* ngx_unlock_mutex(peers->mutex); */
+
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers");
+
+        rrp->peers = peers->next;
+        pc->tries = rrp->peers->number;
+
+        n = rrp->peers->number / (8 * sizeof(uintptr_t)) + 1;
+        for (i = 0; i < n; i++) {
+             rrp->tried[i] = 0;
+        }
+
+        rc = ngx_http_upstream_get_round_robin_peer(pc, rrp);
+
+        if (rc != NGX_BUSY) {
+            return rc;
+        }
+
+        /* ngx_lock_mutex(peers->mutex); */
+    }
+
     /* all peers failed, mark them as live for quick recovery */
 
-    for (i = 0; i < rrp->peers->number; i++) {
-        rrp->peers->peer[i].fails = 0;
+    for (i = 0; i < peers->number; i++) {
+        peers->peer[i].fails = 0;
     }
 
-    /* ngx_unlock_mutex(rrp->peers->mutex); */
+    /* ngx_unlock_mutex(peers->mutex); */
 
-    pc->name = rrp->peers->name;
+    pc->name = peers->name;
 
     return NGX_BUSY;
 }
 
 
+static ngx_uint_t
+ngx_http_upstream_get_peer(ngx_http_upstream_rr_peers_t *peers)
+{
+    ngx_uint_t                    i, n;
+    ngx_http_upstream_rr_peer_t  *peer;
+
+    peer = &peers->peer[0];
+
+    for ( ;; ) {
+
+        for (i = 0; i < peers->number; i++) {
+
+            if (peer[i].current_weight <= 0) {
+                continue;
+            }
+
+            n = i;
+
+            while (i < peers->number - 1) {
+
+                i++;
+
+                if (peer[i].current_weight <= 0) {
+                    continue;
+                }
+
+                if (peer[n].current_weight * 1000 / peer[i].current_weight
+                    > peer[n].weight * 1000 / peer[i].weight)
+                {
+                    return n;
+                }
+
+                n = i;
+            }
+
+            if (peer[i].current_weight > 0) {
+                n = i;
+            }
+
+            return n;
+        }
+
+        for (i = 0; i < peers->number; i++) {
+            peer[i].current_weight += peer[i].weight;
+        }
+    }
+}
+
+
 void
 ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
     ngx_uint_t state)
@@ -370,7 +538,7 @@
 
     /* TODO: NGX_PEER_KEEPALIVE */
 
-    if (rrp->peers->number == 1) {
+    if (rrp->peers->single) {
         pc->tries = 0;
         return;
     }
@@ -385,8 +553,14 @@
         peer->fails++;
         peer->accessed = now;
 
-        if (peer->current_weight > 1) {
-            peer->current_weight /= 2;
+        peer->current_weight -= peer->weight / peer->max_fails;
+
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+                       "free rr peer failed: %ui %i",
+                       rrp->current, peer->current_weight);
+
+        if (peer->current_weight < 0) {
+            peer->current_weight = 0;
         }
 
         /* ngx_unlock_mutex(rrp->peers->mutex); */
Index: src/http/ngx_http_upstream.c
===================================================================
--- src/http/ngx_http_upstream.c	(revision 935)
+++ src/http/ngx_http_upstream.c	(working copy)
@@ -565,9 +565,11 @@
 
     if (rc == NGX_BUSY) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
+        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE);
+        return;
     }
 
-    if (rc == NGX_BUSY || rc == NGX_DECLINED) {
+    if (rc == NGX_DECLINED) {
         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
         return;
     }
@@ -2160,7 +2162,9 @@
         state = NGX_PEER_FAILED;
     }
 
-    u->peer.free(&u->peer, u->peer.data, state);
+    if (ft_type != NGX_HTTP_UPSTREAM_FT_NOLIVE) {
+        u->peer.free(&u->peer, u->peer.data, state);
+    }
 
     if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT,
@@ -3125,6 +3129,17 @@
             continue;
         }
 
+        if (ngx_strncmp(value[i].data, "backup", 6) == 0) {
+
+            if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
+                goto invalid;
+            }
+
+            us->backup = 1;
+
+            continue;
+        }
+
         if (ngx_strncmp(value[i].data, "down", 4) == 0) {
 
             if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) {
Index: src/http/ngx_http_upstream.h
===================================================================
--- src/http/ngx_http_upstream.h	(revision 935)
+++ src/http/ngx_http_upstream.h	(working copy)
@@ -24,6 +24,7 @@
 #define NGX_HTTP_UPSTREAM_FT_HTTP_404        0x00000040
 #define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK       0x00000080
 #define NGX_HTTP_UPSTREAM_FT_MAX_WAITING     0x00000100
+#define NGX_HTTP_UPSTREAM_FT_NOLIVE          0x40000000
 #define NGX_HTTP_UPSTREAM_FT_OFF             0x80000000
 
 
Index: src/http/ngx_http_upstream_round_robin.h
===================================================================
--- src/http/ngx_http_upstream_round_robin.h	(revision 935)
+++ src/http/ngx_http_upstream_round_robin.h	(working copy)
@@ -18,8 +18,8 @@
     socklen_t                       socklen;
     ngx_str_t                       name;
 
-    ngx_uint_t                      current_weight;
-    ngx_uint_t                      weight;
+    ngx_int_t                       current_weight;
+    ngx_int_t                       weight;
 
     ngx_uint_t                      fails;
     time_t                          accessed;
@@ -29,15 +29,16 @@
 
     ngx_uint_t                      down;          /* unsigned  down:1; */
 
-#if (NGX_SSL)
+#if (NGX_HTTP_SSL)
     ngx_ssl_session_t              *ssl_session;   /* local to a process */
 #endif
 } ngx_http_upstream_rr_peer_t;
 
 
-typedef struct {
-    ngx_uint_t                      current;
+typedef struct ngx_http_upstream_rr_peers_s  ngx_http_upstream_rr_peers_t;
 
+struct ngx_http_upstream_rr_peers_s {
+    ngx_uint_t                      single;        /* unsigned  single:1; */
     ngx_uint_t                      number;
     ngx_uint_t                      last_cached;
 
@@ -46,8 +47,10 @@
 
     ngx_str_t                      *name;
 
+    ngx_http_upstream_rr_peers_t   *next;
+
     ngx_http_upstream_rr_peer_t     peer[1];
-} ngx_http_upstream_rr_peers_t;
+};
 
 
 typedef struct {
Index: src/http/modules/ngx_http_upstream_ip_hash_module.c
===================================================================
--- src/http/modules/ngx_http_upstream_ip_hash_module.c	(revision 935)
+++ src/http/modules/ngx_http_upstream_ip_hash_module.c	(working copy)
@@ -140,7 +140,7 @@
 
     /* TODO: cached */
 
-    if (iphp->tries > 20 || iphp->rrp.peers->number == 1) {
+    if (iphp->tries > 20 || iphp->rrp.peers->single) {
         return iphp->get_rr_peer(pc, &iphp->rrp);
     }
 
@@ -160,7 +160,7 @@
         p = hash % iphp->rrp.peers->number;
 
         n = p / (8 * sizeof(uintptr_t));
-        m = 1 << p % (8 * sizeof(uintptr_t));
+        m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
 
         if (!(iphp->rrp.tried[n] & m)) {
 
@@ -195,6 +195,8 @@
         }
     }
 
+    iphp->rrp.current = p;
+
     pc->sockaddr = peer->sockaddr;
     pc->socklen = peer->socklen;
     pc->name = &peer->name;


More information about the nginx-ru mailing list