changeset 218:1bf60f8c5c9e NGINX_0_3_56

nginx 0.3.56 *) Feature: the "dav_access" directive. *) Feature: the "if" directive supports the "-d", "!-d", "-e", "!-e", "-x", and "!-x" operators. *) Bugfix: a segmentation fault occurred if an request returned an redirect and some sent to client header lines were logged in the access log.
author Igor Sysoev <http://sysoev.ru>
date Fri, 04 Aug 2006 00:00:00 +0400
parents a346c23fc94e
children 8045828c3706
files CHANGES CHANGES.ru auto/lib/perl/conf src/core/nginx.h src/core/ngx_file.c src/core/ngx_file.h src/http/modules/ngx_http_dav_module.c src/http/modules/ngx_http_rewrite_module.c src/http/modules/ngx_http_ssl_module.c src/http/ngx_http_header_filter_module.c src/http/ngx_http_request.c src/http/ngx_http_script.c src/http/ngx_http_script.h src/os/unix/ngx_files.h
diffstat 14 files changed, 275 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,16 @@
 
+Changes with nginx 0.3.56                                        04 Aug 2006
+
+    *) Feature: the "dav_access" directive.
+
+    *) Feature: the "if" directive supports the "-d", "!-d", "-e", "!-e", 
+       "-x", and "!-x" operators.
+
+    *) Bugfix: a segmentation fault occurred if an request returned an 
+       redirect and some sent to client header lines were logged in the 
+       access log.
+
+
 Changes with nginx 0.3.55                                        28 Jul 2006
 
     *) Feature: the "stub" parameter in the "include" SSI command.
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,16 @@
 
+Изменения в nginx 0.3.56                                          04.08.2006
+
+    *) Добавление: директива dav_access.
+
+    *) Добавление: директива if поддерживает операторы "-d", "!-d", "-e", 
+       "!-e", "-x" и "!-x".
+
+    *) Исправление: при записи в access_log некоторых передаваемых клиенту 
+       строк заголовков происходил segmentation fault, если запрос 
+       возвращал редирект.
+
+
 Изменения в nginx 0.3.55                                          28.07.2006
 
     *) Добавление: параметр stub в команде SSI include.
@@ -22,7 +34,7 @@
        "client_body_in_file_only on" и делался переход к следующему бэкенду.
 
     *) Исправление: при некоторых условиях во время переконфигурации коды 
-       символов в внутри директивы charset_map могли считаться неверными; 
+       символов внутри директивы charset_map могли считаться неверными; 
        ошибка появилась в 0.3.50.
 
 
--- a/auto/lib/perl/conf
+++ b/auto/lib/perl/conf
@@ -20,6 +20,8 @@ if test -n "$NGX_PERL_VER"; then
     fi
 
     CFLAGS="$CFLAGS `$NGX_PERL -MExtUtils::Embed -e ccopts`"
+    # gcc 4.1/4.2
+    CFLAGS=`echo $CFLAGS | sed -e 's/-Wunused-value/-Wno-unused-value/'`
     ngx_perl_ldopts=`$NGX_PERL -MExtUtils::Embed -e ldopts`
 
     if $NGX_PERL -V:usemultiplicity | grep define > /dev/null; then
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.55"
+#define NGINX_VER          "nginx/0.3.56"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -166,7 +166,7 @@ ngx_create_path(ngx_file_t *file, ngx_pa
         ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
                        "temp file: \"%s\"", file->name.data);
 
