changeset 618:b9763778e212 NGINX_0_9_7

nginx 0.9.7 *) Feature: now keepalive connections may be closed premature, if there are no free worker connections. Thanks to Maxim Dounin. *) Feature: the "rotate" parameter of the "image_filter" directive. Thanks to Adam Bocim. *) Bugfix: a case when a backend in "fastcgi_pass", "scgi_pass", or "uwsgi_pass" directives is given by expression and refers to a defined upstream.
author Igor Sysoev <http://sysoev.ru>
date Mon, 04 Apr 2011 00:00:00 +0400
parents fcda3d3eb4ff
children c4e0de226b0b
files CHANGES CHANGES.ru src/core/nginx.h src/core/ngx_connection.c src/core/ngx_connection.h src/core/ngx_cycle.c src/core/ngx_cycle.h src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_image_filter_module.c src/http/modules/ngx_http_scgi_module.c src/http/modules/ngx_http_uwsgi_module.c src/http/modules/perl/nginx.pm src/http/ngx_http_request.c src/http/ngx_http_upstream.c
diffstat 14 files changed, 209 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,18 @@
 
+Changes with nginx 0.9.7                                         04 Apr 2011
+
+    *) Feature: now keepalive connections may be closed premature, if there 
+       are no free worker connections.
+       Thanks to Maxim Dounin.
+
+    *) Feature: the "rotate" parameter of the "image_filter" directive.
+       Thanks to Adam Bocim.
+
+    *) Bugfix: a case when a backend in "fastcgi_pass", "scgi_pass", or 
+       "uwsgi_pass" directives is given by expression and refers to a 
+       defined upstream.
+
+
 Changes with nginx 0.9.6                                         21 Mar 2011
 
     *) Feature: the "map" directive supports regular expressions as value 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,18 @@
 
+Изменения в nginx 0.9.7                                           04.04.2011
+
+    *) Добавление: теперь соединения в состоянии keepalive могут быть 
+       закрыты преждевременно, если у воркера нет свободных соединений.
+       Спасибо Максиму Дунину.
+
+    *) Добавление: параметр rotate директивы image_filter.
+       Спасибо Adam Bocim.
+
+    *) Исправление: ситуации, когда бэкенд в директивах fastcgi_pass, 
+       scgi_pass или uwsgi_pass задан выражением и ссылается на описанный 
+       upstream.
+
+
 Изменения в nginx 0.9.6                                           21.03.2011
 
     *) Добавление: директива map поддерживает регулярные выражения в 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         9006
-#define NGINX_VERSION      "0.9.6"
+#define nginx_version         9007
+#define NGINX_VERSION      "0.9.7"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -12,6 +12,9 @@
 ngx_os_io_t  ngx_io;
 
 
