changeset 645:4946078f0a79 release-0.3.44

nginx-0.3.44-RELEASE import *) Feature: the "wait" parameter in the "include" SSI command. *) Feature: the Ukrainian and Byelorussian characters were added to koi-win conversion table. *) Bugfix: in the SSI.
author Igor Sysoev <igor@sysoev.ru>
date Thu, 04 May 2006 15:32:46 +0000
parents 610ff734a8cc
children f198dec3e3af
files auto/feature auto/include conf/koi-win conf/nginx.conf docs/xml/nginx/changes.xml src/core/nginx.h src/core/ngx_buf.c src/core/ngx_conf_file.c src/core/ngx_conf_file.h src/core/ngx_log.h src/http/modules/ngx_http_addition_filter_module.c src/http/modules/ngx_http_autoindex_module.c src/http/modules/ngx_http_empty_gif_module.c src/http/modules/ngx_http_index_module.c src/http/modules/ngx_http_log_module.c src/http/modules/ngx_http_memcached_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/ngx_http_ssi_filter_module.h src/http/modules/ngx_http_static_module.c src/http/modules/perl/nginx.pm src/http/ngx_http_core_module.c src/http/ngx_http_request.c src/mysql/ngx_mysql.c src/mysql/ngx_mysql.h src/os/unix/ngx_socket.c src/os/unix/ngx_socket.h
diffstat 26 files changed, 440 insertions(+), 131 deletions(-) [+]
line wrap: on
line diff
--- a/auto/feature
+++ b/auto/feature
@@ -14,7 +14,8 @@ END
 ngx_found=no
 
 if test -n "$ngx_feature_name"; then