-        if (ngx_create_dir(file->name.data) == NGX_FILE_ERROR) {
+        if (ngx_create_dir(file->name.data, 0700) == NGX_FILE_ERROR) {
             err = ngx_errno;
             if (err != NGX_EEXIST) {
                 ngx_log_error(NGX_LOG_CRIT, file->log, err,
@@ -184,7 +184,7 @@ ngx_create_path(ngx_file_t *file, ngx_pa
 
 
 ngx_err_t
-ngx_create_full_path(u_char *dir)
+ngx_create_full_path(u_char *dir, ngx_uint_t access)
 {
     u_char     *p, ch;
     ngx_err_t   err;
@@ -198,7 +198,7 @@ ngx_create_full_path(u_char *dir)
 
         *p = '\0';
 
-        if (ngx_create_dir(dir) == NGX_FILE_ERROR) {
+        if (ngx_create_dir(dir, access) == NGX_FILE_ERROR) {
             err = ngx_errno;
             if (err != NGX_EEXIST) {
                 return err;
@@ -370,7 +370,7 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng
     path = cycle->pathes.elts;
     for (i = 0; i < cycle->pathes.nelts; i++) {
 
-        if (ngx_create_dir(path[i]->name.data) == NGX_FILE_ERROR) {
+        if (ngx_create_dir(path[i]->name.data, 0700) == NGX_FILE_ERROR) {
             err = ngx_errno;
             if (err != NGX_EEXIST) {
                 ngx_log_error(NGX_LOG_EMERG, cycle->log, err,
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -61,7 +61,7 @@ ngx_int_t ngx_create_temp_file(ngx_file_
     ngx_pool_t *pool, ngx_uint_t persistent,ngx_uint_t mode);
 void ngx_create_hashed_filename(ngx_file_t *file, ngx_path_t *path);
 ngx_int_t ngx_create_path(ngx_file_t *file, ngx_path_t *path);
-ngx_err_t ngx_create_full_path(u_char *dir);
+ngx_err_t ngx_create_full_path(u_char *dir, ngx_uint_t access);
 ngx_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot);
 ngx_int_t ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user);
 
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -14,6 +14,7 @@
 typedef struct {
     ngx_uint_t  methods;
     ngx_flag_t  create_full_put_path;
+    ngx_uint_t  access;
 } ngx_http_dav_loc_conf_t;
 
 
@@ -22,6 +23,8 @@ static void ngx_http_dav_put_handler(ngx
 static ngx_int_t ngx_http_dav_error(ngx_http_request_t *, ngx_err_t err,
     ngx_int_t not_found, char *failed, u_char *path);
 static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r, u_char *path);
+static char *ngx_http_dav_access(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_dav_merge_loc_conf(ngx_conf_t *cf,
     void *parent, void *child);
@@ -53,6 +56,13 @@ static ngx_command_t  ngx_http_dav_comma
       offsetof(ngx_http_dav_loc_conf_t, create_full_put_path),
       NULL },
 
+    { ngx_string("dav_access"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
+      ngx_http_dav_access,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
       ngx_null_command
 };
 
@@ -214,7 +224,7 @@ ngx_http_dav_handler(ngx_http_request_t 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "http mkcol path: \"%s\"", path.data);
 
-        if (ngx_create_dir(path.data) != NGX_FILE_ERROR) {
+        if (ngx_create_dir(path.data, dlcf->access) != NGX_FILE_ERROR) {
             if (ngx_http_dav_location(r, path.data) != NGX_OK) {
                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
             }
@@ -233,6 +243,8 @@ ngx_http_dav_handler(ngx_http_request_t 
 static void
 ngx_http_dav_put_handler(ngx_http_request_t *r)
 {
+    char                     *failed;
+    u_char                   *name;
     ngx_err_t                 err;
     ngx_str_t                *temp, path;
     ngx_uint_t                status;
@@ -267,6 +279,25 @@ ngx_http_dav_put_handler(ngx_http_reques
         }
     }
 
+    dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
+
+#if !(NGX_WIN32)
+
+    if (ngx_change_file_access(temp->data, dlcf->access & ~0111)
+        == NGX_FILE_ERROR)
+    {
+        err = ngx_errno;
+        failed = ngx_change_file_access_n;
+        name = temp->data;
+
+        goto failed;
+    }
+
+#endif
+
+    failed = ngx_rename_file_n;
+    name = path.data;
+
     if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) {
         goto ok;
     }
@@ -275,10 +306,8 @@ ngx_http_dav_put_handler(ngx_http_reques
 
     if (err == NGX_ENOENT) {
 
-        dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
-
         if (dlcf->create_full_put_path) {
-            err = ngx_create_full_path(path.data);
+            err = ngx_create_full_path(path.data, dlcf->access);
 
             if (err == 0) {
                 if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) {
@@ -303,6 +332,11 @@ ngx_http_dav_put_handler(ngx_http_reques
         err = ngx_errno;
     }
 
+
+#else
+
+failed:
+
 #endif
 
     if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) {
@@ -311,9 +345,9 @@ ngx_http_dav_put_handler(ngx_http_reques
                       temp->data);
     }
 
-    ngx_http_finalize_request(r, ngx_http_dav_error(r, err, NGX_HTTP_CONFLICT,
-                                                    ngx_rename_file_n,
-                                                    path.data));
+    ngx_http_finalize_request(r,
+                  ngx_http_dav_error(r, err, NGX_HTTP_CONFLICT, failed, name));
+
     return;
 
 ok:
@@ -407,6 +441,66 @@ ngx_http_dav_location(ngx_http_request_t
 }
 
 
+static char *
+ngx_http_dav_access(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_dav_loc_conf_t *lcf = conf;
+
+    u_char      *p;
+    ngx_str_t   *value;
+    ngx_uint_t   i, right, shift;
+
+    if (lcf->access != NGX_CONF_UNSET_UINT) {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+
+    lcf->access = 0700;
+
+    for (i = 1; i < 3; i++) {
+
+        p = value[i].data;
+
+        if (ngx_strncmp(p, "user:", sizeof("user:") - 1) == 0) {
+            shift = 6;
+            p += sizeof("user:") - 1;
+
+        } else if (ngx_strncmp(p, "group:", sizeof("group:") - 1) == 0) {
+            shift = 3;
+            p += sizeof("group:") - 1;
+
+        } else if (ngx_strncmp(p, "all:", sizeof("all:") - 1) == 0) {
+            shift = 0;
+            p += sizeof("all:") - 1;
+
+        } else {
+            goto invalid;
+        }
+
+        if (ngx_strcmp(p, "rw") == 0) {
+            right = 7;
+
+        } else if (ngx_strcmp(p, "r") == 0) {
+            right = 5;
+
+        } else {
+            goto invalid;
+        }
+
+        lcf->access += right << shift;
+    }
+
+    return NGX_CONF_OK;
+
+invalid:
+
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                       "invalid value \"%V\"", &value[i]);
+    return NGX_CONF_ERROR;
+}
+
+
 static void *
 ngx_http_dav_create_loc_conf(ngx_conf_t *cf)
 {
@@ -424,6 +518,7 @@ ngx_http_dav_create_loc_conf(ngx_conf_t 
      */
 
     conf->create_full_put_path = NGX_CONF_UNSET;
+    conf->access = NGX_CONF_UNSET_UINT;
 
     return conf;
 }
@@ -441,6 +536,8 @@ ngx_http_dav_merge_loc_conf(ngx_conf_t *
     ngx_conf_merge_value(conf->create_full_put_path, prev->create_full_put_path,
                          0);
 
+    ngx_conf_merge_uint_value(conf->access, prev->access, 0600);
+
     return NGX_CONF_OK;
 }
 
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -817,11 +817,41 @@ ngx_http_rewrite_if_condition(ngx_conf_t
             return NGX_CONF_OK;
         }
 
+        if (p[1] == 'd') {
+            fop->op = ngx_http_script_file_dir;
+            return NGX_CONF_OK;
+        }
+
+        if (p[1] == 'e') {
+            fop->op = ngx_http_script_file_exists;
+            return NGX_CONF_OK;
+        }
+
+        if (p[1] == 'x') {
+            fop->op = ngx_http_script_file_exec;
+            return NGX_CONF_OK;
+        }
+
         if (p[0] == '!') {
             if (p[2] == 'f') {
                 fop->op = ngx_http_script_file_not_plain;
                 return NGX_CONF_OK;
             }
+
+            if (p[2] == 'd') {
+                fop->op = ngx_http_script_file_not_dir;
+                return NGX_CONF_OK;
+            }
+
+            if (p[2] == 'e') {
+                fop->op = ngx_http_script_file_not_exists;
+                return NGX_CONF_OK;
+            }
+
+            if (p[2] == 'x') {
+                fop->op = ngx_http_script_file_not_exec;
+                return NGX_CONF_OK;
+            }
         }
 
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -17,6 +17,7 @@ typedef u_char *(*ngx_ssl_variable_handl
 #define NGX_DEFLAUT_CIPHERS  "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"
 
 
+static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);
 static ngx_int_t ngx_http_ssl_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_ssl_client_s_dn(ngx_http_request_t *r,
@@ -384,7 +385,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
     }
 
     if (conf->verify) {
-        SSL_CTX_set_verify(conf->ssl.ctx, NGX_SSL_VERIFY, NULL);
+        SSL_CTX_set_verify(conf->ssl.ctx, NGX_SSL_VERIFY,
+                           ngx_http_ssl_verify_callback);
 
         SSL_CTX_set_verify_depth(conf->ssl.ctx, conf->verify_depth);
 
@@ -422,6 +424,13 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
 }
 
 
+static int
+ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
+{
+    return 1;
+}
+
+
 #if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
 
 static char *
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -460,6 +460,8 @@ ngx_http_header_filter(ngx_http_request_
 
         r->headers_out.location->value.len = b->last - p;
         r->headers_out.location->value.data = p;
+        r->headers_out.location->key.len = sizeof("Location: ") - 1;
+        r->headers_out.location->key.data = (u_char *) "Location: ";
 
         *b->last++ = CR; *b->last++ = LF;
     }
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1269,34 +1269,6 @@ ngx_http_process_request_header(ngx_http
         return NGX_ERROR;
     }
 
-#if (NGX_HTTP_SSL)
-
-    if (r->connection->ssl) {
-        sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
-
-        if (sscf->verify) {
-            rc = SSL_get_verify_result(r->connection->ssl->connection);
-
-            if (rc != X509_V_OK) {
-                ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
-                              "client SSL certificate verify error: %l ", rc);
-                ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR);
-                return NGX_ERROR;
-            }
-
-            if (SSL_get_peer_certificate(r->connection->ssl->connection)
-                == NULL)
-            {
-                ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
-                              "client sent no required SSL certificate");
-                ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT);
-                return NGX_ERROR;
-            }
-        }
-    }
-
-#endif
-
     if (r->headers_in.connection) {
         if (r->headers_in.connection->value.len == 5
             && ngx_strcasecmp(r->headers_in.connection->value.data, "close")
@@ -1362,6 +1334,35 @@ ngx_http_process_request_header(ngx_http
         }
     }
 
+#if (NGX_HTTP_SSL)
+
+    if (r->connection->ssl) {
+        sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
+
+        if (sscf->verify) {
+            rc = SSL_get_verify_result(r->connection->ssl->connection);
+
+            if (rc != X509_V_OK) {
+                ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+                              "client SSL certificate verify error: (%l:%s) ",
+                              rc, X509_verify_cert_error_string(rc));
+                ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR);
+                return NGX_ERROR;
+            }
+
+            if (SSL_get_peer_certificate(r->connection->ssl->connection)
+                == NULL)
+            {
+                ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+                              "client sent no required SSL certificate");
+                ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT);
+                return NGX_ERROR;
+            }
+        }
+    }
+
+#endif
+
     return NGX_OK;
 }
 
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -961,8 +961,13 @@ ngx_http_script_file_code(ngx_http_scrip
 
         switch (code->op) {
         case ngx_http_script_file_plain:
+        case ngx_http_script_file_dir:
+        case ngx_http_script_file_exists:
+        case ngx_http_script_file_exec:
              goto false;
         case ngx_http_script_file_not_plain:
+        case ngx_http_script_file_not_dir:
+        case ngx_http_script_file_not_exec:
              goto true;
         }
 
@@ -981,6 +986,54 @@ ngx_http_script_file_code(ngx_http_scrip
             goto false;
         }
         goto true;
+
+    case ngx_http_script_file_dir:
+        if (ngx_is_dir(&fi)) {
+             goto true;
+        }
+        goto false;
+
+    case ngx_http_script_file_not_dir:
+        if (ngx_is_dir(&fi)) {
+            goto false;
+        }
+        goto true;
+
+    case ngx_http_script_file_exists:
+        if (ngx_is_file(&fi) || ngx_is_dir(&fi) || ngx_is_link(&fi)) {
+             goto true;
+        }
+        goto false;
+
+    case ngx_http_script_file_not_exists:
+        if (ngx_is_file(&fi) || ngx_is_dir(&fi) || ngx_is_link(&fi)) {
+            goto false;
+        }
+        goto true;
+
+#if (NGX_WIN32)
+
+    case ngx_http_script_file_exec:
+        goto false;
+
+    case ngx_http_script_file_not_exec:
+        goto true;
+
+#else
+
+    case ngx_http_script_file_exec:
+        if (ngx_is_exec(&fi)) {
+             goto true;
+        }
+        goto false;
+
+    case ngx_http_script_file_not_exec:
+        if (ngx_is_exec(&fi)) {
+            goto false;
+        }
+        goto true;
+
+#endif
     }
 
 false:
--- a/src/http/ngx_http_script.h
+++ b/src/http/ngx_http_script.h
@@ -140,7 +140,13 @@ typedef struct {
 
 typedef enum {
     ngx_http_script_file_plain = 0,
-    ngx_http_script_file_not_plain
+    ngx_http_script_file_not_plain,
+    ngx_http_script_file_dir,
+    ngx_http_script_file_not_dir,
+    ngx_http_script_file_exists,
+    ngx_http_script_file_not_exists,
+    ngx_http_script_file_exec,
+    ngx_http_script_file_not_exec
 } ngx_http_script_file_op_e;
 
 
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -61,6 +61,10 @@ ssize_t ngx_write_chain_to_file(ngx_file
 #define ngx_rename_file_n        "rename"
 
 
+#define ngx_change_file_access(n, a) chmod((const char *) n, a)
+#define ngx_change_file_access_n "chmod"
+
+
 #define ngx_file_info(file, sb)  stat((const char *) file, sb)
 #define ngx_file_info_n          "stat()"
 
@@ -69,6 +73,8 @@ ssize_t ngx_write_chain_to_file(ngx_file
 
 #define ngx_is_dir(sb)           (S_ISDIR((sb)->st_mode))
 #define ngx_is_file(sb)          (S_ISREG((sb)->st_mode))
+#define ngx_is_link(sb)          (S_ISLNK((sb)->st_mode))
+#define ngx_is_exec(sb)          ((sb)->st_mode & S_IXUSR)
 #define ngx_file_size(sb)        (sb)->st_size
 #define ngx_file_mtime(sb)       (sb)->st_mtime
 #define ngx_file_uniq(sb)        (sb)->st_ino
@@ -95,7 +101,7 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, 
 #define ngx_read_dir_n           "readdir()"
 
 
-#define ngx_create_dir(name)     mkdir((const char *) name, 0700)
+#define ngx_create_dir(name, access) mkdir((const char *) name, access)
 #define ngx_create_dir_n         "mkdir()"