+static void ngx_drain_connections(void);
+
+
 ngx_listening_t *
 ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen)
 {
@@ -719,6 +722,11 @@ ngx_get_connection(ngx_socket_t s, ngx_l
     c = ngx_cycle->free_connections;
 
     if (c == NULL) {
+        ngx_drain_connections();
+        c = ngx_cycle->free_connections;
+    }
+
+    if (c == NULL) {
         ngx_log_error(NGX_LOG_ALERT, log, 0,
                       "%ui worker_connections are not enough",
                       ngx_cycle->connection_n);
@@ -861,6 +869,8 @@ ngx_close_connection(ngx_connection_t *c
 
 #endif
 
+    ngx_reusable_connection(c, 0);
+
     log_error = c->log_error;
 
     ngx_free_connection(c);
@@ -900,6 +910,51 @@ ngx_close_connection(ngx_connection_t *c
 }
 
 
+void
+ngx_reusable_connection(ngx_connection_t *c, ngx_uint_t reusable)
+{
+    ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
+                   "reusable connection: %ui", reusable);
+
+    if (c->reusable) {
+        ngx_queue_remove(&c->queue);
+    }
+
+    c->reusable = reusable;
+
+    if (reusable) {
+        /* need cast as ngx_cycle is volatile */
+
+        ngx_queue_insert_head(
+            (ngx_queue_t *) &ngx_cycle->reusable_connections_queue, &c->queue);
+    }
+}
+
+
+static void
+ngx_drain_connections(void)
+{
+    ngx_int_t          i;
+    ngx_queue_t       *q;
+    ngx_connection_t  *c;
+
+    for (i = 0; i < 32; i++) {
+        if (ngx_queue_empty(&ngx_cycle->reusable_connections_queue)) {
+            break;
+        }
+
+        q = ngx_queue_last(&ngx_cycle->reusable_connections_queue);
+        c = ngx_queue_data(q, ngx_connection_t, queue);
+
+        ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
+                       "reusing connection");
+
+        c->close = 1;
+        c->read->handler(c->read);
+    }
+}
+
+
 ngx_int_t
 ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,
     ngx_uint_t port)
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -135,6 +135,8 @@ struct ngx_connection_s {
 
     ngx_buf_t          *buffer;
 
+    ngx_queue_t         queue;
+
     ngx_atomic_uint_t   number;
 
     ngx_uint_t          requests;
@@ -150,6 +152,7 @@ struct ngx_connection_s {
     unsigned            destroyed:1;
 
     unsigned            idle:1;
+    unsigned            reusable:1;
     unsigned            close:1;
 
     unsigned            sendfile:1;
@@ -186,5 +189,6 @@ ngx_int_t ngx_connection_error(ngx_conne
 ngx_connection_t *ngx_get_connection(ngx_socket_t s, ngx_log_t *log);
 void ngx_free_connection(ngx_connection_t *c);
 
+void ngx_reusable_connection(ngx_connection_t *c, ngx_uint_t reusable);
 
 #endif /* _NGX_CONNECTION_H_INCLUDED_ */
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -181,6 +181,9 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
     cycle->listening.pool = pool;
 
 
+    ngx_queue_init(&cycle->reusable_connections_queue);
+
+
     cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
     if (cycle->conf_ctx == NULL) {
         ngx_destroy_pool(pool);
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -44,6 +44,8 @@ struct ngx_cycle_s {
     ngx_connection_t         *free_connections;
     ngx_uint_t                free_connection_n;
 
+    ngx_queue_t               reusable_connections_queue;
+
     ngx_array_t               listening;
     ngx_array_t               pathes;
     ngx_list_t                open_files;
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -636,12 +636,6 @@ ngx_http_fastcgi_eval(ngx_http_request_t
         return NGX_ERROR;
     }
 
-    if (url.no_port) {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "no port in upstream \"%V\"", &url.url);
-        return NGX_ERROR;
-    }
-
     u = r->upstream;
 
     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
@@ -658,6 +652,7 @@ ngx_http_fastcgi_eval(ngx_http_request_t
     } else {
         u->resolved->host = url.host;
         u->resolved->port = url.port;
+        u->resolved->no_port = url.no_port;
     }
 
     return NGX_OK;
--- a/src/http/modules/ngx_http_image_filter_module.c
+++ b/src/http/modules/ngx_http_image_filter_module.c
@@ -16,6 +16,7 @@
 #define NGX_HTTP_IMAGE_SIZE      2
 #define NGX_HTTP_IMAGE_RESIZE    3
 #define NGX_HTTP_IMAGE_CROP      4
+#define NGX_HTTP_IMAGE_ROTATE    5
 
 
 #define NGX_HTTP_IMAGE_START     0
@@ -38,12 +39,14 @@ typedef struct {
     ngx_uint_t                   filter;
     ngx_uint_t                   width;
     ngx_uint_t                   height;
+    ngx_uint_t                   angle;
     ngx_uint_t                   jpeg_quality;
 
     ngx_flag_t                   transparency;
 
     ngx_http_complex_value_t    *wcv;
     ngx_http_complex_value_t    *hcv;
+    ngx_http_complex_value_t    *acv;
     ngx_http_complex_value_t    *jqcv;
 
     size_t                       buffer_size;
@@ -58,9 +61,9 @@ typedef struct {
 
     ngx_uint_t                   width;
     ngx_uint_t                   height;
-
     ngx_uint_t                   max_width;
     ngx_uint_t                   max_height;
+    ngx_uint_t                   angle;
 
     ngx_uint_t                   phase;
     ngx_uint_t                   type;
@@ -108,7 +111,7 @@ static ngx_int_t ngx_http_image_filter_i
 static ngx_command_t  ngx_http_image_filter_commands[] = {
 
     { ngx_string("image_filter"),
-      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13,
+      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13|NGX_CONF_TAKE2,
       ngx_http_image_filter,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -492,6 +495,17 @@ ngx_http_image_process(ngx_http_request_
         return ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL);
     }
 
+    ctx->angle = ngx_http_image_filter_get_value(r, conf->acv, conf->angle);
+
+    if (conf->filter == NGX_HTTP_IMAGE_ROTATE) {
+
+        if (ctx->angle != 90 && ctx->angle != 180 && ctx->angle != 270) {
+            return NULL;
+        }
+
+        return ngx_http_image_resize(r, ctx);
+    }
+
     ctx->max_width = ngx_http_image_filter_get_value(r, conf->wcv, conf->width);
     if (ctx->max_width == 0) {
         return NULL;
@@ -506,6 +520,7 @@ ngx_http_image_process(ngx_http_request_
     if (rc == NGX_OK
         && ctx->width <= ctx->max_width
         && ctx->height <= ctx->max_height
+        && ctx->angle == 0
         && !ctx->force)
     {
         return ngx_http_image_asis(r, ctx);
@@ -710,7 +725,7 @@ ngx_http_image_resize(ngx_http_request_t
 {
     int                            sx, sy, dx, dy, ox, oy, size,
                                    colors, palette, transparent,
-                                   red, green, blue;
+                                   red, green, blue, t;
     u_char                        *out;
     ngx_buf_t                     *b;
     ngx_uint_t                     resize;
@@ -730,6 +745,7 @@ ngx_http_image_resize(ngx_http_request_t
     conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
 
     if (!ctx->force
+        && ctx->angle == 0
         && (ngx_uint_t) sx <= ctx->max_width
         && (ngx_uint_t) sy <= ctx->max_height)
     {
@@ -781,6 +797,10 @@ transparent:
 
         resize = 1;
 
+    } else if (conf->filter == NGX_HTTP_IMAGE_ROTATE) {
+
+        resize = 0;
+
     } else { /* NGX_HTTP_IMAGE_CROP */
 
         resize = 0;
@@ -829,6 +849,38 @@ transparent:
         dst = src;
     }
 
+    if (ctx->angle) {
+        src = dst;
+
+        switch (ctx->angle) {
+
+        case 90:
+        case 270:
+            dst = ngx_http_image_new(r, dy, dx, palette);
+            if (dst == NULL) {
+                gdImageDestroy(src);
+                return NULL;
+            }
+            gdImageCopyRotated(dst, src, dy/2, dx/2, 0, 0, dx, dy, ctx->angle);
+            gdImageDestroy(src);
+            break;
+
+        case 180:
+            dst = ngx_http_image_new(r, dx, dy, palette);
+            if (dst == NULL) {
+                gdImageDestroy(src);
+                return NULL;
+            }
+            gdImageCopyRotated(dst, src, dx/2, dy/2, 0, 0, dx, dy, ctx->angle);
+            gdImageDestroy(src);
+            break;
+        }
+
+        t = dx;
+        dx = dy;
+        dy = t;
+    }
+
     if (conf->filter == NGX_HTTP_IMAGE_CROP) {
 
         src = dst;
@@ -1090,6 +1142,7 @@ ngx_http_image_filter_create_conf(ngx_co
 
     conf->filter = NGX_CONF_UNSET_UINT;
     conf->jpeg_quality = NGX_CONF_UNSET_UINT;
+    conf->angle = NGX_CONF_UNSET_UINT;
     conf->transparency = NGX_CONF_UNSET;
     conf->buffer_size = NGX_CONF_UNSET_SIZE;
 
@@ -1124,6 +1177,11 @@ ngx_http_image_filter_merge_conf(ngx_con
         conf->jqcv = prev->jqcv;
     }
 
+    ngx_conf_merge_uint_value(conf->angle, prev->angle, 0);
+    if (conf->acv == NULL) {
+        conf->acv = prev->acv;
+    }
+
     ngx_conf_merge_value(conf->transparency, prev->transparency, 1);
 
     ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
@@ -1163,6 +1221,46 @@ ngx_http_image_filter(ngx_conf_t *cf, ng
         }
 
         return NGX_CONF_OK;
+
+    } else if (cf->args->nelts == 3) {
+
+        if (ngx_strcmp(value[i].data, "rotate") == 0) {
+            imcf->filter = NGX_HTTP_IMAGE_ROTATE;
+
+            ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+            ccv.cf = cf;
+            ccv.value = &value[++i];
+            ccv.complex_value = &cv;
+
+            if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+                return NGX_CONF_ERROR;
+            }
+
+            if (cv.lengths == NULL) {
+                n = ngx_http_image_filter_value(&value[i]);
+
+                if (n != 90 && n != 180 && n != 270) {
+                    goto failed;
+                }
+
+                imcf->angle = (ngx_uint_t) n;
+
+            } else {
+                imcf->acv = ngx_palloc(cf->pool,
+                                       sizeof(ngx_http_complex_value_t));
+                if (imcf->acv == NULL) {
+                    return NGX_CONF_ERROR;
+                }
+
+                *imcf->acv = cv;
+            }
+
+            return NGX_CONF_OK;
+
+        } else {
+            goto failed;
+        }
     }
 
     if (ngx_strcmp(value[i].data, "resize") == 0) {
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -458,12 +458,6 @@ ngx_http_scgi_eval(ngx_http_request_t *r
         return NGX_ERROR;
     }
 
-    if (url.no_port) {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "no port in upstream \"%V\"", &url.url);
-        return NGX_ERROR;
-    }
-
     u = r->upstream;
 
     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
@@ -480,6 +474,7 @@ ngx_http_scgi_eval(ngx_http_request_t *r
     } else {
         u->resolved->host = url.host;
         u->resolved->port = url.port;
+        u->resolved->no_port = url.no_port;
     }
 
     return NGX_OK;
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -491,12 +491,6 @@ ngx_http_uwsgi_eval(ngx_http_request_t *
         return NGX_ERROR;
     }
 
-    if (url.no_port) {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "no port in upstream \"%V\"", &url.url);
-        return NGX_ERROR;
-    }
-
     u = r->upstream;
 
     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
@@ -513,6 +507,7 @@ ngx_http_uwsgi_eval(ngx_http_request_t *
     } else {
         u->resolved->host = url.host;
         u->resolved->port = url.port;
+        u->resolved->no_port = url.no_port;
     }
 
     return NGX_OK;
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -48,7 +48,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.9.6';
+our $VERSION = '0.9.7';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -2594,6 +2594,7 @@ ngx_http_set_keepalive(ngx_http_request_
 #endif
 
     c->idle = 1;
+    ngx_reusable_connection(c, 1);
 
     if (rev->ready) {
         ngx_post_event(rev, &ngx_posted_events);
@@ -2703,6 +2704,7 @@ ngx_http_keepalive_handler(ngx_event_t *
     c->log->action = "reading client request line";
 
     c->idle = 0;
+    ngx_reusable_connection(c, 0);
 
     ngx_http_init_request(rev);
 }
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -574,6 +574,14 @@ ngx_http_upstream_init_request(ngx_http_
             }
         }
 
+        if (u->resolved->port == 0) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "no port in upstream \"%V\"", host);
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return;
+        }
+
         temp.name = *host;
 
         ctx = ngx_resolve_start(clcf->resolver, &temp);