-    ngx_have_feature=`echo $ngx_feature_name | tr '[a-z]' '[A-Z]'`
+    ngx_have_feature=`echo $ngx_feature_name \
+                   | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
 fi
 
 cat << END > $NGX_AUTOTEST.c
--- a/auto/include
+++ b/auto/include
@@ -35,8 +35,8 @@ if [ -x $NGX_AUTOTEST ]; then
 
     echo " found"
 
-    ngx_name=`echo $ngx_include | sed -e 's/\./_/' -e 's/\//_/' \
-                  |  tr '[a-z]' '[A-Z]'`
+    ngx_name=`echo $ngx_include \
+              | tr abcdefghijklmnopqrstuvwxyz/. ABCDEFGHIJKLMNOPQRSTUVWXYZ__`
 
 
     have=NGX_HAVE_$ngx_name . auto/have_headers
--- a/conf/koi-win
+++ b/conf/koi-win
@@ -10,8 +10,22 @@ charset_map  koi8-r  windows-1251 {
     9E  B7 ; # &middot;
 
     A3  B8 ; # small yo
+    A4  BA ; # small Ukrainian ye
+
+    A6  B3 ; # small Ukrainian i
+    A7  BF ; # small Ukrainian j
+
+    AD  B4 ; # small Ukrainian soft g
+    AE  A2 ; # small Byelorussian short u
 
     B3  A8 ; # capital YO
+    B4  AA ; # capital Ukrainian YE
+
+    B6  B2 ; # capital Ukrainian I
+    B7  AF ; # capital Ukrainian J
+
+    BD  A5 ; # capital Ukrainian soft G
+    BE  A1 ; # capital Byelorussian short U
 
     BF  A9 ; # (C)
 
--- a/conf/nginx.conf
+++ b/conf/nginx.conf
@@ -26,9 +26,10 @@ http {
 
     sendfile        on;
     #tcp_nopush     on;
-    #tcp_nodelay    on;
 
     #keepalive_timeout  0;
+    keepalive_timeout  65;
+    tcp_nodelay        on;
 
     #gzip  on;
 
@@ -60,7 +61,8 @@ http {
         #    include        conf/fastcgi_params;
         #}
 
-        # deny access to .htaccess files
+        # deny access to .htaccess files, if Apache's document root
+        # concurs with nginx's one
         #
         #location ~ /\.ht {
         #    deny  all;
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -9,6 +9,39 @@
 <title lang="en">nginx changelog</title>
 
 
+<changes ver="0.3.44" date="04.05.2006">
+
+<change type="feature">
+<para lang="ru">
+параметр wait в команде SSI inlcude.
+</para>
+<para lang="en">
+the "wait" parameter in the SSI "include" command.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+в таблицу перекодировки koi-win добавлены украинские и белорусские символы.
+</para>
+<para lang="en">
+the Ukrainian and Byelorussian characters were added to koi-win conversion
+table.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в SSI.
+</para>
+<para lang="en">
+in the SSI.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="0.3.43" date="26.04.2006">
 
 <change type="bugfix">
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.43"
+#define NGINX_VER          "nginx/0.3.44"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
--- a/src/core/ngx_buf.c
+++ b/src/core/ngx_buf.c
@@ -134,12 +134,6 @@ ngx_chain_add_copy(ngx_pool_t *pool, ngx
     }
 
     while (in) {
-
-        if (ngx_buf_sync_only(in->buf)) {
-            in = in->next;
-            continue;
-        }
-
         cl = ngx_alloc_chain_link(pool);
         if (cl == NULL) {
             return NGX_ERROR;
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -221,12 +221,14 @@ ngx_conf_handler(ngx_conf_t *cf, ngx_int
 {
     char           *rv;
     void           *conf, **confp;
-    ngx_uint_t      i, valid;
+    ngx_uint_t      i, multi;
     ngx_str_t      *name;
     ngx_command_t  *cmd;
 
     name = cf->args->elts;
 
+    multi = 0;
+
     for (i = 0; ngx_modules[i]; i++) {
 
         /* look up the directive in the appropriate modules */
@@ -242,132 +244,138 @@ ngx_conf_handler(ngx_conf_t *cf, ngx_int
             continue;
         }
 
-        while (cmd->name.len) {
+        for ( /* void */ ; cmd->name.len; cmd++) {
 
-            if (name->len == cmd->name.len
-                && ngx_strcmp(name->data, cmd->name.data) == 0)
-            {
-                /* is the directive's location right ? */
+            if (name->len != cmd->name.len) {
+                continue;
+            }
 
-                if (!(cmd->type & cf->cmd_type)) {
-                    ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                                  "directive \"%s\" in %s:%ui "
-                                  "is not allowed here",
-                                  name->data, cf->conf_file->file.name.data,
-                                  cf->conf_file->line);
-                    return NGX_ERROR;
+            if (ngx_strcmp(name->data, cmd->name.data) != 0) {
+                continue;
+            }
+
+
+            /* is the directive's location right ? */
+
+            if (!(cmd->type & cf->cmd_type)) {
+                if (cmd->type & NGX_CONF_MULTI) {
+                    multi = 1;
+                    continue;
                 }
 
-                if (!(cmd->type & NGX_CONF_BLOCK) && last != NGX_OK) {
-                    ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                                  "directive \"%s\" in %s:%ui "
-                                  "is not terminated by \";\"",
-                                  name->data, cf->conf_file->file.name.data,
-                                  cf->conf_file->line);
-                    return NGX_ERROR;
-                }
+                goto not_allowed;
+            }
+
+            if (!(cmd->type & NGX_CONF_BLOCK) && last != NGX_OK) {
+                ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                              "directive \"%s\" in %s:%ui "
+                              "is not terminated by \";\"",
+                              name->data, cf->conf_file->file.name.data,
+                              cf->conf_file->line);
+                return NGX_ERROR;
+            }
 
-                if ((cmd->type & NGX_CONF_BLOCK)
-                    && last != NGX_CONF_BLOCK_START)
-                {
-                    ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                                  "directive \"%s\" in %s:%ui "
-                                  "has not the opening \"{\"",
-                                  name->data, cf->conf_file->file.name.data,
-                                  cf->conf_file->line);
-                    return NGX_ERROR;
-                }
+            if ((cmd->type & NGX_CONF_BLOCK) && last != NGX_CONF_BLOCK_START) {
+                ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                              "directive \"%s\" in %s:%ui "
+                              "has not the opening \"{\"",
+                              name->data, cf->conf_file->file.name.data,
+                              cf->conf_file->line);
+                return NGX_ERROR;
+            }
 
-                /* is the directive's argument count right ? */
+            /* is the directive's argument count right ? */
 
-                if (cmd->type & NGX_CONF_ANY) {
-                    valid = 1;
+            if (!(cmd->type & NGX_CONF_ANY)) {
 
-                } else if (cmd->type & NGX_CONF_FLAG) {
+                if (cmd->type & NGX_CONF_FLAG) {
 
-                    if (cf->args->nelts == 2) {
-                        valid = 1;
-                    } else {
-                        valid = 0;
+                    if (cf->args->nelts != 2) {
+                        goto invalid;
                     }
 
                 } else if (cmd->type & NGX_CONF_1MORE) {
 
-                    if (cf->args->nelts > 1) {
-                        valid = 1;
-                    } else {
-                        valid = 0;
+                    if (cf->args->nelts < 2) {
+                        goto invalid;
                     }
 
                 } else if (cmd->type & NGX_CONF_2MORE) {
 
-                    if (cf->args->nelts > 2) {
-                        valid = 1;
-                    } else {
-                        valid = 0;
+                    if (cf->args->nelts < 3) {
+                        goto invalid;
                     }
 
-                } else if (cf->args->nelts <= NGX_CONF_MAX_ARGS
-                           && (cmd->type
-                               & argument_number[cf->args->nelts - 1]))
-                {
-                    valid = 1;
+                } else if (cf->args->nelts > NGX_CONF_MAX_ARGS) {
 
-                } else {
-                    valid = 0;
-                }
+                    goto invalid;
 
-                if (!valid) {
-                    ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                                  "invalid number arguments in "
-                                  "directive \"%s\" in %s:%ui",
-                                  name->data, cf->conf_file->file.name.data,
-                                  cf->conf_file->line);
-                    return NGX_ERROR;
+                } else if (!(cmd->type & argument_number[cf->args->nelts - 1]))
+                {
+                    goto invalid;
                 }
+            }
 
-                /* set up the directive's configuration context */
+            /* set up the directive's configuration context */
 
-                conf = NULL;
+            conf = NULL;
 
-                if (cmd->type & NGX_DIRECT_CONF) {
-                    conf = ((void **) cf->ctx)[ngx_modules[i]->index];
+            if (cmd->type & NGX_DIRECT_CONF) {
+                conf = ((void **) cf->ctx)[ngx_modules[i]->index];
 
-                } else if (cmd->type & NGX_MAIN_CONF) {
-                    conf = &(((void **) cf->ctx)[ngx_modules[i]->index]);
-
-                } else if (cf->ctx) {
-                    confp = *(void **) ((char *) cf->ctx + cmd->conf);
+            } else if (cmd->type & NGX_MAIN_CONF) {
+                conf = &(((void **) cf->ctx)[ngx_modules[i]->index]);
 
-                    if (confp) {
-                        conf = confp[ngx_modules[i]->ctx_index];
-                    }
-                }
-
-                rv = cmd->set(cf, cmd, conf);
+            } else if (cf->ctx) {
+                confp = *(void **) ((char *) cf->ctx + cmd->conf);
 
-                if (rv == NGX_CONF_OK) {
-                    return NGX_OK;
-                }
-
-                if (rv == NGX_CONF_ERROR) {
-                    return NGX_ERROR;
+                if (confp) {
+                    conf = confp[ngx_modules[i]->ctx_index];
                 }
+            }
 
-                ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                              "the \"%s\" directive %s in %s:%ui",
-                              name->data, rv, cf->conf_file->file.name.data,
-                              cf->conf_file->line);
+            rv = cmd->set(cf, cmd, conf);
 
+            if (rv == NGX_CONF_OK) {
+                return NGX_OK;
+            }
+
+            if (rv == NGX_CONF_ERROR) {
                 return NGX_ERROR;
             }
 
-            cmd++;
+            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                          "the \"%s\" directive %s in %s:%ui",
+                          name->data, rv, cf->conf_file->file.name.data,
+                          cf->conf_file->line);
+
+            return NGX_ERROR;
         }
     }
 
+    if (multi == 0) {
+        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                      "unknown directive \"%s\" in %s:%ui",
+                      name->data, cf->conf_file->file.name.data,
+                      cf->conf_file->line);
+
+        return NGX_ERROR;
+    }
+
+not_allowed:
+
     ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                  "unknown directive \"%s\" in %s:%ui",
+                  "directive \"%s\" in %s:%ui "
+                  "is not allowed here",
+                  name->data, cf->conf_file->file.name.data,
+                  cf->conf_file->line);
+    return NGX_ERROR;
+
+invalid:
+
+    ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                  "invalid number arguments in "
+                  "directive \"%s\" in %s:%ui",
                   name->data, cf->conf_file->file.name.data,
                   cf->conf_file->line);
 
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -44,6 +44,7 @@
 #define NGX_CONF_ANY         0x00000400
 #define NGX_CONF_1MORE       0x00000800
 #define NGX_CONF_2MORE       0x00001000
+#define NGX_CONF_MULTI       0x00002000
 
 #define NGX_DIRECT_CONF      0x00010000
 
--- a/src/core/ngx_log.h
+++ b/src/core/ngx_log.h
@@ -28,6 +28,7 @@
 #define NGX_LOG_DEBUG_EVENT       0x080
 #define NGX_LOG_DEBUG_HTTP        0x100
 #define NGX_LOG_DEBUG_IMAP        0x200
+#define NGX_LOG_DEBUG_MYSQL       0x400
 
 /*
  * do not forget to update debug_levels[] in src/core/ngx_log.c
--- a/src/http/modules/ngx_http_addition_filter_module.c
+++ b/src/http/modules/ngx_http_addition_filter_module.c
@@ -143,7 +143,9 @@ ngx_http_addition_body_filter(ngx_http_r
         ctx->before_body_sent = 1;
 
         if (conf->before_body.len) {
-            if (ngx_http_subrequest(r, &conf->before_body, NULL, 0) != NGX_OK) {
+            if (ngx_http_subrequest(r, &conf->before_body, NULL, 0)
+                == NGX_ERROR)
+            {
                 return NGX_ERROR;
             }
         }
@@ -165,7 +167,7 @@ ngx_http_addition_body_filter(ngx_http_r
         return rc;
     }
 
-    if (ngx_http_subrequest(r, &conf->after_body, NULL, 0) != NGX_OK) {
+    if (ngx_http_subrequest(r, &conf->after_body, NULL, 0) == NGX_ERROR) {
         return NGX_ERROR;
     }
 
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -162,7 +162,7 @@ ngx_http_autoindex_handler(ngx_http_requ
         return NGX_DECLINED;
     }
 
-    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
+    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
         return NGX_DECLINED;
     }
 
--- a/src/http/modules/ngx_http_empty_gif_module.c
+++ b/src/http/modules/ngx_http_empty_gif_module.c
@@ -112,7 +112,7 @@ ngx_http_empty_gif_handler(ngx_http_requ
     ngx_buf_t    *b;
     ngx_chain_t   out;
 
-    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
+    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
         return NGX_HTTP_NOT_ALLOWED;
     }
 
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -143,7 +143,7 @@ ngx_http_index_handler(ngx_http_request_
         return NGX_DECLINED;
     }
 
-    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
+    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
         return NGX_DECLINED;
     }
 
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -128,7 +128,8 @@ static ngx_command_t  ngx_http_log_comma
       NULL },
 
     { ngx_string("access_log"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
+                        |NGX_CONF_TAKE123,
       ngx_http_log_set_log,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -154,7 +154,7 @@ ngx_http_memcached_handler(ngx_http_requ
     ngx_http_memcached_ctx_t       *ctx;
     ngx_http_memcached_loc_conf_t  *mlcf;
 
-    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
+    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
         return NGX_HTTP_NOT_ALLOWED;
     }
 
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -188,6 +188,7 @@ static ngx_str_t ngx_http_ssi_none = ngx
 
 #define  NGX_HTTP_SSI_INCLUDE_VIRTUAL  0
 #define  NGX_HTTP_SSI_INCLUDE_FILE     1
+#define  NGX_HTTP_SSI_INCLUDE_WAIT     2
 
 #define  NGX_HTTP_SSI_ECHO_VAR         0
 #define  NGX_HTTP_SSI_ECHO_DEFAULT     1
@@ -204,6 +205,7 @@ static ngx_str_t ngx_http_ssi_none = ngx
 static ngx_http_ssi_param_t  ngx_http_ssi_include_params[] = {
     { ngx_string("virtual"), NGX_HTTP_SSI_INCLUDE_VIRTUAL, 0, 0 },
     { ngx_string("file"), NGX_HTTP_SSI_INCLUDE_FILE, 0, 0 },
+    { ngx_string("wait"), NGX_HTTP_SSI_INCLUDE_WAIT, 0, 0 },
     { ngx_null_string, 0, 0, 0 }
 };
 
@@ -361,7 +363,12 @@ ngx_http_ssi_body_filter(ngx_http_reques
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module);
 
-    if (ctx == NULL || (in == NULL && ctx->in == NULL && ctx->busy == NULL)) {
+    if (ctx == NULL
+        || (in == NULL
+            && ctx->buf == NULL
+            && ctx->in == NULL
+            && ctx->busy == NULL))
+    {
         return ngx_http_next_body_filter(r, in);
     }
 
@@ -373,6 +380,19 @@ ngx_http_ssi_body_filter(ngx_http_reques
         }
     }
 
+    if (ctx->wait) {
+        if (r->connection->data != r) {
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http ssi filter \"%V\" wait", &r->uri);
+            return NGX_AGAIN;
+        }
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http ssi filter \"%V\" continue", &r->uri);
+
+        ctx->wait = 0;
+    }
+
     slcf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module);
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -632,6 +652,10 @@ ngx_http_ssi_body_filter(ngx_http_reques
                     continue;
                 }
 
+                if (rc == NGX_AGAIN) {
+                    return NGX_AGAIN;
+                }
+
                 if (rc == NGX_ERROR) {
                     return NGX_ERROR;
                 }
@@ -782,8 +806,13 @@ ngx_http_ssi_output(ngx_http_request_t *
 
         cl = ctx->busy;
         ctx->busy = cl->next;
-        cl->next = ctx->free;
-        ctx->free = cl;
+
+        if (ngx_buf_in_memory(b) || b->in_file) {
+            /* add data bufs only to the free buf chain */
+
+            cl->next = ctx->free;
+            ctx->free = cl;
+        }
     }
 
     return rc;
@@ -1626,11 +1655,13 @@ static ngx_int_t
 ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
     ngx_str_t **params)
 {
-    ngx_str_t   *uri, *file, args;
+    ngx_int_t    rc;
+    ngx_str_t   *uri, *file, *wait, args;
     ngx_uint_t   flags;
 
     uri = params[NGX_HTTP_SSI_INCLUDE_VIRTUAL];
     file = params[NGX_HTTP_SSI_INCLUDE_FILE];
+    wait = params[NGX_HTTP_SSI_INCLUDE_WAIT];
 
     if (uri && file) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
@@ -1645,6 +1676,26 @@ ngx_http_ssi_include(ngx_http_request_t 
         return NGX_HTTP_SSI_ERROR;
     }
 
+    if (wait) {
+        if (uri == NULL) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "\"wait\" may not be used with file=\"%V\"",
+                          uri, file);
+            return NGX_HTTP_SSI_ERROR;
+        }
+
+        if (wait->len == 2 && ngx_strncasecmp(wait->data, "no", 2) == 0) {
+            wait = NULL;
+
+        } else if (wait->len != 3 || ngx_strncasecmp(wait->data, "yes", 3) != 0)
+        {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "invalid value \"%V\" in the \"wait\" parameter",
+                          &wait);
+            return NGX_HTTP_SSI_ERROR;
+        }
+    }
+
     if (uri == NULL) {
         uri = file;
     }
@@ -1666,11 +1717,21 @@ ngx_http_ssi_include(ngx_http_request_t 
         return NGX_HTTP_SSI_ERROR;
     }
 
-    if (ngx_http_subrequest(r, uri, &args, flags) != NGX_OK) {
+    rc = ngx_http_subrequest(r, uri, &args, flags);
+
+    if (rc == NGX_ERROR) {
         return NGX_HTTP_SSI_ERROR;
     }
 
-    return NGX_OK;
+    if (wait == NULL) {
+        return NGX_OK;
+    }
+
+    if (rc == NGX_AGAIN) {
+        ctx->wait = 1;
+    }
+
+    return rc;
 }
 
 
--- a/src/http/modules/ngx_http_ssi_filter_module.h
+++ b/src/http/modules/ngx_http_ssi_filter_module.h
@@ -61,6 +61,7 @@ typedef struct {
     unsigned                  conditional:2;
     unsigned                  output:1;
     unsigned                  output_chosen:1;
+    unsigned                  wait:1;
 
     void                     *value_buf;
     ngx_str_t                 timefmt;
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -86,7 +86,7 @@ ngx_http_static_handler(ngx_http_request
     ngx_pool_cleanup_file_t   *clnf;
     ngx_http_core_loc_conf_t  *clcf;
 
-    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
+    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
         return NGX_HTTP_NOT_ALLOWED;
     }
 
--- 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.3.23';
+our $VERSION = '0.3.43';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1168,7 +1168,7 @@ ngx_http_subrequest(ngx_http_request_t *
 
     sr = ngx_pcalloc(r->pool, sizeof(ngx_http_request_t));
     if (sr == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        return NGX_ERROR;
     }
 
     sr->signature = NGX_HTTP_MODULE;
@@ -1178,14 +1178,14 @@ ngx_http_subrequest(ngx_http_request_t *
 
     sr->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
     if (sr->ctx == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        return NGX_ERROR;
     }
 
     if (ngx_list_init(&sr->headers_out.headers, r->pool, 20,
                       sizeof(ngx_table_elt_t))
         == NGX_ERROR)
     {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        return NGX_ERROR;
     }
 
     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
@@ -1228,7 +1228,7 @@ ngx_http_subrequest(ngx_http_request_t *
     sr->http_protocol = r->http_protocol;
 
     if (ngx_http_set_exten(sr) != NGX_OK) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        return NGX_ERROR;
     }
 
     sr->main = r->main;
@@ -1251,7 +1251,7 @@ ngx_http_subrequest(ngx_http_request_t *
 
     pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t));
     if (pr == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        return NGX_ERROR;
     }
 
     pr->request = sr;
@@ -1275,10 +1275,18 @@ ngx_http_subrequest(ngx_http_request_t *
     ngx_http_handler(sr);
 
     if (!c->destroyed) {
-        sr->fast_subrequest = 0;
-
         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
                        "http subrequest done \"%V?%V\"", uri, &sr->args);
+
+        if (sr->fast_subrequest) {
+            sr->fast_subrequest = 0;
+
+            if (sr->done) {
+                return NGX_OK;
+            }
+        }
+
+        return NGX_AGAIN;
     }
 
     return NGX_OK;
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -958,7 +958,7 @@ ngx_http_read_request_header(ngx_http_re
     }
 
     if (n == 0 || n == NGX_ERROR) {
-        ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST);
+        ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
         return NGX_ERROR;
     }
 
@@ -1480,17 +1480,24 @@ ngx_http_finalize_request(ngx_http_reque
             }
 
             if (r->fast_subrequest) {
+
+                if (rc == NGX_AGAIN) {
+                    r->fast_subrequest = 0;
+                }
+
                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                            "http fast subrequest: \"%V?%V\" done",
                            &r->uri, &r->args);
                 return;
             }
 
-            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "http wake parent request: \"%V?%V\"",
-                           &pr->uri, &pr->args);
-
-            pr->write_event_handler(pr);
+            if (rc != NGX_AGAIN) {
+                ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                               "http wake parent request: \"%V?%V\"",
+                               &pr->uri, &pr->args);
+
+                pr->write_event_handler(pr);
+            }
         }
 
         return;
new file mode 100644
--- /dev/null
+++ b/src/mysql/ngx_mysql.c
@@ -0,0 +1,136 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_mysql.h>
+
+
+/* the library supports the subset of the MySQL 4.1+ protocol (version 10) */
+
+
+ngx_int_t
+ngx_mysql_connect(ngx_mysql_t *m)
+{
+    ngx_int_t  rc;
+
+#if 0
+    if (cached) {
+        return NGX_OK;
+    }
+#endif
+
+    m->peer.log->action = "connecting to mysql server";
+
+    rc = ngx_event_connect_peer(&m->peer);
+
+    if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
+        return rc;
+    }
+
+    m->peer.connection->read->handler = ngx_mysql_read_server_greeting;
+    m->peer.connection->write->handler = ngx_mysql_emtpy_handler;
+
+    ngx_add_timer(m->peer.connection->read, /* STUB */ 5000);
+    ngx_add_timer(m->peer.connection->write, /* STUB */ 5000);
+
+    return NGX_OK;
+}
+
+
+static void
+ngx_mysql_read_server_greeting(ngx_event_t *rev)
+{
+    size_t             len;
+    u_char            *p, *t;
+    ngx_mysql_t       *m;
+    ngx_connection_t  *c;
+
+    c = rev->data;
+    m = c->data;
+
+    if (rev->timedout) {
+        ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
+                      "mysql server %V timed out",
+                      &ctx->peer.peers->peer[0].name);
+
+        ngx_mysql_close(m, NGX_ERROR);
+        return;
+    }
+
+    if (m->buf == NULL) {
+        m->peer.log->action = "reading to mysql server greeting";
+
+        m->buf = ngx_create_temp(m->pool, /* STUB */ 1024);
+        if (m->buf == NULL) {
+            ngx_mysql_close(m, NGX_ERROR);
+            return;
+        }
+    }
+
+    n = ngx_recv(m->peer.connection, m->buf->pos, /* STUB */ 1024);
+
+    if (n == NGX_AGAIN) {
+        return;
+    }
+
+    if (n < 5) {
+        ngx_mysql_close(m, NGX_ERROR);
+        return;
+    }
+
+    p = m->buf->pos;
+
+    if (ngx_m24toh(p) > n - 4) {
+        ngx_log_error(NGX_LOG_ERR, rev->log, 0,
+                      "mysql server %V sent incomplete greeting packet",
+                      &ctx->peer.peers->peer[0].name);
+
+        ngx_mysql_close(m, NGX_ERROR);
+        return;
+    }
+
+    if (p[4]) < 10) {
+        ngx_log_error(NGX_LOG_ERR, rev->log, 0,
+                      "mysql server %V sent unsupported protocol version %ud",
+                      &ctx->peer.peers->peer[0].name, p[4]);
+
+        ngx_mysql_close(m, NGX_ERROR);
+        return;
+    }
+
+    len = ngx_strlen(&p[5]);
+    t = p + 5 + len + 1;
+
+    capacity = ngx_m16toh((&t[4 + 9]));
+
+    ngx_log_debug8(NGX_LOG_DEBUG_MYSQL, rev->log, 0,
+                   "mysql version: %ud, \"%s\", thread: %ud, salt: \"%s\", ",
+                   "capacity: %Xd, charset: %ud, status: %ud, salt rest \"%s\"",
+                   p[4], &p[5], ngx_m32toh(t), &t[4],
+                   capacity, t[4 + 9 + 2],
+                   ngx_m16toh((&t[4 + 9 + 2 + 1])),
+                   t[4 + 9 + 2 + 1 + 2 + 13]);
+
+    capacity &= NGX_MYSQL_LONG_PASSWORD
+                | NGX_MYSQL_CONNECT_WITH_DB
+                | NGX_MYSQL_PROTOCOL_41;
+
+}
+
+
+static void
+ngx_mysql_close(ngx_mysql_t *m, ngx_int_t rc)
+{
+    if (rc == NGX_ERROR) {
+        ngx_close_connection(m->peer.connection);
+    }
+
+    m->state = rc;
+
+    m->handler(m);
+}
new file mode 100644
--- /dev/null
+++ b/src/mysql/ngx_mysql.h
@@ -0,0 +1,36 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_MYSQL_H_INCLUDED_
+#define _NGX_MYSQL_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+typedef struct {
+    ngx_peer_connection_t   peer;
+} ngx_mysql_t;
+
+
+#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED && 0)
+
+#define ngx_m16toh(n)   (*(uint32_t *) n & 0x0000ffff)
+#define ngx_m24toh(n)   (*(uint32_t *) n & 0x00ffffff)
+#define ngx_m32toh(n)   *(uint32_t *) n
+
+#else
+
+#define ngx_m16toh(n)   (n[0] | n[1] << 8)
+#define ngx_m24toh(n)   (n[0] | n[1] << 8 | n[2] << 16)
+#define ngx_m32toh(n)   (n[0] | n[1] << 8 | n[2] << 16 | n[3] << 24)
+
+#endif
+
+
+#endif /* _NGX_MYSQL_H_INCLUDED_ */
--- a/src/os/unix/ngx_socket.c
+++ b/src/os/unix/ngx_socket.c
@@ -10,7 +10,7 @@
 
 /*
  * ioctl(FIONBIO) sets a blocking mode with the single syscall
- * while fcntl(F_SETFL, ~O_NONBLOCK) needs to learn before
+ * while fcntl(F_SETFL, !O_NONBLOCK) needs to learn before
  * the previous state using fcntl(F_GETFL).
  *
  * ioctl() and fcntl() are syscalls at least in FreeBSD 2.x, Linux 2.2
--- a/src/os/unix/ngx_socket.h
+++ b/src/os/unix/ngx_socket.h
@@ -29,9 +29,12 @@ int ngx_blocking(ngx_socket_t s);
 
 #else
 
-#define ngx_nonblocking(s)  fcntl(s, F_SETFL, O_NONBLOCK)
+#define ngx_nonblocking(s)  fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK)
 #define ngx_nonblocking_n   "fcntl(O_NONBLOCK)"
 
+#define ngx_blocking(s)     fcntl(s, F_SETFL, fcntl(s, F_GETFL) & ~O_NONBLOCK)
+#define ngx_blocking_n      "fcntl(!O_NONBLOCK)"
+
 #endif
 
 int ngx_tcp_nopush(ngx_socket_t s);